llvm-project

Форк
0
/
SnippetGeneratorTest.cpp 
551 строка · 20.8 Кб
1
//===-- SnippetGeneratorTest.cpp --------------------------------*- C++ -*-===//
2
//
3
// 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
6
//
7
//===----------------------------------------------------------------------===//
8

9
#include "../Common/AssemblerUtils.h"
10
#include "LlvmState.h"
11
#include "MCInstrDescView.h"
12
#include "ParallelSnippetGenerator.h"
13
#include "RegisterAliasing.h"
14
#include "SerialSnippetGenerator.h"
15
#include "TestBase.h"
16
#include "X86InstrInfo.h"
17
#include "llvm/ADT/SetOperations.h"
18

19
#include <unordered_set>
20

21
namespace llvm {
22
namespace exegesis {
23

24
void InitializeX86ExegesisTarget();
25

26
namespace {
27

28
using testing::AnyOf;
29
using testing::ElementsAre;
30
using testing::Gt;
31
using testing::HasSubstr;
32
using testing::IsEmpty;
33
using testing::Not;
34
using testing::SizeIs;
35

36
MATCHER(IsInvalid, "") { return !arg.isValid(); }
37
MATCHER(IsReg, "") { return arg.isReg(); }
38

39
template <typename SnippetGeneratorT>
40
class X86SnippetGeneratorTest : public X86TestBase {
41
protected:
42
  X86SnippetGeneratorTest() : Generator(State, SnippetGenerator::Options()),
43
	                      InstrInfo(State.getInstrInfo()) {}
44

45
  std::vector<CodeTemplate> checkAndGetCodeTemplates(unsigned Opcode) {
46
    randomGenerator().seed(0); // Initialize seed.
47
    const Instruction &Instr = State.getIC().getInstr(Opcode);
48
    auto CodeTemplateOrError = Generator.generateCodeTemplates(
49
        &Instr, State.getRATC().emptyRegisters());
50
    EXPECT_FALSE(CodeTemplateOrError.takeError()); // Valid configuration.
51
    return std::move(CodeTemplateOrError.get());
52
  }
53

54
  SnippetGeneratorT Generator;
55
  const MCInstrInfo &InstrInfo;
56
};
57

58
using X86SerialSnippetGeneratorTest = X86SnippetGeneratorTest<SerialSnippetGenerator>;
59

60
using X86ParallelSnippetGeneratorTest =
61
    X86SnippetGeneratorTest<ParallelSnippetGenerator>;
62

63
TEST_F(X86SerialSnippetGeneratorTest, ImplicitSelfDependencyThroughImplicitReg) {
64
  // - ADC16i16
65
  // - Op0 Explicit Use Immediate
66
  // - Op1 Implicit Def Reg(AX)
67
  // - Op2 Implicit Def Reg(EFLAGS)
68
  // - Op3 Implicit Use Reg(AX)
69
  // - Op4 Implicit Use Reg(EFLAGS)
70
  // - Var0 [Op0]
71
  // - hasAliasingImplicitRegisters (execution is always serial)
72
  // - hasAliasingRegisters
73
  const unsigned Opcode = X86::ADC16i16;
74
  EXPECT_THAT(InstrInfo.get(Opcode).implicit_defs()[0], X86::AX);
75
  EXPECT_THAT(InstrInfo.get(Opcode).implicit_defs()[1], X86::EFLAGS);
76
  EXPECT_THAT(InstrInfo.get(Opcode).implicit_uses()[0], X86::AX);
77
  EXPECT_THAT(InstrInfo.get(Opcode).implicit_uses()[1], X86::EFLAGS);
78
  const auto CodeTemplates = checkAndGetCodeTemplates(Opcode);
79
  ASSERT_THAT(CodeTemplates, SizeIs(1));
80
  const auto &CT = CodeTemplates[0];
81
  EXPECT_THAT(CT.Execution, ExecutionMode::ALWAYS_SERIAL_IMPLICIT_REGS_ALIAS);
82
  ASSERT_THAT(CT.Instructions, SizeIs(1));
83
  const InstructionTemplate &IT = CT.Instructions[0];
84
  EXPECT_THAT(IT.getOpcode(), Opcode);
85
  ASSERT_THAT(IT.getVariableValues(), SizeIs(1)); // Imm.
86
  EXPECT_THAT(IT.getVariableValues()[0], IsInvalid()) << "Immediate is not set";
87
}
88

89
TEST_F(X86SerialSnippetGeneratorTest, ImplicitSelfDependencyThroughTiedRegs) {
90
  // - ADD16ri
91
  // - Op0 Explicit Def RegClass(GR16)
92
  // - Op1 Explicit Use RegClass(GR16) TiedToOp0
93
  // - Op2 Explicit Use Immediate
94
  // - Op3 Implicit Def Reg(EFLAGS)
95
  // - Var0 [Op0,Op1]
96
  // - Var1 [Op2]
97
  // - hasTiedRegisters (execution is always serial)
98
  // - hasAliasingRegisters
99
  const unsigned Opcode = X86::ADD16ri;
100
  EXPECT_THAT(InstrInfo.get(Opcode).implicit_defs()[0], X86::EFLAGS);
101
  const auto CodeTemplates = checkAndGetCodeTemplates(Opcode);
102
  ASSERT_THAT(CodeTemplates, SizeIs(1));
103
  const auto &CT = CodeTemplates[0];
104
  EXPECT_THAT(CT.Execution, ExecutionMode::ALWAYS_SERIAL_TIED_REGS_ALIAS);
105
  ASSERT_THAT(CT.Instructions, SizeIs(1));
106
  const InstructionTemplate &IT = CT.Instructions[0];
107
  EXPECT_THAT(IT.getOpcode(), Opcode);
108
  ASSERT_THAT(IT.getVariableValues(), SizeIs(2));
109
  EXPECT_THAT(IT.getVariableValues()[0], IsInvalid()) << "Operand 1 is not set";
110
  EXPECT_THAT(IT.getVariableValues()[1], IsInvalid()) << "Operand 2 is not set";
111
}
112

113
TEST_F(X86SerialSnippetGeneratorTest, ImplicitSelfDependencyThroughExplicitRegs) {
114
  // - VXORPSrr
115
  // - Op0 Explicit Def RegClass(VR128)
116
  // - Op1 Explicit Use RegClass(VR128)
117
  // - Op2 Explicit Use RegClass(VR128)
118
  // - Var0 [Op0]
119
  // - Var1 [Op1]
120
  // - Var2 [Op2]
121
  // - hasAliasingRegisters
122
  const unsigned Opcode = X86::VXORPSrr;
123
  const auto CodeTemplates = checkAndGetCodeTemplates(Opcode);
124
  ASSERT_THAT(CodeTemplates, SizeIs(1));
125
  const auto &CT = CodeTemplates[0];
126
  EXPECT_THAT(CT.Execution, ExecutionMode::SERIAL_VIA_EXPLICIT_REGS);
127
  ASSERT_THAT(CT.Instructions, SizeIs(1));
128
  const InstructionTemplate &IT = CT.Instructions[0];
129
  EXPECT_THAT(IT.getOpcode(), Opcode);
130
  ASSERT_THAT(IT.getVariableValues(), SizeIs(3));
131
  EXPECT_THAT(IT.getVariableValues(),
132
              AnyOf(ElementsAre(IsReg(), IsInvalid(), IsReg()),
133
                    ElementsAre(IsReg(), IsReg(), IsInvalid())))
134
      << "Op0 is either set to Op1 or to Op2";
135
}
136

137
TEST_F(X86SerialSnippetGeneratorTest,
138
       ImplicitSelfDependencyThroughExplicitRegsForbidAll) {
139
  // - VXORPSrr
140
  // - Op0 Explicit Def RegClass(VR128)
141
  // - Op1 Explicit Use RegClass(VR128)
142
  // - Op2 Explicit Use RegClass(VR128)
143
  // - Var0 [Op0]
144
  // - Var1 [Op1]
145
  // - Var2 [Op2]
146
  // - hasAliasingRegisters
147
  const unsigned Opcode = X86::VXORPSrr;
148
  randomGenerator().seed(0); // Initialize seed.
149
  const Instruction &Instr = State.getIC().getInstr(Opcode);
150
  auto AllRegisters = State.getRATC().emptyRegisters();
151
  AllRegisters.flip();
152
  auto Error =
153
      Generator.generateCodeTemplates(&Instr, AllRegisters).takeError();
154
  EXPECT_TRUE((bool)Error);
155
  consumeError(std::move(Error));
156
}
157

158
TEST_F(X86SerialSnippetGeneratorTest,
159
       ImplicitSelfDependencyThroughExplicitRegsForbidAlmostAll) {
160
  // - VXORPSrr
161
  // - Op0 Explicit Def RegClass(VR128)
162
  // - Op1 Explicit Use RegClass(VR128)
163
  // - Op2 Explicit Use RegClass(VR128)
164
  // - Var0 [Op0]
165
  // - Var1 [Op1]
166
  // - Var2 [Op2]
167
  // - hasAliasingRegisters
168
  const unsigned Opcode = X86::VXORPSrr;
169
  randomGenerator().seed(0); // Initialize seed.
170
  const Instruction &Instr = State.getIC().getInstr(Opcode);
171
  auto ForbiddenRegisters = State.getRATC().emptyRegisters();
172
  ForbiddenRegisters.flip();
173
  ForbiddenRegisters.reset(X86::XMM0);
174
  auto Error = Generator.generateCodeTemplates(&Instr, ForbiddenRegisters);
175
  EXPECT_FALSE((bool)Error.takeError());
176
  auto CodeTemplates = std::move(Error.get());
177
  ASSERT_THAT(CodeTemplates, SizeIs(Gt(0U))) << "Templates are available";
178
  for (const auto &CT : CodeTemplates) {
179
    EXPECT_THAT(CT.Execution, ExecutionMode::SERIAL_VIA_EXPLICIT_REGS);
180
    ASSERT_THAT(CT.Instructions, SizeIs(1));
181
    const InstructionTemplate &IT = CT.Instructions[0];
182
    EXPECT_THAT(IT.getOpcode(), Opcode);
183
    ASSERT_THAT(IT.getVariableValues(), SizeIs(3));
184
    for (const auto &Var : IT.getVariableValues()) {
185
      if (Var.isReg()) {
186
        EXPECT_FALSE(ForbiddenRegisters[Var.getReg()]);
187
      }
188
    }
189
  }
190
}
191

192
TEST_F(X86SerialSnippetGeneratorTest, DependencyThroughOtherOpcode) {
193
  // - CMP64rr
194
  // - Op0 Explicit Use RegClass(GR64)
195
  // - Op1 Explicit Use RegClass(GR64)
196
  // - Op2 Implicit Def Reg(EFLAGS)
197
  // - Var0 [Op0]
198
  // - Var1 [Op1]
199
  const unsigned Opcode = X86::CMP64rr;
200
  const auto CodeTemplates = checkAndGetCodeTemplates(Opcode);
201
  ASSERT_THAT(CodeTemplates, SizeIs(Gt(1U))) << "Many templates are available";
202
  for (const auto &CT : CodeTemplates) {
203
    EXPECT_THAT(CT.Execution, ExecutionMode::SERIAL_VIA_NON_MEMORY_INSTR);
204
    ASSERT_THAT(CT.Instructions, SizeIs(2));
205
    const InstructionTemplate &IT = CT.Instructions[0];
206
    EXPECT_THAT(IT.getOpcode(), Opcode);
207
    ASSERT_THAT(IT.getVariableValues(), SizeIs(2));
208
    EXPECT_THAT(IT.getVariableValues(),
209
                AnyOf(ElementsAre(IsReg(), IsInvalid()),
210
                      ElementsAre(IsInvalid(), IsReg())));
211
    EXPECT_THAT(CT.Instructions[1].getOpcode(), Not(Opcode));
212
    // TODO: check that the two instructions alias each other.
213
  }
214
}
215

216
TEST_F(X86SerialSnippetGeneratorTest, LAHF) {
217
  // - LAHF
218
  // - Op0 Implicit Def Reg(AH)
219
  // - Op1 Implicit Use Reg(EFLAGS)
220
  const unsigned Opcode = X86::LAHF;
221
  const auto CodeTemplates = checkAndGetCodeTemplates(Opcode);
222
  ASSERT_THAT(CodeTemplates, SizeIs(Gt(1U))) << "Many templates are available";
223
  for (const auto &CT : CodeTemplates) {
224
    EXPECT_THAT(CT.Execution, ExecutionMode::SERIAL_VIA_NON_MEMORY_INSTR);
225
    ASSERT_THAT(CT.Instructions, SizeIs(2));
226
    const InstructionTemplate &IT = CT.Instructions[0];
227
    EXPECT_THAT(IT.getOpcode(), Opcode);
228
    ASSERT_THAT(IT.getVariableValues(), SizeIs(0));
229
  }
230
}
231

232
TEST_F(X86SerialSnippetGeneratorTest, VCVTUSI642SDZrrb_Int) {
233
  // - VCVTUSI642SDZrrb_Int
234
  // - Op0 Explicit Def RegClass(VR128X)
235
  // - Op1 Explicit Use RegClass(VR128X)
236
  // - Op2 Explicit Use STATIC_ROUNDING
237
  // - Op2 Explicit Use RegClass(GR64)
238
  // - Op4 Implicit Use Reg(MXSCR)
239
  const unsigned Opcode = X86::VCVTUSI642SDZrrb_Int;
240
  const Instruction &Instr = State.getIC().getInstr(Opcode);
241
  std::vector<BenchmarkCode> Configs;
242
  auto Error = Generator.generateConfigurations(
243
      &Instr, Configs, State.getRATC().emptyRegisters());
244
  ASSERT_FALSE(Error);
245
  ASSERT_THAT(Configs, SizeIs(1));
246
  const BenchmarkCode &BC = Configs[0];
247
  ASSERT_THAT(BC.Key.Instructions, SizeIs(1));
248
  ASSERT_TRUE(BC.Key.Instructions[0].getOperand(3).isImm());
249
}
250

251
TEST_F(X86ParallelSnippetGeneratorTest, SerialInstruction) {
252
  // - CDQ
253
  // - Op0 Implicit Def Reg(EAX)
254
  // - Op1 Implicit Def Reg(EDX)
255
  // - Op2 Implicit Use Reg(EAX)
256
  // - hasAliasingImplicitRegisters (execution is always serial)
257
  // - hasAliasingRegisters
258
  const unsigned Opcode = X86::CDQ;
259
  const auto CodeTemplates = checkAndGetCodeTemplates(Opcode);
260
  ASSERT_THAT(CodeTemplates, SizeIs(1));
261
  const auto &CT = CodeTemplates[0];
262
  EXPECT_THAT(CT.Info, HasSubstr("serial"));
263
  EXPECT_THAT(CT.Execution, ExecutionMode::UNKNOWN);
264
  ASSERT_THAT(CT.Instructions, SizeIs(1));
265
  const InstructionTemplate &IT = CT.Instructions[0];
266
  EXPECT_THAT(IT.getOpcode(), Opcode);
267
  ASSERT_THAT(IT.getVariableValues(), SizeIs(0));
268
}
269

270
TEST_F(X86ParallelSnippetGeneratorTest, ReadAfterWrite_CMOV32rr) {
271
  // CMOV32rr has tied variables, we enumerate the possible values to execute
272
  // as many in parallel as possible.
273

274
  // - CMOV32rr
275
  // - Op0 Explicit Def RegClass(GR32)
276
  // - Op1 Explicit Use RegClass(GR32) TiedToOp0
277
  // - Op2 Explicit Use RegClass(GR32)
278
  // - Op3 Explicit Use Immediate
279
  // - Op3 Implicit Use Reg(EFLAGS)
280
  // - Var0 [Op0,Op1]
281
  // - Var1 [Op2]
282
  // - hasTiedRegisters (execution is always serial)
283
  // - hasAliasingRegisters
284
  const unsigned Opcode = X86::CMOV32rr;
285
  const auto CodeTemplates = checkAndGetCodeTemplates(Opcode);
286
  ASSERT_THAT(CodeTemplates, SizeIs(2));
287
  for (const auto &CT : CodeTemplates) {
288
    EXPECT_THAT(CT.Info, HasSubstr("avoiding Read-After-Write issue"));
289
    EXPECT_THAT(CT.Execution, ExecutionMode::UNKNOWN);
290
    ASSERT_GT(CT.Instructions.size(), 1U);
291
    std::unordered_set<unsigned> AllDefRegisters;
292
    std::unordered_set<unsigned> AllUseRegisters;
293
    for (const auto &IT : CT.Instructions) {
294
      ASSERT_THAT(IT.getVariableValues(), SizeIs(3));
295
      AllDefRegisters.insert(IT.getVariableValues()[0].getReg());
296
      AllUseRegisters.insert(IT.getVariableValues()[1].getReg());
297
    }
298
    EXPECT_THAT(AllDefRegisters, SizeIs(CT.Instructions.size()))
299
        << "Each instruction writes to a different register";
300
    EXPECT_THAT(AllUseRegisters, Not(IsEmpty()))
301
        << "In total, some other registers are used";
302
    auto AllDefAndUseRegs = AllUseRegisters;
303
    llvm::set_intersect(AllDefAndUseRegs, AllDefRegisters); // A := A ^ B
304
    EXPECT_THAT(AllDefAndUseRegs, IsEmpty())
305
        << "No instruction uses any register defined by any of the "
306
           "instructions";
307
  }
308
}
309

310
TEST_F(X86ParallelSnippetGeneratorTest, ReadAfterWrite_VFMADD132PDr) {
311
  // VFMADD132PDr has tied variables, we enumerate the possible values
312
  // to execute as many in parallel as possible.
313

314
  // - VFMADD132PDr
315
  // - Op0 Explicit Def RegClass(XMM)
316
  // - Op1 Explicit Use RegClass(XMM) TiedToOp0
317
  // - Op2 Explicit Use RegClass(XMM)
318
  // - Op3 Explicit Use RegClass(XMM)
319
  // - Var0 [Op0,Op1]
320
  // - Var1 [Op2]
321
  // - Var2 [Op3]
322
  // - hasTiedRegisters (execution is always serial)
323
  // - hasAliasingRegisters
324
  const unsigned Opcode = X86::VFMADD132PDr;
325
  const auto CodeTemplates = checkAndGetCodeTemplates(Opcode);
326
  ASSERT_THAT(CodeTemplates, SizeIs(3));
327
  for (const auto &CT : CodeTemplates) {
328
    EXPECT_THAT(CT.Info, HasSubstr("avoiding Read-After-Write issue"));
329
    EXPECT_THAT(CT.Execution, ExecutionMode::UNKNOWN);
330
    ASSERT_GT(CT.Instructions.size(), 1U);
331
    std::unordered_set<unsigned> AllDefRegisters;
332
    std::unordered_set<unsigned> AllUseRegisters;
333
    for (const auto &IT : CT.Instructions) {
334
      ASSERT_THAT(IT.getVariableValues(), SizeIs(3));
335
      AllDefRegisters.insert(IT.getVariableValues()[0].getReg());
336
      AllUseRegisters.insert(IT.getVariableValues()[1].getReg());
337
      AllUseRegisters.insert(IT.getVariableValues()[2].getReg());
338
    }
339
    EXPECT_THAT(AllDefRegisters, SizeIs(CT.Instructions.size()))
340
        << "Each instruction writes to a different register";
341
    EXPECT_THAT(AllUseRegisters, Not(IsEmpty()))
342
        << "In total, some other registers are used";
343
    auto AllDefAndUseRegs = AllUseRegisters;
344
    llvm::set_intersect(AllDefAndUseRegs, AllDefRegisters); // A := A ^ B
345
    EXPECT_THAT(AllDefAndUseRegs, IsEmpty())
346
        << "No instruction uses any register defined by any of the "
347
           "instructions";
348
  }
349
}
350

351
TEST_F(X86ParallelSnippetGeneratorTest, NoTiedVariables) {
352
  // CMOV_GR32 has no tied variables, we make sure def and use are different
353
  // from each other.
354

355
  // - CMOV_GR32
356
  // - Op0 Explicit Def RegClass(GR32)
357
  // - Op1 Explicit Use RegClass(GR32)
358
  // - Op2 Explicit Use RegClass(GR32)
359
  // - Op3 Explicit Use Immediate
360
  // - Op4 Implicit Use Reg(EFLAGS)
361
  // - Var0 [Op0]
362
  // - Var1 [Op1]
363
  // - Var2 [Op2]
364
  // - Var3 [Op3]
365
  // - hasAliasingRegisters
366
  const unsigned Opcode = X86::CMOV_GR32;
367
  const auto CodeTemplates = checkAndGetCodeTemplates(Opcode);
368
  ASSERT_THAT(CodeTemplates, SizeIs(2));
369
  for (const auto &CT : CodeTemplates) {
370
    EXPECT_THAT(CT.Info, HasSubstr("no tied variables"));
371
    EXPECT_THAT(CT.Execution, ExecutionMode::UNKNOWN);
372
    ASSERT_THAT(CT.Instructions, SizeIs(1));
373
    const InstructionTemplate &IT = CT.Instructions[0];
374
    EXPECT_THAT(IT.getOpcode(), Opcode);
375
    ASSERT_THAT(IT.getVariableValues(), SizeIs(4));
376
    EXPECT_THAT(IT.getVariableValues()[0].getReg(),
377
                Not(IT.getVariableValues()[1].getReg()))
378
        << "Def is different from first Use";
379
    EXPECT_THAT(IT.getVariableValues()[0].getReg(),
380
                Not(IT.getVariableValues()[2].getReg()))
381
        << "Def is different from second Use";
382
    EXPECT_THAT(IT.getVariableValues()[3], IsInvalid());
383
  }
384
}
385

386
TEST_F(X86ParallelSnippetGeneratorTest, MemoryUse) {
387
  // Mov32rm reads from memory.
388
  // - MOV32rm
389
  // - Op0 Explicit Def RegClass(GR32)
390
  // - Op1 Explicit Use Memory RegClass(GR8)
391
  // - Op2 Explicit Use Memory
392
  // - Op3 Explicit Use Memory RegClass(GRH8)
393
  // - Op4 Explicit Use Memory
394
  // - Op5 Explicit Use Memory RegClass(SEGMENT_REG)
395
  // - Var0 [Op0]
396
  // - Var1 [Op1]
397
  // - Var2 [Op2]
398
  // - Var3 [Op3]
399
  // - Var4 [Op4]
400
  // - Var5 [Op5]
401
  // - hasMemoryOperands
402
  // - hasAliasingRegisters
403
  const unsigned Opcode = X86::MOV32rm;
404
  const auto CodeTemplates = checkAndGetCodeTemplates(Opcode);
405
  ASSERT_THAT(CodeTemplates, SizeIs(1));
406
  for (const auto &CT : CodeTemplates) {
407
    EXPECT_THAT(CT.Info, HasSubstr("no tied variables"));
408
    EXPECT_THAT(CT.Execution, ExecutionMode::UNKNOWN);
409
    ASSERT_THAT(CT.Instructions,
410
                SizeIs(ParallelSnippetGenerator::kMinNumDifferentAddresses));
411
    const InstructionTemplate &IT = CT.Instructions[0];
412
    EXPECT_THAT(IT.getOpcode(), Opcode);
413
    ASSERT_THAT(IT.getVariableValues(), SizeIs(6));
414
    EXPECT_EQ(IT.getVariableValues()[2].getImm(), 1);
415
    EXPECT_EQ(IT.getVariableValues()[3].getReg(), 0u);
416
    EXPECT_EQ(IT.getVariableValues()[4].getImm(), 0);
417
    EXPECT_EQ(IT.getVariableValues()[5].getReg(), 0u);
418
  }
419
}
420

421
TEST_F(X86ParallelSnippetGeneratorTest, MOV16ms) {
422
  const unsigned Opcode = X86::MOV16ms;
423
  const Instruction &Instr = State.getIC().getInstr(Opcode);
424
  std::vector<BenchmarkCode> Benchmarks;
425
  auto Err = Generator.generateConfigurations(&Instr, Benchmarks,
426
                                              State.getRATC().emptyRegisters());
427
  EXPECT_TRUE((bool)Err);
428
  EXPECT_THAT(toString(std::move(Err)),
429
              testing::HasSubstr("no available registers"));
430
}
431

432
TEST_F(X86ParallelSnippetGeneratorTest,
433
       AvoidSerializingThroughImplicitRegisters) {
434
  // MULX32rr implicitly uses EDX. We should not select that register to avoid
435
  // serialization.
436
  const unsigned Opcode = X86::MULX32rr;
437
  randomGenerator().seed(0); // Initialize seed.
438
  const Instruction &Instr = State.getIC().getInstr(Opcode);
439
  // Forbid all registers but RDX/EDX/DX/DH/DL. The only option would be to
440
  // choose that register, but that would serialize the instruction, so we
441
  // should be returning an error.
442
  auto AllRegisters = State.getRATC().emptyRegisters();
443
  AllRegisters.flip();
444
  AllRegisters.reset(X86::RDX);
445
  AllRegisters.reset(X86::EDX);
446
  AllRegisters.reset(X86::DX);
447
  AllRegisters.reset(X86::DH);
448
  AllRegisters.reset(X86::DL);
449
  auto Err = Generator.generateCodeTemplates(&Instr, AllRegisters);
450
  EXPECT_FALSE((bool)Err);
451
  EXPECT_THAT(toString(Err.takeError()),
452
              testing::HasSubstr("Failed to produce any snippet"));
453
}
454

455
class X86FakeSnippetGenerator : public SnippetGenerator {
456
public:
457
  X86FakeSnippetGenerator(const LLVMState &State, const Options &Opts)
458
      : SnippetGenerator(State, Opts) {}
459

460
  const Instruction &getInstr(unsigned Opcode) {
461
    return State.getIC().getInstr(Opcode);
462
  }
463

464
  InstructionTemplate getInstructionTemplate(unsigned Opcode) {
465
    return {&getInstr(Opcode)};
466
  }
467

468
private:
469
  Expected<std::vector<CodeTemplate>>
470
  generateCodeTemplates(InstructionTemplate, const BitVector &) const override {
471
    return make_error<StringError>("not implemented", inconvertibleErrorCode());
472
  }
473
};
474

475
using X86FakeSnippetGeneratorTest = X86SnippetGeneratorTest<X86FakeSnippetGenerator>;
476

477
testing::Matcher<const RegisterValue &> IsRegisterValue(unsigned Reg,
478
                                                        APInt Value) {
479
  return testing::AllOf(testing::Field(&RegisterValue::Register, Reg),
480
                        testing::Field(&RegisterValue::Value, Value));
481
}
482

483
TEST_F(X86FakeSnippetGeneratorTest, MemoryUse_Movsb) {
484
  // MOVSB writes to scratch memory register.
485
  // - MOVSB
486
  // - Op0 Explicit Use Memory RegClass(GR8)
487
  // - Op1 Explicit Use Memory RegClass(GR8)
488
  // - Op2 Explicit Use Memory RegClass(SEGMENT_REG)
489
  // - Op3 Implicit Def Reg(EDI)
490
  // - Op4 Implicit Def Reg(ESI)
491
  // - Op5 Implicit Use Reg(EDI)
492
  // - Op6 Implicit Use Reg(ESI)
493
  // - Op7 Implicit Use Reg(DF)
494
  // - Var0 [Op0]
495
  // - Var1 [Op1]
496
  // - Var2 [Op2]
497
  // - hasMemoryOperands
498
  // - hasAliasingImplicitRegisters (execution is always serial)
499
  // - hasAliasingRegisters
500
  const unsigned Opcode = X86::MOVSB;
501
  const Instruction &Instr = State.getIC().getInstr(Opcode);
502
  std::vector<BenchmarkCode> Benchmarks;
503
  auto Error = Generator.generateConfigurations(
504
      &Instr, Benchmarks, State.getRATC().emptyRegisters());
505
  EXPECT_TRUE((bool)Error);
506
  consumeError(std::move(Error));
507
}
508

509
TEST_F(X86FakeSnippetGeneratorTest, ComputeRegisterInitialValuesAdd16ri) {
510
  // ADD16ri:
511
  // explicit def 0       : reg RegClass=GR16
512
  // explicit use 1       : reg RegClass=GR16 | TIED_TO:0
513
  // explicit use 2       : imm
514
  // implicit def         : EFLAGS
515
  InstructionTemplate IT = Generator.getInstructionTemplate(X86::ADD16ri);
516
  IT.getValueFor(IT.getInstr().Variables[0]) = MCOperand::createReg(X86::AX);
517
  std::vector<InstructionTemplate> Snippet;
518
  Snippet.push_back(std::move(IT));
519
  const auto RIV = Generator.computeRegisterInitialValues(Snippet);
520
  EXPECT_THAT(RIV, ElementsAre(IsRegisterValue(X86::AX, APInt())));
521
}
522

523
TEST_F(X86FakeSnippetGeneratorTest, ComputeRegisterInitialValuesAdd64rr) {
524
  // ADD64rr:
525
  //  mov64ri rax, 42
526
  //  add64rr rax, rax, rbx
527
  // -> only rbx needs defining.
528
  std::vector<InstructionTemplate> Snippet;
529
  {
530
    InstructionTemplate Mov = Generator.getInstructionTemplate(X86::MOV64ri);
531
    Mov.getValueFor(Mov.getInstr().Variables[0]) =
532
        MCOperand::createReg(X86::RAX);
533
    Mov.getValueFor(Mov.getInstr().Variables[1]) = MCOperand::createImm(42);
534
    Snippet.push_back(std::move(Mov));
535
  }
536
  {
537
    InstructionTemplate Add = Generator.getInstructionTemplate(X86::ADD64rr);
538
    Add.getValueFor(Add.getInstr().Variables[0]) =
539
        MCOperand::createReg(X86::RAX);
540
    Add.getValueFor(Add.getInstr().Variables[1]) =
541
        MCOperand::createReg(X86::RBX);
542
    Snippet.push_back(std::move(Add));
543
  }
544

545
  const auto RIV = Generator.computeRegisterInitialValues(Snippet);
546
  EXPECT_THAT(RIV, ElementsAre(IsRegisterValue(X86::RBX, APInt())));
547
}
548

549
} // namespace
550
} // namespace exegesis
551
} // namespace llvm
552

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.