From 0e69e2d74739a119a78d131c29b92c25787ec2f3 Mon Sep 17 00:00:00 2001 From: Clement Courbet Date: Thu, 17 May 2018 10:52:18 +0000 Subject: 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 --- .../tools/llvm-exegesis/ARM/AssemblerTest.cpp | 48 ++++ .../tools/llvm-exegesis/ARM/CMakeLists.txt | 3 +- .../llvm-exegesis/ARM/InMemoryAssemblerTest.cpp | 79 ------ llvm/unittests/tools/llvm-exegesis/CMakeLists.txt | 1 - .../tools/llvm-exegesis/Common/AssemblerUtils.h | 81 ++++++ .../tools/llvm-exegesis/OperandGraphTest.cpp | 48 ---- .../tools/llvm-exegesis/X86/AssemblerTest.cpp | 57 ++++ .../tools/llvm-exegesis/X86/CMakeLists.txt | 5 +- .../llvm-exegesis/X86/InMemoryAssemblerTest.cpp | 120 -------- .../X86/InstructionSnippetGeneratorTest.cpp | 309 --------------------- .../llvm-exegesis/X86/RegisterAliasingTest.cpp | 82 ++++++ 11 files changed, 271 insertions(+), 562 deletions(-) create mode 100644 llvm/unittests/tools/llvm-exegesis/ARM/AssemblerTest.cpp delete mode 100644 llvm/unittests/tools/llvm-exegesis/ARM/InMemoryAssemblerTest.cpp create mode 100644 llvm/unittests/tools/llvm-exegesis/Common/AssemblerUtils.h delete mode 100644 llvm/unittests/tools/llvm-exegesis/OperandGraphTest.cpp create mode 100644 llvm/unittests/tools/llvm-exegesis/X86/AssemblerTest.cpp delete mode 100644 llvm/unittests/tools/llvm-exegesis/X86/InMemoryAssemblerTest.cpp delete mode 100644 llvm/unittests/tools/llvm-exegesis/X86/InstructionSnippetGeneratorTest.cpp create mode 100644 llvm/unittests/tools/llvm-exegesis/X86/RegisterAliasingTest.cpp (limited to 'llvm/unittests/tools') 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 - -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 createTargetMachine() { - std::string Error; - const llvm::Target *TheTarget = - llvm::TargetRegistry::lookupTarget(TT, Error); - assert(TheTarget); - const llvm::TargetOptions Options; - return std::unique_ptr( - static_cast(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 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 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( + static_cast(TM)); + } + + ExecutableFunction + assembleToFunction(llvm::ArrayRef 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 - -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 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( - static_cast(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 -#include - -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 InstrInfo; - std::unique_ptr 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 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 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 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 Vars = { - makeVariableWithRegisters(true, {4}), - makeVariableWithRegisters(true, {4}), - }; - const auto Regs = getExclusiveAssignment(Vars); - EXPECT_THAT(Regs, ElementsAre()); -} - -TEST(getExclusiveAssignment, Feasible1) { - const std::vector 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 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 Vars = { - makeVariableWithRegisters(true, {}), - makeVariableWithRegisters(true, {1, 2}), - }; - const auto Regs = getGreedyAssignment(Vars); - ASSERT_THAT(Regs, ElementsAre()); -} - -TEST(getGreedyAssignment, FeasibleNoFallback) { - const std::vector 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 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 +#include + +#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 MCRegInfo; +}; + +TEST_F(RegisterAliasingTest, TrackSimpleRegister) { + const auto &RegInfo = getMCRegInfo(); + const RegisterAliasingTracker tracker(RegInfo, llvm::X86::EAX); + const std::set ActualAliasedRegisters( + tracker.aliasedBits().set_bits().begin(), + tracker.aliasedBits().set_bits().end()); + const std::set 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 -- cgit v1.2.3