Intel®ArchitectureCodeAnalyzer (IACA)を使用して、(私にとって)予期しない何かを見つけました。
[base+index]
アドレス指定を使用した次の命令
addps xmm1, xmmword ptr [rsi+rax*1]
iACAによるとマイクロヒューズはありません。ただし、このように[base+offset]
を使用すると
addps xmm1, xmmword ptr [rsi]
IACAはそれがヒューズをすることを報告します。
Intel最適化リファレンスマニュアル のセクション2-11は、「すべてのデコーダーで処理できるマイクロ融合マイクロオペレーションの例」として以下を示しています。
FADD DOUBLE PTR [RDI + RSI*8]
および Agner Fogの最適化アセンブリマニュアル は、[base+index]
アドレス指定を使用したマイクロオペレーションフュージョンの例も示しています。たとえば、セクション12.2「Core2の同じ例」を参照してください。それで、正解は何ですか?
デコーダーとuop-cacheでは、アドレッシングモードはマイクロフュージョンに影響を与えません(ただし、即値オペランドを持つ命令はRIP相対アドレッシングモードをマイクロフューズできません)。
ただし、uopとアドレッシングモードの組み合わせによっては、ROB(アウトオブオーダーコア)でマイクロフュージョンを維持できないため、Intel SnBファミリCPUは、問題が発生する前のある時点で、必要に応じて「ラミネート解除」されます。ステージの名前を変更します。問題のスループット、および順序が正しくないウィンドウサイズ(ROBサイズ)の場合、ラミネーション解除後の融合ドメインuopカウントが重要です。
Intelの最適化マニュアルセクション2.5.2.4:Micro-op Queue and the Loop Stream Detector(LSD)で、Sandybridgeのラミネーション解除について説明していますが、 t以降のマイクロアーキテクチャの変更について説明します。
UPDATE:Intelのマニュアルには、Haswellのラミネート解除について説明する詳細なセクションがあります。セクション2.4.5剥離を参照してください。また、SandyBridgeの簡単な説明はセクション2.5.2.4にあります。
ルール、SnB、HSW、SKLの実験からわかるように:
adc
とcmov
がマイクロヒューズしないことを意味します。ほとんどのVEXエンコード命令も、一般に3つのオペランドがあるため、融合しません(したがって、_paddb xmm0, [rdi+rbx]
_は融合しますが、_vpaddb xmm0, xmm0, [rdi+rbx]
_は融合しません)。最後に、_pabsb xmm0, [rax + rbx]
_などの最初のオペランドが書き込み専用である場合がある2オペランド命令も、融合しません。 IACAは間違っており、SnBルールを適用しています。関連:ポート7(Haswell以降)の専用ストアアドレスユニットが処理できるのは、単純な(インデックス付けされていない)アドレッシングモードだけなので、ストアのインデックス付きアドレッシングモードを回避することは依然として役立つ可能性があります。 (これに対する良いトリックは、単一のレジスタでdstをアドレス指定することですが、srcはdst+(initial_src-initial_dst)
でアドレス指定します。その後、ループ内でdstレジスタをインクリメントするだけで済みます。)
一部の命令は(デコーダー/ uopキャッシュ内であっても)マイクロヒューズをまったく行わないことに注意してください。例えば_shufps xmm, [mem], imm8
_または_vinsertf128 ymm, ymm, [mem], imm8
_は、レジスタソースバージョンが1 uopしかない場合でも、Skylakeを介したSnBでは常に2uopです。これは、imm8制御オペランドと通常のdest/src1、src2レジスタ/メモリオペランドを使用する命令で一般的ですが、他にもいくつかの場合があります。例えば_PSRLW/D/Q xmm,[mem]
_(メモリオペランドからのベクトルシフトカウント)はマイクロヒューズを行わず、PMULLDも行いません。
参照 Agner Fogのブログのこの投稿 多くのレジスタを読み取るときのHSW/SKLの問題スループット制限に関する議論:インデックス付きアドレッシングモードを使用した多くのマイクロフュージョンレジスタオペランドが少ない同じ命令と比較して、速度が低下する可能性があります。1レジスタアドレッシングモードとイミディエート。原因はまだわかりませんが、何らかのレジスタ読み取り制限があると思われます。 、おそらくPRFから多くのコールドレジスタを読み取ることに関連しています。
テストケース、実際の測定値からの数値:デコーダー内のこれらすべてのマイクロヒューズ、AFAIK、後でラミネートされていない場合でも。
_# store
mov [rax], edi SnB/HSW/SKL: 1 fused-domain, 2 unfused. The store-address uop can run on port7.
mov [rax+rsi], edi SnB: unlaminated. HSW/SKL: stays micro-fused. (The store-address can't use port7, though).
mov [buf +rax*4], edi SnB: unlaminated. HSW/SKL: stays micro-fused.
# normal ALU stuff
add edx, [rsp+rsi] SnB: unlaminated. HSW/SKL: stays micro-fused.
# I assume the majority of traditional/normal ALU insns are like add
_
HSW/SKLがラミネート解除する必要がある可能性のある3つの入力命令
_vfmadd213ps xmm0,xmm0,[rel buf] HSW/SKL: stays micro-fused: 1 fused, 2 unfused.
vfmadd213ps xmm0,xmm0,[rdi] HSW/SKL: stays micro-fused
vfmadd213ps xmm0,xmm0,[0+rdi*4] HSW/SKL: un-laminated: 2 uops in fused & unfused-domains.
(So indexed addressing mode is still the condition for HSW/SKL, same as documented by Intel for SnB)
# no idea why this one-source BMI2 instruction is unlaminated
# It's different from ADD in that its destination is write-only (and it uses a VEX encoding)
blsi edi, [rdi] HSW/SKL: 1 fused-domain, 2 unfused.
blsi edi, [rdi+rsi] HSW/SKL: 2 fused & unfused-domain.
adc eax, [rdi] same as cmov r, [rdi]
cmove ebx, [rdi] Stays micro-fused. (SnB?)/HSW: 2 fused-domain, 3 unfused domain.
SKL: 1 fused-domain, 2 unfused.
# I haven't confirmed that this micro-fuses in the decoders, but I'm assuming it does since a one-register addressing mode does.
adc eax, [rdi+rsi] same as cmov r, [rdi+rsi]
cmove ebx, [rdi+rax] SnB: untested, probably 3 fused&unfused-domain.
HSW: un-laminated to 3 fused&unfused-domain.
SKL: un-laminated to 2 fused&unfused-domain.
_
Broadwellはadc/cmovのSkylakeのように動作すると思います。
HSWがメモリソースADCとCMOVをラミネート解除するのは奇妙です。たぶん、IntelはHaswellの出荷期限に達する前に、SnBからそれを変更することに取り掛かっていなかったのだろう。
Agnerのinsnテーブルには、_cmovcc r,m
_と_adc r,m
_はHSW/SKLでまったくマイクロヒューズしないと書かれていますが、それは私の実験とは一致しません。私が測定しているサイクルカウントは、4 uops /クロック発行のボトルネックの場合、融合ドメインuop発行カウントと一致します。うまくいけば、彼はそれを再確認し、テーブルを修正するでしょう。
メモリ宛先整数ALU:
_add [rdi], eax SnB: untested (Agner says 2 fused-domain, 4 unfused-domain (load + ALU + store-address + store-data)
HSW/SKL: 2 fused-domain, 4 unfused.
add [rdi+rsi], eax SnB: untested, probably 4 fused & unfused-domain
HSW/SKL: 3 fused-domain, 4 unfused. (I don't know which uop stays fused).
HSW: About 0.95 cycles extra store-forwarding latency vs. [rdi] for the same address used repeatedly. (6.98c per iter, up from 6.04c for [rdi])
SKL: 0.02c extra latency (5.45c per iter, up from 5.43c for [rdi]), again in a tiny loop with dec ecx/jnz
adc [rdi], eax SnB: untested
HSW: 4 fused-domain, 6 unfused-domain. (same-address throughput 7.23c with dec, 7.19c with sub ecx,1)
SKL: 4 fused-domain, 6 unfused-domain. (same-address throughput ~5.25c with dec, 5.28c with sub)
adc [rdi+rsi], eax SnB: untested
HSW: 5 fused-domain, 6 unfused-domain. (same-address throughput = 7.03c)
SKL: 5 fused-domain, 6 unfused-domain. (same-address throughput = ~5.4c with sub ecx,1 for the loop branch, or 5.23c with dec ecx for the loop branch.)
_
はい、そうです、_adc [rdi],eax
_/_dec ecx
_/jnz
は、代わりにadd
を使用した同じループよりも速く実行されます SKLではadc
。明らかにSKLは同じアドレスの繰り返しの書き換えを好まないため、異なるアドレスを使用しようとはしませんでした(ストア転送の待ち時間が予想よりも長くなります。 同じアドレスへの繰り返しのストア/リロードが遅いことに関するこの投稿も参照してください) SKLで予想されるよりも 。
メモリ宛先adc
は非常に多くのuopsです。これは、Intel P6ファミリ(および明らかにSnBファミリ)がマルチuop命令のすべてのuopに対して同じTLBエントリを保持できないため、 この問題を回避するには、追加のuopが必要です。ロードと追加が完了し、ストアに障害が発生したが、CFが既に更新されているため、insnを再起動できない場合 。 Andy Glew(@krazyglew)からの興味深い一連のコメント。
おそらく、デコーダーでの融合とラミネーション解除により、_adc [base+idx], reg
_の単一の命令から4つ以上の融合ドメインuopsを生成するために マイクロコードROMが必要 から私たちを救うことができます。
SnBファミリーがラミネートを解除する理由:
Sandybridgeは、内部uop形式を簡素化して、電力とトランジスタを節約しました(ROBに入力/出力データを保持する代わりに、物理レジスタファイルの使用に大きな変更を加えました)。 SnBファミリCPUは、アウトオブオーダーコアの融合ドメインuopに対して限られた数の入力レジスタのみを許可します。 SnB/IvBの場合、その制限は2入力(フラグを含む)です。 HSW以降の場合、uopの制限は3入力です。メモリ宛先add
とadc
がそれを最大限に活用しているかどうか、またはIntelがいくつかの指示でHaswellをドアから出さなければならなかったかどうかはわかりません
Nehalem以前では、非融合ドメインuopに対して2入力の制限がありますが、ROBは、3つの入力レジスタ(非メモリレジスタのオペランド、ベース、およびインデックス)でマイクロ融合uopを追跡できるようです。
したがって、インデックス付きストアとALU + load命令は、効率的にデコードでき(グループの最初のuopである必要はありません)、uopキャッシュに余分なスペースを取りませんが、それ以外の場合、マイクロフュージョンの利点はチューニングのために本質的に失われますタイトなループ。 「ラミネーション解除」は、4-fused-domain-uops-per-cycleの発行/リタイア幅のアウトオブオーダーコアの前に発生します。融合ドメインパフォーマンスカウンター(uops_issued/uops_retired.retire_slots)は、ラミネーション解除後に融合ドメインuopsをカウントします。
Intelによる名前変更者の説明(セクション2.3.3.1:名前変更者)は、実際にラミネート解除を行うのは問題/名前変更の段階であることを示しているため、ラミネート解除を目的としたuopsは引き続き28/56/64融合ドメインuop発行キュー/ループバッファー(別名IDQ)でマイクロ融合されます。
TODO:これをテストします。ループバッファにかろうじて収まるはずのループを作成します。発行前にuopの1つがラミネート解除されるように何かを変更し、それがまだループバッファー(LSD)から実行されているかどうか、またはすべてのuopがuopキャッシュ(DSB)から再フェッチされているかどうかを確認します。 uopsがどこから来たのかを追跡するためのパフォーマンスカウンターがあるので、これは簡単なはずです。
より難しいTODO:uopキャッシュからの読み取りとIDQへの追加の間にラミネーション解除が発生した場合は、uopキャッシュの帯域幅を削減できるかどうかをテストします。または、問題の段階でラミネート解除が発生した場合、問題のスループットに悪影響を与える可能性がありますか? (つまり、最初の4を発行した後に残ったuopsをどのように処理しますか。)
(LUTコードの調整に基づく推測については、この回答の以前のバージョンを参照してください。vpgatherdd
に関する注記はpinsrw
ループの約1.7倍です。)
HSW/SKL数は、i5-4210Uおよびi7-6700kで測定されました。どちらもHTが有効になっています(ただし、システムはアイドル状態であるため、スレッドはコア全体をそれ自体に持っていました)。 _ocperf.py
_を使用して、SKL上のLinux4.10とHSW上のLinux4.8の両方のシステムで同じ静的バイナリを実行しました。 (HSWラップトップは私のSKLデスクトップの/ homeをNFSマウントしました。)
SnB数は、動作しなくなったi5-2500kで、以下に説明するように測定されました。
Uopsとサイクルのパフォーマンスカウンターでテストすることで確認されました。
Linuxのperf
コマンドで使用するために Intel SandybridgeのPMUイベントの表 を見つけました。 (残念ながら、標準のperf
には、uopsなどのほとんどのハードウェア固有のPMUイベントの記号名がありません。) 最近の回答 に使用しました。
_ocperf.py
_は、これらのuarch固有のPMUイベントの記号名を提供します なので、テーブルを検索する必要はありません。また、同じシンボリック名が複数のアーチで機能します。私が最初にこの答えを書いたとき、私はそれを知りませんでした。
Uopマイクロフュージョンをテストするために、IntelCPUのサイクルあたり4uopsのフューズドドメイン制限でボトルネックになっているテストプログラムを作成しました。実行ポートの競合を回避するために、これらのuopの多くはnop
sであり、実行ポートにディスパッチされないことを除いて、uopキャッシュに残り、他のuopと同じようにパイプラインを通過します。 。 (_xor x, same
_、または削除された移動は同じになります。)
テストプログラム:_yasm -f elf64 uop-test.s && ld uop-test.o -o uop-test
_
_GLOBAL _start
_start:
xor eax, eax
xor ebx, ebx
xor edx, edx
xor edi, edi
lea rsi, [rel mydata] ; load pointer
mov ecx, 10000000
cmp dword [rsp], 2 ; argc >= 2
jge .loop_2reg
ALIGN 32
.loop_1reg:
or eax, [rsi + 0]
or ebx, [rsi + 4]
dec ecx
nop
nop
nop
nop
jg .loop_1reg
; xchg r8, r9 ; no effect on flags; decided to use NOPs instead
jmp .out
ALIGN 32
.loop_2reg:
or eax, [rsi + 0 + rdi]
or ebx, [rsi + 4 + rdi]
dec ecx
nop
nop
nop
nop
jg .loop_2reg
.out:
xor edi, edi
mov eax, 231 ; exit(0)
syscall
SECTION .rodata
mydata:
db 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
_
また、ループが4 uopsの倍数でない場合、ループバッファーからのuop帯域幅はサイクルごとに一定の4ではないこともわかりました。 (つまり、abc
、abc
、...; abca
、bcab
、...ではありません)。 Agner Fogのmicroarchドキュメントは、残念ながら、ループバッファのこの制限について明確ではありませんでした。 HSW/SKLの詳細については、 opカウントがプロセッサ幅の倍数ではないループを実行するとパフォーマンスが低下しますか? を参照してください。この場合、SnBはHSWよりも悪い可能性がありますが、確信がなく、SnBハードウェアがまだ機能していません。
マクロ融合(比較と分岐)を画像から除外したかったので、nop
と分岐の間にdec
sを使用しました。 4 nop
sを使用したので、マイクロフュージョンを使用すると、ループは8 uopsになり、1回の反復ごとに2サイクルでパイプラインを埋めます。
ループの他のバージョンでは、マイクロヒューズを使用しない2オペランドアドレッシングモードを使用すると、ループは10個の融合ドメインuopsになり、3サイクルで実行されます。
3.3GHz Intel Sandybridge(i5 2500k)の結果。テスト前にcpufreqガバナーにクロック速度を上げるために何もしませんでした。サイクルは、メモリと対話していないときのサイクルです。 16進数で入力する必要のあるパフォーマンスカウンターイベントの注釈を追加しました。
1-regアドレッシングモードのテスト:コマンドライン引数なし
_$ perf stat -e task-clock,cycles,instructions,r1b1,r10e,r2c2,r1c2,stalled-cycles-frontend,stalled-cycles-backend ./uop-test
Performance counter stats for './uop-test':
11.489620 task-clock (msec) # 0.961 CPUs utilized
20,288,530 cycles # 1.766 GHz
80,082,993 instructions # 3.95 insns per cycle
# 0.00 stalled cycles per insn
60,190,182 r1b1 ; UOPS_DISPATCHED: (unfused-domain. 1->umask 02 -> uops sent to execution ports from this thread)
80,203,853 r10e ; UOPS_ISSUED: fused-domain
80,118,315 r2c2 ; UOPS_RETIRED: retirement slots used (fused-domain)
100,136,097 r1c2 ; UOPS_RETIRED: ALL (unfused-domain)
220,440 stalled-cycles-frontend # 1.09% frontend cycles idle
193,887 stalled-cycles-backend # 0.96% backend cycles idle
0.011949917 seconds time elapsed
_
2-regアドレッシングモードのテスト:コマンドラインargを使用
_$ perf stat -e task-clock,cycles,instructions,r1b1,r10e,r2c2,r1c2,stalled-cycles-frontend,stalled-cycles-backend ./uop-test x
Performance counter stats for './uop-test x':
18.756134 task-clock (msec) # 0.981 CPUs utilized
30,377,306 cycles # 1.620 GHz
80,105,553 instructions # 2.64 insns per cycle
# 0.01 stalled cycles per insn
60,218,693 r1b1 ; UOPS_DISPATCHED: (unfused-domain. 1->umask 02 -> uops sent to execution ports from this thread)
100,224,654 r10e ; UOPS_ISSUED: fused-domain
100,148,591 r2c2 ; UOPS_RETIRED: retirement slots used (fused-domain)
100,172,151 r1c2 ; UOPS_RETIRED: ALL (unfused-domain)
307,712 stalled-cycles-frontend # 1.01% frontend cycles idle
1,100,168 stalled-cycles-backend # 3.62% backend cycles idle
0.019114911 seconds time elapsed
_
したがって、両方のバージョンで80Mの命令が実行され、実行ポートに60Mのuopsがディスパッチされました。 (メモリソースを使用したor
は、パイプラインの残りの部分でマイクロフュージョンされているかどうかに関係なく、or
のALUと、ロードのロードポートにディスパッチします。nop
は実行ポートにまったくディスパッチしません。)同様に、ここでは4,000万のnopsがカウントされるため、どちらのバージョンも1億の非融合ドメインuopsを廃止します。
違いは、fused-domainのカウンターにあります。
ブランチの予測ミスにより、発行後、リタイア前にuopsがキャンセルされた場合にのみ、UOPS_ISSUEDとUOPS_RETIRED(リタイアメントスロットが使用されます)の違いが見られると思います。
そして最後に、パフォーマンスへの影響は現実的です。非融合バージョンは1.5倍のクロックサイクルを要しました。これは、ほとんどの実際のケースと比較してパフォーマンスの違いを誇張しています。ループは整数サイクルで実行する必要があり、2つの追加のuopsが2から3にプッシュします。多くの場合、追加の2つの融合ドメインuopsはあまり違いがありません。また、コードが4-fused-domain-uops-per-cycle以外の何かによってボトルネックになっている場合、潜在的に違いはありません。
それでも、ループ内で多くのメモリ参照を行うコードは、_[base + immediate offset]
_アドレッシングを使用する代わりに、単純な_[base + index]
_アドレッシングで使用される複数のポインターを適度に展開およびインクリメントして実装すると、より高速になる可能性があります。モード。
RIP-即時のマイクロヒューズはできません。 Agner Fogのテストによると、これはデコーダー/ uop-cacheでも当てはまるため、(ラミネートされていないのではなく)そもそも融合することはありません。
IACAはこれを誤解し、これらのマイクロヒューズの両方が次のように主張しています。
_cmp dword [abs mydata], 0x1b ; fused counters != unfused counters (micro-fusion happened, and wasn't un-laminated). Uses 2 entries in the uop-cache, according to Agner Fog's testing
cmp dword [rel mydata], 0x1b ; fused counters ~= unfused counters (micro-fusion didn't happen)
_
RIP-relは、即時がない場合にマイクロヒューズを実行します(そして融合を維持します)。
_or eax, dword [rel mydata] ; fused counters != unfused counters, i.e. micro-fusion happens
_
マイクロフュージョンは命令のレイテンシーを増加させません。他の入力の準備が整う前に、負荷が発生する可能性があります。
_ALIGN 32
.dep_Fuse:
or eax, [rsi + 0]
or eax, [rsi + 0]
or eax, [rsi + 0]
or eax, [rsi + 0]
or eax, [rsi + 0]
dec ecx
jg .dep_Fuse
_
eax
depチェーンがあるため、このループは反復ごとに5サイクルで実行されます。 _or eax, [rsi + 0 + rdi]
_または_mov ebx, [rsi + 0 + rdi] / or eax, ebx
_のシーケンスよりも速くはありません。 (unfusedバージョンとmov
バージョンはどちらも同じ数のuopsを実行します。)スケジューリング/ depチェックはunfused-domainで行われます。新しく発行されたuopsは、ROBだけでなくスケジューラー(別名リザベーションステーション(RS))にも入ります。それらは、ディスパッチ(実行ユニットに送信されることもあります)後にスケジューラーを離れますが、リタイアするまでROBに留まります。したがって、ロードレイテンシを非表示にするためのアウトオブオーダーウィンドウは、少なくともスケジューラサイズです( Sandybridgeでは54のunfused-domain uops、Haswellでは6 、Skylakeでは97)。
マイクロフュージョンには、ベースとオフセットが同じレジスタであるためのショートカットがありません。 _or eax, [mydata + rdi+4*rdi]
_(rdiがゼロになっている)のループは、_or eax, [rsi+rdi]
_のループと同じ数のuopsとサイクルを実行します。このアドレッシングモードは、固定アドレスから始まる奇数サイズの構造体の配列を反復処理するために使用できます。これはおそらくほとんどのプログラムで使用されることはないので、Intelがこの特殊なケースの2レジスタモードをマイクロヒューズに許可することにトランジスタを費やさなかったのは当然のことです。 (そしてIntelは、レジスターとスケールファクターが必要な場合、とにかく「インデックス付きアドレッシングモード」としてそれを文書化します。)
cmp
/jcc
またはdec
/jcc
のマクロ融合 unfused-domainでも単一のuopとして残るuopを作成します。 _dec / nop / jge
_は引き続き単一サイクルで実行できますが、1つではなく3つのuopsです。
注:私がこの回答を書いたので、PeterはHaswellとSkylakeもテストし、その結果を上記の受け入れられた回答に統合しました(特に、以下のSkylakeに起因する改善のほとんどは実際にHaswellに登場)。 CPU全体の動作の概要については、 その回答 が表示されます。この回答(間違いではありませんが)は、ほとんど歴史的に興味深いものです。
私のテストでは、少なくともSkylakeで1、Sandybridgeとは異なり、プロセッサは複雑なアドレッシングモードでも完全に融合します。
つまり、1-argおよび2-argバージョンのPeterによって上記に投稿されたコードは、同じサイクル数で実行され、同じ数のuopsがディスパッチされてリタイアされます。
私の結果:
./uop-test
のパフォーマンスカウンター統計:
23.718772 task-clock (msec) # 0.973 CPUs utilized
20,642,233 cycles # 0.870 GHz
80,111,957 instructions # 3.88 insns per cycle
60,253,831 uops_executed_thread # 2540.344 M/sec
80,295,685 uops_issued_any # 3385.322 M/sec
80,176,940 uops_retired_retire_slots # 3380.316 M/sec
0.024376698 seconds time elapsed
./uop-test x
のパフォーマンスカウンター統計:
13.532440 task-clock (msec) # 0.967 CPUs utilized
21,592,044 cycles # 1.596 GHz
80,073,676 instructions # 3.71 insns per cycle
60,144,749 uops_executed_thread # 4444.487 M/sec
80,162,360 uops_issued_any # 5923.718 M/sec
80,104,978 uops_retired_retire_slots # 5919.478 M/sec
0.013997088 seconds time elapsed
./uop-test x x
のパフォーマンスカウンター統計:
16.672198 task-clock (msec) # 0.981 CPUs utilized
27,056,453 cycles # 1.623 GHz
80,083,140 instructions # 2.96 insns per cycle
60,164,049 uops_executed_thread # 3608.645 M/sec
100,187,390 uops_issued_any # 6009.249 M/sec
100,118,409 uops_retired_retire_slots # 6005.112 M/sec
0.016997874 seconds time elapsed
SkylakeでUOPS_RETIRED_ANY命令は見つかりませんでした。明らかに、融合ドメインである「リタイアされたスロット」の人だけでした。
最終テスト(uop-test x x
)は、Peterが提案するバリアントであり、RIP相対cmp
を即時で使用します。これは、マイクロフューズしないことが知られています。
.loop_riprel
cmp dword [rel mydata], 1
cmp dword [rel mydata], 2
dec ecx
nop
nop
nop
nop
jg .loop_riprel
結果は、サイクルごとに余分な2 uopsが、発行されたuopsとリタイアされたカウンターによって取得されることを示しています(したがって、テストでは、融合が発生するかどうかを区別できます)。
他のアーキテクチャでのさらなるテストは大歓迎です!コードを見つけることができます(上記のPeterからコピー) github内 。
[1] ...そしておそらくSkylakeとSandybridgeの間にある他のいくつかのアーキテクチャ。PeterはSBのみをテストし、私はSKLのみをテストしたからです。
Intel Sandy Bridge、Ivy Bridge、Haswell、Broadwellのテスト結果を確認しました。 Skylakeでのテストにはまだアクセスできません。結果は次のとおりです。
結果は他の要因による可能性があります。私はIACAを使おうとはしていません。
Uopキャッシュのない古いIntelプロセッサは融合を実行できるため、これがuopキャッシュの欠点である可能性があります。今はこれをテストする時間がありませんが、次回更新するときにuopfusionのテストを追加します テストスクリプト 。 FMAの指示を試しましたか?これらは、融合されていないuopで3つの入力依存関係を許可する唯一の命令です。