Line data Source code
1 : // Copyright 2009 the V8 project authors. All rights reserved.
2 : // Redistribution and use in source and binary forms, with or without
3 : // modification, are permitted provided that the following conditions are
4 : // met:
5 : //
6 : // * Redistributions of source code must retain the above copyright
7 : // notice, this list of conditions and the following disclaimer.
8 : // * Redistributions in binary form must reproduce the above
9 : // copyright notice, this list of conditions and the following
10 : // disclaimer in the documentation and/or other materials provided
11 : // with the distribution.
12 : // * Neither the name of Google Inc. nor the names of its
13 : // contributors may be used to endorse or promote products derived
14 : // from this software without specific prior written permission.
15 : //
16 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 : // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 : // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 : // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 : // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 : // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 : // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 : // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 : // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 : // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 :
28 : #include <stdlib.h>
29 :
30 : #include "src/v8.h"
31 :
32 : #include "src/base/platform/platform.h"
33 : #include "src/heap/factory.h"
34 : #include "src/macro-assembler.h"
35 : #include "src/objects-inl.h"
36 : #include "src/objects/smi.h"
37 : #include "src/simulator.h"
38 : #include "test/cctest/cctest.h"
39 : #include "test/common/assembler-tester.h"
40 :
41 : namespace v8 {
42 : namespace internal {
43 : namespace test_macro_assembler_x64 {
44 :
45 : // Test the x64 assembler by compiling some simple functions into
46 : // a buffer and executing them. These tests do not initialize the
47 : // V8 library, create a context, or use any V8 objects.
48 : // The AMD64 calling convention is used, with the first five arguments
49 : // in RSI, RDI, RDX, RCX, R8, and R9, and floating point arguments in
50 : // the XMM registers. The return value is in RAX.
51 : // This calling convention is used on Linux, with GCC, and on Mac OS,
52 : // with GCC. A different convention is used on 64-bit windows.
53 :
54 : typedef int(F0)();
55 :
56 : #define __ masm->
57 :
58 : static void EntryCode(MacroAssembler* masm) {
59 : // Smi constant register is callee save.
60 35 : __ pushq(kRootRegister);
61 35 : __ InitializeRootRegister();
62 : }
63 :
64 35 : static void ExitCode(MacroAssembler* masm) { __ popq(kRootRegister); }
65 :
66 26644 : TEST(Smi) {
67 : // Check that C++ Smi operations work as expected.
68 : int64_t test_numbers[] = {
69 : 0, 1, -1, 127, 128, -128, -129, 255, 256, -256, -257,
70 : Smi::kMaxValue, static_cast<int64_t>(Smi::kMaxValue) + 1,
71 : Smi::kMinValue, static_cast<int64_t>(Smi::kMinValue) - 1
72 5 : };
73 : int test_number_count = 15;
74 155 : for (int i = 0; i < test_number_count; i++) {
75 75 : int64_t number = test_numbers[i];
76 : bool is_valid = Smi::IsValid(number);
77 75 : bool is_in_range = number >= Smi::kMinValue && number <= Smi::kMaxValue;
78 75 : CHECK_EQ(is_in_range, is_valid);
79 75 : if (is_valid) {
80 : Smi smi_from_intptr = Smi::FromIntptr(number);
81 65 : if (static_cast<int>(number) == number) { // Is a 32-bit int.
82 : Smi smi_from_int = Smi::FromInt(static_cast<int32_t>(number));
83 65 : CHECK_EQ(smi_from_int, smi_from_intptr);
84 : }
85 65 : int64_t smi_value = smi_from_intptr->value();
86 65 : CHECK_EQ(number, smi_value);
87 : }
88 : }
89 5 : }
90 :
91 60 : static void TestMoveSmi(MacroAssembler* masm, Label* exit, int id, Smi value) {
92 60 : __ movl(rax, Immediate(id));
93 60 : __ Move(rcx, value);
94 60 : __ Set(rdx, static_cast<intptr_t>(value.ptr()));
95 : __ cmpq(rcx, rdx);
96 60 : __ j(not_equal, exit);
97 60 : }
98 :
99 :
100 : // Test that we can move a Smi value literally into a register.
101 26644 : TEST(SmiMove) {
102 : Isolate* isolate = CcTest::i_isolate();
103 : HandleScope handles(isolate);
104 : auto buffer = AllocateAssemblerBuffer();
105 : MacroAssembler assembler(isolate, v8::internal::CodeObjectRequired::kYes,
106 10 : buffer->CreateView());
107 : MacroAssembler* masm = &assembler; // Create a pointer for the __ macro.
108 : EntryCode(masm);
109 5 : Label exit;
110 :
111 5 : TestMoveSmi(masm, &exit, 1, Smi::zero());
112 5 : TestMoveSmi(masm, &exit, 2, Smi::FromInt(127));
113 5 : TestMoveSmi(masm, &exit, 3, Smi::FromInt(128));
114 5 : TestMoveSmi(masm, &exit, 4, Smi::FromInt(255));
115 5 : TestMoveSmi(masm, &exit, 5, Smi::FromInt(256));
116 5 : TestMoveSmi(masm, &exit, 6, Smi::FromInt(Smi::kMaxValue));
117 5 : TestMoveSmi(masm, &exit, 7, Smi::FromInt(-1));
118 5 : TestMoveSmi(masm, &exit, 8, Smi::FromInt(-128));
119 5 : TestMoveSmi(masm, &exit, 9, Smi::FromInt(-129));
120 5 : TestMoveSmi(masm, &exit, 10, Smi::FromInt(-256));
121 5 : TestMoveSmi(masm, &exit, 11, Smi::FromInt(-257));
122 5 : TestMoveSmi(masm, &exit, 12, Smi::FromInt(Smi::kMinValue));
123 :
124 : __ xorq(rax, rax); // Success.
125 5 : __ bind(&exit);
126 : ExitCode(masm);
127 5 : __ ret(0);
128 :
129 5 : CodeDesc desc;
130 : masm->GetCode(isolate, &desc);
131 5 : buffer->MakeExecutable();
132 : // Call the function from C++.
133 5 : auto f = GeneratedCode<F0>::FromBuffer(CcTest::i_isolate(), buffer->start());
134 : int result = f.Call();
135 5 : CHECK_EQ(0, result);
136 5 : }
137 :
138 :
139 95 : void TestSmiCompare(MacroAssembler* masm, Label* exit, int id, int x, int y) {
140 95 : __ Move(rcx, Smi::FromInt(x));
141 95 : __ movq(r8, rcx);
142 95 : __ Move(rdx, Smi::FromInt(y));
143 : __ movq(r9, rdx);
144 95 : __ SmiCompare(rcx, rdx);
145 95 : if (x < y) {
146 35 : __ movl(rax, Immediate(id + 1));
147 35 : __ j(greater_equal, exit);
148 60 : } else if (x > y) {
149 35 : __ movl(rax, Immediate(id + 2));
150 35 : __ j(less_equal, exit);
151 : } else {
152 25 : CHECK_EQ(x, y);
153 25 : __ movl(rax, Immediate(id + 3));
154 25 : __ j(not_equal, exit);
155 : }
156 95 : __ movl(rax, Immediate(id + 4));
157 : __ cmpq(rcx, r8);
158 95 : __ j(not_equal, exit);
159 : __ incq(rax);
160 : __ cmpq(rdx, r9);
161 95 : __ j(not_equal, exit);
162 :
163 95 : if (x != y) {
164 70 : __ SmiCompare(rdx, rcx);
165 70 : if (y < x) {
166 35 : __ movl(rax, Immediate(id + 9));
167 35 : __ j(greater_equal, exit);
168 : } else {
169 35 : CHECK(y > x);
170 35 : __ movl(rax, Immediate(id + 10));
171 35 : __ j(less_equal, exit);
172 : }
173 : } else {
174 : __ cmpq(rcx, rcx);
175 25 : __ movl(rax, Immediate(id + 11));
176 25 : __ j(not_equal, exit);
177 : __ incq(rax);
178 : __ cmpq(rcx, r8);
179 25 : __ j(not_equal, exit);
180 : }
181 95 : }
182 :
183 :
184 : // Test that we can compare smis for equality (and more).
185 26644 : TEST(SmiCompare) {
186 : Isolate* isolate = CcTest::i_isolate();
187 : HandleScope handles(isolate);
188 : auto buffer = AllocateAssemblerBuffer(2 * Assembler::kMinimalBufferSize);
189 : MacroAssembler assembler(isolate, v8::internal::CodeObjectRequired::kYes,
190 10 : buffer->CreateView());
191 :
192 : MacroAssembler* masm = &assembler;
193 : EntryCode(masm);
194 5 : Label exit;
195 :
196 5 : TestSmiCompare(masm, &exit, 0x10, 0, 0);
197 5 : TestSmiCompare(masm, &exit, 0x20, 0, 1);
198 5 : TestSmiCompare(masm, &exit, 0x30, 1, 0);
199 5 : TestSmiCompare(masm, &exit, 0x40, 1, 1);
200 5 : TestSmiCompare(masm, &exit, 0x50, 0, -1);
201 5 : TestSmiCompare(masm, &exit, 0x60, -1, 0);
202 5 : TestSmiCompare(masm, &exit, 0x70, -1, -1);
203 5 : TestSmiCompare(masm, &exit, 0x80, 0, Smi::kMinValue);
204 5 : TestSmiCompare(masm, &exit, 0x90, Smi::kMinValue, 0);
205 5 : TestSmiCompare(masm, &exit, 0xA0, 0, Smi::kMaxValue);
206 5 : TestSmiCompare(masm, &exit, 0xB0, Smi::kMaxValue, 0);
207 5 : TestSmiCompare(masm, &exit, 0xC0, -1, Smi::kMinValue);
208 5 : TestSmiCompare(masm, &exit, 0xD0, Smi::kMinValue, -1);
209 5 : TestSmiCompare(masm, &exit, 0xE0, -1, Smi::kMaxValue);
210 5 : TestSmiCompare(masm, &exit, 0xF0, Smi::kMaxValue, -1);
211 5 : TestSmiCompare(masm, &exit, 0x100, Smi::kMinValue, Smi::kMinValue);
212 5 : TestSmiCompare(masm, &exit, 0x110, Smi::kMinValue, Smi::kMaxValue);
213 5 : TestSmiCompare(masm, &exit, 0x120, Smi::kMaxValue, Smi::kMinValue);
214 5 : TestSmiCompare(masm, &exit, 0x130, Smi::kMaxValue, Smi::kMaxValue);
215 :
216 : __ xorq(rax, rax); // Success.
217 5 : __ bind(&exit);
218 : ExitCode(masm);
219 5 : __ ret(0);
220 :
221 5 : CodeDesc desc;
222 : masm->GetCode(isolate, &desc);
223 5 : buffer->MakeExecutable();
224 : // Call the function from C++.
225 5 : auto f = GeneratedCode<F0>::FromBuffer(CcTest::i_isolate(), buffer->start());
226 : int result = f.Call();
227 5 : CHECK_EQ(0, result);
228 5 : }
229 :
230 26644 : TEST(SmiTag) {
231 : Isolate* isolate = CcTest::i_isolate();
232 : HandleScope handles(isolate);
233 : auto buffer = AllocateAssemblerBuffer();
234 : MacroAssembler assembler(isolate, v8::internal::CodeObjectRequired::kYes,
235 10 : buffer->CreateView());
236 :
237 : MacroAssembler* masm = &assembler;
238 : EntryCode(masm);
239 5 : Label exit;
240 :
241 : __ movq(rax, Immediate(1)); // Test number.
242 : __ movq(rcx, Immediate(0));
243 5 : __ SmiTag(rcx, rcx);
244 5 : __ Set(rdx, Smi::kZero.ptr());
245 : __ cmpq(rcx, rdx);
246 5 : __ j(not_equal, &exit);
247 :
248 : __ movq(rax, Immediate(2)); // Test number.
249 : __ movq(rcx, Immediate(1024));
250 5 : __ SmiTag(rcx, rcx);
251 5 : __ Set(rdx, Smi::FromInt(1024).ptr());
252 : __ cmpq(rcx, rdx);
253 5 : __ j(not_equal, &exit);
254 :
255 : __ movq(rax, Immediate(3)); // Test number.
256 : __ movq(rcx, Immediate(-1));
257 5 : __ SmiTag(rcx, rcx);
258 5 : __ Set(rdx, Smi::FromInt(-1).ptr());
259 : __ cmpq(rcx, rdx);
260 5 : __ j(not_equal, &exit);
261 :
262 : __ movq(rax, Immediate(4)); // Test number.
263 : __ movq(rcx, Immediate(Smi::kMaxValue));
264 5 : __ SmiTag(rcx, rcx);
265 5 : __ Set(rdx, Smi::FromInt(Smi::kMaxValue).ptr());
266 : __ cmpq(rcx, rdx);
267 5 : __ j(not_equal, &exit);
268 :
269 : __ movq(rax, Immediate(5)); // Test number.
270 : __ movq(rcx, Immediate(Smi::kMinValue));
271 5 : __ SmiTag(rcx, rcx);
272 5 : __ Set(rdx, Smi::FromInt(Smi::kMinValue).ptr());
273 : __ cmpq(rcx, rdx);
274 5 : __ j(not_equal, &exit);
275 :
276 : // Different target register.
277 :
278 : __ movq(rax, Immediate(6)); // Test number.
279 : __ movq(rcx, Immediate(0));
280 5 : __ SmiTag(r8, rcx);
281 5 : __ Set(rdx, Smi::zero().ptr());
282 : __ cmpq(r8, rdx);
283 5 : __ j(not_equal, &exit);
284 :
285 : __ movq(rax, Immediate(7)); // Test number.
286 : __ movq(rcx, Immediate(1024));
287 5 : __ SmiTag(r8, rcx);
288 5 : __ Set(rdx, Smi::FromInt(1024).ptr());
289 : __ cmpq(r8, rdx);
290 5 : __ j(not_equal, &exit);
291 :
292 : __ movq(rax, Immediate(8)); // Test number.
293 : __ movq(rcx, Immediate(-1));
294 5 : __ SmiTag(r8, rcx);
295 5 : __ Set(rdx, Smi::FromInt(-1).ptr());
296 : __ cmpq(r8, rdx);
297 5 : __ j(not_equal, &exit);
298 :
299 : __ movq(rax, Immediate(9)); // Test number.
300 : __ movq(rcx, Immediate(Smi::kMaxValue));
301 5 : __ SmiTag(r8, rcx);
302 5 : __ Set(rdx, Smi::FromInt(Smi::kMaxValue).ptr());
303 : __ cmpq(r8, rdx);
304 5 : __ j(not_equal, &exit);
305 :
306 : __ movq(rax, Immediate(10)); // Test number.
307 : __ movq(rcx, Immediate(Smi::kMinValue));
308 5 : __ SmiTag(r8, rcx);
309 5 : __ Set(rdx, Smi::FromInt(Smi::kMinValue).ptr());
310 : __ cmpq(r8, rdx);
311 5 : __ j(not_equal, &exit);
312 :
313 :
314 : __ xorq(rax, rax); // Success.
315 5 : __ bind(&exit);
316 : ExitCode(masm);
317 5 : __ ret(0);
318 :
319 5 : CodeDesc desc;
320 : masm->GetCode(isolate, &desc);
321 5 : buffer->MakeExecutable();
322 : // Call the function from C++.
323 5 : auto f = GeneratedCode<F0>::FromBuffer(CcTest::i_isolate(), buffer->start());
324 : int result = f.Call();
325 5 : CHECK_EQ(0, result);
326 5 : }
327 :
328 26644 : TEST(SmiCheck) {
329 : Isolate* isolate = CcTest::i_isolate();
330 : HandleScope handles(isolate);
331 : auto buffer = AllocateAssemblerBuffer();
332 : MacroAssembler assembler(isolate, v8::internal::CodeObjectRequired::kYes,
333 10 : buffer->CreateView());
334 :
335 : MacroAssembler* masm = &assembler;
336 : EntryCode(masm);
337 5 : Label exit;
338 : Condition cond;
339 :
340 : __ movl(rax, Immediate(1)); // Test number.
341 :
342 : // CheckSmi
343 :
344 : __ movl(rcx, Immediate(0));
345 5 : __ SmiTag(rcx, rcx);
346 5 : cond = masm->CheckSmi(rcx);
347 5 : __ j(NegateCondition(cond), &exit);
348 :
349 : __ incq(rax);
350 : __ xorq(rcx, Immediate(kSmiTagMask));
351 5 : cond = masm->CheckSmi(rcx);
352 5 : __ j(cond, &exit);
353 :
354 : __ incq(rax);
355 : __ movl(rcx, Immediate(-1));
356 5 : __ SmiTag(rcx, rcx);
357 5 : cond = masm->CheckSmi(rcx);
358 5 : __ j(NegateCondition(cond), &exit);
359 :
360 : __ incq(rax);
361 : __ xorq(rcx, Immediate(kSmiTagMask));
362 5 : cond = masm->CheckSmi(rcx);
363 5 : __ j(cond, &exit);
364 :
365 : __ incq(rax);
366 : __ movl(rcx, Immediate(Smi::kMaxValue));
367 5 : __ SmiTag(rcx, rcx);
368 5 : cond = masm->CheckSmi(rcx);
369 5 : __ j(NegateCondition(cond), &exit);
370 :
371 : __ incq(rax);
372 : __ xorq(rcx, Immediate(kSmiTagMask));
373 5 : cond = masm->CheckSmi(rcx);
374 5 : __ j(cond, &exit);
375 :
376 : __ incq(rax);
377 : __ movl(rcx, Immediate(Smi::kMinValue));
378 5 : __ SmiTag(rcx, rcx);
379 5 : cond = masm->CheckSmi(rcx);
380 5 : __ j(NegateCondition(cond), &exit);
381 :
382 : __ incq(rax);
383 : __ xorq(rcx, Immediate(kSmiTagMask));
384 5 : cond = masm->CheckSmi(rcx);
385 5 : __ j(cond, &exit);
386 :
387 : // Success
388 : __ xorq(rax, rax);
389 :
390 5 : __ bind(&exit);
391 : ExitCode(masm);
392 5 : __ ret(0);
393 :
394 5 : CodeDesc desc;
395 : masm->GetCode(isolate, &desc);
396 5 : buffer->MakeExecutable();
397 : // Call the function from C++.
398 5 : auto f = GeneratedCode<F0>::FromBuffer(CcTest::i_isolate(), buffer->start());
399 : int result = f.Call();
400 5 : CHECK_EQ(0, result);
401 5 : }
402 :
403 25 : void TestSmiIndex(MacroAssembler* masm, Label* exit, int id, int x) {
404 25 : __ movl(rax, Immediate(id));
405 :
406 425 : for (int i = 0; i < 8; i++) {
407 200 : __ Move(rcx, Smi::FromInt(x));
408 200 : SmiIndex index = masm->SmiToIndex(rdx, rcx, i);
409 200 : CHECK(index.reg == rcx || index.reg == rdx);
410 200 : __ shlq(index.reg, Immediate(index.scale));
411 200 : __ Set(r8, static_cast<intptr_t>(x) << i);
412 : __ cmpq(index.reg, r8);
413 200 : __ j(not_equal, exit);
414 : __ incq(rax);
415 200 : __ Move(rcx, Smi::FromInt(x));
416 200 : index = masm->SmiToIndex(rcx, rcx, i);
417 200 : CHECK(index.reg == rcx);
418 200 : __ shlq(rcx, Immediate(index.scale));
419 200 : __ Set(r8, static_cast<intptr_t>(x) << i);
420 : __ cmpq(rcx, r8);
421 200 : __ j(not_equal, exit);
422 : __ incq(rax);
423 : }
424 25 : }
425 :
426 26644 : TEST(SmiIndex) {
427 : Isolate* isolate = CcTest::i_isolate();
428 : HandleScope handles(isolate);
429 : auto buffer = AllocateAssemblerBuffer();
430 : MacroAssembler assembler(isolate, v8::internal::CodeObjectRequired::kYes,
431 10 : buffer->CreateView());
432 :
433 : MacroAssembler* masm = &assembler;
434 : EntryCode(masm);
435 5 : Label exit;
436 :
437 5 : TestSmiIndex(masm, &exit, 0x10, 0);
438 5 : TestSmiIndex(masm, &exit, 0x20, 1);
439 5 : TestSmiIndex(masm, &exit, 0x30, 100);
440 5 : TestSmiIndex(masm, &exit, 0x40, 1000);
441 5 : TestSmiIndex(masm, &exit, 0x50, Smi::kMaxValue);
442 :
443 : __ xorq(rax, rax); // Success.
444 5 : __ bind(&exit);
445 : ExitCode(masm);
446 5 : __ ret(0);
447 :
448 5 : CodeDesc desc;
449 : masm->GetCode(isolate, &desc);
450 5 : buffer->MakeExecutable();
451 : // Call the function from C++.
452 5 : auto f = GeneratedCode<F0>::FromBuffer(CcTest::i_isolate(), buffer->start());
453 : int result = f.Call();
454 5 : CHECK_EQ(0, result);
455 5 : }
456 :
457 26644 : TEST(OperandOffset) {
458 : uint32_t data[256];
459 1285 : for (uint32_t i = 0; i < 256; i++) { data[i] = i * 0x01010101; }
460 :
461 : Isolate* isolate = CcTest::i_isolate();
462 : HandleScope handles(isolate);
463 : auto buffer = AllocateAssemblerBuffer();
464 : MacroAssembler assembler(isolate, v8::internal::CodeObjectRequired::kYes,
465 10 : buffer->CreateView());
466 :
467 : MacroAssembler* masm = &assembler;
468 5 : Label exit;
469 :
470 : EntryCode(masm);
471 5 : __ pushq(r13);
472 5 : __ pushq(r14);
473 5 : __ pushq(rbx);
474 5 : __ pushq(rbp);
475 5 : __ pushq(Immediate(0x100)); // <-- rbp
476 : __ movq(rbp, rsp);
477 5 : __ pushq(Immediate(0x101));
478 5 : __ pushq(Immediate(0x102));
479 5 : __ pushq(Immediate(0x103));
480 5 : __ pushq(Immediate(0x104));
481 5 : __ pushq(Immediate(0x105)); // <-- rbx
482 5 : __ pushq(Immediate(0x106));
483 5 : __ pushq(Immediate(0x107));
484 5 : __ pushq(Immediate(0x108));
485 5 : __ pushq(Immediate(0x109)); // <-- rsp
486 : // rbp = rsp[9]
487 : // r15 = rsp[3]
488 : // rbx = rsp[5]
489 : // r13 = rsp[7]
490 10 : __ leaq(r14, Operand(rsp, 3 * kSystemPointerSize));
491 10 : __ leaq(r13, Operand(rbp, -3 * kSystemPointerSize));
492 10 : __ leaq(rbx, Operand(rbp, -5 * kSystemPointerSize));
493 : __ movl(rcx, Immediate(2));
494 : __ Move(r8, reinterpret_cast<Address>(&data[128]), RelocInfo::NONE);
495 : __ movl(rax, Immediate(1));
496 :
497 5 : Operand sp0 = Operand(rsp, 0);
498 :
499 : // Test 1.
500 : __ movl(rdx, sp0); // Sanity check.
501 : __ cmpl(rdx, Immediate(0x109));
502 5 : __ j(not_equal, &exit);
503 : __ incq(rax);
504 :
505 : // Test 2.
506 : // Zero to non-zero displacement.
507 10 : __ movl(rdx, Operand(sp0, 2 * kSystemPointerSize));
508 : __ cmpl(rdx, Immediate(0x107));
509 5 : __ j(not_equal, &exit);
510 : __ incq(rax);
511 :
512 5 : Operand sp2 = Operand(rsp, 2 * kSystemPointerSize);
513 :
514 : // Test 3.
515 : __ movl(rdx, sp2); // Sanity check.
516 : __ cmpl(rdx, Immediate(0x107));
517 5 : __ j(not_equal, &exit);
518 : __ incq(rax);
519 :
520 10 : __ movl(rdx, Operand(sp2, 2 * kSystemPointerSize));
521 : __ cmpl(rdx, Immediate(0x105));
522 5 : __ j(not_equal, &exit);
523 : __ incq(rax);
524 :
525 : // Non-zero to zero displacement.
526 10 : __ movl(rdx, Operand(sp2, -2 * kSystemPointerSize));
527 : __ cmpl(rdx, Immediate(0x109));
528 5 : __ j(not_equal, &exit);
529 : __ incq(rax);
530 :
531 : Operand sp2c2 =
532 5 : Operand(rsp, rcx, times_system_pointer_size, 2 * kSystemPointerSize);
533 :
534 : // Test 6.
535 : __ movl(rdx, sp2c2); // Sanity check.
536 : __ cmpl(rdx, Immediate(0x105));
537 5 : __ j(not_equal, &exit);
538 : __ incq(rax);
539 :
540 10 : __ movl(rdx, Operand(sp2c2, 2 * kSystemPointerSize));
541 : __ cmpl(rdx, Immediate(0x103));
542 5 : __ j(not_equal, &exit);
543 : __ incq(rax);
544 :
545 : // Non-zero to zero displacement.
546 10 : __ movl(rdx, Operand(sp2c2, -2 * kSystemPointerSize));
547 : __ cmpl(rdx, Immediate(0x107));
548 5 : __ j(not_equal, &exit);
549 : __ incq(rax);
550 :
551 :
552 5 : Operand bp0 = Operand(rbp, 0);
553 :
554 : // Test 9.
555 : __ movl(rdx, bp0); // Sanity check.
556 : __ cmpl(rdx, Immediate(0x100));
557 5 : __ j(not_equal, &exit);
558 : __ incq(rax);
559 :
560 : // Zero to non-zero displacement.
561 10 : __ movl(rdx, Operand(bp0, -2 * kSystemPointerSize));
562 : __ cmpl(rdx, Immediate(0x102));
563 5 : __ j(not_equal, &exit);
564 : __ incq(rax);
565 :
566 5 : Operand bp2 = Operand(rbp, -2 * kSystemPointerSize);
567 :
568 : // Test 11.
569 : __ movl(rdx, bp2); // Sanity check.
570 : __ cmpl(rdx, Immediate(0x102));
571 5 : __ j(not_equal, &exit);
572 : __ incq(rax);
573 :
574 : // Non-zero to zero displacement.
575 10 : __ movl(rdx, Operand(bp2, 2 * kSystemPointerSize));
576 : __ cmpl(rdx, Immediate(0x100));
577 5 : __ j(not_equal, &exit);
578 : __ incq(rax);
579 :
580 10 : __ movl(rdx, Operand(bp2, -2 * kSystemPointerSize));
581 : __ cmpl(rdx, Immediate(0x104));
582 5 : __ j(not_equal, &exit);
583 : __ incq(rax);
584 :
585 : Operand bp2c4 =
586 5 : Operand(rbp, rcx, times_system_pointer_size, -4 * kSystemPointerSize);
587 :
588 : // Test 14:
589 : __ movl(rdx, bp2c4); // Sanity check.
590 : __ cmpl(rdx, Immediate(0x102));
591 5 : __ j(not_equal, &exit);
592 : __ incq(rax);
593 :
594 10 : __ movl(rdx, Operand(bp2c4, 2 * kSystemPointerSize));
595 : __ cmpl(rdx, Immediate(0x100));
596 5 : __ j(not_equal, &exit);
597 : __ incq(rax);
598 :
599 10 : __ movl(rdx, Operand(bp2c4, -2 * kSystemPointerSize));
600 : __ cmpl(rdx, Immediate(0x104));
601 5 : __ j(not_equal, &exit);
602 : __ incq(rax);
603 :
604 5 : Operand bx0 = Operand(rbx, 0);
605 :
606 : // Test 17.
607 : __ movl(rdx, bx0); // Sanity check.
608 : __ cmpl(rdx, Immediate(0x105));
609 5 : __ j(not_equal, &exit);
610 : __ incq(rax);
611 :
612 10 : __ movl(rdx, Operand(bx0, 5 * kSystemPointerSize));
613 : __ cmpl(rdx, Immediate(0x100));
614 5 : __ j(not_equal, &exit);
615 : __ incq(rax);
616 :
617 10 : __ movl(rdx, Operand(bx0, -4 * kSystemPointerSize));
618 : __ cmpl(rdx, Immediate(0x109));
619 5 : __ j(not_equal, &exit);
620 : __ incq(rax);
621 :
622 5 : Operand bx2 = Operand(rbx, 2 * kSystemPointerSize);
623 :
624 : // Test 20.
625 : __ movl(rdx, bx2); // Sanity check.
626 : __ cmpl(rdx, Immediate(0x103));
627 5 : __ j(not_equal, &exit);
628 : __ incq(rax);
629 :
630 10 : __ movl(rdx, Operand(bx2, 2 * kSystemPointerSize));
631 : __ cmpl(rdx, Immediate(0x101));
632 5 : __ j(not_equal, &exit);
633 : __ incq(rax);
634 :
635 : // Non-zero to zero displacement.
636 10 : __ movl(rdx, Operand(bx2, -2 * kSystemPointerSize));
637 : __ cmpl(rdx, Immediate(0x105));
638 5 : __ j(not_equal, &exit);
639 : __ incq(rax);
640 :
641 : Operand bx2c2 =
642 5 : Operand(rbx, rcx, times_system_pointer_size, -2 * kSystemPointerSize);
643 :
644 : // Test 23.
645 : __ movl(rdx, bx2c2); // Sanity check.
646 : __ cmpl(rdx, Immediate(0x105));
647 5 : __ j(not_equal, &exit);
648 : __ incq(rax);
649 :
650 10 : __ movl(rdx, Operand(bx2c2, 2 * kSystemPointerSize));
651 : __ cmpl(rdx, Immediate(0x103));
652 5 : __ j(not_equal, &exit);
653 : __ incq(rax);
654 :
655 10 : __ movl(rdx, Operand(bx2c2, -2 * kSystemPointerSize));
656 : __ cmpl(rdx, Immediate(0x107));
657 5 : __ j(not_equal, &exit);
658 : __ incq(rax);
659 :
660 5 : Operand r80 = Operand(r8, 0);
661 :
662 : // Test 26.
663 : __ movl(rdx, r80); // Sanity check.
664 : __ cmpl(rdx, Immediate(0x80808080));
665 5 : __ j(not_equal, &exit);
666 : __ incq(rax);
667 :
668 10 : __ movl(rdx, Operand(r80, -8 * kIntSize));
669 : __ cmpl(rdx, Immediate(0x78787878));
670 5 : __ j(not_equal, &exit);
671 : __ incq(rax);
672 :
673 10 : __ movl(rdx, Operand(r80, 8 * kIntSize));
674 : __ cmpl(rdx, Immediate(0x88888888));
675 5 : __ j(not_equal, &exit);
676 : __ incq(rax);
677 :
678 10 : __ movl(rdx, Operand(r80, -64 * kIntSize));
679 : __ cmpl(rdx, Immediate(0x40404040));
680 5 : __ j(not_equal, &exit);
681 : __ incq(rax);
682 :
683 10 : __ movl(rdx, Operand(r80, 64 * kIntSize));
684 : __ cmpl(rdx, Immediate(0xC0C0C0C0));
685 5 : __ j(not_equal, &exit);
686 : __ incq(rax);
687 :
688 5 : Operand r88 = Operand(r8, 8 * kIntSize);
689 :
690 : // Test 31.
691 : __ movl(rdx, r88); // Sanity check.
692 : __ cmpl(rdx, Immediate(0x88888888));
693 5 : __ j(not_equal, &exit);
694 : __ incq(rax);
695 :
696 10 : __ movl(rdx, Operand(r88, -8 * kIntSize));
697 : __ cmpl(rdx, Immediate(0x80808080));
698 5 : __ j(not_equal, &exit);
699 : __ incq(rax);
700 :
701 10 : __ movl(rdx, Operand(r88, 8 * kIntSize));
702 : __ cmpl(rdx, Immediate(0x90909090));
703 5 : __ j(not_equal, &exit);
704 : __ incq(rax);
705 :
706 10 : __ movl(rdx, Operand(r88, -64 * kIntSize));
707 : __ cmpl(rdx, Immediate(0x48484848));
708 5 : __ j(not_equal, &exit);
709 : __ incq(rax);
710 :
711 10 : __ movl(rdx, Operand(r88, 64 * kIntSize));
712 : __ cmpl(rdx, Immediate(0xC8C8C8C8));
713 5 : __ j(not_equal, &exit);
714 : __ incq(rax);
715 :
716 :
717 5 : Operand r864 = Operand(r8, 64 * kIntSize);
718 :
719 : // Test 36.
720 : __ movl(rdx, r864); // Sanity check.
721 : __ cmpl(rdx, Immediate(0xC0C0C0C0));
722 5 : __ j(not_equal, &exit);
723 : __ incq(rax);
724 :
725 10 : __ movl(rdx, Operand(r864, -8 * kIntSize));
726 : __ cmpl(rdx, Immediate(0xB8B8B8B8));
727 5 : __ j(not_equal, &exit);
728 : __ incq(rax);
729 :
730 10 : __ movl(rdx, Operand(r864, 8 * kIntSize));
731 : __ cmpl(rdx, Immediate(0xC8C8C8C8));
732 5 : __ j(not_equal, &exit);
733 : __ incq(rax);
734 :
735 10 : __ movl(rdx, Operand(r864, -64 * kIntSize));
736 : __ cmpl(rdx, Immediate(0x80808080));
737 5 : __ j(not_equal, &exit);
738 : __ incq(rax);
739 :
740 10 : __ movl(rdx, Operand(r864, 32 * kIntSize));
741 : __ cmpl(rdx, Immediate(0xE0E0E0E0));
742 5 : __ j(not_equal, &exit);
743 : __ incq(rax);
744 :
745 : // 32-bit offset to 8-bit offset.
746 10 : __ movl(rdx, Operand(r864, -60 * kIntSize));
747 : __ cmpl(rdx, Immediate(0x84848484));
748 5 : __ j(not_equal, &exit);
749 : __ incq(rax);
750 :
751 10 : __ movl(rdx, Operand(r864, 60 * kIntSize));
752 : __ cmpl(rdx, Immediate(0xFCFCFCFC));
753 5 : __ j(not_equal, &exit);
754 : __ incq(rax);
755 :
756 : // Test unaligned offsets.
757 :
758 : // Test 43.
759 10 : __ movl(rdx, Operand(r80, 2));
760 : __ cmpl(rdx, Immediate(0x81818080));
761 5 : __ j(not_equal, &exit);
762 : __ incq(rax);
763 :
764 10 : __ movl(rdx, Operand(r80, -2));
765 : __ cmpl(rdx, Immediate(0x80807F7F));
766 5 : __ j(not_equal, &exit);
767 : __ incq(rax);
768 :
769 10 : __ movl(rdx, Operand(r80, 126));
770 : __ cmpl(rdx, Immediate(0xA0A09F9F));
771 5 : __ j(not_equal, &exit);
772 : __ incq(rax);
773 :
774 10 : __ movl(rdx, Operand(r80, -126));
775 : __ cmpl(rdx, Immediate(0x61616060));
776 5 : __ j(not_equal, &exit);
777 : __ incq(rax);
778 :
779 10 : __ movl(rdx, Operand(r80, 254));
780 : __ cmpl(rdx, Immediate(0xC0C0BFBF));
781 5 : __ j(not_equal, &exit);
782 : __ incq(rax);
783 :
784 10 : __ movl(rdx, Operand(r80, -254));
785 : __ cmpl(rdx, Immediate(0x41414040));
786 5 : __ j(not_equal, &exit);
787 : __ incq(rax);
788 :
789 : // Success.
790 :
791 : __ movl(rax, Immediate(0));
792 5 : __ bind(&exit);
793 10 : __ leaq(rsp, Operand(rbp, kSystemPointerSize));
794 5 : __ popq(rbp);
795 5 : __ popq(rbx);
796 5 : __ popq(r14);
797 5 : __ popq(r13);
798 : ExitCode(masm);
799 5 : __ ret(0);
800 :
801 :
802 5 : CodeDesc desc;
803 : masm->GetCode(isolate, &desc);
804 5 : buffer->MakeExecutable();
805 : // Call the function from C++.
806 5 : auto f = GeneratedCode<F0>::FromBuffer(CcTest::i_isolate(), buffer->start());
807 : int result = f.Call();
808 5 : CHECK_EQ(0, result);
809 5 : }
810 :
811 5 : void TestFloat32x4Abs(MacroAssembler* masm, Label* exit, float x, float y,
812 : float z, float w) {
813 5 : __ subq(rsp, Immediate(kSimd128Size));
814 :
815 5 : __ Move(xmm1, x);
816 10 : __ Movss(Operand(rsp, 0 * kFloatSize), xmm1);
817 : __ Move(xmm2, y);
818 10 : __ Movss(Operand(rsp, 1 * kFloatSize), xmm2);
819 : __ Move(xmm3, z);
820 10 : __ Movss(Operand(rsp, 2 * kFloatSize), xmm3);
821 : __ Move(xmm4, w);
822 10 : __ Movss(Operand(rsp, 3 * kFloatSize), xmm4);
823 10 : __ Movups(xmm0, Operand(rsp, 0));
824 :
825 5 : __ Absps(xmm0);
826 10 : __ Movups(Operand(rsp, 0), xmm0);
827 :
828 : __ incq(rax);
829 5 : __ Move(xmm1, fabsf(x));
830 10 : __ Ucomiss(xmm1, Operand(rsp, 0 * kFloatSize));
831 5 : __ j(not_equal, exit);
832 : __ incq(rax);
833 5 : __ Move(xmm2, fabsf(y));
834 10 : __ Ucomiss(xmm2, Operand(rsp, 1 * kFloatSize));
835 5 : __ j(not_equal, exit);
836 : __ incq(rax);
837 5 : __ Move(xmm3, fabsf(z));
838 10 : __ Ucomiss(xmm3, Operand(rsp, 2 * kFloatSize));
839 5 : __ j(not_equal, exit);
840 : __ incq(rax);
841 5 : __ Move(xmm4, fabsf(w));
842 10 : __ Ucomiss(xmm4, Operand(rsp, 3 * kFloatSize));
843 5 : __ j(not_equal, exit);
844 :
845 : __ addq(rsp, Immediate(kSimd128Size));
846 5 : }
847 :
848 5 : void TestFloat32x4Neg(MacroAssembler* masm, Label* exit, float x, float y,
849 : float z, float w) {
850 5 : __ subq(rsp, Immediate(kSimd128Size));
851 :
852 5 : __ Move(xmm1, x);
853 10 : __ Movss(Operand(rsp, 0 * kFloatSize), xmm1);
854 : __ Move(xmm2, y);
855 10 : __ Movss(Operand(rsp, 1 * kFloatSize), xmm2);
856 : __ Move(xmm3, z);
857 10 : __ Movss(Operand(rsp, 2 * kFloatSize), xmm3);
858 : __ Move(xmm4, w);
859 10 : __ Movss(Operand(rsp, 3 * kFloatSize), xmm4);
860 10 : __ Movups(xmm0, Operand(rsp, 0));
861 :
862 5 : __ Negps(xmm0);
863 10 : __ Movups(Operand(rsp, 0), xmm0);
864 :
865 : __ incq(rax);
866 5 : __ Move(xmm1, -x);
867 10 : __ Ucomiss(xmm1, Operand(rsp, 0 * kFloatSize));
868 5 : __ j(not_equal, exit);
869 : __ incq(rax);
870 5 : __ Move(xmm2, -y);
871 10 : __ Ucomiss(xmm2, Operand(rsp, 1 * kFloatSize));
872 5 : __ j(not_equal, exit);
873 : __ incq(rax);
874 5 : __ Move(xmm3, -z);
875 10 : __ Ucomiss(xmm3, Operand(rsp, 2 * kFloatSize));
876 5 : __ j(not_equal, exit);
877 : __ incq(rax);
878 5 : __ Move(xmm4, -w);
879 10 : __ Ucomiss(xmm4, Operand(rsp, 3 * kFloatSize));
880 5 : __ j(not_equal, exit);
881 :
882 : __ addq(rsp, Immediate(kSimd128Size));
883 5 : }
884 :
885 5 : void TestFloat64x2Abs(MacroAssembler* masm, Label* exit, double x, double y) {
886 5 : __ subq(rsp, Immediate(kSimd128Size));
887 :
888 5 : __ Move(xmm1, x);
889 10 : __ Movsd(Operand(rsp, 0 * kDoubleSize), xmm1);
890 : __ Move(xmm2, y);
891 10 : __ Movsd(Operand(rsp, 1 * kDoubleSize), xmm2);
892 5 : __ movupd(xmm0, Operand(rsp, 0));
893 :
894 5 : __ Abspd(xmm0);
895 5 : __ movupd(Operand(rsp, 0), xmm0);
896 :
897 : __ incq(rax);
898 5 : __ Move(xmm1, fabs(x));
899 10 : __ Ucomisd(xmm1, Operand(rsp, 0 * kDoubleSize));
900 5 : __ j(not_equal, exit);
901 : __ incq(rax);
902 5 : __ Move(xmm2, fabs(y));
903 10 : __ Ucomisd(xmm2, Operand(rsp, 1 * kDoubleSize));
904 5 : __ j(not_equal, exit);
905 :
906 : __ addq(rsp, Immediate(kSimd128Size));
907 5 : }
908 :
909 5 : void TestFloat64x2Neg(MacroAssembler* masm, Label* exit, double x, double y) {
910 5 : __ subq(rsp, Immediate(kSimd128Size));
911 :
912 5 : __ Move(xmm1, x);
913 10 : __ Movsd(Operand(rsp, 0 * kDoubleSize), xmm1);
914 : __ Move(xmm2, y);
915 10 : __ Movsd(Operand(rsp, 1 * kDoubleSize), xmm2);
916 5 : __ movupd(xmm0, Operand(rsp, 0));
917 :
918 5 : __ Negpd(xmm0);
919 5 : __ movupd(Operand(rsp, 0), xmm0);
920 :
921 : __ incq(rax);
922 5 : __ Move(xmm1, -x);
923 10 : __ Ucomisd(xmm1, Operand(rsp, 0 * kDoubleSize));
924 5 : __ j(not_equal, exit);
925 : __ incq(rax);
926 5 : __ Move(xmm2, -y);
927 10 : __ Ucomisd(xmm2, Operand(rsp, 1 * kDoubleSize));
928 5 : __ j(not_equal, exit);
929 :
930 : __ addq(rsp, Immediate(kSimd128Size));
931 5 : }
932 :
933 26644 : TEST(SIMDMacros) {
934 : Isolate* isolate = CcTest::i_isolate();
935 : HandleScope handles(isolate);
936 : auto buffer = AllocateAssemblerBuffer();
937 : MacroAssembler assembler(isolate, v8::internal::CodeObjectRequired::kYes,
938 10 : buffer->CreateView());
939 :
940 : MacroAssembler* masm = &assembler;
941 : EntryCode(masm);
942 5 : Label exit;
943 :
944 : __ xorq(rax, rax);
945 5 : TestFloat32x4Abs(masm, &exit, 1.5, -1.5, 0.5, -0.5);
946 5 : TestFloat32x4Neg(masm, &exit, 1.5, -1.5, 0.5, -0.5);
947 5 : TestFloat64x2Abs(masm, &exit, 1.75, -1.75);
948 5 : TestFloat64x2Neg(masm, &exit, 1.75, -1.75);
949 :
950 : __ xorq(rax, rax); // Success.
951 5 : __ bind(&exit);
952 : ExitCode(masm);
953 5 : __ ret(0);
954 :
955 5 : CodeDesc desc;
956 : masm->GetCode(isolate, &desc);
957 5 : buffer->MakeExecutable();
958 : // Call the function from C++.
959 5 : auto f = GeneratedCode<F0>::FromBuffer(CcTest::i_isolate(), buffer->start());
960 : int result = f.Call();
961 5 : CHECK_EQ(0, result);
962 5 : }
963 :
964 26644 : TEST(AreAliased) {
965 : DCHECK(!AreAliased(rax));
966 : DCHECK(!AreAliased(rax, no_reg));
967 : DCHECK(!AreAliased(no_reg, rax, no_reg));
968 :
969 : DCHECK(AreAliased(rax, rax));
970 : DCHECK(!AreAliased(no_reg, no_reg));
971 :
972 : DCHECK(!AreAliased(rax, rbx, rcx, rdx, no_reg));
973 : DCHECK(AreAliased(rax, rbx, rcx, rdx, rax, no_reg));
974 :
975 : // no_regs are allowed in
976 : DCHECK(!AreAliased(rax, no_reg, rbx, no_reg, rcx, no_reg, rdx, no_reg));
977 : DCHECK(AreAliased(rax, no_reg, rbx, no_reg, rcx, no_reg, rdx, rax, no_reg));
978 5 : }
979 :
980 : #undef __
981 :
982 : } // namespace test_macro_assembler_x64
983 : } // namespace internal
984 79917 : } // namespace v8
|