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/. */
7
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"
15
16 #include "jsapi-tests/tests.h"
17
18 #include "jit/MacroAssembler-inl.h"
19
20 using namespace js;
21 using namespace js::jit;
22
23 using mozilla::NegativeInfinity;
24 using mozilla::PositiveInfinity;
25
26 #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
27
28 typedef void (*EnterTest)();
29
Prepare(MacroAssembler & masm)30 static bool Prepare(MacroAssembler& masm) {
31 AllocatableRegisterSet regs(RegisterSet::All());
32 LiveRegisterSet save(regs.asLiveSet());
33 masm.PushRegsInMask(save);
34 return true;
35 }
36
Execute(JSContext * cx,MacroAssembler & masm)37 static bool Execute(JSContext* cx, MacroAssembler& masm) {
38 AllocatableRegisterSet regs(RegisterSet::All());
39 LiveRegisterSet save(regs.asLiveSet());
40 masm.PopRegsInMask(save);
41 masm.ret(); // Add return statement to be sure.
42
43 if (masm.oom()) {
44 return false;
45 }
46
47 Linker linker(masm);
48 JitCode* code = linker.newCode(cx, CodeKind::Other);
49 if (!code) {
50 return false;
51 }
52 if (!ExecutableAllocator::makeExecutableAndFlushICache(code->raw(),
53 code->bufferSize())) {
54 return false;
55 }
56
57 JS::AutoSuppressGCAnalysis suppress;
58 EnterTest test = code->as<EnterTest>();
59 test();
60 return true;
61 }
62
BEGIN_TEST(testJitMacroAssembler_flexibleDivMod)63 BEGIN_TEST(testJitMacroAssembler_flexibleDivMod) {
64 StackMacroAssembler masm(cx);
65
66 if (!Prepare(masm)) {
67 return false;
68 }
69
70 // Test case divides 9/2;
71 const uintptr_t quotient_result = 4;
72 const uintptr_t remainder_result = 1;
73 const uintptr_t dividend = 9;
74 const uintptr_t divisor = 2;
75
76 AllocatableGeneralRegisterSet leftOutputHandSides(GeneralRegisterSet::All());
77
78 while (!leftOutputHandSides.empty()) {
79 Register lhsOutput = leftOutputHandSides.takeAny();
80
81 AllocatableGeneralRegisterSet rightHandSides(GeneralRegisterSet::All());
82 while (!rightHandSides.empty()) {
83 Register rhs = rightHandSides.takeAny();
84
85 AllocatableGeneralRegisterSet remainders(GeneralRegisterSet::All());
86 while (!remainders.empty()) {
87 Register remainderOutput = remainders.takeAny();
88 if (lhsOutput == rhs || lhsOutput == remainderOutput ||
89 rhs == remainderOutput) {
90 continue;
91 }
92
93 AllocatableRegisterSet regs(RegisterSet::Volatile());
94 LiveRegisterSet save(regs.asLiveSet());
95
96 Label next, fail;
97 masm.mov(ImmWord(dividend), lhsOutput);
98 masm.mov(ImmWord(divisor), rhs);
99 masm.flexibleDivMod32(rhs, lhsOutput, remainderOutput, false, save);
100 masm.branch32(Assembler::NotEqual, AbsoluteAddress("ient_result),
101 lhsOutput, &fail);
102 masm.branch32(Assembler::NotEqual, AbsoluteAddress(&remainder_result),
103 remainderOutput, &fail);
104 // Ensure RHS was not clobbered
105 masm.branch32(Assembler::NotEqual, AbsoluteAddress(&divisor), rhs,
106 &fail);
107 masm.jump(&next);
108 masm.bind(&fail);
109 masm.printf("Failed");
110 masm.breakpoint();
111
112 masm.bind(&next);
113 }
114 }
115 }
116
117 return Execute(cx, masm);
118 }
119 END_TEST(testJitMacroAssembler_flexibleDivMod)
120
BEGIN_TEST(testJitMacroAssembler_flexibleRemainder)121 BEGIN_TEST(testJitMacroAssembler_flexibleRemainder) {
122 StackMacroAssembler masm(cx);
123
124 if (!Prepare(masm)) {
125 return false;
126 }
127
128 // Test case divides 9/2;
129 const uintptr_t dividend = 9;
130 const uintptr_t divisor = 2;
131 const uintptr_t remainder_result = 1;
132
133 AllocatableGeneralRegisterSet leftOutputHandSides(GeneralRegisterSet::All());
134
135 while (!leftOutputHandSides.empty()) {
136 Register lhsOutput = leftOutputHandSides.takeAny();
137
138 AllocatableGeneralRegisterSet rightHandSides(GeneralRegisterSet::All());
139 while (!rightHandSides.empty()) {
140 Register rhs = rightHandSides.takeAny();
141
142 if (lhsOutput == rhs) {
143 continue;
144 }
145
146 AllocatableRegisterSet regs(RegisterSet::Volatile());
147 LiveRegisterSet save(regs.asLiveSet());
148
149 Label next, fail;
150 masm.mov(ImmWord(dividend), lhsOutput);
151 masm.mov(ImmWord(divisor), rhs);
152 masm.flexibleRemainder32(rhs, lhsOutput, false, save);
153 masm.branch32(Assembler::NotEqual, AbsoluteAddress(&remainder_result),
154 lhsOutput, &fail);
155 // Ensure RHS was not clobbered
156 masm.branch32(Assembler::NotEqual, AbsoluteAddress(&divisor), rhs, &fail);
157 masm.jump(&next);
158 masm.bind(&fail);
159 masm.printf("Failed\n");
160 masm.breakpoint();
161
162 masm.bind(&next);
163 }
164 }
165
166 return Execute(cx, masm);
167 }
168 END_TEST(testJitMacroAssembler_flexibleRemainder)
169
BEGIN_TEST(testJitMacroAssembler_flexibleQuotient)170 BEGIN_TEST(testJitMacroAssembler_flexibleQuotient) {
171 StackMacroAssembler masm(cx);
172
173 if (!Prepare(masm)) {
174 return false;
175 }
176
177 // Test case divides 9/2;
178 const uintptr_t dividend = 9;
179 const uintptr_t divisor = 2;
180 const uintptr_t quotient_result = 4;
181
182 AllocatableGeneralRegisterSet leftOutputHandSides(GeneralRegisterSet::All());
183
184 while (!leftOutputHandSides.empty()) {
185 Register lhsOutput = leftOutputHandSides.takeAny();
186
187 AllocatableGeneralRegisterSet rightHandSides(GeneralRegisterSet::All());
188 while (!rightHandSides.empty()) {
189 Register rhs = rightHandSides.takeAny();
190
191 if (lhsOutput == rhs) {
192 continue;
193 }
194
195 AllocatableRegisterSet regs(RegisterSet::Volatile());
196 LiveRegisterSet save(regs.asLiveSet());
197
198 Label next, fail;
199 masm.mov(ImmWord(dividend), lhsOutput);
200 masm.mov(ImmWord(divisor), rhs);
201 masm.flexibleQuotient32(rhs, lhsOutput, false, save);
202 masm.branch32(Assembler::NotEqual, AbsoluteAddress("ient_result),
203 lhsOutput, &fail);
204 // Ensure RHS was not clobbered
205 masm.branch32(Assembler::NotEqual, AbsoluteAddress(&divisor), rhs, &fail);
206 masm.jump(&next);
207 masm.bind(&fail);
208 masm.printf("Failed\n");
209 masm.breakpoint();
210
211 masm.bind(&next);
212 }
213 }
214
215 return Execute(cx, masm);
216 }
217 END_TEST(testJitMacroAssembler_flexibleQuotient)
218
219 // To make sure ecx isn't being clobbered; globally scoped to ensure it has the
220 // right lifetime.
221 const uintptr_t guardEcx = 0xfeedbad;
222
shiftTest(JSContext * cx,const char * name,void (* operation)(StackMacroAssembler & masm,Register,Register),const uintptr_t * lhsInput,const uintptr_t * rhsInput,const uintptr_t * result)223 bool shiftTest(JSContext* cx, const char* name,
224 void (*operation)(StackMacroAssembler& masm, Register, Register),
225 const uintptr_t* lhsInput, const uintptr_t* rhsInput,
226 const uintptr_t* result) {
227 StackMacroAssembler masm(cx);
228
229 if (!Prepare(masm)) {
230 return false;
231 }
232
233 JS::AutoSuppressGCAnalysis suppress;
234 AllocatableGeneralRegisterSet leftOutputHandSides(GeneralRegisterSet::All());
235
236 while (!leftOutputHandSides.empty()) {
237 Register lhsOutput = leftOutputHandSides.takeAny();
238
239 AllocatableGeneralRegisterSet rightHandSides(GeneralRegisterSet::All());
240 while (!rightHandSides.empty()) {
241 Register rhs = rightHandSides.takeAny();
242
243 // You can only use shift as the same reg if the values are the same
244 if (lhsOutput == rhs && *lhsInput != *rhsInput) {
245 continue;
246 }
247
248 Label next, outputFail, clobberRhs, clobberEcx, dump;
249 masm.mov(ImmWord(guardEcx), ecx);
250 masm.mov(ImmWord(*lhsInput), lhsOutput);
251 masm.mov(ImmWord(*rhsInput), rhs);
252
253 operation(masm, rhs, lhsOutput);
254
255 // Ensure Result is correct
256 masm.branch32(Assembler::NotEqual, AbsoluteAddress(result), lhsOutput,
257 &outputFail);
258
259 // Ensure RHS was not clobbered, unless it's also the output register.
260 if (lhsOutput != rhs) {
261 masm.branch32(Assembler::NotEqual, AbsoluteAddress(rhsInput), rhs,
262 &clobberRhs);
263 }
264
265 if (lhsOutput != ecx && rhs != ecx) {
266 // If neither lhsOutput nor rhs is ecx, make sure ecx has been
267 // preserved, otherwise it's expected to be covered by the RHS clobber
268 // check above, or intentionally clobbered as the output.
269 masm.branch32(Assembler::NotEqual, AbsoluteAddress(&guardEcx), ecx,
270 &clobberEcx);
271 }
272
273 masm.jump(&next);
274
275 masm.bind(&outputFail);
276 masm.printf("Incorrect output (got %d) ", lhsOutput);
277 masm.jump(&dump);
278
279 masm.bind(&clobberRhs);
280 masm.printf("rhs clobbered %d", rhs);
281 masm.jump(&dump);
282
283 masm.bind(&clobberEcx);
284 masm.printf("ecx clobbered");
285 masm.jump(&dump);
286
287 masm.bind(&dump);
288 masm.mov(ImmPtr(lhsOutput.name()), lhsOutput);
289 masm.printf("(lhsOutput/srcDest) %s ", lhsOutput);
290 masm.mov(ImmPtr(name), lhsOutput);
291 masm.printf("%s ", lhsOutput);
292 masm.mov(ImmPtr(rhs.name()), lhsOutput);
293 masm.printf("(shift/rhs) %s \n", lhsOutput);
294 // Breakpoint to force test failure.
295 masm.breakpoint();
296 masm.bind(&next);
297 }
298 }
299
300 return Execute(cx, masm);
301 }
302
BEGIN_TEST(testJitMacroAssembler_flexibleRshift)303 BEGIN_TEST(testJitMacroAssembler_flexibleRshift) {
304 {
305 // Test case 16 >> 2 == 4;
306 const uintptr_t lhsInput = 16;
307 const uintptr_t rhsInput = 2;
308 const uintptr_t result = 4;
309
310 bool res = shiftTest(
311 cx, "flexibleRshift32",
312 [](StackMacroAssembler& masm, Register rhs, Register lhsOutput) {
313 masm.flexibleRshift32(rhs, lhsOutput);
314 },
315 &lhsInput, &rhsInput, &result);
316 if (!res) {
317 return false;
318 }
319 }
320
321 {
322 // Test case 16 >> 16 == 0 -- this helps cover the case where the same
323 // register can be passed for source and dest.
324 const uintptr_t lhsInput = 16;
325 const uintptr_t rhsInput = 16;
326 const uintptr_t result = 0;
327
328 bool res = shiftTest(
329 cx, "flexibleRshift32",
330 [](StackMacroAssembler& masm, Register rhs, Register lhsOutput) {
331 masm.flexibleRshift32(rhs, lhsOutput);
332 },
333 &lhsInput, &rhsInput, &result);
334 if (!res) {
335 return false;
336 }
337 }
338
339 return true;
340 }
341 END_TEST(testJitMacroAssembler_flexibleRshift)
342
BEGIN_TEST(testJitMacroAssembler_flexibleRshiftArithmetic)343 BEGIN_TEST(testJitMacroAssembler_flexibleRshiftArithmetic) {
344 {
345 // Test case 4294967295 >> 2 == 4294967295;
346 const uintptr_t lhsInput = 4294967295;
347 const uintptr_t rhsInput = 2;
348 const uintptr_t result = 4294967295;
349 bool res = shiftTest(
350 cx, "flexibleRshift32Arithmetic",
351 [](StackMacroAssembler& masm, Register rhs, Register lhsOutput) {
352 masm.flexibleRshift32Arithmetic(rhs, lhsOutput);
353 },
354 &lhsInput, &rhsInput, &result);
355 if (!res) {
356 return false;
357 }
358 }
359
360 {
361 // Test case 16 >> 16 == 0 -- this helps cover the case where the same
362 // register can be passed for source and dest.
363 const uintptr_t lhsInput = 16;
364 const uintptr_t rhsInput = 16;
365 const uintptr_t result = 0;
366
367 bool res = shiftTest(
368 cx, "flexibleRshift32Arithmetic",
369 [](StackMacroAssembler& masm, Register rhs, Register lhsOutput) {
370 masm.flexibleRshift32Arithmetic(rhs, lhsOutput);
371 },
372 &lhsInput, &rhsInput, &result);
373 if (!res) {
374 return false;
375 }
376 }
377
378 return true;
379 }
380 END_TEST(testJitMacroAssembler_flexibleRshiftArithmetic)
381
BEGIN_TEST(testJitMacroAssembler_flexibleLshift)382 BEGIN_TEST(testJitMacroAssembler_flexibleLshift) {
383 {
384 // Test case 16 << 2 == 64;
385 const uintptr_t lhsInput = 16;
386 const uintptr_t rhsInput = 2;
387 const uintptr_t result = 64;
388
389 bool res = shiftTest(
390 cx, "flexibleLshift32",
391 [](StackMacroAssembler& masm, Register rhs, Register lhsOutput) {
392 masm.flexibleLshift32(rhs, lhsOutput);
393 },
394 &lhsInput, &rhsInput, &result);
395 if (!res) {
396 return false;
397 }
398 }
399
400 {
401 // Test case 4 << 4 == 64; duplicated input case
402 const uintptr_t lhsInput = 4;
403 const uintptr_t rhsInput = 4;
404 const uintptr_t result = 64;
405
406 bool res = shiftTest(
407 cx, "flexibleLshift32",
408 [](StackMacroAssembler& masm, Register rhs, Register lhsOutput) {
409 masm.flexibleLshift32(rhs, lhsOutput);
410 },
411 &lhsInput, &rhsInput, &result);
412 if (!res) {
413 return false;
414 }
415 }
416
417 return true;
418 }
419 END_TEST(testJitMacroAssembler_flexibleLshift)
420
BEGIN_TEST(testJitMacroAssembler_truncateDoubleToInt64)421 BEGIN_TEST(testJitMacroAssembler_truncateDoubleToInt64) {
422 StackMacroAssembler masm(cx);
423
424 if (!Prepare(masm)) {
425 return false;
426 }
427
428 AllocatableGeneralRegisterSet allRegs(GeneralRegisterSet::All());
429 AllocatableFloatRegisterSet allFloatRegs(FloatRegisterSet::All());
430 FloatRegister input = allFloatRegs.takeAny();
431 # ifdef JS_NUNBOX32
432 Register64 output(allRegs.takeAny(), allRegs.takeAny());
433 # else
434 Register64 output(allRegs.takeAny());
435 # endif
436 Register temp = allRegs.takeAny();
437
438 masm.reserveStack(sizeof(int32_t));
439
440 # define TEST(INPUT, OUTPUT) \
441 { \
442 Label next; \
443 masm.loadConstantDouble(double(INPUT), input); \
444 masm.storeDouble(input, Operand(esp, 0)); \
445 masm.truncateDoubleToInt64(Address(esp, 0), Address(esp, 0), temp); \
446 masm.branch64(Assembler::Equal, Address(esp, 0), Imm64(OUTPUT), &next); \
447 masm.printf("truncateDoubleToInt64(" #INPUT ") failed\n"); \
448 masm.breakpoint(); \
449 masm.bind(&next); \
450 }
451
452 TEST(0, 0);
453 TEST(-0, 0);
454 TEST(1, 1);
455 TEST(9223372036854774784.0, 9223372036854774784);
456 TEST(-9223372036854775808.0, 0x8000000000000000);
457 TEST(9223372036854775808.0, 0x8000000000000000);
458 TEST(JS::GenericNaN(), 0x8000000000000000);
459 TEST(PositiveInfinity<double>(), 0x8000000000000000);
460 TEST(NegativeInfinity<double>(), 0x8000000000000000);
461 # undef TEST
462
463 masm.freeStack(sizeof(int32_t));
464
465 return Execute(cx, masm);
466 }
467 END_TEST(testJitMacroAssembler_truncateDoubleToInt64)
468
BEGIN_TEST(testJitMacroAssembler_truncateDoubleToUInt64)469 BEGIN_TEST(testJitMacroAssembler_truncateDoubleToUInt64) {
470 StackMacroAssembler masm(cx);
471
472 if (!Prepare(masm)) {
473 return false;
474 }
475
476 AllocatableGeneralRegisterSet allRegs(GeneralRegisterSet::All());
477 AllocatableFloatRegisterSet allFloatRegs(FloatRegisterSet::All());
478 FloatRegister input = allFloatRegs.takeAny();
479 FloatRegister floatTemp = allFloatRegs.takeAny();
480 # ifdef JS_NUNBOX32
481 Register64 output(allRegs.takeAny(), allRegs.takeAny());
482 # else
483 Register64 output(allRegs.takeAny());
484 # endif
485 Register temp = allRegs.takeAny();
486
487 masm.reserveStack(sizeof(int32_t));
488
489 # define TEST(INPUT, OUTPUT) \
490 { \
491 Label next; \
492 masm.loadConstantDouble(double(INPUT), input); \
493 masm.storeDouble(input, Operand(esp, 0)); \
494 masm.truncateDoubleToUInt64(Address(esp, 0), Address(esp, 0), temp, \
495 floatTemp); \
496 masm.branch64(Assembler::Equal, Address(esp, 0), Imm64(OUTPUT), &next); \
497 masm.printf("truncateDoubleToUInt64(" #INPUT ") failed\n"); \
498 masm.breakpoint(); \
499 masm.bind(&next); \
500 }
501
502 TEST(0, 0);
503 TEST(1, 1);
504 TEST(9223372036854774784.0, 9223372036854774784);
505 TEST((uint64_t)0x8000000000000000, 0x8000000000000000);
506 TEST((uint64_t)0x8000000000000001, 0x8000000000000000);
507 TEST((uint64_t)0x8006004000000001, 0x8006004000000000);
508 TEST(-0.0, 0);
509 TEST(-0.5, 0);
510 TEST(-0.99, 0);
511 TEST(JS::GenericNaN(), 0x8000000000000000);
512 TEST(PositiveInfinity<double>(), 0x8000000000000000);
513 TEST(NegativeInfinity<double>(), 0x8000000000000000);
514 # undef TEST
515
516 masm.freeStack(sizeof(int32_t));
517
518 return Execute(cx, masm);
519 }
520 END_TEST(testJitMacroAssembler_truncateDoubleToUInt64)
521
BEGIN_TEST(testJitMacroAssembler_branchDoubleNotInInt64Range)522 BEGIN_TEST(testJitMacroAssembler_branchDoubleNotInInt64Range) {
523 StackMacroAssembler masm(cx);
524
525 if (!Prepare(masm)) {
526 return false;
527 }
528
529 AllocatableGeneralRegisterSet allRegs(GeneralRegisterSet::All());
530 AllocatableFloatRegisterSet allFloatRegs(FloatRegisterSet::All());
531 FloatRegister input = allFloatRegs.takeAny();
532 # ifdef JS_NUNBOX32
533 Register64 output(allRegs.takeAny(), allRegs.takeAny());
534 # else
535 Register64 output(allRegs.takeAny());
536 # endif
537 Register temp = allRegs.takeAny();
538
539 masm.reserveStack(sizeof(int32_t));
540
541 # define TEST(INPUT, OUTPUT) \
542 { \
543 Label next; \
544 masm.loadConstantDouble(double(INPUT), input); \
545 masm.storeDouble(input, Operand(esp, 0)); \
546 if (OUTPUT) { \
547 masm.branchDoubleNotInInt64Range(Address(esp, 0), temp, &next); \
548 } else { \
549 Label fail; \
550 masm.branchDoubleNotInInt64Range(Address(esp, 0), temp, &fail); \
551 masm.jump(&next); \
552 masm.bind(&fail); \
553 } \
554 masm.printf("branchDoubleNotInInt64Range(" #INPUT ") failed\n"); \
555 masm.breakpoint(); \
556 masm.bind(&next); \
557 }
558
559 TEST(0, false);
560 TEST(-0, false);
561 TEST(1, false);
562 TEST(9223372036854774784.0, false);
563 TEST(-9223372036854775808.0, true);
564 TEST(9223372036854775808.0, true);
565 TEST(JS::GenericNaN(), true);
566 TEST(PositiveInfinity<double>(), true);
567 TEST(NegativeInfinity<double>(), true);
568 # undef TEST
569
570 masm.freeStack(sizeof(int32_t));
571
572 return Execute(cx, masm);
573 }
574 END_TEST(testJitMacroAssembler_branchDoubleNotInInt64Range)
575
BEGIN_TEST(testJitMacroAssembler_branchDoubleNotInUInt64Range)576 BEGIN_TEST(testJitMacroAssembler_branchDoubleNotInUInt64Range) {
577 StackMacroAssembler masm(cx);
578
579 if (!Prepare(masm)) {
580 return false;
581 }
582
583 AllocatableGeneralRegisterSet allRegs(GeneralRegisterSet::All());
584 AllocatableFloatRegisterSet allFloatRegs(FloatRegisterSet::All());
585 FloatRegister input = allFloatRegs.takeAny();
586 # ifdef JS_NUNBOX32
587 Register64 output(allRegs.takeAny(), allRegs.takeAny());
588 # else
589 Register64 output(allRegs.takeAny());
590 # endif
591 Register temp = allRegs.takeAny();
592
593 masm.reserveStack(sizeof(int32_t));
594
595 # define TEST(INPUT, OUTPUT) \
596 { \
597 Label next; \
598 masm.loadConstantDouble(double(INPUT), input); \
599 masm.storeDouble(input, Operand(esp, 0)); \
600 if (OUTPUT) { \
601 masm.branchDoubleNotInUInt64Range(Address(esp, 0), temp, &next); \
602 } else { \
603 Label fail; \
604 masm.branchDoubleNotInUInt64Range(Address(esp, 0), temp, &fail); \
605 masm.jump(&next); \
606 masm.bind(&fail); \
607 } \
608 masm.printf("branchDoubleNotInUInt64Range(" #INPUT ") failed\n"); \
609 masm.breakpoint(); \
610 masm.bind(&next); \
611 }
612
613 TEST(0, false);
614 TEST(1, false);
615 TEST(9223372036854774784.0, false);
616 TEST((uint64_t)0x8000000000000000, false);
617 TEST((uint64_t)0x8000000000000001, false);
618 TEST((uint64_t)0x8006004000000001, false);
619 TEST(-0.0, true);
620 TEST(-0.5, true);
621 TEST(-0.99, true);
622 TEST(JS::GenericNaN(), true);
623 TEST(PositiveInfinity<double>(), true);
624 TEST(NegativeInfinity<double>(), true);
625 # undef TEST
626
627 masm.freeStack(sizeof(int32_t));
628
629 return Execute(cx, masm);
630 }
631 END_TEST(testJitMacroAssembler_branchDoubleNotInUInt64Range)
632
BEGIN_TEST(testJitMacroAssembler_lshift64)633 BEGIN_TEST(testJitMacroAssembler_lshift64) {
634 StackMacroAssembler masm(cx);
635
636 if (!Prepare(masm)) {
637 return false;
638 }
639
640 AllocatableGeneralRegisterSet allRegs(GeneralRegisterSet::All());
641 AllocatableFloatRegisterSet allFloatRegs(FloatRegisterSet::All());
642 # if defined(JS_CODEGEN_X86)
643 Register shift = ecx;
644 allRegs.take(shift);
645 # elif defined(JS_CODEGEN_X64)
646 Register shift = rcx;
647 allRegs.take(shift);
648 # else
649 Register shift = allRegs.takeAny();
650 # endif
651
652 # ifdef JS_NUNBOX32
653 Register64 input(allRegs.takeAny(), allRegs.takeAny());
654 # else
655 Register64 input(allRegs.takeAny());
656 # endif
657
658 masm.reserveStack(sizeof(int32_t));
659
660 # define TEST(SHIFT, INPUT, OUTPUT) \
661 { \
662 Label next; \
663 masm.move64(Imm64(INPUT), input); \
664 masm.move32(Imm32(SHIFT), shift); \
665 masm.lshift64(shift, input); \
666 masm.branch64(Assembler::Equal, input, Imm64(OUTPUT), &next); \
667 masm.printf("lshift64(" #SHIFT ", " #INPUT ") failed\n"); \
668 masm.breakpoint(); \
669 masm.bind(&next); \
670 } \
671 { \
672 Label next; \
673 masm.move64(Imm64(INPUT), input); \
674 masm.lshift64(Imm32(SHIFT & 0x3f), input); \
675 masm.branch64(Assembler::Equal, input, Imm64(OUTPUT), &next); \
676 masm.printf("lshift64(Imm32(" #SHIFT "&0x3f), " #INPUT ") failed\n"); \
677 masm.breakpoint(); \
678 masm.bind(&next); \
679 }
680
681 TEST(0, 1, 1);
682 TEST(1, 1, 2);
683 TEST(2, 1, 4);
684 TEST(32, 1, 0x0000000100000000);
685 TEST(33, 1, 0x0000000200000000);
686 TEST(0, -1, 0xffffffffffffffff);
687 TEST(1, -1, 0xfffffffffffffffe);
688 TEST(2, -1, 0xfffffffffffffffc);
689 TEST(32, -1, 0xffffffff00000000);
690 TEST(0xffffffff, 1, 0x8000000000000000);
691 TEST(0xfffffffe, 1, 0x4000000000000000);
692 TEST(0xfffffffd, 1, 0x2000000000000000);
693 TEST(0x80000001, 1, 2);
694 # undef TEST
695
696 masm.freeStack(sizeof(int32_t));
697
698 return Execute(cx, masm);
699 }
700 END_TEST(testJitMacroAssembler_lshift64)
701
BEGIN_TEST(testJitMacroAssembler_rshift64Arithmetic)702 BEGIN_TEST(testJitMacroAssembler_rshift64Arithmetic) {
703 StackMacroAssembler masm(cx);
704
705 if (!Prepare(masm)) {
706 return false;
707 }
708
709 AllocatableGeneralRegisterSet allRegs(GeneralRegisterSet::All());
710 AllocatableFloatRegisterSet allFloatRegs(FloatRegisterSet::All());
711 # if defined(JS_CODEGEN_X86)
712 Register shift = ecx;
713 allRegs.take(shift);
714 # elif defined(JS_CODEGEN_X64)
715 Register shift = rcx;
716 allRegs.take(shift);
717 # else
718 Register shift = allRegs.takeAny();
719 # endif
720
721 # ifdef JS_NUNBOX32
722 Register64 input(allRegs.takeAny(), allRegs.takeAny());
723 # else
724 Register64 input(allRegs.takeAny());
725 # endif
726
727 masm.reserveStack(sizeof(int32_t));
728
729 # define TEST(SHIFT, INPUT, OUTPUT) \
730 { \
731 Label next; \
732 masm.move64(Imm64(INPUT), input); \
733 masm.move32(Imm32(SHIFT), shift); \
734 masm.rshift64Arithmetic(shift, input); \
735 masm.branch64(Assembler::Equal, input, Imm64(OUTPUT), &next); \
736 masm.printf("rshift64Arithmetic(" #SHIFT ", " #INPUT ") failed\n"); \
737 masm.breakpoint(); \
738 masm.bind(&next); \
739 } \
740 { \
741 Label next; \
742 masm.move64(Imm64(INPUT), input); \
743 masm.rshift64Arithmetic(Imm32(SHIFT & 0x3f), input); \
744 masm.branch64(Assembler::Equal, input, Imm64(OUTPUT), &next); \
745 masm.printf("rshift64Arithmetic(Imm32(" #SHIFT "&0x3f), " #INPUT \
746 ") failed\n"); \
747 masm.breakpoint(); \
748 masm.bind(&next); \
749 }
750
751 TEST(0, 0x4000000000000000, 0x4000000000000000);
752 TEST(1, 0x4000000000000000, 0x2000000000000000);
753 TEST(2, 0x4000000000000000, 0x1000000000000000);
754 TEST(32, 0x4000000000000000, 0x0000000040000000);
755 TEST(0, 0x8000000000000000, 0x8000000000000000);
756 TEST(1, 0x8000000000000000, 0xc000000000000000);
757 TEST(2, 0x8000000000000000, 0xe000000000000000);
758 TEST(32, 0x8000000000000000, 0xffffffff80000000);
759 TEST(0xffffffff, 0x8000000000000000, 0xffffffffffffffff);
760 TEST(0xfffffffe, 0x8000000000000000, 0xfffffffffffffffe);
761 TEST(0xfffffffd, 0x8000000000000000, 0xfffffffffffffffc);
762 TEST(0x80000001, 0x8000000000000000, 0xc000000000000000);
763 # undef TEST
764
765 masm.freeStack(sizeof(int32_t));
766
767 return Execute(cx, masm);
768 }
769 END_TEST(testJitMacroAssembler_rshift64Arithmetic)
770
BEGIN_TEST(testJitMacroAssembler_rshift64)771 BEGIN_TEST(testJitMacroAssembler_rshift64) {
772 StackMacroAssembler masm(cx);
773
774 if (!Prepare(masm)) {
775 return false;
776 }
777
778 AllocatableGeneralRegisterSet allRegs(GeneralRegisterSet::All());
779 AllocatableFloatRegisterSet allFloatRegs(FloatRegisterSet::All());
780 # if defined(JS_CODEGEN_X86)
781 Register shift = ecx;
782 allRegs.take(shift);
783 # elif defined(JS_CODEGEN_X64)
784 Register shift = rcx;
785 allRegs.take(shift);
786 # else
787 Register shift = allRegs.takeAny();
788 # endif
789
790 # ifdef JS_NUNBOX32
791 Register64 input(allRegs.takeAny(), allRegs.takeAny());
792 # else
793 Register64 input(allRegs.takeAny());
794 # endif
795
796 masm.reserveStack(sizeof(int32_t));
797
798 # define TEST(SHIFT, INPUT, OUTPUT) \
799 { \
800 Label next; \
801 masm.move64(Imm64(INPUT), input); \
802 masm.move32(Imm32(SHIFT), shift); \
803 masm.rshift64(shift, input); \
804 masm.branch64(Assembler::Equal, input, Imm64(OUTPUT), &next); \
805 masm.printf("rshift64(" #SHIFT ", " #INPUT ") failed\n"); \
806 masm.breakpoint(); \
807 masm.bind(&next); \
808 } \
809 { \
810 Label next; \
811 masm.move64(Imm64(INPUT), input); \
812 masm.rshift64(Imm32(SHIFT & 0x3f), input); \
813 masm.branch64(Assembler::Equal, input, Imm64(OUTPUT), &next); \
814 masm.printf("rshift64(Imm32(" #SHIFT "&0x3f), " #INPUT ") failed\n"); \
815 masm.breakpoint(); \
816 masm.bind(&next); \
817 }
818
819 TEST(0, 0x4000000000000000, 0x4000000000000000);
820 TEST(1, 0x4000000000000000, 0x2000000000000000);
821 TEST(2, 0x4000000000000000, 0x1000000000000000);
822 TEST(32, 0x4000000000000000, 0x0000000040000000);
823 TEST(0, 0x8000000000000000, 0x8000000000000000);
824 TEST(1, 0x8000000000000000, 0x4000000000000000);
825 TEST(2, 0x8000000000000000, 0x2000000000000000);
826 TEST(32, 0x8000000000000000, 0x0000000080000000);
827 TEST(0xffffffff, 0x8000000000000000, 0x0000000000000001);
828 TEST(0xfffffffe, 0x8000000000000000, 0x0000000000000002);
829 TEST(0xfffffffd, 0x8000000000000000, 0x0000000000000004);
830 TEST(0x80000001, 0x8000000000000000, 0x4000000000000000);
831 # undef TEST
832
833 masm.freeStack(sizeof(int32_t));
834
835 return Execute(cx, masm);
836 }
837 END_TEST(testJitMacroAssembler_rshift64)
838
839 #endif
840