3

MOVZXEMU8086 (をサポートしない 8086 をエミュレートする) を使用しているため、を置き換える命令を見つけようとしていMOVZXます。

私が見つけた最も近い命令はCBW、レジスタに値を入れる でしたが、これはAX符号付きの値のみを対象としています。符号なしの値で機能するものが必要です。

私のオプションは何ですか?単一の命令でそれを行うことは可能ですか?

4

1 に答える 1

3

このmovzx命令は、幅の広いレジスタに収まるように幅の狭い値をゼロ拡張します。たとえばmovzx、16 ビット値を 32 ビット レジスタに移動するために使用されます。(符号拡張movsxを除いて同じことを行う とは対照的です。値が符号なしの場合と、値が符号付きの場合に使用します。)movzxmovsx

ご指摘のとおり、これらの命令は 386 まで導入されなかったため、以前の世代のプロセッサをターゲットにしている場合は、代替手段を見つける必要があります。


他の人がコメントで指摘したように、基本的な戦略は、最初に宛先レジスタをゼロにしてから、より小さい値を に移動することです。これは、 とまったく同じことを達成しmovzxます。レジスタをゼロにする明白な方法は を使用することですが、 を使用したmov reg, 0が小さくて高速xor reg, regです。したがって、次のようなコード:

movzx  edx, WORD PTR [bx]

次のように置き換えることができます:

xor    edx, edx
mov    dx,  WORD PTR [bx]

最新のプロセッサでは、これは よりも遅くなりますがmovzx、実際にmovzxは が比較的遅い 386 および 486 でより高速になります。もちろん、存在しないプロセッサでmovzxは、選択の余地はありません。xor命令を先に発行し、他のコードに分散させることで、コストをさらに最小限に抑えることができます。


このアプローチの重大な欠点の 1 つは、レジスタに格納されている値に対してインプレース ゼロ拡張を実行できないことです。つまり、次のようなコードがある場合、このトリックを使用する方法はありません。

movzx  edx, dx

代わりに、一時レジスタを使用する必要があります。

xor  eax, eax
mov  ax,  dx
mov  dx,  ax    ; optional, if you really needed the result to be in DX


または、8 ビット値をゼロ拡張する場合、x86 では 16 ビット レジスタの上位 8 ビットと下位 8 ビットに個別にアクセスできるという事実を利用して、上位 8 ビットを単純にゼロにすることができます。 . 例えば:

mov    al, BYTE PTR [bx]
xor    ah, ah
; now read from value in AX

これはインプレース ゼロ拡張で機能することに注意してください。つまり、上位 8 ビットをゼロにするだけです。ただし、この手法を使用して 16 ビット値をゼロ拡張することはできません。これは、32 ビット レジスタの上位 16 ビットだけにアクセスする方法がないためです。


幸いなことに、これらの古いアーキテクチャでのゼロ拡張の必要性は、部分的なレジスタの停止や誤った依存関係に対して積極的に保護する必要がないため、最新のアーキテクチャでの必要性よりもはるかに少なくなっています。


movzxコメントでは、すべての選択肢が複数の指示 を必要とするという懸念が提起されました。もちろん、それは本当です。1 つの命令でそれを行う方法があれば、386 が導入する必要はなかったでしょうmovzx。実行速度が心配な場合は、xor+が利用可能である場合と mov同じくらい高速ではないにしても、上記で述べたことを考慮してください。movzx

命令数が気になる場合は、コードが少ないからといってコードが高速になるとは限らないのでご安心ください。実際、多くの場合、命令を追加すると、プログラムの実行速度が向上します。コードの特定のチャンクを最適化しようとしている場合は、ここまたはコード レビューで質問することをお勧めします(アセンブリ言語に関する質問がもっと必要です!)。

于 2017-01-06T18:56:27.030 に答える