summaryrefslogtreecommitdiff
path: root/unittests/tools
diff options
context:
space:
mode:
authorGuillaume Chatelet <gchatelet@google.com>2018-06-20 08:52:30 +0000
committerGuillaume Chatelet <gchatelet@google.com>2018-06-20 08:52:30 +0000
commitb1497a74adb1d3669dbb16a9e02ee5214ea211a6 (patch)
treee5f51ec34e90ecd3df944e26ae005cdbe9b2005a /unittests/tools
parent7e9ed1d023d99cc515f42791fd2dd730d60d2e17 (diff)
[llvm-exegesis] Use a Prototype to defer picking a value for free vars.
Summary: Introducing a Prototype object to capture Variables that must be set but keeps degrees of freedom as Invalid. This allows exploring non constraint variables later on. Reviewers: courbet Subscribers: tschuett, llvm-commits Differential Revision: https://reviews.llvm.org/D48316 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@335105 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'unittests/tools')
-rw-r--r--unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp159
1 files changed, 82 insertions, 77 deletions
diff --git a/unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp b/unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp
index fda7d069534..aef137b16e3 100644
--- a/unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp
+++ b/unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp
@@ -20,6 +20,13 @@
namespace exegesis {
namespace {
+using testing::HasSubstr;
+using testing::Not;
+using testing::SizeIs;
+
+MATCHER(IsInvalid, "") { return !arg.isValid(); }
+MATCHER(IsReg, "") { return arg.isReg(); }
+
class X86SnippetGeneratorTest : public ::testing::Test {
protected:
X86SnippetGeneratorTest()
@@ -38,20 +45,26 @@ protected:
const llvm::MCRegisterInfo &MCRegisterInfo;
};
-class LatencySnippetGeneratorTest : public X86SnippetGeneratorTest {
+template <typename BenchmarkRunner>
+class SnippetGeneratorTest : public X86SnippetGeneratorTest {
protected:
- LatencySnippetGeneratorTest() : Runner(State) {}
+ SnippetGeneratorTest() : Runner(State) {}
- BenchmarkConfiguration checkAndGetConfiguration(unsigned Opcode) {
+ SnippetPrototype checkAndGetConfigurations(unsigned Opcode) {
randomGenerator().seed(0); // Initialize seed.
- auto ConfOrError = Runner.generateConfiguration(Opcode);
- EXPECT_FALSE(ConfOrError.takeError()); // Valid configuration.
- return ConfOrError.get();
+ auto ProtoOrError = Runner.generatePrototype(Opcode);
+ EXPECT_FALSE(ProtoOrError.takeError()); // Valid configuration.
+ return std::move(ProtoOrError.get());
}
- LatencyBenchmarkRunner Runner;
+ BenchmarkRunner Runner;
};
+using LatencySnippetGeneratorTest =
+ SnippetGeneratorTest<LatencyBenchmarkRunner>;
+
+using UopsSnippetGeneratorTest = SnippetGeneratorTest<UopsBenchmarkRunner>;
+
TEST_F(LatencySnippetGeneratorTest, ImplicitSelfDependency) {
// ADC16i16 self alias because of implicit use and def.
@@ -61,17 +74,17 @@ TEST_F(LatencySnippetGeneratorTest, ImplicitSelfDependency) {
// implicit use : AX
// implicit use : EFLAGS
const unsigned Opcode = llvm::X86::ADC16i16;
- auto Conf = checkAndGetConfiguration(Opcode);
- EXPECT_THAT(Conf.Info, testing::HasSubstr("implicit"));
- ASSERT_THAT(Conf.Snippet, testing::SizeIs(1));
- const llvm::MCInst Instr = Conf.Snippet[0];
- EXPECT_THAT(Instr.getOpcode(), Opcode);
- EXPECT_THAT(Instr.getNumOperands(), 1);
- EXPECT_TRUE(Instr.getOperand(0).isImm()); // Use
EXPECT_THAT(MCInstrInfo.get(Opcode).getImplicitDefs()[0], llvm::X86::AX);
EXPECT_THAT(MCInstrInfo.get(Opcode).getImplicitDefs()[1], llvm::X86::EFLAGS);
EXPECT_THAT(MCInstrInfo.get(Opcode).getImplicitUses()[0], llvm::X86::AX);
EXPECT_THAT(MCInstrInfo.get(Opcode).getImplicitUses()[1], llvm::X86::EFLAGS);
+ const SnippetPrototype Proto = checkAndGetConfigurations(Opcode);
+ EXPECT_THAT(Proto.Explanation, HasSubstr("implicit"));
+ ASSERT_THAT(Proto.Snippet, SizeIs(1));
+ const InstructionInstance &II = Proto.Snippet[0];
+ EXPECT_THAT(II.getOpcode(), Opcode);
+ ASSERT_THAT(II.VariableValues, SizeIs(1)); // Imm.
+ EXPECT_THAT(II.VariableValues[0], IsInvalid()) << "Immediate is not set";
}
TEST_F(LatencySnippetGeneratorTest, ExplicitSelfDependency) {
@@ -82,18 +95,15 @@ TEST_F(LatencySnippetGeneratorTest, ExplicitSelfDependency) {
// explicit use 2 : imm
// implicit def : EFLAGS
const unsigned Opcode = llvm::X86::ADD16ri;
- auto Conf = checkAndGetConfiguration(Opcode);
- EXPECT_THAT(Conf.Info, testing::HasSubstr("explicit"));
- ASSERT_THAT(Conf.Snippet, testing::SizeIs(1));
- const llvm::MCInst Instr = Conf.Snippet[0];
- EXPECT_THAT(Instr.getOpcode(), Opcode);
- EXPECT_THAT(Instr.getNumOperands(), 3);
- EXPECT_TRUE(Instr.getOperand(0).isReg());
- EXPECT_TRUE(Instr.getOperand(1).isReg());
- EXPECT_THAT(Instr.getOperand(0).getReg(), Instr.getOperand(1).getReg())
- << "Op0 and Op1 should have the same value";
- EXPECT_TRUE(Instr.getOperand(2).isImm());
EXPECT_THAT(MCInstrInfo.get(Opcode).getImplicitDefs()[0], llvm::X86::EFLAGS);
+ const SnippetPrototype Proto = checkAndGetConfigurations(Opcode);
+ EXPECT_THAT(Proto.Explanation, HasSubstr("explicit"));
+ ASSERT_THAT(Proto.Snippet, SizeIs(1));
+ const InstructionInstance &II = Proto.Snippet[0];
+ EXPECT_THAT(II.getOpcode(), Opcode);
+ ASSERT_THAT(II.VariableValues, SizeIs(2));
+ EXPECT_THAT(II.VariableValues[0], IsReg()) << "Operand 0 and 1";
+ EXPECT_THAT(II.VariableValues[1], IsInvalid()) << "Operand 2 is not set";
}
TEST_F(LatencySnippetGeneratorTest, DependencyThroughOtherOpcode) {
@@ -103,49 +113,43 @@ TEST_F(LatencySnippetGeneratorTest, DependencyThroughOtherOpcode) {
// implicit def : EFLAGS
const unsigned Opcode = llvm::X86::CMP64rr;
- auto Conf = checkAndGetConfiguration(Opcode);
- EXPECT_THAT(Conf.Info, testing::HasSubstr("cycle through"));
- ASSERT_THAT(Conf.Snippet, testing::SizeIs(2));
- const llvm::MCInst Instr = Conf.Snippet[0];
- EXPECT_THAT(Instr.getOpcode(), Opcode);
+ const SnippetPrototype Proto = checkAndGetConfigurations(Opcode);
+ EXPECT_THAT(Proto.Explanation, HasSubstr("cycle through"));
+ ASSERT_THAT(Proto.Snippet, SizeIs(2));
+ const InstructionInstance &II = Proto.Snippet[0];
+ EXPECT_THAT(II.getOpcode(), Opcode);
+ ASSERT_THAT(II.VariableValues, SizeIs(2));
+ EXPECT_THAT(II.VariableValues[0], IsReg());
+ EXPECT_THAT(II.VariableValues[1], IsInvalid());
+ EXPECT_THAT(Proto.Snippet[1].getOpcode(), Not(Opcode));
// TODO: check that the two instructions alias each other.
}
TEST_F(LatencySnippetGeneratorTest, LAHF) {
const unsigned Opcode = llvm::X86::LAHF;
- auto Conf = checkAndGetConfiguration(Opcode);
- EXPECT_THAT(Conf.Info, testing::HasSubstr("cycle through"));
- ASSERT_THAT(Conf.Snippet, testing::SizeIs(2));
- const llvm::MCInst Instr = Conf.Snippet[0];
- EXPECT_THAT(Instr.getOpcode(), Opcode);
+ const SnippetPrototype Proto = checkAndGetConfigurations(Opcode);
+ EXPECT_THAT(Proto.Explanation, HasSubstr("cycle through"));
+ ASSERT_THAT(Proto.Snippet, SizeIs(2));
+ const InstructionInstance &II = Proto.Snippet[0];
+ EXPECT_THAT(II.getOpcode(), Opcode);
+ ASSERT_THAT(II.VariableValues, SizeIs(0));
}
-class UopsSnippetGeneratorTest : public X86SnippetGeneratorTest {
-protected:
- UopsSnippetGeneratorTest() : Runner(State) {}
-
- BenchmarkConfiguration checkAndGetConfiguration(unsigned Opcode) {
- randomGenerator().seed(0); // Initialize seed.
- auto ConfOrError = Runner.generateConfiguration(Opcode);
- EXPECT_FALSE(ConfOrError.takeError()); // Valid configuration.
- return ConfOrError.get();
- }
-
- UopsBenchmarkRunner Runner;
-};
-
TEST_F(UopsSnippetGeneratorTest, ParallelInstruction) {
- // BNDCL32rr is parallelno matter what.
+ // BNDCL32rr is parallel no matter what.
// explicit use 0 : reg RegClass=BNDR
// explicit use 1 : reg RegClass=GR32
const unsigned Opcode = llvm::X86::BNDCL32rr;
- auto Conf = checkAndGetConfiguration(Opcode);
- EXPECT_THAT(Conf.Info, testing::HasSubstr("parallel"));
- ASSERT_THAT(Conf.Snippet, testing::SizeIs(1));
- const llvm::MCInst Instr = Conf.Snippet[0];
- EXPECT_THAT(Instr.getOpcode(), Opcode);
+ const SnippetPrototype Proto = checkAndGetConfigurations(Opcode);
+ EXPECT_THAT(Proto.Explanation, HasSubstr("parallel"));
+ ASSERT_THAT(Proto.Snippet, SizeIs(1));
+ const InstructionInstance &II = Proto.Snippet[0];
+ EXPECT_THAT(II.getOpcode(), Opcode);
+ ASSERT_THAT(II.VariableValues, SizeIs(2));
+ EXPECT_THAT(II.VariableValues[0], IsInvalid());
+ EXPECT_THAT(II.VariableValues[1], IsInvalid());
}
TEST_F(UopsSnippetGeneratorTest, SerialInstruction) {
@@ -155,11 +159,12 @@ TEST_F(UopsSnippetGeneratorTest, SerialInstruction) {
// implicit def : EDX
// implicit use : EAX
const unsigned Opcode = llvm::X86::CDQ;
- auto Conf = checkAndGetConfiguration(Opcode);
- EXPECT_THAT(Conf.Info, testing::HasSubstr("serial"));
- ASSERT_THAT(Conf.Snippet, testing::SizeIs(1));
- const llvm::MCInst Instr = Conf.Snippet[0];
- EXPECT_THAT(Instr.getOpcode(), Opcode);
+ const SnippetPrototype Proto = checkAndGetConfigurations(Opcode);
+ EXPECT_THAT(Proto.Explanation, HasSubstr("serial"));
+ ASSERT_THAT(Proto.Snippet, SizeIs(1));
+ const InstructionInstance &II = Proto.Snippet[0];
+ EXPECT_THAT(II.getOpcode(), Opcode);
+ ASSERT_THAT(II.VariableValues, SizeIs(0));
}
TEST_F(UopsSnippetGeneratorTest, StaticRenaming) {
@@ -171,14 +176,16 @@ TEST_F(UopsSnippetGeneratorTest, StaticRenaming) {
// explicit use 2 : reg RegClass=GR32
// implicit use : EFLAGS
const unsigned Opcode = llvm::X86::CMOVA32rr;
- auto Conf = checkAndGetConfiguration(Opcode);
- EXPECT_THAT(Conf.Info, testing::HasSubstr("static renaming"));
+ const SnippetPrototype Proto = checkAndGetConfigurations(Opcode);
+ EXPECT_THAT(Proto.Explanation, HasSubstr("static renaming"));
constexpr const unsigned kInstructionCount = 15;
- ASSERT_THAT(Conf.Snippet, testing::SizeIs(kInstructionCount));
+ ASSERT_THAT(Proto.Snippet, SizeIs(kInstructionCount));
std::unordered_set<unsigned> AllDefRegisters;
- for (const auto &Inst : Conf.Snippet)
- AllDefRegisters.insert(Inst.getOperand(0).getReg());
- EXPECT_THAT(AllDefRegisters, testing::SizeIs(kInstructionCount))
+ for (const auto &II : Proto.Snippet) {
+ ASSERT_THAT(II.VariableValues, SizeIs(2));
+ AllDefRegisters.insert(II.VariableValues[0].getReg());
+ }
+ EXPECT_THAT(AllDefRegisters, SizeIs(kInstructionCount))
<< "Each instruction writes to a different register";
}
@@ -192,19 +199,17 @@ TEST_F(UopsSnippetGeneratorTest, NoTiedVariables) {
// explicit use 3 : imm
// implicit use : EFLAGS
const unsigned Opcode = llvm::X86::CMOV_GR32;
- auto Conf = checkAndGetConfiguration(Opcode);
- EXPECT_THAT(Conf.Info, testing::HasSubstr("no tied variables"));
- ASSERT_THAT(Conf.Snippet, testing::SizeIs(1));
- const llvm::MCInst Instr = Conf.Snippet[0];
- EXPECT_THAT(Instr.getOpcode(), Opcode);
- EXPECT_THAT(Instr.getNumOperands(), 4);
- EXPECT_THAT(Instr.getOperand(0).getReg(),
- testing::Not(Instr.getOperand(1).getReg()))
+ const SnippetPrototype Proto = checkAndGetConfigurations(Opcode);
+ EXPECT_THAT(Proto.Explanation, HasSubstr("no tied variables"));
+ ASSERT_THAT(Proto.Snippet, SizeIs(1));
+ const InstructionInstance &II = Proto.Snippet[0];
+ EXPECT_THAT(II.getOpcode(), Opcode);
+ ASSERT_THAT(II.VariableValues, SizeIs(4));
+ EXPECT_THAT(II.VariableValues[0].getReg(), Not(II.VariableValues[1].getReg()))
<< "Def is different from first Use";
- EXPECT_THAT(Instr.getOperand(0).getReg(),
- testing::Not(Instr.getOperand(2).getReg()))
+ EXPECT_THAT(II.VariableValues[0].getReg(), Not(II.VariableValues[2].getReg()))
<< "Def is different from second Use";
- EXPECT_THAT(Instr.getOperand(3).getImm(), 1);
+ EXPECT_THAT(II.VariableValues[3], IsInvalid());
}
} // namespace