1//===- subzero/unittest/unittest/AssemblerX8632/TestUtil.h ------*- C++ -*-===//
2//
3//                        The Subzero Code Generator
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// Utility classes for testing the X8632 Assembler.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef ASSEMBLERX8632_TESTUTIL_H_
15#define ASSEMBLERX8632_TESTUTIL_H_
16
17#include "IceAssemblerX8632.h"
18#include "IceDefs.h"
19
20#include "gtest/gtest.h"
21
22#if defined(__unix__)
23#include <sys/mman.h>
24#elif defined(_WIN32)
25#define NOMINMAX
26#include <Windows.h>
27#else
28#error "Platform unsupported"
29#endif
30
31#include <cassert>
32
33namespace Ice {
34namespace X8632 {
35namespace Test {
36
37class AssemblerX8632TestBase : public ::testing::Test {
38protected:
39  using Address = AssemblerX8632::Traits::Address;
40  using Cond = AssemblerX8632::Traits::Cond;
41  using GPRRegister = AssemblerX8632::Traits::GPRRegister;
42  using ByteRegister = AssemblerX8632::Traits::ByteRegister;
43  using Label = ::Ice::X8632::Label;
44  using Traits = AssemblerX8632::Traits;
45  using XmmRegister = AssemblerX8632::Traits::XmmRegister;
46  using X87STRegister = AssemblerX8632::Traits::X87STRegister;
47
48  AssemblerX8632TestBase() { reset(); }
49
50  void reset() { Assembler = makeUnique<AssemblerX8632>(); }
51
52  AssemblerX8632 *assembler() const { return Assembler.get(); }
53
54  size_t codeBytesSize() const { return Assembler->getBufferView().size(); }
55
56  const uint8_t *codeBytes() const {
57    return static_cast<const uint8_t *>(
58        static_cast<const void *>(Assembler->getBufferView().data()));
59  }
60
61private:
62  std::unique_ptr<AssemblerX8632> Assembler;
63};
64
65// __ is a helper macro. It allows test cases to emit X8632 assembly
66// instructions with
67//
68//   __ mov(GPRRegister::Reg_Eax, 1);
69//   __ ret();
70//
71// and so on. The idea of having this was "stolen" from dart's unit tests.
72#define __ (this->assembler())->
73
74// AssemblerX8632LowLevelTest verify that the "basic" instructions the tests
75// rely on are encoded correctly. Therefore, instead of executing the assembled
76// code, these tests will verify that the assembled bytes are sane.
77class AssemblerX8632LowLevelTest : public AssemblerX8632TestBase {
78protected:
79  // verifyBytes is a template helper that takes a Buffer, and a variable number
80  // of bytes. As the name indicates, it is used to verify the bytes for an
81  // instruction encoding.
82  template <int N, int I> static bool verifyBytes(const uint8_t *) {
83    static_assert(I == N, "Invalid template instantiation.");
84    return true;
85  }
86
87  template <int N, int I = 0, typename... Args>
88  static bool verifyBytes(const uint8_t *Buffer, uint8_t Byte,
89                          Args... OtherBytes) {
90    static_assert(I < N, "Invalid template instantiation.");
91    EXPECT_EQ(Byte, Buffer[I]) << "Byte " << (I + 1) << " of " << N;
92    return verifyBytes<N, I + 1>(Buffer, OtherBytes...) && Buffer[I] == Byte;
93  }
94};
95
96// After these tests we should have a sane environment; we know the following
97// work:
98//
99//  (*) zeroing eax, ebx, ecx, edx, edi, and esi;
100//  (*) call $4 instruction (used for ip materialization);
101//  (*) register push and pop;
102//  (*) cmp reg, reg; and
103//  (*) returning from functions.
104//
105// We can now dive into testing each emitting method in AssemblerX8632. Each
106// test will emit some instructions for performing the test. The assembled
107// instructions will operate in a "safe" environment. All x86-32 registers are
108// spilled to the program stack, and the registers are then zeroed out, with the
109// exception of %esp and %ebp.
110//
111// The jitted code and the unittest code will share the same stack. Therefore,
112// test harnesses need to ensure it does not leave anything it pushed on the
113// stack.
114//
115// %ebp is initialized with a pointer for rIP-based addressing. This pointer is
116// used for position-independent access to a scratchpad area for use in tests.
117// This mechanism is used because the test framework needs to generate addresses
118// that work on both x86-32 and x86-64 hosts, but are encodable using our x86-32
119// assembler. This is made possible because the encoding for
120//
121//    pushq %rax (x86-64 only)
122//
123// is the same as the one for
124//
125//    pushl %eax (x86-32 only; not encodable in x86-64)
126//
127// Likewise, the encodings for
128//
129//    movl offset(%ebp), %reg (32-bit only)
130//    movl <src>, offset(%ebp) (32-bit only)
131//
132// and
133//
134//    movl offset(%rbp), %reg (64-bit only)
135//    movl <src>, offset(%rbp) (64-bit only)
136//
137// are also the same.
138//
139// We use a call instruction in order to generate a natural sized address on the
140// stack. Said address is then removed from the stack with a pop %rBP, which can
141// then be used to address memory safely in either x86-32 or x86-64, as long as
142// the test code does not perform any arithmetic operation that writes to %rBP.
143// This PC materialization technique is very common in x86-32 PIC.
144//
145// %rBP is used to provide the tests with a scratchpad area that can safely and
146// portably be written to and read from. This scratchpad area is also used to
147// store the "final" values in eax, ebx, ecx, edx, esi, and edi, allowing the
148// harnesses access to 6 "return values" instead of the usual single return
149// value supported by C++.
150//
151// The jitted code will look like the following:
152//
153// test:
154//       push %eax
155//       push %ebx
156//       push %ecx
157//       push %edx
158//       push %edi
159//       push %esi
160//       push %ebp
161//       call test$materialize_ip
162// test$materialize_ip:                           <<------- %eBP will point here
163//       pop  %ebp
164//       mov  $0, %eax
165//       mov  $0, %ebx
166//       mov  $0, %ecx
167//       mov  $0, %edx
168//       mov  $0, %edi
169//       mov  $0, %esi
170//
171//       << test code goes here >>
172//
173//       mov %eax, { 0 + $ScratchpadOffset}(%ebp)
174//       mov %ebx, { 4 + $ScratchpadOffset}(%ebp)
175//       mov %ecx, { 8 + $ScratchpadOffset}(%ebp)
176//       mov %edx, {12 + $ScratchpadOffset}(%ebp)
177//       mov %edi, {16 + $ScratchpadOffset}(%ebp)
178//       mov %esi, {20 + $ScratchpadOffset}(%ebp)
179//       mov %ebp, {24 + $ScratchpadOffset}(%ebp)
180//       mov %esp, {28 + $ScratchpadOffset}(%ebp)
181//       movups %xmm0, {32 + $ScratchpadOffset}(%ebp)
182//       movups %xmm1, {48 + $ScratchpadOffset}(%ebp)
183//       movups %xmm2, {64 + $ScratchpadOffset}(%ebp)
184//       movusp %xmm3, {80 + $ScratchpadOffset}(%ebp)
185//       movusp %xmm4, {96 + $ScratchpadOffset}(%ebp)
186//       movusp %xmm5, {112 + $ScratchpadOffset}(%ebp)
187//       movusp %xmm6, {128 + $ScratchpadOffset}(%ebp)
188//       movusp %xmm7, {144 + $ScratchpadOffset}(%ebp)
189//
190//       pop %ebp
191//       pop %esi
192//       pop %edi
193//       pop %edx
194//       pop %ecx
195//       pop %ebx
196//       pop %eax
197//       ret
198//
199//      << ... >>
200//
201// scratchpad:                              <<------- accessed via $Offset(%ebp)
202//
203//      << test scratch area >>
204//
205// TODO(jpp): test the
206//
207//    mov %reg, $Offset(%ebp)
208//    movups %xmm, $Offset(%ebp)
209//
210// encodings using the low level assembler test ensuring that the register
211// values can be written to the scratchpad area.
212class AssemblerX8632Test : public AssemblerX8632TestBase {
213protected:
214  // Dqword is used to represent 128-bit data types. The Dqword's contents are
215  // the same as the contents read from memory. Tests can then use the union
216  // members to verify the tests' outputs.
217  //
218  // NOTE: We want sizeof(Dqword) == sizeof(uint64_t) * 2. In other words, we
219  // want Dqword's contents to be **exactly** what the memory contents were so
220  // that we can do, e.g.,
221  //
222  // ...
223  // float Ret[4];
224  // // populate Ret
225  // return *reinterpret_cast<Dqword *>(&Ret);
226  //
227  // While being an ugly hack, this kind of return statements are used
228  // extensively in the PackedArith (see below) class.
229  union Dqword {
230    template <typename T0, typename T1, typename T2, typename T3,
231              typename = typename std::enable_if<
232                  std::is_floating_point<T0>::value>::type>
233    Dqword(T0 F0, T1 F1, T2 F2, T3 F3) {
234      F32[0] = F0;
235      F32[1] = F1;
236      F32[2] = F2;
237      F32[3] = F3;
238    }
239
240    template <typename T>
241    Dqword(typename std::enable_if<std::is_same<T, int32_t>::value, T>::type I0,
242           T I1, T I2, T I3) {
243      I32[0] = I0;
244      I32[1] = I1;
245      I32[2] = I2;
246      I32[3] = I3;
247    }
248
249    template <typename T>
250    Dqword(typename std::enable_if<std::is_same<T, uint64_t>::value, T>::type
251               U64_0,
252           T U64_1) {
253      U64[0] = U64_0;
254      U64[1] = U64_1;
255    }
256
257    template <typename T>
258    Dqword(typename std::enable_if<std::is_same<T, double>::value, T>::type D0,
259           T D1) {
260      F64[0] = D0;
261      F64[1] = D1;
262    }
263
264    bool operator==(const Dqword &Rhs) const {
265      return std::memcmp(this, &Rhs, sizeof(*this)) == 0;
266    }
267
268    double F64[2];
269    uint64_t U64[2];
270    int64_t I64[2];
271
272    float F32[4];
273    uint32_t U32[4];
274    int32_t I32[4];
275
276    uint16_t U16[8];
277    int16_t I16[8];
278
279    uint8_t U8[16];
280    int8_t I8[16];
281
282  private:
283    Dqword() = delete;
284  };
285
286  // As stated, we want this condition to hold, so we assert.
287  static_assert(sizeof(Dqword) == 2 * sizeof(uint64_t),
288                "Dqword has the wrong size.");
289
290  // PackedArith is an interface provider for Dqwords. PackedArith's C argument
291  // is the undelying Dqword's type, which is then used so that we can define
292  // operators in terms of C++ operators on the underlying elements' type.
293  template <typename C> class PackedArith {
294  public:
295    static constexpr uint32_t N = sizeof(Dqword) / sizeof(C);
296    static_assert(N * sizeof(C) == sizeof(Dqword),
297                  "Invalid template paramenter.");
298    static_assert((N & 1) == 0, "N should be divisible by 2");
299
300#define DefinePackedComparisonOperator(Op)                                     \
301  template <typename Container = C, int Size = N>                              \
302  typename std::enable_if<std::is_floating_point<Container>::value,            \
303                          Dqword>::type                                        \
304  operator Op(const Dqword &Rhs) const {                                       \
305    using ElemType =                                                           \
306        typename std::conditional<std::is_same<float, Container>::value,       \
307                                  int32_t, int64_t>::type;                     \
308    static_assert(sizeof(ElemType) == sizeof(Container),                       \
309                  "Check ElemType definition.");                               \
310    const ElemType *const RhsPtr =                                             \
311        reinterpret_cast<const ElemType *const>(&Rhs);                         \
312    const ElemType *const LhsPtr =                                             \
313        reinterpret_cast<const ElemType *const>(&Lhs);                         \
314    ElemType Ret[N];                                                           \
315    for (uint32_t i = 0; i < N; ++i) {                                         \
316      Ret[i] = (LhsPtr[i] Op RhsPtr[i]) ? -1 : 0;                              \
317    }                                                                          \
318    return *reinterpret_cast<Dqword *>(&Ret);                                  \
319  }
320
321    DefinePackedComparisonOperator(< );
322    DefinePackedComparisonOperator(<= );
323    DefinePackedComparisonOperator(> );
324    DefinePackedComparisonOperator(>= );
325    DefinePackedComparisonOperator(== );
326    DefinePackedComparisonOperator(!= );
327
328#undef DefinePackedComparisonOperator
329
330#define DefinePackedOrdUnordComparisonOperator(Op, Ordered)                    \
331  template <typename Container = C, int Size = N>                              \
332  typename std::enable_if<std::is_floating_point<Container>::value,            \
333                          Dqword>::type                                        \
334  Op(const Dqword &Rhs) const {                                                \
335    using ElemType =                                                           \
336        typename std::conditional<std::is_same<float, Container>::value,       \
337                                  int32_t, int64_t>::type;                     \
338    static_assert(sizeof(ElemType) == sizeof(Container),                       \
339                  "Check ElemType definition.");                               \
340    const Container *const RhsPtr =                                            \
341        reinterpret_cast<const Container *const>(&Rhs);                        \
342    const Container *const LhsPtr =                                            \
343        reinterpret_cast<const Container *const>(&Lhs);                        \
344    ElemType Ret[N];                                                           \
345    for (uint32_t i = 0; i < N; ++i) {                                         \
346      Ret[i] = (!(LhsPtr[i] == LhsPtr[i]) || !(RhsPtr[i] == RhsPtr[i])) !=     \
347                       (Ordered)                                               \
348                   ? -1                                                        \
349                   : 0;                                                        \
350    }                                                                          \
351    return *reinterpret_cast<Dqword *>(&Ret);                                  \
352  }
353
354    DefinePackedOrdUnordComparisonOperator(ord, true);
355    DefinePackedOrdUnordComparisonOperator(unord, false);
356#undef DefinePackedOrdUnordComparisonOperator
357
358#define DefinePackedArithOperator(Op, RhsIndexChanges, NeedsInt)               \
359  template <typename Container = C, int Size = N>                              \
360  Dqword operator Op(const Dqword &Rhs) const {                                \
361    using ElemTypeForFp = typename std::conditional<                           \
362        !(NeedsInt), Container,                                                \
363        typename std::conditional<                                             \
364            std::is_same<Container, float>::value, uint32_t,                   \
365            typename std::conditional<std::is_same<Container, double>::value,  \
366                                      uint64_t, void>::type>::type>::type;     \
367    using ElemType =                                                           \
368        typename std::conditional<std::is_integral<Container>::value,          \
369                                  Container, ElemTypeForFp>::type;             \
370    static_assert(!std::is_same<void, ElemType>::value,                        \
371                  "Check ElemType definition.");                               \
372    const ElemType *const RhsPtr =                                             \
373        reinterpret_cast<const ElemType *const>(&Rhs);                         \
374    const ElemType *const LhsPtr =                                             \
375        reinterpret_cast<const ElemType *const>(&Lhs);                         \
376    ElemType Ret[N];                                                           \
377    for (uint32_t i = 0; i < N; ++i) {                                         \
378      Ret[i] = LhsPtr[i] Op RhsPtr[(RhsIndexChanges) ? i : 0];                 \
379    }                                                                          \
380    return *reinterpret_cast<Dqword *>(&Ret);                                  \
381  }
382
383    DefinePackedArithOperator(>>, false, true);
384    DefinePackedArithOperator(<<, false, true);
385    DefinePackedArithOperator(+, true, false);
386    DefinePackedArithOperator(-, true, false);
387    DefinePackedArithOperator(/, true, false);
388    DefinePackedArithOperator(&, true, true);
389    DefinePackedArithOperator(|, true, true);
390    DefinePackedArithOperator (^, true, true);
391
392#undef DefinePackedArithOperator
393
394#define DefinePackedArithShiftImm(Op)                                          \
395  template <typename Container = C, int Size = N>                              \
396  Dqword operator Op(uint8_t imm) const {                                      \
397    const Container *const LhsPtr =                                            \
398        reinterpret_cast<const Container *const>(&Lhs);                        \
399    Container Ret[N];                                                          \
400    for (uint32_t i = 0; i < N; ++i) {                                         \
401      Ret[i] = LhsPtr[i] Op imm;                                               \
402    }                                                                          \
403    return *reinterpret_cast<Dqword *>(&Ret);                                  \
404  }
405
406    DefinePackedArithShiftImm(>> );
407    DefinePackedArithShiftImm(<< );
408
409#undef DefinePackedArithShiftImm
410
411    template <typename Container = C, int Size = N>
412    typename std::enable_if<std::is_signed<Container>::value ||
413                                std::is_floating_point<Container>::value,
414                            Dqword>::type
415    operator*(const Dqword &Rhs) const {
416      static_assert((std::is_integral<Container>::value &&
417                     sizeof(Container) < sizeof(uint64_t)) ||
418                        std::is_floating_point<Container>::value,
419                    "* is only defined for i(8|16|32), and fp types.");
420
421      const Container *const RhsPtr =
422          reinterpret_cast<const Container *const>(&Rhs);
423      const Container *const LhsPtr =
424          reinterpret_cast<const Container *const>(&Lhs);
425      Container Ret[Size];
426      for (uint32_t i = 0; i < Size; ++i) {
427        Ret[i] = LhsPtr[i] * RhsPtr[i];
428      }
429      return *reinterpret_cast<Dqword *>(&Ret);
430    }
431
432    template <typename Container = C, int Size = N,
433              typename = typename std::enable_if<
434                  !std::is_signed<Container>::value>::type>
435    Dqword operator*(const Dqword &Rhs) const {
436      static_assert(std::is_integral<Container>::value &&
437                        sizeof(Container) < sizeof(uint64_t),
438                    "* is only defined for ui(8|16|32)");
439      using NextType = typename std::conditional<
440          sizeof(Container) == 1, uint16_t,
441          typename std::conditional<sizeof(Container) == 2, uint32_t,
442                                    uint64_t>::type>::type;
443      static_assert(sizeof(Container) * 2 == sizeof(NextType),
444                    "Unexpected size");
445
446      const Container *const RhsPtr =
447          reinterpret_cast<const Container *const>(&Rhs);
448      const Container *const LhsPtr =
449          reinterpret_cast<const Container *const>(&Lhs);
450      NextType Ret[Size / 2];
451      for (uint32_t i = 0; i < Size; i += 2) {
452        Ret[i / 2] =
453            static_cast<NextType>(LhsPtr[i]) * static_cast<NextType>(RhsPtr[i]);
454      }
455      return *reinterpret_cast<Dqword *>(&Ret);
456    }
457
458    template <typename Container = C, int Size = N>
459    PackedArith<Container> operator~() const {
460      const Container *const LhsPtr =
461          reinterpret_cast<const Container *const>(&Lhs);
462      Container Ret[Size];
463      for (uint32_t i = 0; i < Size; ++i) {
464        Ret[i] = ~LhsPtr[i];
465      }
466      return PackedArith<Container>(*reinterpret_cast<Dqword *>(&Ret));
467    }
468
469#define MinMaxOperations(Name, Suffix)                                         \
470  template <typename Container = C, int Size = N>                              \
471  Dqword Name##Suffix(const Dqword &Rhs) const {                               \
472    static_assert(std::is_floating_point<Container>::value,                    \
473                  #Name #Suffix "ps is only available for fp.");               \
474    const Container *const RhsPtr =                                            \
475        reinterpret_cast<const Container *const>(&Rhs);                        \
476    const Container *const LhsPtr =                                            \
477        reinterpret_cast<const Container *const>(&Lhs);                        \
478    Container Ret[Size];                                                       \
479    for (uint32_t i = 0; i < Size; ++i) {                                      \
480      Ret[i] = std::Name(LhsPtr[i], RhsPtr[i]);                                \
481    }                                                                          \
482    return *reinterpret_cast<Dqword *>(&Ret);                                  \
483  }
484
485    MinMaxOperations(max, ps);
486    MinMaxOperations(max, pd);
487    MinMaxOperations(min, ps);
488    MinMaxOperations(min, pd);
489#undef MinMaxOperations
490
491    template <typename Container = C, int Size = N>
492    Dqword blendWith(const Dqword &Rhs, const Dqword &Mask) const {
493      using MaskType = typename std::conditional<
494          sizeof(Container) == 1, int8_t,
495          typename std::conditional<sizeof(Container) == 2, int16_t,
496                                    int32_t>::type>::type;
497      static_assert(sizeof(MaskType) == sizeof(Container),
498                    "MaskType has the wrong size.");
499      const Container *const RhsPtr =
500          reinterpret_cast<const Container *const>(&Rhs);
501      const Container *const LhsPtr =
502          reinterpret_cast<const Container *const>(&Lhs);
503      const MaskType *const MaskPtr =
504          reinterpret_cast<const MaskType *const>(&Mask);
505      Container Ret[Size];
506      for (int i = 0; i < Size; ++i) {
507        Ret[i] = ((MaskPtr[i] < 0) ? RhsPtr : LhsPtr)[i];
508      }
509      return *reinterpret_cast<Dqword *>(&Ret);
510    }
511
512  private:
513    // The AssemblerX8632Test class needs to be a friend so that it can create
514    // PackedArith objects (see below.)
515    friend class AssemblerX8632Test;
516
517    explicit PackedArith(const Dqword &MyLhs) : Lhs(MyLhs) {}
518
519    // Lhs can't be a & because operator~ returns a temporary object that needs
520    // access to its own Dqword.
521    const Dqword Lhs;
522  };
523
524  // Named constructor for PackedArith objects.
525  template <typename C> static PackedArith<C> packedAs(const Dqword &D) {
526    return PackedArith<C>(D);
527  }
528
529  AssemblerX8632Test() { reset(); }
530
531  void reset() {
532    AssemblerX8632TestBase::reset();
533
534    NeedsEpilogue = true;
535    // These dwords are allocated for saving the GPR state after the jitted code
536    // runs.
537    NumAllocatedDwords = AssembledTest::ScratchpadSlots;
538    addPrologue();
539  }
540
541  // AssembledTest is a wrapper around a PROT_EXEC mmap'ed buffer. This buffer
542  // contains both the test code as well as prologue/epilogue, and the
543  // scratchpad area that tests may use -- all tests use this scratchpad area
544  // for storing the processor's registers after the tests executed. This class
545  // also exposes helper methods for reading the register state after test
546  // execution, as well as for reading the scratchpad area.
547  class AssembledTest {
548    AssembledTest() = delete;
549    AssembledTest(const AssembledTest &) = delete;
550    AssembledTest &operator=(const AssembledTest &) = delete;
551
552  public:
553    static constexpr uint32_t MaximumCodeSize = 1 << 20;
554    static constexpr uint32_t EaxSlot = 0;
555    static constexpr uint32_t EbxSlot = 1;
556    static constexpr uint32_t EcxSlot = 2;
557    static constexpr uint32_t EdxSlot = 3;
558    static constexpr uint32_t EdiSlot = 4;
559    static constexpr uint32_t EsiSlot = 5;
560    static constexpr uint32_t EbpSlot = 6;
561    static constexpr uint32_t EspSlot = 7;
562    // save 4 dwords for each xmm registers.
563    static constexpr uint32_t Xmm0Slot = 8;
564    static constexpr uint32_t Xmm1Slot = 12;
565    static constexpr uint32_t Xmm2Slot = 16;
566    static constexpr uint32_t Xmm3Slot = 20;
567    static constexpr uint32_t Xmm4Slot = 24;
568    static constexpr uint32_t Xmm5Slot = 28;
569    static constexpr uint32_t Xmm6Slot = 32;
570    static constexpr uint32_t Xmm7Slot = 36;
571    static constexpr uint32_t ScratchpadSlots = 40;
572
573    AssembledTest(const uint8_t *Data, const size_t MySize,
574                  const size_t ExtraStorageDwords)
575        : Size(MaximumCodeSize + 4 * ExtraStorageDwords) {
576      // MaxCodeSize is needed because EXPECT_LT needs a symbol with a name --
577      // probably a compiler bug?
578      uint32_t MaxCodeSize = MaximumCodeSize;
579      EXPECT_LT(MySize, MaxCodeSize);
580      assert(MySize < MaximumCodeSize);
581
582#if defined(__unix__)
583      ExecutableData = mmap(nullptr, Size, PROT_WRITE | PROT_READ | PROT_EXEC,
584                            MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
585      EXPECT_NE(MAP_FAILED, ExecutableData) << strerror(errno);
586      assert(MAP_FAILED != ExecutableData);
587#elif defined(_WIN32)
588      ExecutableData = VirtualAlloc(NULL, Size, MEM_COMMIT | MEM_RESERVE,
589                                    PAGE_EXECUTE_READWRITE);
590      EXPECT_NE(nullptr, ExecutableData) << strerror(errno);
591      assert(nullptr != ExecutableData);
592#else
593#error "Platform unsupported"
594#endif
595
596      std::memcpy(ExecutableData, Data, MySize);
597    }
598
599    // We allow AssembledTest to be moved so that we can return objects of
600    // this type.
601    AssembledTest(AssembledTest &&Buffer)
602        : ExecutableData(Buffer.ExecutableData), Size(Buffer.Size) {
603      Buffer.ExecutableData = nullptr;
604      Buffer.Size = 0;
605    }
606
607    AssembledTest &operator=(AssembledTest &&Buffer) {
608      ExecutableData = Buffer.ExecutableData;
609      Buffer.ExecutableData = nullptr;
610      Size = Buffer.Size;
611      Buffer.Size = 0;
612      return *this;
613    }
614
615    ~AssembledTest() {
616      if (ExecutableData != nullptr) {
617#if defined(__unix__)
618        munmap(ExecutableData, Size);
619#elif defined(_WIN32)
620        VirtualFree(ExecutableData, 0, MEM_RELEASE);
621#endif
622        ExecutableData = nullptr;
623      }
624    }
625
626    void run() const { reinterpret_cast<void (*)()>(ExecutableData)(); }
627
628    uint32_t eax() const { return contentsOfDword(AssembledTest::EaxSlot); }
629
630    uint32_t ebx() const { return contentsOfDword(AssembledTest::EbxSlot); }
631
632    uint32_t ecx() const { return contentsOfDword(AssembledTest::EcxSlot); }
633
634    uint32_t edx() const { return contentsOfDword(AssembledTest::EdxSlot); }
635
636    uint32_t edi() const { return contentsOfDword(AssembledTest::EdiSlot); }
637
638    uint32_t esi() const { return contentsOfDword(AssembledTest::EsiSlot); }
639
640    uint32_t ebp() const { return contentsOfDword(AssembledTest::EbpSlot); }
641
642    uint32_t esp() const { return contentsOfDword(AssembledTest::EspSlot); }
643
644    template <typename T> T xmm0() const {
645      return xmm<T>(AssembledTest::Xmm0Slot);
646    }
647
648    template <typename T> T xmm1() const {
649      return xmm<T>(AssembledTest::Xmm1Slot);
650    }
651
652    template <typename T> T xmm2() const {
653      return xmm<T>(AssembledTest::Xmm2Slot);
654    }
655
656    template <typename T> T xmm3() const {
657      return xmm<T>(AssembledTest::Xmm3Slot);
658    }
659
660    template <typename T> T xmm4() const {
661      return xmm<T>(AssembledTest::Xmm4Slot);
662    }
663
664    template <typename T> T xmm5() const {
665      return xmm<T>(AssembledTest::Xmm5Slot);
666    }
667
668    template <typename T> T xmm6() const {
669      return xmm<T>(AssembledTest::Xmm6Slot);
670    }
671
672    template <typename T> T xmm7() const {
673      return xmm<T>(AssembledTest::Xmm7Slot);
674    }
675
676    // contentsOfDword is used for reading the values in the scratchpad area.
677    // Valid arguments are the dword ids returned by
678    // AssemblerX8632Test::allocateDword() -- other inputs are considered
679    // invalid, and are not guaranteed to work if the implementation changes.
680    template <typename T = uint32_t, typename = typename std::enable_if<
681                                         sizeof(T) == sizeof(uint32_t)>::type>
682    T contentsOfDword(uint32_t Dword) const {
683      return *reinterpret_cast<T *>(static_cast<uint8_t *>(ExecutableData) +
684                                    dwordOffset(Dword));
685    }
686
687    template <typename T = uint64_t, typename = typename std::enable_if<
688                                         sizeof(T) == sizeof(uint64_t)>::type>
689    T contentsOfQword(uint32_t InitialDword) const {
690      return *reinterpret_cast<T *>(static_cast<uint8_t *>(ExecutableData) +
691                                    dwordOffset(InitialDword));
692    }
693
694    Dqword contentsOfDqword(uint32_t InitialDword) const {
695      return *reinterpret_cast<Dqword *>(
696                 static_cast<uint8_t *>(ExecutableData) +
697                 dwordOffset(InitialDword));
698    }
699
700    template <typename T = uint32_t, typename = typename std::enable_if<
701                                         sizeof(T) == sizeof(uint32_t)>::type>
702    void setDwordTo(uint32_t Dword, T value) {
703      *reinterpret_cast<uint32_t *>(static_cast<uint8_t *>(ExecutableData) +
704                                    dwordOffset(Dword)) =
705          *reinterpret_cast<uint32_t *>(&value);
706    }
707
708    template <typename T = uint64_t, typename = typename std::enable_if<
709                                         sizeof(T) == sizeof(uint64_t)>::type>
710    void setQwordTo(uint32_t InitialDword, T value) {
711      *reinterpret_cast<uint64_t *>(static_cast<uint8_t *>(ExecutableData) +
712                                    dwordOffset(InitialDword)) =
713          *reinterpret_cast<uint64_t *>(&value);
714    }
715
716    void setDqwordTo(uint32_t InitialDword, const Dqword &qdword) {
717      setQwordTo(InitialDword, qdword.U64[0]);
718      setQwordTo(InitialDword + 2, qdword.U64[1]);
719    }
720
721  private:
722    template <typename T>
723    typename std::enable_if<std::is_same<T, Dqword>::value, Dqword>::type
724    xmm(uint8_t Slot) const {
725      return contentsOfDqword(Slot);
726    }
727
728    template <typename T>
729    typename std::enable_if<!std::is_same<T, Dqword>::value, T>::type
730    xmm(uint8_t Slot) const {
731      constexpr bool TIs64Bit = sizeof(T) == sizeof(uint64_t);
732      using _64BitType = typename std::conditional<TIs64Bit, T, uint64_t>::type;
733      using _32BitType = typename std::conditional<TIs64Bit, uint32_t, T>::type;
734      if (TIs64Bit) {
735        return contentsOfQword<_64BitType>(Slot);
736      }
737      return contentsOfDword<_32BitType>(Slot);
738    }
739
740    static uint32_t dwordOffset(uint32_t Index) {
741      return MaximumCodeSize + (Index * 4);
742    }
743
744    void *ExecutableData = nullptr;
745    size_t Size;
746  };
747
748  // assemble created an AssembledTest with the jitted code. The first time
749  // assemble is executed it will add the epilogue to the jitted code (which is
750  // the reason why this method is not const qualified.
751  AssembledTest assemble() {
752    if (NeedsEpilogue) {
753      addEpilogue();
754    }
755    NeedsEpilogue = false;
756
757    for (const auto *Fixup : assembler()->fixups()) {
758      Fixup->emitOffset(assembler());
759    }
760
761    return AssembledTest(codeBytes(), codeBytesSize(), NumAllocatedDwords);
762  }
763
764  // Allocates a new dword slot in the test's scratchpad area.
765  uint32_t allocateDword() { return NumAllocatedDwords++; }
766
767  // Allocates a new qword slot in the test's scratchpad area.
768  uint32_t allocateQword() {
769    uint32_t InitialDword = allocateDword();
770    allocateDword();
771    return InitialDword;
772  }
773
774  // Allocates a new dqword slot in the test's scratchpad area.
775  uint32_t allocateDqword() {
776    uint32_t InitialDword = allocateQword();
777    allocateQword();
778    return InitialDword;
779  }
780
781  Address dwordAddress(uint32_t Dword) {
782    return Address(GPRRegister::Encoded_Reg_ebp, dwordDisp(Dword), nullptr);
783  }
784
785private:
786  // e??SlotAddress returns an AssemblerX8632::Traits::Address that can be used
787  // by the test cases to encode an address operand for accessing the slot for
788  // the specified register. These are all private for, when jitting the test
789  // code, tests should not tamper with these values. Besides, during the test
790  // execution these slots' contents are undefined and should not be accessed.
791  Address eaxSlotAddress() { return dwordAddress(AssembledTest::EaxSlot); }
792  Address ebxSlotAddress() { return dwordAddress(AssembledTest::EbxSlot); }
793  Address ecxSlotAddress() { return dwordAddress(AssembledTest::EcxSlot); }
794  Address edxSlotAddress() { return dwordAddress(AssembledTest::EdxSlot); }
795  Address ediSlotAddress() { return dwordAddress(AssembledTest::EdiSlot); }
796  Address esiSlotAddress() { return dwordAddress(AssembledTest::EsiSlot); }
797  Address ebpSlotAddress() { return dwordAddress(AssembledTest::EbpSlot); }
798  Address espSlotAddress() { return dwordAddress(AssembledTest::EspSlot); }
799  Address xmm0SlotAddress() { return dwordAddress(AssembledTest::Xmm0Slot); }
800  Address xmm1SlotAddress() { return dwordAddress(AssembledTest::Xmm1Slot); }
801  Address xmm2SlotAddress() { return dwordAddress(AssembledTest::Xmm2Slot); }
802  Address xmm3SlotAddress() { return dwordAddress(AssembledTest::Xmm3Slot); }
803  Address xmm4SlotAddress() { return dwordAddress(AssembledTest::Xmm4Slot); }
804  Address xmm5SlotAddress() { return dwordAddress(AssembledTest::Xmm5Slot); }
805  Address xmm6SlotAddress() { return dwordAddress(AssembledTest::Xmm6Slot); }
806  Address xmm7SlotAddress() { return dwordAddress(AssembledTest::Xmm7Slot); }
807
808  // Returns the displacement that should be used when accessing the specified
809  // Dword in the scratchpad area. It needs to adjust for the initial
810  // instructions that are emitted before the call that materializes the IP
811  // register.
812  uint32_t dwordDisp(uint32_t Dword) const {
813    EXPECT_LT(Dword, NumAllocatedDwords);
814    assert(Dword < NumAllocatedDwords);
815    static constexpr uint8_t PushBytes = 1;
816    static constexpr uint8_t CallImmBytes = 5;
817    return AssembledTest::MaximumCodeSize + (Dword * 4) -
818           (7 * PushBytes + CallImmBytes);
819  }
820
821  void addPrologue() {
822    __ pushl(GPRRegister::Encoded_Reg_eax);
823    __ pushl(GPRRegister::Encoded_Reg_ebx);
824    __ pushl(GPRRegister::Encoded_Reg_ecx);
825    __ pushl(GPRRegister::Encoded_Reg_edx);
826    __ pushl(GPRRegister::Encoded_Reg_edi);
827    __ pushl(GPRRegister::Encoded_Reg_esi);
828    __ pushl(GPRRegister::Encoded_Reg_ebp);
829
830    __ call(Immediate(4));
831    __ popl(GPRRegister::Encoded_Reg_ebp);
832    __ mov(IceType_i32, GPRRegister::Encoded_Reg_eax, Immediate(0x00));
833    __ mov(IceType_i32, GPRRegister::Encoded_Reg_ebx, Immediate(0x00));
834    __ mov(IceType_i32, GPRRegister::Encoded_Reg_ecx, Immediate(0x00));
835    __ mov(IceType_i32, GPRRegister::Encoded_Reg_edx, Immediate(0x00));
836    __ mov(IceType_i32, GPRRegister::Encoded_Reg_edi, Immediate(0x00));
837    __ mov(IceType_i32, GPRRegister::Encoded_Reg_esi, Immediate(0x00));
838  }
839
840  void addEpilogue() {
841    __ mov(IceType_i32, eaxSlotAddress(), GPRRegister::Encoded_Reg_eax);
842    __ mov(IceType_i32, ebxSlotAddress(), GPRRegister::Encoded_Reg_ebx);
843    __ mov(IceType_i32, ecxSlotAddress(), GPRRegister::Encoded_Reg_ecx);
844    __ mov(IceType_i32, edxSlotAddress(), GPRRegister::Encoded_Reg_edx);
845    __ mov(IceType_i32, ediSlotAddress(), GPRRegister::Encoded_Reg_edi);
846    __ mov(IceType_i32, esiSlotAddress(), GPRRegister::Encoded_Reg_esi);
847    __ mov(IceType_i32, ebpSlotAddress(), GPRRegister::Encoded_Reg_ebp);
848    __ mov(IceType_i32, espSlotAddress(), GPRRegister::Encoded_Reg_esp);
849    __ movups(xmm0SlotAddress(), XmmRegister::Encoded_Reg_xmm0);
850    __ movups(xmm1SlotAddress(), XmmRegister::Encoded_Reg_xmm1);
851    __ movups(xmm2SlotAddress(), XmmRegister::Encoded_Reg_xmm2);
852    __ movups(xmm3SlotAddress(), XmmRegister::Encoded_Reg_xmm3);
853    __ movups(xmm4SlotAddress(), XmmRegister::Encoded_Reg_xmm4);
854    __ movups(xmm5SlotAddress(), XmmRegister::Encoded_Reg_xmm5);
855    __ movups(xmm6SlotAddress(), XmmRegister::Encoded_Reg_xmm6);
856    __ movups(xmm7SlotAddress(), XmmRegister::Encoded_Reg_xmm7);
857
858    __ popl(GPRRegister::Encoded_Reg_ebp);
859    __ popl(GPRRegister::Encoded_Reg_esi);
860    __ popl(GPRRegister::Encoded_Reg_edi);
861    __ popl(GPRRegister::Encoded_Reg_edx);
862    __ popl(GPRRegister::Encoded_Reg_ecx);
863    __ popl(GPRRegister::Encoded_Reg_ebx);
864    __ popl(GPRRegister::Encoded_Reg_eax);
865
866    __ ret();
867  }
868
869  bool NeedsEpilogue;
870  uint32_t NumAllocatedDwords;
871};
872
873} // end of namespace Test
874} // end of namespace X8632
875} // end of namespace Ice
876
877#endif // ASSEMBLERX8632_TESTUTIL_H_
878