diff options
| author | Clement Courbet <courbet@google.com> | 2018-05-17 07:38:21 +0000 |
|---|---|---|
| committer | Clement Courbet <courbet@google.com> | 2018-05-17 07:38:21 +0000 |
| commit | ee110fb735651d63252f70104d39c5a0376ee20d (patch) | |
| tree | 56191aacb80508141d669128159f56b5afef5879 /llvm/unittests | |
| parent | f4b09a3a30875842ea4f8e8fce22936a2a29164e (diff) | |
| download | bcm5719-llvm-ee110fb735651d63252f70104d39c5a0376ee20d.tar.gz bcm5719-llvm-ee110fb735651d63252f70104d39c5a0376ee20d.zip | |
[llvm-exegesis] Update to cover latency through another opcode.
Restructuring the code to measure latency and uops.
The end goal is to have this program spawn another process to deal with SIGILL and other malformed programs. It is not yet the case in this redesign, it is still the main program that runs the code (and may crash).
It now uses BitVector instead of Graph for performance reasons.
https://reviews.llvm.org/D46821
Authored by Guillaume Chatelet
llvm-svn: 332579
Diffstat (limited to 'llvm/unittests')
6 files changed, 120 insertions, 389 deletions
diff --git a/llvm/unittests/tools/llvm-exegesis/CMakeLists.txt b/llvm/unittests/tools/llvm-exegesis/CMakeLists.txt index 22b5f1d79c3..95426aa1564 100644 --- a/llvm/unittests/tools/llvm-exegesis/CMakeLists.txt +++ b/llvm/unittests/tools/llvm-exegesis/CMakeLists.txt @@ -13,7 +13,6 @@ set(LLVM_LINK_COMPONENTS add_llvm_unittest(LLVMExegesisTests BenchmarkResultTest.cpp ClusteringTest.cpp - OperandGraphTest.cpp PerfHelperTest.cpp ) target_link_libraries(LLVMExegesisTests PRIVATE LLVMExegesis) diff --git a/llvm/unittests/tools/llvm-exegesis/OperandGraphTest.cpp b/llvm/unittests/tools/llvm-exegesis/OperandGraphTest.cpp deleted file mode 100644 index a29813b03ef..00000000000 --- a/llvm/unittests/tools/llvm-exegesis/OperandGraphTest.cpp +++ /dev/null @@ -1,48 +0,0 @@ -//===-- OperandGraphTest.cpp ------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "OperandGraph.h" -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -using testing::ElementsAre; -using testing::IsEmpty; -using testing::Not; - -namespace exegesis { -namespace graph { -namespace { - -static const auto In = Node::In(); -static const auto Out = Node::Out(); - -TEST(OperandGraphTest, NoPath) { - Graph TheGraph; - EXPECT_THAT(TheGraph.getPathFrom(In, Out), IsEmpty()); -} - -TEST(OperandGraphTest, Connecting) { - Graph TheGraph; - TheGraph.connect(In, Out); - EXPECT_THAT(TheGraph.getPathFrom(In, Out), Not(IsEmpty())); - EXPECT_THAT(TheGraph.getPathFrom(In, Out), ElementsAre(In, Out)); -} - -TEST(OperandGraphTest, ConnectingThroughVariable) { - const Node Var = Node::Var(1); - Graph TheGraph; - TheGraph.connect(In, Var); - TheGraph.connect(Var, Out); - EXPECT_THAT(TheGraph.getPathFrom(In, Out), Not(IsEmpty())); - EXPECT_THAT(TheGraph.getPathFrom(In, Out), ElementsAre(In, Var, Out)); -} - -} // namespace -} // namespace graph -} // namespace exegesis diff --git a/llvm/unittests/tools/llvm-exegesis/X86/CMakeLists.txt b/llvm/unittests/tools/llvm-exegesis/X86/CMakeLists.txt index 4d76f1a18c0..d1e2ed192b1 100644 --- a/llvm/unittests/tools/llvm-exegesis/X86/CMakeLists.txt +++ b/llvm/unittests/tools/llvm-exegesis/X86/CMakeLists.txt @@ -14,8 +14,7 @@ set(LLVM_LINK_COMPONENTS ) add_llvm_unittest(LLVMExegesisX86Tests + RegisterAliasingTest.cpp InMemoryAssemblerTest.cpp - InstructionSnippetGeneratorTest.cpp ) target_link_libraries(LLVMExegesisX86Tests PRIVATE LLVMExegesis) - diff --git a/llvm/unittests/tools/llvm-exegesis/X86/InMemoryAssemblerTest.cpp b/llvm/unittests/tools/llvm-exegesis/X86/InMemoryAssemblerTest.cpp index d00b223393f..24b55c8f109 100644 --- a/llvm/unittests/tools/llvm-exegesis/X86/InMemoryAssemblerTest.cpp +++ b/llvm/unittests/tools/llvm-exegesis/X86/InMemoryAssemblerTest.cpp @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// -#include "InMemoryAssembler.h" +#include "Assembler.h" #include "X86InstrInfo.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/CodeGen/MachineInstrBuilder.h" @@ -51,8 +51,8 @@ protected: llvm::TargetRegistry::lookupTarget(TT, Error); EXPECT_TRUE(TheTarget) << Error << " " << TT; const llvm::TargetOptions Options; - llvm::TargetMachine* TM = TheTarget->createTargetMachine( - TT, CpuName, "", Options, llvm::Reloc::Model::Static); + llvm::TargetMachine *TM = TheTarget->createTargetMachine( + TT, CpuName, "", Options, llvm::Reloc::Model::Static); EXPECT_TRUE(TM) << TT << " " << CpuName; return std::unique_ptr<llvm::LLVMTargetMachine>( static_cast<llvm::LLVMTargetMachine *>(TM)); @@ -62,58 +62,66 @@ protected: return llvm::StringRef(TT).startswith_lower("x86_64"); } + ExecutableFunction assembleFunction(llvm::MCInst MCInst) { + return assembleToFunction({MCInst}); + } + + ExecutableFunction assembleEmptyFunction() { return assembleToFunction({}); } + private: + ExecutableFunction + assembleToFunction(llvm::ArrayRef<llvm::MCInst> Instructions) { + llvm::SmallString<256> Buffer; + llvm::raw_svector_ostream AsmStream(Buffer); + assembleToStream(createTargetMachine(), Instructions, AsmStream); + return ExecutableFunction(createTargetMachine(), + getObjectFromBuffer(AsmStream.str())); + } const std::string TT; const std::string CpuName; }; // Used to skip tests on unsupported architectures and operating systems. // To skip a test, add this macro at the top of a test-case. -#define SKIP_UNSUPPORTED_PLATFORM \ - do \ - if (!IsSupportedTarget()) \ - return; \ - while(0) - +#define SKIP_UNSUPPORTED_PLATFORM \ + do \ + if (!IsSupportedTarget()) \ + return; \ + while (0) -TEST_F(MachineFunctionGeneratorTest, DISABLED_JitFunction) { +TEST_F(MachineFunctionGeneratorTest, JitFunction) { SKIP_UNSUPPORTED_PLATFORM; - JitFunctionContext Context(createTargetMachine()); - JitFunction Function(std::move(Context), {}); + const ExecutableFunction Function = assembleEmptyFunction(); ASSERT_THAT(Function.getFunctionBytes().str(), ElementsAre(0xc3)); // FIXME: Check that the function runs without errors. Right now this is // disabled because it fails on some bots. - // Function(); + Function(); } -TEST_F(MachineFunctionGeneratorTest, DISABLED_JitFunctionXOR32rr) { +TEST_F(MachineFunctionGeneratorTest, JitFunctionXOR32rr) { SKIP_UNSUPPORTED_PLATFORM; - JitFunctionContext Context(createTargetMachine()); - JitFunction Function( - std::move(Context), - {MCInstBuilder(XOR32rr).addReg(EAX).addReg(EAX).addReg(EAX)}); + const ExecutableFunction Function = assembleFunction( + MCInstBuilder(XOR32rr).addReg(EAX).addReg(EAX).addReg(EAX)); ASSERT_THAT(Function.getFunctionBytes().str(), ElementsAre(0x31, 0xc0, 0xc3)); - // Function(); + Function(); } -TEST_F(MachineFunctionGeneratorTest, DISABLED_JitFunctionMOV64ri) { +TEST_F(MachineFunctionGeneratorTest, JitFunctionMOV64ri) { SKIP_UNSUPPORTED_PLATFORM; - JitFunctionContext Context(createTargetMachine()); - JitFunction Function(std::move(Context), - {MCInstBuilder(MOV64ri32).addReg(RAX).addImm(42)}); + const ExecutableFunction Function = + assembleFunction(MCInstBuilder(MOV64ri32).addReg(RAX).addImm(42)); ASSERT_THAT(Function.getFunctionBytes().str(), ElementsAre(0x48, 0xc7, 0xc0, 0x2a, 0x00, 0x00, 0x00, 0xc3)); - // Function(); + Function(); } -TEST_F(MachineFunctionGeneratorTest, DISABLED_JitFunctionMOV32ri) { +TEST_F(MachineFunctionGeneratorTest, JitFunctionMOV32ri) { SKIP_UNSUPPORTED_PLATFORM; - JitFunctionContext Context(createTargetMachine()); - JitFunction Function(std::move(Context), - {MCInstBuilder(MOV32ri).addReg(EAX).addImm(42)}); + const ExecutableFunction Function = + assembleFunction(MCInstBuilder(MOV32ri).addReg(EAX).addImm(42)); ASSERT_THAT(Function.getFunctionBytes().str(), ElementsAre(0xb8, 0x2a, 0x00, 0x00, 0x00, 0xc3)); - // Function(); + Function(); } } // namespace diff --git a/llvm/unittests/tools/llvm-exegesis/X86/InstructionSnippetGeneratorTest.cpp b/llvm/unittests/tools/llvm-exegesis/X86/InstructionSnippetGeneratorTest.cpp deleted file mode 100644 index f4136561a11..00000000000 --- a/llvm/unittests/tools/llvm-exegesis/X86/InstructionSnippetGeneratorTest.cpp +++ /dev/null @@ -1,309 +0,0 @@ -//===-- InstructionSnippetGeneratorTest.cpp ---------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "InstructionSnippetGenerator.h" -#include "X86InstrInfo.h" -#include "llvm/MC/MCInstBuilder.h" -#include "llvm/Support/Host.h" -#include "llvm/Support/TargetRegistry.h" -#include "llvm/Support/TargetSelect.h" -#include "gmock/gmock.h" -#include "gtest/gtest.h" -#include <memory> -#include <set> - -namespace llvm { - -bool operator==(const MCOperand &A, const MCOperand &B) { - if ((A.isValid() == false) && (B.isValid() == false)) - return true; - if (A.isReg() && B.isReg()) - return A.getReg() == B.getReg(); - if (A.isImm() && B.isImm()) - return A.getImm() == B.getImm(); - return false; -} - -} // namespace llvm - -namespace exegesis { -namespace { - -using testing::_; -using testing::AllOf; -using testing::AnyOf; -using testing::Contains; -using testing::ElementsAre; -using testing::Eq; -using testing::Field; -using testing::Not; -using testing::SizeIs; -using testing::UnorderedElementsAre; -using testing::Value; - -using llvm::X86::AL; -using llvm::X86::AX; -using llvm::X86::EFLAGS; -using llvm::X86::RAX; - -class MCInstrDescViewTest : public ::testing::Test { -protected: - MCInstrDescViewTest() - : TheTriple("x86_64") {} - - static void SetUpTestCase() { - LLVMInitializeX86TargetInfo(); - LLVMInitializeX86TargetMC(); - LLVMInitializeX86Target(); - } - - void SetUp() override { - std::string Error; - const auto *Target = llvm::TargetRegistry::lookupTarget(TheTriple, Error); - InstrInfo.reset(Target->createMCInstrInfo()); - RegInfo.reset(Target->createMCRegInfo(TheTriple)); - } - - const std::string TheTriple; - std::unique_ptr<const llvm::MCInstrInfo> InstrInfo; - std::unique_ptr<const llvm::MCRegisterInfo> RegInfo; -}; - -MATCHER(IsDef, "") { return arg.IsDef; } -MATCHER(IsUse, "") { return arg.IsUse; } -MATCHER_P2(EqVarAssignement, VariableIndexMatcher, AssignedRegisterMatcher, - "") { - return Value( - arg, - AllOf(Field(&VariableAssignment::VarIdx, VariableIndexMatcher), - Field(&VariableAssignment::AssignedReg, AssignedRegisterMatcher))); -} - -size_t returnIndexZero(const size_t UpperBound) { return 0; } - -TEST_F(MCInstrDescViewTest, DISABLED_XOR64rr) { - const llvm::MCInstrDesc &InstrDesc = InstrInfo->get(llvm::X86::XOR64rr); - const auto Vars = - getVariables(*RegInfo, InstrDesc, llvm::BitVector(RegInfo->getNumRegs())); - - // XOR64rr has the following operands: - // 0. out register - // 1. in register (tied to out) - // 2. in register - // 3. out EFLAGS (implicit) - // - // This translates to 3 variables, one for 0 and 1, one for 2, one for 3. - ASSERT_THAT(Vars, SizeIs(3)); - - EXPECT_THAT(Vars[0].ExplicitOperands, ElementsAre(0, 1)); - EXPECT_THAT(Vars[1].ExplicitOperands, ElementsAre(2)); - EXPECT_THAT(Vars[2].ExplicitOperands, ElementsAre()); // implicit - - EXPECT_THAT(Vars[0], AllOf(IsUse(), IsDef())); - EXPECT_THAT(Vars[1], AllOf(IsUse(), Not(IsDef()))); - EXPECT_THAT(Vars[2], AllOf(Not(IsUse()), IsDef())); - - EXPECT_THAT(Vars[0].PossibleRegisters, Contains(RAX)); - EXPECT_THAT(Vars[1].PossibleRegisters, Contains(RAX)); - EXPECT_THAT(Vars[2].PossibleRegisters, ElementsAre(EFLAGS)); - - // Computing chains. - const auto Chains = computeSequentialAssignmentChains(*RegInfo, Vars); - - // Because operands 0 and 1 are tied together any possible value for variable - // 0 would do. - for (const auto &Reg : Vars[0].PossibleRegisters) { - EXPECT_THAT(Chains, Contains(ElementsAre(EqVarAssignement(0, Reg)))); - } - - // We also have chains going through operand 0 to 2 (i.e. Vars 0 and 1). - EXPECT_THAT(Vars[0].PossibleRegisters, Eq(Vars[1].PossibleRegisters)) - << "Variables 0 and 1 are of the same class"; - for (const auto &Reg : Vars[0].PossibleRegisters) { - EXPECT_THAT(Chains, - Contains(UnorderedElementsAre(EqVarAssignement(0, Reg), - EqVarAssignement(1, Reg)))); - } - - // EFLAGS does not appear as an input therefore no chain can contain EFLAGS. - EXPECT_THAT(Chains, Not(Contains(Contains(EqVarAssignement(_, EFLAGS))))); - - // Computing assignment. - const auto Regs = getRandomAssignment(Vars, Chains, &returnIndexZero); - EXPECT_THAT(Regs, ElementsAre(RAX, RAX, EFLAGS)); - - // Generating assembler representation. - const llvm::MCInst Inst = generateMCInst(InstrDesc, Vars, Regs); - EXPECT_THAT(Inst.getOpcode(), llvm::X86::XOR64rr); - EXPECT_THAT(Inst.getNumOperands(), 3); - EXPECT_THAT(Inst.getOperand(0), llvm::MCOperand::createReg(RAX)); - EXPECT_THAT(Inst.getOperand(1), llvm::MCOperand::createReg(RAX)); - EXPECT_THAT(Inst.getOperand(2), llvm::MCOperand::createReg(RAX)); -} - -TEST_F(MCInstrDescViewTest, DISABLED_AAA) { - const llvm::MCInstrDesc &InstrDesc = InstrInfo->get(llvm::X86::AAA); - const auto Vars = - getVariables(*RegInfo, InstrDesc, llvm::BitVector(RegInfo->getNumRegs())); - - // AAA has the following operands: - // 0. out AX (implicit) - // 1. out EFLAGS (implicit) - // 2. in AL (implicit) - // 3. in EFLAGS (implicit) - // - // This translates to 4 Vars (non are tied together). - ASSERT_THAT(Vars, SizeIs(4)); - - EXPECT_THAT(Vars[0].ExplicitOperands, ElementsAre()); // implicit - EXPECT_THAT(Vars[1].ExplicitOperands, ElementsAre()); // implicit - EXPECT_THAT(Vars[2].ExplicitOperands, ElementsAre()); // implicit - EXPECT_THAT(Vars[3].ExplicitOperands, ElementsAre()); // implicit - - EXPECT_THAT(Vars[0], AllOf(Not(IsUse()), IsDef())); - EXPECT_THAT(Vars[1], AllOf(Not(IsUse()), IsDef())); - EXPECT_THAT(Vars[2], AllOf(IsUse(), Not(IsDef()))); - EXPECT_THAT(Vars[3], AllOf(IsUse(), Not(IsDef()))); - - EXPECT_THAT(Vars[0].PossibleRegisters, ElementsAre(AX)); - EXPECT_THAT(Vars[1].PossibleRegisters, ElementsAre(EFLAGS)); - EXPECT_THAT(Vars[2].PossibleRegisters, ElementsAre(AL)); - EXPECT_THAT(Vars[3].PossibleRegisters, ElementsAre(EFLAGS)); - - const auto Chains = computeSequentialAssignmentChains(*RegInfo, Vars); - EXPECT_THAT(Chains, - ElementsAre(UnorderedElementsAre(EqVarAssignement(0, AX), - EqVarAssignement(2, AL)), - UnorderedElementsAre(EqVarAssignement(1, EFLAGS), - EqVarAssignement(3, EFLAGS)))); - - // Computing assignment. - const auto Regs = getRandomAssignment(Vars, Chains, &returnIndexZero); - EXPECT_THAT(Regs, ElementsAre(AX, EFLAGS, AL, EFLAGS)); - - // Generating assembler representation. - const llvm::MCInst Inst = generateMCInst(InstrDesc, Vars, Regs); - EXPECT_THAT(Inst.getOpcode(), llvm::X86::AAA); - EXPECT_THAT(Inst.getNumOperands(), 0) << "All operands are implicit"; -} - -TEST_F(MCInstrDescViewTest, DISABLED_ReservedRegisters) { - llvm::BitVector ReservedRegisters(RegInfo->getNumRegs()); - - const llvm::MCInstrDesc &InstrDesc = InstrInfo->get(llvm::X86::XOR64rr); - { - const auto Vars = getVariables(*RegInfo, InstrDesc, ReservedRegisters); - ASSERT_THAT(Vars, SizeIs(3)); - EXPECT_THAT(Vars[0].PossibleRegisters, Contains(RAX)); - EXPECT_THAT(Vars[1].PossibleRegisters, Contains(RAX)); - } - - // Disable RAX. - ReservedRegisters.set(RAX); - { - const auto Vars = getVariables(*RegInfo, InstrDesc, ReservedRegisters); - ASSERT_THAT(Vars, SizeIs(3)); - EXPECT_THAT(Vars[0].PossibleRegisters, Not(Contains(RAX))); - EXPECT_THAT(Vars[1].PossibleRegisters, Not(Contains(RAX))); - } -} - -Variable makeVariableWithRegisters(bool IsReg, - std::initializer_list<int> Regs) { - assert((IsReg || (Regs.size() == 0)) && "IsReg => !(Regs.size() == 0)"); - Variable Var; - Var.IsReg = IsReg; - Var.PossibleRegisters.insert(Regs.begin(), Regs.end()); - return Var; -} - -TEST(getExclusiveAssignment, TriviallyFeasible) { - const std::vector<Variable> Vars = { - makeVariableWithRegisters(true, {3}), - makeVariableWithRegisters(false, {}), - makeVariableWithRegisters(true, {4}), - makeVariableWithRegisters(true, {5}), - }; - const auto Regs = getExclusiveAssignment(Vars); - EXPECT_THAT(Regs, ElementsAre(3, 0, 4, 5)); -} - -TEST(getExclusiveAssignment, TriviallyInfeasible1) { - const std::vector<Variable> Vars = { - makeVariableWithRegisters(true, {3}), - makeVariableWithRegisters(true, {}), - makeVariableWithRegisters(true, {4}), - makeVariableWithRegisters(true, {5}), - }; - const auto Regs = getExclusiveAssignment(Vars); - EXPECT_THAT(Regs, ElementsAre()); -} - -TEST(getExclusiveAssignment, TriviallyInfeasible) { - const std::vector<Variable> Vars = { - makeVariableWithRegisters(true, {4}), - makeVariableWithRegisters(true, {4}), - }; - const auto Regs = getExclusiveAssignment(Vars); - EXPECT_THAT(Regs, ElementsAre()); -} - -TEST(getExclusiveAssignment, Feasible1) { - const std::vector<Variable> Vars = { - makeVariableWithRegisters(true, {4, 3}), - makeVariableWithRegisters(true, {6, 3}), - makeVariableWithRegisters(true, {6, 4}), - }; - const auto Regs = getExclusiveAssignment(Vars); - ASSERT_THAT(Regs, AnyOf(ElementsAre(3, 6, 4), ElementsAre(4, 3, 6))); -} - -TEST(getExclusiveAssignment, Feasible2) { - const std::vector<Variable> Vars = { - makeVariableWithRegisters(true, {1, 2}), - makeVariableWithRegisters(true, {3, 4}), - }; - const auto Regs = getExclusiveAssignment(Vars); - ASSERT_THAT(Regs, AnyOf(ElementsAre(1, 3), ElementsAre(1, 4), - ElementsAre(2, 3), ElementsAre(2, 4))); -} - -TEST(getGreedyAssignment, Infeasible) { - const std::vector<Variable> Vars = { - makeVariableWithRegisters(true, {}), - makeVariableWithRegisters(true, {1, 2}), - }; - const auto Regs = getGreedyAssignment(Vars); - ASSERT_THAT(Regs, ElementsAre()); -} - -TEST(getGreedyAssignment, FeasibleNoFallback) { - const std::vector<Variable> Vars = { - makeVariableWithRegisters(true, {1, 2}), - makeVariableWithRegisters(false, {}), - makeVariableWithRegisters(true, {2, 3}), - }; - const auto Regs = getGreedyAssignment(Vars); - ASSERT_THAT(Regs, ElementsAre(1, 0, 2)); -} - -TEST(getGreedyAssignment, Feasible) { - const std::vector<Variable> Vars = { - makeVariableWithRegisters(false, {}), - makeVariableWithRegisters(true, {1, 2}), - makeVariableWithRegisters(true, {2, 3}), - makeVariableWithRegisters(true, {2, 3}), - makeVariableWithRegisters(true, {2, 3}), - }; - const auto Regs = getGreedyAssignment(Vars); - ASSERT_THAT(Regs, ElementsAre(0, 1, 2, 3, 2)); -} - -} // namespace -} // namespace exegesis diff --git a/llvm/unittests/tools/llvm-exegesis/X86/RegisterAliasingTest.cpp b/llvm/unittests/tools/llvm-exegesis/X86/RegisterAliasingTest.cpp new file mode 100644 index 00000000000..eb6f294dc13 --- /dev/null +++ b/llvm/unittests/tools/llvm-exegesis/X86/RegisterAliasingTest.cpp @@ -0,0 +1,82 @@ +#include "RegisterAliasing.h" + +#include <cassert> +#include <memory> + +#include "X86InstrInfo.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/TargetSelect.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +namespace exegesis { +namespace { + +class RegisterAliasingTest : public ::testing::Test { +protected: + RegisterAliasingTest() { + const std::string TT = llvm::sys::getProcessTriple(); + std::string error; + const llvm::Target *const TheTarget = + llvm::TargetRegistry::lookupTarget(TT, error); + assert(TheTarget); + MCRegInfo.reset(TheTarget->createMCRegInfo(TT)); + } + + static void SetUpTestCase() { llvm::InitializeNativeTarget(); } + + const llvm::MCRegisterInfo &getMCRegInfo() { return *MCRegInfo; } + +private: + std::unique_ptr<const llvm::MCRegisterInfo> MCRegInfo; +}; + +TEST_F(RegisterAliasingTest, TrackSimpleRegister) { + const auto &RegInfo = getMCRegInfo(); + const RegisterAliasingTracker tracker(RegInfo, llvm::X86::EAX); + const std::set<llvm::MCPhysReg> ActualAliasedRegisters( + tracker.aliasedBits().set_bits().begin(), + tracker.aliasedBits().set_bits().end()); + const std::set<llvm::MCPhysReg> ExpectedAliasedRegisters = { + llvm::X86::AL, llvm::X86::AH, llvm::X86::AX, + llvm::X86::EAX, llvm::X86::HAX, llvm::X86::RAX}; + ASSERT_THAT(ActualAliasedRegisters, ExpectedAliasedRegisters); + for (llvm::MCPhysReg aliased : ExpectedAliasedRegisters) { + ASSERT_THAT(tracker.getOrigin(aliased), llvm::X86::EAX); + } +} + +TEST_F(RegisterAliasingTest, TrackRegisterClass) { + // The alias bits for GR8_ABCD_LRegClassID are the union of the alias bits for + // AL, BL, CL and DL. + const auto &RegInfo = getMCRegInfo(); + const llvm::BitVector NoReservedReg(RegInfo.getNumRegs()); + + const RegisterAliasingTracker RegClassTracker( + RegInfo, NoReservedReg, + RegInfo.getRegClass(llvm::X86::GR8_ABCD_LRegClassID)); + + llvm::BitVector sum(RegInfo.getNumRegs()); + sum |= RegisterAliasingTracker(RegInfo, llvm::X86::AL).aliasedBits(); + sum |= RegisterAliasingTracker(RegInfo, llvm::X86::BL).aliasedBits(); + sum |= RegisterAliasingTracker(RegInfo, llvm::X86::CL).aliasedBits(); + sum |= RegisterAliasingTracker(RegInfo, llvm::X86::DL).aliasedBits(); + + ASSERT_THAT(RegClassTracker.aliasedBits(), sum); +} + +TEST_F(RegisterAliasingTest, TrackRegisterClassCache) { + // Fetching twice the same tracker yields the same pointers. + const auto &RegInfo = getMCRegInfo(); + const llvm::BitVector NoReservedReg(RegInfo.getNumRegs()); + RegisterAliasingTrackerCache Cache(RegInfo, NoReservedReg); + ASSERT_THAT(&Cache.getRegister(llvm::X86::AX), + &Cache.getRegister(llvm::X86::AX)); + + ASSERT_THAT(&Cache.getRegisterClass(llvm::X86::GR8_ABCD_LRegClassID), + &Cache.getRegisterClass(llvm::X86::GR8_ABCD_LRegClassID)); +} + +} // namespace +} // namespace exegesis |

