blob: a833e1e22793b51444a1236cfc5553992db35f4a [file] [log] [blame]
Guillaume Chateletc9f727b2018-06-13 13:24:41 +00001//===-- SnippetGeneratorTest.cpp --------------------------------*- C++ -*-===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Guillaume Chateletc9f727b2018-06-13 13:24:41 +00006//
7//===----------------------------------------------------------------------===//
8
9#include "../Common/AssemblerUtils.h"
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000010#include "LlvmState.h"
11#include "MCInstrDescView.h"
Miloš Stojanović24b7b992020-01-17 14:28:54 +010012#include "ParallelSnippetGenerator.h"
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000013#include "RegisterAliasing.h"
Miloš Stojanović24b7b992020-01-17 14:28:54 +010014#include "SerialSnippetGenerator.h"
Clement Courbet81099012019-10-01 09:20:36 +000015#include "TestBase.h"
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000016#include "X86InstrInfo.h"
17
18#include <unordered_set>
19
Fangrui Song32401af2018-10-22 17:10:47 +000020namespace llvm {
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000021namespace exegesis {
Guillaume Chateletfb943542018-08-01 14:41:45 +000022
23void InitializeX86ExegesisTarget();
24
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000025namespace {
26
Guillaume Chatelet1ebb6752018-06-20 11:09:36 +000027using testing::AnyOf;
28using testing::ElementsAre;
Guillaume Chateletfcbb6f32018-10-17 11:37:28 +000029using testing::Gt;
Guillaume Chateletef6cef52018-06-20 08:52:30 +000030using testing::HasSubstr;
31using testing::Not;
32using testing::SizeIs;
Clement Courbeta51efc22018-06-25 13:12:02 +000033using testing::UnorderedElementsAre;
Guillaume Chateletef6cef52018-06-20 08:52:30 +000034
35MATCHER(IsInvalid, "") { return !arg.isValid(); }
36MATCHER(IsReg, "") { return arg.isReg(); }
37
Clement Courbet81099012019-10-01 09:20:36 +000038class X86SnippetGeneratorTest : public X86TestBase {
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000039protected:
Clement Courbet81099012019-10-01 09:20:36 +000040 X86SnippetGeneratorTest() : InstrInfo(State.getInstrInfo()) {}
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000041
Clement Courbetd422d3a2019-10-09 11:29:21 +000042 const MCInstrInfo &InstrInfo;
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000043};
44
Clement Courbetd939f6d2018-09-13 07:40:53 +000045template <typename SnippetGeneratorT>
Guillaume Chateletef6cef52018-06-20 08:52:30 +000046class SnippetGeneratorTest : public X86SnippetGeneratorTest {
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000047protected:
Clement Courbet2cd0f282019-10-08 14:30:24 +000048 SnippetGeneratorTest() : Generator(State, SnippetGenerator::Options()) {}
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000049
Guillaume Chateletfcbb6f32018-10-17 11:37:28 +000050 std::vector<CodeTemplate> checkAndGetCodeTemplates(unsigned Opcode) {
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000051 randomGenerator().seed(0); // Initialize seed.
Guillaume Chateletda11b852018-10-24 11:55:06 +000052 const Instruction &Instr = State.getIC().getInstr(Opcode);
Clement Courbet8ef97e12019-09-27 08:04:10 +000053 auto CodeTemplateOrError = Generator.generateCodeTemplates(
54 Instr, State.getRATC().emptyRegisters());
Guillaume Chatelete60866a2018-08-03 09:29:38 +000055 EXPECT_FALSE(CodeTemplateOrError.takeError()); // Valid configuration.
Guillaume Chateletfcbb6f32018-10-17 11:37:28 +000056 return std::move(CodeTemplateOrError.get());
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000057 }
58
Clement Courbetd939f6d2018-09-13 07:40:53 +000059 SnippetGeneratorT Generator;
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000060};
61
Miloš Stojanović24b7b992020-01-17 14:28:54 +010062using SerialSnippetGeneratorTest = SnippetGeneratorTest<SerialSnippetGenerator>;
Guillaume Chateletef6cef52018-06-20 08:52:30 +000063
Miloš Stojanović24b7b992020-01-17 14:28:54 +010064using ParallelSnippetGeneratorTest =
65 SnippetGeneratorTest<ParallelSnippetGenerator>;
Guillaume Chateletef6cef52018-06-20 08:52:30 +000066
Miloš Stojanović24b7b992020-01-17 14:28:54 +010067TEST_F(SerialSnippetGeneratorTest, ImplicitSelfDependencyThroughImplicitReg) {
Guillaume Chateletfcbb6f32018-10-17 11:37:28 +000068 // - ADC16i16
69 // - Op0 Explicit Use Immediate
70 // - Op1 Implicit Def Reg(AX)
71 // - Op2 Implicit Def Reg(EFLAGS)
72 // - Op3 Implicit Use Reg(AX)
73 // - Op4 Implicit Use Reg(EFLAGS)
74 // - Var0 [Op0]
75 // - hasAliasingImplicitRegisters (execution is always serial)
76 // - hasAliasingRegisters
Clement Courbetd422d3a2019-10-09 11:29:21 +000077 const unsigned Opcode = X86::ADC16i16;
78 EXPECT_THAT(InstrInfo.get(Opcode).getImplicitDefs()[0], X86::AX);
79 EXPECT_THAT(InstrInfo.get(Opcode).getImplicitDefs()[1], X86::EFLAGS);
80 EXPECT_THAT(InstrInfo.get(Opcode).getImplicitUses()[0], X86::AX);
81 EXPECT_THAT(InstrInfo.get(Opcode).getImplicitUses()[1], X86::EFLAGS);
Guillaume Chateletfcbb6f32018-10-17 11:37:28 +000082 const auto CodeTemplates = checkAndGetCodeTemplates(Opcode);
83 ASSERT_THAT(CodeTemplates, SizeIs(1));
84 const auto &CT = CodeTemplates[0];
85 EXPECT_THAT(CT.Execution, ExecutionMode::ALWAYS_SERIAL_IMPLICIT_REGS_ALIAS);
Guillaume Chatelete60866a2018-08-03 09:29:38 +000086 ASSERT_THAT(CT.Instructions, SizeIs(1));
Guillaume Chatelet70ac0192018-09-27 09:23:04 +000087 const InstructionTemplate &IT = CT.Instructions[0];
88 EXPECT_THAT(IT.getOpcode(), Opcode);
Guillaume Chatelet32d384c2019-12-18 12:08:38 +010089 ASSERT_THAT(IT.getVariableValues(), SizeIs(1)); // Imm.
90 EXPECT_THAT(IT.getVariableValues()[0], IsInvalid()) << "Immediate is not set";
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000091}
92
Miloš Stojanović24b7b992020-01-17 14:28:54 +010093TEST_F(SerialSnippetGeneratorTest, ImplicitSelfDependencyThroughTiedRegs) {
Guillaume Chateletfcbb6f32018-10-17 11:37:28 +000094 // - ADD16ri
95 // - Op0 Explicit Def RegClass(GR16)
96 // - Op1 Explicit Use RegClass(GR16) TiedToOp0
97 // - Op2 Explicit Use Immediate
98 // - Op3 Implicit Def Reg(EFLAGS)
99 // - Var0 [Op0,Op1]
100 // - Var1 [Op2]
101 // - hasTiedRegisters (execution is always serial)
102 // - hasAliasingRegisters
Clement Courbetd422d3a2019-10-09 11:29:21 +0000103 const unsigned Opcode = X86::ADD16ri;
104 EXPECT_THAT(InstrInfo.get(Opcode).getImplicitDefs()[0], X86::EFLAGS);
Guillaume Chateletfcbb6f32018-10-17 11:37:28 +0000105 const auto CodeTemplates = checkAndGetCodeTemplates(Opcode);
106 ASSERT_THAT(CodeTemplates, SizeIs(1));
107 const auto &CT = CodeTemplates[0];
108 EXPECT_THAT(CT.Execution, ExecutionMode::ALWAYS_SERIAL_TIED_REGS_ALIAS);
Guillaume Chatelete60866a2018-08-03 09:29:38 +0000109 ASSERT_THAT(CT.Instructions, SizeIs(1));
Guillaume Chatelet70ac0192018-09-27 09:23:04 +0000110 const InstructionTemplate &IT = CT.Instructions[0];
111 EXPECT_THAT(IT.getOpcode(), Opcode);
Guillaume Chatelet32d384c2019-12-18 12:08:38 +0100112 ASSERT_THAT(IT.getVariableValues(), SizeIs(2));
113 EXPECT_THAT(IT.getVariableValues()[0], IsInvalid()) << "Operand 1 is not set";
114 EXPECT_THAT(IT.getVariableValues()[1], IsInvalid()) << "Operand 2 is not set";
Guillaume Chateletc9f727b2018-06-13 13:24:41 +0000115}
116
Miloš Stojanović24b7b992020-01-17 14:28:54 +0100117TEST_F(SerialSnippetGeneratorTest, ImplicitSelfDependencyThroughExplicitRegs) {
Guillaume Chateletfcbb6f32018-10-17 11:37:28 +0000118 // - VXORPSrr
119 // - Op0 Explicit Def RegClass(VR128)
120 // - Op1 Explicit Use RegClass(VR128)
121 // - Op2 Explicit Use RegClass(VR128)
122 // - Var0 [Op0]
123 // - Var1 [Op1]
124 // - Var2 [Op2]
125 // - hasAliasingRegisters
Clement Courbetd422d3a2019-10-09 11:29:21 +0000126 const unsigned Opcode = X86::VXORPSrr;
Guillaume Chateletfcbb6f32018-10-17 11:37:28 +0000127 const auto CodeTemplates = checkAndGetCodeTemplates(Opcode);
128 ASSERT_THAT(CodeTemplates, SizeIs(1));
129 const auto &CT = CodeTemplates[0];
130 EXPECT_THAT(CT.Execution, ExecutionMode::SERIAL_VIA_EXPLICIT_REGS);
131 ASSERT_THAT(CT.Instructions, SizeIs(1));
Guillaume Chatelet70ac0192018-09-27 09:23:04 +0000132 const InstructionTemplate &IT = CT.Instructions[0];
133 EXPECT_THAT(IT.getOpcode(), Opcode);
Guillaume Chatelet32d384c2019-12-18 12:08:38 +0100134 ASSERT_THAT(IT.getVariableValues(), SizeIs(3));
135 EXPECT_THAT(IT.getVariableValues(),
Guillaume Chateletfcbb6f32018-10-17 11:37:28 +0000136 AnyOf(ElementsAre(IsReg(), IsInvalid(), IsReg()),
137 ElementsAre(IsReg(), IsReg(), IsInvalid())))
138 << "Op0 is either set to Op1 or to Op2";
139}
140
Miloš Stojanović24b7b992020-01-17 14:28:54 +0100141TEST_F(SerialSnippetGeneratorTest,
Clement Courbet8ef97e12019-09-27 08:04:10 +0000142 ImplicitSelfDependencyThroughExplicitRegsForbidAll) {
143 // - VXORPSrr
144 // - Op0 Explicit Def RegClass(VR128)
145 // - Op1 Explicit Use RegClass(VR128)
146 // - Op2 Explicit Use RegClass(VR128)
147 // - Var0 [Op0]
148 // - Var1 [Op1]
149 // - Var2 [Op2]
150 // - hasAliasingRegisters
Clement Courbetd422d3a2019-10-09 11:29:21 +0000151 const unsigned Opcode = X86::VXORPSrr;
Clement Courbet8ef97e12019-09-27 08:04:10 +0000152 randomGenerator().seed(0); // Initialize seed.
153 const Instruction &Instr = State.getIC().getInstr(Opcode);
154 auto AllRegisters = State.getRATC().emptyRegisters();
155 AllRegisters.flip();
156 auto Error = Generator.generateCodeTemplates(Instr, AllRegisters).takeError();
157 EXPECT_TRUE((bool)Error);
Clement Courbetd422d3a2019-10-09 11:29:21 +0000158 consumeError(std::move(Error));
Clement Courbet8ef97e12019-09-27 08:04:10 +0000159}
160
Miloš Stojanović24b7b992020-01-17 14:28:54 +0100161TEST_F(SerialSnippetGeneratorTest, DependencyThroughOtherOpcode) {
Guillaume Chateletfcbb6f32018-10-17 11:37:28 +0000162 // - CMP64rr
163 // - Op0 Explicit Use RegClass(GR64)
164 // - Op1 Explicit Use RegClass(GR64)
165 // - Op2 Implicit Def Reg(EFLAGS)
166 // - Var0 [Op0]
167 // - Var1 [Op1]
Clement Courbetd422d3a2019-10-09 11:29:21 +0000168 const unsigned Opcode = X86::CMP64rr;
Guillaume Chateletfcbb6f32018-10-17 11:37:28 +0000169 const auto CodeTemplates = checkAndGetCodeTemplates(Opcode);
170 ASSERT_THAT(CodeTemplates, SizeIs(Gt(1U))) << "Many templates are available";
171 for (const auto &CT : CodeTemplates) {
172 EXPECT_THAT(CT.Execution, ExecutionMode::SERIAL_VIA_NON_MEMORY_INSTR);
173 ASSERT_THAT(CT.Instructions, SizeIs(2));
174 const InstructionTemplate &IT = CT.Instructions[0];
175 EXPECT_THAT(IT.getOpcode(), Opcode);
Guillaume Chatelet32d384c2019-12-18 12:08:38 +0100176 ASSERT_THAT(IT.getVariableValues(), SizeIs(2));
177 EXPECT_THAT(IT.getVariableValues(),
178 AnyOf(ElementsAre(IsReg(), IsInvalid()),
179 ElementsAre(IsInvalid(), IsReg())));
Guillaume Chateletfcbb6f32018-10-17 11:37:28 +0000180 EXPECT_THAT(CT.Instructions[1].getOpcode(), Not(Opcode));
181 // TODO: check that the two instructions alias each other.
182 }
Guillaume Chateletc9f727b2018-06-13 13:24:41 +0000183}
184
Miloš Stojanović24b7b992020-01-17 14:28:54 +0100185TEST_F(SerialSnippetGeneratorTest, LAHF) {
Guillaume Chateletfcbb6f32018-10-17 11:37:28 +0000186 // - LAHF
187 // - Op0 Implicit Def Reg(AH)
188 // - Op1 Implicit Use Reg(EFLAGS)
Clement Courbetd422d3a2019-10-09 11:29:21 +0000189 const unsigned Opcode = X86::LAHF;
Guillaume Chateletfcbb6f32018-10-17 11:37:28 +0000190 const auto CodeTemplates = checkAndGetCodeTemplates(Opcode);
191 ASSERT_THAT(CodeTemplates, SizeIs(Gt(1U))) << "Many templates are available";
192 for (const auto &CT : CodeTemplates) {
193 EXPECT_THAT(CT.Execution, ExecutionMode::SERIAL_VIA_NON_MEMORY_INSTR);
194 ASSERT_THAT(CT.Instructions, SizeIs(2));
195 const InstructionTemplate &IT = CT.Instructions[0];
196 EXPECT_THAT(IT.getOpcode(), Opcode);
Guillaume Chatelet32d384c2019-12-18 12:08:38 +0100197 ASSERT_THAT(IT.getVariableValues(), SizeIs(0));
Guillaume Chateletfcbb6f32018-10-17 11:37:28 +0000198 }
Guillaume Chatelet60e3d582018-06-13 13:53:56 +0000199}
200
Clement Courbetd6f4cfd2020-01-21 10:12:13 +0100201TEST_F(SerialSnippetGeneratorTest, VCVTUSI642SDZrrb_Int) {
202 // - VCVTUSI642SDZrrb_Int
203 // - Op0 Explicit Def RegClass(VR128X)
204 // - Op1 Explicit Use RegClass(VR128X)
205 // - Op2 Explicit Use STATIC_ROUNDING
206 // - Op2 Explicit Use RegClass(GR64)
207 // - Op4 Implicit Use Reg(MXSCR)
208 const unsigned Opcode = X86::VCVTUSI642SDZrrb_Int;
209 const Instruction &Instr = State.getIC().getInstr(Opcode);
210 auto Configs =
211 Generator.generateConfigurations(Instr, State.getRATC().emptyRegisters());
212 ASSERT_FALSE(Configs.takeError());
213 ASSERT_THAT(*Configs, SizeIs(1));
214 const BenchmarkCode &BC = (*Configs)[0];
215 ASSERT_THAT(BC.Key.Instructions, SizeIs(1));
216 ASSERT_TRUE(BC.Key.Instructions[0].getOperand(3).isImm());
217}
218
Miloš Stojanović24b7b992020-01-17 14:28:54 +0100219TEST_F(ParallelSnippetGeneratorTest, ParallelInstruction) {
Guillaume Chateletfcbb6f32018-10-17 11:37:28 +0000220 // - BNDCL32rr
221 // - Op0 Explicit Use RegClass(BNDR)
222 // - Op1 Explicit Use RegClass(GR32)
223 // - Var0 [Op0]
224 // - Var1 [Op1]
Clement Courbetd422d3a2019-10-09 11:29:21 +0000225 const unsigned Opcode = X86::BNDCL32rr;
Guillaume Chateletfcbb6f32018-10-17 11:37:28 +0000226 const auto CodeTemplates = checkAndGetCodeTemplates(Opcode);
227 ASSERT_THAT(CodeTemplates, SizeIs(1));
228 const auto &CT = CodeTemplates[0];
Guillaume Chatelete60866a2018-08-03 09:29:38 +0000229 EXPECT_THAT(CT.Info, HasSubstr("parallel"));
Guillaume Chateletfcbb6f32018-10-17 11:37:28 +0000230 EXPECT_THAT(CT.Execution, ExecutionMode::UNKNOWN);
Guillaume Chatelete60866a2018-08-03 09:29:38 +0000231 ASSERT_THAT(CT.Instructions, SizeIs(1));
Guillaume Chatelet70ac0192018-09-27 09:23:04 +0000232 const InstructionTemplate &IT = CT.Instructions[0];
233 EXPECT_THAT(IT.getOpcode(), Opcode);
Guillaume Chatelet32d384c2019-12-18 12:08:38 +0100234 ASSERT_THAT(IT.getVariableValues(), SizeIs(2));
235 EXPECT_THAT(IT.getVariableValues()[0], IsInvalid());
236 EXPECT_THAT(IT.getVariableValues()[1], IsInvalid());
Guillaume Chateletc9f727b2018-06-13 13:24:41 +0000237}
238
Miloš Stojanović24b7b992020-01-17 14:28:54 +0100239TEST_F(ParallelSnippetGeneratorTest, SerialInstruction) {
Guillaume Chateletfcbb6f32018-10-17 11:37:28 +0000240 // - CDQ
241 // - Op0 Implicit Def Reg(EAX)
242 // - Op1 Implicit Def Reg(EDX)
243 // - Op2 Implicit Use Reg(EAX)
244 // - hasAliasingImplicitRegisters (execution is always serial)
245 // - hasAliasingRegisters
Clement Courbetd422d3a2019-10-09 11:29:21 +0000246 const unsigned Opcode = X86::CDQ;
Guillaume Chateletfcbb6f32018-10-17 11:37:28 +0000247 const auto CodeTemplates = checkAndGetCodeTemplates(Opcode);
248 ASSERT_THAT(CodeTemplates, SizeIs(1));
249 const auto &CT = CodeTemplates[0];
Guillaume Chatelete60866a2018-08-03 09:29:38 +0000250 EXPECT_THAT(CT.Info, HasSubstr("serial"));
Guillaume Chateletfcbb6f32018-10-17 11:37:28 +0000251 EXPECT_THAT(CT.Execution, ExecutionMode::UNKNOWN);
Guillaume Chatelete60866a2018-08-03 09:29:38 +0000252 ASSERT_THAT(CT.Instructions, SizeIs(1));
Guillaume Chatelet70ac0192018-09-27 09:23:04 +0000253 const InstructionTemplate &IT = CT.Instructions[0];
254 EXPECT_THAT(IT.getOpcode(), Opcode);
Guillaume Chatelet32d384c2019-12-18 12:08:38 +0100255 ASSERT_THAT(IT.getVariableValues(), SizeIs(0));
Guillaume Chateletc9f727b2018-06-13 13:24:41 +0000256}
257
Miloš Stojanović24b7b992020-01-17 14:28:54 +0100258TEST_F(ParallelSnippetGeneratorTest, StaticRenaming) {
Craig Toppere0bfeb52019-04-05 19:27:41 +0000259 // CMOV32rr has tied variables, we enumerate the possible values to execute
Guillaume Chateletc9f727b2018-06-13 13:24:41 +0000260 // as many in parallel as possible.
261
Craig Toppere0bfeb52019-04-05 19:27:41 +0000262 // - CMOV32rr
Guillaume Chateletfcbb6f32018-10-17 11:37:28 +0000263 // - Op0 Explicit Def RegClass(GR32)
264 // - Op1 Explicit Use RegClass(GR32) TiedToOp0
265 // - Op2 Explicit Use RegClass(GR32)
Craig Toppere0bfeb52019-04-05 19:27:41 +0000266 // - Op3 Explicit Use Immediate
Guillaume Chateletfcbb6f32018-10-17 11:37:28 +0000267 // - Op3 Implicit Use Reg(EFLAGS)
268 // - Var0 [Op0,Op1]
269 // - Var1 [Op2]
270 // - hasTiedRegisters (execution is always serial)
271 // - hasAliasingRegisters
Clement Courbetd422d3a2019-10-09 11:29:21 +0000272 const unsigned Opcode = X86::CMOV32rr;
Guillaume Chateletfcbb6f32018-10-17 11:37:28 +0000273 const auto CodeTemplates = checkAndGetCodeTemplates(Opcode);
274 ASSERT_THAT(CodeTemplates, SizeIs(1));
275 const auto &CT = CodeTemplates[0];
Guillaume Chatelete60866a2018-08-03 09:29:38 +0000276 EXPECT_THAT(CT.Info, HasSubstr("static renaming"));
Guillaume Chateletfcbb6f32018-10-17 11:37:28 +0000277 EXPECT_THAT(CT.Execution, ExecutionMode::UNKNOWN);
Guillaume Chateletc9f727b2018-06-13 13:24:41 +0000278 constexpr const unsigned kInstructionCount = 15;
Guillaume Chatelete60866a2018-08-03 09:29:38 +0000279 ASSERT_THAT(CT.Instructions, SizeIs(kInstructionCount));
Guillaume Chateletc9f727b2018-06-13 13:24:41 +0000280 std::unordered_set<unsigned> AllDefRegisters;
Guillaume Chatelet70ac0192018-09-27 09:23:04 +0000281 for (const auto &IT : CT.Instructions) {
Guillaume Chatelet32d384c2019-12-18 12:08:38 +0100282 ASSERT_THAT(IT.getVariableValues(), SizeIs(3));
283 AllDefRegisters.insert(IT.getVariableValues()[0].getReg());
Guillaume Chateletef6cef52018-06-20 08:52:30 +0000284 }
285 EXPECT_THAT(AllDefRegisters, SizeIs(kInstructionCount))
Guillaume Chateletc9f727b2018-06-13 13:24:41 +0000286 << "Each instruction writes to a different register";
287}
288
Miloš Stojanović24b7b992020-01-17 14:28:54 +0100289TEST_F(ParallelSnippetGeneratorTest, NoTiedVariables) {
Guillaume Chateletc9f727b2018-06-13 13:24:41 +0000290 // CMOV_GR32 has no tied variables, we make sure def and use are different
291 // from each other.
292
Guillaume Chateletfcbb6f32018-10-17 11:37:28 +0000293 // - CMOV_GR32
294 // - Op0 Explicit Def RegClass(GR32)
295 // - Op1 Explicit Use RegClass(GR32)
296 // - Op2 Explicit Use RegClass(GR32)
297 // - Op3 Explicit Use Immediate
298 // - Op4 Implicit Use Reg(EFLAGS)
299 // - Var0 [Op0]
300 // - Var1 [Op1]
301 // - Var2 [Op2]
302 // - Var3 [Op3]
303 // - hasAliasingRegisters
Clement Courbetd422d3a2019-10-09 11:29:21 +0000304 const unsigned Opcode = X86::CMOV_GR32;
Guillaume Chateletfcbb6f32018-10-17 11:37:28 +0000305 const auto CodeTemplates = checkAndGetCodeTemplates(Opcode);
306 ASSERT_THAT(CodeTemplates, SizeIs(1));
307 const auto &CT = CodeTemplates[0];
Guillaume Chatelete60866a2018-08-03 09:29:38 +0000308 EXPECT_THAT(CT.Info, HasSubstr("no tied variables"));
Guillaume Chateletfcbb6f32018-10-17 11:37:28 +0000309 EXPECT_THAT(CT.Execution, ExecutionMode::UNKNOWN);
Guillaume Chatelete60866a2018-08-03 09:29:38 +0000310 ASSERT_THAT(CT.Instructions, SizeIs(1));
Guillaume Chatelet70ac0192018-09-27 09:23:04 +0000311 const InstructionTemplate &IT = CT.Instructions[0];
312 EXPECT_THAT(IT.getOpcode(), Opcode);
Guillaume Chatelet32d384c2019-12-18 12:08:38 +0100313 ASSERT_THAT(IT.getVariableValues(), SizeIs(4));
314 EXPECT_THAT(IT.getVariableValues()[0].getReg(),
315 Not(IT.getVariableValues()[1].getReg()))
Guillaume Chateletc9f727b2018-06-13 13:24:41 +0000316 << "Def is different from first Use";
Guillaume Chatelet32d384c2019-12-18 12:08:38 +0100317 EXPECT_THAT(IT.getVariableValues()[0].getReg(),
318 Not(IT.getVariableValues()[2].getReg()))
Guillaume Chateletc9f727b2018-06-13 13:24:41 +0000319 << "Def is different from second Use";
Guillaume Chatelet32d384c2019-12-18 12:08:38 +0100320 EXPECT_THAT(IT.getVariableValues()[3], IsInvalid());
Guillaume Chateletc9f727b2018-06-13 13:24:41 +0000321}
322
Miloš Stojanović24b7b992020-01-17 14:28:54 +0100323TEST_F(ParallelSnippetGeneratorTest, MemoryUse) {
Guillaume Chateletfb943542018-08-01 14:41:45 +0000324 // Mov32rm reads from memory.
Guillaume Chateletfcbb6f32018-10-17 11:37:28 +0000325 // - MOV32rm
326 // - Op0 Explicit Def RegClass(GR32)
327 // - Op1 Explicit Use Memory RegClass(GR8)
328 // - Op2 Explicit Use Memory
329 // - Op3 Explicit Use Memory RegClass(GRH8)
330 // - Op4 Explicit Use Memory
331 // - Op5 Explicit Use Memory RegClass(SEGMENT_REG)
332 // - Var0 [Op0]
333 // - Var1 [Op1]
334 // - Var2 [Op2]
335 // - Var3 [Op3]
336 // - Var4 [Op4]
337 // - Var5 [Op5]
338 // - hasMemoryOperands
339 // - hasAliasingRegisters
Clement Courbetd422d3a2019-10-09 11:29:21 +0000340 const unsigned Opcode = X86::MOV32rm;
Guillaume Chateletfcbb6f32018-10-17 11:37:28 +0000341 const auto CodeTemplates = checkAndGetCodeTemplates(Opcode);
342 ASSERT_THAT(CodeTemplates, SizeIs(1));
343 const auto &CT = CodeTemplates[0];
Guillaume Chatelete60866a2018-08-03 09:29:38 +0000344 EXPECT_THAT(CT.Info, HasSubstr("no tied variables"));
Guillaume Chateletfcbb6f32018-10-17 11:37:28 +0000345 EXPECT_THAT(CT.Execution, ExecutionMode::UNKNOWN);
Guillaume Chatelete60866a2018-08-03 09:29:38 +0000346 ASSERT_THAT(CT.Instructions,
Miloš Stojanović24b7b992020-01-17 14:28:54 +0100347 SizeIs(ParallelSnippetGenerator::kMinNumDifferentAddresses));
Guillaume Chatelet70ac0192018-09-27 09:23:04 +0000348 const InstructionTemplate &IT = CT.Instructions[0];
349 EXPECT_THAT(IT.getOpcode(), Opcode);
Guillaume Chatelet32d384c2019-12-18 12:08:38 +0100350 ASSERT_THAT(IT.getVariableValues(), SizeIs(6));
351 EXPECT_EQ(IT.getVariableValues()[2].getImm(), 1);
352 EXPECT_EQ(IT.getVariableValues()[3].getReg(), 0u);
353 EXPECT_EQ(IT.getVariableValues()[4].getImm(), 0);
354 EXPECT_EQ(IT.getVariableValues()[5].getReg(), 0u);
Guillaume Chateletfb943542018-08-01 14:41:45 +0000355}
356
Clement Courbet04fd2042020-01-22 15:49:10 +0100357TEST_F(ParallelSnippetGeneratorTest, MOV16ms) {
358 const unsigned Opcode = X86::MOV16ms;
359 const Instruction &Instr = State.getIC().getInstr(Opcode);
360 auto Err =
361 Generator.generateConfigurations(Instr, State.getRATC().emptyRegisters())
362 .takeError();
363 EXPECT_TRUE((bool)Err);
364 EXPECT_THAT(toString(std::move(Err)),
365 testing::HasSubstr("no available registers"));
366}
367
Clement Courbet8ef97e12019-09-27 08:04:10 +0000368class FakeSnippetGenerator : public SnippetGenerator {
369public:
Clement Courbet2cd0f282019-10-08 14:30:24 +0000370 FakeSnippetGenerator(const LLVMState &State, const Options &Opts)
371 : SnippetGenerator(State, Opts) {}
Clement Courbet8ef97e12019-09-27 08:04:10 +0000372
Guillaume Chatelet32d384c2019-12-18 12:08:38 +0100373 const Instruction &getInstr(unsigned Opcode) {
Clement Courbet8ef97e12019-09-27 08:04:10 +0000374 return State.getIC().getInstr(Opcode);
375 }
376
Guillaume Chatelet32d384c2019-12-18 12:08:38 +0100377 InstructionTemplate getInstructionTemplate(unsigned Opcode) {
378 return {&getInstr(Opcode)};
379 }
380
Clement Courbet8ef97e12019-09-27 08:04:10 +0000381private:
Clement Courbetd422d3a2019-10-09 11:29:21 +0000382 Expected<std::vector<CodeTemplate>>
Clement Courbet8ef97e12019-09-27 08:04:10 +0000383 generateCodeTemplates(const Instruction &, const BitVector &) const override {
Clement Courbetd422d3a2019-10-09 11:29:21 +0000384 return make_error<StringError>("not implemented", inconvertibleErrorCode());
Clement Courbet8ef97e12019-09-27 08:04:10 +0000385 }
386};
387
388using FakeSnippetGeneratorTest = SnippetGeneratorTest<FakeSnippetGenerator>;
389
390testing::Matcher<const RegisterValue &> IsRegisterValue(unsigned Reg,
Clement Courbetd422d3a2019-10-09 11:29:21 +0000391 APInt Value) {
Clement Courbet8ef97e12019-09-27 08:04:10 +0000392 return testing::AllOf(testing::Field(&RegisterValue::Register, Reg),
393 testing::Field(&RegisterValue::Value, Value));
394}
395
396TEST_F(FakeSnippetGeneratorTest, MemoryUse_Movsb) {
Guillaume Chateletfb943542018-08-01 14:41:45 +0000397 // MOVSB writes to scratch memory register.
Guillaume Chateletfcbb6f32018-10-17 11:37:28 +0000398 // - MOVSB
399 // - Op0 Explicit Use Memory RegClass(GR8)
400 // - Op1 Explicit Use Memory RegClass(GR8)
401 // - Op2 Explicit Use Memory RegClass(SEGMENT_REG)
402 // - Op3 Implicit Def Reg(EDI)
403 // - Op4 Implicit Def Reg(ESI)
404 // - Op5 Implicit Use Reg(EDI)
405 // - Op6 Implicit Use Reg(ESI)
406 // - Op7 Implicit Use Reg(DF)
407 // - Var0 [Op0]
408 // - Var1 [Op1]
409 // - Var2 [Op2]
410 // - hasMemoryOperands
411 // - hasAliasingImplicitRegisters (execution is always serial)
412 // - hasAliasingRegisters
Clement Courbetd422d3a2019-10-09 11:29:21 +0000413 const unsigned Opcode = X86::MOVSB;
Guillaume Chateletda11b852018-10-24 11:55:06 +0000414 const Instruction &Instr = State.getIC().getInstr(Opcode);
Clement Courbet9431b722019-09-27 12:56:24 +0000415 auto Error =
416 Generator.generateConfigurations(Instr, State.getRATC().emptyRegisters())
417 .takeError();
Guillaume Chateletfb943542018-08-01 14:41:45 +0000418 EXPECT_TRUE((bool)Error);
Clement Courbetd422d3a2019-10-09 11:29:21 +0000419 consumeError(std::move(Error));
Guillaume Chateletfb943542018-08-01 14:41:45 +0000420}
421
Guillaume Chateletc96a97b2018-09-20 12:22:18 +0000422TEST_F(FakeSnippetGeneratorTest, ComputeRegisterInitialValuesAdd16ri) {
Clement Courbeta51efc22018-06-25 13:12:02 +0000423 // ADD16ri:
424 // explicit def 0 : reg RegClass=GR16
425 // explicit use 1 : reg RegClass=GR16 | TIED_TO:0
426 // explicit use 2 : imm
427 // implicit def : EFLAGS
Guillaume Chatelet32d384c2019-12-18 12:08:38 +0100428 InstructionTemplate IT = Generator.getInstructionTemplate(X86::ADD16ri);
429 IT.getValueFor(IT.getInstr().Variables[0]) = MCOperand::createReg(X86::AX);
Guillaume Chatelet70ac0192018-09-27 09:23:04 +0000430 std::vector<InstructionTemplate> Snippet;
431 Snippet.push_back(std::move(IT));
Guillaume Chateletc96a97b2018-09-20 12:22:18 +0000432 const auto RIV = Generator.computeRegisterInitialValues(Snippet);
Clement Courbetd422d3a2019-10-09 11:29:21 +0000433 EXPECT_THAT(RIV, ElementsAre(IsRegisterValue(X86::AX, APInt())));
Clement Courbeta51efc22018-06-25 13:12:02 +0000434}
435
Guillaume Chateletc96a97b2018-09-20 12:22:18 +0000436TEST_F(FakeSnippetGeneratorTest, ComputeRegisterInitialValuesAdd64rr) {
Clement Courbeta51efc22018-06-25 13:12:02 +0000437 // ADD64rr:
438 // mov64ri rax, 42
439 // add64rr rax, rax, rbx
440 // -> only rbx needs defining.
Guillaume Chatelet70ac0192018-09-27 09:23:04 +0000441 std::vector<InstructionTemplate> Snippet;
Clement Courbeta51efc22018-06-25 13:12:02 +0000442 {
Guillaume Chatelet32d384c2019-12-18 12:08:38 +0100443 InstructionTemplate Mov = Generator.getInstructionTemplate(X86::MOV64ri);
444 Mov.getValueFor(Mov.getInstr().Variables[0]) =
445 MCOperand::createReg(X86::RAX);
446 Mov.getValueFor(Mov.getInstr().Variables[1]) = MCOperand::createImm(42);
Clement Courbeta51efc22018-06-25 13:12:02 +0000447 Snippet.push_back(std::move(Mov));
448 }
449 {
Guillaume Chatelet32d384c2019-12-18 12:08:38 +0100450 InstructionTemplate Add = Generator.getInstructionTemplate(X86::ADD64rr);
451 Add.getValueFor(Add.getInstr().Variables[0]) =
452 MCOperand::createReg(X86::RAX);
453 Add.getValueFor(Add.getInstr().Variables[1]) =
454 MCOperand::createReg(X86::RBX);
Clement Courbeta51efc22018-06-25 13:12:02 +0000455 Snippet.push_back(std::move(Add));
456 }
457
Guillaume Chateletc96a97b2018-09-20 12:22:18 +0000458 const auto RIV = Generator.computeRegisterInitialValues(Snippet);
Clement Courbetd422d3a2019-10-09 11:29:21 +0000459 EXPECT_THAT(RIV, ElementsAre(IsRegisterValue(X86::RBX, APInt())));
Clement Courbeta51efc22018-06-25 13:12:02 +0000460}
461
Guillaume Chateletc9f727b2018-06-13 13:24:41 +0000462} // namespace
463} // namespace exegesis
Fangrui Song32401af2018-10-22 17:10:47 +0000464} // namespace llvm