aboutsummaryrefslogtreecommitdiff
path: root/unittests
diff options
context:
space:
mode:
authorGuillaume Chatelet <gchatelet@google.com>2018-10-17 11:37:28 +0000
committerGuillaume Chatelet <gchatelet@google.com>2018-10-17 11:37:28 +0000
commit91e6826692e9bbf42880df69c51226f46b0a9167 (patch)
tree61a7eaa4d7868a2800a7dc84cbb185999e225fd5 /unittests
parent1e04734fb63189fd334a0d67bc6cd1cff95a5f4b (diff)
[llvm-exegeis] Computing Latency configuration upfront so we can generate many CodeTemplates at once.
Summary: LatencyGenerator now computes all possible mode of serial execution for an Instruction upfront and generates CodeTemplate for the ones that give the best results (e.g. no need to generate a two instructions snippet when repeating a single one would do). The next step is to generate even more configurations for cases (e.g. for XOR we should generate "XOR EAX, EAX, EAX" and "XOR EAX, EAX, EBX") Reviewers: courbet Reviewed By: courbet Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D53320 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@344689 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'unittests')
-rw-r--r--unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp237
1 files changed, 168 insertions, 69 deletions
diff --git a/unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp b/unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp
index 6cc24a02cfc..4b3fa5455a3 100644
--- a/unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp
+++ b/unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp
@@ -25,6 +25,7 @@ namespace {
using testing::AnyOf;
using testing::ElementsAre;
+using testing::Gt;
using testing::HasSubstr;
using testing::Not;
using testing::SizeIs;
@@ -57,14 +58,12 @@ class SnippetGeneratorTest : public X86SnippetGeneratorTest {
protected:
SnippetGeneratorTest() : Generator(State) {}
- CodeTemplate checkAndGetCodeTemplate(unsigned Opcode) {
+ std::vector<CodeTemplate> checkAndGetCodeTemplates(unsigned Opcode) {
randomGenerator().seed(0); // Initialize seed.
const Instruction Instr(State, Opcode);
auto CodeTemplateOrError = Generator.generateCodeTemplates(Instr);
EXPECT_FALSE(CodeTemplateOrError.takeError()); // Valid configuration.
- auto &CodeTemplate = CodeTemplateOrError.get();
- EXPECT_EQ(CodeTemplate.size(), 1U);
- return std::move(CodeTemplate.front());
+ return std::move(CodeTemplateOrError.get());
}
SnippetGeneratorT Generator;
@@ -75,21 +74,25 @@ using LatencySnippetGeneratorTest =
using UopsSnippetGeneratorTest = SnippetGeneratorTest<UopsSnippetGenerator>;
-TEST_F(LatencySnippetGeneratorTest, ImplicitSelfDependency) {
- // ADC16i16 self alias because of implicit use and def.
-
- // explicit use 0 : imm
- // implicit def : AX
- // implicit def : EFLAGS
- // implicit use : AX
- // implicit use : EFLAGS
+TEST_F(LatencySnippetGeneratorTest, ImplicitSelfDependencyThroughImplicitReg) {
+ // - ADC16i16
+ // - Op0 Explicit Use Immediate
+ // - Op1 Implicit Def Reg(AX)
+ // - Op2 Implicit Def Reg(EFLAGS)
+ // - Op3 Implicit Use Reg(AX)
+ // - Op4 Implicit Use Reg(EFLAGS)
+ // - Var0 [Op0]
+ // - hasAliasingImplicitRegisters (execution is always serial)
+ // - hasAliasingRegisters
const unsigned Opcode = llvm::X86::ADC16i16;
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 CodeTemplate CT = checkAndGetCodeTemplate(Opcode);
- EXPECT_THAT(CT.Info, HasSubstr("implicit"));
+ const auto CodeTemplates = checkAndGetCodeTemplates(Opcode);
+ ASSERT_THAT(CodeTemplates, SizeIs(1));
+ const auto &CT = CodeTemplates[0];
+ EXPECT_THAT(CT.Execution, ExecutionMode::ALWAYS_SERIAL_IMPLICIT_REGS_ALIAS);
ASSERT_THAT(CT.Instructions, SizeIs(1));
const InstructionTemplate &IT = CT.Instructions[0];
EXPECT_THAT(IT.getOpcode(), Opcode);
@@ -97,63 +100,105 @@ TEST_F(LatencySnippetGeneratorTest, ImplicitSelfDependency) {
EXPECT_THAT(IT.VariableValues[0], IsInvalid()) << "Immediate is not set";
}
-TEST_F(LatencySnippetGeneratorTest, ExplicitSelfDependency) {
- // ADD16ri self alias because Op0 and Op1 are tied together.
-
- // explicit def 0 : reg RegClass=GR16
- // explicit use 1 : reg RegClass=GR16 | TIED_TO:0
- // explicit use 2 : imm
- // implicit def : EFLAGS
+TEST_F(LatencySnippetGeneratorTest, ImplicitSelfDependencyThroughTiedRegs) {
+ // - ADD16ri
+ // - Op0 Explicit Def RegClass(GR16)
+ // - Op1 Explicit Use RegClass(GR16) TiedToOp0
+ // - Op2 Explicit Use Immediate
+ // - Op3 Implicit Def Reg(EFLAGS)
+ // - Var0 [Op0,Op1]
+ // - Var1 [Op2]
+ // - hasTiedRegisters (execution is always serial)
+ // - hasAliasingRegisters
const unsigned Opcode = llvm::X86::ADD16ri;
EXPECT_THAT(MCInstrInfo.get(Opcode).getImplicitDefs()[0], llvm::X86::EFLAGS);
- const CodeTemplate CT = checkAndGetCodeTemplate(Opcode);
- EXPECT_THAT(CT.Info, HasSubstr("explicit"));
+ const auto CodeTemplates = checkAndGetCodeTemplates(Opcode);
+ ASSERT_THAT(CodeTemplates, SizeIs(1));
+ const auto &CT = CodeTemplates[0];
+ EXPECT_THAT(CT.Execution, ExecutionMode::ALWAYS_SERIAL_TIED_REGS_ALIAS);
ASSERT_THAT(CT.Instructions, SizeIs(1));
const InstructionTemplate &IT = CT.Instructions[0];
EXPECT_THAT(IT.getOpcode(), Opcode);
ASSERT_THAT(IT.VariableValues, SizeIs(2));
- EXPECT_THAT(IT.VariableValues[0], IsReg()) << "Operand 0 and 1";
+ EXPECT_THAT(IT.VariableValues[0], IsInvalid()) << "Operand 1 is not set";
EXPECT_THAT(IT.VariableValues[1], IsInvalid()) << "Operand 2 is not set";
}
-TEST_F(LatencySnippetGeneratorTest, DependencyThroughOtherOpcode) {
- // CMP64rr
- // explicit use 0 : reg RegClass=GR64
- // explicit use 1 : reg RegClass=GR64
- // implicit def : EFLAGS
-
- const unsigned Opcode = llvm::X86::CMP64rr;
- const CodeTemplate CT = checkAndGetCodeTemplate(Opcode);
- EXPECT_THAT(CT.Info, HasSubstr("cycle through"));
- ASSERT_THAT(CT.Instructions, SizeIs(2));
+TEST_F(LatencySnippetGeneratorTest, ImplicitSelfDependencyThroughExplicitRegs) {
+ // - VXORPSrr
+ // - Op0 Explicit Def RegClass(VR128)
+ // - Op1 Explicit Use RegClass(VR128)
+ // - Op2 Explicit Use RegClass(VR128)
+ // - Var0 [Op0]
+ // - Var1 [Op1]
+ // - Var2 [Op2]
+ // - hasAliasingRegisters
+ const unsigned Opcode = llvm::X86::VXORPSrr;
+ const auto CodeTemplates = checkAndGetCodeTemplates(Opcode);
+ ASSERT_THAT(CodeTemplates, SizeIs(1));
+ const auto &CT = CodeTemplates[0];
+ EXPECT_THAT(CT.Execution, ExecutionMode::SERIAL_VIA_EXPLICIT_REGS);
+ ASSERT_THAT(CT.Instructions, SizeIs(1));
const InstructionTemplate &IT = CT.Instructions[0];
EXPECT_THAT(IT.getOpcode(), Opcode);
- ASSERT_THAT(IT.VariableValues, SizeIs(2));
- EXPECT_THAT(IT.VariableValues, AnyOf(ElementsAre(IsReg(), IsInvalid()),
- ElementsAre(IsInvalid(), IsReg())));
- EXPECT_THAT(CT.Instructions[1].getOpcode(), Not(Opcode));
- // TODO: check that the two instructions alias each other.
+ ASSERT_THAT(IT.VariableValues, SizeIs(3));
+ EXPECT_THAT(IT.VariableValues,
+ AnyOf(ElementsAre(IsReg(), IsInvalid(), IsReg()),
+ ElementsAre(IsReg(), IsReg(), IsInvalid())))
+ << "Op0 is either set to Op1 or to Op2";
+}
+
+TEST_F(LatencySnippetGeneratorTest, DependencyThroughOtherOpcode) {
+ // - CMP64rr
+ // - Op0 Explicit Use RegClass(GR64)
+ // - Op1 Explicit Use RegClass(GR64)
+ // - Op2 Implicit Def Reg(EFLAGS)
+ // - Var0 [Op0]
+ // - Var1 [Op1]
+ const unsigned Opcode = llvm::X86::CMP64rr;
+ const auto CodeTemplates = checkAndGetCodeTemplates(Opcode);
+ ASSERT_THAT(CodeTemplates, SizeIs(Gt(1U))) << "Many templates are available";
+ for (const auto &CT : CodeTemplates) {
+ EXPECT_THAT(CT.Execution, ExecutionMode::SERIAL_VIA_NON_MEMORY_INSTR);
+ ASSERT_THAT(CT.Instructions, SizeIs(2));
+ const InstructionTemplate &IT = CT.Instructions[0];
+ EXPECT_THAT(IT.getOpcode(), Opcode);
+ ASSERT_THAT(IT.VariableValues, SizeIs(2));
+ EXPECT_THAT(IT.VariableValues, AnyOf(ElementsAre(IsReg(), IsInvalid()),
+ ElementsAre(IsInvalid(), IsReg())));
+ EXPECT_THAT(CT.Instructions[1].getOpcode(), Not(Opcode));
+ // TODO: check that the two instructions alias each other.
+ }
}
TEST_F(LatencySnippetGeneratorTest, LAHF) {
+ // - LAHF
+ // - Op0 Implicit Def Reg(AH)
+ // - Op1 Implicit Use Reg(EFLAGS)
const unsigned Opcode = llvm::X86::LAHF;
- const CodeTemplate CT = checkAndGetCodeTemplate(Opcode);
- EXPECT_THAT(CT.Info, HasSubstr("cycle through"));
- ASSERT_THAT(CT.Instructions, SizeIs(2));
- const InstructionTemplate &IT = CT.Instructions[0];
- EXPECT_THAT(IT.getOpcode(), Opcode);
- ASSERT_THAT(IT.VariableValues, SizeIs(0));
+ const auto CodeTemplates = checkAndGetCodeTemplates(Opcode);
+ ASSERT_THAT(CodeTemplates, SizeIs(Gt(1U))) << "Many templates are available";
+ for (const auto &CT : CodeTemplates) {
+ EXPECT_THAT(CT.Execution, ExecutionMode::SERIAL_VIA_NON_MEMORY_INSTR);
+ ASSERT_THAT(CT.Instructions, SizeIs(2));
+ const InstructionTemplate &IT = CT.Instructions[0];
+ EXPECT_THAT(IT.getOpcode(), Opcode);
+ ASSERT_THAT(IT.VariableValues, SizeIs(0));
+ }
}
TEST_F(UopsSnippetGeneratorTest, ParallelInstruction) {
- // BNDCL32rr is parallel no matter what.
-
- // explicit use 0 : reg RegClass=BNDR
- // explicit use 1 : reg RegClass=GR32
-
+ // - BNDCL32rr
+ // - Op0 Explicit Use RegClass(BNDR)
+ // - Op1 Explicit Use RegClass(GR32)
+ // - Var0 [Op0]
+ // - Var1 [Op1]
const unsigned Opcode = llvm::X86::BNDCL32rr;
- const CodeTemplate CT = checkAndGetCodeTemplate(Opcode);
+ const auto CodeTemplates = checkAndGetCodeTemplates(Opcode);
+ ASSERT_THAT(CodeTemplates, SizeIs(1));
+ const auto &CT = CodeTemplates[0];
EXPECT_THAT(CT.Info, HasSubstr("parallel"));
+ EXPECT_THAT(CT.Execution, ExecutionMode::UNKNOWN);
ASSERT_THAT(CT.Instructions, SizeIs(1));
const InstructionTemplate &IT = CT.Instructions[0];
EXPECT_THAT(IT.getOpcode(), Opcode);
@@ -163,14 +208,18 @@ TEST_F(UopsSnippetGeneratorTest, ParallelInstruction) {
}
TEST_F(UopsSnippetGeneratorTest, SerialInstruction) {
- // CDQ is serial no matter what.
-
- // implicit def : EAX
- // implicit def : EDX
- // implicit use : EAX
+ // - CDQ
+ // - Op0 Implicit Def Reg(EAX)
+ // - Op1 Implicit Def Reg(EDX)
+ // - Op2 Implicit Use Reg(EAX)
+ // - hasAliasingImplicitRegisters (execution is always serial)
+ // - hasAliasingRegisters
const unsigned Opcode = llvm::X86::CDQ;
- const CodeTemplate CT = checkAndGetCodeTemplate(Opcode);
+ const auto CodeTemplates = checkAndGetCodeTemplates(Opcode);
+ ASSERT_THAT(CodeTemplates, SizeIs(1));
+ const auto &CT = CodeTemplates[0];
EXPECT_THAT(CT.Info, HasSubstr("serial"));
+ EXPECT_THAT(CT.Execution, ExecutionMode::UNKNOWN);
ASSERT_THAT(CT.Instructions, SizeIs(1));
const InstructionTemplate &IT = CT.Instructions[0];
EXPECT_THAT(IT.getOpcode(), Opcode);
@@ -181,13 +230,21 @@ TEST_F(UopsSnippetGeneratorTest, StaticRenaming) {
// CMOVA32rr has tied variables, we enumerate the possible values to execute
// as many in parallel as possible.
- // explicit def 0 : reg RegClass=GR32
- // explicit use 1 : reg RegClass=GR32 | TIED_TO:0
- // explicit use 2 : reg RegClass=GR32
- // implicit use : EFLAGS
+ // - CMOVA32rr
+ // - Op0 Explicit Def RegClass(GR32)
+ // - Op1 Explicit Use RegClass(GR32) TiedToOp0
+ // - Op2 Explicit Use RegClass(GR32)
+ // - Op3 Implicit Use Reg(EFLAGS)
+ // - Var0 [Op0,Op1]
+ // - Var1 [Op2]
+ // - hasTiedRegisters (execution is always serial)
+ // - hasAliasingRegisters
const unsigned Opcode = llvm::X86::CMOVA32rr;
- const CodeTemplate CT = checkAndGetCodeTemplate(Opcode);
+ const auto CodeTemplates = checkAndGetCodeTemplates(Opcode);
+ ASSERT_THAT(CodeTemplates, SizeIs(1));
+ const auto &CT = CodeTemplates[0];
EXPECT_THAT(CT.Info, HasSubstr("static renaming"));
+ EXPECT_THAT(CT.Execution, ExecutionMode::UNKNOWN);
constexpr const unsigned kInstructionCount = 15;
ASSERT_THAT(CT.Instructions, SizeIs(kInstructionCount));
std::unordered_set<unsigned> AllDefRegisters;
@@ -203,14 +260,23 @@ TEST_F(UopsSnippetGeneratorTest, NoTiedVariables) {
// CMOV_GR32 has no tied variables, we make sure def and use are different
// from each other.
- // explicit def 0 : reg RegClass=GR32
- // explicit use 1 : reg RegClass=GR32
- // explicit use 2 : reg RegClass=GR32
- // explicit use 3 : imm
- // implicit use : EFLAGS
+ // - CMOV_GR32
+ // - Op0 Explicit Def RegClass(GR32)
+ // - Op1 Explicit Use RegClass(GR32)
+ // - Op2 Explicit Use RegClass(GR32)
+ // - Op3 Explicit Use Immediate
+ // - Op4 Implicit Use Reg(EFLAGS)
+ // - Var0 [Op0]
+ // - Var1 [Op1]
+ // - Var2 [Op2]
+ // - Var3 [Op3]
+ // - hasAliasingRegisters
const unsigned Opcode = llvm::X86::CMOV_GR32;
- const CodeTemplate CT = checkAndGetCodeTemplate(Opcode);
+ const auto CodeTemplates = checkAndGetCodeTemplates(Opcode);
+ ASSERT_THAT(CodeTemplates, SizeIs(1));
+ const auto &CT = CodeTemplates[0];
EXPECT_THAT(CT.Info, HasSubstr("no tied variables"));
+ EXPECT_THAT(CT.Execution, ExecutionMode::UNKNOWN);
ASSERT_THAT(CT.Instructions, SizeIs(1));
const InstructionTemplate &IT = CT.Instructions[0];
EXPECT_THAT(IT.getOpcode(), Opcode);
@@ -224,9 +290,27 @@ TEST_F(UopsSnippetGeneratorTest, NoTiedVariables) {
TEST_F(UopsSnippetGeneratorTest, MemoryUse) {
// Mov32rm reads from memory.
+ // - MOV32rm
+ // - Op0 Explicit Def RegClass(GR32)
+ // - Op1 Explicit Use Memory RegClass(GR8)
+ // - Op2 Explicit Use Memory
+ // - Op3 Explicit Use Memory RegClass(GRH8)
+ // - Op4 Explicit Use Memory
+ // - Op5 Explicit Use Memory RegClass(SEGMENT_REG)
+ // - Var0 [Op0]
+ // - Var1 [Op1]
+ // - Var2 [Op2]
+ // - Var3 [Op3]
+ // - Var4 [Op4]
+ // - Var5 [Op5]
+ // - hasMemoryOperands
+ // - hasAliasingRegisters
const unsigned Opcode = llvm::X86::MOV32rm;
- const CodeTemplate CT = checkAndGetCodeTemplate(Opcode);
+ const auto CodeTemplates = checkAndGetCodeTemplates(Opcode);
+ ASSERT_THAT(CodeTemplates, SizeIs(1));
+ const auto &CT = CodeTemplates[0];
EXPECT_THAT(CT.Info, HasSubstr("no tied variables"));
+ EXPECT_THAT(CT.Execution, ExecutionMode::UNKNOWN);
ASSERT_THAT(CT.Instructions,
SizeIs(UopsSnippetGenerator::kMinNumDifferentAddresses));
const InstructionTemplate &IT = CT.Instructions[0];
@@ -240,6 +324,21 @@ TEST_F(UopsSnippetGeneratorTest, MemoryUse) {
TEST_F(UopsSnippetGeneratorTest, MemoryUse_Movsb) {
// MOVSB writes to scratch memory register.
+ // - MOVSB
+ // - Op0 Explicit Use Memory RegClass(GR8)
+ // - Op1 Explicit Use Memory RegClass(GR8)
+ // - Op2 Explicit Use Memory RegClass(SEGMENT_REG)
+ // - Op3 Implicit Def Reg(EDI)
+ // - Op4 Implicit Def Reg(ESI)
+ // - Op5 Implicit Use Reg(EDI)
+ // - Op6 Implicit Use Reg(ESI)
+ // - Op7 Implicit Use Reg(DF)
+ // - Var0 [Op0]
+ // - Var1 [Op1]
+ // - Var2 [Op2]
+ // - hasMemoryOperands
+ // - hasAliasingImplicitRegisters (execution is always serial)
+ // - hasAliasingRegisters
const unsigned Opcode = llvm::X86::MOVSB;
const Instruction Instr(State, Opcode);
auto Error = Generator.generateCodeTemplates(Instr).takeError();