diff --git a/llvm/test/tools/llvm-exegesis/X86/latency-SBB8rr.s b/llvm/test/tools/llvm-exegesis/X86/latency-SBB8rr.s new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-exegesis/X86/latency-SBB8rr.s @@ -0,0 +1,11 @@ +# RUN: llvm-exegesis -mode=latency -opcode-name=SBB8rr | FileCheck %s + +CHECK: --- +CHECK-NEXT: mode: latency +CHECK-NEXT: key: +CHECK-NEXT: instructions: +CHECK-NEXT: SBB8rr +CHECK-NEXT: config: '' +CHECK-NEXT: register_initial_values: +CHECK-DAG: - '[[REG1:[A-Z0-9]+]]=0x0' +CHECK-LAST: ... diff --git a/llvm/tools/llvm-exegesis/lib/LlvmState.cpp b/llvm/tools/llvm-exegesis/lib/LlvmState.cpp --- a/llvm/tools/llvm-exegesis/lib/LlvmState.cpp +++ b/llvm/tools/llvm-exegesis/lib/LlvmState.cpp @@ -38,8 +38,11 @@ } PfmCounters = &TheExegesisTarget->getPfmCounters(CpuName); - RATC.reset(new RegisterAliasingTrackerCache( - getRegInfo(), getFunctionReservedRegs(getTargetMachine()))); + BitVector ReservedRegs = getFunctionReservedRegs(getTargetMachine()); + for (const unsigned Reg : TheExegesisTarget->getUnavailableRegisters()) + ReservedRegs.set(Reg); + RATC.reset( + new RegisterAliasingTrackerCache(getRegInfo(), std::move(ReservedRegs))); IC.reset(new InstructionsCache(getInstrInfo(), getRATC())); } diff --git a/llvm/tools/llvm-exegesis/lib/Target.h b/llvm/tools/llvm-exegesis/lib/Target.h --- a/llvm/tools/llvm-exegesis/lib/Target.h +++ b/llvm/tools/llvm-exegesis/lib/Target.h @@ -90,6 +90,11 @@ "fillMemoryOperands() requires getScratchMemoryRegister() > 0"); } + // Returns a list of unavailable registers. + // Targets can use this to prevent some registers to be automatically selected + // for use in snippets. + virtual ArrayRef getUnavailableRegisters() const { return {}; } + // Returns the maximum number of bytes a load/store instruction can access at // once. This is typically the size of the largest register available on the // processor. Note that this only used as a hint to generate independant diff --git a/llvm/tools/llvm-exegesis/lib/X86/Target.cpp b/llvm/tools/llvm-exegesis/lib/X86/Target.cpp --- a/llvm/tools/llvm-exegesis/lib/X86/Target.cpp +++ b/llvm/tools/llvm-exegesis/lib/X86/Target.cpp @@ -435,6 +435,12 @@ unsigned Reg, const llvm::APInt &Value) const override; + ArrayRef getUnavailableRegisters() const override { + return makeArrayRef(kUnavailableRegisters, + sizeof(kUnavailableRegisters) / + sizeof(kUnavailableRegisters[0])); + } + std::unique_ptr createLatencySnippetGenerator(const LLVMState &State) const override { return llvm::make_unique(State); @@ -448,7 +454,14 @@ bool matchesArch(llvm::Triple::ArchType Arch) const override { return Arch == llvm::Triple::x86_64 || Arch == llvm::Triple::x86; } + + static const unsigned kUnavailableRegisters[4]; }; + +// We disable a few registers that cannot be encoded on instructions with a REX +// prefix. +const unsigned ExegesisX86Target::kUnavailableRegisters[4] = {X86::AH, X86::BH, + X86::CH, X86::DH}; } // namespace void ExegesisX86Target::addTargetSpecificPasses( diff --git a/llvm/unittests/tools/llvm-exegesis/X86/TargetTest.cpp b/llvm/unittests/tools/llvm-exegesis/X86/TargetTest.cpp --- a/llvm/unittests/tools/llvm-exegesis/X86/TargetTest.cpp +++ b/llvm/unittests/tools/llvm-exegesis/X86/TargetTest.cpp @@ -144,6 +144,10 @@ Core2Avx512TargetTest() : X86TargetTest("+avx512vl") {} }; +TEST_F(Core2TargetTest, NoHighByteRegs) { + EXPECT_TRUE(State.getRATC().reservedRegisters().test(X86::AH)); +} + TEST_F(Core2TargetTest, SetFlags) { const unsigned Reg = llvm::X86::EFLAGS; EXPECT_THAT(