Bug 1716030 [wpt PR 29346] - Update wpt metadata, a=testonly
[gecko.git] / js / src / jsapi-tests / testJitMacroAssembler.cpp
blob3f5c881d6ced2caa45245969a053e3e8bb173bcc
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 StackMacroAssembler masm(cx);
31 AutoCreatedBy acb(masm, __func__);
33 PrepareJit(masm);
35 // Test case divides 9/2;
36 const uintptr_t quotient_result = 4;
37 const uintptr_t remainder_result = 1;
38 const uintptr_t dividend = 9;
39 const uintptr_t divisor = 2;
41 AllocatableGeneralRegisterSet leftOutputHandSides(GeneralRegisterSet::All());
43 while (!leftOutputHandSides.empty()) {
44 Register lhsOutput = leftOutputHandSides.takeAny();
46 AllocatableGeneralRegisterSet rightHandSides(GeneralRegisterSet::All());
47 while (!rightHandSides.empty()) {
48 Register rhs = rightHandSides.takeAny();
50 AllocatableGeneralRegisterSet remainders(GeneralRegisterSet::All());
51 while (!remainders.empty()) {
52 Register remainderOutput = remainders.takeAny();
53 if (lhsOutput == rhs || lhsOutput == remainderOutput ||
54 rhs == remainderOutput) {
55 continue;
58 AllocatableRegisterSet regs(RegisterSet::Volatile());
59 LiveRegisterSet save(regs.asLiveSet());
61 Label next, fail;
62 masm.mov(ImmWord(dividend), lhsOutput);
63 masm.mov(ImmWord(divisor), rhs);
64 masm.flexibleDivMod32(rhs, lhsOutput, remainderOutput, false, save);
65 masm.branch32(Assembler::NotEqual, AbsoluteAddress(&quotient_result),
66 lhsOutput, &fail);
67 masm.branch32(Assembler::NotEqual, AbsoluteAddress(&remainder_result),
68 remainderOutput, &fail);
69 // Ensure RHS was not clobbered
70 masm.branch32(Assembler::NotEqual, AbsoluteAddress(&divisor), rhs,
71 &fail);
72 masm.jump(&next);
73 masm.bind(&fail);
74 masm.printf("Failed");
75 masm.breakpoint();
77 masm.bind(&next);
82 return ExecuteJit(cx, masm);
84 END_TEST(testJitMacroAssembler_flexibleDivMod)
86 BEGIN_TEST(testJitMacroAssembler_flexibleRemainder) {
87 StackMacroAssembler masm(cx);
88 AutoCreatedBy acb(masm, __func__);
90 PrepareJit(masm);
92 // Test case divides 9/2;
93 const uintptr_t dividend = 9;
94 const uintptr_t divisor = 2;
95 const uintptr_t remainder_result = 1;
97 AllocatableGeneralRegisterSet leftOutputHandSides(GeneralRegisterSet::All());
99 while (!leftOutputHandSides.empty()) {
100 Register lhsOutput = leftOutputHandSides.takeAny();
102 AllocatableGeneralRegisterSet rightHandSides(GeneralRegisterSet::All());
103 while (!rightHandSides.empty()) {
104 Register rhs = rightHandSides.takeAny();
106 if (lhsOutput == rhs) {
107 continue;
110 AllocatableRegisterSet regs(RegisterSet::Volatile());
111 LiveRegisterSet save(regs.asLiveSet());
113 Label next, fail;
114 masm.mov(ImmWord(dividend), lhsOutput);
115 masm.mov(ImmWord(divisor), rhs);
116 masm.flexibleRemainder32(rhs, lhsOutput, false, save);
117 masm.branch32(Assembler::NotEqual, AbsoluteAddress(&remainder_result),
118 lhsOutput, &fail);
119 // Ensure RHS was not clobbered
120 masm.branch32(Assembler::NotEqual, AbsoluteAddress(&divisor), rhs, &fail);
121 masm.jump(&next);
122 masm.bind(&fail);
123 masm.printf("Failed\n");
124 masm.breakpoint();
126 masm.bind(&next);
130 return ExecuteJit(cx, masm);
132 END_TEST(testJitMacroAssembler_flexibleRemainder)
134 BEGIN_TEST(testJitMacroAssembler_flexibleQuotient) {
135 StackMacroAssembler masm(cx);
136 AutoCreatedBy acb(masm, __func__);
138 PrepareJit(masm);
140 // Test case divides 9/2;
141 const uintptr_t dividend = 9;
142 const uintptr_t divisor = 2;
143 const uintptr_t quotient_result = 4;
145 AllocatableGeneralRegisterSet leftOutputHandSides(GeneralRegisterSet::All());
147 while (!leftOutputHandSides.empty()) {
148 Register lhsOutput = leftOutputHandSides.takeAny();
150 AllocatableGeneralRegisterSet rightHandSides(GeneralRegisterSet::All());
151 while (!rightHandSides.empty()) {
152 Register rhs = rightHandSides.takeAny();
154 if (lhsOutput == rhs) {
155 continue;
158 AllocatableRegisterSet regs(RegisterSet::Volatile());
159 LiveRegisterSet save(regs.asLiveSet());
161 Label next, fail;
162 masm.mov(ImmWord(dividend), lhsOutput);
163 masm.mov(ImmWord(divisor), rhs);
164 masm.flexibleQuotient32(rhs, lhsOutput, false, save);
165 masm.branch32(Assembler::NotEqual, AbsoluteAddress(&quotient_result),
166 lhsOutput, &fail);
167 // Ensure RHS was not clobbered
168 masm.branch32(Assembler::NotEqual, AbsoluteAddress(&divisor), rhs, &fail);
169 masm.jump(&next);
170 masm.bind(&fail);
171 masm.printf("Failed\n");
172 masm.breakpoint();
174 masm.bind(&next);
178 return ExecuteJit(cx, masm);
180 END_TEST(testJitMacroAssembler_flexibleQuotient)
182 // To make sure ecx isn't being clobbered; globally scoped to ensure it has the
183 // right lifetime.
184 const uintptr_t guardEcx = 0xfeedbad;
186 bool shiftTest(JSContext* cx, const char* name,
187 void (*operation)(StackMacroAssembler& masm, Register, Register),
188 const uintptr_t* lhsInput, const uintptr_t* rhsInput,
189 const uintptr_t* result) {
190 StackMacroAssembler masm(cx);
191 AutoCreatedBy acb(masm, __func__);
193 PrepareJit(masm);
195 JS::AutoSuppressGCAnalysis suppress;
196 AllocatableGeneralRegisterSet leftOutputHandSides(GeneralRegisterSet::All());
198 while (!leftOutputHandSides.empty()) {
199 Register lhsOutput = leftOutputHandSides.takeAny();
201 AllocatableGeneralRegisterSet rightHandSides(GeneralRegisterSet::All());
202 while (!rightHandSides.empty()) {
203 Register rhs = rightHandSides.takeAny();
205 // You can only use shift as the same reg if the values are the same
206 if (lhsOutput == rhs && *lhsInput != *rhsInput) {
207 continue;
210 Label next, outputFail, clobberRhs, clobberEcx, dump;
211 masm.mov(ImmWord(guardEcx), ecx);
212 masm.mov(ImmWord(*lhsInput), lhsOutput);
213 masm.mov(ImmWord(*rhsInput), rhs);
215 operation(masm, rhs, lhsOutput);
217 // Ensure Result is correct
218 masm.branch32(Assembler::NotEqual, AbsoluteAddress(result), lhsOutput,
219 &outputFail);
221 // Ensure RHS was not clobbered, unless it's also the output register.
222 if (lhsOutput != rhs) {
223 masm.branch32(Assembler::NotEqual, AbsoluteAddress(rhsInput), rhs,
224 &clobberRhs);
227 if (lhsOutput != ecx && rhs != ecx) {
228 // If neither lhsOutput nor rhs is ecx, make sure ecx has been
229 // preserved, otherwise it's expected to be covered by the RHS clobber
230 // check above, or intentionally clobbered as the output.
231 masm.branch32(Assembler::NotEqual, AbsoluteAddress(&guardEcx), ecx,
232 &clobberEcx);
235 masm.jump(&next);
237 masm.bind(&outputFail);
238 masm.printf("Incorrect output (got %d) ", lhsOutput);
239 masm.jump(&dump);
241 masm.bind(&clobberRhs);
242 masm.printf("rhs clobbered %d", rhs);
243 masm.jump(&dump);
245 masm.bind(&clobberEcx);
246 masm.printf("ecx clobbered");
247 masm.jump(&dump);
249 masm.bind(&dump);
250 masm.mov(ImmPtr(lhsOutput.name()), lhsOutput);
251 masm.printf("(lhsOutput/srcDest) %s ", lhsOutput);
252 masm.mov(ImmPtr(name), lhsOutput);
253 masm.printf("%s ", lhsOutput);
254 masm.mov(ImmPtr(rhs.name()), lhsOutput);
255 masm.printf("(shift/rhs) %s \n", lhsOutput);
256 // Breakpoint to force test failure.
257 masm.breakpoint();
258 masm.bind(&next);
262 return ExecuteJit(cx, masm);
265 BEGIN_TEST(testJitMacroAssembler_flexibleRshift) {
267 // Test case 16 >> 2 == 4;
268 const uintptr_t lhsInput = 16;
269 const uintptr_t rhsInput = 2;
270 const uintptr_t result = 4;
272 bool res = shiftTest(
273 cx, "flexibleRshift32",
274 [](StackMacroAssembler& masm, Register rhs, Register lhsOutput) {
275 masm.flexibleRshift32(rhs, lhsOutput);
277 &lhsInput, &rhsInput, &result);
278 if (!res) {
279 return false;
284 // Test case 16 >> 16 == 0 -- this helps cover the case where the same
285 // register can be passed for source and dest.
286 const uintptr_t lhsInput = 16;
287 const uintptr_t rhsInput = 16;
288 const uintptr_t result = 0;
290 bool res = shiftTest(
291 cx, "flexibleRshift32",
292 [](StackMacroAssembler& masm, Register rhs, Register lhsOutput) {
293 masm.flexibleRshift32(rhs, lhsOutput);
295 &lhsInput, &rhsInput, &result);
296 if (!res) {
297 return false;
301 return true;
303 END_TEST(testJitMacroAssembler_flexibleRshift)
305 BEGIN_TEST(testJitMacroAssembler_flexibleRshiftArithmetic) {
307 // Test case 4294967295 >> 2 == 4294967295;
308 const uintptr_t lhsInput = 4294967295;
309 const uintptr_t rhsInput = 2;
310 const uintptr_t result = 4294967295;
311 bool res = shiftTest(
312 cx, "flexibleRshift32Arithmetic",
313 [](StackMacroAssembler& masm, Register rhs, Register lhsOutput) {
314 masm.flexibleRshift32Arithmetic(rhs, lhsOutput);
316 &lhsInput, &rhsInput, &result);
317 if (!res) {
318 return false;
323 // Test case 16 >> 16 == 0 -- this helps cover the case where the same
324 // register can be passed for source and dest.
325 const uintptr_t lhsInput = 16;
326 const uintptr_t rhsInput = 16;
327 const uintptr_t result = 0;
329 bool res = shiftTest(
330 cx, "flexibleRshift32Arithmetic",
331 [](StackMacroAssembler& masm, Register rhs, Register lhsOutput) {
332 masm.flexibleRshift32Arithmetic(rhs, lhsOutput);
334 &lhsInput, &rhsInput, &result);
335 if (!res) {
336 return false;
340 return true;
342 END_TEST(testJitMacroAssembler_flexibleRshiftArithmetic)
344 BEGIN_TEST(testJitMacroAssembler_flexibleLshift) {
346 // Test case 16 << 2 == 64;
347 const uintptr_t lhsInput = 16;
348 const uintptr_t rhsInput = 2;
349 const uintptr_t result = 64;
351 bool res = shiftTest(
352 cx, "flexibleLshift32",
353 [](StackMacroAssembler& masm, Register rhs, Register lhsOutput) {
354 masm.flexibleLshift32(rhs, lhsOutput);
356 &lhsInput, &rhsInput, &result);
357 if (!res) {
358 return false;
363 // Test case 4 << 4 == 64; duplicated input case
364 const uintptr_t lhsInput = 4;
365 const uintptr_t rhsInput = 4;
366 const uintptr_t result = 64;
368 bool res = shiftTest(
369 cx, "flexibleLshift32",
370 [](StackMacroAssembler& masm, Register rhs, Register lhsOutput) {
371 masm.flexibleLshift32(rhs, lhsOutput);
373 &lhsInput, &rhsInput, &result);
374 if (!res) {
375 return false;
379 return true;
381 END_TEST(testJitMacroAssembler_flexibleLshift)
383 BEGIN_TEST(testJitMacroAssembler_truncateDoubleToInt64) {
384 StackMacroAssembler masm(cx);
385 AutoCreatedBy acb(masm, __func__);
387 PrepareJit(masm);
389 AllocatableGeneralRegisterSet allRegs(GeneralRegisterSet::All());
390 AllocatableFloatRegisterSet allFloatRegs(FloatRegisterSet::All());
391 FloatRegister input = allFloatRegs.takeAny();
392 # ifdef JS_NUNBOX32
393 Register64 output(allRegs.takeAny(), allRegs.takeAny());
394 # else
395 Register64 output(allRegs.takeAny());
396 # endif
397 Register temp = allRegs.takeAny();
399 masm.reserveStack(sizeof(int32_t));
401 # define TEST(INPUT, OUTPUT) \
403 Label next; \
404 masm.loadConstantDouble(double(INPUT), input); \
405 masm.storeDouble(input, Operand(esp, 0)); \
406 masm.truncateDoubleToInt64(Address(esp, 0), Address(esp, 0), temp); \
407 masm.branch64(Assembler::Equal, Address(esp, 0), Imm64(OUTPUT), &next); \
408 masm.printf("truncateDoubleToInt64(" #INPUT ") failed\n"); \
409 masm.breakpoint(); \
410 masm.bind(&next); \
413 TEST(0, 0);
414 TEST(-0, 0);
415 TEST(1, 1);
416 TEST(9223372036854774784.0, 9223372036854774784);
417 TEST(-9223372036854775808.0, 0x8000000000000000);
418 TEST(9223372036854775808.0, 0x8000000000000000);
419 TEST(JS::GenericNaN(), 0x8000000000000000);
420 TEST(PositiveInfinity<double>(), 0x8000000000000000);
421 TEST(NegativeInfinity<double>(), 0x8000000000000000);
422 # undef TEST
424 masm.freeStack(sizeof(int32_t));
426 return ExecuteJit(cx, masm);
428 END_TEST(testJitMacroAssembler_truncateDoubleToInt64)
430 BEGIN_TEST(testJitMacroAssembler_truncateDoubleToUInt64) {
431 StackMacroAssembler masm(cx);
432 AutoCreatedBy acb(masm, __func__);
434 PrepareJit(masm);
436 AllocatableGeneralRegisterSet allRegs(GeneralRegisterSet::All());
437 AllocatableFloatRegisterSet allFloatRegs(FloatRegisterSet::All());
438 FloatRegister input = allFloatRegs.takeAny();
439 FloatRegister floatTemp = allFloatRegs.takeAny();
440 # ifdef JS_NUNBOX32
441 Register64 output(allRegs.takeAny(), allRegs.takeAny());
442 # else
443 Register64 output(allRegs.takeAny());
444 # endif
445 Register temp = allRegs.takeAny();
447 masm.reserveStack(sizeof(int32_t));
449 # define TEST(INPUT, OUTPUT) \
451 Label next; \
452 masm.loadConstantDouble(double(INPUT), input); \
453 masm.storeDouble(input, Operand(esp, 0)); \
454 masm.truncateDoubleToUInt64(Address(esp, 0), Address(esp, 0), temp, \
455 floatTemp); \
456 masm.branch64(Assembler::Equal, Address(esp, 0), Imm64(OUTPUT), &next); \
457 masm.printf("truncateDoubleToUInt64(" #INPUT ") failed\n"); \
458 masm.breakpoint(); \
459 masm.bind(&next); \
462 TEST(0, 0);
463 TEST(1, 1);
464 TEST(9223372036854774784.0, 9223372036854774784);
465 TEST((uint64_t)0x8000000000000000, 0x8000000000000000);
466 TEST((uint64_t)0x8000000000000001, 0x8000000000000000);
467 TEST((uint64_t)0x8006004000000001, 0x8006004000000000);
468 TEST(-0.0, 0);
469 TEST(-0.5, 0);
470 TEST(-0.99, 0);
471 TEST(JS::GenericNaN(), 0x8000000000000000);
472 TEST(PositiveInfinity<double>(), 0x8000000000000000);
473 TEST(NegativeInfinity<double>(), 0x8000000000000000);
474 # undef TEST
476 masm.freeStack(sizeof(int32_t));
478 return ExecuteJit(cx, masm);
480 END_TEST(testJitMacroAssembler_truncateDoubleToUInt64)
482 BEGIN_TEST(testJitMacroAssembler_branchDoubleNotInInt64Range) {
483 StackMacroAssembler masm(cx);
484 AutoCreatedBy acb(masm, __func__);
486 PrepareJit(masm);
488 AllocatableGeneralRegisterSet allRegs(GeneralRegisterSet::All());
489 AllocatableFloatRegisterSet allFloatRegs(FloatRegisterSet::All());
490 FloatRegister input = allFloatRegs.takeAny();
491 # ifdef JS_NUNBOX32
492 Register64 output(allRegs.takeAny(), allRegs.takeAny());
493 # else
494 Register64 output(allRegs.takeAny());
495 # endif
496 Register temp = allRegs.takeAny();
498 masm.reserveStack(sizeof(int32_t));
500 # define TEST(INPUT, OUTPUT) \
502 Label next; \
503 masm.loadConstantDouble(double(INPUT), input); \
504 masm.storeDouble(input, Operand(esp, 0)); \
505 if (OUTPUT) { \
506 masm.branchDoubleNotInInt64Range(Address(esp, 0), temp, &next); \
507 } else { \
508 Label fail; \
509 masm.branchDoubleNotInInt64Range(Address(esp, 0), temp, &fail); \
510 masm.jump(&next); \
511 masm.bind(&fail); \
513 masm.printf("branchDoubleNotInInt64Range(" #INPUT ") failed\n"); \
514 masm.breakpoint(); \
515 masm.bind(&next); \
518 TEST(0, false);
519 TEST(-0, false);
520 TEST(1, false);
521 TEST(9223372036854774784.0, false);
522 TEST(-9223372036854775808.0, true);
523 TEST(9223372036854775808.0, true);
524 TEST(JS::GenericNaN(), true);
525 TEST(PositiveInfinity<double>(), true);
526 TEST(NegativeInfinity<double>(), true);
527 # undef TEST
529 masm.freeStack(sizeof(int32_t));
531 return ExecuteJit(cx, masm);
533 END_TEST(testJitMacroAssembler_branchDoubleNotInInt64Range)
535 BEGIN_TEST(testJitMacroAssembler_branchDoubleNotInUInt64Range) {
536 StackMacroAssembler masm(cx);
537 AutoCreatedBy acb(masm, __func__);
539 PrepareJit(masm);
541 AllocatableGeneralRegisterSet allRegs(GeneralRegisterSet::All());
542 AllocatableFloatRegisterSet allFloatRegs(FloatRegisterSet::All());
543 FloatRegister input = allFloatRegs.takeAny();
544 # ifdef JS_NUNBOX32
545 Register64 output(allRegs.takeAny(), allRegs.takeAny());
546 # else
547 Register64 output(allRegs.takeAny());
548 # endif
549 Register temp = allRegs.takeAny();
551 masm.reserveStack(sizeof(int32_t));
553 # define TEST(INPUT, OUTPUT) \
555 Label next; \
556 masm.loadConstantDouble(double(INPUT), input); \
557 masm.storeDouble(input, Operand(esp, 0)); \
558 if (OUTPUT) { \
559 masm.branchDoubleNotInUInt64Range(Address(esp, 0), temp, &next); \
560 } else { \
561 Label fail; \
562 masm.branchDoubleNotInUInt64Range(Address(esp, 0), temp, &fail); \
563 masm.jump(&next); \
564 masm.bind(&fail); \
566 masm.printf("branchDoubleNotInUInt64Range(" #INPUT ") failed\n"); \
567 masm.breakpoint(); \
568 masm.bind(&next); \
571 TEST(0, false);
572 TEST(1, false);
573 TEST(9223372036854774784.0, false);
574 TEST((uint64_t)0x8000000000000000, false);
575 TEST((uint64_t)0x8000000000000001, false);
576 TEST((uint64_t)0x8006004000000001, false);
577 TEST(-0.0, true);
578 TEST(-0.5, true);
579 TEST(-0.99, true);
580 TEST(JS::GenericNaN(), true);
581 TEST(PositiveInfinity<double>(), true);
582 TEST(NegativeInfinity<double>(), true);
583 # undef TEST
585 masm.freeStack(sizeof(int32_t));
587 return ExecuteJit(cx, masm);
589 END_TEST(testJitMacroAssembler_branchDoubleNotInUInt64Range)
591 BEGIN_TEST(testJitMacroAssembler_lshift64) {
592 StackMacroAssembler masm(cx);
593 AutoCreatedBy acb(masm, __func__);
595 PrepareJit(masm);
597 AllocatableGeneralRegisterSet allRegs(GeneralRegisterSet::All());
598 AllocatableFloatRegisterSet allFloatRegs(FloatRegisterSet::All());
599 # if defined(JS_CODEGEN_X86)
600 Register shift = ecx;
601 allRegs.take(shift);
602 # elif defined(JS_CODEGEN_X64)
603 Register shift = rcx;
604 allRegs.take(shift);
605 # else
606 Register shift = allRegs.takeAny();
607 # endif
609 # ifdef JS_NUNBOX32
610 Register64 input(allRegs.takeAny(), allRegs.takeAny());
611 # else
612 Register64 input(allRegs.takeAny());
613 # endif
615 masm.reserveStack(sizeof(int32_t));
617 # define TEST(SHIFT, INPUT, OUTPUT) \
619 Label next; \
620 masm.move64(Imm64(INPUT), input); \
621 masm.move32(Imm32(SHIFT), shift); \
622 masm.lshift64(shift, input); \
623 masm.branch64(Assembler::Equal, input, Imm64(OUTPUT), &next); \
624 masm.printf("lshift64(" #SHIFT ", " #INPUT ") failed\n"); \
625 masm.breakpoint(); \
626 masm.bind(&next); \
629 Label next; \
630 masm.move64(Imm64(INPUT), input); \
631 masm.lshift64(Imm32(SHIFT & 0x3f), input); \
632 masm.branch64(Assembler::Equal, input, Imm64(OUTPUT), &next); \
633 masm.printf("lshift64(Imm32(" #SHIFT "&0x3f), " #INPUT ") failed\n"); \
634 masm.breakpoint(); \
635 masm.bind(&next); \
638 TEST(0, 1, 1);
639 TEST(1, 1, 2);
640 TEST(2, 1, 4);
641 TEST(32, 1, 0x0000000100000000);
642 TEST(33, 1, 0x0000000200000000);
643 TEST(0, -1, 0xffffffffffffffff);
644 TEST(1, -1, 0xfffffffffffffffe);
645 TEST(2, -1, 0xfffffffffffffffc);
646 TEST(32, -1, 0xffffffff00000000);
647 TEST(0xffffffff, 1, 0x8000000000000000);
648 TEST(0xfffffffe, 1, 0x4000000000000000);
649 TEST(0xfffffffd, 1, 0x2000000000000000);
650 TEST(0x80000001, 1, 2);
651 # undef TEST
653 masm.freeStack(sizeof(int32_t));
655 return ExecuteJit(cx, masm);
657 END_TEST(testJitMacroAssembler_lshift64)
659 BEGIN_TEST(testJitMacroAssembler_rshift64Arithmetic) {
660 StackMacroAssembler masm(cx);
661 AutoCreatedBy acb(masm, __func__);
663 PrepareJit(masm);
665 AllocatableGeneralRegisterSet allRegs(GeneralRegisterSet::All());
666 AllocatableFloatRegisterSet allFloatRegs(FloatRegisterSet::All());
667 # if defined(JS_CODEGEN_X86)
668 Register shift = ecx;
669 allRegs.take(shift);
670 # elif defined(JS_CODEGEN_X64)
671 Register shift = rcx;
672 allRegs.take(shift);
673 # else
674 Register shift = allRegs.takeAny();
675 # endif
677 # ifdef JS_NUNBOX32
678 Register64 input(allRegs.takeAny(), allRegs.takeAny());
679 # else
680 Register64 input(allRegs.takeAny());
681 # endif
683 masm.reserveStack(sizeof(int32_t));
685 # define TEST(SHIFT, INPUT, OUTPUT) \
687 Label next; \
688 masm.move64(Imm64(INPUT), input); \
689 masm.move32(Imm32(SHIFT), shift); \
690 masm.rshift64Arithmetic(shift, input); \
691 masm.branch64(Assembler::Equal, input, Imm64(OUTPUT), &next); \
692 masm.printf("rshift64Arithmetic(" #SHIFT ", " #INPUT ") failed\n"); \
693 masm.breakpoint(); \
694 masm.bind(&next); \
697 Label next; \
698 masm.move64(Imm64(INPUT), input); \
699 masm.rshift64Arithmetic(Imm32(SHIFT & 0x3f), input); \
700 masm.branch64(Assembler::Equal, input, Imm64(OUTPUT), &next); \
701 masm.printf("rshift64Arithmetic(Imm32(" #SHIFT "&0x3f), " #INPUT \
702 ") failed\n"); \
703 masm.breakpoint(); \
704 masm.bind(&next); \
707 TEST(0, 0x4000000000000000, 0x4000000000000000);
708 TEST(1, 0x4000000000000000, 0x2000000000000000);
709 TEST(2, 0x4000000000000000, 0x1000000000000000);
710 TEST(32, 0x4000000000000000, 0x0000000040000000);
711 TEST(0, 0x8000000000000000, 0x8000000000000000);
712 TEST(1, 0x8000000000000000, 0xc000000000000000);
713 TEST(2, 0x8000000000000000, 0xe000000000000000);
714 TEST(32, 0x8000000000000000, 0xffffffff80000000);
715 TEST(0xffffffff, 0x8000000000000000, 0xffffffffffffffff);
716 TEST(0xfffffffe, 0x8000000000000000, 0xfffffffffffffffe);
717 TEST(0xfffffffd, 0x8000000000000000, 0xfffffffffffffffc);
718 TEST(0x80000001, 0x8000000000000000, 0xc000000000000000);
719 # undef TEST
721 masm.freeStack(sizeof(int32_t));
723 return ExecuteJit(cx, masm);
725 END_TEST(testJitMacroAssembler_rshift64Arithmetic)
727 BEGIN_TEST(testJitMacroAssembler_rshift64) {
728 StackMacroAssembler masm(cx);
729 AutoCreatedBy acb(masm, __func__);
731 PrepareJit(masm);
733 AllocatableGeneralRegisterSet allRegs(GeneralRegisterSet::All());
734 AllocatableFloatRegisterSet allFloatRegs(FloatRegisterSet::All());
735 # if defined(JS_CODEGEN_X86)
736 Register shift = ecx;
737 allRegs.take(shift);
738 # elif defined(JS_CODEGEN_X64)
739 Register shift = rcx;
740 allRegs.take(shift);
741 # else
742 Register shift = allRegs.takeAny();
743 # endif
745 # ifdef JS_NUNBOX32
746 Register64 input(allRegs.takeAny(), allRegs.takeAny());
747 # else
748 Register64 input(allRegs.takeAny());
749 # endif
751 masm.reserveStack(sizeof(int32_t));
753 # define TEST(SHIFT, INPUT, OUTPUT) \
755 Label next; \
756 masm.move64(Imm64(INPUT), input); \
757 masm.move32(Imm32(SHIFT), shift); \
758 masm.rshift64(shift, input); \
759 masm.branch64(Assembler::Equal, input, Imm64(OUTPUT), &next); \
760 masm.printf("rshift64(" #SHIFT ", " #INPUT ") failed\n"); \
761 masm.breakpoint(); \
762 masm.bind(&next); \
765 Label next; \
766 masm.move64(Imm64(INPUT), input); \
767 masm.rshift64(Imm32(SHIFT & 0x3f), input); \
768 masm.branch64(Assembler::Equal, input, Imm64(OUTPUT), &next); \
769 masm.printf("rshift64(Imm32(" #SHIFT "&0x3f), " #INPUT ") failed\n"); \
770 masm.breakpoint(); \
771 masm.bind(&next); \
774 TEST(0, 0x4000000000000000, 0x4000000000000000);
775 TEST(1, 0x4000000000000000, 0x2000000000000000);
776 TEST(2, 0x4000000000000000, 0x1000000000000000);
777 TEST(32, 0x4000000000000000, 0x0000000040000000);
778 TEST(0, 0x8000000000000000, 0x8000000000000000);
779 TEST(1, 0x8000000000000000, 0x4000000000000000);
780 TEST(2, 0x8000000000000000, 0x2000000000000000);
781 TEST(32, 0x8000000000000000, 0x0000000080000000);
782 TEST(0xffffffff, 0x8000000000000000, 0x0000000000000001);
783 TEST(0xfffffffe, 0x8000000000000000, 0x0000000000000002);
784 TEST(0xfffffffd, 0x8000000000000000, 0x0000000000000004);
785 TEST(0x80000001, 0x8000000000000000, 0x4000000000000000);
786 # undef TEST
788 masm.freeStack(sizeof(int32_t));
790 return ExecuteJit(cx, masm);
792 END_TEST(testJitMacroAssembler_rshift64)
794 #endif