summaryrefslogtreecommitdiffstats
path: root/llvm/unittests/tools
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/unittests/tools')
-rw-r--r--llvm/unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp237
1 files changed, 168 insertions, 69 deletions
diff --git a/llvm/unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp b/llvm/unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp
index 6cc24a02cfc..4b3fa5455a3 100644
--- a/llvm/unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp
+++ b/llvm/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();
OpenPOWER on IntegriCloud