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:
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"
16 #include "jsapi-tests/tests.h"
17 #include "jsapi-tests/testsJit.h"
19 #include "jit/MacroAssembler-inl.h"
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());
32 StackMacroAssembler
masm(cx
, tempAlloc
);
33 AutoCreatedBy
acb(masm
, __func__
);
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
) {
60 AllocatableRegisterSet
regs(RegisterSet::Volatile());
61 LiveRegisterSet
save(regs
.asLiveSet());
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("ient_result
),
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
,
76 masm
.printf("Failed");
84 return ExecuteJit(cx
, masm
);
86 END_TEST(testJitMacroAssembler_flexibleDivMod
)
88 BEGIN_TEST(testJitMacroAssembler_flexibleRemainder
) {
89 TempAllocator
tempAlloc(&cx
->tempLifoAlloc());
91 StackMacroAssembler
masm(cx
, tempAlloc
);
92 AutoCreatedBy
acb(masm
, __func__
);
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
) {
114 AllocatableRegisterSet
regs(RegisterSet::Volatile());
115 LiveRegisterSet
save(regs
.asLiveSet());
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
),
123 // Ensure RHS was not clobbered
124 masm
.branch32(Assembler::NotEqual
, AbsoluteAddress(&divisor
), rhs
, &fail
);
127 masm
.printf("Failed\n");
134 return ExecuteJit(cx
, masm
);
136 END_TEST(testJitMacroAssembler_flexibleRemainder
)
138 BEGIN_TEST(testJitMacroAssembler_flexibleQuotient
) {
139 TempAllocator
tempAlloc(&cx
->tempLifoAlloc());
141 StackMacroAssembler
masm(cx
, tempAlloc
);
142 AutoCreatedBy
acb(masm
, __func__
);
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
) {
164 AllocatableRegisterSet
regs(RegisterSet::Volatile());
165 LiveRegisterSet
save(regs
.asLiveSet());
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("ient_result
),
173 // Ensure RHS was not clobbered
174 masm
.branch32(Assembler::NotEqual
, AbsoluteAddress(&divisor
), rhs
, &fail
);
177 masm
.printf("Failed\n");
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
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());
198 StackMacroAssembler
masm(cx
, tempAlloc
);
199 AutoCreatedBy
acb(masm
, __func__
);
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
) {
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
,
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
,
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
,
245 masm
.bind(&outputFail
);
246 masm
.printf("Incorrect output (got %d) ", lhsOutput
);
249 masm
.bind(&clobberRhs
);
250 masm
.printf("rhs clobbered %d", rhs
);
253 masm
.bind(&clobberEcx
);
254 masm
.printf("ecx clobbered");
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.
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
);
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
);
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
);
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
);
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
);
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
);
389 END_TEST(testJitMacroAssembler_flexibleLshift
)
391 BEGIN_TEST(testJitMacroAssembler_truncateDoubleToInt64
) {
392 TempAllocator
tempAlloc(&cx
->tempLifoAlloc());
394 StackMacroAssembler
masm(cx
, tempAlloc
);
395 AutoCreatedBy
acb(masm
, __func__
);
399 AllocatableGeneralRegisterSet
allRegs(GeneralRegisterSet::All());
400 AllocatableFloatRegisterSet
allFloatRegs(FloatRegisterSet::All());
401 FloatRegister input
= allFloatRegs
.takeAny();
403 Register64
output(allRegs
.takeAny(), allRegs
.takeAny());
405 Register64
output(allRegs
.takeAny());
407 Register temp
= allRegs
.takeAny();
409 masm
.reserveStack(sizeof(int32_t));
411 # define TEST(INPUT, OUTPUT) \
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"); \
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);
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());
443 StackMacroAssembler
masm(cx
, tempAlloc
);
444 AutoCreatedBy
acb(masm
, __func__
);
448 AllocatableGeneralRegisterSet
allRegs(GeneralRegisterSet::All());
449 AllocatableFloatRegisterSet
allFloatRegs(FloatRegisterSet::All());
450 FloatRegister input
= allFloatRegs
.takeAny();
451 FloatRegister floatTemp
= allFloatRegs
.takeAny();
453 Register64
output(allRegs
.takeAny(), allRegs
.takeAny());
455 Register64
output(allRegs
.takeAny());
457 Register temp
= allRegs
.takeAny();
459 masm
.reserveStack(sizeof(int32_t));
461 # define TEST(INPUT, OUTPUT) \
464 masm.loadConstantDouble(double(INPUT), input); \
465 masm.storeDouble(input, Operand(esp, 0)); \
466 masm.truncateDoubleToUInt64(Address(esp, 0), Address(esp, 0), temp, \
468 masm.branch64(Assembler::Equal, Address(esp, 0), Imm64(OUTPUT), &next); \
469 masm.printf("truncateDoubleToUInt64(" #INPUT ") failed\n"); \
476 TEST(9223372036854774784.0, 9223372036854774784);
477 TEST((uint64_t)0x8000000000000000, 0x8000000000000000);
478 TEST((uint64_t)0x8000000000000001, 0x8000000000000000);
479 TEST((uint64_t)0x8006004000000001, 0x8006004000000000);
483 TEST(JS::GenericNaN(), 0x8000000000000000);
484 TEST(PositiveInfinity
<double>(), 0x8000000000000000);
485 TEST(NegativeInfinity
<double>(), 0x8000000000000000);
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());
497 StackMacroAssembler
masm(cx
, tempAlloc
);
498 AutoCreatedBy
acb(masm
, __func__
);
502 AllocatableGeneralRegisterSet
allRegs(GeneralRegisterSet::All());
503 AllocatableFloatRegisterSet
allFloatRegs(FloatRegisterSet::All());
504 FloatRegister input
= allFloatRegs
.takeAny();
506 Register64
output(allRegs
.takeAny(), allRegs
.takeAny());
508 Register64
output(allRegs
.takeAny());
510 Register temp
= allRegs
.takeAny();
512 masm
.reserveStack(sizeof(int32_t));
514 # define TEST(INPUT, OUTPUT) \
517 masm.loadConstantDouble(double(INPUT), input); \
518 masm.storeDouble(input, Operand(esp, 0)); \
520 masm.branchDoubleNotInInt64Range(Address(esp, 0), temp, &next); \
523 masm.branchDoubleNotInInt64Range(Address(esp, 0), temp, &fail); \
527 masm.printf("branchDoubleNotInInt64Range(" #INPUT ") failed\n"); \
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);
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());
552 StackMacroAssembler
masm(cx
, tempAlloc
);
553 AutoCreatedBy
acb(masm
, __func__
);
557 AllocatableGeneralRegisterSet
allRegs(GeneralRegisterSet::All());
558 AllocatableFloatRegisterSet
allFloatRegs(FloatRegisterSet::All());
559 FloatRegister input
= allFloatRegs
.takeAny();
561 Register64
output(allRegs
.takeAny(), allRegs
.takeAny());
563 Register64
output(allRegs
.takeAny());
565 Register temp
= allRegs
.takeAny();
567 masm
.reserveStack(sizeof(int32_t));
569 # define TEST(INPUT, OUTPUT) \
572 masm.loadConstantDouble(double(INPUT), input); \
573 masm.storeDouble(input, Operand(esp, 0)); \
575 masm.branchDoubleNotInUInt64Range(Address(esp, 0), temp, &next); \
578 masm.branchDoubleNotInUInt64Range(Address(esp, 0), temp, &fail); \
582 masm.printf("branchDoubleNotInUInt64Range(" #INPUT ") failed\n"); \
589 TEST(9223372036854774784.0, false);
590 TEST((uint64_t)0x8000000000000000, false);
591 TEST((uint64_t)0x8000000000000001, false);
592 TEST((uint64_t)0x8006004000000001, false);
596 TEST(JS::GenericNaN(), true);
597 TEST(PositiveInfinity
<double>(), true);
598 TEST(NegativeInfinity
<double>(), true);
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());
610 StackMacroAssembler
masm(cx
, tempAlloc
);
611 AutoCreatedBy
acb(masm
, __func__
);
615 AllocatableGeneralRegisterSet
allRegs(GeneralRegisterSet::All());
616 AllocatableFloatRegisterSet
allFloatRegs(FloatRegisterSet::All());
617 # if defined(JS_CODEGEN_X86)
618 Register shift
= ecx
;
620 # elif defined(JS_CODEGEN_X64)
621 Register shift
= rcx
;
624 Register shift
= allRegs
.takeAny();
628 Register64
input(allRegs
.takeAny(), allRegs
.takeAny());
630 Register64
input(allRegs
.takeAny());
633 masm
.reserveStack(sizeof(int32_t));
635 # define TEST(SHIFT, INPUT, OUTPUT) \
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"); \
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"); \
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);
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());
680 StackMacroAssembler
masm(cx
, tempAlloc
);
681 AutoCreatedBy
acb(masm
, __func__
);
685 AllocatableGeneralRegisterSet
allRegs(GeneralRegisterSet::All());
686 AllocatableFloatRegisterSet
allFloatRegs(FloatRegisterSet::All());
687 # if defined(JS_CODEGEN_X86)
688 Register shift
= ecx
;
690 # elif defined(JS_CODEGEN_X64)
691 Register shift
= rcx
;
694 Register shift
= allRegs
.takeAny();
698 Register64
input(allRegs
.takeAny(), allRegs
.takeAny());
700 Register64
input(allRegs
.takeAny());
703 masm
.reserveStack(sizeof(int32_t));
705 # define TEST(SHIFT, INPUT, OUTPUT) \
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"); \
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 \
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);
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());
750 StackMacroAssembler
masm(cx
, tempAlloc
);
751 AutoCreatedBy
acb(masm
, __func__
);
755 AllocatableGeneralRegisterSet
allRegs(GeneralRegisterSet::All());
756 AllocatableFloatRegisterSet
allFloatRegs(FloatRegisterSet::All());
757 # if defined(JS_CODEGEN_X86)
758 Register shift
= ecx
;
760 # elif defined(JS_CODEGEN_X64)
761 Register shift
= rcx
;
764 Register shift
= allRegs
.takeAny();
768 Register64
input(allRegs
.takeAny(), allRegs
.takeAny());
770 Register64
input(allRegs
.takeAny());
773 masm
.reserveStack(sizeof(int32_t));
775 # define TEST(SHIFT, INPUT, OUTPUT) \
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"); \
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"); \
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);
810 masm
.freeStack(sizeof(int32_t));
812 return ExecuteJit(cx
, masm
);
814 END_TEST(testJitMacroAssembler_rshift64
)