blob: aef137b16e372061814c11f84de763b99a051c9f [file] [log] [blame]
Guillaume Chateletc9f727b2018-06-13 13:24:41 +00001//===-- SnippetGeneratorTest.cpp --------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "../Common/AssemblerUtils.h"
11#include "Latency.h"
12#include "LlvmState.h"
13#include "MCInstrDescView.h"
14#include "RegisterAliasing.h"
15#include "Uops.h"
16#include "X86InstrInfo.h"
17
18#include <unordered_set>
19
20namespace exegesis {
21namespace {
22
Guillaume Chateletef6cef52018-06-20 08:52:30 +000023using testing::HasSubstr;
24using testing::Not;
25using testing::SizeIs;
26
27MATCHER(IsInvalid, "") { return !arg.isValid(); }
28MATCHER(IsReg, "") { return arg.isReg(); }
29
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000030class X86SnippetGeneratorTest : public ::testing::Test {
31protected:
32 X86SnippetGeneratorTest()
Guillaume Chateletb391f242018-06-13 14:07:36 +000033 : State("x86_64-unknown-linux", "haswell"),
34 MCInstrInfo(State.getInstrInfo()), MCRegisterInfo(State.getRegInfo()) {}
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000035
36 static void SetUpTestCase() {
37 LLVMInitializeX86TargetInfo();
38 LLVMInitializeX86TargetMC();
39 LLVMInitializeX86Target();
40 LLVMInitializeX86AsmPrinter();
41 }
42
43 const LLVMState State;
44 const llvm::MCInstrInfo &MCInstrInfo;
45 const llvm::MCRegisterInfo &MCRegisterInfo;
46};
47
Guillaume Chateletef6cef52018-06-20 08:52:30 +000048template <typename BenchmarkRunner>
49class SnippetGeneratorTest : public X86SnippetGeneratorTest {
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000050protected:
Guillaume Chateletef6cef52018-06-20 08:52:30 +000051 SnippetGeneratorTest() : Runner(State) {}
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000052
Guillaume Chateletef6cef52018-06-20 08:52:30 +000053 SnippetPrototype checkAndGetConfigurations(unsigned Opcode) {
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000054 randomGenerator().seed(0); // Initialize seed.
Guillaume Chateletef6cef52018-06-20 08:52:30 +000055 auto ProtoOrError = Runner.generatePrototype(Opcode);
56 EXPECT_FALSE(ProtoOrError.takeError()); // Valid configuration.
57 return std::move(ProtoOrError.get());
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000058 }
59
Guillaume Chateletef6cef52018-06-20 08:52:30 +000060 BenchmarkRunner Runner;
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000061};
62
Guillaume Chateletef6cef52018-06-20 08:52:30 +000063using LatencySnippetGeneratorTest =
64 SnippetGeneratorTest<LatencyBenchmarkRunner>;
65
66using UopsSnippetGeneratorTest = SnippetGeneratorTest<UopsBenchmarkRunner>;
67
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000068TEST_F(LatencySnippetGeneratorTest, ImplicitSelfDependency) {
69 // ADC16i16 self alias because of implicit use and def.
70
71 // explicit use 0 : imm
72 // implicit def : AX
73 // implicit def : EFLAGS
74 // implicit use : AX
75 // implicit use : EFLAGS
76 const unsigned Opcode = llvm::X86::ADC16i16;
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000077 EXPECT_THAT(MCInstrInfo.get(Opcode).getImplicitDefs()[0], llvm::X86::AX);
78 EXPECT_THAT(MCInstrInfo.get(Opcode).getImplicitDefs()[1], llvm::X86::EFLAGS);
79 EXPECT_THAT(MCInstrInfo.get(Opcode).getImplicitUses()[0], llvm::X86::AX);
80 EXPECT_THAT(MCInstrInfo.get(Opcode).getImplicitUses()[1], llvm::X86::EFLAGS);
Guillaume Chateletef6cef52018-06-20 08:52:30 +000081 const SnippetPrototype Proto = checkAndGetConfigurations(Opcode);
82 EXPECT_THAT(Proto.Explanation, HasSubstr("implicit"));
83 ASSERT_THAT(Proto.Snippet, SizeIs(1));
84 const InstructionInstance &II = Proto.Snippet[0];
85 EXPECT_THAT(II.getOpcode(), Opcode);
86 ASSERT_THAT(II.VariableValues, SizeIs(1)); // Imm.
87 EXPECT_THAT(II.VariableValues[0], IsInvalid()) << "Immediate is not set";
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000088}
89
90TEST_F(LatencySnippetGeneratorTest, ExplicitSelfDependency) {
91 // ADD16ri self alias because Op0 and Op1 are tied together.
92
93 // explicit def 0 : reg RegClass=GR16
94 // explicit use 1 : reg RegClass=GR16 | TIED_TO:0
95 // explicit use 2 : imm
96 // implicit def : EFLAGS
97 const unsigned Opcode = llvm::X86::ADD16ri;
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000098 EXPECT_THAT(MCInstrInfo.get(Opcode).getImplicitDefs()[0], llvm::X86::EFLAGS);
Guillaume Chateletef6cef52018-06-20 08:52:30 +000099 const SnippetPrototype Proto = checkAndGetConfigurations(Opcode);
100 EXPECT_THAT(Proto.Explanation, HasSubstr("explicit"));
101 ASSERT_THAT(Proto.Snippet, SizeIs(1));
102 const InstructionInstance &II = Proto.Snippet[0];
103 EXPECT_THAT(II.getOpcode(), Opcode);
104 ASSERT_THAT(II.VariableValues, SizeIs(2));
105 EXPECT_THAT(II.VariableValues[0], IsReg()) << "Operand 0 and 1";
106 EXPECT_THAT(II.VariableValues[1], IsInvalid()) << "Operand 2 is not set";
Guillaume Chateletc9f727b2018-06-13 13:24:41 +0000107}
108
109TEST_F(LatencySnippetGeneratorTest, DependencyThroughOtherOpcode) {
110 // CMP64rr
111 // explicit use 0 : reg RegClass=GR64
112 // explicit use 1 : reg RegClass=GR64
113 // implicit def : EFLAGS
114
115 const unsigned Opcode = llvm::X86::CMP64rr;
Guillaume Chateletef6cef52018-06-20 08:52:30 +0000116 const SnippetPrototype Proto = checkAndGetConfigurations(Opcode);
117 EXPECT_THAT(Proto.Explanation, HasSubstr("cycle through"));
118 ASSERT_THAT(Proto.Snippet, SizeIs(2));
119 const InstructionInstance &II = Proto.Snippet[0];
120 EXPECT_THAT(II.getOpcode(), Opcode);
121 ASSERT_THAT(II.VariableValues, SizeIs(2));
122 EXPECT_THAT(II.VariableValues[0], IsReg());
123 EXPECT_THAT(II.VariableValues[1], IsInvalid());
124 EXPECT_THAT(Proto.Snippet[1].getOpcode(), Not(Opcode));
Guillaume Chateletc9f727b2018-06-13 13:24:41 +0000125 // TODO: check that the two instructions alias each other.
126}
127
Guillaume Chatelet60e3d582018-06-13 13:53:56 +0000128TEST_F(LatencySnippetGeneratorTest, LAHF) {
129 const unsigned Opcode = llvm::X86::LAHF;
Guillaume Chateletef6cef52018-06-20 08:52:30 +0000130 const SnippetPrototype Proto = checkAndGetConfigurations(Opcode);
131 EXPECT_THAT(Proto.Explanation, HasSubstr("cycle through"));
132 ASSERT_THAT(Proto.Snippet, SizeIs(2));
133 const InstructionInstance &II = Proto.Snippet[0];
134 EXPECT_THAT(II.getOpcode(), Opcode);
135 ASSERT_THAT(II.VariableValues, SizeIs(0));
Guillaume Chatelet60e3d582018-06-13 13:53:56 +0000136}
137
Guillaume Chateletc9f727b2018-06-13 13:24:41 +0000138TEST_F(UopsSnippetGeneratorTest, ParallelInstruction) {
Guillaume Chateletef6cef52018-06-20 08:52:30 +0000139 // BNDCL32rr is parallel no matter what.
Guillaume Chateletc9f727b2018-06-13 13:24:41 +0000140
141 // explicit use 0 : reg RegClass=BNDR
142 // explicit use 1 : reg RegClass=GR32
143
144 const unsigned Opcode = llvm::X86::BNDCL32rr;
Guillaume Chateletef6cef52018-06-20 08:52:30 +0000145 const SnippetPrototype Proto = checkAndGetConfigurations(Opcode);
146 EXPECT_THAT(Proto.Explanation, HasSubstr("parallel"));
147 ASSERT_THAT(Proto.Snippet, SizeIs(1));
148 const InstructionInstance &II = Proto.Snippet[0];
149 EXPECT_THAT(II.getOpcode(), Opcode);
150 ASSERT_THAT(II.VariableValues, SizeIs(2));
151 EXPECT_THAT(II.VariableValues[0], IsInvalid());
152 EXPECT_THAT(II.VariableValues[1], IsInvalid());
Guillaume Chateletc9f727b2018-06-13 13:24:41 +0000153}
154
155TEST_F(UopsSnippetGeneratorTest, SerialInstruction) {
156 // CDQ is serial no matter what.
157
158 // implicit def : EAX
159 // implicit def : EDX
160 // implicit use : EAX
161 const unsigned Opcode = llvm::X86::CDQ;
Guillaume Chateletef6cef52018-06-20 08:52:30 +0000162 const SnippetPrototype Proto = checkAndGetConfigurations(Opcode);
163 EXPECT_THAT(Proto.Explanation, HasSubstr("serial"));
164 ASSERT_THAT(Proto.Snippet, SizeIs(1));
165 const InstructionInstance &II = Proto.Snippet[0];
166 EXPECT_THAT(II.getOpcode(), Opcode);
167 ASSERT_THAT(II.VariableValues, SizeIs(0));
Guillaume Chateletc9f727b2018-06-13 13:24:41 +0000168}
169
170TEST_F(UopsSnippetGeneratorTest, StaticRenaming) {
171 // CMOVA32rr has tied variables, we enumarate the possible values to execute
172 // as many in parallel as possible.
173
174 // explicit def 0 : reg RegClass=GR32
175 // explicit use 1 : reg RegClass=GR32 | TIED_TO:0
176 // explicit use 2 : reg RegClass=GR32
177 // implicit use : EFLAGS
178 const unsigned Opcode = llvm::X86::CMOVA32rr;
Guillaume Chateletef6cef52018-06-20 08:52:30 +0000179 const SnippetPrototype Proto = checkAndGetConfigurations(Opcode);
180 EXPECT_THAT(Proto.Explanation, HasSubstr("static renaming"));
Guillaume Chateletc9f727b2018-06-13 13:24:41 +0000181 constexpr const unsigned kInstructionCount = 15;
Guillaume Chateletef6cef52018-06-20 08:52:30 +0000182 ASSERT_THAT(Proto.Snippet, SizeIs(kInstructionCount));
Guillaume Chateletc9f727b2018-06-13 13:24:41 +0000183 std::unordered_set<unsigned> AllDefRegisters;
Guillaume Chateletef6cef52018-06-20 08:52:30 +0000184 for (const auto &II : Proto.Snippet) {
185 ASSERT_THAT(II.VariableValues, SizeIs(2));
186 AllDefRegisters.insert(II.VariableValues[0].getReg());
187 }
188 EXPECT_THAT(AllDefRegisters, SizeIs(kInstructionCount))
Guillaume Chateletc9f727b2018-06-13 13:24:41 +0000189 << "Each instruction writes to a different register";
190}
191
192TEST_F(UopsSnippetGeneratorTest, NoTiedVariables) {
193 // CMOV_GR32 has no tied variables, we make sure def and use are different
194 // from each other.
195
196 // explicit def 0 : reg RegClass=GR32
197 // explicit use 1 : reg RegClass=GR32
198 // explicit use 2 : reg RegClass=GR32
199 // explicit use 3 : imm
200 // implicit use : EFLAGS
201 const unsigned Opcode = llvm::X86::CMOV_GR32;
Guillaume Chateletef6cef52018-06-20 08:52:30 +0000202 const SnippetPrototype Proto = checkAndGetConfigurations(Opcode);
203 EXPECT_THAT(Proto.Explanation, HasSubstr("no tied variables"));
204 ASSERT_THAT(Proto.Snippet, SizeIs(1));
205 const InstructionInstance &II = Proto.Snippet[0];
206 EXPECT_THAT(II.getOpcode(), Opcode);
207 ASSERT_THAT(II.VariableValues, SizeIs(4));
208 EXPECT_THAT(II.VariableValues[0].getReg(), Not(II.VariableValues[1].getReg()))
Guillaume Chateletc9f727b2018-06-13 13:24:41 +0000209 << "Def is different from first Use";
Guillaume Chateletef6cef52018-06-20 08:52:30 +0000210 EXPECT_THAT(II.VariableValues[0].getReg(), Not(II.VariableValues[2].getReg()))
Guillaume Chateletc9f727b2018-06-13 13:24:41 +0000211 << "Def is different from second Use";
Guillaume Chateletef6cef52018-06-20 08:52:30 +0000212 EXPECT_THAT(II.VariableValues[3], IsInvalid());
Guillaume Chateletc9f727b2018-06-13 13:24:41 +0000213}
214
215} // namespace
216} // namespace exegesis