Bug 1852740: add tests for the `fetchpriority` attribute in Link headers. r=necko...
[gecko.git] / js / src / jsapi-tests / testJitMacroAssembler.cpp
blob0cfa71700fba1dd29a1b1014747035f94c5c90fa
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 */
4 /* This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #include "jit/IonAnalysis.h"
9 #include "jit/Linker.h"
10 #include "jit/MacroAssembler.h"
11 #include "jit/MIRGenerator.h"
12 #include "jit/MIRGraph.h"
13 #include "jit/ValueNumbering.h"
14 #include "js/Value.h"
16 #include "jsapi-tests/tests.h"
17 #include "jsapi-tests/testsJit.h"
19 #include "jit/MacroAssembler-inl.h"
21 using namespace js;
22 using namespace js::jit;
24 using mozilla::NegativeInfinity;
25 using mozilla::PositiveInfinity;
27 #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
29 BEGIN_TEST(testJitMacroAssembler_flexibleDivMod) {
30 TempAllocator tempAlloc(&cx->tempLifoAlloc());
31 JitContext jcx(cx);
32 StackMacroAssembler masm(cx, tempAlloc);
33 AutoCreatedBy acb(masm, __func__);
35 PrepareJit(masm);
37 // Test case divides 9/2;
38 const uintptr_t quotient_result = 4;
39 const uintptr_t remainder_result = 1;
40 const uintptr_t dividend = 9;
41 const uintptr_t divisor = 2;
43 AllocatableGeneralRegisterSet leftOutputHandSides(GeneralRegisterSet::All());
45 while (!leftOutputHandSides.empty()) {
46 Register lhsOutput = leftOutputHandSides.takeAny();
48 AllocatableGeneralRegisterSet rightHandSides(GeneralRegisterSet::All());
49 while (!rightHandSides.empty()) {
50 Register rhs = rightHandSides.takeAny();
52 AllocatableGeneralRegisterSet remainders(GeneralRegisterSet::All());
53 while (!remainders.empty()) {
54 Register remainderOutput = remainders.takeAny();
55 if (lhsOutput == rhs || lhsOutput == remainderOutput ||
56 rhs == remainderOutput) {
57 continue;
60 AllocatableRegisterSet regs(RegisterSet::Volatile());
61 LiveRegisterSet save(regs.asLiveSet());
63 Label next, fail;
64 masm.mov(ImmWord(dividend), lhsOutput);
65 masm.mov(ImmWord(divisor), rhs);
66 masm.flexibleDivMod32(rhs, lhsOutput, remainderOutput, false, save);
67 masm.branch32(Assembler::NotEqual, AbsoluteAddress(&quotient_result),
68 lhsOutput, &fail);
69 masm.branch32(Assembler::NotEqual, AbsoluteAddress(&remainder_result),
70 remainderOutput, &fail);
71 // Ensure RHS was not clobbered
72 masm.branch32(Assembler::NotEqual, AbsoluteAddress(&divisor), rhs,
73 &fail);
74 masm.jump(&next);
75 masm.bind(&fail);
76 masm.printf("Failed");
77 masm.breakpoint();
79 masm.bind(&next);
84 return ExecuteJit(cx, masm);
86 END_TEST(testJitMacroAssembler_flexibleDivMod)
88 BEGIN_TEST(testJitMacroAssembler_flexibleRemainder) {
89 TempAllocator tempAlloc(&cx->tempLifoAlloc());
90 JitContext jcx(cx);
91 StackMacroAssembler masm(cx, tempAlloc);
92 AutoCreatedBy acb(masm, __func__);
94 PrepareJit(masm);
96 // Test case divides 9/2;
97 const uintptr_t dividend = 9;
98 const uintptr_t divisor = 2;
99 const uintptr_t remainder_result = 1;
101 AllocatableGeneralRegisterSet leftOutputHandSides(GeneralRegisterSet::All());
103 while (!leftOutputHandSides.empty()) {
104 Register lhsOutput = leftOutputHandSides.takeAny();
106 AllocatableGeneralRegisterSet rightHandSides(GeneralRegisterSet::All());
107 while (!rightHandSides.empty()) {
108 Register rhs = rightHandSides.takeAny();
110 if (lhsOutput == rhs) {
111 continue;
114 AllocatableRegisterSet regs(RegisterSet::Volatile());
115 LiveRegisterSet save(regs.asLiveSet());
117 Label next, fail;
118 masm.mov(ImmWord(dividend), lhsOutput);
119 masm.mov(ImmWord(divisor), rhs);
120 masm.flexibleRemainder32(rhs, lhsOutput, false, save);
121 masm.branch32(Assembler::NotEqual, AbsoluteAddress(&remainder_result),
122 lhsOutput, &fail);
123 // Ensure RHS was not clobbered
124 masm.branch32(Assembler::NotEqual, AbsoluteAddress(&divisor), rhs, &fail);
125 masm.jump(&next);
126 masm.bind(&fail);
127 masm.printf("Failed\n");
128 masm.breakpoint();
130 masm.bind(&next);
134 return ExecuteJit(cx, masm);
136 END_TEST(testJitMacroAssembler_flexibleRemainder)
138 BEGIN_TEST(testJitMacroAssembler_flexibleQuotient) {
139 TempAllocator tempAlloc(&cx->tempLifoAlloc());
140 JitContext jcx(cx);
141 StackMacroAssembler masm(cx, tempAlloc);
142 AutoCreatedBy acb(masm, __func__);
144 PrepareJit(masm);
146 // Test case divides 9/2;
147 const uintptr_t dividend = 9;
148 const uintptr_t divisor = 2;
149 const uintptr_t quotient_result = 4;
151 AllocatableGeneralRegisterSet leftOutputHandSides(GeneralRegisterSet::All());
153 while (!leftOutputHandSides.empty()) {
154 Register lhsOutput = leftOutputHandSides.takeAny();
156 AllocatableGeneralRegisterSet rightHandSides(GeneralRegisterSet::All());
157 while (!rightHandSides.empty()) {
158 Register rhs = rightHandSides.takeAny();
160 if (lhsOutput == rhs) {
161 continue;
164 AllocatableRegisterSet regs(RegisterSet::Volatile());
165 LiveRegisterSet save(regs.asLiveSet());
167 Label next, fail;
168 masm.mov(ImmWord(dividend), lhsOutput);
169 masm.mov(ImmWord(divisor), rhs);
170 masm.flexibleQuotient32(rhs, lhsOutput, false, save);
171 masm.branch32(Assembler::NotEqual, AbsoluteAddress(&quotient_result),
172 lhsOutput, &fail);
173 // Ensure RHS was not clobbered
174 masm.branch32(Assembler::NotEqual, AbsoluteAddress(&divisor), rhs, &fail);
175 masm.jump(&next);
176 masm.bind(&fail);
177 masm.printf("Failed\n");
178 masm.breakpoint();
180 masm.bind(&next);
184 return ExecuteJit(cx, masm);
186 END_TEST(testJitMacroAssembler_flexibleQuotient)
188 // To make sure ecx isn't being clobbered; globally scoped to ensure it has the
189 // right lifetime.
190 const uintptr_t guardEcx = 0xfeedbad;
192 bool shiftTest(JSContext* cx, const char* name,
193 void (*operation)(StackMacroAssembler& masm, Register, Register),
194 const uintptr_t* lhsInput, const uintptr_t* rhsInput,
195 const uintptr_t* result) {
196 TempAllocator tempAlloc(&cx->tempLifoAlloc());
197 JitContext jcx(cx);
198 StackMacroAssembler masm(cx, tempAlloc);
199 AutoCreatedBy acb(masm, __func__);
201 PrepareJit(masm);
203 JS::AutoSuppressGCAnalysis suppress;
204 AllocatableGeneralRegisterSet leftOutputHandSides(GeneralRegisterSet::All());
206 while (!leftOutputHandSides.empty()) {
207 Register lhsOutput = leftOutputHandSides.takeAny();
209 AllocatableGeneralRegisterSet rightHandSides(GeneralRegisterSet::All());
210 while (!rightHandSides.empty()) {
211 Register rhs = rightHandSides.takeAny();
213 // You can only use shift as the same reg if the values are the same
214 if (lhsOutput == rhs && *lhsInput != *rhsInput) {
215 continue;
218 Label next, outputFail, clobberRhs, clobberEcx, dump;
219 masm.mov(ImmWord(guardEcx), ecx);
220 masm.mov(ImmWord(*lhsInput), lhsOutput);
221 masm.mov(ImmWord(*rhsInput), rhs);
223 operation(masm, rhs, lhsOutput);
225 // Ensure Result is correct
226 masm.branch32(Assembler::NotEqual, AbsoluteAddress(result), lhsOutput,
227 &outputFail);
229 // Ensure RHS was not clobbered, unless it's also the output register.
230 if (lhsOutput != rhs) {
231 masm.branch32(Assembler::NotEqual, AbsoluteAddress(rhsInput), rhs,
232 &clobberRhs);
235 if (lhsOutput != ecx && rhs != ecx) {
236 // If neither lhsOutput nor rhs is ecx, make sure ecx has been
237 // preserved, otherwise it's expected to be covered by the RHS clobber
238 // check above, or intentionally clobbered as the output.
239 masm.branch32(Assembler::NotEqual, AbsoluteAddress(&guardEcx), ecx,
240 &clobberEcx);
243 masm.jump(&next);
245 masm.bind(&outputFail);
246 masm.printf("Incorrect output (got %d) ", lhsOutput);
247 masm.jump(&dump);
249 masm.bind(&clobberRhs);
250 masm.printf("rhs clobbered %d", rhs);
251 masm.jump(&dump);
253 masm.bind(&clobberEcx);
254 masm.printf("ecx clobbered");
255 masm.jump(&dump);
257 masm.bind(&dump);
258 masm.mov(ImmPtr(lhsOutput.name()), lhsOutput);
259 masm.printf("(lhsOutput/srcDest) %s ", lhsOutput);
260 masm.mov(ImmPtr(name), lhsOutput);
261 masm.printf("%s ", lhsOutput);
262 masm.mov(ImmPtr(rhs.name()), lhsOutput);
263 masm.printf("(shift/rhs) %s \n", lhsOutput);
264 // Breakpoint to force test failure.
265 masm.breakpoint();
266 masm.bind(&next);
270 return ExecuteJit(cx, masm);
273 BEGIN_TEST(testJitMacroAssembler_flexibleRshift) {
275 // Test case 16 >> 2 == 4;
276 const uintptr_t lhsInput = 16;
277 const uintptr_t rhsInput = 2;
278 const uintptr_t result = 4;
280 bool res = shiftTest(
281 cx, "flexibleRshift32",
282 [](StackMacroAssembler& masm, Register rhs, Register lhsOutput) {
283 masm.flexibleRshift32(rhs, lhsOutput);
285 &lhsInput, &rhsInput, &result);
286 if (!res) {
287 return false;
292 // Test case 16 >> 16 == 0 -- this helps cover the case where the same
293 // register can be passed for source and dest.
294 const uintptr_t lhsInput = 16;
295 const uintptr_t rhsInput = 16;
296 const uintptr_t result = 0;
298 bool res = shiftTest(
299 cx, "flexibleRshift32",
300 [](StackMacroAssembler& masm, Register rhs, Register lhsOutput) {
301 masm.flexibleRshift32(rhs, lhsOutput);
303 &lhsInput, &rhsInput, &result);
304 if (!res) {
305 return false;
309 return true;
311 END_TEST(testJitMacroAssembler_flexibleRshift)
313 BEGIN_TEST(testJitMacroAssembler_flexibleRshiftArithmetic) {
315 // Test case 4294967295 >> 2 == 4294967295;
316 const uintptr_t lhsInput = 4294967295;
317 const uintptr_t rhsInput = 2;
318 const uintptr_t result = 4294967295;
319 bool res = shiftTest(
320 cx, "flexibleRshift32Arithmetic",
321 [](StackMacroAssembler& masm, Register rhs, Register lhsOutput) {
322 masm.flexibleRshift32Arithmetic(rhs, lhsOutput);
324 &lhsInput, &rhsInput, &result);
325 if (!res) {
326 return false;
331 // Test case 16 >> 16 == 0 -- this helps cover the case where the same
332 // register can be passed for source and dest.
333 const uintptr_t lhsInput = 16;
334 const uintptr_t rhsInput = 16;
335 const uintptr_t result = 0;
337 bool res = shiftTest(
338 cx, "flexibleRshift32Arithmetic",
339 [](StackMacroAssembler& masm, Register rhs, Register lhsOutput) {
340 masm.flexibleRshift32Arithmetic(rhs, lhsOutput);
342 &lhsInput, &rhsInput, &result);
343 if (!res) {
344 return false;
348 return true;
350 END_TEST(testJitMacroAssembler_flexibleRshiftArithmetic)
352 BEGIN_TEST(testJitMacroAssembler_flexibleLshift) {
354 // Test case 16 << 2 == 64;
355 const uintptr_t lhsInput = 16;
356 const uintptr_t rhsInput = 2;
357 const uintptr_t result = 64;
359 bool res = shiftTest(
360 cx, "flexibleLshift32",
361 [](StackMacroAssembler& masm, Register rhs, Register lhsOutput) {
362 masm.flexibleLshift32(rhs, lhsOutput);
364 &lhsInput, &rhsInput, &result);
365 if (!res) {
366 return false;
371 // Test case 4 << 4 == 64; duplicated input case
372 const uintptr_t lhsInput = 4;
373 const uintptr_t rhsInput = 4;
374 const uintptr_t result = 64;
376 bool res = shiftTest(
377 cx, "flexibleLshift32",
378 [](StackMacroAssembler& masm, Register rhs, Register lhsOutput) {
379 masm.flexibleLshift32(rhs, lhsOutput);
381 &lhsInput, &rhsInput, &result);
382 if (!res) {
383 return false;
387 return true;
389 END_TEST(testJitMacroAssembler_flexibleLshift)
391 BEGIN_TEST(testJitMacroAssembler_truncateDoubleToInt64) {
392 TempAllocator tempAlloc(&cx->tempLifoAlloc());
393 JitContext jcx(cx);
394 StackMacroAssembler masm(cx, tempAlloc);
395 AutoCreatedBy acb(masm, __func__);
397 PrepareJit(masm);
399 AllocatableGeneralRegisterSet allRegs(GeneralRegisterSet::All());
400 AllocatableFloatRegisterSet allFloatRegs(FloatRegisterSet::All());
401 FloatRegister input = allFloatRegs.takeAny();
402 # ifdef JS_NUNBOX32
403 Register64 output(allRegs.takeAny(), allRegs.takeAny());
404 # else
405 Register64 output(allRegs.takeAny());
406 # endif
407 Register temp = allRegs.takeAny();
409 masm.reserveStack(sizeof(int32_t));
411 # define TEST(INPUT, OUTPUT) \
413 Label next; \
414 masm.loadConstantDouble(double(INPUT), input); \
415 masm.storeDouble(input, Operand(esp, 0)); \
416 masm.truncateDoubleToInt64(Address(esp, 0), Address(esp, 0), temp); \
417 masm.branch64(Assembler::Equal, Address(esp, 0), Imm64(OUTPUT), &next); \
418 masm.printf("truncateDoubleToInt64(" #INPUT ") failed\n"); \
419 masm.breakpoint(); \
420 masm.bind(&next); \
423 TEST(0, 0);
424 TEST(-0, 0);
425 TEST(1, 1);
426 TEST(9223372036854774784.0, 9223372036854774784);
427 TEST(-9223372036854775808.0, 0x8000000000000000);
428 TEST(9223372036854775808.0, 0x8000000000000000);
429 TEST(JS::GenericNaN(), 0x8000000000000000);
430 TEST(PositiveInfinity<double>(), 0x8000000000000000);
431 TEST(NegativeInfinity<double>(), 0x8000000000000000);
432 # undef TEST
434 masm.freeStack(sizeof(int32_t));
436 return ExecuteJit(cx, masm);
438 END_TEST(testJitMacroAssembler_truncateDoubleToInt64)
440 BEGIN_TEST(testJitMacroAssembler_truncateDoubleToUInt64) {
441 TempAllocator tempAlloc(&cx->tempLifoAlloc());
442 JitContext jcx(cx);
443 StackMacroAssembler masm(cx, tempAlloc);
444 AutoCreatedBy acb(masm, __func__);
446 PrepareJit(masm);
448 AllocatableGeneralRegisterSet allRegs(GeneralRegisterSet::All());
449 AllocatableFloatRegisterSet allFloatRegs(FloatRegisterSet::All());
450 FloatRegister input = allFloatRegs.takeAny();
451 FloatRegister floatTemp = allFloatRegs.takeAny();
452 # ifdef JS_NUNBOX32
453 Register64 output(allRegs.takeAny(), allRegs.takeAny());
454 # else
455 Register64 output(allRegs.takeAny());
456 # endif
457 Register temp = allRegs.takeAny();
459 masm.reserveStack(sizeof(int32_t));
461 # define TEST(INPUT, OUTPUT) \
463 Label next; \
464 masm.loadConstantDouble(double(INPUT), input); \
465 masm.storeDouble(input, Operand(esp, 0)); \
466 masm.truncateDoubleToUInt64(Address(esp, 0), Address(esp, 0), temp, \
467 floatTemp); \
468 masm.branch64(Assembler::Equal, Address(esp, 0), Imm64(OUTPUT), &next); \
469 masm.printf("truncateDoubleToUInt64(" #INPUT ") failed\n"); \
470 masm.breakpoint(); \
471 masm.bind(&next); \
474 TEST(0, 0);
475 TEST(1, 1);
476 TEST(9223372036854774784.0, 9223372036854774784);
477 TEST((uint64_t)0x8000000000000000, 0x8000000000000000);
478 TEST((uint64_t)0x8000000000000001, 0x8000000000000000);
479 TEST((uint64_t)0x8006004000000001, 0x8006004000000000);
480 TEST(-0.0, 0);
481 TEST(-0.5, 0);
482 TEST(-0.99, 0);
483 TEST(JS::GenericNaN(), 0x8000000000000000);
484 TEST(PositiveInfinity<double>(), 0x8000000000000000);
485 TEST(NegativeInfinity<double>(), 0x8000000000000000);
486 # undef TEST
488 masm.freeStack(sizeof(int32_t));
490 return ExecuteJit(cx, masm);
492 END_TEST(testJitMacroAssembler_truncateDoubleToUInt64)
494 BEGIN_TEST(testJitMacroAssembler_branchDoubleNotInInt64Range) {
495 TempAllocator tempAlloc(&cx->tempLifoAlloc());
496 JitContext jcx(cx);
497 StackMacroAssembler masm(cx, tempAlloc);
498 AutoCreatedBy acb(masm, __func__);
500 PrepareJit(masm);
502 AllocatableGeneralRegisterSet allRegs(GeneralRegisterSet::All());
503 AllocatableFloatRegisterSet allFloatRegs(FloatRegisterSet::All());
504 FloatRegister input = allFloatRegs.takeAny();
505 # ifdef JS_NUNBOX32
506 Register64 output(allRegs.takeAny(), allRegs.takeAny());
507 # else
508 Register64 output(allRegs.takeAny());
509 # endif
510 Register temp = allRegs.takeAny();
512 masm.reserveStack(sizeof(int32_t));
514 # define TEST(INPUT, OUTPUT) \
516 Label next; \
517 masm.loadConstantDouble(double(INPUT), input); \
518 masm.storeDouble(input, Operand(esp, 0)); \
519 if (OUTPUT) { \
520 masm.branchDoubleNotInInt64Range(Address(esp, 0), temp, &next); \
521 } else { \
522 Label fail; \
523 masm.branchDoubleNotInInt64Range(Address(esp, 0), temp, &fail); \
524 masm.jump(&next); \
525 masm.bind(&fail); \
527 masm.printf("branchDoubleNotInInt64Range(" #INPUT ") failed\n"); \
528 masm.breakpoint(); \
529 masm.bind(&next); \
532 TEST(0, false);
533 TEST(-0, false);
534 TEST(1, false);
535 TEST(9223372036854774784.0, false);
536 TEST(-9223372036854775808.0, true);
537 TEST(9223372036854775808.0, true);
538 TEST(JS::GenericNaN(), true);
539 TEST(PositiveInfinity<double>(), true);
540 TEST(NegativeInfinity<double>(), true);
541 # undef TEST
543 masm.freeStack(sizeof(int32_t));
545 return ExecuteJit(cx, masm);
547 END_TEST(testJitMacroAssembler_branchDoubleNotInInt64Range)
549 BEGIN_TEST(testJitMacroAssembler_branchDoubleNotInUInt64Range) {
550 TempAllocator tempAlloc(&cx->tempLifoAlloc());
551 JitContext jcx(cx);
552 StackMacroAssembler masm(cx, tempAlloc);
553 AutoCreatedBy acb(masm, __func__);
555 PrepareJit(masm);
557 AllocatableGeneralRegisterSet allRegs(GeneralRegisterSet::All());
558 AllocatableFloatRegisterSet allFloatRegs(FloatRegisterSet::All());
559 FloatRegister input = allFloatRegs.takeAny();
560 # ifdef JS_NUNBOX32
561 Register64 output(allRegs.takeAny(), allRegs.takeAny());
562 # else
563 Register64 output(allRegs.takeAny());
564 # endif
565 Register temp = allRegs.takeAny();
567 masm.reserveStack(sizeof(int32_t));
569 # define TEST(INPUT, OUTPUT) \
571 Label next; \
572 masm.loadConstantDouble(double(INPUT), input); \
573 masm.storeDouble(input, Operand(esp, 0)); \
574 if (OUTPUT) { \
575 masm.branchDoubleNotInUInt64Range(Address(esp, 0), temp, &next); \
576 } else { \
577 Label fail; \
578 masm.branchDoubleNotInUInt64Range(Address(esp, 0), temp, &fail); \
579 masm.jump(&next); \
580 masm.bind(&fail); \
582 masm.printf("branchDoubleNotInUInt64Range(" #INPUT ") failed\n"); \
583 masm.breakpoint(); \
584 masm.bind(&next); \
587 TEST(0, false);
588 TEST(1, false);
589 TEST(9223372036854774784.0, false);
590 TEST((uint64_t)0x8000000000000000, false);
591 TEST((uint64_t)0x8000000000000001, false);
592 TEST((uint64_t)0x8006004000000001, false);
593 TEST(-0.0, true);
594 TEST(-0.5, true);
595 TEST(-0.99, true);
596 TEST(JS::GenericNaN(), true);
597 TEST(PositiveInfinity<double>(), true);
598 TEST(NegativeInfinity<double>(), true);
599 # undef TEST
601 masm.freeStack(sizeof(int32_t));
603 return ExecuteJit(cx, masm);
605 END_TEST(testJitMacroAssembler_branchDoubleNotInUInt64Range)
607 BEGIN_TEST(testJitMacroAssembler_lshift64) {
608 TempAllocator tempAlloc(&cx->tempLifoAlloc());
609 JitContext jcx(cx);
610 StackMacroAssembler masm(cx, tempAlloc);
611 AutoCreatedBy acb(masm, __func__);
613 PrepareJit(masm);
615 AllocatableGeneralRegisterSet allRegs(GeneralRegisterSet::All());
616 AllocatableFloatRegisterSet allFloatRegs(FloatRegisterSet::All());
617 # if defined(JS_CODEGEN_X86)
618 Register shift = ecx;
619 allRegs.take(shift);
620 # elif defined(JS_CODEGEN_X64)
621 Register shift = rcx;
622 allRegs.take(shift);
623 # else
624 Register shift = allRegs.takeAny();
625 # endif
627 # ifdef JS_NUNBOX32
628 Register64 input(allRegs.takeAny(), allRegs.takeAny());
629 # else
630 Register64 input(allRegs.takeAny());
631 # endif
633 masm.reserveStack(sizeof(int32_t));
635 # define TEST(SHIFT, INPUT, OUTPUT) \
637 Label next; \
638 masm.move64(Imm64(INPUT), input); \
639 masm.move32(Imm32(SHIFT), shift); \
640 masm.lshift64(shift, input); \
641 masm.branch64(Assembler::Equal, input, Imm64(OUTPUT), &next); \
642 masm.printf("lshift64(" #SHIFT ", " #INPUT ") failed\n"); \
643 masm.breakpoint(); \
644 masm.bind(&next); \
647 Label next; \
648 masm.move64(Imm64(INPUT), input); \
649 masm.lshift64(Imm32(SHIFT & 0x3f), input); \
650 masm.branch64(Assembler::Equal, input, Imm64(OUTPUT), &next); \
651 masm.printf("lshift64(Imm32(" #SHIFT "&0x3f), " #INPUT ") failed\n"); \
652 masm.breakpoint(); \
653 masm.bind(&next); \
656 TEST(0, 1, 1);
657 TEST(1, 1, 2);
658 TEST(2, 1, 4);
659 TEST(32, 1, 0x0000000100000000);
660 TEST(33, 1, 0x0000000200000000);
661 TEST(0, -1, 0xffffffffffffffff);
662 TEST(1, -1, 0xfffffffffffffffe);
663 TEST(2, -1, 0xfffffffffffffffc);
664 TEST(32, -1, 0xffffffff00000000);
665 TEST(0xffffffff, 1, 0x8000000000000000);
666 TEST(0xfffffffe, 1, 0x4000000000000000);
667 TEST(0xfffffffd, 1, 0x2000000000000000);
668 TEST(0x80000001, 1, 2);
669 # undef TEST
671 masm.freeStack(sizeof(int32_t));
673 return ExecuteJit(cx, masm);
675 END_TEST(testJitMacroAssembler_lshift64)
677 BEGIN_TEST(testJitMacroAssembler_rshift64Arithmetic) {
678 TempAllocator tempAlloc(&cx->tempLifoAlloc());
679 JitContext jcx(cx);
680 StackMacroAssembler masm(cx, tempAlloc);
681 AutoCreatedBy acb(masm, __func__);
683 PrepareJit(masm);
685 AllocatableGeneralRegisterSet allRegs(GeneralRegisterSet::All());
686 AllocatableFloatRegisterSet allFloatRegs(FloatRegisterSet::All());
687 # if defined(JS_CODEGEN_X86)
688 Register shift = ecx;
689 allRegs.take(shift);
690 # elif defined(JS_CODEGEN_X64)
691 Register shift = rcx;
692 allRegs.take(shift);
693 # else
694 Register shift = allRegs.takeAny();
695 # endif
697 # ifdef JS_NUNBOX32
698 Register64 input(allRegs.takeAny(), allRegs.takeAny());
699 # else
700 Register64 input(allRegs.takeAny());
701 # endif
703 masm.reserveStack(sizeof(int32_t));
705 # define TEST(SHIFT, INPUT, OUTPUT) \
707 Label next; \
708 masm.move64(Imm64(INPUT), input); \
709 masm.move32(Imm32(SHIFT), shift); \
710 masm.rshift64Arithmetic(shift, input); \
711 masm.branch64(Assembler::Equal, input, Imm64(OUTPUT), &next); \
712 masm.printf("rshift64Arithmetic(" #SHIFT ", " #INPUT ") failed\n"); \
713 masm.breakpoint(); \
714 masm.bind(&next); \
717 Label next; \
718 masm.move64(Imm64(INPUT), input); \
719 masm.rshift64Arithmetic(Imm32(SHIFT & 0x3f), input); \
720 masm.branch64(Assembler::Equal, input, Imm64(OUTPUT), &next); \
721 masm.printf("rshift64Arithmetic(Imm32(" #SHIFT "&0x3f), " #INPUT \
722 ") failed\n"); \
723 masm.breakpoint(); \
724 masm.bind(&next); \
727 TEST(0, 0x4000000000000000, 0x4000000000000000);
728 TEST(1, 0x4000000000000000, 0x2000000000000000);
729 TEST(2, 0x4000000000000000, 0x1000000000000000);
730 TEST(32, 0x4000000000000000, 0x0000000040000000);
731 TEST(0, 0x8000000000000000, 0x8000000000000000);
732 TEST(1, 0x8000000000000000, 0xc000000000000000);
733 TEST(2, 0x8000000000000000, 0xe000000000000000);
734 TEST(32, 0x8000000000000000, 0xffffffff80000000);
735 TEST(0xffffffff, 0x8000000000000000, 0xffffffffffffffff);
736 TEST(0xfffffffe, 0x8000000000000000, 0xfffffffffffffffe);
737 TEST(0xfffffffd, 0x8000000000000000, 0xfffffffffffffffc);
738 TEST(0x80000001, 0x8000000000000000, 0xc000000000000000);
739 # undef TEST
741 masm.freeStack(sizeof(int32_t));
743 return ExecuteJit(cx, masm);
745 END_TEST(testJitMacroAssembler_rshift64Arithmetic)
747 BEGIN_TEST(testJitMacroAssembler_rshift64) {
748 TempAllocator tempAlloc(&cx->tempLifoAlloc());
749 JitContext jcx(cx);
750 StackMacroAssembler masm(cx, tempAlloc);
751 AutoCreatedBy acb(masm, __func__);
753 PrepareJit(masm);
755 AllocatableGeneralRegisterSet allRegs(GeneralRegisterSet::All());
756 AllocatableFloatRegisterSet allFloatRegs(FloatRegisterSet::All());
757 # if defined(JS_CODEGEN_X86)
758 Register shift = ecx;
759 allRegs.take(shift);
760 # elif defined(JS_CODEGEN_X64)
761 Register shift = rcx;
762 allRegs.take(shift);
763 # else
764 Register shift = allRegs.takeAny();
765 # endif
767 # ifdef JS_NUNBOX32
768 Register64 input(allRegs.takeAny(), allRegs.takeAny());
769 # else
770 Register64 input(allRegs.takeAny());
771 # endif
773 masm.reserveStack(sizeof(int32_t));
775 # define TEST(SHIFT, INPUT, OUTPUT) \
777 Label next; \
778 masm.move64(Imm64(INPUT), input); \
779 masm.move32(Imm32(SHIFT), shift); \
780 masm.rshift64(shift, input); \
781 masm.branch64(Assembler::Equal, input, Imm64(OUTPUT), &next); \
782 masm.printf("rshift64(" #SHIFT ", " #INPUT ") failed\n"); \
783 masm.breakpoint(); \
784 masm.bind(&next); \
787 Label next; \
788 masm.move64(Imm64(INPUT), input); \
789 masm.rshift64(Imm32(SHIFT & 0x3f), input); \
790 masm.branch64(Assembler::Equal, input, Imm64(OUTPUT), &next); \
791 masm.printf("rshift64(Imm32(" #SHIFT "&0x3f), " #INPUT ") failed\n"); \
792 masm.breakpoint(); \
793 masm.bind(&next); \
796 TEST(0, 0x4000000000000000, 0x4000000000000000);
797 TEST(1, 0x4000000000000000, 0x2000000000000000);
798 TEST(2, 0x4000000000000000, 0x1000000000000000);
799 TEST(32, 0x4000000000000000, 0x0000000040000000);
800 TEST(0, 0x8000000000000000, 0x8000000000000000);
801 TEST(1, 0x8000000000000000, 0x4000000000000000);
802 TEST(2, 0x8000000000000000, 0x2000000000000000);
803 TEST(32, 0x8000000000000000, 0x0000000080000000);
804 TEST(0xffffffff, 0x8000000000000000, 0x0000000000000001);
805 TEST(0xfffffffe, 0x8000000000000000, 0x0000000000000002);
806 TEST(0xfffffffd, 0x8000000000000000, 0x0000000000000004);
807 TEST(0x80000001, 0x8000000000000000, 0x4000000000000000);
808 # undef TEST
810 masm.freeStack(sizeof(int32_t));
812 return ExecuteJit(cx, masm);
814 END_TEST(testJitMacroAssembler_rshift64)
816 #endif