Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(12)

Side by Side Diff: unittest/IceAssemblerX8664Test.cpp

Issue 1224173006: Adds the x86-64 assembler. (Closed) Base URL: https://chromium.googlesource.com/native_client/pnacl-subzero.git@master
Patch Set: Introduces the X8664 assembler and tests. No REX support yet. Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 //===- subzero/unittest/IceAssemblerX8664.cpp - X8664 Assembler tests -----===//
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 #include "IceAssemblerX8664.h"
11
12 #include "IceDefs.h"
13
14 #include "gtest/gtest.h"
15
16 #include <algorithm>
17 #include <cstring>
18 #include <errno.h>
19 #include <iostream>
20 #include <limits>
21 #include <memory>
22 #include <sys/mman.h>
23 #include <type_traits>
24
25 namespace Ice {
26 namespace X8664 {
27 namespace {
28 class AssemblerX8664TestBase : public ::testing::Test {
29 protected:
30 using Address = AssemblerX8664::Traits::Address;
31 using ByteRegister = AssemblerX8664::Traits::ByteRegister;
32 using Cond = AssemblerX8664::Traits::Cond;
33 using GPRRegister = AssemblerX8664::Traits::GPRRegister;
34 using Traits = AssemblerX8664::Traits;
35 using XmmRegister = AssemblerX8664::Traits::XmmRegister;
36
37 AssemblerX8664TestBase() { reset(); }
38
39 void reset() { Assembler.reset(new AssemblerX8664()); }
40
41 AssemblerX8664 *assembler() const { return Assembler.get(); }
42
43 size_t codeBytesSize() const { return Assembler->getBufferView().size(); }
44
45 const uint8_t *codeBytes() const {
46 return static_cast<const uint8_t *>(
47 static_cast<const void *>(Assembler->getBufferView().data()));
48 }
49
50 private:
51 std::unique_ptr<AssemblerX8664> Assembler;
52 };
53
54 // __ is a helper macro. It allows test cases to emit X8664 assembly
55 // instructions with
56 //
57 // __ mov(GPRRegister::Reg_Eax, 1);
58 // __ ret();
59 //
60 // and so on. The idea of having this was "stolen" from dart's unit tests.
61 #define __ (this->assembler())->
62
63 // AssemblerX8664LowLevelTest verify that the "basic" instructions the tests
64 // rely on are encoded correctly. Therefore, instead of executing the assembled
65 // code, these tests will verify that the assembled bytes are sane.
66 class AssemblerX8664LowLevelTest : public AssemblerX8664TestBase {
67 protected:
68 // verifyBytes is a template helper that takes a Buffer, and a variable number
69 // of bytes. As the name indicates, it is used to verify the bytes for an
70 // instruction encoding.
71 template <int N, int I> static bool verifyBytes(const uint8_t *) {
72 static_assert(I == N, "Invalid template instantiation.");
73 return true;
74 }
75
76 template <int N, int I = 0, typename... Args>
77 static bool verifyBytes(const uint8_t *Buffer, uint8_t Byte,
78 Args... OtherBytes) {
79 static_assert(I < N, "Invalid template instantiation.");
80 EXPECT_EQ(Byte, Buffer[I]) << "Byte " << (I + 1) << " of " << N;
81 return verifyBytes<N, I + 1>(Buffer, OtherBytes...) && Buffer[I] == Byte;
82 }
83 };
84
85 TEST_F(AssemblerX8664LowLevelTest, Ret) {
86 __ ret();
87
88 constexpr size_t ByteCount = 1;
89 ASSERT_EQ(ByteCount, codeBytesSize());
90
91 verifyBytes<ByteCount>(codeBytes(), 0xc3);
92 }
93
94 TEST_F(AssemblerX8664LowLevelTest, RetImm) {
95 __ ret(Immediate(0x20));
96
97 constexpr size_t ByteCount = 3;
98 ASSERT_EQ(ByteCount, codeBytesSize());
99
100 verifyBytes<ByteCount>(codeBytes(), 0xC2, 0x20, 0x00);
101 }
102
103 TEST_F(AssemblerX8664LowLevelTest, CallImm4) {
104 __ call(Immediate(4));
105
106 constexpr size_t ByteCount = 5;
107 ASSERT_EQ(ByteCount, codeBytesSize());
108
109 verifyBytes<ByteCount>(codeBytes(), 0xe8, 0x00, 0x00, 0x00, 0x00);
110 }
111
112 TEST_F(AssemblerX8664LowLevelTest, PopRegs) {
113 __ popl(GPRRegister::Encoded_Reg_eax);
114 __ popl(GPRRegister::Encoded_Reg_ebx);
115 __ popl(GPRRegister::Encoded_Reg_ecx);
116 __ popl(GPRRegister::Encoded_Reg_edx);
117 __ popl(GPRRegister::Encoded_Reg_edi);
118 __ popl(GPRRegister::Encoded_Reg_esi);
119 __ popl(GPRRegister::Encoded_Reg_ebp);
120
121 constexpr size_t ByteCount = 7;
122 ASSERT_EQ(ByteCount, codeBytesSize());
123
124 constexpr uint8_t PopOpcode = 0x58;
125 verifyBytes<ByteCount>(codeBytes(), PopOpcode | GPRRegister::Encoded_Reg_eax,
126 PopOpcode | GPRRegister::Encoded_Reg_ebx,
127 PopOpcode | GPRRegister::Encoded_Reg_ecx,
128 PopOpcode | GPRRegister::Encoded_Reg_edx,
129 PopOpcode | GPRRegister::Encoded_Reg_edi,
130 PopOpcode | GPRRegister::Encoded_Reg_esi,
131 PopOpcode | GPRRegister::Encoded_Reg_ebp);
132 }
133
134 TEST_F(AssemblerX8664LowLevelTest, PushRegs) {
135 __ pushl(GPRRegister::Encoded_Reg_eax);
136 __ pushl(GPRRegister::Encoded_Reg_ebx);
137 __ pushl(GPRRegister::Encoded_Reg_ecx);
138 __ pushl(GPRRegister::Encoded_Reg_edx);
139 __ pushl(GPRRegister::Encoded_Reg_edi);
140 __ pushl(GPRRegister::Encoded_Reg_esi);
141 __ pushl(GPRRegister::Encoded_Reg_ebp);
142
143 constexpr size_t ByteCount = 7;
144 ASSERT_EQ(ByteCount, codeBytesSize());
145
146 constexpr uint8_t PushOpcode = 0x50;
147 verifyBytes<ByteCount>(codeBytes(), PushOpcode | GPRRegister::Encoded_Reg_eax,
148 PushOpcode | GPRRegister::Encoded_Reg_ebx,
149 PushOpcode | GPRRegister::Encoded_Reg_ecx,
150 PushOpcode | GPRRegister::Encoded_Reg_edx,
151 PushOpcode | GPRRegister::Encoded_Reg_edi,
152 PushOpcode | GPRRegister::Encoded_Reg_esi,
153 PushOpcode | GPRRegister::Encoded_Reg_ebp);
154 }
155
156 TEST_F(AssemblerX8664LowLevelTest, MovRegisterZero) {
157 __ mov(IceType_i32, GPRRegister::Encoded_Reg_eax, Immediate(0x00));
158 __ mov(IceType_i32, GPRRegister::Encoded_Reg_ebx, Immediate(0x00));
159 __ mov(IceType_i32, GPRRegister::Encoded_Reg_ecx, Immediate(0x00));
160 __ mov(IceType_i32, GPRRegister::Encoded_Reg_edx, Immediate(0x00));
161 __ mov(IceType_i32, GPRRegister::Encoded_Reg_edi, Immediate(0x00));
162 __ mov(IceType_i32, GPRRegister::Encoded_Reg_esi, Immediate(0x00));
163
164 constexpr size_t MovReg32BitImmBytes = 5;
165 constexpr size_t ByteCount = 6 * MovReg32BitImmBytes;
166 ASSERT_EQ(ByteCount, codeBytesSize());
167
168 constexpr uint8_t MovOpcode = 0xb8;
169 verifyBytes<ByteCount>(
170 codeBytes(), MovOpcode | GPRRegister::Encoded_Reg_eax, 0x00, 0x00, 0x00,
171 0x00, MovOpcode | GPRRegister::Encoded_Reg_ebx, 0x00, 0x00, 0x00, 0x00,
172 MovOpcode | GPRRegister::Encoded_Reg_ecx, 0x00, 0x00, 0x00, 0x00,
173 MovOpcode | GPRRegister::Encoded_Reg_edx, 0x00, 0x00, 0x00, 0x00,
174 MovOpcode | GPRRegister::Encoded_Reg_edi, 0x00, 0x00, 0x00, 0x00,
175 MovOpcode | GPRRegister::Encoded_Reg_esi, 0x00, 0x00, 0x00, 0x00);
176 }
177
178 TEST_F(AssemblerX8664LowLevelTest, Cmp) {
179 #define TestRegReg(Inst, Dst, Src, OpType, ByteCountUntyped, ...) \
180 do { \
181 static constexpr char TestString[] = \
182 "(" #Inst ", " #Dst ", " #Src ", " #OpType ", " #ByteCountUntyped \
183 ", " #__VA_ARGS__ ")"; \
184 static constexpr uint8_t ByteCount = ByteCountUntyped; \
185 __ Inst(IceType_##OpType, GPRRegister::Encoded_Reg_##Dst, \
186 GPRRegister::Encoded_Reg_##Src); \
187 ASSERT_EQ(ByteCount, codeBytesSize()) << TestString; \
188 ASSERT_TRUE(verifyBytes<ByteCount>(codeBytes(), __VA_ARGS__)) \
189 << TestString; \
190 reset(); \
191 } while (0)
192
193 #define TestRegImm(Inst, Dst, Imm, OpType, ByteCountUntyped, ...) \
194 do { \
195 static constexpr char TestString[] = \
196 "(" #Inst ", " #Dst ", " #Imm ", " #OpType ", " #ByteCountUntyped \
197 ", " #__VA_ARGS__ ")"; \
198 static constexpr uint8_t ByteCount = ByteCountUntyped; \
199 __ Inst(IceType_##OpType, GPRRegister::Encoded_Reg_##Dst, Immediate(Imm)); \
200 ASSERT_EQ(ByteCount, codeBytesSize()) << TestString; \
201 ASSERT_TRUE(verifyBytes<ByteCount>(codeBytes(), __VA_ARGS__)) \
202 << TestString; \
203 reset(); \
204 } while (0)
205
206 #define TestRegAbsoluteAddr(Inst, Dst, Disp, OpType, ByteCountUntyped, ...) \
207 do { \
208 static constexpr char TestString[] = \
209 "(" #Inst ", " #Dst ", " #Disp ", " #OpType ", " #ByteCountUntyped \
210 ", " #__VA_ARGS__ ")"; \
211 static constexpr uint8_t ByteCount = ByteCountUntyped; \
212 __ Inst(IceType_##OpType, GPRRegister::Encoded_Reg_##Dst, \
213 Address(Address::ABSOLUTE, Disp)); \
214 ASSERT_EQ(ByteCount, codeBytesSize()) << TestString; \
215 ASSERT_TRUE(verifyBytes<ByteCount>(codeBytes(), __VA_ARGS__)) \
216 << TestString; \
217 reset(); \
218 } while (0)
219
220 #define TestRegAddrBase(Inst, Dst, Base, Disp, OpType, ByteCountUntyped, ...) \
221 do { \
222 static constexpr char TestString[] = \
223 "(" #Inst ", " #Dst ", " #Base ", " #Disp ", " #OpType \
224 ", " #ByteCountUntyped ", " #__VA_ARGS__ ")"; \
225 static constexpr uint8_t ByteCount = ByteCountUntyped; \
226 __ Inst(IceType_##OpType, GPRRegister::Encoded_Reg_##Dst, \
227 Address(GPRRegister::Encoded_Reg_##Base, Disp)); \
228 ASSERT_EQ(ByteCount, codeBytesSize()) << TestString; \
229 ASSERT_TRUE(verifyBytes<ByteCount>(codeBytes(), __VA_ARGS__)) \
230 << TestString; \
231 reset(); \
232 } while (0)
233
234 #define TestRegAddrScaledIndex(Inst, Dst, Index, Scale, Disp, OpType, \
235 ByteCountUntyped, ...) \
236 do { \
237 static constexpr char TestString[] = \
238 "(" #Inst ", " #Dst ", " #Index ", " #Scale ", " #Disp ", " #OpType \
239 ", " #ByteCountUntyped ", " #__VA_ARGS__ ")"; \
240 static constexpr uint8_t ByteCount = ByteCountUntyped; \
241 __ Inst(IceType_##OpType, GPRRegister::Encoded_Reg_##Dst, \
242 Address(GPRRegister::Encoded_Reg_##Index, Traits::TIMES_##Scale, \
243 Disp)); \
244 ASSERT_EQ(ByteCount, codeBytesSize()) << TestString; \
245 ASSERT_TRUE(verifyBytes<ByteCount>(codeBytes(), __VA_ARGS__)) \
246 << TestString; \
247 reset(); \
248 } while (0)
249
250 #define TestRegAddrBaseScaledIndex(Inst, Dst, Base, Index, Scale, Disp, \
251 OpType, ByteCountUntyped, ...) \
252 do { \
253 static constexpr char TestString[] = \
254 "(" #Inst ", " #Dst ", " #Base ", " #Index ", " #Scale ", " #Disp \
255 ", " #OpType ", " #ByteCountUntyped ", " #__VA_ARGS__ ")"; \
256 static constexpr uint8_t ByteCount = ByteCountUntyped; \
257 __ Inst(IceType_##OpType, GPRRegister::Encoded_Reg_##Dst, \
258 Address(GPRRegister::Encoded_Reg_##Base, \
259 GPRRegister::Encoded_Reg_##Index, Traits::TIMES_##Scale, \
260 Disp)); \
261 ASSERT_EQ(ByteCount, codeBytesSize()) << TestString; \
262 ASSERT_TRUE(verifyBytes<ByteCount>(codeBytes(), __VA_ARGS__)) \
263 << TestString; \
264 reset(); \
265 } while (0)
266
267 #define TestAddrBaseScaledIndexImm(Inst, Base, Index, Scale, Disp, Imm, \
268 OpType, ByteCountUntyped, ...) \
269 do { \
270 static constexpr char TestString[] = \
271 "(" #Inst ", " #Base ", " #Index ", " #Scale ", " #Disp ", " #Imm \
272 ", " #OpType ", " #ByteCountUntyped ", " #__VA_ARGS__ ")"; \
273 static constexpr uint8_t ByteCount = ByteCountUntyped; \
274 __ Inst(IceType_##OpType, Address(GPRRegister::Encoded_Reg_##Base, \
275 GPRRegister::Encoded_Reg_##Index, \
276 Traits::TIMES_##Scale, Disp), \
277 Immediate(Imm)); \
278 ASSERT_EQ(ByteCount, codeBytesSize()) << TestString; \
279 ASSERT_TRUE(verifyBytes<ByteCount>(codeBytes(), __VA_ARGS__)) \
280 << TestString; \
281 reset(); \
282 } while (0)
283
284 #define TestAddrBaseScaledIndexReg(Inst, Base, Index, Scale, Disp, Src, \
285 OpType, ByteCountUntyped, ...) \
286 do { \
287 static constexpr char TestString[] = \
288 "(" #Inst ", " #Base ", " #Index ", " #Scale ", " #Disp ", " #Src \
289 ", " #OpType ", " #ByteCountUntyped ", " #__VA_ARGS__ ")"; \
290 static constexpr uint8_t ByteCount = ByteCountUntyped; \
291 __ Inst(IceType_##OpType, Address(GPRRegister::Encoded_Reg_##Base, \
292 GPRRegister::Encoded_Reg_##Index, \
293 Traits::TIMES_##Scale, Disp), \
294 GPRRegister::Encoded_Reg_##Src); \
295 ASSERT_EQ(ByteCount, codeBytesSize()) << TestString; \
296 ASSERT_TRUE(verifyBytes<ByteCount>(codeBytes(), __VA_ARGS__)) \
297 << TestString; \
298 reset(); \
299 } while (0)
300
301 /* cmp GPR, GPR */
302 TestRegReg(cmp, eax, ecx, i32, 2, 0x3B, 0xC1);
303 TestRegReg(cmp, ecx, edx, i32, 2, 0x3B, 0xCA);
304 TestRegReg(cmp, edx, ebx, i32, 2, 0x3B, 0xD3);
305 TestRegReg(cmp, ebx, esp, i32, 2, 0x3B, 0xDC);
306 TestRegReg(cmp, esp, ebp, i32, 2, 0x3B, 0xE5);
307 TestRegReg(cmp, ebp, esi, i32, 2, 0x3B, 0xEE);
308 TestRegReg(cmp, esi, edi, i32, 2, 0x3B, 0xF7);
309 TestRegReg(cmp, edi, eax, i32, 2, 0x3B, 0xF8);
310
311 TestRegReg(cmp, eax, ecx, i16, 3, 0x66, 0x3B, 0xC1);
312 TestRegReg(cmp, ecx, edx, i16, 3, 0x66, 0x3B, 0xCA);
313 TestRegReg(cmp, edx, ebx, i16, 3, 0x66, 0x3B, 0xD3);
314 TestRegReg(cmp, ebx, esp, i16, 3, 0x66, 0x3B, 0xDC);
315 TestRegReg(cmp, esp, ebp, i16, 3, 0x66, 0x3B, 0xE5);
316 TestRegReg(cmp, ebp, esi, i16, 3, 0x66, 0x3B, 0xEE);
317 TestRegReg(cmp, esi, edi, i16, 3, 0x66, 0x3B, 0xF7);
318 TestRegReg(cmp, edi, eax, i16, 3, 0x66, 0x3B, 0xF8);
319
320 TestRegReg(cmp, eax, ecx, i8, 2, 0x3A, 0xC1);
321 TestRegReg(cmp, ecx, edx, i8, 2, 0x3A, 0xCA);
322 TestRegReg(cmp, edx, ebx, i8, 2, 0x3A, 0xD3);
323 TestRegReg(cmp, ebx, esp, i8, 2, 0x3A, 0xDC);
324 TestRegReg(cmp, esp, ebp, i8, 2, 0x3A, 0xE5);
325 TestRegReg(cmp, ebp, esi, i8, 2, 0x3A, 0xEE);
326 TestRegReg(cmp, esi, edi, i8, 2, 0x3A, 0xF7);
327 TestRegReg(cmp, edi, eax, i8, 2, 0x3A, 0xF8);
328
329 /* cmp GPR, Imm8 */
330 TestRegImm(cmp, eax, 5, i32, 3, 0x83, 0xF8, 0x05);
331 TestRegImm(cmp, ecx, 5, i32, 3, 0x83, 0xF9, 0x05);
332 TestRegImm(cmp, edx, 5, i32, 3, 0x83, 0xFA, 0x05);
333 TestRegImm(cmp, ebx, 5, i32, 3, 0x83, 0xFB, 0x05);
334 TestRegImm(cmp, esp, 5, i32, 3, 0x83, 0xFC, 0x05);
335 TestRegImm(cmp, ebp, 5, i32, 3, 0x83, 0xFD, 0x05);
336 TestRegImm(cmp, esi, 5, i32, 3, 0x83, 0xFE, 0x05);
337 TestRegImm(cmp, edi, 5, i32, 3, 0x83, 0xFF, 0x05);
338
339 TestRegImm(cmp, eax, 5, i16, 4, 0x66, 0x83, 0xF8, 0x05);
340 TestRegImm(cmp, ecx, 5, i16, 4, 0x66, 0x83, 0xF9, 0x05);
341 TestRegImm(cmp, edx, 5, i16, 4, 0x66, 0x83, 0xFA, 0x05);
342 TestRegImm(cmp, ebx, 5, i16, 4, 0x66, 0x83, 0xFB, 0x05);
343 TestRegImm(cmp, esp, 5, i16, 4, 0x66, 0x83, 0xFC, 0x05);
344 TestRegImm(cmp, ebp, 5, i16, 4, 0x66, 0x83, 0xFD, 0x05);
345 TestRegImm(cmp, esi, 5, i16, 4, 0x66, 0x83, 0xFE, 0x05);
346 TestRegImm(cmp, edi, 5, i16, 4, 0x66, 0x83, 0xFF, 0x05);
347
348 TestRegImm(cmp, eax, 5, i8, 2, 0x3C, 0x05);
349 TestRegImm(cmp, ecx, 5, i8, 3, 0x80, 0xF9, 0x05);
350 TestRegImm(cmp, edx, 5, i8, 3, 0x80, 0xFA, 0x05);
351 TestRegImm(cmp, ebx, 5, i8, 3, 0x80, 0xFB, 0x05);
352 TestRegImm(cmp, esp, 5, i8, 3, 0x80, 0xFC, 0x05);
353 TestRegImm(cmp, ebp, 5, i8, 3, 0x80, 0xFD, 0x05);
354 TestRegImm(cmp, esi, 5, i8, 3, 0x80, 0xFE, 0x05);
355 TestRegImm(cmp, edi, 5, i8, 3, 0x80, 0xFF, 0x05);
356
357 /* cmp GPR, Imm16 */
358 TestRegImm(cmp, eax, 0x100, i32, 5, 0x3D, 0x00, 0x01, 0x00, 0x00);
359 TestRegImm(cmp, ecx, 0x100, i32, 6, 0x81, 0xF9, 0x00, 0x01, 0x00, 0x00);
360 TestRegImm(cmp, edx, 0x100, i32, 6, 0x81, 0xFA, 0x00, 0x01, 0x00, 0x00);
361 TestRegImm(cmp, ebx, 0x100, i32, 6, 0x81, 0xFB, 0x00, 0x01, 0x00, 0x00);
362 TestRegImm(cmp, esp, 0x100, i32, 6, 0x81, 0xFC, 0x00, 0x01, 0x00, 0x00);
363 TestRegImm(cmp, ebp, 0x100, i32, 6, 0x81, 0xFD, 0x00, 0x01, 0x00, 0x00);
364 TestRegImm(cmp, esi, 0x100, i32, 6, 0x81, 0xFE, 0x00, 0x01, 0x00, 0x00);
365 TestRegImm(cmp, edi, 0x100, i32, 6, 0x81, 0xFF, 0x00, 0x01, 0x00, 0x00);
366
367 TestRegImm(cmp, eax, 0x100, i16, 4, 0x66, 0x3D, 0x00, 0x01);
368 TestRegImm(cmp, ecx, 0x100, i16, 5, 0x66, 0x81, 0xF9, 0x00, 0x01);
369 TestRegImm(cmp, edx, 0x100, i16, 5, 0x66, 0x81, 0xFA, 0x00, 0x01);
370 TestRegImm(cmp, ebx, 0x100, i16, 5, 0x66, 0x81, 0xFB, 0x00, 0x01);
371 TestRegImm(cmp, esp, 0x100, i16, 5, 0x66, 0x81, 0xFC, 0x00, 0x01);
372 TestRegImm(cmp, ebp, 0x100, i16, 5, 0x66, 0x81, 0xFD, 0x00, 0x01);
373 TestRegImm(cmp, esi, 0x100, i16, 5, 0x66, 0x81, 0xFE, 0x00, 0x01);
374 TestRegImm(cmp, edi, 0x100, i16, 5, 0x66, 0x81, 0xFF, 0x00, 0x01);
375
376 /* cmp GPR, Absolute */
377 TestRegAbsoluteAddr(cmp, eax, 0xF00FBEEF, i32, 6, 0x3B, 0x05, 0xEF, 0xBE,
378 0x0F, 0xF0);
379 TestRegAbsoluteAddr(cmp, eax, 0xF00FBEEF, i16, 7, 0x66, 0x3B, 0x05, 0xEF,
380 0xBE, 0x0F, 0xF0);
381 TestRegAbsoluteAddr(cmp, eax, 0xF00FBEEF, i8, 6, 0x3A, 0x05, 0xEF, 0xBE, 0x0F,
382 0xF0);
383
384 /* cmp GPR, 0(Base) */
385 TestRegAddrBase(cmp, eax, ecx, 0, i32, 2, 0x3B, 0x01);
386 TestRegAddrBase(cmp, ecx, edx, 0, i32, 2, 0x3B, 0x0A);
387 TestRegAddrBase(cmp, edx, ebx, 0, i32, 2, 0x3B, 0x13);
388 TestRegAddrBase(cmp, ebx, esp, 0, i32, 3, 0x3B, 0x1C, 0x24);
389 TestRegAddrBase(cmp, esp, ebp, 0, i32, 3, 0x3B, 0x65, 0x00);
390 TestRegAddrBase(cmp, ebp, esi, 0, i32, 2, 0x3B, 0x2E);
391 TestRegAddrBase(cmp, esi, edi, 0, i32, 2, 0x3B, 0x37);
392 TestRegAddrBase(cmp, edi, eax, 0, i32, 2, 0x3B, 0x38);
393
394 TestRegAddrBase(cmp, eax, ecx, 0, i16, 3, 0x66, 0x3B, 0x01);
395 TestRegAddrBase(cmp, ecx, edx, 0, i16, 3, 0x66, 0x3B, 0x0A);
396 TestRegAddrBase(cmp, edx, ebx, 0, i16, 3, 0x66, 0x3B, 0x13);
397 TestRegAddrBase(cmp, ebx, esp, 0, i16, 4, 0x66, 0x3B, 0x1C, 0x24);
398 TestRegAddrBase(cmp, esp, ebp, 0, i16, 4, 0x66, 0x3B, 0x65, 0x00);
399 TestRegAddrBase(cmp, ebp, esi, 0, i16, 3, 0x66, 0x3B, 0x2E);
400 TestRegAddrBase(cmp, esi, edi, 0, i16, 3, 0x66, 0x3B, 0x37);
401 TestRegAddrBase(cmp, edi, eax, 0, i16, 3, 0x66, 0x3B, 0x38);
402
403 TestRegAddrBase(cmp, eax, ecx, 0, i8, 2, 0x3A, 0x01);
404 TestRegAddrBase(cmp, ecx, edx, 0, i8, 2, 0x3A, 0x0A);
405 TestRegAddrBase(cmp, edx, ebx, 0, i8, 2, 0x3A, 0x13);
406 TestRegAddrBase(cmp, ebx, esp, 0, i8, 3, 0x3A, 0x1C, 0x24);
407 TestRegAddrBase(cmp, esp, ebp, 0, i8, 3, 0x3A, 0x65, 0x00);
408 TestRegAddrBase(cmp, ebp, esi, 0, i8, 2, 0x3A, 0x2E);
409 TestRegAddrBase(cmp, esi, edi, 0, i8, 2, 0x3A, 0x37);
410 TestRegAddrBase(cmp, edi, eax, 0, i8, 2, 0x3A, 0x38);
411
412 /* cmp GPR, Imm8(Base) */
413 TestRegAddrBase(cmp, eax, ecx, 0x40, i32, 3, 0x3B, 0x41, 0x40);
414 TestRegAddrBase(cmp, ecx, edx, 0x40, i32, 3, 0x3B, 0x4A, 0x40);
415 TestRegAddrBase(cmp, edx, ebx, 0x40, i32, 3, 0x3B, 0x53, 0x40);
416 TestRegAddrBase(cmp, ebx, esp, 0x40, i32, 4, 0x3B, 0x5C, 0x24, 0x40);
417 TestRegAddrBase(cmp, esp, ebp, 0x40, i32, 3, 0x3B, 0x65, 0x40);
418 TestRegAddrBase(cmp, ebp, esi, 0x40, i32, 3, 0x3B, 0x6E, 0x40);
419 TestRegAddrBase(cmp, esi, edi, 0x40, i32, 3, 0x3B, 0x77, 0x40);
420 TestRegAddrBase(cmp, edi, eax, 0x40, i32, 3, 0x3B, 0x78, 0x40);
421
422 TestRegAddrBase(cmp, eax, ecx, 0x40, i16, 4, 0x66, 0x3B, 0x41, 0x40);
423 TestRegAddrBase(cmp, ecx, edx, 0x40, i16, 4, 0x66, 0x3B, 0x4A, 0x40);
424 TestRegAddrBase(cmp, edx, ebx, 0x40, i16, 4, 0x66, 0x3B, 0x53, 0x40);
425 TestRegAddrBase(cmp, ebx, esp, 0x40, i16, 5, 0x66, 0x3B, 0x5C, 0x24, 0x40);
426 TestRegAddrBase(cmp, esp, ebp, 0x40, i16, 4, 0x66, 0x3B, 0x65, 0x40);
427 TestRegAddrBase(cmp, ebp, esi, 0x40, i16, 4, 0x66, 0x3B, 0x6E, 0x40);
428 TestRegAddrBase(cmp, esi, edi, 0x40, i16, 4, 0x66, 0x3B, 0x77, 0x40);
429 TestRegAddrBase(cmp, edi, eax, 0x40, i16, 4, 0x66, 0x3B, 0x78, 0x40);
430
431 TestRegAddrBase(cmp, eax, ecx, 0x40, i8, 3, 0x3A, 0x41, 0x40);
432 TestRegAddrBase(cmp, ecx, edx, 0x40, i8, 3, 0x3A, 0x4A, 0x40);
433 TestRegAddrBase(cmp, edx, ebx, 0x40, i8, 3, 0x3A, 0x53, 0x40);
434 TestRegAddrBase(cmp, ebx, esp, 0x40, i8, 4, 0x3A, 0x5C, 0x24, 0x40);
435 TestRegAddrBase(cmp, esp, ebp, 0x40, i8, 3, 0x3A, 0x65, 0x40);
436 TestRegAddrBase(cmp, ebp, esi, 0x40, i8, 3, 0x3A, 0x6E, 0x40);
437 TestRegAddrBase(cmp, esi, edi, 0x40, i8, 3, 0x3A, 0x77, 0x40);
438 TestRegAddrBase(cmp, edi, eax, 0x40, i8, 3, 0x3A, 0x78, 0x40);
439
440 /* cmp GPR, Imm32(Base) */
441 TestRegAddrBase(cmp, eax, ecx, 0xF0, i32, 6, 0x3B, 0x81, 0xF0, 0x00, 0x00,
442 0x00);
443 TestRegAddrBase(cmp, ecx, edx, 0xF0, i32, 6, 0x3B, 0x8A, 0xF0, 0x00, 0x00,
444 0x00);
445 TestRegAddrBase(cmp, edx, ebx, 0xF0, i32, 6, 0x3B, 0x93, 0xF0, 0x00, 0x00,
446 0x00);
447 TestRegAddrBase(cmp, ebx, esp, 0xF0, i32, 7, 0x3B, 0x9C, 0x24, 0xF0, 0x00,
448 0x00, 0x00);
449 TestRegAddrBase(cmp, esp, ebp, 0xF0, i32, 6, 0x3B, 0xA5, 0xF0, 0x00, 0x00,
450 0x00);
451 TestRegAddrBase(cmp, ebp, esi, 0xF0, i32, 6, 0x3B, 0xAE, 0xF0, 0x00, 0x00,
452 0x00);
453 TestRegAddrBase(cmp, esi, edi, 0xF0, i32, 6, 0x3B, 0xB7, 0xF0, 0x00, 0x00,
454 0x00);
455 TestRegAddrBase(cmp, edi, eax, 0xF0, i32, 6, 0x3B, 0xB8, 0xF0, 0x00, 0x00,
456 0x00);
457
458 TestRegAddrBase(cmp, eax, ecx, 0xF0, i16, 7, 0x66, 0x3B, 0x81, 0xF0, 0x00,
459 0x00, 0x00);
460 TestRegAddrBase(cmp, ecx, edx, 0xF0, i16, 7, 0x66, 0x3B, 0x8A, 0xF0, 0x00,
461 0x00, 0x00);
462 TestRegAddrBase(cmp, edx, ebx, 0xF0, i16, 7, 0x66, 0x3B, 0x93, 0xF0, 0x00,
463 0x00, 0x00);
464 TestRegAddrBase(cmp, ebx, esp, 0xF0, i16, 8, 0x66, 0x3B, 0x9C, 0x24, 0xF0,
465 0x00, 0x00, 0x00);
466 TestRegAddrBase(cmp, esp, ebp, 0xF0, i16, 7, 0x66, 0x3B, 0xa5, 0xF0, 0x00,
467 0x00, 0x00);
468 TestRegAddrBase(cmp, ebp, esi, 0xF0, i16, 7, 0x66, 0x3B, 0xaE, 0xF0, 0x00,
469 0x00, 0x00);
470 TestRegAddrBase(cmp, esi, edi, 0xF0, i16, 7, 0x66, 0x3B, 0xb7, 0xF0, 0x00,
471 0x00, 0x00);
472 TestRegAddrBase(cmp, edi, eax, 0xF0, i16, 7, 0x66, 0x3B, 0xb8, 0xF0, 0x00,
473 0x00, 0x00);
474
475 TestRegAddrBase(cmp, eax, ecx, 0xF0, i8, 6, 0x3A, 0x81, 0xF0, 0x00, 0x00,
476 0x00);
477 TestRegAddrBase(cmp, ecx, edx, 0xF0, i8, 6, 0x3A, 0x8A, 0xF0, 0x00, 0x00,
478 0x00);
479 TestRegAddrBase(cmp, edx, ebx, 0xF0, i8, 6, 0x3A, 0x93, 0xF0, 0x00, 0x00,
480 0x00);
481 TestRegAddrBase(cmp, ebx, esp, 0xF0, i8, 7, 0x3A, 0x9C, 0x24, 0xF0, 0x00,
482 0x00, 0x00);
483 TestRegAddrBase(cmp, esp, ebp, 0xF0, i8, 6, 0x3A, 0xA5, 0xF0, 0x00, 0x00,
484 0x00);
485 TestRegAddrBase(cmp, ebp, esi, 0xF0, i8, 6, 0x3A, 0xAE, 0xF0, 0x00, 0x00,
486 0x00);
487 TestRegAddrBase(cmp, esi, edi, 0xF0, i8, 6, 0x3A, 0xB7, 0xF0, 0x00, 0x00,
488 0x00);
489 TestRegAddrBase(cmp, edi, eax, 0xF0, i8, 6, 0x3A, 0xB8, 0xF0, 0x00, 0x00,
490 0x00);
491
492 /* cmp GPR, Imm(,Index,Scale) */
493 TestRegAddrScaledIndex(cmp, eax, ecx, 1, 0, i32, 7, 0x3B, 0x04, 0x0D, 0x00,
494 0x00, 0x00, 0x00);
495 TestRegAddrScaledIndex(cmp, ecx, edx, 2, 0, i32, 7, 0x3B, 0x0C, 0x55, 0x00,
496 0x00, 0x00, 0x00);
497 TestRegAddrScaledIndex(cmp, edx, ebx, 4, 0, i32, 7, 0x3B, 0x14, 0x9D, 0x00,
498 0x00, 0x00, 0x00);
499 // esp cannot be an scaled index.
500 TestRegAddrScaledIndex(cmp, esp, ebp, 8, 0, i32, 7, 0x3B, 0x24, 0xED, 0x00,
501 0x00, 0x00, 0x00);
502 TestRegAddrScaledIndex(cmp, ebp, esi, 1, 0, i32, 7, 0x3B, 0x2C, 0x35, 0x00,
503 0x00, 0x00, 0x00);
504 TestRegAddrScaledIndex(cmp, esi, edi, 2, 0, i32, 7, 0x3B, 0x34, 0x7D, 0x00,
505 0x00, 0x00, 0x00);
506 TestRegAddrScaledIndex(cmp, edi, eax, 4, 0, i32, 7, 0x3B, 0x3C, 0x85, 0x00,
507 0x00, 0x00, 0x00);
508 TestRegAddrScaledIndex(cmp, ebx, ecx, 8, 0, i32, 7, 0x3B, 0x1C, 0xCD, 0x00,
509 0x00, 0x00, 0x00);
510
511 TestRegAddrScaledIndex(cmp, eax, ecx, 8, 0, i16, 8, 0x66, 0x3B, 0x04, 0xCD,
512 0x00, 0x00, 0x00, 0x00);
513 TestRegAddrScaledIndex(cmp, ecx, edx, 1, 0, i16, 8, 0x66, 0x3B, 0x0C, 0x15,
514 0x00, 0x00, 0x00, 0x00);
515 TestRegAddrScaledIndex(cmp, edx, ebx, 2, 0, i16, 8, 0x66, 0x3B, 0x14, 0x5D,
516 0x00, 0x00, 0x00, 0x00);
517 // esp cannot be an scaled index.
518 TestRegAddrScaledIndex(cmp, esp, ebp, 4, 0, i16, 8, 0x66, 0x3B, 0x24, 0xAD,
519 0x00, 0x00, 0x00, 0x00);
520 TestRegAddrScaledIndex(cmp, ebp, esi, 8, 0, i16, 8, 0x66, 0x3B, 0x2C, 0xF5,
521 0x00, 0x00, 0x00, 0x00);
522 TestRegAddrScaledIndex(cmp, esi, edi, 1, 0, i16, 8, 0x66, 0x3B, 0x34, 0x3D,
523 0x00, 0x00, 0x00, 0x00);
524 TestRegAddrScaledIndex(cmp, edi, eax, 2, 0, i16, 8, 0x66, 0x3B, 0x3C, 0x45,
525 0x00, 0x00, 0x00, 0x00);
526 TestRegAddrScaledIndex(cmp, ebx, ecx, 8, 0, i16, 8, 0x66, 0x3B, 0x1C, 0xCD,
527 0x00, 0x00, 0x00, 0x00);
528
529 TestRegAddrScaledIndex(cmp, eax, ecx, 4, 0, i8, 7, 0x3A, 0x04, 0x8D, 0x00,
530 0x00, 0x00, 0x00);
531 TestRegAddrScaledIndex(cmp, ecx, edx, 8, 0, i8, 7, 0x3A, 0x0C, 0xD5, 0x00,
532 0x00, 0x00, 0x00);
533 TestRegAddrScaledIndex(cmp, edx, ebx, 1, 0, i8, 7, 0x3A, 0x14, 0x1D, 0x00,
534 0x00, 0x00, 0x00);
535 // esp cannot be an scaled index.
536 TestRegAddrScaledIndex(cmp, esp, ebp, 2, 0, i8, 7, 0x3A, 0x24, 0x6D, 0x00,
537 0x00, 0x00, 0x00);
538 TestRegAddrScaledIndex(cmp, ebp, esi, 4, 0, i8, 7, 0x3A, 0x2C, 0xB5, 0x00,
539 0x00, 0x00, 0x00);
540 TestRegAddrScaledIndex(cmp, esi, edi, 8, 0, i8, 7, 0x3A, 0x34, 0xFD, 0x00,
541 0x00, 0x00, 0x00);
542 TestRegAddrScaledIndex(cmp, edi, eax, 1, 0, i8, 7, 0x3A, 0x3C, 0x05, 0x00,
543 0x00, 0x00, 0x00);
544 TestRegAddrScaledIndex(cmp, ebx, ecx, 8, 0, i8, 7, 0x3a, 0x1C, 0xCD, 0x00,
545 0x00, 0x00, 0x00);
546
547 /* cmp GPR, 0(Base,Index,Scale) */
548 TestRegAddrBaseScaledIndex(cmp, eax, ecx, edx, 1, 0, i32, 3, 0x3B, 0x04,
549 0x11);
550 TestRegAddrBaseScaledIndex(cmp, ecx, edx, ebx, 2, 0, i32, 3, 0x3B, 0x0C,
551 0x5A);
552 // esp cannot be an scaled index.
553 TestRegAddrBaseScaledIndex(cmp, ebx, esp, ebp, 4, 0, i32, 3, 0x3B, 0x1C,
554 0xAC);
555 TestRegAddrBaseScaledIndex(cmp, esp, ebp, esi, 8, 0, i32, 4, 0x3B, 0x64, 0xF5,
556 0x00);
557 TestRegAddrBaseScaledIndex(cmp, ebp, esi, edi, 1, 0, i32, 3, 0x3B, 0x2C,
558 0x3E);
559 TestRegAddrBaseScaledIndex(cmp, esi, edi, eax, 2, 0, i32, 3, 0x3B, 0x34,
560 0x47);
561 TestRegAddrBaseScaledIndex(cmp, edi, eax, ebx, 4, 0, i32, 3, 0x3B, 0x3C,
562 0x98);
563 TestRegAddrBaseScaledIndex(cmp, ebx, ecx, edx, 8, 0, i32, 3, 0x3B, 0x1C,
564 0xD1);
565
566 TestRegAddrBaseScaledIndex(cmp, eax, ecx, edx, 1, 0, i16, 4, 0x66, 0x3B, 0x04,
567 0x11);
568 TestRegAddrBaseScaledIndex(cmp, ecx, edx, ebx, 2, 0, i16, 4, 0x66, 0x3B, 0x0C,
569 0x5A);
570 // esp cannot be an scaled index.
571 TestRegAddrBaseScaledIndex(cmp, ebx, esp, ebp, 4, 0, i16, 4, 0x66, 0x3B, 0x1C,
572 0xAC);
573 TestRegAddrBaseScaledIndex(cmp, esp, ebp, esi, 8, 0, i16, 5, 0x66, 0x3B, 0x64,
574 0xF5, 0x00);
575 TestRegAddrBaseScaledIndex(cmp, ebp, esi, edi, 1, 0, i16, 4, 0x66, 0x3B, 0x2C,
576 0x3E);
577 TestRegAddrBaseScaledIndex(cmp, esi, edi, eax, 2, 0, i16, 4, 0x66, 0x3B, 0x34,
578 0x47);
579 TestRegAddrBaseScaledIndex(cmp, edi, eax, ebx, 4, 0, i16, 4, 0x66, 0x3B, 0x3C,
580 0x98);
581 TestRegAddrBaseScaledIndex(cmp, ebx, ecx, edx, 8, 0, i16, 4, 0x66, 0x3B, 0x1C,
582 0xD1);
583
584 TestRegAddrBaseScaledIndex(cmp, eax, ecx, edx, 1, 0, i8, 3, 0x3A, 0x04, 0x11);
585 TestRegAddrBaseScaledIndex(cmp, ecx, edx, ebx, 2, 0, i8, 3, 0x3A, 0x0C, 0x5A);
586 // esp cannot be an scaled index.
587 TestRegAddrBaseScaledIndex(cmp, ebx, esp, ebp, 4, 0, i8, 3, 0x3A, 0x1C, 0xAC);
588 TestRegAddrBaseScaledIndex(cmp, esp, ebp, esi, 8, 0, i8, 4, 0x3A, 0x64, 0xF5,
589 0x00);
590 TestRegAddrBaseScaledIndex(cmp, ebp, esi, edi, 1, 0, i8, 3, 0x3A, 0x2C, 0x3E);
591 TestRegAddrBaseScaledIndex(cmp, esi, edi, eax, 2, 0, i8, 3, 0x3A, 0x34, 0x47);
592 TestRegAddrBaseScaledIndex(cmp, edi, eax, ebx, 4, 0, i8, 3, 0x3A, 0x3C, 0x98);
593 TestRegAddrBaseScaledIndex(cmp, ebx, ecx, edx, 8, 0, i8, 3, 0x3A, 0x1C, 0xD1);
594
595 /* cmp GPR, Imm8(Base,Index,Scale) */
596 TestRegAddrBaseScaledIndex(cmp, eax, ecx, edx, 1, 0x40, i32, 4, 0x3B, 0x44,
597 0x11, 0x40);
598 TestRegAddrBaseScaledIndex(cmp, ecx, edx, ebx, 2, 0x40, i32, 4, 0x3B, 0x4C,
599 0x5A, 0x40);
600 // esp cannot be an scaled index.
601 TestRegAddrBaseScaledIndex(cmp, ebx, esp, ebp, 4, 0x40, i32, 4, 0x3B, 0x5C,
602 0xAC, 0x40);
603 TestRegAddrBaseScaledIndex(cmp, esp, ebp, esi, 8, 0x40, i32, 4, 0x3B, 0x64,
604 0xF5, 0x40);
605 TestRegAddrBaseScaledIndex(cmp, ebp, esi, edi, 1, 0x40, i32, 4, 0x3B, 0x6C,
606 0x3E, 0x40);
607 TestRegAddrBaseScaledIndex(cmp, esi, edi, eax, 2, 0x40, i32, 4, 0x3B, 0x74,
608 0x47, 0x40);
609 TestRegAddrBaseScaledIndex(cmp, edi, eax, ebx, 4, 0x40, i32, 4, 0x3B, 0x7C,
610 0x98, 0x40);
611 TestRegAddrBaseScaledIndex(cmp, ebx, ecx, edx, 8, 0x40, i32, 4, 0x3B, 0x5C,
612 0xD1, 0x40);
613
614 TestRegAddrBaseScaledIndex(cmp, eax, ecx, edx, 1, 0x40, i16, 5, 0x66, 0x3B,
615 0x44, 0x11, 0x40);
616 TestRegAddrBaseScaledIndex(cmp, ecx, edx, ebx, 2, 0x40, i16, 5, 0x66, 0x3B,
617 0x4C, 0x5A, 0x40);
618 // esp cannot be an scaled index.
619 TestRegAddrBaseScaledIndex(cmp, ebx, esp, ebp, 4, 0x40, i16, 5, 0x66, 0x3B,
620 0x5C, 0xAC, 0x40);
621 TestRegAddrBaseScaledIndex(cmp, esp, ebp, esi, 8, 0x40, i16, 5, 0x66, 0x3B,
622 0x64, 0xF5, 0x40);
623 TestRegAddrBaseScaledIndex(cmp, ebp, esi, edi, 1, 0x40, i16, 5, 0x66, 0x3B,
624 0x6C, 0x3E, 0x40);
625 TestRegAddrBaseScaledIndex(cmp, esi, edi, eax, 2, 0x40, i16, 5, 0x66, 0x3B,
626 0x74, 0x47, 0x40);
627 TestRegAddrBaseScaledIndex(cmp, edi, eax, ebx, 4, 0x40, i16, 5, 0x66, 0x3B,
628 0x7C, 0x98, 0x40);
629 TestRegAddrBaseScaledIndex(cmp, ebx, ecx, edx, 8, 0x40, i16, 5, 0x66, 0x3B,
630 0x5C, 0xD1, 0x40);
631
632 TestRegAddrBaseScaledIndex(cmp, eax, ecx, edx, 1, 0x40, i8, 4, 0x3A, 0x44,
633 0x11, 0x40);
634 TestRegAddrBaseScaledIndex(cmp, ecx, edx, ebx, 2, 0x40, i8, 4, 0x3A, 0x4C,
635 0x5A, 0x40);
636 // esp cannot be an scaled index.
637 TestRegAddrBaseScaledIndex(cmp, ebx, esp, ebp, 4, 0x40, i8, 4, 0x3A, 0x5C,
638 0xAC, 0x40);
639 TestRegAddrBaseScaledIndex(cmp, esp, ebp, esi, 8, 0x40, i8, 4, 0x3A, 0x64,
640 0xF5, 0x40);
641 TestRegAddrBaseScaledIndex(cmp, ebp, esi, edi, 1, 0x40, i8, 4, 0x3A, 0x6C,
642 0x3E, 0x40);
643 TestRegAddrBaseScaledIndex(cmp, esi, edi, eax, 2, 0x40, i8, 4, 0x3A, 0x74,
644 0x47, 0x40);
645 TestRegAddrBaseScaledIndex(cmp, edi, eax, ebx, 4, 0x40, i8, 4, 0x3A, 0x7C,
646 0x98, 0x40);
647 TestRegAddrBaseScaledIndex(cmp, ebx, ecx, edx, 8, 0x40, i8, 4, 0x3A, 0x5C,
648 0xD1, 0x40);
649
650 /* cmp GPR, Imm32(Base,Index,Scale) */
651 TestRegAddrBaseScaledIndex(cmp, eax, ecx, edx, 1, 0xF0, i32, 7, 0x3B, 0x84,
652 0x11, 0xF0, 0x00, 0x00, 0x00);
653 TestRegAddrBaseScaledIndex(cmp, ecx, edx, ebx, 2, 0xF0, i32, 7, 0x3B, 0x8C,
654 0x5A, 0xF0, 0x00, 0x00, 0x00);
655 // esp cannot be an scaled index.
656 TestRegAddrBaseScaledIndex(cmp, ebx, esp, ebp, 4, 0xF0, i32, 7, 0x3B, 0x9C,
657 0xAC, 0xF0, 0x00, 0x00, 0x00);
658 TestRegAddrBaseScaledIndex(cmp, esp, ebp, esi, 8, 0xF0, i32, 7, 0x3B, 0xA4,
659 0xF5, 0xF0, 0x00, 0x00, 0x00);
660 TestRegAddrBaseScaledIndex(cmp, ebp, esi, edi, 1, 0xF0, i32, 7, 0x3B, 0xAC,
661 0x3E, 0xF0, 0x00, 0x00, 0x00);
662 TestRegAddrBaseScaledIndex(cmp, esi, edi, eax, 2, 0xF0, i32, 7, 0x3B, 0xB4,
663 0x47, 0xF0, 0x00, 0x00, 0x00);
664 TestRegAddrBaseScaledIndex(cmp, edi, eax, ebx, 4, 0xF0, i32, 7, 0x3B, 0xBC,
665 0x98, 0xF0, 0x00, 0x00, 0x00);
666 TestRegAddrBaseScaledIndex(cmp, ebx, ecx, edx, 8, 0xF0, i32, 7, 0x3B, 0x9C,
667 0xD1, 0xF0, 0x00, 0x00, 0x00);
668
669 TestRegAddrBaseScaledIndex(cmp, eax, ecx, edx, 1, 0xF0, i16, 8, 0x66, 0x3B,
670 0x84, 0x11, 0xF0, 0x00, 0x00, 0x00);
671 TestRegAddrBaseScaledIndex(cmp, ecx, edx, ebx, 2, 0xF0, i16, 8, 0x66, 0x3B,
672 0x8C, 0x5A, 0xF0, 0x00, 0x00, 0x00);
673 // esp cannot be an scaled index.
674 TestRegAddrBaseScaledIndex(cmp, ebx, esp, ebp, 4, 0xF0, i16, 8, 0x66, 0x3B,
675 0x9C, 0xAC, 0xF0, 0x00, 0x00, 0x00);
676 TestRegAddrBaseScaledIndex(cmp, esp, ebp, esi, 8, 0xF0, i16, 8, 0x66, 0x3B,
677 0xA4, 0xF5, 0xF0, 0x00, 0x00, 0x00);
678 TestRegAddrBaseScaledIndex(cmp, ebp, esi, edi, 1, 0xF0, i16, 8, 0x66, 0x3B,
679 0xAC, 0x3E, 0xF0, 0x00, 0x00, 0x00);
680 TestRegAddrBaseScaledIndex(cmp, esi, edi, eax, 2, 0xF0, i16, 8, 0x66, 0x3B,
681 0xB4, 0x47, 0xF0, 0x00, 0x00, 0x00);
682 TestRegAddrBaseScaledIndex(cmp, edi, eax, ebx, 4, 0xF0, i16, 8, 0x66, 0x3B,
683 0xBC, 0x98, 0xF0, 0x00, 0x00, 0x00);
684 TestRegAddrBaseScaledIndex(cmp, ebx, ecx, edx, 8, 0xF0, i16, 8, 0x66, 0x3B,
685 0x9C, 0xD1, 0xF0, 0x00, 0x00, 0x00);
686
687 TestRegAddrBaseScaledIndex(cmp, eax, ecx, edx, 1, 0xF0, i8, 7, 0x3A, 0x84,
688 0x11, 0xF0, 0x00, 0x00, 0x00);
689 TestRegAddrBaseScaledIndex(cmp, ecx, edx, ebx, 2, 0xF0, i8, 7, 0x3A, 0x8C,
690 0x5A, 0xF0, 0x00, 0x00, 0x00);
691 // esp cannot be an scaled index.
692 TestRegAddrBaseScaledIndex(cmp, ebx, esp, ebp, 4, 0xF0, i8, 7, 0x3A, 0x9C,
693 0xAC, 0xF0, 0x00, 0x00, 0x00);
694 TestRegAddrBaseScaledIndex(cmp, esp, ebp, esi, 8, 0xF0, i8, 7, 0x3A, 0xA4,
695 0xF5, 0xF0, 0x00, 0x00, 0x00);
696 TestRegAddrBaseScaledIndex(cmp, ebp, esi, edi, 1, 0xF0, i8, 7, 0x3A, 0xAC,
697 0x3E, 0xF0, 0x00, 0x00, 0x00);
698 TestRegAddrBaseScaledIndex(cmp, esi, edi, eax, 2, 0xF0, i8, 7, 0x3A, 0xB4,
699 0x47, 0xF0, 0x00, 0x00, 0x00);
700 TestRegAddrBaseScaledIndex(cmp, edi, eax, ebx, 4, 0xF0, i8, 7, 0x3A, 0xBC,
701 0x98, 0xF0, 0x00, 0x00, 0x00);
702 TestRegAddrBaseScaledIndex(cmp, ebx, ecx, edx, 8, 0xF0, i8, 7, 0x3A, 0x9C,
703 0xD1, 0xF0, 0x00, 0x00, 0x00);
704
705 /* cmp Addr, Imm */
706 // Note: at this point we trust the assembler knows how to encode addresses,
707 // so no more exhaustive addressing mode testing.
708 TestAddrBaseScaledIndexImm(cmp, eax, ecx, 1, 0xF0, 0x12, i32, 8, 0x83, 0xBC,
709 0x08, 0xF0, 0x00, 0x00, 0x00, 0x12);
710 TestAddrBaseScaledIndexImm(cmp, ecx, edx, 1, 0xF0, 0xF0, i32, 11, 0x81, 0xBC,
711 0x11, 0xF0, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00,
712 0x00);
713
714 TestAddrBaseScaledIndexImm(cmp, eax, ecx, 1, 0xF0, 0x12, i16, 9, 0x66, 0x83,
715 0xBC, 0x08, 0xF0, 0x00, 0x00, 0x00, 0x12);
716 TestAddrBaseScaledIndexImm(cmp, ecx, edx, 1, 0xF0, 0xF0, i16, 10, 0x66, 0x81,
717 0xBC, 0x11, 0xF0, 0x00, 0x00, 0x00, 0xF0, 0x00);
718
719 TestAddrBaseScaledIndexImm(cmp, eax, ecx, 1, 0xF0, 0x12, i8, 8, 0x80, 0xBC,
720 0x08, 0xF0, 0x00, 0x00, 0x00, 0x12);
721
722 /* cmp Addr, GPR */
723 TestAddrBaseScaledIndexReg(cmp, eax, ecx, 1, 0xF0, edx, i32, 7, 0x39, 0x94,
724 0x08, 0xF0, 0x00, 0x00, 0x00);
725
726 TestAddrBaseScaledIndexReg(cmp, eax, ecx, 1, 0xF0, edx, i16, 8, 0x66, 0x39,
727 0x94, 0x08, 0xF0, 0x00, 0x00, 0x00);
728
729 TestAddrBaseScaledIndexReg(cmp, eax, ecx, 1, 0xF0, edx, i8, 7, 0x38, 0x94,
730 0x08, 0xF0, 0x00, 0x00, 0x00);
731
732 #undef TestAddrBaseScaledIndexReg
733 #undef TestAddrBaseScaledIndexImm
734 #undef TestRegAddrBaseScaledIndex
735 #undef TestRegAddrScaledIndex
736 #undef TestRegAddrBase
737 #undef TestRegAbsoluteAddr
738 #undef TestRegImm
739 #undef TestRegReg
740 }
741
742 // After these tests we should have a sane environment; we know the following
743 // work:
744 //
745 // (*) zeroing eax, ebx, ecx, edx, edi, and esi;
746 // (*) call $4 instruction (used for ip materialization);
747 // (*) register push and pop;
748 // (*) cmp reg, reg; and
749 // (*) returning from functions.
750 //
751 // We can now dive into testing each emitting method in AssemblerX8664. Each
752 // test will emit some instructions for performing the test. The assembled
753 // instructions will operate in a "safe" environment. All x86-32 registers are
754 // spilled to the program stack, and the registers are then zeroed out, with the
755 // exception of %esp and %ebp.
756 //
757 // The jitted code and the unittest code will share the same stack. Therefore,
758 // test harnesses need to ensure it does not leave anything it pushed on the
759 // stack.
760 //
761 // %ebp is initialized with a pointer for rIP-based addressing. This pointer is
762 // used for position-independent access to a scratchpad area for use in tests.
763 // This mechanism is used because the test framework needs to generate addresses
764 // that work on both x86-32 and x86-64 hosts, but are encodable using our x86-32
765 // assembler. This is made possible because the encoding for
766 //
767 // pushq %rax (x86-64 only)
768 //
769 // is the same as the one for
770 //
771 // pushl %eax (x86-32 only; not encodable in x86-64)
772 //
773 // Likewise, the encodings for
774 //
775 // movl offset(%ebp), %reg (32-bit only)
776 // movl <src>, offset(%ebp) (32-bit only)
777 //
778 // and
779 //
780 // movl offset(%rbp), %reg (64-bit only)
781 // movl <src>, offset(%rbp) (64-bit only)
782 //
783 // are also the same.
784 //
785 // We use a call instruction in order to generate a natural sized address on the
786 // stack. Said address is then removed from the stack with a pop %rBP, which can
787 // then be used to address memory safely in either x86-32 or x86-64, as long as
788 // the test code does not perform any arithmetic operation that writes to %rBP.
789 // This PC materialization technique is very common in x86-32 PIC.
790 //
791 // %rBP is used to provide the tests with a scratchpad area that can safely and
792 // portably be written to and read from. This scratchpad area is also used to
793 // store the "final" values in eax, ebx, ecx, edx, esi, and edi, allowing the
794 // harnesses access to 6 "return values" instead of the usual single return
795 // value supported by C++.
796 //
797 // The jitted code will look like the following:
798 //
799 // test:
800 // push %eax
801 // push %ebx
802 // push %ecx
803 // push %edx
804 // push %edi
805 // push %esi
806 // push %ebp
807 // call test$materialize_ip
808 // test$materialize_ip: <<------- %eBP will point here
809 // pop %ebp
810 // mov $0, %eax
811 // mov $0, %ebx
812 // mov $0, %ecx
813 // mov $0, %edx
814 // mov $0, %edi
815 // mov $0, %esi
816 //
817 // << test code goes here >>
818 //
819 // mov %eax, { 0 + $ScratchpadOffset}(%ebp)
820 // mov %ebx, { 4 + $ScratchpadOffset}(%ebp)
821 // mov %ecx, { 8 + $ScratchpadOffset}(%ebp)
822 // mov %edx, {12 + $ScratchpadOffset}(%ebp)
823 // mov %edi, {16 + $ScratchpadOffset}(%ebp)
824 // mov %esi, {20 + $ScratchpadOffset}(%ebp)
825 // mov %ebp, {24 + $ScratchpadOffset}(%ebp)
826 // mov %esp, {28 + $ScratchpadOffset}(%ebp)
827 // movups %xmm0, {32 + $ScratchpadOffset}(%ebp)
828 // movups %xmm1, {48 + $ScratchpadOffset}(%ebp)
829 // movups %xmm2, {64 + $ScratchpadOffset}(%ebp)
830 // movusp %xmm3, {80 + $ScratchpadOffset}(%ebp)
831 // movusp %xmm4, {96 + $ScratchpadOffset}(%ebp)
832 // movusp %xmm5, {112 + $ScratchpadOffset}(%ebp)
833 // movusp %xmm6, {128 + $ScratchpadOffset}(%ebp)
834 // movusp %xmm7, {144 + $ScratchpadOffset}(%ebp)
835 //
836 // pop %ebp
837 // pop %esi
838 // pop %edi
839 // pop %edx
840 // pop %ecx
841 // pop %ebx
842 // pop %eax
843 // ret
844 //
845 // << ... >>
846 //
847 // scratchpad: <<------- accessed via $Offset(%ebp)
848 //
849 // << test scratch area >>
850 //
851 // TODO(jpp): test the
852 //
853 // mov %reg, $Offset(%ebp)
854 // movups %xmm, $Offset(%ebp)
855 //
856 // encodings using the low level assembler test ensuring that the register
857 // values can be written to the scratchpad area.
858 class AssemblerX8664Test : public AssemblerX8664TestBase {
859 protected:
860 // Dqword is used to represent 128-bit data types. The Dqword's contents are
861 // the same as the contents read from memory. Tests can then use the union
862 // members to verify the tests' outputs.
863 //
864 // NOTE: We want sizeof(Dqword) == sizeof(uint64_t) * 2. In other words, we
865 // want Dqword's contents to be **exactly** what the memory contents were so
866 // that we can do, e.g.,
867 //
868 // ...
869 // float Ret[4];
870 // // populate Ret
871 // return *reinterpret_cast<Dqword *>(&Ret);
872 //
873 // While being an ugly hack, this kind of return statements are used
874 // extensively in the PackedArith (see below) class.
875 union Dqword {
876 template <typename T0, typename T1, typename T2, typename T3,
877 typename = typename std::enable_if<
878 std::is_floating_point<T0>::value>::type>
879 Dqword(T0 F0, T1 F1, T2 F2, T3 F3) {
880 F32[0] = F0;
881 F32[1] = F1;
882 F32[2] = F2;
883 F32[3] = F3;
884 }
885
886 template <typename T>
887 Dqword(typename std::enable_if<std::is_same<T, int32_t>::value, T>::type I0,
888 T I1, T I2, T I3) {
889 I32[0] = I0;
890 I32[1] = I1;
891 I32[2] = I2;
892 I32[3] = I3;
893 }
894
895 template <typename T>
896 Dqword(typename std::enable_if<std::is_same<T, uint64_t>::value, T>::type
897 U64_0,
898 T U64_1) {
899 U64[0] = U64_0;
900 U64[1] = U64_1;
901 }
902
903 template <typename T>
904 Dqword(typename std::enable_if<std::is_same<T, double>::value, T>::type D0,
905 T D1) {
906 F64[0] = D0;
907 F64[1] = D1;
908 }
909
910 bool operator==(const Dqword &Rhs) const {
911 return std::memcmp(this, &Rhs, sizeof(*this)) == 0;
912 }
913
914 double F64[2];
915 uint64_t U64[2];
916 int64_t I64[2];
917
918 float F32[4];
919 uint32_t U32[4];
920 int32_t I32[4];
921
922 uint16_t U16[8];
923 int16_t I16[8];
924
925 uint8_t U8[16];
926 int8_t I8[16];
927
928 private:
929 Dqword() = delete;
930 };
931
932 // As stated, we want this condition to hold, so we assert.
933 static_assert(sizeof(Dqword) == 2 * sizeof(uint64_t),
934 "Dqword has the wrong size.");
935
936 // PackedArith is an interface provider for Dqwords. PackedArith's C argument
937 // is the undelying Dqword's type, which is then used so that we can define
938 // operators in terms of C++ operators on the underlying elements' type.
939 template <typename C> class PackedArith {
940 public:
941 static constexpr uint32_t N = sizeof(Dqword) / sizeof(C);
942 static_assert(N * sizeof(C) == sizeof(Dqword),
943 "Invalid template paramenter.");
944 static_assert((N & 1) == 0, "N should be divisible by 2");
945
946 #define DefinePackedComparisonOperator(Op) \
947 template <typename Container = C, int Size = N> \
948 typename std::enable_if<std::is_floating_point<Container>::value, \
949 Dqword>::type \
950 operator Op(const Dqword &Rhs) const { \
951 using ElemType = \
952 typename std::conditional<std::is_same<float, Container>::value, \
953 int32_t, int64_t>::type; \
954 static_assert(sizeof(ElemType) == sizeof(Container), \
955 "Check ElemType definition."); \
956 const ElemType *const RhsPtr = \
957 reinterpret_cast<const ElemType *const>(&Rhs); \
958 const ElemType *const LhsPtr = \
959 reinterpret_cast<const ElemType *const>(&Lhs); \
960 ElemType Ret[N]; \
961 for (uint32_t i = 0; i < N; ++i) { \
962 Ret[i] = (LhsPtr[i] Op RhsPtr[i]) ? -1 : 0; \
963 } \
964 return *reinterpret_cast<Dqword *>(&Ret); \
965 }
966
967 DefinePackedComparisonOperator(< );
968 DefinePackedComparisonOperator(<= );
969 DefinePackedComparisonOperator(> );
970 DefinePackedComparisonOperator(>= );
971 DefinePackedComparisonOperator(== );
972 DefinePackedComparisonOperator(!= );
973
974 #undef DefinePackedComparisonOperator
975
976 #define DefinePackedOrdUnordComparisonOperator(Op, Ordered) \
977 template <typename Container = C, int Size = N> \
978 typename std::enable_if<std::is_floating_point<Container>::value, \
979 Dqword>::type \
980 Op(const Dqword &Rhs) const { \
981 using ElemType = \
982 typename std::conditional<std::is_same<float, Container>::value, \
983 int32_t, int64_t>::type; \
984 static_assert(sizeof(ElemType) == sizeof(Container), \
985 "Check ElemType definition."); \
986 const Container *const RhsPtr = \
987 reinterpret_cast<const Container *const>(&Rhs); \
988 const Container *const LhsPtr = \
989 reinterpret_cast<const Container *const>(&Lhs); \
990 ElemType Ret[N]; \
991 for (uint32_t i = 0; i < N; ++i) { \
992 Ret[i] = (!(LhsPtr[i] == LhsPtr[i]) || !(RhsPtr[i] == RhsPtr[i])) != \
993 (Ordered) \
994 ? -1 \
995 : 0; \
996 } \
997 return *reinterpret_cast<Dqword *>(&Ret); \
998 }
999
1000 DefinePackedOrdUnordComparisonOperator(ord, true);
1001 DefinePackedOrdUnordComparisonOperator(unord, false);
1002 #undef DefinePackedOrdUnordComparisonOperator
1003
1004 #define DefinePackedArithOperator(Op, RhsIndexChanges, NeedsInt) \
1005 template <typename Container = C, int Size = N> \
1006 Dqword operator Op(const Dqword &Rhs) const { \
1007 using ElemTypeForFp = typename std::conditional< \
1008 !(NeedsInt), Container, \
1009 typename std::conditional< \
1010 std::is_same<Container, float>::value, uint32_t, \
1011 typename std::conditional<std::is_same<Container, double>::value, \
1012 uint64_t, void>::type>::type>::type; \
1013 using ElemType = \
1014 typename std::conditional<std::is_integral<Container>::value, \
1015 Container, ElemTypeForFp>::type; \
1016 static_assert(!std::is_same<void, ElemType>::value, \
1017 "Check ElemType definition."); \
1018 const ElemType *const RhsPtr = \
1019 reinterpret_cast<const ElemType *const>(&Rhs); \
1020 const ElemType *const LhsPtr = \
1021 reinterpret_cast<const ElemType *const>(&Lhs); \
1022 ElemType Ret[N]; \
1023 for (uint32_t i = 0; i < N; ++i) { \
1024 Ret[i] = LhsPtr[i] Op RhsPtr[(RhsIndexChanges) ? i : 0]; \
1025 } \
1026 return *reinterpret_cast<Dqword *>(&Ret); \
1027 }
1028
1029 DefinePackedArithOperator(>>, false, true);
1030 DefinePackedArithOperator(<<, false, true);
1031 DefinePackedArithOperator(+, true, false);
1032 DefinePackedArithOperator(-, true, false);
1033 DefinePackedArithOperator(/, true, false);
1034 DefinePackedArithOperator(&, true, true);
1035 DefinePackedArithOperator(|, true, true);
1036 DefinePackedArithOperator (^, true, true);
1037
1038 #undef DefinePackedArithOperator
1039
1040 #define DefinePackedArithShiftImm(Op) \
1041 template <typename Container = C, int Size = N> \
1042 Dqword operator Op(uint8_t imm) const { \
1043 const Container *const LhsPtr = \
1044 reinterpret_cast<const Container *const>(&Lhs); \
1045 Container Ret[N]; \
1046 for (uint32_t i = 0; i < N; ++i) { \
1047 Ret[i] = LhsPtr[i] Op imm; \
1048 } \
1049 return *reinterpret_cast<Dqword *>(&Ret); \
1050 }
1051
1052 DefinePackedArithShiftImm(>> );
1053 DefinePackedArithShiftImm(<< );
1054
1055 #undef DefinePackedArithShiftImm
1056
1057 template <typename Container = C, int Size = N>
1058 typename std::enable_if<std::is_signed<Container>::value ||
1059 std::is_floating_point<Container>::value,
1060 Dqword>::type
1061 operator*(const Dqword &Rhs) const {
1062 static_assert((std::is_integral<Container>::value &&
1063 sizeof(Container) < sizeof(uint64_t)) ||
1064 std::is_floating_point<Container>::value,
1065 "* is only defined for i(8|16|32), and fp types.");
1066
1067 const Container *const RhsPtr =
1068 reinterpret_cast<const Container *const>(&Rhs);
1069 const Container *const LhsPtr =
1070 reinterpret_cast<const Container *const>(&Lhs);
1071 Container Ret[Size];
1072 for (uint32_t i = 0; i < Size; ++i) {
1073 Ret[i] = LhsPtr[i] * RhsPtr[i];
1074 }
1075 return *reinterpret_cast<Dqword *>(&Ret);
1076 }
1077
1078 template <typename Container = C, int Size = N,
1079 typename = typename std::enable_if<
1080 !std::is_signed<Container>::value>::type>
1081 Dqword operator*(const Dqword &Rhs) const {
1082 static_assert(std::is_integral<Container>::value &&
1083 sizeof(Container) < sizeof(uint64_t),
1084 "* is only defined for ui(8|16|32)");
1085 using NextType = typename std::conditional<
1086 sizeof(Container) == 1, uint16_t,
1087 typename std::conditional<sizeof(Container) == 2, uint32_t,
1088 uint64_t>::type>::type;
1089 static_assert(sizeof(Container) * 2 == sizeof(NextType),
1090 "Unexpected size");
1091
1092 const Container *const RhsPtr =
1093 reinterpret_cast<const Container *const>(&Rhs);
1094 const Container *const LhsPtr =
1095 reinterpret_cast<const Container *const>(&Lhs);
1096 NextType Ret[Size / 2];
1097 for (uint32_t i = 0; i < Size; i += 2) {
1098 Ret[i / 2] =
1099 static_cast<NextType>(LhsPtr[i]) * static_cast<NextType>(RhsPtr[i]);
1100 }
1101 return *reinterpret_cast<Dqword *>(&Ret);
1102 }
1103
1104 template <typename Container = C, int Size = N>
1105 PackedArith<Container> operator~() const {
1106 const Container *const LhsPtr =
1107 reinterpret_cast<const Container *const>(&Lhs);
1108 Container Ret[Size];
1109 for (uint32_t i = 0; i < Size; ++i) {
1110 Ret[i] = ~LhsPtr[i];
1111 }
1112 return PackedArith<Container>(*reinterpret_cast<Dqword *>(&Ret));
1113 }
1114
1115 #define MinMaxOperations(Name, Suffix) \
1116 template <typename Container = C, int Size = N> \
1117 Dqword Name##Suffix(const Dqword &Rhs) const { \
1118 static_assert(std::is_floating_point<Container>::value, \
1119 #Name #Suffix "ps is only available for fp."); \
1120 const Container *const RhsPtr = \
1121 reinterpret_cast<const Container *const>(&Rhs); \
1122 const Container *const LhsPtr = \
1123 reinterpret_cast<const Container *const>(&Lhs); \
1124 Container Ret[Size]; \
1125 for (uint32_t i = 0; i < Size; ++i) { \
1126 Ret[i] = std::Name(LhsPtr[i], RhsPtr[i]); \
1127 } \
1128 return *reinterpret_cast<Dqword *>(&Ret); \
1129 }
1130
1131 MinMaxOperations(max, ps);
1132 MinMaxOperations(max, pd);
1133 MinMaxOperations(min, ps);
1134 MinMaxOperations(min, pd);
1135 #undef MinMaxOperations
1136
1137 template <typename Container = C, int Size = N>
1138 Dqword blendWith(const Dqword &Rhs, const Dqword &Mask) const {
1139 using MaskType = typename std::conditional<
1140 sizeof(Container) == 1, int8_t,
1141 typename std::conditional<sizeof(Container) == 2, int16_t,
1142 int32_t>::type>::type;
1143 static_assert(sizeof(MaskType) == sizeof(Container),
1144 "MaskType has the wrong size.");
1145 const Container *const RhsPtr =
1146 reinterpret_cast<const Container *const>(&Rhs);
1147 const Container *const LhsPtr =
1148 reinterpret_cast<const Container *const>(&Lhs);
1149 const MaskType *const MaskPtr =
1150 reinterpret_cast<const MaskType *const>(&Mask);
1151 Container Ret[Size];
1152 for (int i = 0; i < Size; ++i) {
1153 Ret[i] = ((MaskPtr[i] < 0) ? RhsPtr : LhsPtr)[i];
1154 }
1155 return *reinterpret_cast<Dqword *>(&Ret);
1156 }
1157
1158 private:
1159 // The AssemblerX8664Test class needs to be a friend so that it can create
1160 // PackedArith objects (see below.)
1161 friend class AssemblerX8664Test;
1162
1163 explicit PackedArith(const Dqword &MyLhs) : Lhs(MyLhs) {}
1164
1165 // Lhs can't be a & because operator~ returns a temporary object that needs
1166 // access to its own Dqword.
1167 const Dqword Lhs;
1168 };
1169
1170 // Named constructor for PackedArith objects.
1171 template <typename C> static PackedArith<C> packedAs(const Dqword &D) {
1172 return PackedArith<C>(D);
1173 }
1174
1175 AssemblerX8664Test() { reset(); }
1176
1177 void reset() {
1178 AssemblerX8664TestBase::reset();
1179
1180 NeedsEpilogue = true;
1181 // These dwords are allocated for saving the GPR state after the jitted code
1182 // runs.
1183 NumAllocatedDwords = AssembledTest::ScratchpadSlots;
1184 addPrologue();
1185 }
1186
1187 // AssembledTest is a wrapper around a PROT_EXEC mmap'ed buffer. This buffer
1188 // contains both the test code as well as prologue/epilogue, and the
1189 // scratchpad area that tests may use -- all tests use this scratchpad area
1190 // for storing the processor's registers after the tests executed. This class
1191 // also exposes helper methods for reading the register state after test
1192 // execution, as well as for reading the scratchpad area.
1193 class AssembledTest {
1194 AssembledTest() = delete;
1195 AssembledTest(const AssembledTest &) = delete;
1196 AssembledTest &operator=(const AssembledTest &) = delete;
1197
1198 public:
1199 static constexpr uint32_t MaximumCodeSize = 1 << 20;
1200 static constexpr uint32_t EaxSlot = 0;
1201 static constexpr uint32_t EbxSlot = 1;
1202 static constexpr uint32_t EcxSlot = 2;
1203 static constexpr uint32_t EdxSlot = 3;
1204 static constexpr uint32_t EdiSlot = 4;
1205 static constexpr uint32_t EsiSlot = 5;
1206 static constexpr uint32_t EbpSlot = 6;
1207 static constexpr uint32_t EspSlot = 7;
1208 // save 4 dwords for each xmm registers.
1209 static constexpr uint32_t Xmm0Slot = 8;
1210 static constexpr uint32_t Xmm1Slot = 12;
1211 static constexpr uint32_t Xmm2Slot = 16;
1212 static constexpr uint32_t Xmm3Slot = 20;
1213 static constexpr uint32_t Xmm4Slot = 24;
1214 static constexpr uint32_t Xmm5Slot = 28;
1215 static constexpr uint32_t Xmm6Slot = 32;
1216 static constexpr uint32_t Xmm7Slot = 36;
1217 static constexpr uint32_t ScratchpadSlots = 40;
1218
1219 AssembledTest(const uint8_t *Data, const size_t MySize,
1220 const size_t ExtraStorageDwords)
1221 : Size(MaximumCodeSize + 4 * ExtraStorageDwords) {
1222 // MaxCodeSize is needed because EXPECT_LT needs a symbol with a name --
1223 // probably a compiler bug?
1224 uint32_t MaxCodeSize = MaximumCodeSize;
1225 EXPECT_LT(MySize, MaxCodeSize);
1226 assert(MySize < MaximumCodeSize);
1227 ExecutableData = mmap(nullptr, Size, PROT_WRITE | PROT_READ | PROT_EXEC,
1228 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
1229 EXPECT_NE(MAP_FAILED, ExecutableData) << strerror(errno);
1230 assert(MAP_FAILED != ExecutableData);
1231 std::memcpy(ExecutableData, Data, MySize);
1232 }
1233
1234 // We allow AssembledTest to be moved so that we can return objects of
1235 // this type.
1236 AssembledTest(AssembledTest &&Buffer)
1237 : ExecutableData(Buffer.ExecutableData), Size(Buffer.Size) {
1238 Buffer.ExecutableData = nullptr;
1239 Buffer.Size = 0;
1240 }
1241
1242 AssembledTest &operator=(AssembledTest &&Buffer) {
1243 ExecutableData = Buffer.ExecutableData;
1244 Buffer.ExecutableData = nullptr;
1245 Size = Buffer.Size;
1246 Buffer.Size = 0;
1247 return *this;
1248 }
1249
1250 ~AssembledTest() {
1251 if (ExecutableData != nullptr) {
1252 munmap(ExecutableData, Size);
1253 ExecutableData = nullptr;
1254 }
1255 }
1256
1257 void run() const { reinterpret_cast<void (*)()>(ExecutableData)(); }
1258
1259 uint32_t eax() const { return contentsOfDword(AssembledTest::EaxSlot); }
1260
1261 uint32_t ebx() const { return contentsOfDword(AssembledTest::EbxSlot); }
1262
1263 uint32_t ecx() const { return contentsOfDword(AssembledTest::EcxSlot); }
1264
1265 uint32_t edx() const { return contentsOfDword(AssembledTest::EdxSlot); }
1266
1267 uint32_t edi() const { return contentsOfDword(AssembledTest::EdiSlot); }
1268
1269 uint32_t esi() const { return contentsOfDword(AssembledTest::EsiSlot); }
1270
1271 uint32_t ebp() const { return contentsOfDword(AssembledTest::EbpSlot); }
1272
1273 uint32_t esp() const { return contentsOfDword(AssembledTest::EspSlot); }
1274
1275 template <typename T> T xmm0() const {
1276 return xmm<T>(AssembledTest::Xmm0Slot);
1277 }
1278
1279 template <typename T> T xmm1() const {
1280 return xmm<T>(AssembledTest::Xmm1Slot);
1281 }
1282
1283 template <typename T> T xmm2() const {
1284 return xmm<T>(AssembledTest::Xmm2Slot);
1285 }
1286
1287 template <typename T> T xmm3() const {
1288 return xmm<T>(AssembledTest::Xmm3Slot);
1289 }
1290
1291 template <typename T> T xmm4() const {
1292 return xmm<T>(AssembledTest::Xmm4Slot);
1293 }
1294
1295 template <typename T> T xmm5() const {
1296 return xmm<T>(AssembledTest::Xmm5Slot);
1297 }
1298
1299 template <typename T> T xmm6() const {
1300 return xmm<T>(AssembledTest::Xmm6Slot);
1301 }
1302
1303 template <typename T> T xmm7() const {
1304 return xmm<T>(AssembledTest::Xmm7Slot);
1305 }
1306
1307 // contentsOfDword is used for reading the values in the scratchpad area.
1308 // Valid arguments are the dword ids returned by
1309 // AssemblerX8664Test::allocateDword() -- other inputs are considered
1310 // invalid, and are not guaranteed to work if the implementation changes.
1311 template <typename T = uint32_t, typename = typename std::enable_if<
1312 sizeof(T) == sizeof(uint32_t)>::type>
1313 T contentsOfDword(uint32_t Dword) const {
1314 return *reinterpret_cast<T *>(static_cast<uint8_t *>(ExecutableData) +
1315 dwordOffset(Dword));
1316 }
1317
1318 template <typename T = uint64_t, typename = typename std::enable_if<
1319 sizeof(T) == sizeof(uint64_t)>::type>
1320 T contentsOfQword(uint32_t InitialDword) const {
1321 return *reinterpret_cast<T *>(static_cast<uint8_t *>(ExecutableData) +
1322 dwordOffset(InitialDword));
1323 }
1324
1325 Dqword contentsOfDqword(uint32_t InitialDword) const {
1326 return *reinterpret_cast<Dqword *>(
1327 static_cast<uint8_t *>(ExecutableData) +
1328 dwordOffset(InitialDword));
1329 }
1330
1331 template <typename T = uint32_t, typename = typename std::enable_if<
1332 sizeof(T) == sizeof(uint32_t)>::type>
1333 void setDwordTo(uint32_t Dword, T value) {
1334 *reinterpret_cast<uint32_t *>(static_cast<uint8_t *>(ExecutableData) +
1335 dwordOffset(Dword)) =
1336 *reinterpret_cast<uint32_t *>(&value);
1337 }
1338
1339 template <typename T = uint64_t, typename = typename std::enable_if<
1340 sizeof(T) == sizeof(uint64_t)>::type>
1341 void setQwordTo(uint32_t InitialDword, T value) {
1342 *reinterpret_cast<uint64_t *>(static_cast<uint8_t *>(ExecutableData) +
1343 dwordOffset(InitialDword)) =
1344 *reinterpret_cast<uint64_t *>(&value);
1345 }
1346
1347 void setDqwordTo(uint32_t InitialDword, const Dqword &qdword) {
1348 setQwordTo(InitialDword, qdword.U64[0]);
1349 setQwordTo(InitialDword + 2, qdword.U64[1]);
1350 }
1351
1352 private:
1353 template <typename T>
1354 typename std::enable_if<std::is_same<T, Dqword>::value, Dqword>::type
1355 xmm(uint8_t Slot) const {
1356 return contentsOfDqword(Slot);
1357 }
1358
1359 template <typename T>
1360 typename std::enable_if<!std::is_same<T, Dqword>::value, T>::type
1361 xmm(uint8_t Slot) const {
1362 constexpr bool TIs64Bit = sizeof(T) == sizeof(uint64_t);
1363 using _64BitType = typename std::conditional<TIs64Bit, T, uint64_t>::type;
1364 using _32BitType = typename std::conditional<TIs64Bit, uint32_t, T>::type;
1365 if (TIs64Bit) {
1366 return contentsOfQword<_64BitType>(Slot);
1367 }
1368 return contentsOfDword<_32BitType>(Slot);
1369 }
1370
1371 static uint32_t dwordOffset(uint32_t Index) {
1372 return MaximumCodeSize + (Index * 4);
1373 }
1374
1375 void *ExecutableData = nullptr;
1376 size_t Size;
1377 };
1378
1379 // assemble created an AssembledTest with the jitted code. The first time
1380 // assemble is executed it will add the epilogue to the jitted code (which is
1381 // the reason why this method is not const qualified.
1382 AssembledTest assemble() {
1383 if (NeedsEpilogue) {
1384 addEpilogue();
1385 }
1386
1387 NeedsEpilogue = false;
1388 return AssembledTest(codeBytes(), codeBytesSize(), NumAllocatedDwords);
1389 }
1390
1391 // Allocates a new dword slot in the test's scratchpad area.
1392 uint32_t allocateDword() { return NumAllocatedDwords++; }
1393
1394 // Allocates a new qword slot in the test's scratchpad area.
1395 uint32_t allocateQword() {
1396 uint32_t InitialDword = allocateDword();
1397 allocateDword();
1398 return InitialDword;
1399 }
1400
1401 // Allocates a new dqword slot in the test's scratchpad area.
1402 uint32_t allocateDqword() {
1403 uint32_t InitialDword = allocateQword();
1404 allocateQword();
1405 return InitialDword;
1406 }
1407
1408 Address dwordAddress(uint32_t Dword) {
1409 return Address(GPRRegister::Encoded_Reg_ebp, dwordDisp(Dword));
1410 }
1411
1412 private:
1413 // e??SlotAddress returns an AssemblerX8664::Traits::Address that can be used
1414 // by the test cases to encode an address operand for accessing the slot for
1415 // the specified register. These are all private for, when jitting the test
1416 // code, tests should not tamper with these values. Besides, during the test
1417 // execution these slots' contents are undefined and should not be accessed.
1418 Address eaxSlotAddress() { return dwordAddress(AssembledTest::EaxSlot); }
1419 Address ebxSlotAddress() { return dwordAddress(AssembledTest::EbxSlot); }
1420 Address ecxSlotAddress() { return dwordAddress(AssembledTest::EcxSlot); }
1421 Address edxSlotAddress() { return dwordAddress(AssembledTest::EdxSlot); }
1422 Address ediSlotAddress() { return dwordAddress(AssembledTest::EdiSlot); }
1423 Address esiSlotAddress() { return dwordAddress(AssembledTest::EsiSlot); }
1424 Address ebpSlotAddress() { return dwordAddress(AssembledTest::EbpSlot); }
1425 Address espSlotAddress() { return dwordAddress(AssembledTest::EspSlot); }
1426 Address xmm0SlotAddress() { return dwordAddress(AssembledTest::Xmm0Slot); }
1427 Address xmm1SlotAddress() { return dwordAddress(AssembledTest::Xmm1Slot); }
1428 Address xmm2SlotAddress() { return dwordAddress(AssembledTest::Xmm2Slot); }
1429 Address xmm3SlotAddress() { return dwordAddress(AssembledTest::Xmm3Slot); }
1430 Address xmm4SlotAddress() { return dwordAddress(AssembledTest::Xmm4Slot); }
1431 Address xmm5SlotAddress() { return dwordAddress(AssembledTest::Xmm5Slot); }
1432 Address xmm6SlotAddress() { return dwordAddress(AssembledTest::Xmm6Slot); }
1433 Address xmm7SlotAddress() { return dwordAddress(AssembledTest::Xmm7Slot); }
1434
1435 // Returns the displacement that should be used when accessing the specified
1436 // Dword in the scratchpad area. It needs to adjust for the initial
1437 // instructions that are emitted before the call that materializes the IP
1438 // register.
1439 uint32_t dwordDisp(uint32_t Dword) const {
1440 EXPECT_LT(Dword, NumAllocatedDwords);
1441 assert(Dword < NumAllocatedDwords);
1442 static constexpr uint8_t PushBytes = 1;
1443 static constexpr uint8_t CallImmBytes = 5;
1444 return AssembledTest::MaximumCodeSize + (Dword * 4) -
1445 (7 * PushBytes + CallImmBytes);
1446 }
1447
1448 void addPrologue() {
1449 __ pushl(GPRRegister::Encoded_Reg_eax);
1450 __ pushl(GPRRegister::Encoded_Reg_ebx);
1451 __ pushl(GPRRegister::Encoded_Reg_ecx);
1452 __ pushl(GPRRegister::Encoded_Reg_edx);
1453 __ pushl(GPRRegister::Encoded_Reg_edi);
1454 __ pushl(GPRRegister::Encoded_Reg_esi);
1455 __ pushl(GPRRegister::Encoded_Reg_ebp);
1456
1457 __ call(Immediate(4));
1458 __ popl(GPRRegister::Encoded_Reg_ebp);
1459 __ mov(IceType_i32, GPRRegister::Encoded_Reg_eax, Immediate(0x00));
1460 __ mov(IceType_i32, GPRRegister::Encoded_Reg_ebx, Immediate(0x00));
1461 __ mov(IceType_i32, GPRRegister::Encoded_Reg_ecx, Immediate(0x00));
1462 __ mov(IceType_i32, GPRRegister::Encoded_Reg_edx, Immediate(0x00));
1463 __ mov(IceType_i32, GPRRegister::Encoded_Reg_edi, Immediate(0x00));
1464 __ mov(IceType_i32, GPRRegister::Encoded_Reg_esi, Immediate(0x00));
1465 }
1466
1467 void addEpilogue() {
1468 __ mov(IceType_i32, eaxSlotAddress(), GPRRegister::Encoded_Reg_eax);
1469 __ mov(IceType_i32, ebxSlotAddress(), GPRRegister::Encoded_Reg_ebx);
1470 __ mov(IceType_i32, ecxSlotAddress(), GPRRegister::Encoded_Reg_ecx);
1471 __ mov(IceType_i32, edxSlotAddress(), GPRRegister::Encoded_Reg_edx);
1472 __ mov(IceType_i32, ediSlotAddress(), GPRRegister::Encoded_Reg_edi);
1473 __ mov(IceType_i32, esiSlotAddress(), GPRRegister::Encoded_Reg_esi);
1474 __ mov(IceType_i32, ebpSlotAddress(), GPRRegister::Encoded_Reg_ebp);
1475 __ mov(IceType_i32, espSlotAddress(), GPRRegister::Encoded_Reg_esp);
1476 __ movups(xmm0SlotAddress(), XmmRegister::Encoded_Reg_xmm0);
1477 __ movups(xmm1SlotAddress(), XmmRegister::Encoded_Reg_xmm1);
1478 __ movups(xmm2SlotAddress(), XmmRegister::Encoded_Reg_xmm2);
1479 __ movups(xmm3SlotAddress(), XmmRegister::Encoded_Reg_xmm3);
1480 __ movups(xmm4SlotAddress(), XmmRegister::Encoded_Reg_xmm4);
1481 __ movups(xmm5SlotAddress(), XmmRegister::Encoded_Reg_xmm5);
1482 __ movups(xmm6SlotAddress(), XmmRegister::Encoded_Reg_xmm6);
1483 __ movups(xmm7SlotAddress(), XmmRegister::Encoded_Reg_xmm7);
1484
1485 __ popl(GPRRegister::Encoded_Reg_ebp);
1486 __ popl(GPRRegister::Encoded_Reg_esi);
1487 __ popl(GPRRegister::Encoded_Reg_edi);
1488 __ popl(GPRRegister::Encoded_Reg_edx);
1489 __ popl(GPRRegister::Encoded_Reg_ecx);
1490 __ popl(GPRRegister::Encoded_Reg_ebx);
1491 __ popl(GPRRegister::Encoded_Reg_eax);
1492
1493 __ ret();
1494 }
1495
1496 bool NeedsEpilogue;
1497 uint32_t NumAllocatedDwords;
1498 };
1499
1500 TEST_F(AssemblerX8664Test, ScratchpadGettersAndSetters) {
1501 const uint32_t S0 = allocateDword();
1502 const uint32_t S1 = allocateDword();
1503 const uint32_t S2 = allocateDword();
1504 const uint32_t S3 = allocateDword();
1505 AssembledTest test = assemble();
1506 test.setDwordTo(S0, 0xBEEF0000u);
1507 test.setDwordTo(S1, 0xDEADu);
1508 test.setDwordTo(S2, 0x20406080u);
1509 ASSERT_EQ(0xBEEF0000u, test.contentsOfDword(S0));
1510 ASSERT_EQ(0xDEADu, test.contentsOfDword(S1));
1511 ASSERT_EQ(0x20406080u, test.contentsOfDword(S2));
1512 ASSERT_EQ(0xDEADBEEF0000ull, test.contentsOfQword(S0));
1513 ASSERT_EQ(0x204060800000DEADull, test.contentsOfQword(S1));
1514
1515 test.setQwordTo(S1, 0x1234567890ABCDEFull);
1516 ASSERT_EQ(0x1234567890ABCDEFull, test.contentsOfQword(S1));
1517 test.setDwordTo(S0, 0xBEEF0000u);
1518 ASSERT_EQ(0x90ABCDEFull, test.contentsOfDword(S1));
1519 ASSERT_EQ(0x12345678ull, test.contentsOfDword(S2));
1520
1521 test.setDwordTo(S0, 1.0f);
1522 ASSERT_FLOAT_EQ(1.0f, test.contentsOfDword<float>(S0));
1523 test.setQwordTo(S0, 3.14);
1524 ASSERT_DOUBLE_EQ(3.14, test.contentsOfQword<double>(S0));
1525
1526 test.setDqwordTo(S0, Dqword(1.0f, 2.0f, 3.0f, 4.0f));
1527 ASSERT_EQ(Dqword(1.0f, 2.0f, 3.0f, 4.0f), test.contentsOfDqword(S0));
1528 EXPECT_FLOAT_EQ(1.0f, test.contentsOfDword<float>(S0));
1529 EXPECT_FLOAT_EQ(2.0f, test.contentsOfDword<float>(S1));
1530 EXPECT_FLOAT_EQ(3.0f, test.contentsOfDword<float>(S2));
1531 EXPECT_FLOAT_EQ(4.0f, test.contentsOfDword<float>(S3));
1532 }
1533
1534 TEST_F(AssemblerX8664Test, MovRegImm) {
1535 constexpr uint32_t ExpectedEax = 0x000000FFul;
1536 constexpr uint32_t ExpectedEbx = 0x0000FF00ul;
1537 constexpr uint32_t ExpectedEcx = 0x00FF0000ul;
1538 constexpr uint32_t ExpectedEdx = 0xFF000000ul;
1539 constexpr uint32_t ExpectedEdi = 0x6AAA0006ul;
1540 constexpr uint32_t ExpectedEsi = 0x6000AAA6ul;
1541
1542 __ mov(IceType_i32, GPRRegister::Encoded_Reg_eax, Immediate(ExpectedEax));
1543 __ mov(IceType_i32, GPRRegister::Encoded_Reg_ebx, Immediate(ExpectedEbx));
1544 __ mov(IceType_i32, GPRRegister::Encoded_Reg_ecx, Immediate(ExpectedEcx));
1545 __ mov(IceType_i32, GPRRegister::Encoded_Reg_edx, Immediate(ExpectedEdx));
1546 __ mov(IceType_i32, GPRRegister::Encoded_Reg_edi, Immediate(ExpectedEdi));
1547 __ mov(IceType_i32, GPRRegister::Encoded_Reg_esi, Immediate(ExpectedEsi));
1548
1549 AssembledTest test = assemble();
1550 test.run();
1551 EXPECT_EQ(ExpectedEax, test.eax());
1552 EXPECT_EQ(ExpectedEbx, test.ebx());
1553 EXPECT_EQ(ExpectedEcx, test.ecx());
1554 EXPECT_EQ(ExpectedEdx, test.edx());
1555 EXPECT_EQ(ExpectedEdi, test.edi());
1556 EXPECT_EQ(ExpectedEsi, test.esi());
1557 }
1558
1559 TEST_F(AssemblerX8664Test, MovMemImm) {
1560 const uint32_t T0 = allocateDword();
1561 constexpr uint32_t ExpectedT0 = 0x00111100ul;
1562 const uint32_t T1 = allocateDword();
1563 constexpr uint32_t ExpectedT1 = 0x00222200ul;
1564 const uint32_t T2 = allocateDword();
1565 constexpr uint32_t ExpectedT2 = 0x03333000ul;
1566 const uint32_t T3 = allocateDword();
1567 constexpr uint32_t ExpectedT3 = 0x00444400ul;
1568
1569 __ mov(IceType_i32, dwordAddress(T0), Immediate(ExpectedT0));
1570 __ mov(IceType_i32, dwordAddress(T1), Immediate(ExpectedT1));
1571 __ mov(IceType_i32, dwordAddress(T2), Immediate(ExpectedT2));
1572 __ mov(IceType_i32, dwordAddress(T3), Immediate(ExpectedT3));
1573
1574 AssembledTest test = assemble();
1575 test.run();
1576 EXPECT_EQ(0ul, test.eax());
1577 EXPECT_EQ(0ul, test.ebx());
1578 EXPECT_EQ(0ul, test.ecx());
1579 EXPECT_EQ(0ul, test.edx());
1580 EXPECT_EQ(0ul, test.edi());
1581 EXPECT_EQ(0ul, test.esi());
1582 EXPECT_EQ(ExpectedT0, test.contentsOfDword(T0));
1583 EXPECT_EQ(ExpectedT1, test.contentsOfDword(T1));
1584 EXPECT_EQ(ExpectedT2, test.contentsOfDword(T2));
1585 EXPECT_EQ(ExpectedT3, test.contentsOfDword(T3));
1586 }
1587
1588 TEST_F(AssemblerX8664Test, MovMemReg) {
1589 const uint32_t T0 = allocateDword();
1590 constexpr uint32_t ExpectedT0 = 0x00111100ul;
1591 const uint32_t T1 = allocateDword();
1592 constexpr uint32_t ExpectedT1 = 0x00222200ul;
1593 const uint32_t T2 = allocateDword();
1594 constexpr uint32_t ExpectedT2 = 0x00333300ul;
1595 const uint32_t T3 = allocateDword();
1596 constexpr uint32_t ExpectedT3 = 0x00444400ul;
1597 const uint32_t T4 = allocateDword();
1598 constexpr uint32_t ExpectedT4 = 0x00555500ul;
1599 const uint32_t T5 = allocateDword();
1600 constexpr uint32_t ExpectedT5 = 0x00666600ul;
1601
1602 __ mov(IceType_i32, GPRRegister::Encoded_Reg_eax, Immediate(ExpectedT0));
1603 __ mov(IceType_i32, dwordAddress(T0), GPRRegister::Encoded_Reg_eax);
1604 __ mov(IceType_i32, GPRRegister::Encoded_Reg_ebx, Immediate(ExpectedT1));
1605 __ mov(IceType_i32, dwordAddress(T1), GPRRegister::Encoded_Reg_ebx);
1606 __ mov(IceType_i32, GPRRegister::Encoded_Reg_ecx, Immediate(ExpectedT2));
1607 __ mov(IceType_i32, dwordAddress(T2), GPRRegister::Encoded_Reg_ecx);
1608 __ mov(IceType_i32, GPRRegister::Encoded_Reg_edx, Immediate(ExpectedT3));
1609 __ mov(IceType_i32, dwordAddress(T3), GPRRegister::Encoded_Reg_edx);
1610 __ mov(IceType_i32, GPRRegister::Encoded_Reg_edi, Immediate(ExpectedT4));
1611 __ mov(IceType_i32, dwordAddress(T4), GPRRegister::Encoded_Reg_edi);
1612 __ mov(IceType_i32, GPRRegister::Encoded_Reg_esi, Immediate(ExpectedT5));
1613 __ mov(IceType_i32, dwordAddress(T5), GPRRegister::Encoded_Reg_esi);
1614
1615 AssembledTest test = assemble();
1616 test.run();
1617 EXPECT_EQ(ExpectedT0, test.contentsOfDword(T0));
1618 EXPECT_EQ(ExpectedT1, test.contentsOfDword(T1));
1619 EXPECT_EQ(ExpectedT2, test.contentsOfDword(T2));
1620 EXPECT_EQ(ExpectedT3, test.contentsOfDword(T3));
1621 EXPECT_EQ(ExpectedT4, test.contentsOfDword(T4));
1622 EXPECT_EQ(ExpectedT5, test.contentsOfDword(T5));
1623 }
1624
1625 TEST_F(AssemblerX8664Test, MovRegReg) {
1626 __ mov(IceType_i32, GPRRegister::Encoded_Reg_eax, Immediate(0x20));
1627 __ mov(IceType_i32, GPRRegister::Encoded_Reg_ebx,
1628 GPRRegister::Encoded_Reg_eax);
1629 __ mov(IceType_i32, GPRRegister::Encoded_Reg_ecx,
1630 GPRRegister::Encoded_Reg_ebx);
1631 __ mov(IceType_i32, GPRRegister::Encoded_Reg_edx,
1632 GPRRegister::Encoded_Reg_ecx);
1633 __ mov(IceType_i32, GPRRegister::Encoded_Reg_edi,
1634 GPRRegister::Encoded_Reg_edx);
1635 __ mov(IceType_i32, GPRRegister::Encoded_Reg_esi,
1636 GPRRegister::Encoded_Reg_edi);
1637
1638 __ mov(IceType_i32, GPRRegister::Encoded_Reg_esi, Immediate(0x55000000ul));
1639 __ mov(IceType_i32, GPRRegister::Encoded_Reg_eax,
1640 GPRRegister::Encoded_Reg_esi);
1641
1642 AssembledTest test = assemble();
1643 test.run();
1644 EXPECT_EQ(0x55000000ul, test.eax());
1645 EXPECT_EQ(0x20ul, test.ebx());
1646 EXPECT_EQ(0x20ul, test.ecx());
1647 EXPECT_EQ(0x20ul, test.edx());
1648 EXPECT_EQ(0x20ul, test.edi());
1649 EXPECT_EQ(0x55000000ul, test.esi());
1650 }
1651
1652 TEST_F(AssemblerX8664Test, MovRegMem) {
1653 const uint32_t T0 = allocateDword();
1654 constexpr uint32_t ExpectedT0 = 0x00111100ul;
1655 const uint32_t T1 = allocateDword();
1656 constexpr uint32_t ExpectedT1 = 0x00222200ul;
1657 const uint32_t T2 = allocateDword();
1658 constexpr uint32_t ExpectedT2 = 0x00333300ul;
1659 const uint32_t T3 = allocateDword();
1660 constexpr uint32_t ExpectedT3 = 0x00444400ul;
1661 const uint32_t T4 = allocateDword();
1662 constexpr uint32_t ExpectedT4 = 0x00555500ul;
1663 const uint32_t T5 = allocateDword();
1664 constexpr uint32_t ExpectedT5 = 0x00666600ul;
1665
1666 __ mov(IceType_i32, dwordAddress(T0), Immediate(ExpectedT0));
1667 __ mov(IceType_i32, GPRRegister::Encoded_Reg_eax, dwordAddress(T0));
1668
1669 __ mov(IceType_i32, dwordAddress(T1), Immediate(ExpectedT1));
1670 __ mov(IceType_i32, GPRRegister::Encoded_Reg_ebx, dwordAddress(T1));
1671
1672 __ mov(IceType_i32, dwordAddress(T2), Immediate(ExpectedT2));
1673 __ mov(IceType_i32, GPRRegister::Encoded_Reg_ecx, dwordAddress(T2));
1674
1675 __ mov(IceType_i32, dwordAddress(T3), Immediate(ExpectedT3));
1676 __ mov(IceType_i32, GPRRegister::Encoded_Reg_edx, dwordAddress(T3));
1677
1678 __ mov(IceType_i32, dwordAddress(T4), Immediate(ExpectedT4));
1679 __ mov(IceType_i32, GPRRegister::Encoded_Reg_edi, dwordAddress(T4));
1680
1681 __ mov(IceType_i32, dwordAddress(T5), Immediate(ExpectedT5));
1682 __ mov(IceType_i32, GPRRegister::Encoded_Reg_esi, dwordAddress(T5));
1683
1684 AssembledTest test = assemble();
1685 test.run();
1686 EXPECT_EQ(ExpectedT0, test.eax());
1687 EXPECT_EQ(ExpectedT1, test.ebx());
1688 EXPECT_EQ(ExpectedT2, test.ecx());
1689 EXPECT_EQ(ExpectedT3, test.edx());
1690 EXPECT_EQ(ExpectedT4, test.edi());
1691 EXPECT_EQ(ExpectedT5, test.esi());
1692 }
1693
1694 TEST_F(AssemblerX8664Test, J) {
1695 #define TestJ(C, Near, Src0, Value0, Src1, Value1, Dest) \
1696 do { \
1697 const bool NearJmp = AssemblerX8664::k##Near##Jump; \
1698 Label ShouldBeTaken; \
1699 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##Src0, Immediate(Value0)); \
1700 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##Src1, Immediate(Value1)); \
1701 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##Dest, Immediate(0xBEEF)); \
1702 __ cmp(IceType_i32, GPRRegister::Encoded_Reg_##Src0, \
1703 GPRRegister::Encoded_Reg_##Src1); \
1704 __ j(Cond::Br_##C, &ShouldBeTaken, NearJmp); \
1705 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##Dest, Immediate(0xC0FFEE)); \
1706 __ bind(&ShouldBeTaken); \
1707 AssembledTest test = assemble(); \
1708 test.run(); \
1709 EXPECT_EQ(Value0, test.Src0()) << "Br_" #C ", " #Near; \
1710 EXPECT_EQ(Value1, test.Src1()) << "Br_" #C ", " #Near; \
1711 EXPECT_EQ(0xBEEFul, test.Dest()) << "Br_" #C ", " #Near; \
1712 reset(); \
1713 } while (0)
1714
1715 TestJ(o, Near, eax, 0x80000000ul, ebx, 0x1ul, ecx);
1716 TestJ(o, Far, ebx, 0x80000000ul, ecx, 0x1ul, edx);
1717 TestJ(no, Near, ecx, 0x1ul, edx, 0x1ul, edi);
1718 TestJ(no, Far, edx, 0x1ul, edi, 0x1ul, esi);
1719 TestJ(b, Near, edi, 0x1ul, esi, 0x80000000ul, eax);
1720 TestJ(b, Far, esi, 0x1ul, eax, 0x80000000ul, ebx);
1721 TestJ(ae, Near, eax, 0x80000000ul, ebx, 0x1ul, ecx);
1722 TestJ(ae, Far, ebx, 0x80000000ul, ecx, 0x1ul, edx);
1723 TestJ(e, Near, ecx, 0x80000000ul, edx, 0x80000000ul, edi);
1724 TestJ(e, Far, edx, 0x80000000ul, edi, 0x80000000ul, esi);
1725 TestJ(ne, Near, edi, 0x80000000ul, esi, 0x1ul, eax);
1726 TestJ(ne, Far, esi, 0x80000000ul, eax, 0x1ul, ebx);
1727 TestJ(be, Near, eax, 0x1ul, ebx, 0x80000000ul, ecx);
1728 TestJ(be, Far, ebx, 0x1ul, ecx, 0x80000000ul, edx);
1729 TestJ(a, Near, ecx, 0x80000000ul, edx, 0x1ul, edi);
1730 TestJ(a, Far, edx, 0x80000000ul, edi, 0x1ul, esi);
1731 TestJ(s, Near, edi, 0x1ul, esi, 0x80000000ul, eax);
1732 TestJ(s, Far, esi, 0x1ul, eax, 0x80000000ul, ebx);
1733 TestJ(ns, Near, eax, 0x80000000ul, ebx, 0x1ul, ecx);
1734 TestJ(ns, Far, ebx, 0x80000000ul, ecx, 0x1ul, edx);
1735 TestJ(p, Near, ecx, 0x80000000ul, edx, 0x1ul, edi);
1736 TestJ(p, Far, edx, 0x80000000ul, edi, 0x1ul, esi);
1737 TestJ(np, Near, edi, 0x1ul, esi, 0x80000000ul, eax);
1738 TestJ(np, Far, esi, 0x1ul, eax, 0x80000000ul, ebx);
1739 TestJ(l, Near, eax, 0x80000000ul, ebx, 0x1ul, ecx);
1740 TestJ(l, Far, ebx, 0x80000000ul, ecx, 0x1ul, edx);
1741 TestJ(ge, Near, ecx, 0x1ul, edx, 0x80000000ul, edi);
1742 TestJ(ge, Far, edx, 0x1ul, edi, 0x80000000ul, esi);
1743 TestJ(le, Near, edi, 0x80000000ul, esi, 0x1ul, eax);
1744 TestJ(le, Far, esi, 0x80000000ul, eax, 0x1ul, ebx);
1745 TestJ(g, Near, eax, 0x1ul, ebx, 0x80000000ul, ecx);
1746 TestJ(g, Far, ebx, 0x1ul, ecx, 0x80000000ul, edx);
1747
1748 #undef TestJ
1749 }
1750
1751 TEST_F(AssemblerX8664Test, PopAddr) {
1752 const uint32_t T0 = allocateDword();
1753 constexpr uint32_t V0 = 0xEFAB;
1754
1755 __ mov(IceType_i32, GPRRegister::Encoded_Reg_eax, Immediate(0xC0FFEE));
1756 __ pushl(GPRRegister::Encoded_Reg_eax);
1757 __ popl(dwordAddress(T0));
1758
1759 AssembledTest test = assemble();
1760 test.setDwordTo(T0, V0);
1761
1762 test.run();
1763
1764 ASSERT_EQ(0xC0FFEEul, test.contentsOfDword(T0));
1765 }
1766
1767 TEST_F(AssemblerX8664Test, SetCC) {
1768 #define TestSetCC(C, Src0, Value0, Src1, Value1, Dest, IsTrue) \
1769 do { \
1770 const uint32_t T0 = allocateDword(); \
1771 constexpr uint32_t V0 = 0xF00F00; \
1772 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##Src0, Immediate(Value0)); \
1773 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##Src1, Immediate(Value1)); \
1774 __ cmp(IceType_i32, GPRRegister::Encoded_Reg_##Src0, \
1775 GPRRegister::Encoded_Reg_##Src1); \
1776 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##Dest, Immediate(0)); \
1777 __ setcc(Cond::Br_##C, \
1778 RegX8664::getEncodedByteReg(GPRRegister::Encoded_Reg_##Dest)); \
1779 __ setcc(Cond::Br_##C, dwordAddress(T0)); \
1780 \
1781 AssembledTest test = assemble(); \
1782 test.setDwordTo(T0, V0); \
1783 \
1784 test.run(); \
1785 \
1786 EXPECT_EQ(IsTrue, test.Dest()) \
1787 << "(" #C ", " #Src0 ", " #Value0 ", " #Src1 ", " #Value1 ", " #Dest \
1788 ", " #IsTrue ")"; \
1789 EXPECT_EQ((0xF00F00 | IsTrue), test.contentsOfDword(T0)) \
1790 << "(" #C ", " #Src0 ", " #Value0 ", " #Src1 ", " #Value1 ", " #Dest \
1791 ", " #IsTrue ")"; \
1792 \
1793 reset(); \
1794 } while (0)
1795
1796 TestSetCC(o, eax, 0x80000000u, ebx, 0x1u, ecx, 1u);
1797 TestSetCC(o, eax, 0x1u, ebx, 0x10000000u, ecx, 0u);
1798
1799 TestSetCC(no, ebx, 0x1u, ecx, 0x10000000u, edx, 1u);
1800 TestSetCC(no, ebx, 0x80000000u, ecx, 0x1u, edx, 0u);
1801
1802 TestSetCC(b, ecx, 0x1, edx, 0x80000000u, eax, 1u);
1803 TestSetCC(b, ecx, 0x80000000u, edx, 0x1u, eax, 0u);
1804
1805 TestSetCC(ae, edx, 0x80000000u, edi, 0x1u, ebx, 1u);
1806 TestSetCC(ae, edx, 0x1u, edi, 0x80000000u, ebx, 0u);
1807
1808 TestSetCC(e, edi, 0x1u, esi, 0x1u, ecx, 1u);
1809 TestSetCC(e, edi, 0x1u, esi, 0x11111u, ecx, 0u);
1810
1811 TestSetCC(ne, esi, 0x80000000u, eax, 0x1u, edx, 1u);
1812 TestSetCC(ne, esi, 0x1u, eax, 0x1u, edx, 0u);
1813
1814 TestSetCC(be, eax, 0x1u, ebx, 0x80000000u, eax, 1u);
1815 TestSetCC(be, eax, 0x80000000u, ebx, 0x1u, eax, 0u);
1816
1817 TestSetCC(a, ebx, 0x80000000u, ecx, 0x1u, ebx, 1u);
1818 TestSetCC(a, ebx, 0x1u, ecx, 0x80000000u, ebx, 0u);
1819
1820 TestSetCC(s, ecx, 0x1u, edx, 0x80000000u, ecx, 1u);
1821 TestSetCC(s, ecx, 0x80000000u, edx, 0x1u, ecx, 0u);
1822
1823 TestSetCC(ns, edx, 0x80000000u, edi, 0x1u, ecx, 1u);
1824 TestSetCC(ns, edx, 0x1u, edi, 0x80000000u, ecx, 0u);
1825
1826 TestSetCC(p, edi, 0x80000000u, esi, 0x1u, edx, 1u);
1827 TestSetCC(p, edi, 0x1u, esi, 0x80000000u, edx, 0u);
1828
1829 TestSetCC(np, esi, 0x1u, edi, 0x80000000u, eax, 1u);
1830 TestSetCC(np, esi, 0x80000000u, edi, 0x1u, eax, 0u);
1831
1832 TestSetCC(l, edi, 0x80000000u, eax, 0x1u, ebx, 1u);
1833 TestSetCC(l, edi, 0x1u, eax, 0x80000000u, ebx, 0u);
1834
1835 TestSetCC(ge, eax, 0x1u, ebx, 0x80000000u, ecx, 1u);
1836 TestSetCC(ge, eax, 0x80000000u, ebx, 0x1u, ecx, 0u);
1837
1838 TestSetCC(le, ebx, 0x80000000u, ecx, 0x1u, edx, 1u);
1839 TestSetCC(le, ebx, 0x1u, ecx, 0x80000000u, edx, 0u);
1840
1841 #undef TestSetCC
1842 }
1843
1844 TEST_F(AssemblerX8664Test, CallImm) {
1845 __ call(Immediate(16));
1846 __ hlt();
1847 __ hlt();
1848 __ hlt();
1849 __ hlt();
1850 __ hlt();
1851 __ hlt();
1852 __ hlt();
1853 __ hlt();
1854 __ hlt();
1855 __ hlt();
1856 __ hlt();
1857 __ hlt();
1858 __ mov(IceType_i32, GPRRegister::Encoded_Reg_eax, Immediate(0xf00f));
1859 __ popl(GPRRegister::Encoded_Reg_ebx);
1860
1861 AssembledTest test = assemble();
1862
1863 test.run();
1864
1865 EXPECT_EQ(0xF00Fu, test.eax());
1866 }
1867
1868 TEST_F(AssemblerX8664Test, CallReg) {
1869 __ call(Immediate(16));
1870 __ popl(GPRRegister::Encoded_Reg_edx);
1871 __ pushl(GPRRegister::Encoded_Reg_edx);
1872 __ ret();
1873 __ hlt();
1874 __ hlt();
1875 __ hlt();
1876 __ hlt();
1877 __ hlt();
1878 __ hlt();
1879 __ hlt();
1880 __ hlt();
1881 __ hlt();
1882 __ popl(GPRRegister::Encoded_Reg_ebx);
1883 __ call(GPRRegister::Encoded_Reg_ebx);
1884
1885 AssembledTest test = assemble();
1886
1887 test.run();
1888
1889 EXPECT_EQ(15u, test.edx() - test.ebx());
1890 }
1891
1892 TEST_F(AssemblerX8664Test, CallAddr) {
1893 __ call(Immediate(16));
1894 __ mov(IceType_i8, GPRRegister::Encoded_Reg_eax, Immediate(0xf4));
1895 __ ret();
1896 __ hlt();
1897 __ hlt();
1898 __ hlt();
1899 __ hlt();
1900 __ hlt();
1901 __ hlt();
1902 __ hlt();
1903 __ hlt();
1904 __ hlt();
1905 __ mov(IceType_i32, GPRRegister::Encoded_Reg_eax, Immediate(0xf1f2f300));
1906 __ call(Address(GPRRegister::Encoded_Reg_esp, 0));
1907 __ popl(GPRRegister::Encoded_Reg_edx);
1908
1909 AssembledTest test = assemble();
1910
1911 test.run();
1912
1913 EXPECT_EQ(0xf1f2f3f4, test.eax());
1914 }
1915
1916 TEST_F(AssemblerX8664Test, Movzx) {
1917 #define TestMovzx8bitWithRegDest(Src, Dst, Imm) \
1918 do { \
1919 static_assert(((Imm)&0xFF) == (Imm), #Imm " is not an 8bit immediate"); \
1920 __ mov(IceType_i8, GPRRegister::Encoded_Reg_##Src, Immediate(Imm)); \
1921 __ movzx(IceType_i8, GPRRegister::Encoded_Reg_##Dst, \
1922 GPRRegister::Encoded_Reg_##Src); \
1923 AssembledTest test = assemble(); \
1924 test.run(); \
1925 ASSERT_EQ(Imm, test.Dst()) << "(" #Src ", " #Dst ", " #Imm ")"; \
1926 reset(); \
1927 } while (0)
1928
1929 #define TestMovzx16bitWithRegDest(Src, Dst, Imm) \
1930 do { \
1931 static_assert(((Imm)&0xFFFF) == (Imm), #Imm " is not a 16bit immediate"); \
1932 __ mov(IceType_i16, GPRRegister::Encoded_Reg_##Src, Immediate(Imm)); \
1933 __ movzx(IceType_i16, GPRRegister::Encoded_Reg_##Dst, \
1934 GPRRegister::Encoded_Reg_##Src); \
1935 AssembledTest test = assemble(); \
1936 test.run(); \
1937 ASSERT_EQ(Imm, test.Dst()) << "(" #Src ", " #Dst ", " #Imm ")"; \
1938 reset(); \
1939 } while (0)
1940
1941 #define TestMovzx8bitWithAddrSrc(Dst, Imm) \
1942 do { \
1943 static_assert(((Imm)&0xFF) == (Imm), #Imm " is not an 8bit immediate"); \
1944 const uint32_t T0 = allocateDword(); \
1945 const uint32_t V0 = Imm; \
1946 __ movzx(IceType_i8, GPRRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
1947 AssembledTest test = assemble(); \
1948 test.setDwordTo(T0, V0); \
1949 test.run(); \
1950 ASSERT_EQ(Imm, test.Dst()) << "(Addr, " #Dst ", " #Imm ")"; \
1951 reset(); \
1952 } while (0)
1953
1954 #define TestMovzx16bitWithAddrSrc(Dst, Imm) \
1955 do { \
1956 static_assert(((Imm)&0xFFFF) == (Imm), #Imm " is not a 16bit immediate"); \
1957 const uint32_t T0 = allocateDword(); \
1958 const uint32_t V0 = Imm; \
1959 __ movzx(IceType_i16, GPRRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
1960 AssembledTest test = assemble(); \
1961 test.setDwordTo(T0, V0); \
1962 test.run(); \
1963 ASSERT_EQ(Imm, test.Dst()) << "(Addr, " #Dst ", " #Imm ")"; \
1964 reset(); \
1965 } while (0)
1966
1967 #define TestMovzx(Dst) \
1968 do { \
1969 TestMovzx8bitWithRegDest(eax, Dst, 0x81u); \
1970 TestMovzx8bitWithRegDest(ebx, Dst, 0x82u); \
1971 TestMovzx8bitWithRegDest(ecx, Dst, 0x83u); \
1972 TestMovzx8bitWithRegDest(edx, Dst, 0x84u); \
1973 /* esi is encoded as dh */ \
1974 TestMovzx8bitWithRegDest(esi, Dst, 0x85u); \
1975 /* edi is encoded as bh */ \
1976 TestMovzx8bitWithRegDest(edi, Dst, 0x86u); \
1977 /* ebp is encoded as ch */ \
1978 TestMovzx8bitWithRegDest(ebp, Dst, 0x87u); \
1979 /* esp is encoded as ah */ \
1980 TestMovzx8bitWithRegDest(esp, Dst, 0x88u); \
1981 TestMovzx8bitWithAddrSrc(Dst, 0x8Fu); \
1982 \
1983 TestMovzx16bitWithRegDest(eax, Dst, 0x8118u); \
1984 TestMovzx16bitWithRegDest(ebx, Dst, 0x8228u); \
1985 TestMovzx16bitWithRegDest(ecx, Dst, 0x8338u); \
1986 TestMovzx16bitWithRegDest(edx, Dst, 0x8448u); \
1987 TestMovzx16bitWithAddrSrc(Dst, 0x8FF8u); \
1988 } while (0)
1989
1990 TestMovzx(eax);
1991 TestMovzx(ebx);
1992 TestMovzx(ecx);
1993 TestMovzx(edx);
1994 TestMovzx(esi);
1995 TestMovzx(edi);
1996
1997 #undef TestMovzx
1998 #undef TestMovzx16bitWithAddrDest
1999 #undef TestMovzx8bitWithAddrDest
2000 #undef TestMovzx16bitWithRegDest
2001 #undef TestMovzx8bitWithRegDest
2002 }
2003
2004 TEST_F(AssemblerX8664Test, Movsx) {
2005 #define TestMovsx8bitWithRegDest(Src, Dst, Imm) \
2006 do { \
2007 static_assert(((Imm)&0xFF) == (Imm), #Imm " is not an 8bit immediate"); \
2008 __ mov(IceType_i8, GPRRegister::Encoded_Reg_##Src, Immediate(Imm)); \
2009 __ movsx(IceType_i8, GPRRegister::Encoded_Reg_##Dst, \
2010 GPRRegister::Encoded_Reg_##Src); \
2011 AssembledTest test = assemble(); \
2012 test.run(); \
2013 ASSERT_EQ((0xFFFFFF00 | (Imm)), test.Dst()) \
2014 << "(" #Src ", " #Dst ", " #Imm ")"; \
2015 reset(); \
2016 } while (0)
2017
2018 #define TestMovsx16bitWithRegDest(Src, Dst, Imm) \
2019 do { \
2020 static_assert(((Imm)&0xFFFF) == (Imm), #Imm " is not a 16bit immediate"); \
2021 __ mov(IceType_i16, GPRRegister::Encoded_Reg_##Src, Immediate(Imm)); \
2022 __ movsx(IceType_i16, GPRRegister::Encoded_Reg_##Dst, \
2023 GPRRegister::Encoded_Reg_##Src); \
2024 AssembledTest test = assemble(); \
2025 test.run(); \
2026 ASSERT_EQ((0xFFFF0000 | (Imm)), test.Dst()) \
2027 << "(" #Src ", " #Dst ", " #Imm ")"; \
2028 reset(); \
2029 } while (0)
2030
2031 #define TestMovsx8bitWithAddrSrc(Dst, Imm) \
2032 do { \
2033 static_assert(((Imm)&0xFF) == (Imm), #Imm " is not an 8bit immediate"); \
2034 const uint32_t T0 = allocateDword(); \
2035 const uint32_t V0 = Imm; \
2036 __ movsx(IceType_i8, GPRRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
2037 AssembledTest test = assemble(); \
2038 test.setDwordTo(T0, V0); \
2039 test.run(); \
2040 ASSERT_EQ((0xFFFFFF00 | (Imm)), test.Dst()) \
2041 << "(Addr, " #Dst ", " #Imm ")"; \
2042 reset(); \
2043 } while (0)
2044
2045 #define TestMovsx16bitWithAddrSrc(Dst, Imm) \
2046 do { \
2047 static_assert(((Imm)&0xFFFF) == (Imm), #Imm " is not a 16bit immediate"); \
2048 const uint32_t T0 = allocateDword(); \
2049 const uint32_t V0 = Imm; \
2050 __ movsx(IceType_i16, GPRRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
2051 AssembledTest test = assemble(); \
2052 test.setDwordTo(T0, V0); \
2053 test.run(); \
2054 ASSERT_EQ((0xFFFF0000 | (Imm)), test.Dst()) \
2055 << "(Addr, " #Dst ", " #Imm ")"; \
2056 reset(); \
2057 } while (0)
2058
2059 #define TestMovsx(Dst) \
2060 do { \
2061 TestMovsx8bitWithRegDest(eax, Dst, 0x81u); \
2062 TestMovsx8bitWithRegDest(ebx, Dst, 0x82u); \
2063 TestMovsx8bitWithRegDest(ecx, Dst, 0x83u); \
2064 TestMovsx8bitWithRegDest(edx, Dst, 0x84u); \
2065 /* esi is encoded as dh */ \
2066 TestMovsx8bitWithRegDest(esi, Dst, 0x85u); \
2067 /* edi is encoded as bh */ \
2068 TestMovsx8bitWithRegDest(edi, Dst, 0x86u); \
2069 /* ebp is encoded as ch */ \
2070 TestMovsx8bitWithRegDest(ebp, Dst, 0x87u); \
2071 /* esp is encoded as ah */ \
2072 TestMovsx8bitWithRegDest(esp, Dst, 0x88u); \
2073 TestMovsx8bitWithAddrSrc(Dst, 0x8Fu); \
2074 \
2075 TestMovsx16bitWithRegDest(eax, Dst, 0x8118u); \
2076 TestMovsx16bitWithRegDest(ebx, Dst, 0x8228u); \
2077 TestMovsx16bitWithRegDest(ecx, Dst, 0x8338u); \
2078 TestMovsx16bitWithRegDest(edx, Dst, 0x8448u); \
2079 TestMovsx16bitWithAddrSrc(Dst, 0x8FF8u); \
2080 } while (0)
2081
2082 TestMovsx(eax);
2083 TestMovsx(ebx);
2084 TestMovsx(ecx);
2085 TestMovsx(edx);
2086 TestMovsx(esi);
2087 TestMovsx(edi);
2088
2089 #undef TestMovsx
2090 #undef TestMovsx16bitWithAddrDest
2091 #undef TestMovsx8bitWithAddrDest
2092 #undef TestMovsx16bitWithRegDest
2093 #undef TestMovsx8bitWithRegDest
2094 }
2095
2096 TEST_F(AssemblerX8664Test, Lea) {
2097 #define TestLeaBaseDisp(Base, BaseValue, Disp, Dst) \
2098 do { \
2099 static constexpr char TestString[] = \
2100 "(" #Base ", " #BaseValue ", " #Dst ")"; \
2101 if (GPRRegister::Encoded_Reg_##Base != GPRRegister::Encoded_Reg_esp && \
2102 GPRRegister::Encoded_Reg_##Base != GPRRegister::Encoded_Reg_ebp) { \
2103 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##Base, \
2104 Immediate(BaseValue)); \
2105 } \
2106 __ lea(IceType_i32, GPRRegister::Encoded_Reg_##Dst, \
2107 Address(GPRRegister::Encoded_Reg_##Base, Disp)); \
2108 AssembledTest test = assemble(); \
2109 test.run(); \
2110 ASSERT_EQ(test.Base() + (Disp), test.Dst()) << TestString << " with Disp " \
2111 << Disp; \
2112 reset(); \
2113 } while (0)
2114
2115 #define TestLeaIndex32bitDisp(Index, IndexValue, Disp, Dst0, Dst1, Dst2, Dst3) \
2116 do { \
2117 static constexpr char TestString[] = \
2118 "(" #Index ", " #IndexValue ", " #Dst0 ", " #Dst1 ", " #Dst2 \
2119 ", " #Dst3 ")"; \
2120 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##Index, \
2121 Immediate(IndexValue)); \
2122 __ lea(IceType_i32, GPRRegister::Encoded_Reg_##Dst0, \
2123 Address(GPRRegister::Encoded_Reg_##Index, Traits::TIMES_1, Disp)); \
2124 __ lea(IceType_i32, GPRRegister::Encoded_Reg_##Dst1, \
2125 Address(GPRRegister::Encoded_Reg_##Index, Traits::TIMES_2, Disp)); \
2126 __ lea(IceType_i32, GPRRegister::Encoded_Reg_##Dst2, \
2127 Address(GPRRegister::Encoded_Reg_##Index, Traits::TIMES_4, Disp)); \
2128 __ lea(IceType_i32, GPRRegister::Encoded_Reg_##Dst3, \
2129 Address(GPRRegister::Encoded_Reg_##Index, Traits::TIMES_8, Disp)); \
2130 AssembledTest test = assemble(); \
2131 test.run(); \
2132 ASSERT_EQ((test.Index() << Traits::TIMES_1) + (Disp), test.Dst0()) \
2133 << TestString << " " << Disp; \
2134 ASSERT_EQ((test.Index() << Traits::TIMES_2) + (Disp), test.Dst1()) \
2135 << TestString << " " << Disp; \
2136 ASSERT_EQ((test.Index() << Traits::TIMES_4) + (Disp), test.Dst2()) \
2137 << TestString << " " << Disp; \
2138 ASSERT_EQ((test.Index() << Traits::TIMES_8) + (Disp), test.Dst3()) \
2139 << TestString << " " << Disp; \
2140 reset(); \
2141 } while (0)
2142
2143 #define TestLeaBaseIndexDisp(Base, BaseValue, Index, IndexValue, Disp, Dst0, \
2144 Dst1, Dst2, Dst3) \
2145 do { \
2146 static constexpr char TestString[] = \
2147 "(" #Base ", " #BaseValue ", " #Index ", " #IndexValue ", " #Dst0 \
2148 ", " #Dst1 ", " #Dst2 ", " #Dst3 ")"; \
2149 if (GPRRegister::Encoded_Reg_##Base != GPRRegister::Encoded_Reg_esp && \
2150 GPRRegister::Encoded_Reg_##Base != GPRRegister::Encoded_Reg_ebp) { \
2151 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##Base, \
2152 Immediate(BaseValue)); \
2153 } \
2154 /* esp is not a valid index register. */ \
2155 if (GPRRegister::Encoded_Reg_##Index != GPRRegister::Encoded_Reg_ebp) { \
2156 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##Index, \
2157 Immediate(IndexValue)); \
2158 } \
2159 __ lea(IceType_i32, GPRRegister::Encoded_Reg_##Dst0, \
2160 Address(GPRRegister::Encoded_Reg_##Base, \
2161 GPRRegister::Encoded_Reg_##Index, Traits::TIMES_1, Disp)); \
2162 __ lea(IceType_i32, GPRRegister::Encoded_Reg_##Dst1, \
2163 Address(GPRRegister::Encoded_Reg_##Base, \
2164 GPRRegister::Encoded_Reg_##Index, Traits::TIMES_2, Disp)); \
2165 __ lea(IceType_i32, GPRRegister::Encoded_Reg_##Dst2, \
2166 Address(GPRRegister::Encoded_Reg_##Base, \
2167 GPRRegister::Encoded_Reg_##Index, Traits::TIMES_4, Disp)); \
2168 __ lea(IceType_i32, GPRRegister::Encoded_Reg_##Dst3, \
2169 Address(GPRRegister::Encoded_Reg_##Base, \
2170 GPRRegister::Encoded_Reg_##Index, Traits::TIMES_8, Disp)); \
2171 AssembledTest test = assemble(); \
2172 test.run(); \
2173 uint32_t ExpectedIndexValue = test.Index(); \
2174 if (GPRRegister::Encoded_Reg_##Index == GPRRegister::Encoded_Reg_esp) { \
2175 ExpectedIndexValue = 0; \
2176 } \
2177 ASSERT_EQ(test.Base() + (ExpectedIndexValue << Traits::TIMES_1) + (Disp), \
2178 test.Dst0()) \
2179 << TestString << " " << Disp; \
2180 ASSERT_EQ(test.Base() + (ExpectedIndexValue << Traits::TIMES_2) + (Disp), \
2181 test.Dst1()) \
2182 << TestString << " " << Disp; \
2183 ASSERT_EQ(test.Base() + (ExpectedIndexValue << Traits::TIMES_4) + (Disp), \
2184 test.Dst2()) \
2185 << TestString << " " << Disp; \
2186 ASSERT_EQ(test.Base() + (ExpectedIndexValue << Traits::TIMES_8) + (Disp), \
2187 test.Dst3()) \
2188 << TestString << " " << Disp; \
2189 reset(); \
2190 } while (0)
2191
2192 for (const int32_t Disp :
2193 {0x00, 0x06, -0x06, 0x0600, -0x6000, 0x6000000, -0x6000000}) {
2194 TestLeaBaseDisp(eax, 0x10000Fu, Disp, ebx);
2195 TestLeaBaseDisp(ebx, 0x20000Fu, Disp, ecx);
2196 TestLeaBaseDisp(ecx, 0x30000Fu, Disp, edx);
2197 TestLeaBaseDisp(edx, 0x40000Fu, Disp, esi);
2198 TestLeaBaseDisp(esi, 0x50000Fu, Disp, edi);
2199 TestLeaBaseDisp(edi, 0x60000Fu, Disp, eax);
2200 TestLeaBaseDisp(esp, 0x11000Fu, Disp, eax);
2201 TestLeaBaseDisp(ebp, 0x22000Fu, Disp, ecx);
2202 }
2203
2204 // esp is not a valid index register.
2205 // ebp is not valid in this addressing mode (rm = 0).
2206 for (const int32_t Disp :
2207 {0x00, 0x06, -0x06, 0x0600, -0x6000, 0x6000000, -0x6000000}) {
2208 TestLeaIndex32bitDisp(eax, 0x2000u, Disp, ebx, ecx, edx, esi);
2209 TestLeaIndex32bitDisp(ebx, 0x4000u, Disp, ecx, edx, esi, edi);
2210 TestLeaIndex32bitDisp(ecx, 0x6000u, Disp, edx, esi, edi, eax);
2211 TestLeaIndex32bitDisp(edx, 0x8000u, Disp, esi, edi, eax, ebx);
2212 TestLeaIndex32bitDisp(esi, 0xA000u, Disp, edi, eax, ebx, ecx);
2213 TestLeaIndex32bitDisp(edi, 0xC000u, Disp, eax, ebx, ecx, edx);
2214 }
2215
2216 for (const int32_t Disp :
2217 {0x00, 0x06, -0x06, 0x0600, -0x6000, 0x6000000, -0x6000000}) {
2218 TestLeaBaseIndexDisp(eax, 0x100000u, ebx, 0x600u, Disp, ecx, edx, esi, edi);
2219 TestLeaBaseIndexDisp(ebx, 0x200000u, ecx, 0x500u, Disp, edx, esi, edi, eax);
2220 TestLeaBaseIndexDisp(ecx, 0x300000u, edx, 0x400u, Disp, esi, edi, eax, ebx);
2221 TestLeaBaseIndexDisp(edx, 0x400000u, esi, 0x300u, Disp, edi, eax, ebx, ecx);
2222 TestLeaBaseIndexDisp(esi, 0x500000u, edi, 0x200u, Disp, eax, ebx, ecx, edx);
2223 TestLeaBaseIndexDisp(edi, 0x600000u, eax, 0x100u, Disp, ebx, ecx, edx, esi);
2224
2225 /* Initializers are ignored when Src[01] is ebp/esp. */
2226 TestLeaBaseIndexDisp(esp, 0, ebx, 0x6000u, Disp, ecx, edx, esi, edi);
2227 TestLeaBaseIndexDisp(esp, 0, ecx, 0x5000u, Disp, edx, esi, edi, eax);
2228 TestLeaBaseIndexDisp(esp, 0, edx, 0x4000u, Disp, esi, edi, eax, ebx);
2229 TestLeaBaseIndexDisp(esp, 0, esi, 0x3000u, Disp, edi, eax, ebx, ecx);
2230 TestLeaBaseIndexDisp(esp, 0, edi, 0x2000u, Disp, eax, ebx, ecx, edx);
2231 TestLeaBaseIndexDisp(esp, 0, eax, 0x1000u, Disp, ebx, ecx, edx, esi);
2232
2233 TestLeaBaseIndexDisp(ebp, 0, ebx, 0x6000u, Disp, ecx, edx, esi, edi);
2234 TestLeaBaseIndexDisp(ebp, 0, ecx, 0x5000u, Disp, edx, esi, edi, eax);
2235 TestLeaBaseIndexDisp(ebp, 0, edx, 0x4000u, Disp, esi, edi, eax, ebx);
2236 TestLeaBaseIndexDisp(ebp, 0, esi, 0x3000u, Disp, edi, eax, ebx, ecx);
2237 TestLeaBaseIndexDisp(ebp, 0, edi, 0x2000u, Disp, eax, ebx, ecx, edx);
2238 TestLeaBaseIndexDisp(ebp, 0, eax, 0x1000u, Disp, ebx, ecx, edx, esi);
2239
2240 TestLeaBaseIndexDisp(eax, 0x1000000u, ebp, 0, Disp, ecx, edx, esi, edi);
2241 TestLeaBaseIndexDisp(ebx, 0x2000000u, ebp, 0, Disp, edx, esi, edi, eax);
2242 TestLeaBaseIndexDisp(ecx, 0x3000000u, ebp, 0, Disp, esi, edi, eax, ebx);
2243 TestLeaBaseIndexDisp(edx, 0x4000000u, ebp, 0, Disp, edi, eax, ebx, ecx);
2244 TestLeaBaseIndexDisp(esi, 0x5000000u, ebp, 0, Disp, eax, ebx, ecx, edx);
2245 TestLeaBaseIndexDisp(edi, 0x6000000u, ebp, 0, Disp, ebx, ecx, edx, esi);
2246
2247 TestLeaBaseIndexDisp(esp, 0, ebp, 0, Disp, ebx, ecx, edx, esi);
2248 }
2249
2250 // Absolute addressing mode is tested in the Low Level tests. The encoding used
2251 // by the assembler has different meanings in x86-32 and x86-64.
2252 #undef TestLeaBaseIndexDisp
2253 #undef TestLeaScaled32bitDisp
2254 #undef TestLeaBaseDisp
2255 }
2256
2257 TEST_F(AssemblerX8664LowLevelTest, LeaAbsolute) {
2258 #define TestLeaAbsolute(Dst, Value) \
2259 do { \
2260 static constexpr char TestString[] = "(" #Dst ", " #Value ")"; \
2261 __ lea(IceType_i32, GPRRegister::Encoded_Reg_##Dst, \
2262 Address(Address::ABSOLUTE, Value)); \
2263 static constexpr uint32_t ByteCount = 6; \
2264 ASSERT_EQ(ByteCount, codeBytesSize()) << TestString; \
2265 static constexpr uint8_t Opcode = 0x8D; \
2266 static constexpr uint8_t ModRM = \
2267 /*mod=*/0x00 | /*reg*/ (GPRRegister::Encoded_Reg_##Dst << 3) | \
2268 /*rm*/ GPRRegister::Encoded_Reg_ebp; \
2269 verifyBytes<ByteCount>(codeBytes(), Opcode, ModRM, (Value)&0xFF, \
2270 (Value >> 8) & 0xFF, (Value >> 16) & 0xFF, \
2271 (Value >> 24) & 0xFF); \
2272 reset(); \
2273 } while (0)
2274
2275 TestLeaAbsolute(eax, 0x11BEEF22);
2276 TestLeaAbsolute(ebx, 0x33BEEF44);
2277 TestLeaAbsolute(ecx, 0x55BEEF66);
2278 TestLeaAbsolute(edx, 0x77BEEF88);
2279 TestLeaAbsolute(esi, 0x99BEEFAA);
2280 TestLeaAbsolute(edi, 0xBBBEEFBB);
2281
2282 #undef TesLeaAbsolute
2283 }
2284
2285 TEST_F(AssemblerX8664Test, CmovRegReg) {
2286 #define TestCmovRegReg(C, Src0, Value0, Src1, Value1, Dest, IsTrue) \
2287 do { \
2288 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##Src0, Immediate(Value0)); \
2289 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##Src1, Immediate(Value1)); \
2290 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##Dest, Immediate(Value0)); \
2291 __ cmp(IceType_i32, GPRRegister::Encoded_Reg_##Src0, \
2292 GPRRegister::Encoded_Reg_##Src1); \
2293 __ cmov(IceType_i32, Cond::Br_##C, GPRRegister::Encoded_Reg_##Dest, \
2294 GPRRegister::Encoded_Reg_##Src1); \
2295 \
2296 AssembledTest test = assemble(); \
2297 test.run(); \
2298 ASSERT_EQ((IsTrue) ? (Value1) : (Value0), test.Dest()) \
2299 << "(" #C ", " #Src0 ", " #Value0 ", " #Src1 ", " #Value1 ", " #Dest \
2300 ", " #IsTrue ")"; \
2301 \
2302 reset(); \
2303 } while (0)
2304
2305 TestCmovRegReg(o, eax, 0x80000000u, ebx, 0x1u, ecx, 1u);
2306 TestCmovRegReg(o, eax, 0x1u, ebx, 0x10000000u, ecx, 0u);
2307
2308 TestCmovRegReg(no, ebx, 0x1u, ecx, 0x10000000u, edx, 1u);
2309 TestCmovRegReg(no, ebx, 0x80000000u, ecx, 0x1u, edx, 0u);
2310
2311 TestCmovRegReg(b, ecx, 0x1, edx, 0x80000000u, eax, 1u);
2312 TestCmovRegReg(b, ecx, 0x80000000u, edx, 0x1u, eax, 0u);
2313
2314 TestCmovRegReg(ae, edx, 0x80000000u, edi, 0x1u, ebx, 1u);
2315 TestCmovRegReg(ae, edx, 0x1u, edi, 0x80000000u, ebx, 0u);
2316
2317 TestCmovRegReg(e, edi, 0x1u, esi, 0x1u, ecx, 1u);
2318 TestCmovRegReg(e, edi, 0x1u, esi, 0x11111u, ecx, 0u);
2319
2320 TestCmovRegReg(ne, esi, 0x80000000u, eax, 0x1u, edx, 1u);
2321 TestCmovRegReg(ne, esi, 0x1u, eax, 0x1u, edx, 0u);
2322
2323 TestCmovRegReg(be, eax, 0x1u, ebx, 0x80000000u, eax, 1u);
2324 TestCmovRegReg(be, eax, 0x80000000u, ebx, 0x1u, eax, 0u);
2325
2326 TestCmovRegReg(a, ebx, 0x80000000u, ecx, 0x1u, ebx, 1u);
2327 TestCmovRegReg(a, ebx, 0x1u, ecx, 0x80000000u, ebx, 0u);
2328
2329 TestCmovRegReg(s, ecx, 0x1u, edx, 0x80000000u, ecx, 1u);
2330 TestCmovRegReg(s, ecx, 0x80000000u, edx, 0x1u, ecx, 0u);
2331
2332 TestCmovRegReg(ns, edx, 0x80000000u, edi, 0x1u, ecx, 1u);
2333 TestCmovRegReg(ns, edx, 0x1u, edi, 0x80000000u, ecx, 0u);
2334
2335 TestCmovRegReg(p, edi, 0x80000000u, esi, 0x1u, edx, 1u);
2336 TestCmovRegReg(p, edi, 0x1u, esi, 0x80000000u, edx, 0u);
2337
2338 TestCmovRegReg(np, esi, 0x1u, edi, 0x80000000u, eax, 1u);
2339 TestCmovRegReg(np, esi, 0x80000000u, edi, 0x1u, eax, 0u);
2340
2341 TestCmovRegReg(l, edi, 0x80000000u, eax, 0x1u, ebx, 1u);
2342 TestCmovRegReg(l, edi, 0x1u, eax, 0x80000000u, ebx, 0u);
2343
2344 TestCmovRegReg(ge, eax, 0x1u, ebx, 0x80000000u, ecx, 1u);
2345 TestCmovRegReg(ge, eax, 0x80000000u, ebx, 0x1u, ecx, 0u);
2346
2347 TestCmovRegReg(le, ebx, 0x80000000u, ecx, 0x1u, edx, 1u);
2348 TestCmovRegReg(le, ebx, 0x1u, ecx, 0x80000000u, edx, 0u);
2349
2350 #undef TestCmovRegReg
2351 }
2352
2353 TEST_F(AssemblerX8664Test, CmovRegAddr) {
2354 #define TestCmovRegAddr(C, Src0, Value0, Value1, Dest, IsTrue) \
2355 do { \
2356 const uint32_t T0 = allocateDword(); \
2357 const uint32_t V0 = Value1; \
2358 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##Src0, Immediate(Value0)); \
2359 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##Dest, Immediate(Value0)); \
2360 __ cmp(IceType_i32, GPRRegister::Encoded_Reg_##Src0, dwordAddress(T0)); \
2361 __ cmov(IceType_i32, Cond::Br_##C, GPRRegister::Encoded_Reg_##Dest, \
2362 dwordAddress(T0)); \
2363 \
2364 AssembledTest test = assemble(); \
2365 test.setDwordTo(T0, V0); \
2366 test.run(); \
2367 ASSERT_EQ((IsTrue) ? (Value1) : (Value0), test.Dest()) \
2368 << "(" #C ", " #Src0 ", " #Value0 ", " #Value1 ", " #Dest ", " #IsTrue \
2369 ")"; \
2370 \
2371 reset(); \
2372 } while (0)
2373
2374 TestCmovRegAddr(o, eax, 0x80000000u, 0x1u, ecx, 1u);
2375 TestCmovRegAddr(o, eax, 0x1u, 0x10000000u, ecx, 0u);
2376
2377 TestCmovRegAddr(no, ebx, 0x1u, 0x10000000u, edx, 1u);
2378 TestCmovRegAddr(no, ebx, 0x80000000u, 0x1u, edx, 0u);
2379
2380 TestCmovRegAddr(b, ecx, 0x1, 0x80000000u, eax, 1u);
2381 TestCmovRegAddr(b, ecx, 0x80000000u, 0x1u, eax, 0u);
2382
2383 TestCmovRegAddr(ae, edx, 0x80000000u, 0x1u, ebx, 1u);
2384 TestCmovRegAddr(ae, edx, 0x1u, 0x80000000u, ebx, 0u);
2385
2386 TestCmovRegAddr(e, edi, 0x1u, 0x1u, ecx, 1u);
2387 TestCmovRegAddr(e, edi, 0x1u, 0x11111u, ecx, 0u);
2388
2389 TestCmovRegAddr(ne, esi, 0x80000000u, 0x1u, edx, 1u);
2390 TestCmovRegAddr(ne, esi, 0x1u, 0x1u, edx, 0u);
2391
2392 TestCmovRegAddr(be, eax, 0x1u, 0x80000000u, eax, 1u);
2393 TestCmovRegAddr(be, eax, 0x80000000u, 0x1u, eax, 0u);
2394
2395 TestCmovRegAddr(a, ebx, 0x80000000u, 0x1u, ebx, 1u);
2396 TestCmovRegAddr(a, ebx, 0x1u, 0x80000000u, ebx, 0u);
2397
2398 TestCmovRegAddr(s, ecx, 0x1u, 0x80000000u, ecx, 1u);
2399 TestCmovRegAddr(s, ecx, 0x80000000u, 0x1u, ecx, 0u);
2400
2401 TestCmovRegAddr(ns, edx, 0x80000000u, 0x1u, ecx, 1u);
2402 TestCmovRegAddr(ns, edx, 0x1u, 0x80000000u, ecx, 0u);
2403
2404 TestCmovRegAddr(p, edi, 0x80000000u, 0x1u, edx, 1u);
2405 TestCmovRegAddr(p, edi, 0x1u, 0x80000000u, edx, 0u);
2406
2407 TestCmovRegAddr(np, esi, 0x1u, 0x80000000u, eax, 1u);
2408 TestCmovRegAddr(np, esi, 0x80000000u, 0x1u, eax, 0u);
2409
2410 TestCmovRegAddr(l, edi, 0x80000000u, 0x1u, ebx, 1u);
2411 TestCmovRegAddr(l, edi, 0x1u, 0x80000000u, ebx, 0u);
2412
2413 TestCmovRegAddr(ge, eax, 0x1u, 0x80000000u, ecx, 1u);
2414 TestCmovRegAddr(ge, eax, 0x80000000u, 0x1u, ecx, 0u);
2415
2416 TestCmovRegAddr(le, ebx, 0x80000000u, 0x1u, edx, 1u);
2417 TestCmovRegAddr(le, ebx, 0x1u, 0x80000000u, edx, 0u);
2418
2419 #undef TestCmovRegAddr
2420 }
2421
2422 TEST_F(AssemblerX8664LowLevelTest, RepMovsb) {
2423 __ rep_movsb();
2424
2425 static constexpr uint32_t ByteCount = 2;
2426 static constexpr uint8_t Prefix = 0xF3;
2427 static constexpr uint8_t Opcode = 0xA4;
2428
2429 ASSERT_EQ(ByteCount, codeBytesSize());
2430 verifyBytes<ByteCount>(codeBytes(), Prefix, Opcode);
2431 }
2432
2433 TEST_F(AssemblerX8664Test, MovssXmmAddr) {
2434 #define TestMovssXmmAddrFloatLength(FloatLength, Xmm, Value) \
2435 do { \
2436 static_assert((FloatLength) == 32 || (FloatLength) == 64, \
2437 "Invalid fp length #FloatLength"); \
2438 using Type = std::conditional<FloatLength == 32, float, double>::type; \
2439 \
2440 static constexpr char TestString[] = "(" #FloatLength ", " #Xmm ")"; \
2441 static constexpr bool IsDouble = std::is_same<Type, double>::value; \
2442 const uint32_t T0 = allocateQword(); \
2443 const Type V0 = Value; \
2444 \
2445 __ movss(IceType_f##FloatLength, XmmRegister::Encoded_Reg_##Xmm, \
2446 dwordAddress(T0)); \
2447 \
2448 AssembledTest test = assemble(); \
2449 if (IsDouble) { \
2450 test.setQwordTo(T0, static_cast<double>(V0)); \
2451 } else { \
2452 test.setDwordTo(T0, static_cast<float>(V0)); \
2453 } \
2454 test.run(); \
2455 ASSERT_DOUBLE_EQ(Value, test.Xmm<Type>()) << TestString << " value is " \
2456 << Value; \
2457 reset(); \
2458 } while (0)
2459
2460 #define TestMovssXmmAddr(FloatLength) \
2461 do { \
2462 using Type = std::conditional<FloatLength == 32, float, double>::type; \
2463 for (const Type Value : {0.0, -0.0, 1.0, -1.0, 3.14, 99999.9999}) { \
2464 TestMovssXmmAddrFloatLength(FloatLength, xmm0, Value); \
2465 TestMovssXmmAddrFloatLength(FloatLength, xmm1, Value); \
2466 TestMovssXmmAddrFloatLength(FloatLength, xmm2, Value); \
2467 TestMovssXmmAddrFloatLength(FloatLength, xmm3, Value); \
2468 TestMovssXmmAddrFloatLength(FloatLength, xmm4, Value); \
2469 TestMovssXmmAddrFloatLength(FloatLength, xmm5, Value); \
2470 TestMovssXmmAddrFloatLength(FloatLength, xmm6, Value); \
2471 TestMovssXmmAddrFloatLength(FloatLength, xmm7, Value); \
2472 } \
2473 } while (0)
2474
2475 TestMovssXmmAddr(32);
2476 TestMovssXmmAddr(64);
2477
2478 #undef TestMovssXmmAddr
2479 #undef TestMovssXmmAddrType
2480 }
2481
2482 TEST_F(AssemblerX8664Test, MovssAddrXmm) {
2483 #define TestMovssAddrXmmFloatLength(FloatLength, Xmm, Value) \
2484 do { \
2485 static_assert((FloatLength) == 32 || (FloatLength) == 64, \
2486 "Invalid fp length #FloatLength"); \
2487 using Type = std::conditional<FloatLength == 32, float, double>::type; \
2488 \
2489 static constexpr char TestString[] = "(" #FloatLength ", " #Xmm ")"; \
2490 static constexpr bool IsDouble = std::is_same<Type, double>::value; \
2491 const uint32_t T0 = allocateQword(); \
2492 const Type V0 = Value; \
2493 const uint32_t T1 = allocateQword(); \
2494 static_assert(std::numeric_limits<Type>::has_quiet_NaN, \
2495 "f" #FloatLength " does not have quiet nan."); \
2496 const Type V1 = std::numeric_limits<Type>::quiet_NaN(); \
2497 \
2498 __ movss(IceType_f##FloatLength, XmmRegister::Encoded_Reg_##Xmm, \
2499 dwordAddress(T0)); \
2500 \
2501 AssembledTest test = assemble(); \
2502 if (IsDouble) { \
2503 test.setQwordTo(T0, static_cast<double>(V0)); \
2504 test.setQwordTo(T1, static_cast<double>(V1)); \
2505 } else { \
2506 test.setDwordTo(T0, static_cast<float>(V0)); \
2507 test.setDwordTo(T1, static_cast<float>(V1)); \
2508 } \
2509 test.run(); \
2510 ASSERT_DOUBLE_EQ(Value, test.Xmm<Type>()) << TestString << " value is " \
2511 << Value; \
2512 reset(); \
2513 } while (0)
2514
2515 #define TestMovssAddrXmm(FloatLength) \
2516 do { \
2517 using Type = std::conditional<FloatLength == 32, float, double>::type; \
2518 for (const Type Value : {0.0, -0.0, 1.0, -1.0, 3.14, 99999.9999}) { \
2519 TestMovssAddrXmmFloatLength(FloatLength, xmm0, Value); \
2520 TestMovssAddrXmmFloatLength(FloatLength, xmm1, Value); \
2521 TestMovssAddrXmmFloatLength(FloatLength, xmm2, Value); \
2522 TestMovssAddrXmmFloatLength(FloatLength, xmm3, Value); \
2523 TestMovssAddrXmmFloatLength(FloatLength, xmm4, Value); \
2524 TestMovssAddrXmmFloatLength(FloatLength, xmm5, Value); \
2525 TestMovssAddrXmmFloatLength(FloatLength, xmm6, Value); \
2526 TestMovssAddrXmmFloatLength(FloatLength, xmm7, Value); \
2527 } \
2528 } while (0)
2529
2530 TestMovssAddrXmm(32);
2531 TestMovssAddrXmm(64);
2532
2533 #undef TestMovssAddrXmm
2534 #undef TestMovssAddrXmmType
2535 }
2536
2537 TEST_F(AssemblerX8664Test, MovssXmmXmm) {
2538 #define TestMovssXmmXmmFloatLength(FloatLength, Src, Dst, Value) \
2539 do { \
2540 static_assert((FloatLength) == 32 || (FloatLength) == 64, \
2541 "Invalid fp length #FloatLength"); \
2542 using Type = std::conditional<FloatLength == 32, float, double>::type; \
2543 \
2544 static constexpr char TestString[] = \
2545 "(" #FloatLength ", " #Src ", " #Dst ")"; \
2546 static constexpr bool IsDouble = std::is_same<Type, double>::value; \
2547 const uint32_t T0 = allocateQword(); \
2548 const Type V0 = Value; \
2549 const uint32_t T1 = allocateQword(); \
2550 static_assert(std::numeric_limits<Type>::has_quiet_NaN, \
2551 "f" #FloatLength " does not have quiet nan."); \
2552 const Type V1 = std::numeric_limits<Type>::quiet_NaN(); \
2553 \
2554 __ movss(IceType_f##FloatLength, XmmRegister::Encoded_Reg_##Src, \
2555 dwordAddress(T0)); \
2556 __ movss(IceType_f##FloatLength, XmmRegister::Encoded_Reg_##Dst, \
2557 dwordAddress(T1)); \
2558 __ movss(IceType_f##FloatLength, XmmRegister::Encoded_Reg_##Dst, \
2559 XmmRegister::Encoded_Reg_##Src); \
2560 \
2561 AssembledTest test = assemble(); \
2562 if (IsDouble) { \
2563 test.setQwordTo(T0, static_cast<double>(V0)); \
2564 test.setQwordTo(T1, static_cast<double>(V1)); \
2565 } else { \
2566 test.setDwordTo(T0, static_cast<float>(V0)); \
2567 test.setDwordTo(T1, static_cast<float>(V1)); \
2568 } \
2569 test.run(); \
2570 ASSERT_DOUBLE_EQ(Value, test.Dst<Type>()) << TestString << " value is " \
2571 << Value; \
2572 reset(); \
2573 } while (0)
2574
2575 #define TestMovssXmmXmm(FloatLength) \
2576 do { \
2577 using Type = std::conditional<FloatLength == 32, float, double>::type; \
2578 for (const Type Value : {0.0, -0.0, 1.0, -1.0, 3.14, 99999.9999}) { \
2579 TestMovssXmmXmmFloatLength(FloatLength, xmm0, xmm1, Value); \
2580 TestMovssXmmXmmFloatLength(FloatLength, xmm1, xmm2, Value); \
2581 TestMovssXmmXmmFloatLength(FloatLength, xmm2, xmm3, Value); \
2582 TestMovssXmmXmmFloatLength(FloatLength, xmm3, xmm4, Value); \
2583 TestMovssXmmXmmFloatLength(FloatLength, xmm4, xmm5, Value); \
2584 TestMovssXmmXmmFloatLength(FloatLength, xmm5, xmm6, Value); \
2585 TestMovssXmmXmmFloatLength(FloatLength, xmm6, xmm7, Value); \
2586 TestMovssXmmXmmFloatLength(FloatLength, xmm7, xmm0, Value); \
2587 } \
2588 } while (0)
2589
2590 TestMovssXmmXmm(32);
2591 TestMovssXmmXmm(64);
2592
2593 #undef TestMovssXmmXmm
2594 #undef TestMovssXmmXmmType
2595 }
2596
2597 TEST_F(AssemblerX8664Test, MovdToXmm) {
2598 #define TestMovdXmmReg(Src, Dst, Value) \
2599 do { \
2600 assert(((Value)&0xFFFFFFFF) == (Value)); \
2601 static constexpr char TestString[] = "(" #Src ", " #Dst ")"; \
2602 const uint32_t T0 = allocateQword(); \
2603 const uint64_t V0 = 0xFFFFFFFF00000000ull; \
2604 \
2605 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##Src, Immediate(Value)); \
2606 __ movss(IceType_f64, XmmRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
2607 __ movd(XmmRegister::Encoded_Reg_##Dst, GPRRegister::Encoded_Reg_##Src); \
2608 \
2609 AssembledTest test = assemble(); \
2610 \
2611 test.setQwordTo(T0, V0); \
2612 test.run(); \
2613 \
2614 ASSERT_EQ(Value, test.Dst<uint64_t>()) << TestString << " value is " \
2615 << Value; \
2616 reset(); \
2617 } while (0)
2618
2619 #define TestMovdXmmAddr(Dst, Value) \
2620 do { \
2621 assert(((Value)&0xFFFFFFFF) == (Value)); \
2622 static constexpr char TestString[] = "(" #Dst ", Addr)"; \
2623 const uint32_t T0 = allocateQword(); \
2624 const uint32_t V0 = Value; \
2625 const uint32_t T1 = allocateQword(); \
2626 const uint64_t V1 = 0xFFFFFFFF00000000ull; \
2627 \
2628 __ movss(IceType_f64, XmmRegister::Encoded_Reg_##Dst, dwordAddress(T1)); \
2629 __ movd(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
2630 \
2631 AssembledTest test = assemble(); \
2632 \
2633 test.setDwordTo(T0, V0); \
2634 test.setQwordTo(T1, V1); \
2635 test.run(); \
2636 \
2637 ASSERT_EQ(Value, test.Dst<uint64_t>()) << TestString << " value is " \
2638 << Value; \
2639 reset(); \
2640 } while (0)
2641
2642 #define TestMovd(Dst) \
2643 do { \
2644 for (uint32_t Value : {0u, 1u, 0x7FFFFFFFu, 0x80000000u, 0xFFFFFFFFu}) { \
2645 TestMovdXmmReg(eax, Dst, Value); \
2646 TestMovdXmmReg(ebx, Dst, Value); \
2647 TestMovdXmmReg(ecx, Dst, Value); \
2648 TestMovdXmmReg(edx, Dst, Value); \
2649 TestMovdXmmReg(esi, Dst, Value); \
2650 TestMovdXmmReg(edi, Dst, Value); \
2651 TestMovdXmmAddr(Dst, Value); \
2652 } \
2653 } while (0)
2654
2655 TestMovd(xmm0);
2656 TestMovd(xmm1);
2657 TestMovd(xmm2);
2658 TestMovd(xmm3);
2659 TestMovd(xmm4);
2660 TestMovd(xmm5);
2661 TestMovd(xmm6);
2662 TestMovd(xmm7);
2663
2664 #undef TestMovdXmmAddr
2665 #undef TestMovdXmmReg
2666 #undef TestMovd
2667 }
2668
2669 TEST_F(AssemblerX8664Test, MovdFromXmm) {
2670 #define TestMovdRegXmm(Src, Dst, Value) \
2671 do { \
2672 assert(((Value)&0xFFFFFFFF) == (Value)); \
2673 static constexpr char TestString[] = "(" #Src ", " #Dst ")"; \
2674 const uint32_t T0 = allocateDword(); \
2675 const uint32_t V0 = Value; \
2676 \
2677 __ movss(IceType_f64, XmmRegister::Encoded_Reg_##Src, dwordAddress(T0)); \
2678 __ movd(GPRRegister::Encoded_Reg_##Dst, XmmRegister::Encoded_Reg_##Src); \
2679 \
2680 AssembledTest test = assemble(); \
2681 \
2682 test.setDwordTo(T0, V0); \
2683 test.run(); \
2684 \
2685 ASSERT_EQ(Value, test.contentsOfDword(T0)) << TestString << " value is " \
2686 << Value; \
2687 reset(); \
2688 } while (0)
2689
2690 #define TestMovdAddrXmm(Src, Value) \
2691 do { \
2692 assert(((Value)&0xFFFFFFFF) == (Value)); \
2693 static constexpr char TestString[] = "(" #Src ", Addr)"; \
2694 const uint32_t T0 = allocateDword(); \
2695 const uint32_t V0 = Value; \
2696 const uint32_t T1 = allocateDword(); \
2697 const uint32_t V1 = ~(Value); \
2698 \
2699 __ movss(IceType_f64, XmmRegister::Encoded_Reg_##Src, dwordAddress(T0)); \
2700 __ movd(dwordAddress(T1), XmmRegister::Encoded_Reg_##Src); \
2701 \
2702 AssembledTest test = assemble(); \
2703 \
2704 test.setDwordTo(T0, V0); \
2705 test.setDwordTo(T1, V1); \
2706 test.run(); \
2707 \
2708 ASSERT_EQ(Value, test.contentsOfDword(T1)) << TestString << " value is " \
2709 << Value; \
2710 reset(); \
2711 } while (0)
2712
2713 #define TestMovd(Src) \
2714 do { \
2715 for (uint32_t Value : {0u, 1u, 0x7FFFFFFFu, 0x80000000u, 0xFFFFFFFFu}) { \
2716 TestMovdRegXmm(Src, eax, Value); \
2717 TestMovdRegXmm(Src, ebx, Value); \
2718 TestMovdRegXmm(Src, ecx, Value); \
2719 TestMovdRegXmm(Src, edx, Value); \
2720 TestMovdRegXmm(Src, esi, Value); \
2721 TestMovdRegXmm(Src, edi, Value); \
2722 TestMovdAddrXmm(Src, Value); \
2723 } \
2724 } while (0)
2725
2726 TestMovd(xmm0);
2727 TestMovd(xmm1);
2728 TestMovd(xmm2);
2729 TestMovd(xmm3);
2730 TestMovd(xmm4);
2731 TestMovd(xmm5);
2732 TestMovd(xmm6);
2733 TestMovd(xmm7);
2734
2735 #undef TestMovdAddrXmm
2736 #undef TestMovdRegXmm
2737 #undef TestMovd
2738 }
2739
2740 TEST_F(AssemblerX8664Test, MovqXmmAddr) {
2741 #define TestMovd(Dst, Value) \
2742 do { \
2743 static constexpr char TestString[] = "(" #Dst ", Addr)"; \
2744 const uint32_t T0 = allocateQword(); \
2745 const uint64_t V0 = Value; \
2746 const uint32_t T1 = allocateQword(); \
2747 const uint64_t V1 = ~(Value); \
2748 \
2749 __ movss(IceType_f64, XmmRegister::Encoded_Reg_##Dst, dwordAddress(T1)); \
2750 __ movq(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
2751 \
2752 AssembledTest test = assemble(); \
2753 \
2754 test.setQwordTo(T0, V0); \
2755 test.setQwordTo(T1, V1); \
2756 test.run(); \
2757 \
2758 ASSERT_EQ(Value, test.Dst<uint64_t>()) << TestString << " value is " \
2759 << Value; \
2760 reset(); \
2761 } while (0)
2762
2763 for (uint32_t Value : {0u, 1u, 0x7FFFFFFFu, 0x80000000u, 0xFFFFFFFFu}) {
2764 TestMovd(xmm0, Value);
2765 TestMovd(xmm1, Value);
2766 TestMovd(xmm2, Value);
2767 TestMovd(xmm3, Value);
2768 TestMovd(xmm4, Value);
2769 TestMovd(xmm5, Value);
2770 TestMovd(xmm6, Value);
2771 TestMovd(xmm7, Value);
2772 }
2773
2774 #undef TestMovd
2775 }
2776
2777 TEST_F(AssemblerX8664Test, MovqAddrXmm) {
2778 #define TestMovd(Dst, Value) \
2779 do { \
2780 static constexpr char TestString[] = "(" #Dst ", Addr)"; \
2781 const uint32_t T0 = allocateQword(); \
2782 const uint64_t V0 = Value; \
2783 const uint32_t T1 = allocateQword(); \
2784 const uint64_t V1 = ~(Value); \
2785 \
2786 __ movq(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
2787 __ movq(dwordAddress(T1), XmmRegister::Encoded_Reg_##Dst); \
2788 \
2789 AssembledTest test = assemble(); \
2790 \
2791 test.setQwordTo(T0, V0); \
2792 test.setQwordTo(T1, V1); \
2793 test.run(); \
2794 \
2795 ASSERT_EQ(Value, test.Dst<uint64_t>()) << TestString << " value is " \
2796 << Value; \
2797 reset(); \
2798 } while (0)
2799
2800 for (uint32_t Value : {0u, 1u, 0x7FFFFFFFu, 0x80000000u, 0xFFFFFFFFu}) {
2801 TestMovd(xmm0, Value);
2802 TestMovd(xmm1, Value);
2803 TestMovd(xmm2, Value);
2804 TestMovd(xmm3, Value);
2805 TestMovd(xmm4, Value);
2806 TestMovd(xmm5, Value);
2807 TestMovd(xmm6, Value);
2808 TestMovd(xmm7, Value);
2809 }
2810
2811 #undef TestMovd
2812 }
2813
2814 TEST_F(AssemblerX8664Test, MovqXmmXmm) {
2815 #define TestMovd(Src, Dst, Value) \
2816 do { \
2817 static constexpr char TestString[] = "(" #Src ", " #Dst ")"; \
2818 const uint32_t T0 = allocateQword(); \
2819 const uint64_t V0 = Value; \
2820 const uint32_t T1 = allocateQword(); \
2821 const uint64_t V1 = ~(Value); \
2822 \
2823 __ movq(XmmRegister::Encoded_Reg_##Src, dwordAddress(T0)); \
2824 __ movq(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T1)); \
2825 __ movq(XmmRegister::Encoded_Reg_##Dst, XmmRegister::Encoded_Reg_##Src); \
2826 \
2827 AssembledTest test = assemble(); \
2828 \
2829 test.setQwordTo(T0, V0); \
2830 test.setQwordTo(T1, V1); \
2831 test.run(); \
2832 \
2833 ASSERT_EQ(Value, test.Dst<uint64_t>()) << TestString << " value is " \
2834 << Value; \
2835 reset(); \
2836 } while (0)
2837
2838 for (uint32_t Value : {0u, 1u, 0x7FFFFFFFu, 0x80000000u, 0xFFFFFFFFu}) {
2839 TestMovd(xmm0, xmm1, Value);
2840 TestMovd(xmm1, xmm2, Value);
2841 TestMovd(xmm2, xmm3, Value);
2842 TestMovd(xmm3, xmm4, Value);
2843 TestMovd(xmm4, xmm5, Value);
2844 TestMovd(xmm5, xmm6, Value);
2845 TestMovd(xmm6, xmm7, Value);
2846 TestMovd(xmm7, xmm0, Value);
2847 }
2848
2849 #undef TestMovd
2850 }
2851
2852 TEST_F(AssemblerX8664Test, ArithSS) {
2853 #define TestArithSSXmmXmm(FloatSize, Src, Value0, Dst, Value1, Inst, Op) \
2854 do { \
2855 static_assert(FloatSize == 32 || FloatSize == 64, \
2856 "Invalid fp size " #FloatSize); \
2857 static constexpr char TestString[] = \
2858 "(" #FloatSize ", " #Src ", " #Value0 ", " #Dst ", " #Value1 \
2859 ", " #Inst ", " #Op ")"; \
2860 static constexpr bool IsDouble = FloatSize == 64; \
2861 using Type = std::conditional<IsDouble, double, float>::type; \
2862 const uint32_t T0 = allocateQword(); \
2863 const Type V0 = Value0; \
2864 const uint32_t T1 = allocateQword(); \
2865 const Type V1 = Value1; \
2866 \
2867 __ movss(IceType_f##FloatSize, XmmRegister::Encoded_Reg_##Dst, \
2868 dwordAddress(T0)); \
2869 __ movss(IceType_f##FloatSize, XmmRegister::Encoded_Reg_##Src, \
2870 dwordAddress(T1)); \
2871 __ Inst(IceType_f##FloatSize, XmmRegister::Encoded_Reg_##Dst, \
2872 XmmRegister::Encoded_Reg_##Src); \
2873 \
2874 AssembledTest test = assemble(); \
2875 if (IsDouble) { \
2876 test.setQwordTo(T0, static_cast<double>(V0)); \
2877 test.setQwordTo(T1, static_cast<double>(V1)); \
2878 } else { \
2879 test.setDwordTo(T0, static_cast<float>(V0)); \
2880 test.setDwordTo(T1, static_cast<float>(V1)); \
2881 } \
2882 \
2883 test.run(); \
2884 \
2885 ASSERT_DOUBLE_EQ(V0 Op V1, test.Dst<Type>()) << TestString; \
2886 reset(); \
2887 } while (0)
2888
2889 #define TestArithSSXmmAddr(FloatSize, Value0, Dst, Value1, Inst, Op) \
2890 do { \
2891 static_assert(FloatSize == 32 || FloatSize == 64, \
2892 "Invalid fp size " #FloatSize); \
2893 static constexpr char TestString[] = \
2894 "(" #FloatSize ", Addr, " #Value0 ", " #Dst ", " #Value1 ", " #Inst \
2895 ", " #Op ")"; \
2896 static constexpr bool IsDouble = FloatSize == 64; \
2897 using Type = std::conditional<IsDouble, double, float>::type; \
2898 const uint32_t T0 = allocateQword(); \
2899 const Type V0 = Value0; \
2900 const uint32_t T1 = allocateQword(); \
2901 const Type V1 = Value1; \
2902 \
2903 __ movss(IceType_f##FloatSize, XmmRegister::Encoded_Reg_##Dst, \
2904 dwordAddress(T0)); \
2905 __ Inst(IceType_f##FloatSize, XmmRegister::Encoded_Reg_##Dst, \
2906 dwordAddress(T1)); \
2907 \
2908 AssembledTest test = assemble(); \
2909 if (IsDouble) { \
2910 test.setQwordTo(T0, static_cast<double>(V0)); \
2911 test.setQwordTo(T1, static_cast<double>(V1)); \
2912 } else { \
2913 test.setDwordTo(T0, static_cast<float>(V0)); \
2914 test.setDwordTo(T1, static_cast<float>(V1)); \
2915 } \
2916 \
2917 test.run(); \
2918 \
2919 ASSERT_DOUBLE_EQ(V0 Op V1, test.Dst<Type>()) << TestString; \
2920 reset(); \
2921 } while (0)
2922
2923 #define TestArithSS(FloatSize, Src, Dst0, Dst1) \
2924 do { \
2925 TestArithSSXmmXmm(FloatSize, Src, 1.0, Dst0, 10.0, addss, +); \
2926 TestArithSSXmmAddr(FloatSize, 2.0, Dst1, 20.0, addss, +); \
2927 TestArithSSXmmXmm(FloatSize, Src, 3.0, Dst0, 30.0, subss, -); \
2928 TestArithSSXmmAddr(FloatSize, 4.0, Dst1, 40.0, subss, -); \
2929 TestArithSSXmmXmm(FloatSize, Src, 5.0, Dst0, 50.0, mulss, *); \
2930 TestArithSSXmmAddr(FloatSize, 6.0, Dst1, 60.0, mulss, *); \
2931 TestArithSSXmmXmm(FloatSize, Src, 7.0, Dst0, 70.0, divss, / ); \
2932 TestArithSSXmmAddr(FloatSize, 8.0, Dst1, 80.0, divss, / ); \
2933 } while (0)
2934
2935 TestArithSS(32, xmm0, xmm1, xmm2);
2936 TestArithSS(32, xmm1, xmm2, xmm3);
2937 TestArithSS(32, xmm2, xmm3, xmm4);
2938 TestArithSS(32, xmm3, xmm4, xmm5);
2939 TestArithSS(32, xmm4, xmm5, xmm6);
2940 TestArithSS(32, xmm5, xmm6, xmm7);
2941 TestArithSS(32, xmm6, xmm7, xmm0);
2942 TestArithSS(32, xmm7, xmm0, xmm1);
2943
2944 TestArithSS(64, xmm0, xmm1, xmm2);
2945 TestArithSS(64, xmm1, xmm2, xmm3);
2946 TestArithSS(64, xmm2, xmm3, xmm4);
2947 TestArithSS(64, xmm3, xmm4, xmm5);
2948 TestArithSS(64, xmm4, xmm5, xmm6);
2949 TestArithSS(64, xmm5, xmm6, xmm7);
2950 TestArithSS(64, xmm6, xmm7, xmm0);
2951 TestArithSS(64, xmm7, xmm0, xmm1);
2952
2953 #undef TestArithSS
2954 #undef TestArithSSXmmAddr
2955 #undef TestArithSSXmmXmm
2956 }
2957
2958 TEST_F(AssemblerX8664Test, MovupsXmmAddr) {
2959 #define TestMovups(Dst) \
2960 do { \
2961 static constexpr char TestString[] = "(" #Dst ")"; \
2962 const uint32_t T0 = allocateDqword(); \
2963 const Dqword V0(1.0f, -1.0, std::numeric_limits<float>::quiet_NaN(), \
2964 std::numeric_limits<float>::infinity()); \
2965 \
2966 __ movups(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
2967 \
2968 AssembledTest test = assemble(); \
2969 test.setDqwordTo(T0, V0); \
2970 test.run(); \
2971 \
2972 ASSERT_EQ(V0, test.Dst<Dqword>()) << TestString; \
2973 reset(); \
2974 } while (0)
2975
2976 TestMovups(xmm0);
2977 TestMovups(xmm1);
2978 TestMovups(xmm2);
2979 TestMovups(xmm3);
2980 TestMovups(xmm4);
2981 TestMovups(xmm5);
2982 TestMovups(xmm6);
2983 TestMovups(xmm7);
2984
2985 #undef TestMovups
2986 }
2987
2988 TEST_F(AssemblerX8664Test, MovupsAddrXmm) {
2989 #define TestMovups(Src) \
2990 do { \
2991 static constexpr char TestString[] = "(" #Src ")"; \
2992 const uint32_t T0 = allocateDqword(); \
2993 const Dqword V0(1.0f, -1.0, std::numeric_limits<float>::quiet_NaN(), \
2994 std::numeric_limits<float>::infinity()); \
2995 const uint32_t T1 = allocateDqword(); \
2996 const Dqword V1(0.0, 0.0, 0.0, 0.0); \
2997 \
2998 __ movups(XmmRegister::Encoded_Reg_##Src, dwordAddress(T0)); \
2999 __ movups(dwordAddress(T1), XmmRegister::Encoded_Reg_##Src); \
3000 \
3001 AssembledTest test = assemble(); \
3002 test.setDqwordTo(T0, V0); \
3003 test.setDqwordTo(T1, V1); \
3004 test.run(); \
3005 \
3006 ASSERT_EQ(V0, test.contentsOfDqword(T1)) << TestString; \
3007 reset(); \
3008 } while (0)
3009
3010 TestMovups(xmm0);
3011 TestMovups(xmm1);
3012 TestMovups(xmm2);
3013 TestMovups(xmm3);
3014 TestMovups(xmm4);
3015 TestMovups(xmm5);
3016 TestMovups(xmm6);
3017 TestMovups(xmm7);
3018
3019 #undef TestMovups
3020 }
3021
3022 TEST_F(AssemblerX8664Test, MovupsXmmXmm) {
3023 #define TestMovups(Dst, Src) \
3024 do { \
3025 static constexpr char TestString[] = "(" #Dst ", " #Src ")"; \
3026 const uint32_t T0 = allocateDqword(); \
3027 const Dqword V0(1.0f, -1.0, std::numeric_limits<float>::quiet_NaN(), \
3028 std::numeric_limits<float>::infinity()); \
3029 const uint32_t T1 = allocateDqword(); \
3030 const Dqword V1(0.0, 0.0, 0.0, 0.0); \
3031 \
3032 __ movups(XmmRegister::Encoded_Reg_##Src, dwordAddress(T0)); \
3033 __ movups(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T1)); \
3034 __ movups(XmmRegister::Encoded_Reg_##Dst, XmmRegister::Encoded_Reg_##Src); \
3035 \
3036 AssembledTest test = assemble(); \
3037 test.setDqwordTo(T0, V0); \
3038 test.setDqwordTo(T1, V1); \
3039 test.run(); \
3040 \
3041 ASSERT_EQ(V0, test.Dst<Dqword>()) << TestString; \
3042 reset(); \
3043 } while (0)
3044
3045 TestMovups(xmm0, xmm1);
3046 TestMovups(xmm1, xmm2);
3047 TestMovups(xmm2, xmm3);
3048 TestMovups(xmm3, xmm4);
3049 TestMovups(xmm4, xmm5);
3050 TestMovups(xmm5, xmm6);
3051 TestMovups(xmm6, xmm7);
3052 TestMovups(xmm7, xmm0);
3053
3054 #undef TestMovups
3055 }
3056
3057 TEST_F(AssemblerX8664Test, MovapsXmmXmm) {
3058 #define TestMovaps(Dst, Src) \
3059 do { \
3060 static constexpr char TestString[] = "(" #Dst ", " #Src ")"; \
3061 const uint32_t T0 = allocateDqword(); \
3062 const Dqword V0(1.0f, -1.0, std::numeric_limits<float>::quiet_NaN(), \
3063 std::numeric_limits<float>::infinity()); \
3064 const uint32_t T1 = allocateDqword(); \
3065 const Dqword V1(0.0, 0.0, 0.0, 0.0); \
3066 \
3067 __ movups(XmmRegister::Encoded_Reg_##Src, dwordAddress(T0)); \
3068 __ movups(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T1)); \
3069 __ movaps(XmmRegister::Encoded_Reg_##Dst, XmmRegister::Encoded_Reg_##Src); \
3070 \
3071 AssembledTest test = assemble(); \
3072 test.setDqwordTo(T0, V0); \
3073 test.setDqwordTo(T1, V1); \
3074 test.run(); \
3075 \
3076 ASSERT_EQ(V0, test.Dst<Dqword>()) << TestString; \
3077 reset(); \
3078 } while (0)
3079
3080 TestMovaps(xmm0, xmm1);
3081 TestMovaps(xmm1, xmm2);
3082 TestMovaps(xmm2, xmm3);
3083 TestMovaps(xmm3, xmm4);
3084 TestMovaps(xmm4, xmm5);
3085 TestMovaps(xmm5, xmm6);
3086 TestMovaps(xmm6, xmm7);
3087 TestMovaps(xmm7, xmm0);
3088
3089 #undef TestMovaps
3090 }
3091
3092 TEST_F(AssemblerX8664Test, PArith) {
3093 #define TestPArithXmmXmm(Dst, Value0, Src, Value1, Inst, Op, Type, Size) \
3094 do { \
3095 static constexpr char TestString[] = \
3096 "(" #Dst ", " #Value0 ", " #Src ", " #Value1 ", " #Inst ", " #Op \
3097 ", " #Type ", " #Size ")"; \
3098 const uint32_t T0 = allocateDqword(); \
3099 const Dqword V0 Value0; \
3100 \
3101 const uint32_t T1 = allocateDqword(); \
3102 const Dqword V1 Value1; \
3103 \
3104 __ movups(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
3105 __ movups(XmmRegister::Encoded_Reg_##Src, dwordAddress(T1)); \
3106 __ Inst(IceType_i##Size, XmmRegister::Encoded_Reg_##Dst, \
3107 XmmRegister::Encoded_Reg_##Src); \
3108 \
3109 AssembledTest test = assemble(); \
3110 test.setDqwordTo(T0, V0); \
3111 test.setDqwordTo(T1, V1); \
3112 test.run(); \
3113 \
3114 ASSERT_EQ(packedAs<Type##Size##_t>(V0) Op V1, test.Dst<Dqword>()) \
3115 << TestString; \
3116 reset(); \
3117 } while (0)
3118
3119 #define TestPArithXmmAddr(Dst, Value0, Value1, Inst, Op, Type, Size) \
3120 do { \
3121 static constexpr char TestString[] = \
3122 "(" #Dst ", " #Value0 ", Addr, " #Value1 ", " #Inst ", " #Op \
3123 ", " #Type ", " #Size ")"; \
3124 const uint32_t T0 = allocateDqword(); \
3125 const Dqword V0 Value0; \
3126 \
3127 const uint32_t T1 = allocateDqword(); \
3128 const Dqword V1 Value1; \
3129 \
3130 __ movups(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
3131 __ Inst(IceType_i##Size, XmmRegister::Encoded_Reg_##Dst, \
3132 dwordAddress(T1)); \
3133 \
3134 AssembledTest test = assemble(); \
3135 test.setDqwordTo(T0, V0); \
3136 test.setDqwordTo(T1, V1); \
3137 test.run(); \
3138 \
3139 ASSERT_EQ(packedAs<Type##Size##_t>(V0) Op V1, test.Dst<Dqword>()) \
3140 << TestString; \
3141 reset(); \
3142 } while (0)
3143
3144 #define TestPArithXmmImm(Dst, Value0, Imm, Inst, Op, Type, Size) \
3145 do { \
3146 static constexpr char TestString[] = \
3147 "(" #Dst ", " #Value0 ", " #Imm ", " #Inst ", " #Op ", " #Type \
3148 ", " #Size ")"; \
3149 const uint32_t T0 = allocateDqword(); \
3150 const Dqword V0 Value0; \
3151 \
3152 __ movups(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
3153 __ Inst(IceType_i##Size, XmmRegister::Encoded_Reg_##Dst, Immediate(Imm)); \
3154 \
3155 AssembledTest test = assemble(); \
3156 test.setDqwordTo(T0, V0); \
3157 test.run(); \
3158 \
3159 ASSERT_EQ(packedAs<Type##Size##_t>(V0) Op Imm, test.Dst<Dqword>()) \
3160 << TestString; \
3161 reset(); \
3162 } while (0)
3163
3164 #define TestPAndnXmmXmm(Dst, Value0, Src, Value1, Type, Size) \
3165 do { \
3166 static constexpr char TestString[] = \
3167 "(" #Dst ", " #Value0 ", " #Src ", " #Value1 ", pandn, " #Type \
3168 ", " #Size ")"; \
3169 const uint32_t T0 = allocateDqword(); \
3170 const Dqword V0 Value0; \
3171 \
3172 const uint32_t T1 = allocateDqword(); \
3173 const Dqword V1 Value1; \
3174 \
3175 __ movups(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
3176 __ movups(XmmRegister::Encoded_Reg_##Src, dwordAddress(T1)); \
3177 __ pandn(IceType_i##Size, XmmRegister::Encoded_Reg_##Dst, \
3178 XmmRegister::Encoded_Reg_##Src); \
3179 \
3180 AssembledTest test = assemble(); \
3181 test.setDqwordTo(T0, V0); \
3182 test.setDqwordTo(T1, V1); \
3183 test.run(); \
3184 \
3185 ASSERT_EQ(~(packedAs<Type##Size##_t>(V0)) & V1, test.Dst<Dqword>()) \
3186 << TestString; \
3187 reset(); \
3188 } while (0)
3189
3190 #define TestPAndnXmmAddr(Dst, Value0, Value1, Type, Size) \
3191 do { \
3192 static constexpr char TestString[] = \
3193 "(" #Dst ", " #Value0 ", Addr, " #Value1 ", pandn, " #Type ", " #Size \
3194 ")"; \
3195 const uint32_t T0 = allocateDqword(); \
3196 const Dqword V0 Value0; \
3197 \
3198 const uint32_t T1 = allocateDqword(); \
3199 const Dqword V1 Value1; \
3200 \
3201 __ movups(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
3202 __ pandn(IceType_i##Size, XmmRegister::Encoded_Reg_##Dst, \
3203 dwordAddress(T1)); \
3204 \
3205 AssembledTest test = assemble(); \
3206 test.setDqwordTo(T0, V0); \
3207 test.setDqwordTo(T1, V1); \
3208 test.run(); \
3209 \
3210 ASSERT_EQ((~packedAs<Type##Size##_t>(V0)) & V1, test.Dst<Dqword>()) \
3211 << TestString; \
3212 reset(); \
3213 } while (0)
3214
3215 #define TestPArithSize(Dst, Src, Size) \
3216 do { \
3217 static_assert(Size == 8 || Size == 16 || Size == 32, "Invalid size."); \
3218 if (Size != 8) { \
3219 TestPArithXmmXmm( \
3220 Dst, \
3221 (uint64_t(0x8040201008040201ull), uint64_t(0x8080404002020101ull)), \
3222 Src, (uint64_t(3u), uint64_t(0u)), psra, >>, int, Size); \
3223 TestPArithXmmAddr(Dst, (uint64_t(0x8040201008040201ull), \
3224 uint64_t(0x8080404002020101ull)), \
3225 (uint64_t(3u), uint64_t(0u)), psra, >>, int, Size); \
3226 TestPArithXmmImm(Dst, (uint64_t(0x8040201008040201ull), \
3227 uint64_t(0x8080404002020101ull)), \
3228 3u, psra, >>, int, Size); \
3229 TestPArithXmmXmm( \
3230 Dst, \
3231 (uint64_t(0x8040201008040201ull), uint64_t(0x8080404002020101ull)), \
3232 Src, (uint64_t(3u), uint64_t(0u)), psrl, >>, uint, Size); \
3233 TestPArithXmmAddr(Dst, (uint64_t(0x8040201008040201ull), \
3234 uint64_t(0x8080404002020101ull)), \
3235 (uint64_t(3u), uint64_t(0u)), psrl, >>, uint, Size); \
3236 TestPArithXmmImm(Dst, (uint64_t(0x8040201008040201ull), \
3237 uint64_t(0x8080404002020101ull)), \
3238 3u, psrl, >>, uint, Size); \
3239 TestPArithXmmXmm( \
3240 Dst, \
3241 (uint64_t(0x8040201008040201ull), uint64_t(0x8080404002020101ull)), \
3242 Src, (uint64_t(3u), uint64_t(0u)), psll, <<, uint, Size); \
3243 TestPArithXmmAddr(Dst, (uint64_t(0x8040201008040201ull), \
3244 uint64_t(0x8080404002020101ull)), \
3245 (uint64_t(3u), uint64_t(0u)), psll, <<, uint, Size); \
3246 TestPArithXmmImm(Dst, (uint64_t(0x8040201008040201ull), \
3247 uint64_t(0x8080404002020101ull)), \
3248 3u, psll, <<, uint, Size); \
3249 \
3250 TestPArithXmmXmm(Dst, (uint64_t(0x8040201008040201ull), \
3251 uint64_t(0x8080404002020101ull)), \
3252 Src, (uint64_t(0xFFFFFFFF00000000ull), \
3253 uint64_t(0x0123456789ABCDEull)), \
3254 pmull, *, int, Size); \
3255 TestPArithXmmAddr( \
3256 Dst, \
3257 (uint64_t(0x8040201008040201ull), uint64_t(0x8080404002020101ull)), \
3258 (uint64_t(0xFFFFFFFF00000000ull), uint64_t(0x0123456789ABCDEull)), \
3259 pmull, *, int, Size); \
3260 if (Size != 16) { \
3261 TestPArithXmmXmm(Dst, (uint64_t(0x8040201008040201ull), \
3262 uint64_t(0x8080404002020101ull)), \
3263 Src, (uint64_t(0xFFFFFFFF00000000ull), \
3264 uint64_t(0x0123456789ABCDEull)), \
3265 pmuludq, *, uint, Size); \
3266 TestPArithXmmAddr( \
3267 Dst, (uint64_t(0x8040201008040201ull), \
3268 uint64_t(0x8080404002020101ull)), \
3269 (uint64_t(0xFFFFFFFF00000000ull), uint64_t(0x0123456789ABCDEull)), \
3270 pmuludq, *, uint, Size); \
3271 } \
3272 } \
3273 TestPArithXmmXmm(Dst, (uint64_t(0x8040201008040201ull), \
3274 uint64_t(0x8080404002020101ull)), \
3275 Src, (uint64_t(0xFFFFFFFF00000000ull), \
3276 uint64_t(0x0123456789ABCDEull)), \
3277 padd, +, int, Size); \
3278 TestPArithXmmAddr( \
3279 Dst, \
3280 (uint64_t(0x8040201008040201ull), uint64_t(0x8080404002020101ull)), \
3281 (uint64_t(0xFFFFFFFF00000000ull), uint64_t(0x0123456789ABCDEull)), \
3282 padd, +, int, Size); \
3283 TestPArithXmmXmm(Dst, (uint64_t(0x8040201008040201ull), \
3284 uint64_t(0x8080404002020101ull)), \
3285 Src, (uint64_t(0xFFFFFFFF00000000ull), \
3286 uint64_t(0x0123456789ABCDEull)), \
3287 psub, -, int, Size); \
3288 TestPArithXmmAddr( \
3289 Dst, \
3290 (uint64_t(0x8040201008040201ull), uint64_t(0x8080404002020101ull)), \
3291 (uint64_t(0xFFFFFFFF00000000ull), uint64_t(0x0123456789ABCDEull)), \
3292 psub, -, int, Size); \
3293 TestPArithXmmXmm(Dst, (uint64_t(0x8040201008040201ull), \
3294 uint64_t(0x8080404002020101ull)), \
3295 Src, (uint64_t(0xFFFFFFFF00000000ull), \
3296 uint64_t(0x0123456789ABCDEull)), \
3297 pand, &, int, Size); \
3298 TestPArithXmmAddr( \
3299 Dst, \
3300 (uint64_t(0x8040201008040201ull), uint64_t(0x8080404002020101ull)), \
3301 (uint64_t(0xFFFFFFFF00000000ull), uint64_t(0x0123456789ABCDEull)), \
3302 pand, &, int, Size); \
3303 \
3304 TestPAndnXmmXmm(Dst, (uint64_t(0x8040201008040201ull), \
3305 uint64_t(0x8080404002020101ull)), \
3306 Src, (uint64_t(0xFFFFFFFF00000000ull), \
3307 uint64_t(0x0123456789ABCDEull)), \
3308 int, Size); \
3309 TestPAndnXmmAddr( \
3310 Dst, \
3311 (uint64_t(0x8040201008040201ull), uint64_t(0x8080404002020101ull)), \
3312 (uint64_t(0xFFFFFFFF00000000ull), uint64_t(0x0123456789ABCDEull)), \
3313 int, Size); \
3314 \
3315 TestPArithXmmXmm(Dst, (uint64_t(0x8040201008040201ull), \
3316 uint64_t(0x8080404002020101ull)), \
3317 Src, (uint64_t(0xFFFFFFFF00000000ull), \
3318 uint64_t(0x0123456789ABCDEull)), \
3319 por, |, int, Size); \
3320 TestPArithXmmAddr( \
3321 Dst, \
3322 (uint64_t(0x8040201008040201ull), uint64_t(0x8080404002020101ull)), \
3323 (uint64_t(0xFFFFFFFF00000000ull), uint64_t(0x0123456789ABCDEull)), \
3324 por, |, int, Size); \
3325 TestPArithXmmXmm(Dst, (uint64_t(0x8040201008040201ull), \
3326 uint64_t(0x8080404002020101ull)), \
3327 Src, (uint64_t(0xFFFFFFFF00000000ull), \
3328 uint64_t(0x0123456789ABCDEull)), \
3329 pxor, ^, int, Size); \
3330 TestPArithXmmAddr( \
3331 Dst, \
3332 (uint64_t(0x8040201008040201ull), uint64_t(0x8080404002020101ull)), \
3333 (uint64_t(0xFFFFFFFF00000000ull), uint64_t(0x0123456789ABCDEull)), \
3334 pxor, ^, int, Size); \
3335 } while (0)
3336
3337 #define TestPArith(Src, Dst) \
3338 do { \
3339 TestPArithSize(Src, Dst, 8); \
3340 TestPArithSize(Src, Dst, 16); \
3341 TestPArithSize(Src, Dst, 32); \
3342 } while (0)
3343
3344 TestPArith(xmm0, xmm1);
3345 TestPArith(xmm1, xmm2);
3346 TestPArith(xmm2, xmm3);
3347 TestPArith(xmm3, xmm4);
3348 TestPArith(xmm4, xmm5);
3349 TestPArith(xmm5, xmm6);
3350 TestPArith(xmm6, xmm7);
3351 TestPArith(xmm7, xmm0);
3352
3353 #undef TestPArith
3354 #undef TestPArithSize
3355 #undef TestPAndnXmmAddr
3356 #undef TestPAndnXmmXmm
3357 #undef TestPArithXmmImm
3358 #undef TestPArithXmmAddr
3359 #undef TestPArithXmmXmm
3360 }
3361
3362 TEST_F(AssemblerX8664Test, ArithPS) {
3363 #define TestArithPSXmmXmm(Dst, Value0, Src, Value1, Inst, Op, Type) \
3364 do { \
3365 static constexpr char TestString[] = \
3366 "(" #Dst ", " #Value0 ", " #Src ", " #Value1 ", " #Inst ", " #Op \
3367 ", " #Type ")"; \
3368 const uint32_t T0 = allocateDqword(); \
3369 const Dqword V0 Value0; \
3370 const uint32_t T1 = allocateDqword(); \
3371 const Dqword V1 Value1; \
3372 \
3373 __ movups(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
3374 __ movups(XmmRegister::Encoded_Reg_##Src, dwordAddress(T1)); \
3375 __ Inst(IceType_f32, XmmRegister::Encoded_Reg_##Dst, \
3376 XmmRegister::Encoded_Reg_##Src); \
3377 \
3378 AssembledTest test = assemble(); \
3379 test.setDqwordTo(T0, V0); \
3380 test.setDqwordTo(T1, V1); \
3381 test.run(); \
3382 \
3383 ASSERT_EQ(packedAs<Type>(V0) Op V1, test.Dst<Dqword>()) << TestString; \
3384 \
3385 reset(); \
3386 } while (0)
3387
3388 #define TestArithPSXmmXmmUntyped(Dst, Value0, Src, Value1, Inst, Op, Type) \
3389 do { \
3390 static constexpr char TestString[] = \
3391 "(" #Dst ", " #Value0 ", " #Src ", " #Value1 ", " #Inst ", " #Op \
3392 ", " #Type ")"; \
3393 const uint32_t T0 = allocateDqword(); \
3394 const Dqword V0 Value0; \
3395 const uint32_t T1 = allocateDqword(); \
3396 const Dqword V1 Value1; \
3397 \
3398 __ movups(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
3399 __ movups(XmmRegister::Encoded_Reg_##Src, dwordAddress(T1)); \
3400 __ Inst(XmmRegister::Encoded_Reg_##Dst, XmmRegister::Encoded_Reg_##Src); \
3401 \
3402 AssembledTest test = assemble(); \
3403 test.setDqwordTo(T0, V0); \
3404 test.setDqwordTo(T1, V1); \
3405 test.run(); \
3406 \
3407 ASSERT_EQ(packedAs<Type>(V0) Op V1, test.Dst<Dqword>()) << TestString; \
3408 \
3409 reset(); \
3410 } while (0)
3411
3412 #define TestArithPSXmmAddrUntyped(Dst, Value0, Value1, Inst, Op, Type) \
3413 do { \
3414 static constexpr char TestString[] = \
3415 "(" #Dst ", " #Value0 ", Addr, " #Value1 ", " #Inst ", " #Op \
3416 ", " #Type ")"; \
3417 const uint32_t T0 = allocateDqword(); \
3418 const Dqword V0 Value0; \
3419 const uint32_t T1 = allocateDqword(); \
3420 const Dqword V1 Value1; \
3421 \
3422 __ movups(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
3423 __ Inst(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T1)); \
3424 \
3425 AssembledTest test = assemble(); \
3426 test.setDqwordTo(T0, V0); \
3427 test.setDqwordTo(T1, V1); \
3428 test.run(); \
3429 \
3430 ASSERT_EQ(packedAs<Type>(V0) Op V1, test.Dst<Dqword>()) << TestString; \
3431 \
3432 reset(); \
3433 } while (0)
3434
3435 #define TestMinMaxPS(Dst, Value0, Src, Value1, Inst, Type) \
3436 do { \
3437 static constexpr char TestString[] = \
3438 "(" #Dst ", " #Value0 ", " #Src ", " #Value1 ", " #Inst ", " #Type \
3439 ")"; \
3440 const uint32_t T0 = allocateDqword(); \
3441 const Dqword V0 Value0; \
3442 const uint32_t T1 = allocateDqword(); \
3443 const Dqword V1 Value1; \
3444 \
3445 __ movups(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
3446 __ movups(XmmRegister::Encoded_Reg_##Src, dwordAddress(T1)); \
3447 __ Inst(XmmRegister::Encoded_Reg_##Dst, XmmRegister::Encoded_Reg_##Src); \
3448 \
3449 AssembledTest test = assemble(); \
3450 test.setDqwordTo(T0, V0); \
3451 test.setDqwordTo(T1, V1); \
3452 test.run(); \
3453 \
3454 ASSERT_EQ(packedAs<Type>(V0).Inst(V1), test.Dst<Dqword>()) << TestString; \
3455 \
3456 reset(); \
3457 } while (0)
3458
3459 #define TestArithPSXmmAddr(Dst, Value0, Value1, Inst, Op, Type) \
3460 do { \
3461 static constexpr char TestString[] = \
3462 "(" #Dst ", " #Value0 ", Addr, " #Value1 ", " #Inst ", " #Op \
3463 ", " #Type ")"; \
3464 const uint32_t T0 = allocateDqword(); \
3465 const Dqword V0 Value0; \
3466 const uint32_t T1 = allocateDqword(); \
3467 const Dqword V1 Value1; \
3468 \
3469 __ movups(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
3470 __ Inst(IceType_f32, XmmRegister::Encoded_Reg_##Dst, dwordAddress(T1)); \
3471 \
3472 AssembledTest test = assemble(); \
3473 test.setDqwordTo(T0, V0); \
3474 test.setDqwordTo(T1, V1); \
3475 test.run(); \
3476 \
3477 ASSERT_EQ(packedAs<Type>(V0) Op V1, test.Dst<Dqword>()) << TestString; \
3478 \
3479 reset(); \
3480 } while (0)
3481
3482 #define TestArithPS(Src, Dst) \
3483 do { \
3484 TestArithPSXmmXmm(Src, (1.0, 100.0, -1000.0, 20.0), Dst, \
3485 (0.55, 0.43, 0.23, 1.21), addps, +, float); \
3486 TestArithPSXmmAddr(Src, (1.0, 100.0, -1000.0, 20.0), \
3487 (0.55, 0.43, 0.23, 1.21), addps, +, float); \
3488 TestArithPSXmmXmm(Src, (1.0, 100.0, -1000.0, 20.0), Dst, \
3489 (0.55, 0.43, 0.23, 1.21), subps, -, float); \
3490 TestArithPSXmmAddr(Src, (1.0, 100.0, -1000.0, 20.0), \
3491 (0.55, 0.43, 0.23, 1.21), subps, -, float); \
3492 TestArithPSXmmXmm(Src, (1.0, 100.0, -1000.0, 20.0), Dst, \
3493 (0.55, 0.43, 0.23, 1.21), mulps, *, float); \
3494 TestArithPSXmmAddr(Src, (1.0, 100.0, -1000.0, 20.0), \
3495 (0.55, 0.43, 0.23, 1.21), mulps, *, float); \
3496 TestArithPSXmmXmmUntyped(Src, (1.0, 100.0, -1000.0, 20.0), Dst, \
3497 (0.55, 0.43, 0.23, 1.21), andps, &, float); \
3498 TestArithPSXmmXmmUntyped(Src, (1.0, -1000.0), Dst, (0.55, 1.21), andpd, &, \
3499 double); \
3500 TestArithPSXmmAddrUntyped(Src, (1.0, -1000.0), (0.55, 1.21), andpd, &, \
3501 double); \
3502 TestArithPSXmmXmmUntyped(Src, (1.0, 100.0, -1000.0, 20.0), Dst, \
3503 (0.55, 0.43, 0.23, 1.21), orps, |, float); \
3504 TestArithPSXmmXmmUntyped(Src, (1.0, -1000.0), Dst, (0.55, 1.21), orpd, |, \
3505 double); \
3506 TestMinMaxPS(Src, (1.0, 100.0, -1000.0, 20.0), Dst, \
3507 (0.55, 0.43, 0.23, 1.21), minps, float); \
3508 TestMinMaxPS(Src, (1.0, 100.0, -1000.0, 20.0), Dst, \
3509 (0.55, 0.43, 0.23, 1.21), maxps, float); \
3510 TestMinMaxPS(Src, (1.0, -1000.0), Dst, (0.55, 1.21), minpd, double); \
3511 TestMinMaxPS(Src, (1.0, -1000.0), Dst, (0.55, 1.21), maxpd, double); \
3512 TestArithPSXmmXmmUntyped(Src, (1.0, 100.0, -1000.0, 20.0), Dst, \
3513 (0.55, 0.43, 0.23, 1.21), xorps, ^, float); \
3514 TestArithPSXmmAddrUntyped(Src, (1.0, 100.0, -1000.0, 20.0), \
3515 (0.55, 0.43, 0.23, 1.21), xorps, ^, float); \
3516 TestArithPSXmmXmmUntyped(Src, (1.0, -1000.0), Dst, (0.55, 1.21), xorpd, ^, \
3517 double); \
3518 TestArithPSXmmAddrUntyped(Src, (1.0, -1000.0), (0.55, 1.21), xorpd, ^, \
3519 double); \
3520 } while (0)
3521
3522 #if 0
3523
3524 #endif
3525
3526 TestArithPS(xmm0, xmm1);
3527 TestArithPS(xmm1, xmm2);
3528 TestArithPS(xmm2, xmm3);
3529 TestArithPS(xmm3, xmm4);
3530 TestArithPS(xmm4, xmm5);
3531 TestArithPS(xmm5, xmm6);
3532 TestArithPS(xmm6, xmm7);
3533 TestArithPS(xmm7, xmm0);
3534
3535 #undef TestArithPs
3536 #undef TestMinMaxPS
3537 #undef TestArithPSXmmXmmUntyped
3538 #undef TestArithPSXmmAddr
3539 #undef TestArithPSXmmXmm
3540 }
3541
3542 TEST_F(AssemblerX8664Test, Blending) {
3543 using f32 = float;
3544 using i8 = uint8_t;
3545
3546 #define TestBlendingXmmXmm(Dst, Value0, Src, Value1, M /*ask*/, Inst, Type) \
3547 do { \
3548 static constexpr char TestString[] = \
3549 "(" #Dst ", " #Value0 ", " #Src ", " #Value1 ", " #M ", " #Inst \
3550 ", " #Type ")"; \
3551 const uint32_t T0 = allocateDqword(); \
3552 const Dqword V0 Value0; \
3553 const uint32_t T1 = allocateDqword(); \
3554 const Dqword V1 Value1; \
3555 const uint32_t Mask = allocateDqword(); \
3556 const Dqword MaskValue M; \
3557 \
3558 __ movups(XmmRegister::Encoded_Reg_xmm0, dwordAddress(Mask)); \
3559 __ movups(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
3560 __ movups(XmmRegister::Encoded_Reg_##Src, dwordAddress(T1)); \
3561 __ Inst(IceType_##Type, XmmRegister::Encoded_Reg_##Dst, \
3562 XmmRegister::Encoded_Reg_##Src); \
3563 \
3564 AssembledTest test = assemble(); \
3565 test.setDqwordTo(T0, V0); \
3566 test.setDqwordTo(T1, V1); \
3567 test.setDqwordTo(Mask, MaskValue); \
3568 test.run(); \
3569 \
3570 ASSERT_EQ(packedAs<Type>(V0).blendWith(V1, MaskValue), test.Dst<Dqword>()) \
3571 << TestString; \
3572 reset(); \
3573 } while (0)
3574
3575 #define TestBlendingXmmAddr(Dst, Value0, Value1, M /*ask*/, Inst, Type) \
3576 do { \
3577 static constexpr char TestString[] = \
3578 "(" #Dst ", " #Value0 ", Addr, " #Value1 ", " #M ", " #Inst ", " #Type \
3579 ")"; \
3580 const uint32_t T0 = allocateDqword(); \
3581 const Dqword V0 Value0; \
3582 const uint32_t T1 = allocateDqword(); \
3583 const Dqword V1 Value1; \
3584 const uint32_t Mask = allocateDqword(); \
3585 const Dqword MaskValue M; \
3586 \
3587 __ movups(XmmRegister::Encoded_Reg_xmm0, dwordAddress(Mask)); \
3588 __ movups(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
3589 __ Inst(IceType_##Type, XmmRegister::Encoded_Reg_##Dst, dwordAddress(T1)); \
3590 \
3591 AssembledTest test = assemble(); \
3592 test.setDqwordTo(T0, V0); \
3593 test.setDqwordTo(T1, V1); \
3594 test.setDqwordTo(Mask, MaskValue); \
3595 test.run(); \
3596 \
3597 ASSERT_EQ(packedAs<Type>(V0).blendWith(V1, MaskValue), test.Dst<Dqword>()) \
3598 << TestString; \
3599 reset(); \
3600 } while (0)
3601
3602 #define TestBlending(Src, Dst) \
3603 do { \
3604 TestBlendingXmmXmm( \
3605 Dst, (1.0, 2.0, 1.0, 2.0), Src, (-1.0, -2.0, -1.0, -2.0), \
3606 (uint64_t(0x8000000000000000ull), uint64_t(0x0000000080000000ull)), \
3607 blendvps, f32); \
3608 TestBlendingXmmAddr( \
3609 Dst, (1.0, 2.0, 1.0, 2.0), (-1.0, -2.0, -1.0, -2.0), \
3610 (uint64_t(0x8000000000000000ull), uint64_t(0x0000000080000000ull)), \
3611 blendvps, f32); \
3612 TestBlendingXmmXmm( \
3613 Dst, \
3614 (uint64_t(0xFFFFFFFFFFFFFFFFull), uint64_t(0xBBBBBBBBBBBBBBBBull)), \
3615 Src, \
3616 (uint64_t(0xAAAAAAAAAAAAAAAAull), uint64_t(0xEEEEEEEEEEEEEEEEull)), \
3617 (uint64_t(0x8000000000000080ull), uint64_t(0x8080808000000000ull)), \
3618 pblendvb, i8); \
3619 TestBlendingXmmAddr( \
3620 Dst, \
3621 (uint64_t(0xFFFFFFFFFFFFFFFFull), uint64_t(0xBBBBBBBBBBBBBBBBull)), \
3622 (uint64_t(0xAAAAAAAAAAAAAAAAull), uint64_t(0xEEEEEEEEEEEEEEEEull)), \
3623 (uint64_t(0x8000000000000080ull), uint64_t(0x8080808000000000ull)), \
3624 pblendvb, i8); \
3625 } while (0)
3626
3627 /* xmm0 is taken. It is the implicit mask . */
3628 TestBlending(xmm1, xmm2);
3629 TestBlending(xmm2, xmm3);
3630 TestBlending(xmm3, xmm4);
3631 TestBlending(xmm4, xmm5);
3632 TestBlending(xmm5, xmm6);
3633 TestBlending(xmm6, xmm7);
3634 TestBlending(xmm7, xmm1);
3635
3636 #undef TestBlending
3637 #undef TestBlendingXmmAddr
3638 #undef TestBlendingXmmXmm
3639 }
3640
3641 TEST_F(AssemblerX8664Test, Cmpps) {
3642 #define TestCmppsXmmXmm(Dst, Src, C, Op) \
3643 do { \
3644 static constexpr char TestString[] = \
3645 "(" #Src ", " #Dst ", " #C ", " #Op ")"; \
3646 const uint32_t T0 = allocateDqword(); \
3647 const Dqword V0(-1.0, 1.0, 3.14, 1024.5); \
3648 const uint32_t T1 = allocateDqword(); \
3649 const Dqword V1(-1.0, 1.0, 3.14, 1024.5); \
3650 \
3651 __ movups(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
3652 __ movups(XmmRegister::Encoded_Reg_##Src, dwordAddress(T1)); \
3653 __ cmpps(XmmRegister::Encoded_Reg_##Dst, XmmRegister::Encoded_Reg_##Src, \
3654 Cond::Cmpps_##C); \
3655 \
3656 AssembledTest test = assemble(); \
3657 test.setDqwordTo(T0, V0); \
3658 test.setDqwordTo(T1, V1); \
3659 test.run(); \
3660 \
3661 ASSERT_EQ(packedAs<float>(V0) Op V1, test.Dst<Dqword>()) << TestString; \
3662 ; \
3663 reset(); \
3664 } while (0)
3665
3666 #define TestCmppsXmmAddr(Dst, C, Op) \
3667 do { \
3668 static constexpr char TestString[] = "(" #Dst ", Addr, " #C ", " #Op ")"; \
3669 const uint32_t T0 = allocateDqword(); \
3670 const Dqword V0(-1.0, 1.0, 3.14, 1024.5); \
3671 const uint32_t T1 = allocateDqword(); \
3672 const Dqword V1(-1.0, 1.0, 3.14, 1024.5); \
3673 \
3674 __ movups(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
3675 __ cmpps(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T1), \
3676 Cond::Cmpps_##C); \
3677 \
3678 AssembledTest test = assemble(); \
3679 test.setDqwordTo(T0, V0); \
3680 test.setDqwordTo(T1, V1); \
3681 test.run(); \
3682 \
3683 ASSERT_EQ(packedAs<float>(V0) Op V1, test.Dst<Dqword>()) << TestString; \
3684 ; \
3685 reset(); \
3686 } while (0)
3687
3688 #define TestCmppsOrdUnordXmmXmm(Dst, Src, C) \
3689 do { \
3690 static constexpr char TestString[] = "(" #Src ", " #Dst ", " #C ")"; \
3691 const uint32_t T0 = allocateDqword(); \
3692 const Dqword V0(1.0, 1.0, std::numeric_limits<float>::quiet_NaN(), \
3693 std::numeric_limits<float>::quiet_NaN()); \
3694 const uint32_t T1 = allocateDqword(); \
3695 const Dqword V1(1.0, std::numeric_limits<float>::quiet_NaN(), 1.0, \
3696 std::numeric_limits<float>::quiet_NaN()); \
3697 \
3698 __ movups(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
3699 __ movups(XmmRegister::Encoded_Reg_##Src, dwordAddress(T1)); \
3700 __ cmpps(XmmRegister::Encoded_Reg_##Dst, XmmRegister::Encoded_Reg_##Src, \
3701 Cond::Cmpps_##C); \
3702 \
3703 AssembledTest test = assemble(); \
3704 test.setDqwordTo(T0, V0); \
3705 test.setDqwordTo(T1, V1); \
3706 test.run(); \
3707 \
3708 ASSERT_EQ(packedAs<float>(V0).C(V1), test.Dst<Dqword>()) << TestString; \
3709 ; \
3710 reset(); \
3711 } while (0)
3712
3713 #define TestCmppsOrdUnordXmmAddr(Dst, C) \
3714 do { \
3715 static constexpr char TestString[] = "(" #Dst ", " #C ")"; \
3716 const uint32_t T0 = allocateDqword(); \
3717 const Dqword V0(1.0, 1.0, std::numeric_limits<float>::quiet_NaN(), \
3718 std::numeric_limits<float>::quiet_NaN()); \
3719 const uint32_t T1 = allocateDqword(); \
3720 const Dqword V1(1.0, std::numeric_limits<float>::quiet_NaN(), 1.0, \
3721 std::numeric_limits<float>::quiet_NaN()); \
3722 \
3723 __ movups(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
3724 __ cmpps(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T1), \
3725 Cond::Cmpps_##C); \
3726 \
3727 AssembledTest test = assemble(); \
3728 test.setDqwordTo(T0, V0); \
3729 test.setDqwordTo(T1, V1); \
3730 test.run(); \
3731 \
3732 ASSERT_EQ(packedAs<float>(V0).C(V1), test.Dst<Dqword>()) << TestString; \
3733 ; \
3734 reset(); \
3735 } while (0)
3736
3737 #define TestCmpps(Dst, Src) \
3738 do { \
3739 TestCmppsXmmXmm(Dst, Src, eq, == ); \
3740 TestCmppsXmmAddr(Dst, eq, == ); \
3741 TestCmppsXmmXmm(Dst, Src, eq, == ); \
3742 TestCmppsXmmAddr(Dst, eq, == ); \
3743 TestCmppsXmmXmm(Dst, Src, eq, == ); \
3744 TestCmppsXmmAddr(Dst, eq, == ); \
3745 TestCmppsOrdUnordXmmXmm(Dst, Src, unord); \
3746 TestCmppsOrdUnordXmmAddr(Dst, unord); \
3747 TestCmppsXmmXmm(Dst, Src, eq, == ); \
3748 TestCmppsXmmAddr(Dst, eq, == ); \
3749 TestCmppsXmmXmm(Dst, Src, eq, == ); \
3750 TestCmppsXmmAddr(Dst, eq, == ); \
3751 TestCmppsXmmXmm(Dst, Src, eq, == ); \
3752 TestCmppsXmmAddr(Dst, eq, == ); \
3753 TestCmppsOrdUnordXmmXmm(Dst, Src, unord); \
3754 TestCmppsOrdUnordXmmAddr(Dst, unord); \
3755 } while (0)
3756
3757 TestCmpps(xmm0, xmm1);
3758 TestCmpps(xmm1, xmm2);
3759 TestCmpps(xmm2, xmm3);
3760 TestCmpps(xmm3, xmm4);
3761 TestCmpps(xmm4, xmm5);
3762 TestCmpps(xmm5, xmm6);
3763 TestCmpps(xmm6, xmm7);
3764 TestCmpps(xmm7, xmm0);
3765
3766 #undef TestCmpps
3767 #undef TestCmppsOrdUnordXmmAddr
3768 #undef TestCmppsOrdUnordXmmXmm
3769 #undef TestCmppsXmmAddr
3770 #undef TestCmppsXmmXmm
3771 }
3772
3773 TEST_F(AssemblerX8664Test, Sqrtps_Rsqrtps_Reciprocalps_Sqrtpd) {
3774 #define TestImplSingle(Dst, Inst, Expect) \
3775 do { \
3776 static constexpr char TestString[] = "(" #Dst ", " #Inst ")"; \
3777 const uint32_t T0 = allocateDqword(); \
3778 const Dqword V0(1.0, 4.0, 20.0, 3.14); \
3779 \
3780 __ movups(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
3781 __ Inst(XmmRegister::Encoded_Reg_##Dst); \
3782 \
3783 AssembledTest test = assemble(); \
3784 test.setDqwordTo(T0, V0); \
3785 test.run(); \
3786 ASSERT_EQ(Dqword Expect, test.Dst<Dqword>()) << TestString; \
3787 reset(); \
3788 } while (0)
3789
3790 #define TestImpl(Dst) \
3791 do { \
3792 TestImplSingle(Dst, sqrtps, (uint64_t(0x400000003F800000ull), \
3793 uint64_t(0x3FE2D10B408F1BBDull))); \
3794 TestImplSingle(Dst, rsqrtps, (uint64_t(0x3EFFF0003F7FF000ull), \
3795 uint64_t(0x3F1078003E64F000ull))); \
3796 TestImplSingle(Dst, reciprocalps, (uint64_t(0x3E7FF0003F7FF000ull), \
3797 uint64_t(0x3EA310003D4CC000ull))); \
3798 \
3799 TestImplSingle(Dst, sqrtpd, (uint64_t(0x4036A09E9365F5F3ull), \
3800 uint64_t(0x401C42FAE40282A8ull))); \
3801 } while (0)
3802
3803 TestImpl(xmm0);
3804 TestImpl(xmm1);
3805 TestImpl(xmm2);
3806 TestImpl(xmm3);
3807 TestImpl(xmm4);
3808 TestImpl(xmm5);
3809 TestImpl(xmm6);
3810 TestImpl(xmm7);
3811
3812 #undef TestImpl
3813 #undef TestImplSingle
3814 }
3815
3816 TEST_F(AssemblerX8664Test, Movhlps_Movlhps) {
3817 #define TestImplSingle(Dst, Src, Inst, Expect) \
3818 do { \
3819 static constexpr char TestString[] = "(" #Dst ", " #Src ", " #Inst ")"; \
3820 const uint32_t T0 = allocateDqword(); \
3821 const Dqword V0(uint64_t(0xAAAAAAAABBBBBBBBull), \
3822 uint64_t(0xCCCCCCCCDDDDDDDDull)); \
3823 const uint32_t T1 = allocateDqword(); \
3824 const Dqword V1(uint64_t(0xEEEEEEEEFFFFFFFFull), \
3825 uint64_t(0x9999999988888888ull)); \
3826 \
3827 __ movups(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
3828 __ movups(XmmRegister::Encoded_Reg_##Src, dwordAddress(T1)); \
3829 __ Inst(XmmRegister::Encoded_Reg_##Dst, XmmRegister::Encoded_Reg_##Src); \
3830 \
3831 AssembledTest test = assemble(); \
3832 test.setDqwordTo(T0, V0); \
3833 test.setDqwordTo(T1, V1); \
3834 test.run(); \
3835 \
3836 ASSERT_EQ(Dqword Expect, test.Dst<Dqword>()) << TestString; \
3837 reset(); \
3838 } while (0)
3839
3840 #define TestImpl(Dst, Src) \
3841 do { \
3842 TestImplSingle(Dst, Src, movhlps, (uint64_t(0x9999999988888888ull), \
3843 uint64_t(0xCCCCCCCCDDDDDDDDull))); \
3844 TestImplSingle(Dst, Src, movlhps, (uint64_t(0xAAAAAAAABBBBBBBBull), \
3845 uint64_t(0xEEEEEEEEFFFFFFFFull))); \
3846 } while (0)
3847
3848 TestImpl(xmm0, xmm1);
3849 TestImpl(xmm1, xmm2);
3850 TestImpl(xmm2, xmm3);
3851 TestImpl(xmm3, xmm4);
3852 TestImpl(xmm4, xmm5);
3853 TestImpl(xmm5, xmm6);
3854 TestImpl(xmm6, xmm7);
3855 TestImpl(xmm7, xmm0);
3856
3857 #undef TestImpl
3858 #undef TestImplSingle
3859 }
3860
3861 TEST_F(AssemblerX8664Test, Unpck) {
3862 const Dqword V0(uint64_t(0xAAAAAAAABBBBBBBBull),
3863 uint64_t(0xCCCCCCCCDDDDDDDDull));
3864 const Dqword V1(uint64_t(0xEEEEEEEEFFFFFFFFull),
3865 uint64_t(0x9999999988888888ull));
3866
3867 const Dqword unpcklpsExpected(uint64_t(0xFFFFFFFFBBBBBBBBull),
3868 uint64_t(0xEEEEEEEEAAAAAAAAull));
3869 const Dqword unpcklpdExpected(uint64_t(0xAAAAAAAABBBBBBBBull),
3870 uint64_t(0xEEEEEEEEFFFFFFFFull));
3871 const Dqword unpckhpsExpected(uint64_t(0x88888888DDDDDDDDull),
3872 uint64_t(0x99999999CCCCCCCCull));
3873 const Dqword unpckhpdExpected(uint64_t(0xCCCCCCCCDDDDDDDDull),
3874 uint64_t(0x9999999988888888ull));
3875
3876 #define TestImplSingle(Dst, Src, Inst) \
3877 do { \
3878 static constexpr char TestString[] = "(" #Dst ", " #Src ", " #Inst ")"; \
3879 const uint32_t T0 = allocateDqword(); \
3880 const uint32_t T1 = allocateDqword(); \
3881 \
3882 __ movups(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
3883 __ movups(XmmRegister::Encoded_Reg_##Src, dwordAddress(T1)); \
3884 __ Inst(XmmRegister::Encoded_Reg_##Dst, XmmRegister::Encoded_Reg_##Src); \
3885 \
3886 AssembledTest test = assemble(); \
3887 test.setDqwordTo(T0, V0); \
3888 test.setDqwordTo(T1, V1); \
3889 test.run(); \
3890 \
3891 ASSERT_EQ(Inst##Expected, test.Dst<Dqword>()) << TestString; \
3892 reset(); \
3893 } while (0)
3894
3895 #define TestImpl(Dst, Src) \
3896 do { \
3897 TestImplSingle(Dst, Src, unpcklps); \
3898 TestImplSingle(Dst, Src, unpcklpd); \
3899 TestImplSingle(Dst, Src, unpckhps); \
3900 TestImplSingle(Dst, Src, unpckhpd); \
3901 } while (0)
3902
3903 TestImpl(xmm0, xmm1);
3904 TestImpl(xmm1, xmm2);
3905 TestImpl(xmm2, xmm3);
3906 TestImpl(xmm3, xmm4);
3907 TestImpl(xmm4, xmm5);
3908 TestImpl(xmm5, xmm6);
3909 TestImpl(xmm6, xmm7);
3910 TestImpl(xmm7, xmm0);
3911
3912 #undef TestImpl
3913 #undef TestImplSingle
3914 }
3915
3916 TEST_F(AssemblerX8664Test, Shufp) {
3917 const Dqword V0(uint64_t(0x1111111122222222ull),
3918 uint64_t(0x5555555577777777ull));
3919 const Dqword V1(uint64_t(0xAAAAAAAABBBBBBBBull),
3920 uint64_t(0xCCCCCCCCDDDDDDDDull));
3921
3922 const uint8_t pshufdImm = 0x63;
3923 const Dqword pshufdExpected(uint64_t(0xBBBBBBBBCCCCCCCCull),
3924 uint64_t(0xAAAAAAAADDDDDDDDull));
3925
3926 const uint8_t shufpsImm = 0xf9;
3927 const Dqword shufpsExpected(uint64_t(0x7777777711111111ull),
3928 uint64_t(0xCCCCCCCCCCCCCCCCull));
3929 const Dqword shufpsUntypedExpected(uint64_t(0x7777777711111111ull),
3930 uint64_t(0xCCCCCCCCCCCCCCCCull));
3931
3932 const uint8_t shufpdImm = 0x02;
3933 const Dqword shufpdUntypedExpected(uint64_t(0x1111111122222222ull),
3934 uint64_t(0xCCCCCCCCDDDDDDDDull));
3935
3936 #define TestImplSingleXmmXmm(Dst, Src, Inst) \
3937 do { \
3938 static constexpr char TestString[] = "(" #Dst ", " #Src ", " #Inst ")"; \
3939 const uint32_t T0 = allocateDqword(); \
3940 const uint32_t T1 = allocateDqword(); \
3941 \
3942 __ movups(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
3943 __ movups(XmmRegister::Encoded_Reg_##Src, dwordAddress(T1)); \
3944 __ Inst(IceType_f32, XmmRegister::Encoded_Reg_##Dst, \
3945 XmmRegister::Encoded_Reg_##Src, Immediate(Inst##Imm)); \
3946 \
3947 AssembledTest test = assemble(); \
3948 test.setDqwordTo(T0, V0); \
3949 test.setDqwordTo(T1, V1); \
3950 test.run(); \
3951 \
3952 ASSERT_EQ(Inst##Expected, test.Dst<Dqword>()) << TestString; \
3953 reset(); \
3954 } while (0)
3955
3956 #define TestImplSingleXmmAddr(Dst, Inst) \
3957 do { \
3958 static constexpr char TestString[] = "(" #Dst ", Addr, " #Inst ")"; \
3959 const uint32_t T0 = allocateDqword(); \
3960 const uint32_t T1 = allocateDqword(); \
3961 \
3962 __ movups(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
3963 __ Inst(IceType_f32, XmmRegister::Encoded_Reg_##Dst, dwordAddress(T1), \
3964 Immediate(Inst##Imm)); \
3965 \
3966 AssembledTest test = assemble(); \
3967 test.setDqwordTo(T0, V0); \
3968 test.setDqwordTo(T1, V1); \
3969 test.run(); \
3970 \
3971 ASSERT_EQ(Inst##Expected, test.Dst<Dqword>()) << TestString; \
3972 reset(); \
3973 } while (0)
3974
3975 #define TestImplSingleXmmXmmUntyped(Dst, Src, Inst) \
3976 do { \
3977 static constexpr char TestString[] = \
3978 "(" #Dst ", " #Src ", " #Inst ", Untyped)"; \
3979 const uint32_t T0 = allocateDqword(); \
3980 const uint32_t T1 = allocateDqword(); \
3981 \
3982 __ movups(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
3983 __ movups(XmmRegister::Encoded_Reg_##Src, dwordAddress(T1)); \
3984 __ Inst(XmmRegister::Encoded_Reg_##Dst, XmmRegister::Encoded_Reg_##Src, \
3985 Immediate(Inst##Imm)); \
3986 \
3987 AssembledTest test = assemble(); \
3988 test.setDqwordTo(T0, V0); \
3989 test.setDqwordTo(T1, V1); \
3990 test.run(); \
3991 \
3992 ASSERT_EQ(Inst##UntypedExpected, test.Dst<Dqword>()) << TestString; \
3993 reset(); \
3994 } while (0)
3995
3996 #define TestImpl(Dst, Src) \
3997 do { \
3998 TestImplSingleXmmXmm(Dst, Src, pshufd); \
3999 TestImplSingleXmmAddr(Dst, pshufd); \
4000 TestImplSingleXmmXmm(Dst, Src, shufps); \
4001 TestImplSingleXmmAddr(Dst, shufps); \
4002 TestImplSingleXmmXmmUntyped(Dst, Src, shufps); \
4003 TestImplSingleXmmXmmUntyped(Dst, Src, shufpd); \
4004 } while (0)
4005
4006 TestImpl(xmm0, xmm1);
4007 TestImpl(xmm1, xmm2);
4008 TestImpl(xmm2, xmm3);
4009 TestImpl(xmm3, xmm4);
4010 TestImpl(xmm4, xmm5);
4011 TestImpl(xmm5, xmm6);
4012 TestImpl(xmm6, xmm7);
4013 TestImpl(xmm7, xmm0);
4014
4015 #undef TestImpl
4016 #undef TestImplSingleXmmXmmUntyped
4017 #undef TestImplSingleXmmAddr
4018 #undef TestImplSingleXmmXmm
4019 }
4020
4021 TEST_F(AssemblerX8664Test, Cvt) {
4022 const Dqword dq2ps32DstValue(-1.0f, -1.0f, -1.0f, -1.0f);
4023 const Dqword dq2ps32SrcValue(-5, 3, 100, 200);
4024 const Dqword dq2ps32Expected(-5.0f, 3.0f, 100.0, 200.0);
4025
4026 const Dqword dq2ps64DstValue(0.0f, 0.0f, -1.0f, -1.0f);
4027 const Dqword dq2ps64SrcValue(-5, 3, 100, 200);
4028 const Dqword dq2ps64Expected(-5.0f, 3.0f, 100.0, 200.0);
4029
4030 const Dqword tps2dq32DstValue(-1.0f, -1.0f, -1.0f, -1.0f);
4031 const Dqword tps2dq32SrcValue(-5.0f, 3.0f, 100.0, 200.0);
4032 const Dqword tps2dq32Expected(-5, 3, 100, 200);
4033
4034 const Dqword tps2dq64DstValue(-1.0f, -1.0f, -1.0f, -1.0f);
4035 const Dqword tps2dq64SrcValue(-5.0f, 3.0f, 100.0, 200.0);
4036 const Dqword tps2dq64Expected(-5, 3, 100, 200);
4037
4038 const Dqword si2ss32DstValue(-1.0f, -1.0f, -1.0f, -1.0f);
4039 const int32_t si2ss32SrcValue = 5;
4040 const Dqword si2ss32Expected(5.0f, -1.0f, -1.0f, -1.0f);
4041
4042 const Dqword si2ss64DstValue(-1.0, -1.0);
4043 const int32_t si2ss64SrcValue = 5;
4044 const Dqword si2ss64Expected(5.0, -1.0);
4045
4046 const int32_t tss2si32DstValue = 0xF00F0FF0;
4047 const Dqword tss2si32SrcValue(-5.0f, -1.0f, -1.0f, -1.0f);
4048 const int32_t tss2si32Expected = -5;
4049
4050 const int32_t tss2si64DstValue = 0xF00F0FF0;
4051 const Dqword tss2si64SrcValue(-5.0, -1.0);
4052 const int32_t tss2si64Expected = -5;
4053
4054 const Dqword float2float32DstValue(-1.0, -1.0);
4055 const Dqword float2float32SrcValue(-5.0, 3, 100, 200);
4056 const Dqword float2float32Expected(-5.0, -1.0);
4057
4058 const Dqword float2float64DstValue(-1.0, -1.0, -1.0, -1.0);
4059 const Dqword float2float64SrcValue(-5.0, 3.0);
4060 const Dqword float2float64Expected(-5.0, -1.0, -1.0, -1.0);
4061
4062 #define TestImplPXmmXmm(Dst, Src, Inst, Size) \
4063 do { \
4064 static constexpr char TestString[] = \
4065 "(" #Dst ", " #Src ", cvt" #Inst ", f" #Size ")"; \
4066 const uint32_t T0 = allocateDqword(); \
4067 const uint32_t T1 = allocateDqword(); \
4068 \
4069 __ movups(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
4070 __ movups(XmmRegister::Encoded_Reg_##Src, dwordAddress(T1)); \
4071 __ cvt##Inst(IceType_f##Size, XmmRegister::Encoded_Reg_##Dst, \
4072 XmmRegister::Encoded_Reg_##Src); \
4073 \
4074 AssembledTest test = assemble(); \
4075 test.setDqwordTo(T0, Inst##Size##DstValue); \
4076 test.setDqwordTo(T1, Inst##Size##SrcValue); \
4077 test.run(); \
4078 \
4079 ASSERT_EQ(Inst##Size##Expected, test.Dst<Dqword>()) << TestString; \
4080 reset(); \
4081 } while (0)
4082
4083 #define TestImplSXmmReg(Dst, GPR, Inst, Size) \
4084 do { \
4085 static constexpr char TestString[] = \
4086 "(" #Dst ", " #GPR ", cvt" #Inst ", f" #Size ")"; \
4087 const uint32_t T0 = allocateDqword(); \
4088 \
4089 __ movups(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
4090 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##GPR, \
4091 Immediate(Inst##Size##SrcValue)); \
4092 __ cvt##Inst(IceType_f##Size, XmmRegister::Encoded_Reg_##Dst, \
4093 GPRRegister::Encoded_Reg_##GPR); \
4094 \
4095 AssembledTest test = assemble(); \
4096 test.setDqwordTo(T0, Inst##Size##DstValue); \
4097 test.run(); \
4098 \
4099 ASSERT_EQ(Inst##Size##Expected, test.Dst<Dqword>()) << TestString; \
4100 reset(); \
4101 } while (0)
4102
4103 #define TestImplSRegXmm(GPR, Src, Inst, Size) \
4104 do { \
4105 static constexpr char TestString[] = \
4106 "(" #GPR ", " #Src ", cvt" #Inst ", f" #Size ")"; \
4107 const uint32_t T0 = allocateDqword(); \
4108 \
4109 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##GPR, \
4110 Immediate(Inst##Size##DstValue)); \
4111 __ movups(XmmRegister::Encoded_Reg_##Src, dwordAddress(T0)); \
4112 __ cvt##Inst(IceType_f##Size, GPRRegister::Encoded_Reg_##GPR, \
4113 XmmRegister::Encoded_Reg_##Src); \
4114 \
4115 AssembledTest test = assemble(); \
4116 test.setDqwordTo(T0, Inst##Size##SrcValue); \
4117 test.run(); \
4118 \
4119 ASSERT_EQ(static_cast<uint32_t>(Inst##Size##Expected), test.GPR()) \
4120 << TestString; \
4121 reset(); \
4122 } while (0)
4123
4124 #define TestImplPXmmAddr(Dst, Inst, Size) \
4125 do { \
4126 static constexpr char TestString[] = \
4127 "(" #Dst ", Addr, cvt" #Inst ", f" #Size ")"; \
4128 const uint32_t T0 = allocateDqword(); \
4129 const uint32_t T1 = allocateDqword(); \
4130 \
4131 __ movups(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
4132 __ cvt##Inst(IceType_f##Size, XmmRegister::Encoded_Reg_##Dst, \
4133 dwordAddress(T1)); \
4134 \
4135 AssembledTest test = assemble(); \
4136 test.setDqwordTo(T0, Inst##Size##DstValue); \
4137 test.setDqwordTo(T1, Inst##Size##SrcValue); \
4138 test.run(); \
4139 \
4140 ASSERT_EQ(Inst##Size##Expected, test.Dst<Dqword>()) << TestString; \
4141 reset(); \
4142 } while (0)
4143
4144 #define TestImplSXmmAddr(Dst, Inst, Size) \
4145 do { \
4146 static constexpr char TestString[] = \
4147 "(" #Dst ", Addr, cvt" #Inst ", f" #Size ")"; \
4148 const uint32_t T0 = allocateDqword(); \
4149 const uint32_t T1 = allocateDword(); \
4150 \
4151 __ movups(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
4152 __ cvt##Inst(IceType_f##Size, XmmRegister::Encoded_Reg_##Dst, \
4153 dwordAddress(T1)); \
4154 \
4155 AssembledTest test = assemble(); \
4156 test.setDqwordTo(T0, Inst##Size##DstValue); \
4157 test.setDwordTo(T1, Inst##Size##SrcValue); \
4158 test.run(); \
4159 \
4160 ASSERT_EQ(Inst##Size##Expected, test.Dst<Dqword>()) << TestString; \
4161 reset(); \
4162 } while (0)
4163
4164 #define TestImplSRegAddr(GPR, Inst, Size) \
4165 do { \
4166 static constexpr char TestString[] = \
4167 "(" #GPR ", Addr, cvt" #Inst ", f" #Size ")"; \
4168 const uint32_t T0 = allocateDqword(); \
4169 \
4170 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##GPR, \
4171 Immediate(Inst##Size##DstValue)); \
4172 __ cvt##Inst(IceType_f##Size, GPRRegister::Encoded_Reg_##GPR, \
4173 dwordAddress(T0)); \
4174 \
4175 AssembledTest test = assemble(); \
4176 test.setDqwordTo(T0, Inst##Size##SrcValue); \
4177 test.run(); \
4178 \
4179 ASSERT_EQ(static_cast<uint32_t>(Inst##Size##Expected), test.GPR()) \
4180 << TestString; \
4181 reset(); \
4182 } while (0)
4183
4184 #define TestImplSize(Dst, Src, GPR, Size) \
4185 do { \
4186 TestImplPXmmXmm(Dst, Src, dq2ps, Size); \
4187 TestImplPXmmAddr(Src, dq2ps, Size); \
4188 TestImplPXmmXmm(Dst, Src, tps2dq, Size); \
4189 TestImplPXmmAddr(Src, tps2dq, Size); \
4190 TestImplSXmmReg(Dst, GPR, si2ss, Size); \
4191 TestImplSXmmAddr(Dst, si2ss, Size); \
4192 TestImplSRegXmm(GPR, Src, tss2si, Size); \
4193 TestImplSRegAddr(GPR, tss2si, Size); \
4194 TestImplPXmmXmm(Dst, Src, float2float, Size); \
4195 TestImplPXmmAddr(Src, float2float, Size); \
4196 } while (0)
4197
4198 #define TestImpl(Dst, Src, GPR) \
4199 do { \
4200 TestImplSize(Dst, Src, GPR, 32); \
4201 TestImplSize(Dst, Src, GPR, 64); \
4202 } while (0)
4203
4204 TestImpl(xmm0, xmm1, eax);
4205 TestImpl(xmm1, xmm2, ebx);
4206 TestImpl(xmm2, xmm3, ecx);
4207 TestImpl(xmm3, xmm4, edx);
4208 TestImpl(xmm4, xmm5, esi);
4209 TestImpl(xmm5, xmm6, edi);
4210 TestImpl(xmm6, xmm7, eax);
4211 TestImpl(xmm7, xmm0, ebx);
4212
4213 #undef TestImpl
4214 #undef TestImplSize
4215 #undef TestImplSRegAddr
4216 #undef TestImplSXmmAddr
4217 #undef TestImplPXmmAddr
4218 #undef TestImplSRegXmm
4219 #undef TestImplSXmmReg
4220 #undef TestImplPXmmXmm
4221 }
4222
4223 TEST_F(AssemblerX8664Test, Ucomiss) {
4224 static constexpr float qnan32 = std::numeric_limits<float>::quiet_NaN();
4225 static constexpr double qnan64 = std::numeric_limits<float>::quiet_NaN();
4226
4227 Dqword test32DstValue(0.0, qnan32, qnan32, qnan32);
4228 Dqword test32SrcValue(0.0, qnan32, qnan32, qnan32);
4229
4230 Dqword test64DstValue(0.0, qnan64);
4231 Dqword test64SrcValue(0.0, qnan64);
4232
4233 #define TestImplXmmXmm(Dst, Value0, Src, Value1, Size, CompType, BParity, \
4234 BOther) \
4235 do { \
4236 static constexpr char NearBranch = AssemblerX8664::kNearJump; \
4237 static constexpr char TestString[] = \
4238 "(" #Dst ", " #Value0 ", " #Src ", " #Value1 ", " #Size ", " #CompType \
4239 ", " #BParity ", " #BOther ")"; \
4240 const uint32_t T0 = allocateDqword(); \
4241 test##Size##DstValue.F##Size[0] = Value0; \
4242 const uint32_t T1 = allocateDqword(); \
4243 test##Size##SrcValue.F##Size[0] = Value1; \
4244 const uint32_t ImmIfTrue = 0xBEEF; \
4245 const uint32_t ImmIfFalse = 0xC0FFE; \
4246 \
4247 __ movups(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
4248 __ movups(XmmRegister::Encoded_Reg_##Src, dwordAddress(T1)); \
4249 __ mov(IceType_i32, GPRRegister::Encoded_Reg_eax, Immediate(ImmIfFalse)); \
4250 __ ucomiss(IceType_f##Size, XmmRegister::Encoded_Reg_##Dst, \
4251 XmmRegister::Encoded_Reg_##Src); \
4252 Label Done; \
4253 __ j(Cond::Br_##BParity, &Done, NearBranch); \
4254 __ j(Cond::Br_##BOther, &Done, NearBranch); \
4255 __ mov(IceType_i32, GPRRegister::Encoded_Reg_eax, Immediate(ImmIfTrue)); \
4256 __ bind(&Done); \
4257 \
4258 AssembledTest test = assemble(); \
4259 test.setDqwordTo(T0, test##Size##DstValue); \
4260 test.setDqwordTo(T1, test##Size##SrcValue); \
4261 test.run(); \
4262 \
4263 ASSERT_EQ(ImmIfTrue, test.eax()) << TestString; \
4264 reset(); \
4265 } while (0)
4266
4267 #define TestImplXmmAddr(Dst, Value0, Value1, Size, CompType, BParity, BOther) \
4268 do { \
4269 static constexpr char NearBranch = AssemblerX8664::kNearJump; \
4270 static constexpr char TestString[] = \
4271 "(" #Dst ", " #Value0 ", Addr, " #Value1 ", " #Size ", " #CompType \
4272 ", " #BParity ", " #BOther ")"; \
4273 const uint32_t T0 = allocateDqword(); \
4274 test##Size##DstValue.F##Size[0] = Value0; \
4275 const uint32_t T1 = allocateDqword(); \
4276 test##Size##SrcValue.F##Size[0] = Value1; \
4277 const uint32_t ImmIfTrue = 0xBEEF; \
4278 const uint32_t ImmIfFalse = 0xC0FFE; \
4279 \
4280 __ movups(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
4281 __ mov(IceType_i32, GPRRegister::Encoded_Reg_eax, Immediate(ImmIfFalse)); \
4282 __ ucomiss(IceType_f##Size, XmmRegister::Encoded_Reg_##Dst, \
4283 dwordAddress(T1)); \
4284 Label Done; \
4285 __ j(Cond::Br_##BParity, &Done, NearBranch); \
4286 __ j(Cond::Br_##BOther, &Done, NearBranch); \
4287 __ mov(IceType_i32, GPRRegister::Encoded_Reg_eax, Immediate(ImmIfTrue)); \
4288 __ bind(&Done); \
4289 \
4290 AssembledTest test = assemble(); \
4291 test.setDqwordTo(T0, test##Size##DstValue); \
4292 test.setDqwordTo(T1, test##Size##SrcValue); \
4293 test.run(); \
4294 \
4295 ASSERT_EQ(ImmIfTrue, test.eax()) << TestString; \
4296 reset(); \
4297 } while (0)
4298
4299 #define TestImplCond(Dst, Value0, Src, Value1, Size, CompType, BParity, \
4300 BOther) \
4301 do { \
4302 TestImplXmmXmm(Dst, Value0, Src, Value1, Size, CompType, BParity, BOther); \
4303 TestImplXmmAddr(Dst, Value0, Value1, Size, CompType, BParity, BOther); \
4304 } while (0)
4305
4306 #define TestImplSize(Dst, Src, Size) \
4307 do { \
4308 TestImplCond(Dst, 1.0, Src, 1.0, Size, isEq, p, ne); \
4309 TestImplCond(Dst, 1.0, Src, 2.0, Size, isNe, p, e); \
4310 TestImplCond(Dst, 1.0, Src, 2.0, Size, isLe, p, a); \
4311 TestImplCond(Dst, 1.0, Src, 1.0, Size, isLe, p, a); \
4312 TestImplCond(Dst, 1.0, Src, 2.0, Size, isLt, p, ae); \
4313 TestImplCond(Dst, 2.0, Src, 1.0, Size, isGe, p, b); \
4314 TestImplCond(Dst, 1.0, Src, 1.0, Size, isGe, p, b); \
4315 TestImplCond(Dst, 2.0, Src, 1.0, Size, isGt, p, be); \
4316 TestImplCond(Dst, qnan##Size, Src, 1.0, Size, isUnord, np, o); \
4317 TestImplCond(Dst, 1.0, Src, qnan##Size, Size, isUnord, np, s); \
4318 TestImplCond(Dst, qnan##Size, Src, qnan##Size, Size, isUnord, np, s); \
4319 } while (0)
4320
4321 #define TestImpl(Dst, Src) \
4322 do { \
4323 TestImplSize(Dst, Src, 32); \
4324 TestImplSize(Dst, Src, 64); \
4325 } while (0)
4326
4327 TestImpl(xmm0, xmm1);
4328 TestImpl(xmm1, xmm2);
4329 TestImpl(xmm2, xmm3);
4330 TestImpl(xmm3, xmm4);
4331 TestImpl(xmm4, xmm5);
4332 TestImpl(xmm5, xmm6);
4333 TestImpl(xmm6, xmm7);
4334 TestImpl(xmm7, xmm0);
4335
4336 #undef TestImpl
4337 #undef TestImplSize
4338 #undef TestImplCond
4339 #undef TestImplXmmAddr
4340 #undef TestImplXmmXmm
4341 }
4342
4343 TEST_F(AssemblerX8664Test, Movmsk) {
4344 #define TestMovmskGPRXmm(GPR, Src, Value1, Expected, Inst) \
4345 do { \
4346 static constexpr char TestString[] = \
4347 "(" #GPR ", " #Src ", " #Value1 ", " #Expected ", " #Inst ")"; \
4348 const uint32_t T0 = allocateDqword(); \
4349 const Dqword V0 Value1; \
4350 \
4351 __ movups(XmmRegister::Encoded_Reg_##Src, dwordAddress(T0)); \
4352 __ Inst(GPRRegister::Encoded_Reg_##GPR, XmmRegister::Encoded_Reg_##Src); \
4353 \
4354 AssembledTest test = assemble(); \
4355 test.setDqwordTo(T0, V0); \
4356 test.run(); \
4357 \
4358 ASSERT_EQ(Expected, test.GPR()) << TestString; \
4359 reset(); \
4360 } while (0)
4361
4362 #define TestMovmsk(GPR, Src) \
4363 do { \
4364 TestMovmskGPRXmm(GPR, Src, (-1.0, 1.0, -1.0, 1.0), 0x05ul, movmskps); \
4365 TestMovmskGPRXmm(GPR, Src, (1.0, -1.0), 0x02ul, movmskpd); \
4366 } while (0)
4367
4368 TestMovmsk(eax, xmm0);
4369 TestMovmsk(ebx, xmm1);
4370 TestMovmsk(ecx, xmm2);
4371 TestMovmsk(edx, xmm3);
4372 TestMovmsk(esi, xmm4);
4373 TestMovmsk(edi, xmm5);
4374 TestMovmsk(eax, xmm6);
4375 TestMovmsk(ebx, xmm7);
4376
4377 #undef TestMovmskGPRXmm
4378 #undef TestMovmsk
4379 }
4380
4381 TEST_F(AssemblerX8664Test, Sqrtss) {
4382 Dqword test32SrcValue(-100.0, -100.0, -100.0, -100.0);
4383 Dqword test32DstValue(-1.0, -1.0, -1.0, -1.0);
4384
4385 Dqword test64SrcValue(-100.0, -100.0);
4386 Dqword test64DstValue(-1.0, -1.0);
4387
4388 #define TestSqrtssXmmXmm(Dst, Src, Value1, Result, Size) \
4389 do { \
4390 static constexpr char TestString[] = \
4391 "(" #Dst ", " #Src ", " #Value1 ", " #Result ", " #Size ")"; \
4392 const uint32_t T0 = allocateDqword(); \
4393 test##Size##SrcValue.F##Size[0] = Value1; \
4394 const uint32_t T1 = allocateDqword(); \
4395 \
4396 __ movups(XmmRegister::Encoded_Reg_##Src, dwordAddress(T0)); \
4397 __ movups(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T1)); \
4398 __ sqrtss(IceType_f##Size, XmmRegister::Encoded_Reg_##Dst, \
4399 XmmRegister::Encoded_Reg_##Src); \
4400 \
4401 AssembledTest test = assemble(); \
4402 test.setDqwordTo(T0, test##Size##SrcValue); \
4403 test.setDqwordTo(T1, test##Size##DstValue); \
4404 test.run(); \
4405 \
4406 Dqword Expected = test##Size##DstValue; \
4407 Expected.F##Size[0] = Result; \
4408 ASSERT_EQ(Expected, test.Dst<Dqword>()) << TestString; \
4409 reset(); \
4410 } while (0)
4411
4412 #define TestSqrtssXmmAddr(Dst, Value1, Result, Size) \
4413 do { \
4414 static constexpr char TestString[] = \
4415 "(" #Dst ", Addr, " #Value1 ", " #Result ", " #Size ")"; \
4416 const uint32_t T0 = allocateDqword(); \
4417 test##Size##SrcValue.F##Size[0] = Value1; \
4418 const uint32_t T1 = allocateDqword(); \
4419 \
4420 __ movups(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T1)); \
4421 __ sqrtss(IceType_f##Size, XmmRegister::Encoded_Reg_##Dst, \
4422 dwordAddress(T0)); \
4423 \
4424 AssembledTest test = assemble(); \
4425 test.setDqwordTo(T0, test##Size##SrcValue); \
4426 test.setDqwordTo(T1, test##Size##DstValue); \
4427 test.run(); \
4428 \
4429 Dqword Expected = test##Size##DstValue; \
4430 Expected.F##Size[0] = Result; \
4431 ASSERT_EQ(Expected, test.Dst<Dqword>()) << TestString; \
4432 reset(); \
4433 } while (0)
4434
4435 #define TestSqrtssSize(Dst, Src, Size) \
4436 do { \
4437 TestSqrtssXmmXmm(Dst, Src, 4.0, 2.0, Size); \
4438 TestSqrtssXmmAddr(Dst, 4.0, 2.0, Size); \
4439 TestSqrtssXmmXmm(Dst, Src, 9.0, 3.0, Size); \
4440 TestSqrtssXmmAddr(Dst, 9.0, 3.0, Size); \
4441 TestSqrtssXmmXmm(Dst, Src, 100.0, 10.0, Size); \
4442 TestSqrtssXmmAddr(Dst, 100.0, 10.0, Size); \
4443 }
4444
4445 #define TestSqrtss(Dst, Src) \
4446 do { \
4447 TestSqrtssSizeS(Dst, Src, 32); \
4448 TestSqrtssSizeS(Dst, Src, 64); \
4449 } while (0)
4450
4451 #undef TestSqrtss
4452 #undef TestSqrtssSize
4453 #undef TestSqrtssXmmAddr
4454 #undef TestSqrtssXmmXmm
4455 }
4456
4457 TEST_F(AssemblerX8664Test, Insertps) {
4458 #define TestInsertpsXmmXmmImm(Dst, Value0, Src, Value1, Imm, Expected) \
4459 do { \
4460 static constexpr char TestString[] = \
4461 "(" #Dst ", " #Value0 ", " #Src ", " #Value1 ", " #Imm ", " #Expected \
4462 ")"; \
4463 const uint32_t T0 = allocateDqword(); \
4464 const Dqword V0 Value0; \
4465 const uint32_t T1 = allocateDqword(); \
4466 const Dqword V1 Value1; \
4467 \
4468 __ movups(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
4469 __ movups(XmmRegister::Encoded_Reg_##Src, dwordAddress(T1)); \
4470 __ insertps(IceType_v4f32, XmmRegister::Encoded_Reg_##Dst, \
4471 XmmRegister::Encoded_Reg_##Src, Immediate(Imm)); \
4472 \
4473 AssembledTest test = assemble(); \
4474 test.setDqwordTo(T0, V0); \
4475 test.setDqwordTo(T1, V1); \
4476 test.run(); \
4477 \
4478 ASSERT_EQ(Dqword Expected, test.Dst<Dqword>()) << TestString; \
4479 reset(); \
4480 } while (0)
4481
4482 #define TestInsertpsXmmAddrImm(Dst, Value0, Value1, Imm, Expected) \
4483 do { \
4484 static constexpr char TestString[] = \
4485 "(" #Dst ", " #Value0 ", Addr, " #Value1 ", " #Imm ", " #Expected ")"; \
4486 const uint32_t T0 = allocateDqword(); \
4487 const Dqword V0 Value0; \
4488 const uint32_t T1 = allocateDqword(); \
4489 const Dqword V1 Value1; \
4490 \
4491 __ movups(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
4492 __ insertps(IceType_v4f32, XmmRegister::Encoded_Reg_##Dst, \
4493 dwordAddress(T1), Immediate(Imm)); \
4494 \
4495 AssembledTest test = assemble(); \
4496 test.setDqwordTo(T0, V0); \
4497 test.setDqwordTo(T1, V1); \
4498 test.run(); \
4499 \
4500 ASSERT_EQ(Dqword Expected, test.Dst<Dqword>()) << TestString; \
4501 reset(); \
4502 } while (0)
4503
4504 #define TestInsertps(Dst, Src) \
4505 do { \
4506 TestInsertpsXmmXmmImm( \
4507 Dst, (uint64_t(-1), uint64_t(-1)), Src, \
4508 (uint64_t(0xAAAAAAAABBBBBBBBull), uint64_t(0xCCCCCCCCDDDDDDDDull)), \
4509 0x99, \
4510 (uint64_t(0xDDDDDDDD00000000ull), uint64_t(0x00000000FFFFFFFFull))); \
4511 TestInsertpsXmmAddrImm( \
4512 Dst, (uint64_t(-1), uint64_t(-1)), \
4513 (uint64_t(0xAAAAAAAABBBBBBBBull), uint64_t(0xCCCCCCCCDDDDDDDDull)), \
4514 0x99, \
4515 (uint64_t(0xBBBBBBBB00000000ull), uint64_t(0x00000000FFFFFFFFull))); \
4516 TestInsertpsXmmXmmImm( \
4517 Dst, (uint64_t(-1), uint64_t(-1)), Src, \
4518 (uint64_t(0xAAAAAAAABBBBBBBBull), uint64_t(0xCCCCCCCCDDDDDDDDull)), \
4519 0x9D, \
4520 (uint64_t(0xDDDDDDDD00000000ull), uint64_t(0x0000000000000000ull))); \
4521 TestInsertpsXmmAddrImm( \
4522 Dst, (uint64_t(-1), uint64_t(-1)), \
4523 (uint64_t(0xAAAAAAAABBBBBBBBull), uint64_t(0xCCCCCCCCDDDDDDDDull)), \
4524 0x9D, \
4525 (uint64_t(0xBBBBBBBB00000000ull), uint64_t(0x0000000000000000ull))); \
4526 } while (0)
4527
4528 TestInsertps(xmm0, xmm1);
4529
4530 #undef TestInsertps
4531 #undef TestInsertpsXmmXmmAddr
4532 #undef TestInsertpsXmmXmmImm
4533 }
4534
4535 TEST_F(AssemblerX8664Test, Pinsr) {
4536 static constexpr uint8_t Mask32 = 0x03;
4537 static constexpr uint8_t Mask16 = 0x07;
4538 static constexpr uint8_t Mask8 = 0x0F;
4539
4540 #define TestPinsrXmmGPRImm(Dst, Value0, GPR, Value1, Imm, Size) \
4541 do { \
4542 static constexpr char TestString[] = \
4543 "(" #Dst ", " #Value0 ", " #GPR ", " #Value1 ", " #Imm ", " #Size ")"; \
4544 const uint32_t T0 = allocateDqword(); \
4545 const Dqword V0 Value0; \
4546 \
4547 __ movups(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
4548 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##GPR, Immediate(Value1)); \
4549 __ pinsr(IceType_i##Size, XmmRegister::Encoded_Reg_##Dst, \
4550 GPRRegister::Encoded_Reg_##GPR, Immediate(Imm)); \
4551 \
4552 AssembledTest test = assemble(); \
4553 test.setDqwordTo(T0, V0); \
4554 test.run(); \
4555 \
4556 constexpr uint8_t sel = (Imm)&Mask##Size; \
4557 Dqword Expected = V0; \
4558 Expected.U##Size[sel] = Value1; \
4559 ASSERT_EQ(Expected, test.Dst<Dqword>()) << TestString; \
4560 reset(); \
4561 } while (0)
4562
4563 #define TestPinsrXmmAddrImm(Dst, Value0, Value1, Imm, Size) \
4564 do { \
4565 static constexpr char TestString[] = \
4566 "(" #Dst ", " #Value0 ", Addr, " #Value1 ", " #Imm ", " #Size ")"; \
4567 const uint32_t T0 = allocateDqword(); \
4568 const Dqword V0 Value0; \
4569 const uint32_t T1 = allocateDword(); \
4570 const uint32_t V1 = Value1; \
4571 \
4572 __ movups(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
4573 __ pinsr(IceType_i##Size, XmmRegister::Encoded_Reg_##Dst, \
4574 dwordAddress(T1), Immediate(Imm)); \
4575 \
4576 AssembledTest test = assemble(); \
4577 test.setDqwordTo(T0, V0); \
4578 test.setDwordTo(T1, V1); \
4579 test.run(); \
4580 \
4581 constexpr uint8_t sel = (Imm)&Mask##Size; \
4582 Dqword Expected = V0; \
4583 Expected.U##Size[sel] = Value1; \
4584 ASSERT_EQ(Expected, test.Dst<Dqword>()) << TestString; \
4585 reset(); \
4586 } while (0)
4587
4588 #define TestPinsrSize(Dst, GPR, Value1, Imm, Size) \
4589 do { \
4590 TestPinsrXmmGPRImm(Dst, (uint64_t(0xAAAAAAAABBBBBBBBull), \
4591 uint64_t(0xFFFFFFFFDDDDDDDDull)), \
4592 GPR, Value1, Imm, Size); \
4593 TestPinsrXmmAddrImm(Dst, (uint64_t(0xAAAAAAAABBBBBBBBull), \
4594 uint64_t(0xFFFFFFFFDDDDDDDDull)), \
4595 Value1, Imm, Size); \
4596 } while (0)
4597
4598 #define TestPinsr(Src, Dst) \
4599 do { \
4600 TestPinsrSize(Src, Dst, 0xEE, 0x03, 8); \
4601 TestPinsrSize(Src, Dst, 0xFFEE, 0x03, 16); \
4602 TestPinsrSize(Src, Dst, 0xC0FFEE, 0x03, 32); \
4603 } while (0)
4604
4605 TestPinsr(xmm0, eax);
4606 TestPinsr(xmm1, ebx);
4607 TestPinsr(xmm2, ecx);
4608 TestPinsr(xmm3, edx);
4609 TestPinsr(xmm4, esi);
4610 TestPinsr(xmm5, edi);
4611 TestPinsr(xmm6, eax);
4612 TestPinsr(xmm7, ebx);
4613
4614 #undef TestPinsr
4615 #undef TestPinsrSize
4616 #undef TestPinsrXmmAddrImm
4617 #undef TestPinsrXmmGPRImm
4618 }
4619
4620 TEST_F(AssemblerX8664Test, Pextr) {
4621 static constexpr uint8_t Mask32 = 0x03;
4622 static constexpr uint8_t Mask16 = 0x07;
4623 static constexpr uint8_t Mask8 = 0x0F;
4624
4625 #define TestPextrGPRXmmImm(GPR, Src, Value1, Imm, Size) \
4626 do { \
4627 static constexpr char TestString[] = \
4628 "(" #GPR ", " #Src ", " #Value1 ", " #Imm ", " #Size ")"; \
4629 const uint32_t T0 = allocateDqword(); \
4630 const Dqword V0 Value1; \
4631 \
4632 __ movups(XmmRegister::Encoded_Reg_##Src, dwordAddress(T0)); \
4633 __ pextr(IceType_i##Size, GPRRegister::Encoded_Reg_##GPR, \
4634 XmmRegister::Encoded_Reg_##Src, Immediate(Imm)); \
4635 \
4636 AssembledTest test = assemble(); \
4637 test.setDqwordTo(T0, V0); \
4638 test.run(); \
4639 \
4640 constexpr uint8_t sel = (Imm)&Mask##Size; \
4641 ASSERT_EQ(V0.U##Size[sel], test.GPR()) << TestString; \
4642 reset(); \
4643 } while (0)
4644
4645 #define TestPextrSize(GPR, Src, Value1, Imm, Size) \
4646 do { \
4647 TestPextrGPRXmmImm(GPR, Src, (uint64_t(0xAAAAAAAABBBBBBBBull), \
4648 uint64_t(0xFFFFFFFFDDDDDDDDull)), \
4649 Imm, Size); \
4650 } while (0)
4651
4652 #define TestPextr(Src, Dst) \
4653 do { \
4654 TestPextrSize(Src, Dst, 0xEE, 0x03, 8); \
4655 TestPextrSize(Src, Dst, 0xFFEE, 0x03, 16); \
4656 TestPextrSize(Src, Dst, 0xC0FFEE, 0x03, 32); \
4657 } while (0)
4658
4659 TestPextr(eax, xmm0);
4660 TestPextr(ebx, xmm1);
4661 TestPextr(ecx, xmm2);
4662 TestPextr(edx, xmm3);
4663 TestPextr(esi, xmm4);
4664 TestPextr(edi, xmm5);
4665 TestPextr(eax, xmm6);
4666 TestPextr(ebx, xmm7);
4667
4668 #undef TestPextr
4669 #undef TestPextrSize
4670 #undef TestPextrXmmGPRImm
4671 }
4672
4673 TEST_F(AssemblerX8664Test, Pmovsxdq) {
4674 #define TestPmovsxdqXmmXmm(Dst, Src, Value1) \
4675 do { \
4676 static constexpr char TestString[] = "(" #Dst ", " #Src ", " #Value1 ")"; \
4677 const uint32_t T0 = allocateDqword(); \
4678 const Dqword V0 Value1; \
4679 const uint32_t T1 = allocateDqword(); \
4680 const Dqword V1(uint64_t(0), uint64_t(0)); \
4681 \
4682 __ movups(XmmRegister::Encoded_Reg_##Src, dwordAddress(T0)); \
4683 __ movups(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T1)); \
4684 __ pmovsxdq(XmmRegister::Encoded_Reg_##Dst, \
4685 XmmRegister::Encoded_Reg_##Src); \
4686 \
4687 AssembledTest test = assemble(); \
4688 test.setDqwordTo(T0, V0); \
4689 test.setDqwordTo(T1, V1); \
4690 test.run(); \
4691 \
4692 const Dqword Expected(uint64_t(V0.I32[0]), uint64_t(V0.I32[1])); \
4693 ASSERT_EQ(Expected, test.Dst<Dqword>()) << TestString; \
4694 reset(); \
4695 } while (0)
4696
4697 #define TestPmovsxdq(Dst, Src) \
4698 do { \
4699 TestPmovsxdqXmmXmm(Dst, Src, (uint64_t(0x700000007FFFFFFFull), \
4700 uint64_t(0xAAAAAAAAEEEEEEEEull))); \
4701 TestPmovsxdqXmmXmm(Dst, Src, (uint64_t(0x800000007FFFFFFFull), \
4702 uint64_t(0xAAAAAAAAEEEEEEEEull))); \
4703 TestPmovsxdqXmmXmm(Dst, Src, (uint64_t(0x70000000FFFFFFFFull), \
4704 uint64_t(0xAAAAAAAAEEEEEEEEull))); \
4705 TestPmovsxdqXmmXmm(Dst, Src, (uint64_t(0x80000000FFFFFFFFull), \
4706 uint64_t(0xAAAAAAAAEEEEEEEEull))); \
4707 } while (0)
4708
4709 TestPmovsxdq(xmm0, xmm1);
4710 TestPmovsxdq(xmm1, xmm2);
4711 TestPmovsxdq(xmm2, xmm3);
4712 TestPmovsxdq(xmm3, xmm4);
4713 TestPmovsxdq(xmm4, xmm5);
4714 TestPmovsxdq(xmm5, xmm6);
4715 TestPmovsxdq(xmm6, xmm7);
4716 TestPmovsxdq(xmm7, xmm0);
4717
4718 #undef TestPmovsxdq
4719 #undef TestPmovsxdqXmmXmm
4720 }
4721
4722 TEST_F(AssemblerX8664Test, Pcmpeq_Pcmpgt) {
4723 #define TestPcmpXmmXmm(Dst, Value0, Src, Value1, Size, Inst, Op) \
4724 do { \
4725 static constexpr char TestString[] = \
4726 "(" #Dst ", " #Value0 ", " #Src ", " #Value1 ", " #Size ", " #Op ")"; \
4727 const uint32_t T0 = allocateDqword(); \
4728 const Dqword V0 Value0; \
4729 const uint32_t T1 = allocateDqword(); \
4730 const Dqword V1 Value1; \
4731 \
4732 __ movups(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
4733 __ movups(XmmRegister::Encoded_Reg_##Src, dwordAddress(T1)); \
4734 __ Inst(IceType_i##Size, XmmRegister::Encoded_Reg_##Dst, \
4735 XmmRegister::Encoded_Reg_##Src); \
4736 \
4737 AssembledTest test = assemble(); \
4738 test.setDqwordTo(T0, V0); \
4739 test.setDqwordTo(T1, V1); \
4740 test.run(); \
4741 \
4742 Dqword Expected(uint64_t(0), uint64_t(0)); \
4743 static constexpr uint8_t ArraySize = \
4744 sizeof(Dqword) / sizeof(uint##Size##_t); \
4745 for (uint8_t i = 0; i < ArraySize; ++i) { \
4746 Expected.I##Size[i] = (V1.I##Size[i] Op V0.I##Size[i]) ? -1 : 0; \
4747 } \
4748 ASSERT_EQ(Expected, test.Dst<Dqword>()) << TestString; \
4749 reset(); \
4750 } while (0)
4751
4752 #define TestPcmpXmmAddr(Dst, Value0, Value1, Size, Inst, Op) \
4753 do { \
4754 static constexpr char TestString[] = \
4755 "(" #Dst ", " #Value0 ", Addr, " #Value1 ", " #Size ", " #Op ")"; \
4756 const uint32_t T0 = allocateDqword(); \
4757 const Dqword V0 Value0; \
4758 const uint32_t T1 = allocateDqword(); \
4759 const Dqword V1 Value1; \
4760 \
4761 __ movups(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
4762 __ Inst(IceType_i##Size, XmmRegister::Encoded_Reg_##Dst, \
4763 dwordAddress(T1)); \
4764 \
4765 AssembledTest test = assemble(); \
4766 test.setDqwordTo(T0, V0); \
4767 test.setDqwordTo(T1, V1); \
4768 test.run(); \
4769 \
4770 Dqword Expected(uint64_t(0), uint64_t(0)); \
4771 static constexpr uint8_t ArraySize = \
4772 sizeof(Dqword) / sizeof(uint##Size##_t); \
4773 for (uint8_t i = 0; i < ArraySize; ++i) { \
4774 Expected.I##Size[i] = (V1.I##Size[i] Op V0.I##Size[i]) ? -1 : 0; \
4775 } \
4776 ASSERT_EQ(Expected, test.Dst<Dqword>()) << TestString; \
4777 reset(); \
4778 } while (0)
4779
4780 #define TestPcmpValues(Dst, Value0, Src, Value1, Size) \
4781 do { \
4782 TestPcmpXmmXmm(Dst, Value0, Src, Value1, Size, pcmpeq, == ); \
4783 TestPcmpXmmAddr(Dst, Value0, Value1, Size, pcmpeq, == ); \
4784 TestPcmpXmmXmm(Dst, Value0, Src, Value1, Size, pcmpgt, < ); \
4785 TestPcmpXmmAddr(Dst, Value0, Value1, Size, pcmpgt, < ); \
4786 } while (0)
4787
4788 #define TestPcmpSize(Dst, Src, Size) \
4789 do { \
4790 TestPcmpValues(Dst, (uint64_t(0x8888888888888888ull), \
4791 uint64_t(0x0000000000000000ull)), \
4792 Src, (uint64_t(0x0000008800008800ull), \
4793 uint64_t(0xFFFFFFFFFFFFFFFFull)), \
4794 Size); \
4795 TestPcmpValues(Dst, (uint64_t(0x123567ABAB55DE01ull), \
4796 uint64_t(0x12345abcde12345Aull)), \
4797 Src, (uint64_t(0x0000008800008800ull), \
4798 uint64_t(0xAABBCCDD1234321Aull)), \
4799 Size); \
4800 } while (0)
4801
4802 #define TestPcmp(Dst, Src) \
4803 do { \
4804 TestPcmpSize(xmm0, xmm1, 8); \
4805 TestPcmpSize(xmm0, xmm1, 16); \
4806 TestPcmpSize(xmm0, xmm1, 32); \
4807 } while (0)
4808
4809 TestPcmp(xmm0, xmm1);
4810 TestPcmp(xmm1, xmm2);
4811 TestPcmp(xmm2, xmm3);
4812 TestPcmp(xmm3, xmm4);
4813 TestPcmp(xmm4, xmm5);
4814 TestPcmp(xmm5, xmm6);
4815 TestPcmp(xmm6, xmm7);
4816 TestPcmp(xmm7, xmm0);
4817
4818 #undef TestPcmp
4819 #undef TestPcmpSize
4820 #undef TestPcmpValues
4821 #undef TestPcmpXmmAddr
4822 #undef TestPcmpXmmXmm
4823 }
4824
4825 TEST_F(AssemblerX8664Test, Roundsd) {
4826 #define TestRoundsdXmmXmm(Dst, Src, Mode, Input, RN) \
4827 do { \
4828 static constexpr char TestString[] = \
4829 "(" #Dst ", " #Src ", " #Mode ", " #Input ", " #RN ")"; \
4830 const uint32_t T0 = allocateDqword(); \
4831 const Dqword V0(-3.0, -3.0); \
4832 const uint32_t T1 = allocateDqword(); \
4833 const Dqword V1(double(Input), -123.4); \
4834 \
4835 __ movups(XmmRegister::Encoded_Reg_##Dst, dwordAddress(T0)); \
4836 __ movups(XmmRegister::Encoded_Reg_##Src, dwordAddress(T1)); \
4837 __ roundsd(XmmRegister::Encoded_Reg_##Dst, XmmRegister::Encoded_Reg_##Src, \
4838 AssemblerX8664::k##Mode); \
4839 \
4840 AssembledTest test = assemble(); \
4841 test.setDqwordTo(T0, V0); \
4842 test.setDqwordTo(T1, V1); \
4843 test.run(); \
4844 \
4845 const Dqword Expected(double(RN), -3.0); \
4846 EXPECT_EQ(Expected, test.Dst<Dqword>()) << TestString; \
4847 reset(); \
4848 } while (0)
4849
4850 #define TestRoundsd(Dst, Src) \
4851 do { \
4852 TestRoundsdXmmXmm(Dst, Src, RoundToNearest, 5.51, 6); \
4853 TestRoundsdXmmXmm(Dst, Src, RoundToNearest, 5.49, 5); \
4854 TestRoundsdXmmXmm(Dst, Src, RoundDown, 5.51, 5); \
4855 TestRoundsdXmmXmm(Dst, Src, RoundUp, 5.49, 6); \
4856 TestRoundsdXmmXmm(Dst, Src, RoundToZero, 5.49, 5); \
4857 TestRoundsdXmmXmm(Dst, Src, RoundToZero, 5.51, 5); \
4858 } while (0)
4859
4860 TestRoundsd(xmm0, xmm1);
4861 TestRoundsd(xmm1, xmm2);
4862 TestRoundsd(xmm2, xmm3);
4863 TestRoundsd(xmm3, xmm4);
4864 TestRoundsd(xmm4, xmm5);
4865 TestRoundsd(xmm5, xmm6);
4866 TestRoundsd(xmm6, xmm7);
4867 TestRoundsd(xmm7, xmm0);
4868
4869 #undef TestRoundsd
4870 #undef TestRoundsdXmmXmm
4871 }
4872
4873 TEST_F(AssemblerX8664Test, Test) {
4874 static constexpr uint32_t Mask8 = 0xFF;
4875 static constexpr uint32_t Mask16 = 0xFFFF;
4876 static constexpr uint32_t Mask32 = 0xFFFFFFFF;
4877
4878 #define TestImplRegReg(Dst, Value0, Src, Value1, Size) \
4879 do { \
4880 static constexpr bool NearJump = true; \
4881 static constexpr char TestString[] = \
4882 "(" #Dst ", " #Value0 ", " #Src ", " #Value1 ", " #Size ")"; \
4883 static constexpr uint32_t ValueIfTrue = 0xBEEFFEEB; \
4884 static constexpr uint32_t ValueIfFalse = 0x11111111; \
4885 \
4886 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
4887 Immediate(Value0)); \
4888 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Src, \
4889 Immediate(Value1)); \
4890 __ test(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
4891 GPRRegister::Encoded_Reg_##Src); \
4892 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##Dst, \
4893 Immediate(ValueIfFalse)); \
4894 Label Done; \
4895 __ j(Cond::Br_e, &Done, NearJump); \
4896 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##Dst, \
4897 Immediate(ValueIfTrue)); \
4898 __ bind(&Done); \
4899 \
4900 AssembledTest test = assemble(); \
4901 test.run(); \
4902 \
4903 ASSERT_EQ(((Value0)&Mask##Size) & ((Value1)&Mask##Size) ? ValueIfTrue \
4904 : ValueIfFalse, \
4905 test.Dst()) \
4906 << TestString; \
4907 reset(); \
4908 } while (0)
4909
4910 #define TestImplRegImm(Dst, Value0, Imm, Size) \
4911 do { \
4912 static constexpr bool NearJump = true; \
4913 static constexpr char TestString[] = \
4914 "(" #Dst ", " #Value0 ", " #Imm ", " #Size ")"; \
4915 static constexpr uint32_t ValueIfTrue = 0xBEEFFEEB; \
4916 static constexpr uint32_t ValueIfFalse = 0x11111111; \
4917 \
4918 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
4919 Immediate(Value0)); \
4920 __ test(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
4921 Immediate((Imm)&Mask##Size)); \
4922 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##Dst, \
4923 Immediate(ValueIfFalse)); \
4924 Label Done; \
4925 __ j(Cond::Br_e, &Done, NearJump); \
4926 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##Dst, \
4927 Immediate(ValueIfTrue)); \
4928 __ bind(&Done); \
4929 \
4930 AssembledTest test = assemble(); \
4931 test.run(); \
4932 \
4933 ASSERT_EQ(((Value0)&Mask##Size) & ((Imm)&Mask##Size) ? ValueIfTrue \
4934 : ValueIfFalse, \
4935 test.Dst()) \
4936 << TestString; \
4937 reset(); \
4938 } while (0)
4939
4940 #define TestImplAddrReg(Value0, Src, Value1, Size) \
4941 do { \
4942 static constexpr bool NearJump = true; \
4943 static constexpr char TestString[] = \
4944 "(Addr, " #Value0 ", " #Src ", " #Value1 ", " #Size ")"; \
4945 static constexpr uint32_t ValueIfTrue = 0xBEEFFEEB; \
4946 static constexpr uint32_t ValueIfFalse = 0x11111111; \
4947 const uint32_t T0 = allocateDword(); \
4948 \
4949 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Src, \
4950 Immediate(Value1)); \
4951 __ test(IceType_i##Size, dwordAddress(T0), \
4952 GPRRegister::Encoded_Reg_##Src); \
4953 __ mov(IceType_i32, dwordAddress(T0), Immediate(ValueIfFalse)); \
4954 Label Done; \
4955 __ j(Cond::Br_e, &Done, NearJump); \
4956 __ mov(IceType_i32, dwordAddress(T0), Immediate(ValueIfTrue)); \
4957 __ bind(&Done); \
4958 \
4959 AssembledTest test = assemble(); \
4960 test.setDwordTo(T0, uint32_t(Value0)); \
4961 test.run(); \
4962 \
4963 ASSERT_EQ(((Value0)&Mask##Size) & ((Value1)&Mask##Size) ? ValueIfTrue \
4964 : ValueIfFalse, \
4965 test.contentsOfDword(T0)) \
4966 << TestString; \
4967 reset(); \
4968 } while (0)
4969
4970 #define TestImplAddrImm(Value0, Value1, Size) \
4971 do { \
4972 static constexpr bool NearJump = true; \
4973 static constexpr char TestString[] = \
4974 "(Addr, " #Value0 ", " #Value1 ", " #Size ")"; \
4975 static constexpr uint32_t ValueIfTrue = 0xBEEFFEEB; \
4976 static constexpr uint32_t ValueIfFalse = 0x11111111; \
4977 const uint32_t T0 = allocateDword(); \
4978 \
4979 __ test(IceType_i##Size, dwordAddress(T0), \
4980 Immediate((Value1)&Mask##Size)); \
4981 __ mov(IceType_i32, dwordAddress(T0), Immediate(ValueIfFalse)); \
4982 Label Done; \
4983 __ j(Cond::Br_e, &Done, NearJump); \
4984 __ mov(IceType_i32, dwordAddress(T0), Immediate(ValueIfTrue)); \
4985 __ bind(&Done); \
4986 \
4987 AssembledTest test = assemble(); \
4988 test.setDwordTo(T0, uint32_t(Value0)); \
4989 test.run(); \
4990 \
4991 ASSERT_EQ(((Value0)&Mask##Size) & ((Value1)&Mask##Size) ? ValueIfTrue \
4992 : ValueIfFalse, \
4993 test.contentsOfDword(T0)) \
4994 << TestString; \
4995 reset(); \
4996 } while (0)
4997
4998 #define TestImplValues(Dst, Value0, Src, Value1, Size) \
4999 do { \
5000 TestImplRegReg(Dst, Value0, Src, Value1, Size); \
5001 TestImplRegImm(Dst, Value0, Value1, Size); \
5002 TestImplAddrReg(Value0, Src, Value1, Size); \
5003 TestImplAddrImm(Value0, Value1, Size); \
5004 } while (0)
5005
5006 #define TestImplSize(Dst, Src, Size) \
5007 do { \
5008 TestImplValues(Dst, 0xF0F12101, Src, 0x00000000, Size); \
5009 TestImplValues(Dst, 0xF0000000, Src, 0xF0000000, Size); \
5010 TestImplValues(Dst, 0x0F00000F, Src, 0xF00000F0, Size); \
5011 } while (0)
5012
5013 #define TestImpl(Dst, Src) \
5014 do { \
5015 TestImplSize(Dst, Src, 8); \
5016 TestImplSize(Dst, Src, 16); \
5017 TestImplSize(Dst, Src, 32); \
5018 } while (0)
5019
5020 TestImpl(eax, ebx);
5021 TestImpl(ebx, ecx);
5022 TestImpl(ecx, edx);
5023 TestImpl(edx, esi);
5024 TestImpl(esi, edi);
5025 TestImpl(edi, eax);
5026
5027 #undef TestImpl
5028 #undef TestImplSize
5029 #undef TestImplValues
5030 #undef TestImplAddrImm
5031 #undef TestImplAddrReg
5032 #undef TestImplRegImm
5033 #undef TestImplRegReg
5034 }
5035
5036 // No mull/div because x86.
5037 // No shift because x86.
5038 TEST_F(AssemblerX8664Test, Arith_most) {
5039 static constexpr uint32_t Mask8 = 0xFF;
5040 static constexpr uint32_t Mask16 = 0xFFFF;
5041 static constexpr uint32_t Mask32 = 0xFFFFFFFF;
5042
5043 #define TestImplRegReg(Inst, Dst, Value0, Src, Value1, Type, Size, Op) \
5044 do { \
5045 static constexpr char TestString[] = \
5046 "(" #Inst ", " #Dst ", " #Value0 ", " #Src ", " #Value1 \
5047 ", " #Type #Size "_t, " #Op ")"; \
5048 \
5049 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
5050 Immediate(Value0)); \
5051 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Src, \
5052 Immediate(Value1)); \
5053 __ Inst(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
5054 GPRRegister::Encoded_Reg_##Src); \
5055 \
5056 AssembledTest test = assemble(); \
5057 test.run(); \
5058 \
5059 ASSERT_EQ(Mask##Size &static_cast<uint32_t>( \
5060 static_cast<Type##Size##_t>((Value0)&Mask##Size) \
5061 Op static_cast<Type##Size##_t>((Value1)&Mask##Size)), \
5062 Mask##Size &test.Dst()) \
5063 << TestString; \
5064 reset(); \
5065 } while (0)
5066
5067 #define TestImplRegAddr(Inst, Dst, Value0, Value1, Type, Size, Op) \
5068 do { \
5069 static constexpr char TestString[] = \
5070 "(" #Inst ", " #Dst ", " #Value0 ", Addr, " #Value1 ", " #Type #Size \
5071 "_t, " #Op ")"; \
5072 const uint32_t T0 = allocateDword(); \
5073 const uint32_t V0 = Value1; \
5074 \
5075 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
5076 Immediate(Value0)); \
5077 __ mov(IceType_i##Size, dwordAddress(T0), Immediate(Value1)); \
5078 __ Inst(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
5079 dwordAddress(T0)); \
5080 \
5081 AssembledTest test = assemble(); \
5082 test.setDwordTo(T0, V0); \
5083 test.run(); \
5084 \
5085 ASSERT_EQ(Mask##Size &static_cast<uint32_t>( \
5086 static_cast<Type##Size##_t>((Value0)&Mask##Size) \
5087 Op static_cast<Type##Size##_t>((Value1)&Mask##Size)), \
5088 Mask##Size &test.Dst()) \
5089 << TestString; \
5090 reset(); \
5091 } while (0)
5092
5093 #define TestImplRegImm(Inst, Dst, Value0, Imm, Type, Size, Op) \
5094 do { \
5095 static constexpr char TestString[] = \
5096 "(" #Inst ", " #Dst ", " #Value0 ", Imm(" #Imm "), " #Type #Size \
5097 "_t, " #Op ")"; \
5098 \
5099 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
5100 Immediate(Value0)); \
5101 __ Inst(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
5102 Immediate((Imm)&Mask##Size)); \
5103 \
5104 AssembledTest test = assemble(); \
5105 test.run(); \
5106 \
5107 ASSERT_EQ(Mask##Size &static_cast<uint32_t>( \
5108 static_cast<Type##Size##_t>((Value0)&Mask##Size) \
5109 Op static_cast<Type##Size##_t>((Imm)&Mask##Size)), \
5110 Mask##Size &test.Dst()) \
5111 << TestString; \
5112 reset(); \
5113 } while (0)
5114
5115 #define TestImplAddrReg(Inst, Value0, Src, Value1, Type, Size, Op) \
5116 do { \
5117 static constexpr char TestString[] = \
5118 "(" #Inst ", Addr, " #Value0 ", " #Src ", " #Value1 ", " #Type #Size \
5119 "_t, " #Op ")"; \
5120 const uint32_t T0 = allocateDword(); \
5121 const uint32_t V0 = Value0; \
5122 \
5123 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Src, \
5124 Immediate(Value1)); \
5125 __ Inst(IceType_i##Size, dwordAddress(T0), \
5126 GPRRegister::Encoded_Reg_##Src); \
5127 \
5128 AssembledTest test = assemble(); \
5129 test.setDwordTo(T0, V0); \
5130 test.run(); \
5131 \
5132 ASSERT_EQ(Mask##Size &static_cast<uint32_t>( \
5133 static_cast<Type##Size##_t>((Value0)&Mask##Size) \
5134 Op static_cast<Type##Size##_t>((Value1)&Mask##Size)), \
5135 Mask##Size &test.contentsOfDword(T0)) \
5136 << TestString; \
5137 reset(); \
5138 } while (0)
5139
5140 #define TestImplAddrImm(Inst, Value0, Imm, Type, Size, Op) \
5141 do { \
5142 static constexpr char TestString[] = \
5143 "(" #Inst ", Addr, " #Value0 ", Imm, " #Imm ", " #Type #Size \
5144 "_t, " #Op ")"; \
5145 const uint32_t T0 = allocateDword(); \
5146 const uint32_t V0 = Value0; \
5147 \
5148 __ Inst(IceType_i##Size, dwordAddress(T0), Immediate((Imm)&Mask##Size)); \
5149 \
5150 AssembledTest test = assemble(); \
5151 test.setDwordTo(T0, V0); \
5152 test.run(); \
5153 \
5154 ASSERT_EQ(Mask##Size &static_cast<uint32_t>( \
5155 static_cast<Type##Size##_t>((Value0)&Mask##Size) \
5156 Op static_cast<Type##Size##_t>((Imm)&Mask##Size)), \
5157 Mask##Size &test.contentsOfDword(T0)) \
5158 << TestString; \
5159 reset(); \
5160 } while (0)
5161
5162 #define TestImplOp(Inst, Dst, Value0, Src, Value1, Type, Size, Op) \
5163 do { \
5164 TestImplRegReg(Inst, Dst, Value0, Src, Value1, Type, Size, Op); \
5165 TestImplRegAddr(Inst, Dst, Value0, Value1, Type, Size, Op); \
5166 TestImplRegImm(Inst, Dst, Value0, Value1, Type, Size, Op); \
5167 TestImplAddrReg(Inst, Value0, Src, Value1, Type, Size, Op); \
5168 TestImplAddrImm(Inst, Value0, Value1, Type, Size, Op); \
5169 } while (0)
5170
5171 #define TestImplValues(Dst, Value0, Src, Value1, Size) \
5172 do { \
5173 TestImplOp(And, Dst, Value0, Src, Value1, int, Size, &); \
5174 TestImplOp(And, Dst, Value0, Src, Value1, uint, Size, &); \
5175 TestImplOp(Or, Dst, Value0, Src, Value1, int, Size, | ); \
5176 TestImplOp(Or, Dst, Value0, Src, Value1, uint, Size, | ); \
5177 TestImplOp(Xor, Dst, Value0, Src, Value1, int, Size, ^); \
5178 TestImplOp(Xor, Dst, Value0, Src, Value1, uint, Size, ^); \
5179 TestImplOp(add, Dst, Value0, Src, Value1, int, Size, +); \
5180 TestImplOp(add, Dst, Value0, Src, Value1, uint, Size, +); \
5181 TestImplOp(sub, Dst, Value0, Src, Value1, int, Size, -); \
5182 TestImplOp(sub, Dst, Value0, Src, Value1, uint, Size, -); \
5183 } while (0)
5184
5185 #define TestImplSize(Dst, Src, Size) \
5186 do { \
5187 TestImplValues(Dst, 0xF0F12101, Src, 0x00000000, Size); \
5188 TestImplValues(Dst, 0xF0000000, Src, 0xF0000000, Size); \
5189 TestImplValues(Dst, 0x0F00000F, Src, 0xF0000070, Size); \
5190 TestImplValues(Dst, 0x0F00F00F, Src, 0xF000F070, Size); \
5191 } while (0)
5192
5193 #define TestImpl(Dst, Src) \
5194 do { \
5195 if (GPRRegister::Encoded_Reg_##Src <= 3 && \
5196 GPRRegister::Encoded_Reg_##Dst <= 3) { \
5197 TestImplSize(Dst, Src, 8); \
5198 } \
5199 TestImplSize(Dst, Src, 16); \
5200 TestImplSize(Dst, Src, 32); \
5201 } while (0)
5202
5203 TestImpl(eax, ebx);
5204 TestImpl(ebx, ecx);
5205 TestImpl(ecx, edx);
5206 TestImpl(edx, esi);
5207 TestImpl(esi, edi);
5208 TestImpl(edi, eax);
5209
5210 #undef TestImpl
5211 #undef TestImplSize
5212 #undef TestImplValues
5213 #undef TestImplOp
5214 #undef TestImplAddrImm
5215 #undef TestImplAddrReg
5216 #undef TestImplRegImm
5217 #undef TestImplRegAddr
5218 #undef TestImplRegReg
5219 }
5220
5221 TEST_F(AssemblerX8664Test, Arith_BorrowNCarry) {
5222 const uint32_t Mask8 = 0x000000FF;
5223 const uint32_t Mask16 = 0x0000FFFF;
5224 const uint32_t Mask32 = 0xFFFFFFFF;
5225
5226 const uint64_t ResultMask8 = 0x000000000000FFFFull;
5227 const uint64_t ResultMask16 = 0x00000000FFFFFFFFull;
5228 const uint64_t ResultMask32 = 0xFFFFFFFFFFFFFFFFull;
5229
5230 #define TestImplRegReg(Inst0, Inst1, Dst0, Dst1, Value0, Src0, Src1, Value1, \
5231 Op, Size) \
5232 do { \
5233 static_assert(Size == 8 || Size == 16 || Size == 32, \
5234 "Invalid size " #Size); \
5235 static constexpr char TestString[] = \
5236 "(" #Inst0 ", " #Inst1 ", " #Dst0 ", " #Dst1 ", " #Value0 ", " #Src0 \
5237 ", " #Src1 ", " #Value1 ", " #Op ", " #Size ")"; \
5238 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst0, \
5239 Immediate(uint64_t(Value0) & Mask##Size)); \
5240 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst1, \
5241 Immediate((uint64_t(Value0) >> Size) & Mask##Size)); \
5242 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Src0, \
5243 Immediate(uint64_t(Value1) & Mask##Size)); \
5244 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Src1, \
5245 Immediate((uint64_t(Value1) >> Size) & Mask##Size)); \
5246 __ Inst0(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst0, \
5247 GPRRegister::Encoded_Reg_##Src0); \
5248 __ Inst1(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst1, \
5249 GPRRegister::Encoded_Reg_##Src1); \
5250 \
5251 AssembledTest test = assemble(); \
5252 test.run(); \
5253 \
5254 static constexpr uint64_t Result = \
5255 (uint64_t(Value0) & ResultMask##Size)Op(uint64_t(Value1) & \
5256 ResultMask##Size); \
5257 static constexpr uint32_t Expected0 = Result & Mask##Size; \
5258 static constexpr uint32_t Expected1 = (Result >> Size) & Mask##Size; \
5259 ASSERT_EQ(Expected0, test.Dst0()) << TestString << ": 0"; \
5260 ASSERT_EQ(Expected1, test.Dst1()) << TestString << ": 1"; \
5261 reset(); \
5262 } while (0)
5263
5264 #define TestImplRegAddr(Inst0, Inst1, Dst0, Dst1, Value0, Value1, Op, Size) \
5265 do { \
5266 static_assert(Size == 8 || Size == 16 || Size == 32, \
5267 "Invalid size " #Size); \
5268 static constexpr char TestString[] = \
5269 "(" #Inst0 ", " #Inst1 ", " #Dst0 ", " #Dst1 ", " #Value0 \
5270 ", Addr, " #Value1 ", " #Op ", " #Size ")"; \
5271 const uint32_t T0 = allocateDword(); \
5272 const uint32_t V0 = uint64_t(Value1) & Mask##Size; \
5273 const uint32_t T1 = allocateDword(); \
5274 const uint32_t V1 = (uint64_t(Value1) >> Size) & Mask##Size; \
5275 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst0, \
5276 Immediate(uint64_t(Value0) & Mask##Size)); \
5277 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst1, \
5278 Immediate((uint64_t(Value0) >> Size) & Mask##Size)); \
5279 __ Inst0(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst0, \
5280 dwordAddress(T0)); \
5281 __ Inst1(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst1, \
5282 dwordAddress(T1)); \
5283 \
5284 AssembledTest test = assemble(); \
5285 test.setDwordTo(T0, V0); \
5286 test.setDwordTo(T1, V1); \
5287 test.run(); \
5288 \
5289 static constexpr uint64_t Result = \
5290 (uint64_t(Value0) & ResultMask##Size)Op(uint64_t(Value1) & \
5291 ResultMask##Size); \
5292 static constexpr uint32_t Expected0 = Result & Mask##Size; \
5293 static constexpr uint32_t Expected1 = (Result >> Size) & Mask##Size; \
5294 ASSERT_EQ(Expected0, test.Dst0()) << TestString << ": 0"; \
5295 ASSERT_EQ(Expected1, test.Dst1()) << TestString << ": 1"; \
5296 reset(); \
5297 } while (0)
5298
5299 #define TestImplRegImm(Inst0, Inst1, Dst0, Dst1, Value0, Imm, Op, Size) \
5300 do { \
5301 static_assert(Size == 8 || Size == 16 || Size == 32, \
5302 "Invalid size " #Size); \
5303 static constexpr char TestString[] = \
5304 "(" #Inst0 ", " #Inst1 ", " #Dst0 ", " #Dst1 ", " #Value0 \
5305 ", Imm(" #Imm "), " #Op ", " #Size ")"; \
5306 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst0, \
5307 Immediate(uint64_t(Value0) & Mask##Size)); \
5308 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst1, \
5309 Immediate((uint64_t(Value0) >> Size) & Mask##Size)); \
5310 __ Inst0(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst0, \
5311 Immediate(uint64_t(Imm) & Mask##Size)); \
5312 __ Inst1(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst1, \
5313 Immediate((uint64_t(Imm) >> Size) & Mask##Size)); \
5314 \
5315 AssembledTest test = assemble(); \
5316 test.run(); \
5317 \
5318 static constexpr uint64_t Result = \
5319 (uint64_t(Value0) & ResultMask##Size)Op(uint64_t(Imm) & \
5320 ResultMask##Size); \
5321 static constexpr uint32_t Expected0 = Result & Mask##Size; \
5322 static constexpr uint32_t Expected1 = (Result >> Size) & Mask##Size; \
5323 ASSERT_EQ(Expected0, test.Dst0()) << TestString << ": 0"; \
5324 ASSERT_EQ(Expected1, test.Dst1()) << TestString << ": 1"; \
5325 reset(); \
5326 } while (0)
5327
5328 #define TestImplAddrReg(Inst0, Inst1, Value0, Src0, Src1, Value1, Op, Size) \
5329 do { \
5330 static_assert(Size == 8 || Size == 16 || Size == 32, \
5331 "Invalid size " #Size); \
5332 static constexpr char TestString[] = \
5333 "(" #Inst0 ", " #Inst1 ", Addr, " #Value0 ", " #Src0 ", " #Src1 \
5334 ", " #Value1 ", " #Op ", " #Size ")"; \
5335 const uint32_t T0 = allocateDword(); \
5336 const uint32_t V0 = uint64_t(Value0) & Mask##Size; \
5337 const uint32_t T1 = allocateDword(); \
5338 const uint32_t V1 = (uint64_t(Value0) >> Size) & Mask##Size; \
5339 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Src0, \
5340 Immediate(uint64_t(Value1) & Mask##Size)); \
5341 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Src1, \
5342 Immediate((uint64_t(Value1) >> Size) & Mask##Size)); \
5343 __ Inst0(IceType_i##Size, dwordAddress(T0), \
5344 GPRRegister::Encoded_Reg_##Src0); \
5345 __ Inst1(IceType_i##Size, dwordAddress(T1), \
5346 GPRRegister::Encoded_Reg_##Src1); \
5347 \
5348 AssembledTest test = assemble(); \
5349 test.setDwordTo(T0, V0); \
5350 test.setDwordTo(T1, V1); \
5351 test.run(); \
5352 \
5353 static constexpr uint64_t Result = \
5354 (uint64_t(Value0) & ResultMask##Size)Op(uint64_t(Value1) & \
5355 ResultMask##Size); \
5356 static constexpr uint32_t Expected0 = Result & Mask##Size; \
5357 static constexpr uint32_t Expected1 = (Result >> Size) & Mask##Size; \
5358 ASSERT_EQ(Expected0, test.contentsOfDword(T0)) << TestString << ": 0"; \
5359 ASSERT_EQ(Expected1, test.contentsOfDword(T1)) << TestString << ": 1"; \
5360 reset(); \
5361 } while (0)
5362
5363 #define TestImplAddrImm(Inst0, Inst1, Value0, Imm, Op, Size) \
5364 do { \
5365 static_assert(Size == 8 || Size == 16 || Size == 32, \
5366 "Invalid size " #Size); \
5367 static constexpr char TestString[] = \
5368 "(" #Inst0 ", " #Inst1 ", Addr, " #Value0 ", Imm(" #Imm "), " #Op \
5369 ", " #Size ")"; \
5370 const uint32_t T0 = allocateDword(); \
5371 const uint32_t V0 = uint64_t(Value0) & Mask##Size; \
5372 const uint32_t T1 = allocateDword(); \
5373 const uint32_t V1 = (uint64_t(Value0) >> Size) & Mask##Size; \
5374 __ Inst0(IceType_i##Size, dwordAddress(T0), \
5375 Immediate(uint64_t(Imm) & Mask##Size)); \
5376 __ Inst1(IceType_i##Size, dwordAddress(T1), \
5377 Immediate((uint64_t(Imm) >> Size) & Mask##Size)); \
5378 \
5379 AssembledTest test = assemble(); \
5380 test.setDwordTo(T0, V0); \
5381 test.setDwordTo(T1, V1); \
5382 test.run(); \
5383 \
5384 static constexpr uint64_t Result = \
5385 (uint64_t(Value0) & ResultMask##Size)Op(uint64_t(Imm) & \
5386 ResultMask##Size); \
5387 static constexpr uint32_t Expected0 = Result & Mask##Size; \
5388 static constexpr uint32_t Expected1 = (Result >> Size) & Mask##Size; \
5389 ASSERT_EQ(Expected0, test.contentsOfDword(T0)) << TestString << ": 0"; \
5390 ASSERT_EQ(Expected1, test.contentsOfDword(T1)) << TestString << ": 1"; \
5391 reset(); \
5392 } while (0)
5393
5394 #define TestImplOp(Inst0, Inst1, Dst0, Dst1, Value0, Src0, Src1, Value1, Op, \
5395 Size) \
5396 do { \
5397 TestImplRegReg(Inst0, Inst1, Dst0, Dst1, Value0, Src0, Src1, Value1, Op, \
5398 Size); \
5399 TestImplRegAddr(Inst0, Inst1, Dst0, Dst1, Value0, Value1, Op, Size); \
5400 TestImplRegImm(Inst0, Inst1, Dst0, Dst1, Value0, Value1, Op, Size); \
5401 TestImplAddrReg(Inst0, Inst1, Value0, Src0, Src1, Value1, Op, Size); \
5402 TestImplAddrImm(Inst0, Inst1, Value0, Value1, Op, Size); \
5403 } while (0)
5404
5405 #define TestImplValues(Dst0, Dst1, Value0, Src0, Src1, Value1, Size) \
5406 do { \
5407 TestImplOp(add, adc, Dst0, Dst1, Value0, Src0, Src1, Value1, +, Size); \
5408 TestImplOp(sub, sbb, Dst0, Dst1, Value0, Src0, Src1, Value1, -, Size); \
5409 } while (0)
5410
5411 #define TestImplSize(Dst0, Dst1, Src0, Src1, Size) \
5412 do { \
5413 TestImplValues(Dst0, Dst1, 0xFFFFFFFFFFFFFF00ull, Src0, Src1, \
5414 0xFFFFFFFF0000017Full, Size); \
5415 } while (0)
5416
5417 #define TestImpl(Dst0, Dst1, Src0, Src1) \
5418 do { \
5419 if (GPRRegister::Encoded_Reg_##Dst0 <= 3 && \
5420 GPRRegister::Encoded_Reg_##Dst1 <= 3 && \
5421 GPRRegister::Encoded_Reg_##Src0 <= 3 && \
5422 GPRRegister::Encoded_Reg_##Src1 <= 3) { \
5423 TestImplSize(Dst0, Dst1, Src0, Src1, 8); \
5424 } \
5425 TestImplSize(Dst0, Dst1, Src0, Src1, 16); \
5426 TestImplSize(Dst0, Dst1, Src0, Src1, 32); \
5427 } while (0)
5428
5429 TestImpl(eax, ebx, ecx, edx);
5430 TestImpl(ebx, ecx, edx, esi);
5431 TestImpl(ecx, edx, esi, edi);
5432 TestImpl(edx, esi, edi, eax);
5433 TestImpl(esi, edi, eax, ebx);
5434 TestImpl(edi, eax, ebx, ecx);
5435
5436 #undef TestImpl
5437 #undef TestImplSize
5438 #undef TestImplValues
5439 #undef TestImplOp
5440 #undef TestImplAddrImm
5441 #undef TestImplAddrReg
5442 #undef TestImplRegImm
5443 #undef TestImplRegAddr
5444 #undef TestImplRegReg
5445 }
5446
5447 TEST_F(AssemblerX8664LowLevelTest, Cbw_Cwd_Cdq) {
5448 #define TestImpl(Inst, BytesSize, ...) \
5449 do { \
5450 __ Inst(); \
5451 ASSERT_EQ(BytesSize, codeBytesSize()) << #Inst; \
5452 verifyBytes<BytesSize>(codeBytes(), __VA_ARGS__); \
5453 reset(); \
5454 } while (0)
5455
5456 TestImpl(cbw, 2u, 0x66, 0x98);
5457 TestImpl(cwd, 2u, 0x66, 0x99);
5458 TestImpl(cdq, 1u, 0x99);
5459
5460 #undef TestImpl
5461 }
5462
5463 TEST_F(AssemblerX8664Test, SingleOperandMul) {
5464 static constexpr uint32_t Mask8 = 0x000000FF;
5465 static constexpr uint32_t Mask16 = 0x0000FFFF;
5466 static constexpr uint32_t Mask32 = 0xFFFFFFFF;
5467
5468 #define TestImplReg(Inst, Value0, Src, Value1, Type, Size) \
5469 do { \
5470 static_assert(GPRRegister::Encoded_Reg_eax != \
5471 GPRRegister::Encoded_Reg_##Src, \
5472 "eax can not be src1."); \
5473 \
5474 static constexpr char TestString[] = \
5475 "(" #Inst ", " #Value0 ", " #Src ", " #Value1 ", " #Type ", " #Size \
5476 ")"; \
5477 static constexpr Type##64_t OperandEax = \
5478 static_cast<Type##Size##_t>((Value0)&Mask##Size); \
5479 static constexpr Type##64_t OperandOther = \
5480 static_cast<Type##Size##_t>((Value1)&Mask##Size); \
5481 static constexpr uint32_t ExpectedEax = \
5482 Mask##Size & (OperandEax * OperandOther); \
5483 static constexpr uint32_t ExpectedEdx = \
5484 Mask##Size & ((OperandEax * OperandOther) >> Size); \
5485 \
5486 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_eax, \
5487 Immediate((Value0)&Mask##Size)); \
5488 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Src, \
5489 Immediate((Value1)&Mask##Size)); \
5490 __ Inst(IceType_i##Size, GPRRegister::Encoded_Reg_##Src); \
5491 \
5492 if (Size == 8) { \
5493 /* mov %ah, %dl */ \
5494 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_edx, \
5495 GPRRegister::Encoded_Reg_esp); \
5496 __ And(IceType_i16, GPRRegister::Encoded_Reg_eax, Immediate(0x00FF)); \
5497 if (GPRRegister::Encoded_Reg_##Src == GPRRegister::Encoded_Reg_esi) { \
5498 /* src == dh; clear dx's upper 8 bits. */ \
5499 __ And(IceType_i16, GPRRegister::Encoded_Reg_edx, Immediate(0x00FF)); \
5500 } \
5501 } \
5502 \
5503 AssembledTest test = assemble(); \
5504 test.run(); \
5505 \
5506 ASSERT_EQ(ExpectedEax, test.eax()) << TestString; \
5507 ASSERT_EQ(ExpectedEdx, test.edx()) << TestString; \
5508 reset(); \
5509 } while (0)
5510
5511 #define TestImplAddr(Inst, Value0, Value1, Type, Size) \
5512 do { \
5513 static constexpr char TestString[] = \
5514 "(" #Inst ", " #Value0 ", Addr, " #Value1 ", " #Type ", " #Size ")"; \
5515 static const uint32_t T0 = allocateDword(); \
5516 static constexpr uint32_t V0 = Value1; \
5517 static constexpr Type##64_t OperandEax = \
5518 static_cast<Type##Size##_t>((Value0)&Mask##Size); \
5519 static constexpr Type##64_t OperandOther = \
5520 static_cast<Type##Size##_t>((Value1)&Mask##Size); \
5521 static constexpr uint32_t ExpectedEax = \
5522 Mask##Size & (OperandEax * OperandOther); \
5523 static constexpr uint32_t ExpectedEdx = \
5524 Mask##Size & ((OperandEax * OperandOther) >> Size); \
5525 \
5526 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_eax, \
5527 Immediate((Value0)&Mask##Size)); \
5528 __ Inst(IceType_i##Size, dwordAddress(T0)); \
5529 \
5530 if (Size == 8) { \
5531 /* mov %ah, %dl */ \
5532 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_edx, \
5533 GPRRegister::Encoded_Reg_esp); \
5534 __ And(IceType_i16, GPRRegister::Encoded_Reg_eax, Immediate(0x00FF)); \
5535 } \
5536 \
5537 AssembledTest test = assemble(); \
5538 test.setDwordTo(T0, V0); \
5539 test.run(); \
5540 \
5541 ASSERT_EQ(ExpectedEax, test.eax()) << TestString; \
5542 ASSERT_EQ(ExpectedEdx, test.edx()) << TestString; \
5543 reset(); \
5544 } while (0)
5545
5546 #define TestImplOp(Inst, Value0, Src, Value1, Type, Size) \
5547 do { \
5548 TestImplReg(Inst, Value0, Src, Value1, Type, Size); \
5549 TestImplAddr(Inst, Value0, Value1, Type, Size); \
5550 } while (0)
5551
5552 #define TestImplValue(Value0, Src, Value1, Size) \
5553 do { \
5554 TestImplOp(mul, Value0, Src, Value1, uint, Size); \
5555 TestImplOp(imul, Value0, Src, Value1, int, Size); \
5556 } while (0)
5557
5558 #define TestImplSize(Src, Size) \
5559 do { \
5560 TestImplValue(10, Src, 1, Size); \
5561 TestImplValue(10, Src, -1, Size); \
5562 TestImplValue(-10, Src, 37, Size); \
5563 TestImplValue(-10, Src, -15, Size); \
5564 } while (0)
5565
5566 #define TestImpl(Src) \
5567 do { \
5568 TestImplSize(Src, 8); \
5569 TestImplSize(Src, 16); \
5570 TestImplSize(Src, 32); \
5571 } while (0)
5572
5573 TestImpl(ebx);
5574 TestImpl(ecx);
5575 TestImpl(edx);
5576 TestImpl(esi);
5577 TestImpl(edi);
5578
5579 #undef TestImpl
5580 #undef TestImplSize
5581 #undef TestImplValue
5582 #undef TestImplOp
5583 #undef TestImplAddr
5584 #undef TestImplReg
5585 }
5586
5587 TEST_F(AssemblerX8664Test, TwoOperandImul) {
5588 static constexpr uint32_t Mask16 = 0x0000FFFF;
5589 static constexpr uint32_t Mask32 = 0xFFFFFFFF;
5590
5591 #define TestImplRegReg(Dst, Value0, Src, Value1, Size) \
5592 do { \
5593 static constexpr char TestString[] = \
5594 "(" #Dst ", " #Value0 ", " #Src ", " #Value1 ", " #Size ")"; \
5595 static constexpr int64_t Operand0 = \
5596 static_cast<int##Size##_t>((Value0)&Mask##Size); \
5597 static constexpr int64_t Operand1 = \
5598 static_cast<int##Size##_t>((Value1)&Mask##Size); \
5599 static constexpr uint32_t Expected = Mask##Size & (Operand0 * Operand1); \
5600 \
5601 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
5602 Immediate((Value0)&Mask##Size)); \
5603 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Src, \
5604 Immediate((Value1)&Mask##Size)); \
5605 __ imul(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
5606 GPRRegister::Encoded_Reg_##Src); \
5607 \
5608 if (Size == 8) { \
5609 /* mov %ah, %dl */ \
5610 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_edx, \
5611 GPRRegister::Encoded_Reg_esp); \
5612 __ And(IceType_i16, GPRRegister::Encoded_Reg_eax, Immediate(0x00FF)); \
5613 if (GPRRegister::Encoded_Reg_##Src == GPRRegister::Encoded_Reg_esi) { \
5614 /* src == dh; clear dx's upper 8 bits. */ \
5615 __ And(IceType_i16, GPRRegister::Encoded_Reg_edx, Immediate(0x00FF)); \
5616 } \
5617 } \
5618 \
5619 AssembledTest test = assemble(); \
5620 test.run(); \
5621 \
5622 ASSERT_EQ(Expected, test.Dst()) << TestString; \
5623 reset(); \
5624 } while (0)
5625
5626 #define TestImplRegImm(Dst, Value0, Imm, Size) \
5627 do { \
5628 static constexpr char TestString[] = \
5629 "(" #Dst ", " #Value0 ", Imm(" #Imm "), " #Size ")"; \
5630 static constexpr int64_t Operand0 = \
5631 static_cast<int##Size##_t>((Value0)&Mask##Size); \
5632 static constexpr int64_t Operand1 = \
5633 static_cast<int##Size##_t>((Imm)&Mask##Size); \
5634 static constexpr uint32_t Expected = Mask##Size & (Operand0 * Operand1); \
5635 \
5636 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
5637 Immediate((Value0)&Mask##Size)); \
5638 __ imul(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, Immediate(Imm)); \
5639 \
5640 if (Size == 8) { \
5641 /* mov %ah, %dl */ \
5642 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_edx, \
5643 GPRRegister::Encoded_Reg_esp); \
5644 __ And(IceType_i16, GPRRegister::Encoded_Reg_eax, Immediate(0x00FF)); \
5645 } \
5646 \
5647 AssembledTest test = assemble(); \
5648 test.run(); \
5649 \
5650 ASSERT_EQ(Expected, test.Dst()) << TestString; \
5651 reset(); \
5652 } while (0)
5653
5654 #define TestImplRegAddr(Dst, Value0, Value1, Size) \
5655 do { \
5656 static constexpr char TestString[] = \
5657 "(" #Dst ", " #Value0 ", Addr," #Value1 ", " #Size ")"; \
5658 static constexpr int64_t Operand0 = \
5659 static_cast<int##Size##_t>((Value0)&Mask##Size); \
5660 static constexpr int64_t Operand1 = \
5661 static_cast<int##Size##_t>((Value1)&Mask##Size); \
5662 static constexpr uint32_t Expected = Mask##Size & (Operand0 * Operand1); \
5663 const uint32_t T0 = allocateDword(); \
5664 \
5665 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
5666 Immediate((Value0)&Mask##Size)); \
5667 __ imul(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
5668 dwordAddress(T0)); \
5669 \
5670 if (Size == 8) { \
5671 /* mov %ah, %dl */ \
5672 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_edx, \
5673 GPRRegister::Encoded_Reg_esp); \
5674 __ And(IceType_i16, GPRRegister::Encoded_Reg_eax, Immediate(0x00FF)); \
5675 } \
5676 \
5677 AssembledTest test = assemble(); \
5678 test.setDwordTo(T0, static_cast<uint32_t>(Operand1)); \
5679 test.run(); \
5680 \
5681 ASSERT_EQ(Expected, test.Dst()) << TestString; \
5682 reset(); \
5683 } while (0)
5684
5685 #define TestImplValue(Dst, Value0, Src, Value1, Size) \
5686 do { \
5687 TestImplRegReg(Dst, Value0, Src, Value1, Size); \
5688 TestImplRegImm(Dst, Value0, Value1, Size); \
5689 TestImplRegAddr(Dst, Value0, Value1, Size); \
5690 } while (0)
5691
5692 #define TestImplSize(Dst, Src, Size) \
5693 do { \
5694 TestImplValue(Dst, 1, Src, 1, Size); \
5695 TestImplValue(Dst, -10, Src, 0x4050AA20, Size); \
5696 TestImplValue(Dst, -2, Src, -55, Size); \
5697 } while (0)
5698
5699 #define TestImpl(Dst, Src) \
5700 do { \
5701 TestImplSize(Dst, Src, 16); \
5702 TestImplSize(Dst, Src, 32); \
5703 } while (0)
5704
5705 TestImpl(eax, ebx);
5706 TestImpl(ebx, ecx);
5707 TestImpl(ecx, edx);
5708 TestImpl(edx, esi);
5709 TestImpl(esi, edi);
5710 TestImpl(edi, eax);
5711
5712 #undef TestImpl
5713 #undef TestImplSize
5714 #undef TestImplValue
5715 #undef TestImplRegAddr
5716 #undef TestImplRegImm
5717 #undef TestImplRegReg
5718 }
5719
5720 TEST_F(AssemblerX8664Test, Div) {
5721 static constexpr uint32_t Mask8 = 0x000000FF;
5722 static constexpr uint32_t Mask16 = 0x0000FFFF;
5723 static constexpr uint32_t Mask32 = 0xFFFFFFFF;
5724
5725 static constexpr uint64_t Operand0Mask8 = 0x00000000000000FFull;
5726 static constexpr uint64_t Operand0Mask16 = 0x00000000FFFFFFFFull;
5727 static constexpr uint64_t Operand0Mask32 = 0xFFFFFFFFFFFFFFFFull;
5728
5729 using Operand0Type_int8 = int16_t;
5730 using Operand0Type_uint8 = uint16_t;
5731 using Operand0Type_int16 = int32_t;
5732 using Operand0Type_uint16 = uint32_t;
5733 using Operand0Type_int32 = int64_t;
5734 using Operand0Type_uint32 = uint64_t;
5735
5736 #define TestImplReg(Inst, Value0, Src, Value1, Type, Size) \
5737 do { \
5738 static_assert(GPRRegister::Encoded_Reg_eax != \
5739 GPRRegister::Encoded_Reg_##Src, \
5740 "eax can not be src1."); \
5741 static_assert(GPRRegister::Encoded_Reg_edx != \
5742 GPRRegister::Encoded_Reg_##Src, \
5743 "edx can not be src1."); \
5744 \
5745 static constexpr char TestString[] = \
5746 "(" #Inst ", " #Value0 ", " #Src ", " #Value1 ", " #Type ", " #Size \
5747 ")"; \
5748 static constexpr Operand0Type_##Type##Size Operand0 = \
5749 static_cast<Type##64_t>(Value0) & Operand0Mask##Size; \
5750 static constexpr Type##Size##_t Operand0Lo = Operand0 & Mask##Size; \
5751 static constexpr Type##Size##_t Operand0Hi = \
5752 (Operand0 >> Size) & Mask##Size; \
5753 static constexpr Type##Size##_t Operand1 = \
5754 static_cast<Type##Size##_t>(Value1) & Mask##Size; \
5755 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_eax, \
5756 Immediate(Operand0Lo)); \
5757 if (Size == 8) { \
5758 /* mov Operand0Hi, %al */ \
5759 __ mov(IceType_i8, GPRRegister::Encoded_Reg_esp, Immediate(Operand0Hi)); \
5760 } else { \
5761 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_edx, \
5762 Immediate(Operand0Hi)); \
5763 } \
5764 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Src, \
5765 Immediate(Operand1)); \
5766 __ Inst(IceType_i##Size, GPRRegister::Encoded_Reg_##Src); \
5767 if (Size == 8) { \
5768 /* mov %ah, %dl */ \
5769 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_edx, \
5770 GPRRegister::Encoded_Reg_esp); \
5771 __ And(IceType_i16, GPRRegister::Encoded_Reg_eax, Immediate(0x00FF)); \
5772 if (GPRRegister::Encoded_Reg_##Src == GPRRegister::Encoded_Reg_esi) { \
5773 __ And(IceType_i16, GPRRegister::Encoded_Reg_edx, Immediate(0x00FF)); \
5774 } \
5775 } \
5776 \
5777 AssembledTest test = assemble(); \
5778 test.run(); \
5779 \
5780 static constexpr uint32_t Quocient = (Operand0 / Operand1) & Mask##Size; \
5781 static constexpr uint32_t Reminder = (Operand0 % Operand1) & Mask##Size; \
5782 EXPECT_EQ(Quocient, test.eax()) << TestString; \
5783 EXPECT_EQ(Reminder, test.edx()) << TestString; \
5784 reset(); \
5785 } while (0)
5786
5787 #define TestImplAddr(Inst, Value0, Value1, Type, Size) \
5788 do { \
5789 static constexpr char TestString[] = \
5790 "(" #Inst ", " #Value0 ", Addr, " #Value1 ", " #Type ", " #Size ")"; \
5791 static constexpr Operand0Type_##Type##Size Operand0 = \
5792 static_cast<Type##64_t>(Value0) & Operand0Mask##Size; \
5793 static constexpr Type##Size##_t Operand0Lo = Operand0 & Mask##Size; \
5794 static constexpr Type##Size##_t Operand0Hi = \
5795 (Operand0 >> Size) & Mask##Size; \
5796 const uint32_t T0 = allocateDword(); \
5797 static constexpr Type##Size##_t V0 = \
5798 static_cast<Type##Size##_t>(Value1) & Mask##Size; \
5799 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_eax, \
5800 Immediate(Operand0Lo)); \
5801 if (Size == 8) { \
5802 /* mov Operand0Hi, %al */ \
5803 __ mov(IceType_i8, GPRRegister::Encoded_Reg_esp, Immediate(Operand0Hi)); \
5804 } else { \
5805 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_edx, \
5806 Immediate(Operand0Hi)); \
5807 } \
5808 __ Inst(IceType_i##Size, dwordAddress(T0)); \
5809 if (Size == 8) { \
5810 /* mov %ah, %dl */ \
5811 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_edx, \
5812 GPRRegister::Encoded_Reg_esp); \
5813 __ And(IceType_i16, GPRRegister::Encoded_Reg_eax, Immediate(0x00FF)); \
5814 } \
5815 \
5816 AssembledTest test = assemble(); \
5817 test.setDwordTo(T0, static_cast<uint32_t>(V0)); \
5818 test.run(); \
5819 \
5820 static constexpr uint32_t Quocient = (Operand0 / V0) & Mask##Size; \
5821 static constexpr uint32_t Reminder = (Operand0 % V0) & Mask##Size; \
5822 EXPECT_EQ(Quocient, test.eax()) << TestString; \
5823 EXPECT_EQ(Reminder, test.edx()) << TestString; \
5824 reset(); \
5825 } while (0)
5826
5827 #define TestImplOp(Inst, Value0, Src, Value1, Type, Size) \
5828 do { \
5829 TestImplReg(Inst, Value0, Src, Value1, Type, Size); \
5830 TestImplAddr(Inst, Value0, Value1, Type, Size); \
5831 } while (0)
5832
5833 #define TestImplValue(Value0, Src, Value1, Size) \
5834 do { \
5835 TestImplOp(div, Value0, Src, Value1, uint, Size); \
5836 TestImplOp(idiv, Value0, Src, Value1, int, Size); \
5837 } while (0)
5838
5839 #define TestImplSize(Src, Size) \
5840 do { \
5841 TestImplValue(10, Src, 1, Size); \
5842 TestImplValue(10, Src, -1, Size); \
5843 } while (0)
5844
5845 #define TestImpl(Src) \
5846 do { \
5847 TestImplSize(Src, 8); \
5848 TestImplSize(Src, 16); \
5849 TestImplSize(Src, 32); \
5850 } while (0)
5851
5852 TestImpl(ebx);
5853 TestImpl(ecx);
5854 TestImpl(esi);
5855 TestImpl(edi);
5856
5857 #undef TestImpl
5858 #undef TestImplSize
5859 #undef TestImplValue
5860 #undef TestImplOp
5861 #undef TestImplAddr
5862 #undef TestImplReg
5863 }
5864
5865 TEST_F(AssemblerX8664Test, Incl_Decl_Addr) {
5866 #define TestImpl(Inst, Value0) \
5867 do { \
5868 const bool IsInc = std::string(#Inst).find("incl") != std::string::npos; \
5869 const uint32_t T0 = allocateDword(); \
5870 const uint32_t V0 = Value0; \
5871 \
5872 __ Inst(dwordAddress(T0)); \
5873 \
5874 AssembledTest test = assemble(); \
5875 test.setDwordTo(T0, V0); \
5876 test.run(); \
5877 \
5878 ASSERT_EQ(static_cast<uint32_t>(Value0 + (IsInc ? 1 : -1)), \
5879 test.contentsOfDword(T0)); \
5880 reset(); \
5881 } while (0)
5882
5883 #define TestInc(Value0) \
5884 do { \
5885 TestImpl(incl, Value0); \
5886 } while (0)
5887
5888 #define TestDec(Value0) \
5889 do { \
5890 TestImpl(decl, Value0); \
5891 } while (0)
5892
5893 TestInc(230);
5894
5895 TestDec(30);
5896
5897 #undef TestInc
5898 #undef TestDec
5899 #undef TestImpl
5900 }
5901
5902 TEST_F(AssemblerX8664Test, Shifts) {
5903 static constexpr uint32_t Mask8 = 0x000000FF;
5904 static constexpr uint32_t Mask16 = 0x0000FFFF;
5905 static constexpr uint32_t Mask32 = 0xFFFFFFFF;
5906
5907 #define TestImplRegImm(Inst, Dst, Value0, Imm, Op, Type, Size) \
5908 do { \
5909 static constexpr char TestString[] = \
5910 "(" #Inst ", " #Dst ", " #Value0 ", Imm(" #Imm "), " #Op ", " #Type \
5911 ", " #Size ")"; \
5912 const bool IsRol = std::string(#Inst).find("rol") != std::string::npos; \
5913 const uint##Size##_t Expected = \
5914 Mask##Size & (static_cast<Type##Size##_t>(Value0) Op(Imm) | \
5915 (!IsRol ? 0 : (Value0) >> (Size - Imm))); \
5916 \
5917 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
5918 Immediate((Value0)&Mask##Size)); \
5919 __ Inst(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
5920 Immediate((Imm)&Mask##Size)); \
5921 \
5922 AssembledTest test = assemble(); \
5923 test.run(); \
5924 \
5925 ASSERT_EQ(static_cast<uint32_t>(Expected), test.Dst()) << TestString; \
5926 reset(); \
5927 } while (0)
5928
5929 #define TestImplRegRegImm(Inst, Dst, Value0, Src, Value1, Count, Op0, Op1, \
5930 Type, Size) \
5931 do { \
5932 static constexpr char TestString[] = \
5933 "(" #Inst ", " #Dst ", " #Value0 ", " #Src ", " #Value1 \
5934 ", Imm(" #Count "), " #Op0 ", " #Op1 ", " #Type ", " #Size ")"; \
5935 const uint##Size##_t Expected = \
5936 Mask##Size & (static_cast<Type##Size##_t>(Value0) Op0(Count) | \
5937 (static_cast<Type##64_t>(Value1) Op1(Size - Count))); \
5938 \
5939 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
5940 Immediate((Value0)&Mask##Size)); \
5941 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Src, \
5942 Immediate((Value1)&Mask##Size)); \
5943 __ Inst(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
5944 GPRRegister::Encoded_Reg_##Src, Immediate(Count)); \
5945 \
5946 AssembledTest test = assemble(); \
5947 test.run(); \
5948 \
5949 ASSERT_EQ(static_cast<uint32_t>(Expected), test.Dst()) << TestString; \
5950 reset(); \
5951 } while (0)
5952
5953 #define TestImplRegCl(Inst, Dst, Value0, Count, Op, Type, Size) \
5954 do { \
5955 static constexpr char TestString[] = \
5956 "(" #Inst ", " #Dst ", " #Value0 ", " #Count ", " #Op ", " #Type \
5957 ", " #Size ")"; \
5958 const bool IsRol = std::string(#Inst).find("rol") != std::string::npos; \
5959 const uint##Size##_t Expected = \
5960 Mask##Size & (static_cast<Type##Size##_t>(Value0) Op(Count) | \
5961 (!IsRol ? 0 : Value0 >> (Size - Count))); \
5962 \
5963 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
5964 Immediate((Value0)&Mask##Size)); \
5965 __ mov(IceType_i8, GPRRegister::Encoded_Reg_ecx, \
5966 Immediate((Count)&Mask##Size)); \
5967 __ Inst(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
5968 GPRRegister::Encoded_Reg_ecx); \
5969 \
5970 AssembledTest test = assemble(); \
5971 test.run(); \
5972 \
5973 ASSERT_EQ(static_cast<uint32_t>(Expected), test.Dst()) << TestString; \
5974 reset(); \
5975 } while (0)
5976
5977 #define TestImplRegRegCl(Inst, Dst, Value0, Src, Value1, Count, Op0, Op1, \
5978 Type, Size) \
5979 do { \
5980 static constexpr char TestString[] = \
5981 "(" #Inst ", " #Dst ", " #Value0 ", " #Src ", " #Value1 ", " #Count \
5982 ", " #Op0 ", " #Op1 ", " #Type ", " #Size ")"; \
5983 const uint##Size##_t Expected = \
5984 Mask##Size & (static_cast<Type##Size##_t>(Value0) Op0(Count) | \
5985 (static_cast<Type##64_t>(Value1) Op1(Size - Count))); \
5986 \
5987 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
5988 Immediate((Value0)&Mask##Size)); \
5989 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Src, \
5990 Immediate((Value1)&Mask##Size)); \
5991 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_ecx, \
5992 Immediate((Count)&0x7F)); \
5993 __ Inst(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
5994 GPRRegister::Encoded_Reg_##Src); \
5995 \
5996 AssembledTest test = assemble(); \
5997 test.run(); \
5998 \
5999 ASSERT_EQ(static_cast<uint32_t>(Expected), test.Dst()) << TestString; \
6000 reset(); \
6001 } while (0)
6002
6003 #define TestImplAddrCl(Inst, Value0, Count, Op, Type, Size) \
6004 do { \
6005 static constexpr char TestString[] = \
6006 "(" #Inst ", Addr, " #Value0 ", " #Count ", " #Op ", " #Type \
6007 ", " #Size ")"; \
6008 const bool IsRol = std::string(#Inst).find("rol") != std::string::npos; \
6009 const uint##Size##_t Expected = \
6010 Mask##Size & (static_cast<Type##Size##_t>(Value0) Op(Count) | \
6011 (!IsRol ? 0 : Value0 >> (Size - Count))); \
6012 const uint32_t T0 = allocateDword(); \
6013 const uint32_t V0 = Value0; \
6014 \
6015 __ mov(IceType_i8, GPRRegister::Encoded_Reg_ecx, \
6016 Immediate((Count)&Mask##Size)); \
6017 __ Inst(IceType_i##Size, dwordAddress(T0), GPRRegister::Encoded_Reg_ecx); \
6018 \
6019 AssembledTest test = assemble(); \
6020 test.setDwordTo(T0, V0); \
6021 test.run(); \
6022 \
6023 ASSERT_EQ(static_cast<uint32_t>(Expected), \
6024 Mask##Size &test.contentsOfDword(T0)) \
6025 << TestString; \
6026 reset(); \
6027 } while (0)
6028
6029 #define TestImplAddrRegCl(Inst, Value0, Src, Value1, Count, Op0, Op1, Type, \
6030 Size) \
6031 do { \
6032 static constexpr char TestString[] = \
6033 "(" #Inst ", Addr, " #Value0 ", " #Src ", " #Value1 ", " #Count \
6034 ", " #Op0 ", " #Op1 ", " #Type ", " #Size ")"; \
6035 const uint##Size##_t Expected = \
6036 Mask##Size & (static_cast<Type##Size##_t>(Value0) Op0(Count) | \
6037 (static_cast<Type##64_t>(Value1) Op1(Size - Count))); \
6038 const uint32_t T0 = allocateDword(); \
6039 \
6040 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Src, \
6041 Immediate((Value1)&Mask##Size)); \
6042 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_ecx, \
6043 Immediate((Count)&0x7F)); \
6044 __ Inst(IceType_i##Size, dwordAddress(T0), \
6045 GPRRegister::Encoded_Reg_##Src); \
6046 \
6047 AssembledTest test = assemble(); \
6048 test.setDwordTo(T0, static_cast<uint32_t>(Value0)); \
6049 test.run(); \
6050 \
6051 ASSERT_EQ(static_cast<uint32_t>(Expected), test.contentsOfDword(T0)) \
6052 << TestString; \
6053 reset(); \
6054 } while (0)
6055
6056 #define TestImplOp(Inst, Dst, Value0, Count, Op, Type, Size) \
6057 do { \
6058 static_assert(GPRRegister::Encoded_Reg_##Dst != \
6059 GPRRegister::Encoded_Reg_ecx, \
6060 "ecx should not be specified as Dst"); \
6061 TestImplRegImm(Inst, Dst, Value0, Count, Op, Type, Size); \
6062 TestImplRegImm(Inst, ecx, Value0, Count, Op, Type, Size); \
6063 TestImplRegCl(Inst, Dst, Value0, Count, Op, Type, Size); \
6064 TestImplAddrCl(Inst, Value0, Count, Op, Type, Size); \
6065 } while (0)
6066
6067 #define TestImplThreeOperandOp(Inst, Dst, Value0, Src, Value1, Count, Op0, \
6068 Op1, Type, Size) \
6069 do { \
6070 static_assert(GPRRegister::Encoded_Reg_##Dst != \
6071 GPRRegister::Encoded_Reg_ecx, \
6072 "ecx should not be specified as Dst"); \
6073 static_assert(GPRRegister::Encoded_Reg_##Src != \
6074 GPRRegister::Encoded_Reg_ecx, \
6075 "ecx should not be specified as Src"); \
6076 TestImplRegRegImm(Inst, Dst, Value0, Src, Value1, Count, Op0, Op1, Type, \
6077 Size); \
6078 TestImplRegRegCl(Inst, Dst, Value0, Src, Value1, Count, Op0, Op1, Type, \
6079 Size); \
6080 TestImplAddrRegCl(Inst, Value0, Src, Value1, Count, Op0, Op1, Type, Size); \
6081 } while (0)
6082
6083 #define TestImplValue(Dst, Value0, Count, Size) \
6084 do { \
6085 TestImplOp(rol, Dst, Value0, Count, <<, uint, Size); \
6086 TestImplOp(shl, Dst, Value0, Count, <<, uint, Size); \
6087 TestImplOp(shr, Dst, Value0, Count, >>, uint, Size); \
6088 TestImplOp(sar, Dst, Value0, Count, >>, int, Size); \
6089 } while (0)
6090
6091 #define TestImplThreeOperandValue(Dst, Value0, Src, Value1, Count, Size) \
6092 do { \
6093 TestImplThreeOperandOp(shld, Dst, Value0, Src, Value1, Count, <<, >>, \
6094 uint, Size); \
6095 TestImplThreeOperandOp(shrd, Dst, Value0, Src, Value1, Count, >>, <<, \
6096 uint, Size); \
6097 } while (0)
6098
6099 #define TestImplSize(Dst, Size) \
6100 do { \
6101 TestImplValue(Dst, 0x8F, 3, Size); \
6102 TestImplValue(Dst, 0x8FFF, 7, Size); \
6103 TestImplValue(Dst, 0x8FFFF, 7, Size); \
6104 } while (0)
6105
6106 #define TestImplThreeOperandSize(Dst, Src, Size) \
6107 do { \
6108 TestImplThreeOperandValue(Dst, 0xFFF3, Src, 0xA000, 8, Size); \
6109 } while (0)
6110
6111 #define TestImpl(Dst, Src) \
6112 do { \
6113 if (GPRRegister::Encoded_Reg_##Dst < 4) { \
6114 TestImplSize(Dst, 8); \
6115 } \
6116 TestImplSize(Dst, 16); \
6117 TestImplThreeOperandSize(Dst, Src, 16); \
6118 TestImplSize(Dst, 32); \
6119 TestImplThreeOperandSize(Dst, Src, 32); \
6120 } while (0)
6121
6122 TestImpl(eax, ebx);
6123 TestImpl(ebx, edx);
6124 TestImpl(edx, esi);
6125 TestImpl(esi, edi);
6126 TestImpl(edi, eax);
6127
6128 #undef TestImpl
6129 #undef TestImplThreeOperandSize
6130 #undef TestImplSize
6131 #undef TestImplValue
6132 #undef TestImplThreeOperandValue
6133 #undef TestImplOp
6134 #undef TestImplThreeOperandOp
6135 #undef TestImplAddrCl
6136 #undef TestImplRegRegCl
6137 #undef TestImplRegCl
6138 #undef TestImplRegRegImm
6139 #undef TestImplRegImm
6140 }
6141
6142 TEST_F(AssemblerX8664Test, Neg) {
6143 static constexpr uint32_t Mask8 = 0x000000ff;
6144 static constexpr uint32_t Mask16 = 0x0000ffff;
6145 static constexpr uint32_t Mask32 = 0xffffffff;
6146
6147 #define TestImplReg(Dst, Size) \
6148 do { \
6149 static constexpr int32_t Value = 0xFF00A543; \
6150 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
6151 Immediate(static_cast<int##Size##_t>(Value) & Mask##Size)); \
6152 __ neg(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst); \
6153 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_eax, \
6154 GPRRegister::Encoded_Reg_##Dst); \
6155 __ And(IceType_i32, GPRRegister::Encoded_Reg_eax, Immediate(Mask##Size)); \
6156 \
6157 AssembledTest test = assemble(); \
6158 test.run(); \
6159 \
6160 ASSERT_EQ(1 + (~static_cast<int##Size##_t>(Value) & Mask##Size), \
6161 test.eax()) \
6162 << "(" #Dst ", " #Size ")"; \
6163 reset(); \
6164 } while (0)
6165
6166 #define TestImplAddr(Size) \
6167 do { \
6168 static constexpr int32_t Value = 0xFF00A543; \
6169 const uint32_t T0 = allocateDword(); \
6170 __ neg(IceType_i##Size, dwordAddress(T0)); \
6171 \
6172 AssembledTest test = assemble(); \
6173 test.setDwordTo(T0, Value &Mask##Size); \
6174 test.run(); \
6175 \
6176 ASSERT_EQ(1 + (~static_cast<int##Size##_t>(Value) & Mask##Size), \
6177 test.contentsOfDword(T0)) \
6178 << "(Addr, " #Size ")"; \
6179 reset(); \
6180 } while (0)
6181
6182 #define TestImpl(Size) \
6183 do { \
6184 TestImplAddr(Size); \
6185 TestImplReg(eax, Size); \
6186 TestImplReg(ebx, Size); \
6187 TestImplReg(ecx, Size); \
6188 TestImplReg(edx, Size); \
6189 TestImplReg(esi, Size); \
6190 TestImplReg(edi, Size); \
6191 } while (0)
6192
6193 TestImpl(8);
6194 TestImpl(16);
6195 TestImpl(32);
6196
6197 #undef TestImpl
6198 #undef TestImplAddr
6199 #undef TestImplReg
6200 }
6201
6202 TEST_F(AssemblerX8664Test, Not) {
6203 #define TestImpl(Dst) \
6204 do { \
6205 static constexpr uint32_t Value = 0xFF00A543; \
6206 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##Dst, Immediate(Value)); \
6207 __ notl(GPRRegister::Encoded_Reg_##Dst); \
6208 \
6209 AssembledTest test = assemble(); \
6210 test.run(); \
6211 \
6212 ASSERT_EQ(~Value, test.Dst()) << "(" #Dst ")"; \
6213 reset(); \
6214 } while (0)
6215
6216 TestImpl(eax);
6217 TestImpl(ebx);
6218 TestImpl(ecx);
6219 TestImpl(edx);
6220 TestImpl(esi);
6221 TestImpl(edi);
6222
6223 #undef TestImpl
6224 }
6225
6226 TEST_F(AssemblerX8664Test, Bswap) {
6227 #define TestImpl(Dst) \
6228 do { \
6229 static constexpr uint32_t Value = 0xFF00A543; \
6230 static constexpr uint32_t Expected = 0x43A500FF; \
6231 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##Dst, Immediate(Value)); \
6232 __ bswap(IceType_i32, GPRRegister::Encoded_Reg_##Dst); \
6233 \
6234 AssembledTest test = assemble(); \
6235 test.run(); \
6236 \
6237 ASSERT_EQ(Expected, test.Dst()) << "(" #Dst ")"; \
6238 reset(); \
6239 } while (0)
6240
6241 TestImpl(eax);
6242 TestImpl(ebx);
6243 TestImpl(ecx);
6244 TestImpl(edx);
6245 TestImpl(esi);
6246 TestImpl(edi);
6247
6248 #undef TestImpl
6249 }
6250
6251 TEST_F(AssemblerX8664Test, Bt) {
6252 #define TestImpl(Dst, Value0, Src, Value1) \
6253 do { \
6254 static constexpr char TestString[] = \
6255 "(" #Dst ", " #Value0 ", " #Src ", " #Value1 ")"; \
6256 static constexpr uint32_t Expected = ((Value0) & (1u << (Value1))) != 0; \
6257 \
6258 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##Dst, Immediate(Value0)); \
6259 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##Src, Immediate(Value1)); \
6260 __ bt(GPRRegister::Encoded_Reg_##Dst, GPRRegister::Encoded_Reg_##Src); \
6261 __ setcc(Cond::Br_b, ByteRegister::Encoded_Reg_al); \
6262 __ And(IceType_i32, GPRRegister::Encoded_Reg_eax, Immediate(0xFFu)); \
6263 \
6264 AssembledTest test = assemble(); \
6265 test.run(); \
6266 \
6267 ASSERT_EQ(Expected, test.eax()) << TestString; \
6268 reset(); \
6269 } while (0)
6270
6271 TestImpl(eax, 0x08000000, ebx, 27u);
6272 TestImpl(ebx, 0x08000000, ecx, 23u);
6273 TestImpl(ecx, 0x00000000, edx, 1u);
6274 TestImpl(edx, 0x08000300, esi, 9u);
6275 TestImpl(esi, 0x08000300, edi, 10u);
6276 TestImpl(edi, 0x7FFFEFFF, eax, 13u);
6277
6278 #undef TestImpl
6279 }
6280
6281 template <uint32_t Value, uint32_t Bits> class BitScanHelper {
6282 BitScanHelper() = delete;
6283
6284 public:
6285 static_assert(Bits == 16 || Bits == 32, "Bits must be 16 or 32");
6286 using ValueType =
6287 typename std::conditional<Bits == 16, uint16_t, uint32_t>::type;
6288
6289 private:
6290 static constexpr ValueType BitIndex(bool Forward, ValueType Index) {
6291 return (Value == 0)
6292 ? BitScanHelper<Value, Bits>::NoBitSet
6293 : (Value & (1u << Index)
6294 ? Index
6295 : BitIndex(Forward, (Forward ? Index + 1 : Index - 1)));
6296 }
6297
6298 public:
6299 static constexpr ValueType NoBitSet = static_cast<ValueType>(-1);
6300 static constexpr ValueType bsf = BitIndex(/*Forward*/ true, /*Index=*/0);
6301 static constexpr ValueType bsr =
6302 BitIndex(/*Forward*/ false, /*Index=*/Bits - 1);
6303 };
6304
6305 TEST_F(AssemblerX8664Test, BitScanOperations) {
6306 #define TestImplRegReg(Inst, Dst, Src, Value1, Size) \
6307 do { \
6308 static constexpr char TestString[] = \
6309 "(" #Inst ", " #Dst ", " #Src ", " #Value1 ", " #Size ")"; \
6310 static constexpr uint32_t Expected = BitScanHelper<Value1, Size>::Inst; \
6311 const uint32_t ZeroFlag = allocateDword(); \
6312 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Src, \
6313 Immediate(Value1)); \
6314 __ Inst(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
6315 GPRRegister::Encoded_Reg_##Src); \
6316 __ setcc(Cond::Br_e, dwordAddress(ZeroFlag)); \
6317 \
6318 AssembledTest test = assemble(); \
6319 test.setDwordTo(ZeroFlag, 0u); \
6320 test.run(); \
6321 \
6322 ASSERT_EQ((Expected == BitScanHelper<Value1, Size>::NoBitSet), \
6323 test.contentsOfDword(ZeroFlag)) \
6324 << TestString; \
6325 if ((Expected != BitScanHelper<Value1, Size>::NoBitSet)) { \
6326 ASSERT_EQ(Expected, test.Dst()) << TestString; \
6327 } \
6328 reset(); \
6329 } while (0)
6330
6331 #define TestImplRegAddr(Inst, Dst, Value1, Size) \
6332 do { \
6333 static constexpr char TestString[] = \
6334 "(" #Inst ", " #Dst ", Addr, " #Value1 ", " #Size ")"; \
6335 static constexpr uint32_t Expected = BitScanHelper<Value1, Size>::Inst; \
6336 const uint32_t T0 = allocateDword(); \
6337 const uint32_t ZeroFlag = allocateDword(); \
6338 __ Inst(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst, \
6339 dwordAddress(T0)); \
6340 __ setcc(Cond::Br_e, dwordAddress(ZeroFlag)); \
6341 \
6342 AssembledTest test = assemble(); \
6343 test.setDwordTo(T0, Value1); \
6344 test.setDwordTo(ZeroFlag, 0u); \
6345 test.run(); \
6346 \
6347 ASSERT_EQ((Expected == BitScanHelper<Value1, Size>::NoBitSet), \
6348 test.contentsOfDword(ZeroFlag)) \
6349 << TestString; \
6350 if (Expected != BitScanHelper<Value1, Size>::NoBitSet) { \
6351 ASSERT_EQ(Expected, test.Dst()) << TestString; \
6352 } \
6353 reset(); \
6354 } while (0)
6355
6356 #define TestImplSize(Dst, Src, Value1, Size) \
6357 do { \
6358 TestImplRegReg(bsf, Dst, Src, Value1, Size); \
6359 TestImplRegAddr(bsf, Dst, Value1, Size); \
6360 TestImplRegReg(bsr, Dst, Src, Value1, Size); \
6361 TestImplRegAddr(bsf, Dst, Value1, Size); \
6362 } while (0)
6363
6364 #define TestImplValue(Dst, Src, Value1) \
6365 do { \
6366 TestImplSize(Dst, Src, Value1, 16); \
6367 TestImplSize(Dst, Src, Value1, 32); \
6368 } while (0)
6369
6370 #define TestImpl(Dst, Src) \
6371 do { \
6372 TestImplValue(Dst, Src, 0x80000001); \
6373 TestImplValue(Dst, Src, 0x00000000); \
6374 TestImplValue(Dst, Src, 0x80001000); \
6375 TestImplValue(Dst, Src, 0x00FFFF00); \
6376 } while (0)
6377
6378 TestImpl(eax, ebx);
6379 TestImpl(ebx, ecx);
6380 TestImpl(ecx, edx);
6381 TestImpl(edx, esi);
6382 TestImpl(esi, edi);
6383 TestImpl(edi, eax);
6384
6385 #undef TestImpl
6386 #undef TestImplValue
6387 #undef TestImplSize
6388 #undef TestImplRegAddr
6389 #undef TestImplRegReg
6390 }
6391
6392 TEST_F(AssemblerX8664LowLevelTest, Nop) {
6393 #define TestImpl(Size, ...) \
6394 do { \
6395 static constexpr char TestString[] = "(" #Size ", " #__VA_ARGS__ ")"; \
6396 __ nop(Size); \
6397 ASSERT_EQ(Size##u, codeBytesSize()) << TestString; \
6398 ASSERT_TRUE(verifyBytes<Size>(codeBytes(), __VA_ARGS__)) << TestString; \
6399 reset(); \
6400 } while (0);
6401
6402 TestImpl(1, 0x90);
6403 TestImpl(2, 0x66, 0x90);
6404 TestImpl(3, 0x0F, 0x1F, 0x00);
6405 TestImpl(4, 0x0F, 0x1F, 0x40, 0x00);
6406 TestImpl(5, 0x0F, 0x1F, 0x44, 0x00, 0x00);
6407 TestImpl(6, 0x66, 0x0F, 0x1F, 0x44, 0x00, 0x00);
6408 TestImpl(7, 0x0F, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00);
6409 TestImpl(8, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00);
6410
6411 #undef TestImpl
6412 }
6413
6414 TEST_F(AssemblerX8664LowLevelTest, Int3) {
6415 __ int3();
6416 static constexpr uint32_t ByteCount = 1;
6417 ASSERT_EQ(ByteCount, codeBytesSize());
6418 verifyBytes<ByteCount>(codeBytes(), 0xCC);
6419 }
6420
6421 TEST_F(AssemblerX8664LowLevelTest, Hlt) {
6422 __ hlt();
6423 static constexpr uint32_t ByteCount = 1;
6424 ASSERT_EQ(ByteCount, codeBytesSize());
6425 verifyBytes<ByteCount>(codeBytes(), 0xF4);
6426 }
6427
6428 TEST_F(AssemblerX8664LowLevelTest, Ud2) {
6429 __ ud2();
6430 static constexpr uint32_t ByteCount = 2;
6431 ASSERT_EQ(ByteCount, codeBytesSize());
6432 verifyBytes<ByteCount>(codeBytes(), 0x0F, 0x0B);
6433 }
6434
6435 TEST_F(AssemblerX8664Test, Jmp) {
6436 // TestImplReg uses jmp(Label), so jmp(Label) needs to be tested before it.
6437 #define TestImplAddr(Near) \
6438 do { \
6439 Label ForwardJmp; \
6440 Label BackwardJmp; \
6441 Label Done; \
6442 \
6443 __ jmp(&ForwardJmp, AssemblerX8664::k##Near##Jump); \
6444 __ hlt(); \
6445 __ hlt(); \
6446 __ hlt(); \
6447 __ hlt(); \
6448 __ hlt(); \
6449 __ hlt(); \
6450 __ hlt(); \
6451 __ hlt(); \
6452 __ hlt(); \
6453 __ hlt(); \
6454 __ bind(&BackwardJmp); \
6455 __ jmp(&Done, AssemblerX8664::k##Near##Jump); \
6456 __ hlt(); \
6457 __ hlt(); \
6458 __ hlt(); \
6459 __ hlt(); \
6460 __ hlt(); \
6461 __ hlt(); \
6462 __ hlt(); \
6463 __ hlt(); \
6464 __ hlt(); \
6465 __ hlt(); \
6466 __ bind(&ForwardJmp); \
6467 __ jmp(&BackwardJmp, AssemblerX8664::k##NearJump); \
6468 __ hlt(); \
6469 __ hlt(); \
6470 __ hlt(); \
6471 __ hlt(); \
6472 __ hlt(); \
6473 __ hlt(); \
6474 __ hlt(); \
6475 __ hlt(); \
6476 __ hlt(); \
6477 __ hlt(); \
6478 __ bind(&Done); \
6479 } while (0)
6480
6481 #define TestImplReg(Dst) \
6482 do { \
6483 __ call(Immediate(16)); \
6484 Label Done; \
6485 __ jmp(&Done, AssemblerX8664::kNearJump); \
6486 __ hlt(); \
6487 __ hlt(); \
6488 __ hlt(); \
6489 __ hlt(); \
6490 __ hlt(); \
6491 __ hlt(); \
6492 __ hlt(); \
6493 __ hlt(); \
6494 __ hlt(); \
6495 __ hlt(); \
6496 __ popl(GPRRegister::Encoded_Reg_##Dst); \
6497 __ jmp(GPRRegister::Encoded_Reg_##Dst); \
6498 __ hlt(); \
6499 __ hlt(); \
6500 __ hlt(); \
6501 __ hlt(); \
6502 __ hlt(); \
6503 __ hlt(); \
6504 __ hlt(); \
6505 __ hlt(); \
6506 __ hlt(); \
6507 __ hlt(); \
6508 __ bind(&Done); \
6509 \
6510 AssembledTest test = assemble(); \
6511 test.run(); \
6512 \
6513 reset(); \
6514 } while (0)
6515
6516 TestImplAddr(Near);
6517 TestImplAddr(Far);
6518
6519 TestImplReg(eax);
6520 TestImplReg(ebx);
6521 TestImplReg(ecx);
6522 TestImplReg(edx);
6523 TestImplReg(esi);
6524 TestImplReg(edi);
6525
6526 #undef TestImplReg
6527 #undef TestImplAddr
6528 }
6529
6530 TEST_F(AssemblerX8664LowLevelTest, Mfence) {
6531 __ mfence();
6532
6533 static constexpr uint8_t ByteCount = 3;
6534 ASSERT_EQ(ByteCount, codeBytesSize());
6535 verifyBytes<ByteCount>(codeBytes(), 0x0F, 0xAE, 0xF0);
6536 }
6537
6538 TEST_F(AssemblerX8664LowLevelTest, Lock) {
6539 __ lock();
6540
6541 static constexpr uint8_t ByteCount = 1;
6542 ASSERT_EQ(ByteCount, codeBytesSize());
6543 verifyBytes<ByteCount>(codeBytes(), 0xF0);
6544 }
6545
6546 TEST_F(AssemblerX8664Test, Xchg) {
6547 static constexpr uint32_t Mask8 = 0x000000FF;
6548 static constexpr uint32_t Mask16 = 0x0000FFFF;
6549 static constexpr uint32_t Mask32 = 0xFFFFFFFF;
6550
6551 #define TestImplAddrReg(Value0, Dst1, Value1, Size) \
6552 do { \
6553 static constexpr char TestString[] = \
6554 "(" #Value0 ", " #Dst1 ", " #Value1 ", " #Size ")"; \
6555 const uint32_t T0 = allocateDword(); \
6556 const uint32_t V0 = (Value0)&Mask##Size; \
6557 const uint32_t V1 = (Value1)&Mask##Size; \
6558 \
6559 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst1, \
6560 Immediate(Value1)); \
6561 __ xchg(IceType_i##Size, dwordAddress(T0), \
6562 GPRRegister::Encoded_Reg_##Dst1); \
6563 __ And(IceType_i32, GPRRegister::Encoded_Reg_##Dst1, \
6564 Immediate(Mask##Size)); \
6565 \
6566 AssembledTest test = assemble(); \
6567 test.setDwordTo(T0, V0); \
6568 test.run(); \
6569 \
6570 ASSERT_EQ(V0, test.Dst1()) << TestString; \
6571 ASSERT_EQ(V1, test.contentsOfDword(T0)) << TestString; \
6572 reset(); \
6573 } while (0)
6574
6575 #define TestImplSize(Dst1, Size) \
6576 do { \
6577 TestImplAddrReg(0xa2b34567, Dst1, 0x0507ddee, Size); \
6578 } while (0)
6579
6580 #define TestImpl(Dst1) \
6581 do { \
6582 if (GPRRegister::Encoded_Reg_##Dst1 < 4) { \
6583 TestImplSize(Dst1, 8); \
6584 } \
6585 TestImplSize(Dst1, 16); \
6586 TestImplSize(Dst1, 32); \
6587 } while (0)
6588
6589 TestImpl(eax);
6590 TestImpl(ebx);
6591 TestImpl(ecx);
6592 TestImpl(edx);
6593 TestImpl(esi);
6594 TestImpl(edi);
6595
6596 #undef TestImpl
6597 #undef TestImplSize
6598 #undef TestImplAddrReg
6599 }
6600
6601 TEST_F(AssemblerX8664Test, Xadd) {
6602 static constexpr bool NotLocked = false;
6603 static constexpr bool Locked = true;
6604
6605 static constexpr uint32_t Mask8 = 0x000000FF;
6606 static constexpr uint32_t Mask16 = 0x0000FFFF;
6607 static constexpr uint32_t Mask32 = 0xFFFFFFFF;
6608
6609 #define TestImplAddrReg(Value0, Dst1, Value1, LockedOrNot, Size) \
6610 do { \
6611 static constexpr char TestString[] = \
6612 "(" #Value0 ", " #Dst1 ", " #Value1 ", " #Size ")"; \
6613 const uint32_t T0 = allocateDword(); \
6614 const uint32_t V0 = (Value0)&Mask##Size; \
6615 const uint32_t V1 = (Value1)&Mask##Size; \
6616 \
6617 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Dst1, \
6618 Immediate(Value1)); \
6619 __ xadd(IceType_i##Size, dwordAddress(T0), \
6620 GPRRegister::Encoded_Reg_##Dst1, LockedOrNot); \
6621 __ And(IceType_i32, GPRRegister::Encoded_Reg_##Dst1, \
6622 Immediate(Mask##Size)); \
6623 \
6624 AssembledTest test = assemble(); \
6625 test.setDwordTo(T0, V0); \
6626 test.run(); \
6627 \
6628 ASSERT_EQ(V0, test.Dst1()) << TestString; \
6629 ASSERT_EQ(Mask##Size &(V1 + V0), test.contentsOfDword(T0)) << TestString; \
6630 reset(); \
6631 } while (0)
6632
6633 #define TestImplSize(Dst1, Size) \
6634 do { \
6635 TestImplAddrReg(0xa2b34567, Dst1, 0x0507ddee, NotLocked, Size); \
6636 TestImplAddrReg(0xa2b34567, Dst1, 0x0507ddee, Locked, Size); \
6637 } while (0)
6638
6639 #define TestImpl(Dst1) \
6640 do { \
6641 if (GPRRegister::Encoded_Reg_##Dst1 < 4) { \
6642 TestImplSize(Dst1, 8); \
6643 } \
6644 TestImplSize(Dst1, 16); \
6645 TestImplSize(Dst1, 32); \
6646 } while (0)
6647
6648 TestImpl(eax);
6649 TestImpl(ebx);
6650 TestImpl(ecx);
6651 TestImpl(edx);
6652 TestImpl(esi);
6653 TestImpl(edi);
6654
6655 #undef TestImpl
6656 #undef TestImplSize
6657 #undef TestImplAddrReg
6658 }
6659
6660 TEST_F(AssemblerX8664LowLevelTest, Xadd) {
6661 static constexpr bool NotLocked = false;
6662 static constexpr bool Locked = true;
6663
6664 // Ensures that xadd emits a lock prefix accordingly.
6665 {
6666 __ xadd(IceType_i8, Address::Absolute(0x1FF00),
6667 GPRRegister::Encoded_Reg_esi, NotLocked);
6668 static constexpr uint8_t ByteCountNotLocked8 = 7;
6669 ASSERT_EQ(ByteCountNotLocked8, codeBytesSize());
6670 verifyBytes<ByteCountNotLocked8>(codeBytes(), 0x0F, 0xC0, 0x35, 0x00, 0xFF,
6671 0x01, 0x00);
6672 reset();
6673
6674 __ xadd(IceType_i8, Address::Absolute(0x1FF00),
6675 GPRRegister::Encoded_Reg_esi, Locked);
6676 static constexpr uint8_t ByteCountLocked8 = 1 + ByteCountNotLocked8;
6677 ASSERT_EQ(ByteCountLocked8, codeBytesSize());
6678 verifyBytes<ByteCountLocked8>(codeBytes(), 0xF0, 0x0F, 0xC0, 0x35, 0x00,
6679 0xFF, 0x01, 0x00);
6680 reset();
6681 }
6682
6683 {
6684 __ xadd(IceType_i16, Address::Absolute(0x1FF00),
6685 GPRRegister::Encoded_Reg_esi, NotLocked);
6686 static constexpr uint8_t ByteCountNotLocked16 = 8;
6687 ASSERT_EQ(ByteCountNotLocked16, codeBytesSize());
6688 verifyBytes<ByteCountNotLocked16>(codeBytes(), 0x66, 0x0F, 0xC1, 0x35, 0x00,
6689 0xFF, 0x01, 0x00);
6690 reset();
6691
6692 __ xadd(IceType_i16, Address::Absolute(0x1FF00),
6693 GPRRegister::Encoded_Reg_esi, Locked);
6694 static constexpr uint8_t ByteCountLocked16 = 1 + ByteCountNotLocked16;
6695 ASSERT_EQ(ByteCountLocked16, codeBytesSize());
6696 verifyBytes<ByteCountLocked16>(codeBytes(), 0x66, 0xF0, 0x0F, 0xC1, 0x35,
6697 0x00, 0xFF, 0x01, 0x00);
6698 reset();
6699 }
6700
6701 {
6702 __ xadd(IceType_i32, Address::Absolute(0x1FF00),
6703 GPRRegister::Encoded_Reg_esi, NotLocked);
6704 static constexpr uint8_t ByteCountNotLocked32 = 7;
6705 ASSERT_EQ(ByteCountNotLocked32, codeBytesSize());
6706 verifyBytes<ByteCountNotLocked32>(codeBytes(), 0x0F, 0xC1, 0x35, 0x00, 0xFF,
6707 0x01, 0x00);
6708 reset();
6709
6710 __ xadd(IceType_i32, Address::Absolute(0x1FF00),
6711 GPRRegister::Encoded_Reg_esi, Locked);
6712 static constexpr uint8_t ByteCountLocked32 = 1 + ByteCountNotLocked32;
6713 ASSERT_EQ(ByteCountLocked32, codeBytesSize());
6714 verifyBytes<ByteCountLocked32>(codeBytes(), 0xF0, 0x0F, 0xC1, 0x35, 0x00,
6715 0xFF, 0x01, 0x00);
6716 reset();
6717 }
6718 }
6719
6720 TEST_F(AssemblerX8664LowLevelTest, EmitSegmentOverride) {
6721 #define TestImpl(Prefix) \
6722 do { \
6723 static constexpr uint8_t ByteCount = 1; \
6724 __ emitSegmentOverride(Prefix); \
6725 ASSERT_EQ(ByteCount, codeBytesSize()) << Prefix; \
6726 verifyBytes<ByteCount>(codeBytes(), Prefix); \
6727 reset(); \
6728 } while (0)
6729
6730 TestImpl(0x26);
6731 TestImpl(0x2E);
6732 TestImpl(0x36);
6733 TestImpl(0x3E);
6734 TestImpl(0x64);
6735 TestImpl(0x65);
6736 TestImpl(0x66);
6737 TestImpl(0x67);
6738
6739 #undef TestImpl
6740 }
6741
6742 TEST_F(AssemblerX8664Test, Cmpxchg8b) {
6743 static constexpr bool NotLocked = false;
6744 static constexpr bool Locked = true;
6745
6746 #define TestImpl(Value0, Value1, ValueMem, LockedOrNot) \
6747 do { \
6748 static constexpr char TestString[] = \
6749 "(" #Value0 ", " #Value1 ", " #ValueMem ", " #LockedOrNot ")"; \
6750 const uint32_t T0 = allocateQword(); \
6751 static constexpr uint64_t V0 = ValueMem; \
6752 const uint32_t ZeroFlag = allocateDword(); \
6753 \
6754 __ mov(IceType_i32, GPRRegister::Encoded_Reg_eax, \
6755 Immediate(uint64_t(Value0) & 0xFFFFFFFF)); \
6756 __ mov(IceType_i32, GPRRegister::Encoded_Reg_edx, \
6757 Immediate(uint64_t(Value0) >> 32)); \
6758 __ mov(IceType_i32, GPRRegister::Encoded_Reg_ebx, \
6759 Immediate(uint64_t(Value1) & 0xFFFFFFFF)); \
6760 __ mov(IceType_i32, GPRRegister::Encoded_Reg_ecx, \
6761 Immediate(uint64_t(Value1) >> 32)); \
6762 __ cmpxchg8b(dwordAddress(T0), LockedOrNot); \
6763 __ setcc(Cond::Br_e, dwordAddress(ZeroFlag)); \
6764 \
6765 AssembledTest test = assemble(); \
6766 test.setQwordTo(T0, V0); \
6767 test.setDwordTo(ZeroFlag, uint32_t(0xFF)); \
6768 test.run(); \
6769 \
6770 if (V0 == (Value0)) { \
6771 ASSERT_EQ(uint64_t(Value1), test.contentsOfQword(T0)) << TestString; \
6772 ASSERT_EQ(1u, test.contentsOfDword(ZeroFlag)) << TestString; \
6773 } else { \
6774 ASSERT_EQ(uint64_t(ValueMem) & 0xFFFFFFFF, test.eax()) << TestString; \
6775 ASSERT_EQ((uint64_t(ValueMem) >> 32) & 0xFFFFFFFF, test.edx()) \
6776 << TestString; \
6777 ASSERT_EQ(0u, test.contentsOfDword(ZeroFlag)) << TestString; \
6778 } \
6779 reset(); \
6780 } while (0)
6781
6782 TestImpl(0x98987676543210ull, 0x1, 0x98987676543210ull, NotLocked);
6783 TestImpl(0x98987676543210ull, 0x1, 0x98987676543210ull, Locked);
6784 TestImpl(0x98987676543210ull, 0x1, 0x98987676543211ull, NotLocked);
6785 TestImpl(0x98987676543210ull, 0x1, 0x98987676543211ull, Locked);
6786
6787 #undef TestImpl
6788 }
6789
6790 TEST_F(AssemblerX8664LowLevelTest, Cmpxchg8b) {
6791 static constexpr bool NotLocked = false;
6792 static constexpr bool Locked = true;
6793
6794 // Ensures that cmpxchg8b emits a lock prefix accordingly.
6795 __ cmpxchg8b(Address::Absolute(0x1FF00), NotLocked);
6796 static constexpr uint8_t ByteCountNotLocked = 7;
6797 ASSERT_EQ(ByteCountNotLocked, codeBytesSize());
6798 verifyBytes<ByteCountNotLocked>(codeBytes(), 0x0F, 0xC7, 0x0D, 0x00, 0xFF,
6799 0x01, 0x00);
6800 reset();
6801
6802 __ cmpxchg8b(Address::Absolute(0x1FF00), Locked);
6803 static constexpr uint8_t ByteCountLocked = 1 + ByteCountNotLocked;
6804 ASSERT_EQ(ByteCountLocked, codeBytesSize());
6805 verifyBytes<ByteCountLocked>(codeBytes(), 0xF0, 0x0F, 0xC7, 0x0D, 0x00, 0xFF,
6806 0x01, 0x00);
6807 reset();
6808 }
6809
6810 TEST_F(AssemblerX8664Test, Cmpxchg) {
6811 static constexpr bool NotLocked = false;
6812 static constexpr bool Locked = true;
6813
6814 static constexpr uint32_t Mask8 = 0x000000FF;
6815 static constexpr uint32_t Mask16 = 0x0000FFFF;
6816 static constexpr uint32_t Mask32 = 0xFFFFFFFF;
6817
6818 #define TestImplAddrReg(Value0, Src, Value1, ValueMem, LockedOrNot, Size) \
6819 do { \
6820 static constexpr char TestString[] = \
6821 "(" #Value0 ", " #Src ", " #Value1 ", " #ValueMem ", " #LockedOrNot \
6822 ", " #Size ")"; \
6823 const uint32_t T0 = allocateDword(); \
6824 static constexpr uint32_t V0 = (ValueMem)&Mask##Size; \
6825 const uint32_t ZeroFlag = allocateDword(); \
6826 \
6827 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_eax, \
6828 Immediate((Value0)&Mask##Size)); \
6829 __ mov(IceType_i##Size, GPRRegister::Encoded_Reg_##Src, \
6830 Immediate((Value1)&Mask##Size)); \
6831 __ cmpxchg(IceType_i##Size, dwordAddress(T0), \
6832 GPRRegister::Encoded_Reg_##Src, LockedOrNot); \
6833 __ setcc(Cond::Br_e, dwordAddress(ZeroFlag)); \
6834 \
6835 AssembledTest test = assemble(); \
6836 test.setDwordTo(T0, V0); \
6837 test.setDwordTo(ZeroFlag, uint32_t(0xFF)); \
6838 test.run(); \
6839 \
6840 if (V0 == (Mask##Size & (Value0))) { \
6841 ASSERT_EQ(uint32_t((Value1)&Mask##Size), test.contentsOfDword(T0)) \
6842 << TestString; \
6843 ASSERT_EQ(1u, test.contentsOfDword(ZeroFlag)) << TestString; \
6844 } else { \
6845 ASSERT_EQ(uint32_t((ValueMem)&Mask##Size), test.eax()) << TestString; \
6846 ASSERT_EQ(0u, test.contentsOfDword(ZeroFlag)) << TestString; \
6847 } \
6848 reset(); \
6849 } while (0)
6850
6851 #define TestImplValue(Value0, Src, Value1, ValueMem, LockedOrNot) \
6852 do { \
6853 if (GPRRegister::Encoded_Reg_##Src < 4) { \
6854 TestImplAddrReg(Value0, Src, Value1, ValueMem, LockedOrNot, 8); \
6855 } \
6856 TestImplAddrReg(Value0, Src, Value1, ValueMem, LockedOrNot, 16); \
6857 TestImplAddrReg(Value0, Src, Value1, ValueMem, LockedOrNot, 32); \
6858 } while (0)
6859
6860 #define TestImpl(Src, LockedOrNot) \
6861 do { \
6862 TestImplValue(0xFFFFFFFF, Src, 0x1, 0xFFFFFFFF, LockedOrNot); \
6863 TestImplValue(0x0FFF0F0F, Src, 0x1, 0xFFFFFFFF, LockedOrNot); \
6864 } while (0)
6865
6866 TestImpl(ebx, Locked);
6867 TestImpl(edx, NotLocked);
6868 TestImpl(ecx, Locked);
6869 TestImpl(ecx, NotLocked);
6870 TestImpl(edx, Locked);
6871 TestImpl(edx, NotLocked);
6872 TestImpl(esi, Locked);
6873 TestImpl(esi, NotLocked);
6874 TestImpl(edi, Locked);
6875 TestImpl(edi, NotLocked);
6876
6877 #undef TestImpl
6878 #undef TestImplValue
6879 #undef TestImplAddrReg
6880 }
6881
6882 TEST_F(AssemblerX8664LowLevelTest, Cmpxchg) {
6883 static constexpr bool NotLocked = false;
6884 static constexpr bool Locked = true;
6885
6886 // Ensures that cmpxchg emits a lock prefix accordingly.
6887 {
6888 __ cmpxchg(IceType_i8, Address::Absolute(0x1FF00),
6889 GPRRegister::Encoded_Reg_esi, NotLocked);
6890 static constexpr uint8_t ByteCountNotLocked8 = 7;
6891 ASSERT_EQ(ByteCountNotLocked8, codeBytesSize());
6892 verifyBytes<ByteCountNotLocked8>(codeBytes(), 0x0F, 0xB0, 0x35, 0x00, 0xFF,
6893 0x01, 0x00);
6894 reset();
6895
6896 __ cmpxchg(IceType_i8, Address::Absolute(0x1FF00),
6897 GPRRegister::Encoded_Reg_esi, Locked);
6898 static constexpr uint8_t ByteCountLocked8 = 1 + ByteCountNotLocked8;
6899 ASSERT_EQ(ByteCountLocked8, codeBytesSize());
6900 verifyBytes<ByteCountLocked8>(codeBytes(), 0xF0, 0x0F, 0xB0, 0x35, 0x00,
6901 0xFF, 0x01, 0x00);
6902 reset();
6903 }
6904
6905 {
6906 __ cmpxchg(IceType_i16, Address::Absolute(0x1FF00),
6907 GPRRegister::Encoded_Reg_esi, NotLocked);
6908 static constexpr uint8_t ByteCountNotLocked16 = 8;
6909 ASSERT_EQ(ByteCountNotLocked16, codeBytesSize());
6910 verifyBytes<ByteCountNotLocked16>(codeBytes(), 0x66, 0x0F, 0xB1, 0x35, 0x00,
6911 0xFF, 0x01, 0x00);
6912 reset();
6913
6914 __ cmpxchg(IceType_i16, Address::Absolute(0x1FF00),
6915 GPRRegister::Encoded_Reg_esi, Locked);
6916 static constexpr uint8_t ByteCountLocked16 = 1 + ByteCountNotLocked16;
6917 ASSERT_EQ(ByteCountLocked16, codeBytesSize());
6918 verifyBytes<ByteCountLocked16>(codeBytes(), 0x66, 0xF0, 0x0F, 0xB1, 0x35,
6919 0x00, 0xFF, 0x01, 0x00);
6920 reset();
6921 }
6922
6923 {
6924 __ cmpxchg(IceType_i32, Address::Absolute(0x1FF00),
6925 GPRRegister::Encoded_Reg_esi, NotLocked);
6926 static constexpr uint8_t ByteCountNotLocked32 = 7;
6927 ASSERT_EQ(ByteCountNotLocked32, codeBytesSize());
6928 verifyBytes<ByteCountNotLocked32>(codeBytes(), 0x0F, 0xB1, 0x35, 0x00, 0xFF,
6929 0x01, 0x00);
6930 reset();
6931
6932 __ cmpxchg(IceType_i32, Address::Absolute(0x1FF00),
6933 GPRRegister::Encoded_Reg_esi, Locked);
6934 static constexpr uint8_t ByteCountLocked32 = 1 + ByteCountNotLocked32;
6935 ASSERT_EQ(ByteCountLocked32, codeBytesSize());
6936 verifyBytes<ByteCountLocked32>(codeBytes(), 0xF0, 0x0F, 0xB1, 0x35, 0x00,
6937 0xFF, 0x01, 0x00);
6938 reset();
6939 }
6940 }
6941
6942 TEST_F(AssemblerX8664Test, Set1ps) {
6943 #define TestImpl(Xmm, Src, Imm) \
6944 do { \
6945 __ set1ps(XmmRegister::Encoded_Reg_##Xmm, GPRRegister::Encoded_Reg_##Src, \
6946 Immediate(Imm)); \
6947 \
6948 AssembledTest test = assemble(); \
6949 test.run(); \
6950 \
6951 const Dqword Expected((uint64_t(Imm) << 32) | uint32_t(Imm), \
6952 (uint64_t(Imm) << 32) | uint32_t(Imm)); \
6953 ASSERT_EQ(Expected, test.Xmm<Dqword>()) \
6954 << "(" #Xmm ", " #Src ", " #Imm ")"; \
6955 reset(); \
6956 } while (0)
6957
6958 TestImpl(xmm0, ebx, 1);
6959 TestImpl(xmm1, ecx, 2);
6960 TestImpl(xmm2, edx, 3);
6961 TestImpl(xmm3, esi, 4);
6962 TestImpl(xmm4, edi, 5);
6963 TestImpl(xmm5, eax, 6);
6964 TestImpl(xmm6, ebx, 7);
6965 TestImpl(xmm7, ecx, 8);
6966
6967 #undef TestImpl
6968 }
6969
6970 #undef __
6971
6972 } // end of anonymous namespace
6973 } // end of namespace X8664
6974 } // end of namespace Ice
OLDNEW
« unittest/IceAssemblerX8632Test.cpp ('K') | « unittest/IceAssemblerX8632Test.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698