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

Side by Side Diff: unittest/IceAssemblerX8632Test.cpp

Issue 1231903002: Adds tests to the AssemblerX8632. (Closed) Base URL: https://chromium.googlesource.com/native_client/pnacl-subzero.git@master
Patch Set: Better tests -- please disregard previous patches! 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
« no previous file with comments | « src/IceAssemblerX86Base.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 //===- subzero/unittest/IceAssemblerX8632.cpp - X8632 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 "IceAssemblerX8632.h"
11
12 #include "IceDefs.h"
13
14 #include "gtest/gtest.h"
15
16 #include <cstring>
17 #include <errno.h>
18 #include <iostream>
19 #include <memory>
20 #include <sys/mman.h>
21 #include <type_traits>
22
23 namespace Ice {
24 namespace X8632 {
25 namespace {
26
27 class AssemblerX8632TestBase : public ::testing::Test {
28 protected:
29 using Address = AssemblerX8632::Traits::Address;
30 using Cond = AssemblerX8632::Traits::Cond;
31 using GPRRegister = AssemblerX8632::Traits::GPRRegister;
32 using XmmRegister = AssemblerX8632::Traits::XmmRegister;
33 using X87STRegister = AssemblerX8632::Traits::X87STRegister;
34
35 AssemblerX8632TestBase() { reset(); }
36
37 void reset() { Assembler.reset(new AssemblerX8632()); }
38
39 AssemblerX8632 *assembler() const { return Assembler.get(); }
40
41 size_t codeBytesSize() const { return Assembler->getBufferView().size(); }
42
43 const uint8_t *codeBytes() const {
44 return static_cast<const uint8_t *>(
45 static_cast<const void *>(Assembler->getBufferView().data()));
46 }
47
48 private:
49 std::unique_ptr<AssemblerX8632> Assembler;
50 };
51
52 // __ is a helper macro. It allows test cases to emit X8632 assembly
53 // instructions with
54 //
55 // __ ret();
jvoung (off chromium) 2015/07/10 18:17:31 Maybe the example should have __ ret() after, sinc
John 2015/07/10 23:26:36 A very unfortunate example. Done.
56 // __ mov(GPRRegister::Reg_Eax, 1);
57 //
58 // and so on. The idea of having this was "stolen" from dart's unit tests.
59 #define __ (this->assembler())->
60
61 // AssemblerX8632LowLevelTest verify that the "basic" instructions the tests
62 // rely on are encoded correctly. Therefore, instead of executing the assembled
63 // code, these tests will verify that the assembled bytes are sane.
64 class AssemblerX8632LowLevelTest : public AssemblerX8632TestBase {
65 protected:
66 // verifyBytes is a template helper that takes a Buffer, and a variable number
67 // of bytes. As the name indicates, it is used to verify the bytes for an
68 // instruction encoding.
69 template <int N, int I> static void verifyBytes(const uint8_t *) {
70 static_assert(I == N, "Invalid template instantiation.");
71 }
72
73 template <int N, int I = 0, typename... Args>
74 static void verifyBytes(const uint8_t *Buffer, uint8_t Byte,
75 Args... OtherBytes) {
76 static_assert(I < N, "Invalid template instantiation.");
77 EXPECT_EQ(Byte, Buffer[I]) << "Byte " << (I + 1) << " of " << N;
78 verifyBytes<N, I + 1>(Buffer, OtherBytes...);
79 assert(Buffer[I] == Byte);
jvoung (off chromium) 2015/07/10 18:17:31 What's the need for this latter assert, if there i
John 2015/07/10 23:26:36 Yes, exactly: I want verifyBytes to report all err
80 }
81 };
82
83 TEST_F(AssemblerX8632LowLevelTest, Ret) {
84 __ ret();
85
86 constexpr size_t ByteCount = 1;
87 EXPECT_EQ(ByteCount, codeBytesSize());
88 assert(ByteCount == codeBytesSize());
jvoung (off chromium) 2015/07/10 18:17:31 Question for here and below -- why not use ASSERT_
John 2015/07/10 23:26:36 I don't like ASSERT_<<cond>>, they only work withi
89
90 verifyBytes<ByteCount>(codeBytes(), 0xc3);
91 }
92
93 TEST_F(AssemblerX8632LowLevelTest, CallImm4) {
94 __ call(Immediate(4));
95
96 constexpr size_t ByteCount = 5;
97 EXPECT_EQ(ByteCount, codeBytesSize());
98 assert(ByteCount == codeBytesSize());
99
100 verifyBytes<ByteCount>(codeBytes(), 0xe8, 0x00, 0x00, 0x00, 0x00);
101 }
102
103 TEST_F(AssemblerX8632LowLevelTest, PushRegs) {
104 __ popl(GPRRegister::Encoded_Reg_eax);
jvoung (off chromium) 2015/07/10 18:17:32 This test is called PushRegs, but the method used
John 2015/07/10 23:26:36 I was tired... Done.
105 __ popl(GPRRegister::Encoded_Reg_ebx);
106 __ popl(GPRRegister::Encoded_Reg_ecx);
107 __ popl(GPRRegister::Encoded_Reg_edx);
108 __ popl(GPRRegister::Encoded_Reg_edi);
109 __ popl(GPRRegister::Encoded_Reg_esi);
110 __ popl(GPRRegister::Encoded_Reg_ebp);
111
112 constexpr size_t ByteCount = 7;
113 EXPECT_EQ(ByteCount, codeBytesSize());
114 assert(ByteCount == codeBytesSize());
115
116 constexpr uint8_t PushOpcode = 0x58;
jvoung (off chromium) 2015/07/10 18:17:31 PopOpcode?
John 2015/07/10 23:26:36 Done.
117 verifyBytes<ByteCount>(codeBytes(), PushOpcode | GPRRegister::Encoded_Reg_eax,
118 PushOpcode | GPRRegister::Encoded_Reg_ebx,
119 PushOpcode | GPRRegister::Encoded_Reg_ecx,
120 PushOpcode | GPRRegister::Encoded_Reg_edx,
121 PushOpcode | GPRRegister::Encoded_Reg_edi,
122 PushOpcode | GPRRegister::Encoded_Reg_esi,
123 PushOpcode | GPRRegister::Encoded_Reg_ebp);
124 }
125
126 TEST_F(AssemblerX8632LowLevelTest, PopRegs) {
jvoung (off chromium) 2015/07/10 18:17:31 Rename this to "PushRegs"?
John 2015/07/10 23:26:36 Done.
127 __ pushl(GPRRegister::Encoded_Reg_eax);
128 __ pushl(GPRRegister::Encoded_Reg_ebx);
129 __ pushl(GPRRegister::Encoded_Reg_ecx);
130 __ pushl(GPRRegister::Encoded_Reg_edx);
131 __ pushl(GPRRegister::Encoded_Reg_edi);
132 __ pushl(GPRRegister::Encoded_Reg_esi);
133 __ pushl(GPRRegister::Encoded_Reg_ebp);
134
135 constexpr size_t ByteCount = 7;
136 EXPECT_EQ(ByteCount, codeBytesSize());
137 assert(ByteCount == codeBytesSize());
138
139 constexpr uint8_t PopOpcode = 0x50;
140 verifyBytes<ByteCount>(codeBytes(), PopOpcode | GPRRegister::Encoded_Reg_eax,
141 PopOpcode | GPRRegister::Encoded_Reg_ebx,
142 PopOpcode | GPRRegister::Encoded_Reg_ecx,
143 PopOpcode | GPRRegister::Encoded_Reg_edx,
144 PopOpcode | GPRRegister::Encoded_Reg_edi,
145 PopOpcode | GPRRegister::Encoded_Reg_esi,
146 PopOpcode | GPRRegister::Encoded_Reg_ebp);
147 }
148
149 TEST_F(AssemblerX8632LowLevelTest, MovRegisterZero) {
150 __ mov(IceType_i32, GPRRegister::Encoded_Reg_eax, Immediate(0x00));
151 __ mov(IceType_i32, GPRRegister::Encoded_Reg_ebx, Immediate(0x00));
152 __ mov(IceType_i32, GPRRegister::Encoded_Reg_ecx, Immediate(0x00));
153 __ mov(IceType_i32, GPRRegister::Encoded_Reg_edx, Immediate(0x00));
154 __ mov(IceType_i32, GPRRegister::Encoded_Reg_edi, Immediate(0x00));
155 __ mov(IceType_i32, GPRRegister::Encoded_Reg_esi, Immediate(0x00));
156
157 constexpr size_t MovReg32BitImmBytes = 5;
158 constexpr size_t ByteCount = 6 * MovReg32BitImmBytes;
159 EXPECT_EQ(ByteCount, codeBytesSize());
160 assert(ByteCount == codeBytesSize());
161
162 constexpr uint8_t MovOpcode = 0xb8;
163 verifyBytes<ByteCount>(
164 codeBytes(), MovOpcode | GPRRegister::Encoded_Reg_eax, 0x00, 0x00, 0x00,
165 0x00, MovOpcode | GPRRegister::Encoded_Reg_ebx, 0x00, 0x00, 0x00, 0x00,
166 MovOpcode | GPRRegister::Encoded_Reg_ecx, 0x00, 0x00, 0x00, 0x00,
167 MovOpcode | GPRRegister::Encoded_Reg_edx, 0x00, 0x00, 0x00, 0x00,
168 MovOpcode | GPRRegister::Encoded_Reg_edi, 0x00, 0x00, 0x00, 0x00,
169 MovOpcode | GPRRegister::Encoded_Reg_esi, 0x00, 0x00, 0x00, 0x00);
170 }
171
172 TEST_F(AssemblerX8632LowLevelTest, CmpRegReg) {
173 __ cmp(IceType_i32, GPRRegister::Encoded_Reg_eax,
174 GPRRegister::Encoded_Reg_ebx);
175 __ cmp(IceType_i32, GPRRegister::Encoded_Reg_ebx,
176 GPRRegister::Encoded_Reg_ecx);
177 __ cmp(IceType_i32, GPRRegister::Encoded_Reg_ecx,
178 GPRRegister::Encoded_Reg_edx);
179 __ cmp(IceType_i32, GPRRegister::Encoded_Reg_edx,
180 GPRRegister::Encoded_Reg_edi);
181 __ cmp(IceType_i32, GPRRegister::Encoded_Reg_edi,
182 GPRRegister::Encoded_Reg_esi);
183 __ cmp(IceType_i32, GPRRegister::Encoded_Reg_esi,
184 GPRRegister::Encoded_Reg_eax);
185
186 const size_t CmpRegRegBytes = 2;
187 const size_t ByteCount = 6 * CmpRegRegBytes;
188 EXPECT_EQ(ByteCount, codeBytesSize());
189 assert(ByteCount == codeBytesSize());
190
191 constexpr size_t CmpOpcode = 0x3b;
192 constexpr size_t ModRm = 0xC0 /* Register Addressing */;
193 verifyBytes<ByteCount>(
194 codeBytes(), CmpOpcode, ModRm | (GPRRegister::Encoded_Reg_eax << 3) |
195 GPRRegister::Encoded_Reg_ebx,
196 CmpOpcode, ModRm | (GPRRegister::Encoded_Reg_ebx << 3) |
197 GPRRegister::Encoded_Reg_ecx,
198 CmpOpcode, ModRm | (GPRRegister::Encoded_Reg_ecx << 3) |
199 GPRRegister::Encoded_Reg_edx,
200 CmpOpcode, ModRm | (GPRRegister::Encoded_Reg_edx << 3) |
201 GPRRegister::Encoded_Reg_edi,
202 CmpOpcode, ModRm | (GPRRegister::Encoded_Reg_edi << 3) |
203 GPRRegister::Encoded_Reg_esi,
204 CmpOpcode, ModRm | (GPRRegister::Encoded_Reg_esi << 3) |
205 GPRRegister::Encoded_Reg_eax);
206 }
207
208 // After these tests we should have a sane environment; we know the following
209 // work:
210 //
211 // (*) zeroing eax, ebx, ecx, edx, edi, and esi;
212 // (*) call $4 instruction (used for ip materialization);
213 // (*) register push and pop;
214 // (*) cmp reg, reg; and
215 // (*) returning from functions.
216 //
217 // We can now dive into testing each emitting method in AssemblerX8632. Each
218 // test will emit some instructions performing the test. The assembled
219 // instructions will operate in a "safe" environment. In particular, all
220 // registers (except for esp, and ebp) will be zeroed out before they are
221 // executed. ebp will be used as a frame pointer so the jitted routine has a
222 // temporary scratch memory; and esp will not be modified (i.e., the test
223 // function will use the same stack as the program running the tests.
224 //
225 // Upon return from the jitted code, an epilogue will save the final register
226 // values before restoring them.
227 //
228 // The jitted code will look like the following:
229 //
230 // test:
231 // push %eax
232 // push %ebx
233 // push %ecx
234 // push %edx
235 // push %edi
236 // push %esi
237 // push %ebp
238 // call test$materialize_ip
239 // test$materialize_ip:
240 // mov $0, %eax
241 // mov $0, %ebx
242 // mov $0, %ecx
243 // mov $0, %edx
244 // mov $0, %edi
245 // mov $0, %esi
246 // pop %ebp
jvoung (off chromium) 2015/07/10 18:17:32 __ popl(GPRRegister::Encoded_Reg_ebp) in the code
John 2015/07/10 23:26:36 Done.
247 //
248 // << test code goes here >>
249 //
250 // mov %eax, $(1M + 0 - (test$materialize_ip - test))(%ebp,,)
jvoung (off chromium) 2015/07/10 18:17:31 nit: indentation seems to change here (not sure if
jvoung (off chromium) 2015/07/10 18:17:32 I think these slots need a bit more explanation.
John 2015/07/10 23:26:36 Done.
John 2015/07/10 23:26:36 But I already explain about the scratchpad area ab
251 // mov %ebx, $(1M + 4 - (test$materialize_ip - test))(%ebp,,)
252 // mov %ecx, $(1M + 8 - (test$materialize_ip - test))(%ebp,,)
253 // mov %edx, $(1M + 12 - (test$materialize_ip - test))(%ebp,,)
254 // mov %edi, $(1M + 16 - (test$materialize_ip - test))(%ebp,,)
255 // mov %esi, $(1M + 20 - (test$materialize_ip - test))(%ebp,,)
256 //
257 // pop %ebp
258 // pop %esi
259 // pop %edi
260 // pop %edx
261 // pop %ecx
262 // pop %ebx
263 // pop %eax
264 // ret
265 //
266 // This instruction sequence allows the AssemblerX8632 test to be run in both
267 // X86-32 and X86-64 hosts. In particular, the first
268 //
269 // pop %ebp
270 //
271 // instruction will populate ebp in x86-32 and rbp in x86-64 with the return
272 // address pushed by the call to test$materialize_ip, which will have the
273 // appropriate size. To prevent the upper 32 bits from being cleared in x86-64,
274 // the jitted code should not perform any arithmetic with ebp (not that
jvoung (off chromium) 2015/07/10 18:17:32 not that -> note that
John 2015/07/10 23:26:36 Done.
275 // specifying a displacement in the addressing mode is OK -- immediates are
276 // sign-extenteded.)
jvoung (off chromium) 2015/07/10 18:17:32 extenteded -> extended
John 2015/07/10 23:26:36 Done.
277 //
278 // TODO(jpp): test the
279 //
280 // mov %reg, slot
281 //
282 // encodings using the low level assembler test.
283 class AssemblerX8632Test : public AssemblerX8632TestBase {
284 protected:
285 AssemblerX8632Test() { reset(); }
286
287 void reset() {
288 AssemblerX8632TestBase::reset();
289
290 NeedsEpilogue = true;
291 // 6 dwords are allocated for saving the GPR state after the jitted code
292 // runs.
293 NumAllocatedDwords = 6;
294 addPrologue();
295 }
296
297 // AssembledBuffer is a wrapper around a PROT_EXEC mmap'ed buffer. This buffer
298 // contains both the test code as well as prologue/epilogue, and the
299 // scratchpad area that tests may use -- all tests use this scraychpad area
jvoung (off chromium) 2015/07/10 18:17:32 scraychpad -> scratchpad
John 2015/07/10 23:26:36 Done.
300 // for storing the processor's registers after the tests executed. This class
301 // also exposes helper methods for reading the register state after test
302 // execution, as well as for reading the scratchpad area.
303 class AssembledBuffer {
304 AssembledBuffer() = delete;
305 AssembledBuffer(const AssembledBuffer &) = delete;
306 AssembledBuffer &operator=(const AssembledBuffer &) = delete;
307
308 public:
309 static constexpr uint32_t MaximumCodeSize = 1 << 20;
310 static constexpr uint32_t EaxSlot = 0;
311 static constexpr uint32_t EbxSlot = 1;
312 static constexpr uint32_t EcxSlot = 2;
313 static constexpr uint32_t EdxSlot = 3;
314 static constexpr uint32_t EdiSlot = 4;
315 static constexpr uint32_t EsiSlot = 5;
316
317 explicit AssembledBuffer(const uint8_t *Data, const size_t MySize,
jvoung (off chromium) 2015/07/10 18:17:32 doesn't need "explicit" w/ multiple params?
John 2015/07/10 23:26:36 Done.
318 const size_t ExtraStorageDwords)
319 : Size(MaximumCodeSize + 4 * ExtraStorageDwords) {
320 // MaxCodeSize is needed because EXPECT_LT needs a symbol with a name --
321 // probably a compiler bug?
322 uint32_t MaxCodeSize = MaximumCodeSize;
323 EXPECT_LT(MySize, MaxCodeSize);
324 assert(MySize < MaximumCodeSize);
325 ExecutableData = mmap(nullptr, Size, PROT_WRITE | PROT_READ | PROT_EXEC,
326 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
327 EXPECT_NE(MAP_FAILED, ExecutableData) << strerror(errno);
328 assert(MAP_FAILED != ExecutableData);
329 std::memcpy(ExecutableData, Data, MySize);
330 }
331
332 // We allow AssembledBuffer to be moved so that we can return objects of
333 // this type.
334 AssembledBuffer(AssembledBuffer &&Buffer)
335 : ExecutableData(Buffer.ExecutableData), Size(Buffer.Size) {
336 Buffer.ExecutableData = nullptr;
337 Buffer.Size = 0;
338 }
339
340 AssembledBuffer &operator=(AssembledBuffer &&Buffer) {
341 ExecutableData = Buffer.ExecutableData;
342 Buffer.ExecutableData = nullptr;
343 Size = Buffer.Size;
344 Buffer.Size = 0;
345 return *this;
346 }
347
348 ~AssembledBuffer() {
349 if (ExecutableData != nullptr) {
350 munmap(ExecutableData, Size);
351 ExecutableData = nullptr;
352 }
353 }
354
355 void run() const { reinterpret_cast<void (*)()>(ExecutableData)(); }
356
357 uint32_t eax() const { return contentsOfDword(AssembledBuffer::EaxSlot); }
358
359 uint32_t ebx() const { return contentsOfDword(AssembledBuffer::EbxSlot); }
360
361 uint32_t ecx() const { return contentsOfDword(AssembledBuffer::EcxSlot); }
362
363 uint32_t edx() const { return contentsOfDword(AssembledBuffer::EdxSlot); }
364
365 uint32_t edi() const { return contentsOfDword(AssembledBuffer::EdiSlot); }
366
367 uint32_t esi() const { return contentsOfDword(AssembledBuffer::EsiSlot); }
368
369 // contentsOfDword is used for reading the values in the scratchpad area.
370 // Valid arguments are the dword ids returned by
371 // AssemblerX8632Test::allocateDword() -- other inputs are considered
372 // invalid, and are not guaranteed to work if the implementation changes.
373 uint32_t contentsOfDword(uint32_t Dword) const {
374 return *reinterpret_cast<uint32_t *>(
375 static_cast<uint8_t *>(ExecutableData) + dwordOffset(Dword));
376 }
377
378 private:
379 static uint32_t dwordOffset(uint32_t Index) {
380 return MaximumCodeSize + (Index * 4);
381 }
382
383 void *ExecutableData = nullptr;
384 size_t Size;
385 };
386
387 // assemble created an AssembledBuffer with the jitted code. The first time
388 // assemble is executed it will add the epilogue to the jitted code (which is
389 // the reason why this method is not const qualified.
390 AssembledBuffer assemble() {
391 if (NeedsEpilogue) {
jvoung (off chromium) 2015/07/10 18:17:32 Is it ever kosher to run assemble() twice?
John 2015/07/10 23:26:36 Yes! :) assemble **could** be a const method, if
392 addEpilogue();
393 }
394
395 NeedsEpilogue = false;
396 return AssembledBuffer(codeBytes(), codeBytesSize(), NumAllocatedDwords);
397 }
398
399 // Allocates a new dword slot in the test's scratchpad area.
400 uint32_t allocateDword() { return NumAllocatedDwords++; }
401
402 Address dwordAddress(uint32_t Dword) {
403 return Address(GPRRegister::Encoded_Reg_ebp, dwordDisp(Dword));
404 }
405
406 private:
407 // e??SlotAddress returns an AssemblerX8632::Traits::Address that can be used
408 // by the test cases to encode an address operand for accessing the slot for
409 // the spcified register. These are all private for, when jitting the test
jvoung (off chromium) 2015/07/10 18:17:32 spcified -> specified
John 2015/07/10 23:26:36 Done.
410 // code, tests should not tamper with these values. Besides, during the test
411 // execution these slots' contents are undefined and should not be accessed.
412 Address eaxSlotAddress() { return dwordAddress(AssembledBuffer::EaxSlot); }
413 Address ebxSlotAddress() { return dwordAddress(AssembledBuffer::EbxSlot); }
414 Address ecxSlotAddress() { return dwordAddress(AssembledBuffer::EcxSlot); }
415 Address edxSlotAddress() { return dwordAddress(AssembledBuffer::EdxSlot); }
416 Address ediSlotAddress() { return dwordAddress(AssembledBuffer::EdiSlot); }
417 Address esiSlotAddress() { return dwordAddress(AssembledBuffer::EsiSlot); }
418
419 // Returns the displacement that should be used when accessing the specified
420 // Dword in the scratchpad area. It needs to adjust for the initial
421 // instructions that are emitted before the call that materializes the IP
422 // register.
423 uint32_t dwordDisp(uint32_t Dword) const {
424 EXPECT_LT(Dword, NumAllocatedDwords);
425 assert(Dword < NumAllocatedDwords);
426 static constexpr uint8_t PushBytes = 1;
427 static constexpr uint8_t CallImmBytes = 5;
428 return AssembledBuffer::MaximumCodeSize + (Dword * 4) -
429 (7 * PushBytes + CallImmBytes);
430 }
431
432 void addPrologue() {
433 __ pushl(GPRRegister::Encoded_Reg_eax);
434 __ pushl(GPRRegister::Encoded_Reg_ebx);
435 __ pushl(GPRRegister::Encoded_Reg_ecx);
436 __ pushl(GPRRegister::Encoded_Reg_edx);
437 __ pushl(GPRRegister::Encoded_Reg_edi);
438 __ pushl(GPRRegister::Encoded_Reg_esi);
439 __ pushl(GPRRegister::Encoded_Reg_ebp);
440
441 __ call(Immediate(4));
442 __ popl(GPRRegister::Encoded_Reg_ebp);
443 __ mov(IceType_i32, GPRRegister::Encoded_Reg_eax, Immediate(0x00));
444 __ mov(IceType_i32, GPRRegister::Encoded_Reg_ebx, Immediate(0x00));
445 __ mov(IceType_i32, GPRRegister::Encoded_Reg_ecx, Immediate(0x00));
446 __ mov(IceType_i32, GPRRegister::Encoded_Reg_edx, Immediate(0x00));
447 __ mov(IceType_i32, GPRRegister::Encoded_Reg_edi, Immediate(0x00));
448 __ mov(IceType_i32, GPRRegister::Encoded_Reg_esi, Immediate(0x00));
449 }
450
451 void addEpilogue() {
452 __ mov(IceType_i32, eaxSlotAddress(), GPRRegister::Encoded_Reg_eax);
453 __ mov(IceType_i32, ebxSlotAddress(), GPRRegister::Encoded_Reg_ebx);
454 __ mov(IceType_i32, ecxSlotAddress(), GPRRegister::Encoded_Reg_ecx);
455 __ mov(IceType_i32, edxSlotAddress(), GPRRegister::Encoded_Reg_edx);
456 __ mov(IceType_i32, ediSlotAddress(), GPRRegister::Encoded_Reg_edi);
457 __ mov(IceType_i32, esiSlotAddress(), GPRRegister::Encoded_Reg_esi);
458
459 __ popl(GPRRegister::Encoded_Reg_ebp);
460 __ popl(GPRRegister::Encoded_Reg_esi);
461 __ popl(GPRRegister::Encoded_Reg_edi);
462 __ popl(GPRRegister::Encoded_Reg_edx);
463 __ popl(GPRRegister::Encoded_Reg_ecx);
464 __ popl(GPRRegister::Encoded_Reg_ebx);
465 __ popl(GPRRegister::Encoded_Reg_eax);
466
467 __ ret();
468 }
469
470 bool NeedsEpilogue;
471 uint32_t NumAllocatedDwords;
472 };
473
474 TEST_F(AssemblerX8632Test, MovRegImm) {
475 constexpr uint32_t ExpectedEax = 0x000000FFul;
476 constexpr uint32_t ExpectedEbx = 0x0000FF00ul;
477 constexpr uint32_t ExpectedEcx = 0x00FF0000ul;
478 constexpr uint32_t ExpectedEdx = 0xFF000000ul;
479 constexpr uint32_t ExpectedEdi = 0x6AAA0006ul;
480 constexpr uint32_t ExpectedEsi = 0x6000AAA6ul;
481
482 __ mov(IceType_i32, GPRRegister::Encoded_Reg_eax, Immediate(ExpectedEax));
483 __ mov(IceType_i32, GPRRegister::Encoded_Reg_ebx, Immediate(ExpectedEbx));
484 __ mov(IceType_i32, GPRRegister::Encoded_Reg_ecx, Immediate(ExpectedEcx));
485 __ mov(IceType_i32, GPRRegister::Encoded_Reg_edx, Immediate(ExpectedEdx));
486 __ mov(IceType_i32, GPRRegister::Encoded_Reg_edi, Immediate(ExpectedEdi));
487 __ mov(IceType_i32, GPRRegister::Encoded_Reg_esi, Immediate(ExpectedEsi));
488
489 AssembledBuffer test = assemble();
490 test.run();
491 EXPECT_EQ(ExpectedEax, test.eax());
492 EXPECT_EQ(ExpectedEbx, test.ebx());
493 EXPECT_EQ(ExpectedEcx, test.ecx());
494 EXPECT_EQ(ExpectedEdx, test.edx());
495 EXPECT_EQ(ExpectedEdi, test.edi());
496 EXPECT_EQ(ExpectedEsi, test.esi());
497 }
498
499 TEST_F(AssemblerX8632Test, MovMemImm) {
500 const uint32_t T0 = allocateDword();
501 constexpr uint32_t ExpectedT0 = 0x00111100ul;
502 const uint32_t T1 = allocateDword();
503 constexpr uint32_t ExpectedT1 = 0x00222200ul;
504 const uint32_t T2 = allocateDword();
505 constexpr uint32_t ExpectedT2 = 0x03333000ul;
506 const uint32_t T3 = allocateDword();
507 constexpr uint32_t ExpectedT3 = 0x00444400ul;
508
509 __ mov(IceType_i32, dwordAddress(T0), Immediate(ExpectedT0));
510 __ mov(IceType_i32, dwordAddress(T1), Immediate(ExpectedT1));
511 __ mov(IceType_i32, dwordAddress(T2), Immediate(ExpectedT2));
512 __ mov(IceType_i32, dwordAddress(T3), Immediate(ExpectedT3));
513
514 AssembledBuffer test = assemble();
515 test.run();
516 EXPECT_EQ(0ul, test.eax());
517 EXPECT_EQ(0ul, test.ebx());
518 EXPECT_EQ(0ul, test.ecx());
519 EXPECT_EQ(0ul, test.edx());
520 EXPECT_EQ(0ul, test.edi());
521 EXPECT_EQ(0ul, test.esi());
522 EXPECT_EQ(ExpectedT0, test.contentsOfDword(T0));
523 EXPECT_EQ(ExpectedT1, test.contentsOfDword(T1));
524 EXPECT_EQ(ExpectedT2, test.contentsOfDword(T2));
525 EXPECT_EQ(ExpectedT3, test.contentsOfDword(T3));
526 }
527
528 TEST_F(AssemblerX8632Test, MovMemReg) {
529 const uint32_t T0 = allocateDword();
530 constexpr uint32_t ExpectedT0 = 0x00111100ul;
531 const uint32_t T1 = allocateDword();
532 constexpr uint32_t ExpectedT1 = 0x00222200ul;
533 const uint32_t T2 = allocateDword();
534 constexpr uint32_t ExpectedT2 = 0x00333300ul;
535 const uint32_t T3 = allocateDword();
536 constexpr uint32_t ExpectedT3 = 0x00444400ul;
537 const uint32_t T4 = allocateDword();
538 constexpr uint32_t ExpectedT4 = 0x00555500ul;
539 const uint32_t T5 = allocateDword();
540 constexpr uint32_t ExpectedT5 = 0x00666600ul;
541
542 __ mov(IceType_i32, GPRRegister::Encoded_Reg_eax, Immediate(ExpectedT0));
543 __ mov(IceType_i32, dwordAddress(T0), GPRRegister::Encoded_Reg_eax);
544 __ mov(IceType_i32, GPRRegister::Encoded_Reg_ebx, Immediate(ExpectedT1));
545 __ mov(IceType_i32, dwordAddress(T1), GPRRegister::Encoded_Reg_ebx);
546 __ mov(IceType_i32, GPRRegister::Encoded_Reg_ecx, Immediate(ExpectedT2));
547 __ mov(IceType_i32, dwordAddress(T2), GPRRegister::Encoded_Reg_ecx);
548 __ mov(IceType_i32, GPRRegister::Encoded_Reg_edx, Immediate(ExpectedT3));
549 __ mov(IceType_i32, dwordAddress(T3), GPRRegister::Encoded_Reg_edx);
550 __ mov(IceType_i32, GPRRegister::Encoded_Reg_edi, Immediate(ExpectedT4));
551 __ mov(IceType_i32, dwordAddress(T4), GPRRegister::Encoded_Reg_edi);
552 __ mov(IceType_i32, GPRRegister::Encoded_Reg_esi, Immediate(ExpectedT5));
553 __ mov(IceType_i32, dwordAddress(T5), GPRRegister::Encoded_Reg_esi);
554
555 AssembledBuffer test = assemble();
556 test.run();
557 EXPECT_EQ(ExpectedT0, test.contentsOfDword(T0));
558 EXPECT_EQ(ExpectedT1, test.contentsOfDword(T1));
559 EXPECT_EQ(ExpectedT2, test.contentsOfDword(T2));
560 EXPECT_EQ(ExpectedT3, test.contentsOfDword(T3));
561 EXPECT_EQ(ExpectedT4, test.contentsOfDword(T4));
562 EXPECT_EQ(ExpectedT5, test.contentsOfDword(T5));
563 }
564
565 TEST_F(AssemblerX8632Test, MovRegReg) {
566 __ mov(IceType_i32, GPRRegister::Encoded_Reg_eax, Immediate(0x20));
567 __ mov(IceType_i32, GPRRegister::Encoded_Reg_ebx,
568 GPRRegister::Encoded_Reg_eax);
569 __ mov(IceType_i32, GPRRegister::Encoded_Reg_ecx,
570 GPRRegister::Encoded_Reg_ebx);
571 __ mov(IceType_i32, GPRRegister::Encoded_Reg_edx,
572 GPRRegister::Encoded_Reg_ecx);
573 __ mov(IceType_i32, GPRRegister::Encoded_Reg_edi,
574 GPRRegister::Encoded_Reg_edx);
575 __ mov(IceType_i32, GPRRegister::Encoded_Reg_esi,
576 GPRRegister::Encoded_Reg_edi);
577
578 __ mov(IceType_i32, GPRRegister::Encoded_Reg_esi, Immediate(0x55000000ul));
579 __ mov(IceType_i32, GPRRegister::Encoded_Reg_eax,
580 GPRRegister::Encoded_Reg_esi);
581
582 AssembledBuffer test = assemble();
583 test.run();
584 EXPECT_EQ(0x55000000ul, test.eax());
585 EXPECT_EQ(0x20ul, test.ebx());
586 EXPECT_EQ(0x20ul, test.ecx());
587 EXPECT_EQ(0x20ul, test.edx());
588 EXPECT_EQ(0x20ul, test.edi());
589 EXPECT_EQ(0x55000000ul, test.esi());
590 }
591
592 TEST_F(AssemblerX8632Test, MovRegMem) {
593 const uint32_t T0 = allocateDword();
594 constexpr uint32_t ExpectedT0 = 0x00111100ul;
595 const uint32_t T1 = allocateDword();
596 constexpr uint32_t ExpectedT1 = 0x00222200ul;
597 const uint32_t T2 = allocateDword();
598 constexpr uint32_t ExpectedT2 = 0x00333300ul;
599 const uint32_t T3 = allocateDword();
600 constexpr uint32_t ExpectedT3 = 0x00444400ul;
601 const uint32_t T4 = allocateDword();
602 constexpr uint32_t ExpectedT4 = 0x00555500ul;
603 const uint32_t T5 = allocateDword();
604 constexpr uint32_t ExpectedT5 = 0x00666600ul;
605
606 __ mov(IceType_i32, dwordAddress(T0), Immediate(ExpectedT0));
607 __ mov(IceType_i32, GPRRegister::Encoded_Reg_eax, dwordAddress(T0));
608
609 __ mov(IceType_i32, dwordAddress(T1), Immediate(ExpectedT1));
610 __ mov(IceType_i32, GPRRegister::Encoded_Reg_ebx, dwordAddress(T1));
611
612 __ mov(IceType_i32, dwordAddress(T2), Immediate(ExpectedT2));
613 __ mov(IceType_i32, GPRRegister::Encoded_Reg_ecx, dwordAddress(T2));
614
615 __ mov(IceType_i32, dwordAddress(T3), Immediate(ExpectedT3));
616 __ mov(IceType_i32, GPRRegister::Encoded_Reg_edx, dwordAddress(T3));
617
618 __ mov(IceType_i32, dwordAddress(T4), Immediate(ExpectedT4));
619 __ mov(IceType_i32, GPRRegister::Encoded_Reg_edi, dwordAddress(T4));
620
621 __ mov(IceType_i32, dwordAddress(T5), Immediate(ExpectedT5));
622 __ mov(IceType_i32, GPRRegister::Encoded_Reg_esi, dwordAddress(T5));
623
624 AssembledBuffer test = assemble();
625 test.run();
626 EXPECT_EQ(ExpectedT0, test.eax());
627 EXPECT_EQ(ExpectedT1, test.ebx());
628 EXPECT_EQ(ExpectedT2, test.ecx());
629 EXPECT_EQ(ExpectedT3, test.edx());
630 EXPECT_EQ(ExpectedT4, test.edi());
631 EXPECT_EQ(ExpectedT5, test.esi());
632 }
633
634 TEST_F(AssemblerX8632Test, J) {
635 #define TestJ(C, Near, Src0, Value0, Src1, Value1, Dest) \
636 do { \
637 const bool NearJmp = std::strcmp(#Near, "Near") == 0; \
638 Label ShouldBeTaken; \
639 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##Src0, Immediate(Value0)); \
640 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##Src1, Immediate(Value1)); \
641 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##Dest, Immediate(0)); \
jvoung (off chromium) 2015/07/10 18:17:32 How about set to something other than 0 (and other
John 2015/07/10 23:26:36 Done.
642 __ cmp(IceType_i32, GPRRegister::Encoded_Reg_##Src0, \
643 GPRRegister::Encoded_Reg_##Src1); \
644 __ j(Cond::Br_##C, &ShouldBeTaken, NearJmp); \
645 __ mov(IceType_i32, GPRRegister::Encoded_Reg_##Dest, Immediate(0xC0FFEE)); \
646 __ bind(&ShouldBeTaken); \
647 AssembledBuffer test = assemble(); \
648 test.run(); \
649 EXPECT_EQ(Value0, test.Src0()); \
650 EXPECT_EQ(Value1, test.Src1()); \
651 EXPECT_EQ(0ul, test.Dest()); \
652 reset(); \
653 } while (0)
654
655 TestJ(o, Near, eax, 0x80000000ul, ebx, 0x1ul, edi);
656 TestJ(o, Far, eax, 0x80000000ul, ebx, 0x1ul, edi);
657 TestJ(no, Near, ecx, 0x1ul, edx, 0x1ul, esi);
658 TestJ(no, Far, ecx, 0x1ul, edx, 0x1ul, esi);
659 TestJ(b, Near, eax, 0x1ul, ebx, 0x80000000ul, edi);
660 TestJ(b, Far, eax, 0x1ul, ebx, 0x80000000ul, edi);
661 TestJ(l, Near, eax, 0x80000000ul, ebx, 0x1ul, edi);
662 TestJ(l, Far, eax, 0x80000000ul, ebx, 0x1ul, edi);
663
664 #undef TestJ
665 }
666
667 #undef __
668
669 } // end of anonymous namespace
670 } // end of namespace X8632
671 } // end of namespace Ice
OLDNEW
« no previous file with comments | « src/IceAssemblerX86Base.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698