diff options
author | Clement Courbet <courbet@google.com> | 2018-05-17 10:52:18 +0000 |
---|---|---|
committer | Clement Courbet <courbet@google.com> | 2018-05-17 10:52:18 +0000 |
commit | 0e69e2d74739a119a78d131c29b92c25787ec2f3 (patch) | |
tree | c808110b4a710daf2bed231cc96e1e3af1558294 /llvm/unittests/tools | |
parent | ceb4933dc1dc4e769ea9e1752a8cb8425de09002 (diff) | |
download | bcm5719-llvm-0e69e2d74739a119a78d131c29b92c25787ec2f3.tar.gz bcm5719-llvm-0e69e2d74739a119a78d131c29b92c25787ec2f3.zip |
reland r332579: [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
(with fixed ARM tests)
Authored by Guillaume Chatelet
llvm-svn: 332592
Diffstat (limited to 'llvm/unittests/tools')
11 files changed, 271 insertions, 562 deletions
diff --git a/llvm/unittests/tools/llvm-exegesis/ARM/AssemblerTest.cpp b/llvm/unittests/tools/llvm-exegesis/ARM/AssemblerTest.cpp new file mode 100644 index 00000000000..e3da703a88e --- /dev/null +++ b/llvm/unittests/tools/llvm-exegesis/ARM/AssemblerTest.cpp @@ -0,0 +1,48 @@ +//===-- AssemblerTest.cpp ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../Common/AssemblerUtils.h" +#include "ARMInstrInfo.h" + +namespace exegesis { +namespace { + +using llvm::MCInstBuilder; + +class ARMMachineFunctionGeneratorTest + : public MachineFunctionGeneratorBaseTest { +protected: + ARMMachineFunctionGeneratorTest() + : MachineFunctionGeneratorBaseTest("armv7-none-linux-gnueabi", "") {} + + static void SetUpTestCase() { + LLVMInitializeARMTargetInfo(); + LLVMInitializeARMTargetMC(); + LLVMInitializeARMTarget(); + LLVMInitializeARMAsmPrinter(); + } +}; + +TEST_F(ARMMachineFunctionGeneratorTest, JitFunction) { + Check(llvm::MCInst(), 0x1e, 0xff, 0x2f, 0xe1); +} + +TEST_F(ARMMachineFunctionGeneratorTest, JitFunctionADDrr) { + Check(MCInstBuilder(llvm::ARM::ADDrr) + .addReg(llvm::ARM::R0) + .addReg(llvm::ARM::R0) + .addReg(llvm::ARM::R0) + .addImm(llvm::ARMCC::AL) + .addReg(0) + .addReg(0), + 0x00, 0x00, 0x80, 0xe0, 0x1e, 0xff, 0x2f, 0xe1); +} + +} // namespace +} // namespace exegesis diff --git a/llvm/unittests/tools/llvm-exegesis/ARM/CMakeLists.txt b/llvm/unittests/tools/llvm-exegesis/ARM/CMakeLists.txt index aacb23b55b4..b000974938f 100644 --- a/llvm/unittests/tools/llvm-exegesis/ARM/CMakeLists.txt +++ b/llvm/unittests/tools/llvm-exegesis/ARM/CMakeLists.txt @@ -14,7 +14,6 @@ set(LLVM_LINK_COMPONENTS ) add_llvm_unittest(LLVMExegesisARMTests - InMemoryAssemblerTest.cpp + AssemblerTest.cpp ) target_link_libraries(LLVMExegesisARMTests PRIVATE LLVMExegesis) - diff --git a/llvm/unittests/tools/llvm-exegesis/ARM/InMemoryAssemblerTest.cpp b/llvm/unittests/tools/llvm-exegesis/ARM/InMemoryAssemblerTest.cpp deleted file mode 100644 index 50564e56ba0..00000000000 --- a/llvm/unittests/tools/llvm-exegesis/ARM/InMemoryAssemblerTest.cpp +++ /dev/null @@ -1,79 +0,0 @@ -//===-- InMemoryAssemblerTest.cpp -------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "InMemoryAssembler.h" -#include "ARMInstrInfo.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/CodeGen/MachineInstrBuilder.h" -#include "llvm/CodeGen/TargetInstrInfo.h" -#include "llvm/CodeGen/TargetSubtargetInfo.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> - -namespace exegesis { -namespace { - -using llvm::MCInstBuilder; -using testing::ElementsAre; - -class MachineFunctionGeneratorTest : public ::testing::Test { -protected: - MachineFunctionGeneratorTest() - : TT("armv7-none-linux-gnueabi"), CpuName("") {} - - static void SetUpTestCase() { - LLVMInitializeARMTargetInfo(); - LLVMInitializeARMTargetMC(); - LLVMInitializeARMTarget(); - LLVMInitializeARMAsmPrinter(); - } - - std::unique_ptr<llvm::LLVMTargetMachine> createTargetMachine() { - std::string Error; - const llvm::Target *TheTarget = - llvm::TargetRegistry::lookupTarget(TT, Error); - assert(TheTarget); - const llvm::TargetOptions Options; - return std::unique_ptr<llvm::LLVMTargetMachine>( - static_cast<llvm::LLVMTargetMachine *>(TheTarget->createTargetMachine( - TT, CpuName, "", Options, llvm::Reloc::Model::Static))); - } - -private: - const std::string TT; - const std::string CpuName; -}; - -TEST_F(MachineFunctionGeneratorTest, JitFunction) { - JitFunctionContext Context(createTargetMachine()); - JitFunction Function(std::move(Context), {}); - ASSERT_THAT(Function.getFunctionBytes().str(), - ElementsAre(0x1e, 0xff, 0x2f, 0xe1)); -} - -TEST_F(MachineFunctionGeneratorTest, JitFunctionADDrr) { - JitFunctionContext Context(createTargetMachine()); - JitFunction Function(std::move(Context), {MCInstBuilder(llvm::ARM::ADDrr) - .addReg(llvm::ARM::R0) - .addReg(llvm::ARM::R0) - .addReg(llvm::ARM::R0) - .addImm(llvm::ARMCC::AL) - .addReg(0) - .addReg(0)}); - ASSERT_THAT(Function.getFunctionBytes().str(), - ElementsAre(0x00, 0x00, 0x80, 0xe0, 0x1e, 0xff, 0x2f, 0xe1)); -} - -} // namespace -} // namespace exegesis 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/Common/AssemblerUtils.h b/llvm/unittests/tools/llvm-exegesis/Common/AssemblerUtils.h new file mode 100644 index 00000000000..78b0c2506fa --- /dev/null +++ b/llvm/unittests/tools/llvm-exegesis/Common/AssemblerUtils.h @@ -0,0 +1,81 @@ +//===-- AssemblerUtils.h ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Assembler.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/TargetInstrInfo.h" +#include "llvm/CodeGen/TargetSubtargetInfo.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" + +namespace exegesis { + +class MachineFunctionGeneratorBaseTest : public ::testing::Test { +protected: + MachineFunctionGeneratorBaseTest(const std::string &TT, + const std::string &CpuName) + : TT(TT), CpuName(CpuName), + CanExecute(llvm::Triple(TT).getArch() == + llvm::Triple(llvm::sys::getProcessTriple()).getArch()) { + if (!CanExecute) { + llvm::outs() << "Skipping execution, host:" + << llvm::sys::getProcessTriple() << ", target:" << TT + << "\n"; + } + } + + void RunIfSupported(const ExecutableFunction &Function) const { + if (CanExecute) + Function(); + } + + template <class... Bs> inline void Check(llvm::MCInst MCInst, Bs... Bytes) { + ExecutableFunction Function = (MCInst.getOpcode() == 0) + ? assembleToFunction({}) + : assembleToFunction({MCInst}); + ASSERT_THAT(Function.getFunctionBytes().str(), + testing::ElementsAre(Bytes...)); + if (CanExecute) + Function(); + } + +private: + std::unique_ptr<llvm::LLVMTargetMachine> createTargetMachine() { + std::string Error; + const llvm::Target *TheTarget = + 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); + EXPECT_TRUE(TM) << TT << " " << CpuName; + return std::unique_ptr<llvm::LLVMTargetMachine>( + static_cast<llvm::LLVMTargetMachine *>(TM)); + } + + 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; + const bool CanExecute; +}; + +} // namespace exegesis 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/AssemblerTest.cpp b/llvm/unittests/tools/llvm-exegesis/X86/AssemblerTest.cpp new file mode 100644 index 00000000000..e1c36e2dd99 --- /dev/null +++ b/llvm/unittests/tools/llvm-exegesis/X86/AssemblerTest.cpp @@ -0,0 +1,57 @@ +//===-- AssemblerTest.cpp ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../Common/AssemblerUtils.h" +#include "X86InstrInfo.h" + +namespace exegesis { +namespace { + +using llvm::MCInstBuilder; +using llvm::X86::EAX; +using llvm::X86::MOV32ri; +using llvm::X86::MOV64ri32; +using llvm::X86::RAX; +using llvm::X86::XOR32rr; + +class X86MachineFunctionGeneratorTest + : public MachineFunctionGeneratorBaseTest { +protected: + X86MachineFunctionGeneratorTest() + : MachineFunctionGeneratorBaseTest("x86_64-unknown-linux", "haswell") {} + + static void SetUpTestCase() { + LLVMInitializeX86TargetInfo(); + LLVMInitializeX86TargetMC(); + LLVMInitializeX86Target(); + LLVMInitializeX86AsmPrinter(); + } +}; + +TEST_F(X86MachineFunctionGeneratorTest, JitFunction) { + Check(llvm::MCInst(), 0xc3); +} + +TEST_F(X86MachineFunctionGeneratorTest, JitFunctionXOR32rr) { + Check(MCInstBuilder(XOR32rr).addReg(EAX).addReg(EAX).addReg(EAX), 0x31, 0xc0, + 0xc3); +} + +TEST_F(X86MachineFunctionGeneratorTest, JitFunctionMOV64ri) { + Check(MCInstBuilder(MOV64ri32).addReg(RAX).addImm(42), 0x48, 0xc7, 0xc0, 0x2a, + 0x00, 0x00, 0x00, 0xc3); +} + +TEST_F(X86MachineFunctionGeneratorTest, JitFunctionMOV32ri) { + Check(MCInstBuilder(MOV32ri).addReg(EAX).addImm(42), 0xb8, 0x2a, 0x00, 0x00, + 0x00, 0xc3); +} + +} // namespace +} // namespace exegesis diff --git a/llvm/unittests/tools/llvm-exegesis/X86/CMakeLists.txt b/llvm/unittests/tools/llvm-exegesis/X86/CMakeLists.txt index 4d76f1a18c0..e8b1381d8ba 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 - InMemoryAssemblerTest.cpp - InstructionSnippetGeneratorTest.cpp + RegisterAliasingTest.cpp + AssemblerTest.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 deleted file mode 100644 index d00b223393f..00000000000 --- a/llvm/unittests/tools/llvm-exegesis/X86/InMemoryAssemblerTest.cpp +++ /dev/null @@ -1,120 +0,0 @@ -//===-- InMemoryAssemblerTest.cpp -------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "InMemoryAssembler.h" -#include "X86InstrInfo.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/CodeGen/MachineInstrBuilder.h" -#include "llvm/CodeGen/TargetInstrInfo.h" -#include "llvm/CodeGen/TargetSubtargetInfo.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> - -namespace exegesis { -namespace { - -using llvm::MCInstBuilder; -using llvm::X86::EAX; -using llvm::X86::MOV32ri; -using llvm::X86::MOV64ri32; -using llvm::X86::RAX; -using llvm::X86::XOR32rr; -using testing::ElementsAre; - -class MachineFunctionGeneratorTest : public ::testing::Test { -protected: - MachineFunctionGeneratorTest() - : TT(llvm::sys::getProcessTriple()), - CpuName(llvm::sys::getHostCPUName().str()) {} - - static void SetUpTestCase() { - LLVMInitializeX86TargetInfo(); - LLVMInitializeX86TargetMC(); - LLVMInitializeX86Target(); - LLVMInitializeX86AsmPrinter(); - } - - std::unique_ptr<llvm::LLVMTargetMachine> createTargetMachine() { - std::string Error; - const llvm::Target *TheTarget = - 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); - EXPECT_TRUE(TM) << TT << " " << CpuName; - return std::unique_ptr<llvm::LLVMTargetMachine>( - static_cast<llvm::LLVMTargetMachine *>(TM)); - } - - bool IsSupportedTarget() const { - return llvm::StringRef(TT).startswith_lower("x86_64"); - } - -private: - 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) - - -TEST_F(MachineFunctionGeneratorTest, DISABLED_JitFunction) { - SKIP_UNSUPPORTED_PLATFORM; - JitFunctionContext Context(createTargetMachine()); - JitFunction Function(std::move(Context), {}); - 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(); -} - -TEST_F(MachineFunctionGeneratorTest, DISABLED_JitFunctionXOR32rr) { - SKIP_UNSUPPORTED_PLATFORM; - JitFunctionContext Context(createTargetMachine()); - JitFunction Function( - std::move(Context), - {MCInstBuilder(XOR32rr).addReg(EAX).addReg(EAX).addReg(EAX)}); - ASSERT_THAT(Function.getFunctionBytes().str(), ElementsAre(0x31, 0xc0, 0xc3)); - // Function(); -} - -TEST_F(MachineFunctionGeneratorTest, DISABLED_JitFunctionMOV64ri) { - SKIP_UNSUPPORTED_PLATFORM; - JitFunctionContext Context(createTargetMachine()); - JitFunction Function(std::move(Context), - {MCInstBuilder(MOV64ri32).addReg(RAX).addImm(42)}); - ASSERT_THAT(Function.getFunctionBytes().str(), - ElementsAre(0x48, 0xc7, 0xc0, 0x2a, 0x00, 0x00, 0x00, 0xc3)); - // Function(); -} - -TEST_F(MachineFunctionGeneratorTest, DISABLED_JitFunctionMOV32ri) { - SKIP_UNSUPPORTED_PLATFORM; - JitFunctionContext Context(createTargetMachine()); - JitFunction Function(std::move(Context), - {MCInstBuilder(MOV32ri).addReg(EAX).addImm(42)}); - ASSERT_THAT(Function.getFunctionBytes().str(), - ElementsAre(0xb8, 0x2a, 0x00, 0x00, 0x00, 0xc3)); - // Function(); -} - -} // namespace -} // namespace exegesis 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 |