2016-10-19 5 views
5

これはおそらく、マイクロ - ナノ操作ではないということですが、主題に興味があり、ロングモードで非ネイティブなレジスタサイズを使用するときに罰金がかかりますか?ロングモードで64/32ビットレジスタを使用する場合、罰則がありますか?

さまざまな情報源から、eaxの代わりにaxなどの部分的なレジスタの更新が発生すると、eflagsが停止し、パフォーマンスが低下することがあります。しかし、私はロングモードについては分かりません。このプロセッサ動作モードでは、どのレジスタサイズがネイティブであると考えられますか? x86-64はまだx86アーキテクチャの拡張版なので、32ビットはまだネイティブだと思います。または私は間違っていますか?

sub eax, r14d 

又は

sub rax, r14 

様例えば

、命令は、同じ大きさを有するが、それらのいずれかを使用する場合、任意のペナルティが存在してもよいですか? 下記のような連続した命令でレジスタサイズをミキシングするときに罰則がありますか?連続する命令で32ビットおよび64ビット・レジスタ・サイズとを混合する際に

sub ecx, eax 
sub r14, rax 
+0

16ビットアクセスのペナルティがあります。 32ビットレジスタの使用とr8-r15の回避はOKであり、実際にはコードサイズが小さくなることがあります。 –

+4

32ビットレジスタに書き込むと、自動的に上位32ビットがクリアされるので、部分的な更新の問題は回避されます。 – Jester

+0

EFLAGSレジスタは、最新のプロセッサで大幅に仮想化されています。すべてのレジスタと同様です。必然的に、あまりにも多くの命令がそれを修正し、それはスーパースカラー実行の大きなダンパーです。あなたのコードにないものは、実際に*レジスタを使用する命令です。だから、プロセッサがそれを連動させ、あなたが掲示したコードを停止させる魅力的な理由はありません。どのようにして/うまくいかなければならないかについて誰かの意見を聞かないでください。アセンブリコードを書く唯一のポイントは、Cコンパイラよりも高速にすることです。測定する。 –

答えて

8

(高いDWORDは、すべての場合においてゼロであると仮定して)任意のペナルティが存在してもよいですか?

No, writing to a 32-bit register always zero-extends to the full registerであるため、x86-64では、32ビットおよび64ビット命令の部分的なペナルティが回避されます。

したがって、私は32ビットがまだネイティブであると信じています。

はい、ほとんどの命令(other than PUSH/POP)のデフォルトのオペランドサイズは32ビットです。 64ビットにはWビットが1に設定されたREXプレフィックスが必要です。したがって、コードサイズの理由から32ビットを優先します。これは、コンパイラが静的データのアドレスにmov r32, imm32を使用する理由です(デフォルトのコード・モデルでは、コード・アドレスと静的データ・アドレスが仮想アドレス空間の2GiBの低位にある必要があるためです)。

これはAMDによって設計された選択でした。彼らは他の方法を選ぶことができ、32ビットのオペランドサイズを得るために接頭辞が必要でした。ロングモードは独立したモードなので、x86-64マシンコードはx86-32マシンコードとは異なる場合があります。 AMDはその差異を最小限に抑えて、できるだけ多くのトランジスタをデコーダで共有できるようにしました。あなたの結論は正しいですが、あなたの推論はまったく間違っています。 (代わりに、EAXの斧のような)


部分レジスタの更新EFLAGSストールが発生し、パフォーマンスが低下する可能性があります。

パーシャルフラグストールは、パーシャルレジスタストールとは別です。それらは内部的にも同様に扱われます(EFLAGSの個別に名前が変更された部分は、変更されたAXをEAXの未変更の上位バイトとマージする必要があります)。 しかし、1つは他を引き起こさない

# partial-reg stall 
setcc al   # leaves the upper 3 (or 7) bytes unmodified 
add  edx, eax  # reads full EAX. Older CPUs stall while merging 

Zeroing EAX ahead of the flag-setting and setcc with xor eax,eax avoids the partial-register penalty entirely。 (Core2/Nehalemは、以前のCPUよりも少ないサイクルで停止しますが、併合uopを挿入している間は2または3cで停止します。マージアップを挿入している間、Sandybridgeは全く停止しません)。

(別のCPUでの部分的なレジスタペナルティの別の要約:Why doesn't GCC use partial registers?、基本的に同じことを言っています)。

AMDは後でフル・レジスタを読み出すときに部分的なレジスタ・ストールを受けませんが、部分的なレジスタの書き込みと読み出しは完全なレジスタに偽の依存性を持ちます。 (AMD CPUは最初の場所で別々にサブレジスタの名前を変更しないでください。インテルP4とSilvermont /ナイトのランディングは、同じ方法です。)

インテルハスウェル/ Skylakeマイクロアーキテクチャ(そしておそらくIvybridgeの)別にalの名前を変更しないでくださいraxはすべてなので、low8/low16レジスタをマージする必要はありません。しかし、setcc alは、古い値に偽の依存性があります。彼らはまだ名前を変更してahをマージします。 (Details on HSW/SKL partial-reg performance。)


# partial flag stall when reading a flag that didn't come from 
# the last instruction to write any flags. 
clc 
# edi and esi = one-past-the-end of dst and src 
# ecx = -count 
bigInt_add: 
    mov eax, [esi+ecx*4] 
    adc [edi+ecx*4], eax # reads CF, partial flag stall on 2nd and later iterations 
    inc ecx    # writes all flags except CF 
    jl bitInt_add   # loop upwards towards zero 

はSandybridge対インテル事前Sandybridge上の部分のフラグの問題の詳細な議論のためのthis Q&Aを参照してください。


Agner Fog's microarch pdfも参照してください、とこれのすべての詳細についてはタグウィキ内の他のリンク。

+0

ありがとう –

関連する問題