]> granicus.if.org Git - llvm/commit
[X86][Btver2] Fix latency and throughput of CMPXCHG instructions.
authorAndrea Di Biagio <Andrea_DiBiagio@sn.scee.net>
Tue, 20 Aug 2019 10:23:55 +0000 (10:23 +0000)
committerAndrea Di Biagio <Andrea_DiBiagio@sn.scee.net>
Tue, 20 Aug 2019 10:23:55 +0000 (10:23 +0000)
commited0c466ac8a6e58b55d632eca52654bb69a028eb
tree0c2bb03c912668d77e31f4a7f4179fd5dead2838
parentc134f2724c71d92b0ca654f1143b9ca48acd296a
[X86][Btver2] Fix latency and throughput of CMPXCHG instructions.

On Jaguar, CMPXCHG has a latency of 11cy, and a maximum throughput of 0.33 IPC.
Throughput is superiorly limited to 0.33 because of the implicit in/out
dependency on register EAX. In the case of repeated non-atomic CMPXCHG with the
same memory location, store-to-load forwarding occurs and values for sequent
loads are quickly forwarded from the store buffer.

Interestingly, the functionality in LLVM that computes the reciprocal throughput
doesn't seem to know about RMW instructions. That functionality only looks at
the "consumed resource cycles" for the throughput computation. It should be
fixed/improved by a future patch. In particular, for RMW instructions, that
logic should also take into account for the write latency of in/out register
operands.

An atomic CMPXCHG has a latency of ~17cy. Throughput is also limited to
~17cy/inst due to cache locking, which prevents other memory uOPs to start
executing before the "lock releasing" store uOP.

CMPXCHG8rr and CMPXCHG8rm are treated specially because they decode to one less
macro opcode. Their latency tend to be the same as the other RR/RM variants. RR
variants are relatively fast 3cy (but still microcoded - 5 macro opcodes).

CMPXCHG8B is 11cy and unfortunately doesn't seem to benefit from store-to-load
forwarding. That means, throughput is clearly limited by the in/out dependency
on GPR registers. The uOP composition is sadly unknown (due to the lack of PMCs
for the Integer pipes). I have reused the same mix of consumed resource from the
other CMPXCHG instructions for CMPXCHG8B too.
LOCK CMPXCHG8B is instead 18cycles.

CMPXCHG16B is 32cycles. Up to 38cycles when the LOCK prefix is specified. Due to
the in/out dependencies, throughput is limited to 1 instruction every 32 (or 38)
cycles dependeing on whether the LOCK prefix is specified or not.
I wouldn't be surprised if the microcode for CMPXCHG16B is similar to 2x
microcode from CMPXCHG8B. So, I have speculatively set the JALU01 consumption to
2x the resource cycles used for CMPXCHG8B.

The two new hasLockPrefix() functions are used by the btver2 scheduling model
check if a MCInst/MachineInst has a LOCK prefix. Calls to hasLockPrefix() have
been encoded in predicates of variant scheduling classes that describe lat/thr
of CMPXCHG.

Differential Revision: https://reviews.llvm.org/D66424

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@369365 91177308-0d34-0410-b5e6-96231b3b80d8
lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp
lib/Target/X86/MCTargetDesc/X86MCTargetDesc.h
lib/Target/X86/X86InstrInfo.h
lib/Target/X86/X86SchedPredicates.td
lib/Target/X86/X86ScheduleBtVer2.td
test/tools/llvm-mca/X86/BtVer2/resources-cmpxchg.s
test/tools/llvm-mca/X86/BtVer2/resources-x86_64.s