diff options
Diffstat (limited to 'js/src/jsapi-tests/testJitMacroAssembler.cpp')
-rw-r--r-- | js/src/jsapi-tests/testJitMacroAssembler.cpp | 816 |
1 files changed, 816 insertions, 0 deletions
diff --git a/js/src/jsapi-tests/testJitMacroAssembler.cpp b/js/src/jsapi-tests/testJitMacroAssembler.cpp new file mode 100644 index 0000000000..0cfa71700f --- /dev/null +++ b/js/src/jsapi-tests/testJitMacroAssembler.cpp @@ -0,0 +1,816 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "jit/IonAnalysis.h" +#include "jit/Linker.h" +#include "jit/MacroAssembler.h" +#include "jit/MIRGenerator.h" +#include "jit/MIRGraph.h" +#include "jit/ValueNumbering.h" +#include "js/Value.h" + +#include "jsapi-tests/tests.h" +#include "jsapi-tests/testsJit.h" + +#include "jit/MacroAssembler-inl.h" + +using namespace js; +using namespace js::jit; + +using mozilla::NegativeInfinity; +using mozilla::PositiveInfinity; + +#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64) + +BEGIN_TEST(testJitMacroAssembler_flexibleDivMod) { + TempAllocator tempAlloc(&cx->tempLifoAlloc()); + JitContext jcx(cx); + StackMacroAssembler masm(cx, tempAlloc); + AutoCreatedBy acb(masm, __func__); + + PrepareJit(masm); + + // Test case divides 9/2; + const uintptr_t quotient_result = 4; + const uintptr_t remainder_result = 1; + const uintptr_t dividend = 9; + const uintptr_t divisor = 2; + + AllocatableGeneralRegisterSet leftOutputHandSides(GeneralRegisterSet::All()); + + while (!leftOutputHandSides.empty()) { + Register lhsOutput = leftOutputHandSides.takeAny(); + + AllocatableGeneralRegisterSet rightHandSides(GeneralRegisterSet::All()); + while (!rightHandSides.empty()) { + Register rhs = rightHandSides.takeAny(); + + AllocatableGeneralRegisterSet remainders(GeneralRegisterSet::All()); + while (!remainders.empty()) { + Register remainderOutput = remainders.takeAny(); + if (lhsOutput == rhs || lhsOutput == remainderOutput || + rhs == remainderOutput) { + continue; + } + + AllocatableRegisterSet regs(RegisterSet::Volatile()); + LiveRegisterSet save(regs.asLiveSet()); + + Label next, fail; + masm.mov(ImmWord(dividend), lhsOutput); + masm.mov(ImmWord(divisor), rhs); + masm.flexibleDivMod32(rhs, lhsOutput, remainderOutput, false, save); + masm.branch32(Assembler::NotEqual, AbsoluteAddress("ient_result), + lhsOutput, &fail); + masm.branch32(Assembler::NotEqual, AbsoluteAddress(&remainder_result), + remainderOutput, &fail); + // Ensure RHS was not clobbered + masm.branch32(Assembler::NotEqual, AbsoluteAddress(&divisor), rhs, + &fail); + masm.jump(&next); + masm.bind(&fail); + masm.printf("Failed"); + masm.breakpoint(); + + masm.bind(&next); + } + } + } + + return ExecuteJit(cx, masm); +} +END_TEST(testJitMacroAssembler_flexibleDivMod) + +BEGIN_TEST(testJitMacroAssembler_flexibleRemainder) { + TempAllocator tempAlloc(&cx->tempLifoAlloc()); + JitContext jcx(cx); + StackMacroAssembler masm(cx, tempAlloc); + AutoCreatedBy acb(masm, __func__); + + PrepareJit(masm); + + // Test case divides 9/2; + const uintptr_t dividend = 9; + const uintptr_t divisor = 2; + const uintptr_t remainder_result = 1; + + AllocatableGeneralRegisterSet leftOutputHandSides(GeneralRegisterSet::All()); + + while (!leftOutputHandSides.empty()) { + Register lhsOutput = leftOutputHandSides.takeAny(); + + AllocatableGeneralRegisterSet rightHandSides(GeneralRegisterSet::All()); + while (!rightHandSides.empty()) { + Register rhs = rightHandSides.takeAny(); + + if (lhsOutput == rhs) { + continue; + } + + AllocatableRegisterSet regs(RegisterSet::Volatile()); + LiveRegisterSet save(regs.asLiveSet()); + + Label next, fail; + masm.mov(ImmWord(dividend), lhsOutput); + masm.mov(ImmWord(divisor), rhs); + masm.flexibleRemainder32(rhs, lhsOutput, false, save); + masm.branch32(Assembler::NotEqual, AbsoluteAddress(&remainder_result), + lhsOutput, &fail); + // Ensure RHS was not clobbered + masm.branch32(Assembler::NotEqual, AbsoluteAddress(&divisor), rhs, &fail); + masm.jump(&next); + masm.bind(&fail); + masm.printf("Failed\n"); + masm.breakpoint(); + + masm.bind(&next); + } + } + + return ExecuteJit(cx, masm); +} +END_TEST(testJitMacroAssembler_flexibleRemainder) + +BEGIN_TEST(testJitMacroAssembler_flexibleQuotient) { + TempAllocator tempAlloc(&cx->tempLifoAlloc()); + JitContext jcx(cx); + StackMacroAssembler masm(cx, tempAlloc); + AutoCreatedBy acb(masm, __func__); + + PrepareJit(masm); + + // Test case divides 9/2; + const uintptr_t dividend = 9; + const uintptr_t divisor = 2; + const uintptr_t quotient_result = 4; + + AllocatableGeneralRegisterSet leftOutputHandSides(GeneralRegisterSet::All()); + + while (!leftOutputHandSides.empty()) { + Register lhsOutput = leftOutputHandSides.takeAny(); + + AllocatableGeneralRegisterSet rightHandSides(GeneralRegisterSet::All()); + while (!rightHandSides.empty()) { + Register rhs = rightHandSides.takeAny(); + + if (lhsOutput == rhs) { + continue; + } + + AllocatableRegisterSet regs(RegisterSet::Volatile()); + LiveRegisterSet save(regs.asLiveSet()); + + Label next, fail; + masm.mov(ImmWord(dividend), lhsOutput); + masm.mov(ImmWord(divisor), rhs); + masm.flexibleQuotient32(rhs, lhsOutput, false, save); + masm.branch32(Assembler::NotEqual, AbsoluteAddress("ient_result), + lhsOutput, &fail); + // Ensure RHS was not clobbered + masm.branch32(Assembler::NotEqual, AbsoluteAddress(&divisor), rhs, &fail); + masm.jump(&next); + masm.bind(&fail); + masm.printf("Failed\n"); + masm.breakpoint(); + + masm.bind(&next); + } + } + + return ExecuteJit(cx, masm); +} +END_TEST(testJitMacroAssembler_flexibleQuotient) + +// To make sure ecx isn't being clobbered; globally scoped to ensure it has the +// right lifetime. +const uintptr_t guardEcx = 0xfeedbad; + +bool shiftTest(JSContext* cx, const char* name, + void (*operation)(StackMacroAssembler& masm, Register, Register), + const uintptr_t* lhsInput, const uintptr_t* rhsInput, + const uintptr_t* result) { + TempAllocator tempAlloc(&cx->tempLifoAlloc()); + JitContext jcx(cx); + StackMacroAssembler masm(cx, tempAlloc); + AutoCreatedBy acb(masm, __func__); + + PrepareJit(masm); + + JS::AutoSuppressGCAnalysis suppress; + AllocatableGeneralRegisterSet leftOutputHandSides(GeneralRegisterSet::All()); + + while (!leftOutputHandSides.empty()) { + Register lhsOutput = leftOutputHandSides.takeAny(); + + AllocatableGeneralRegisterSet rightHandSides(GeneralRegisterSet::All()); + while (!rightHandSides.empty()) { + Register rhs = rightHandSides.takeAny(); + + // You can only use shift as the same reg if the values are the same + if (lhsOutput == rhs && *lhsInput != *rhsInput) { + continue; + } + + Label next, outputFail, clobberRhs, clobberEcx, dump; + masm.mov(ImmWord(guardEcx), ecx); + masm.mov(ImmWord(*lhsInput), lhsOutput); + masm.mov(ImmWord(*rhsInput), rhs); + + operation(masm, rhs, lhsOutput); + + // Ensure Result is correct + masm.branch32(Assembler::NotEqual, AbsoluteAddress(result), lhsOutput, + &outputFail); + + // Ensure RHS was not clobbered, unless it's also the output register. + if (lhsOutput != rhs) { + masm.branch32(Assembler::NotEqual, AbsoluteAddress(rhsInput), rhs, + &clobberRhs); + } + + if (lhsOutput != ecx && rhs != ecx) { + // If neither lhsOutput nor rhs is ecx, make sure ecx has been + // preserved, otherwise it's expected to be covered by the RHS clobber + // check above, or intentionally clobbered as the output. + masm.branch32(Assembler::NotEqual, AbsoluteAddress(&guardEcx), ecx, + &clobberEcx); + } + + masm.jump(&next); + + masm.bind(&outputFail); + masm.printf("Incorrect output (got %d) ", lhsOutput); + masm.jump(&dump); + + masm.bind(&clobberRhs); + masm.printf("rhs clobbered %d", rhs); + masm.jump(&dump); + + masm.bind(&clobberEcx); + masm.printf("ecx clobbered"); + masm.jump(&dump); + + masm.bind(&dump); + masm.mov(ImmPtr(lhsOutput.name()), lhsOutput); + masm.printf("(lhsOutput/srcDest) %s ", lhsOutput); + masm.mov(ImmPtr(name), lhsOutput); + masm.printf("%s ", lhsOutput); + masm.mov(ImmPtr(rhs.name()), lhsOutput); + masm.printf("(shift/rhs) %s \n", lhsOutput); + // Breakpoint to force test failure. + masm.breakpoint(); + masm.bind(&next); + } + } + + return ExecuteJit(cx, masm); +} + +BEGIN_TEST(testJitMacroAssembler_flexibleRshift) { + { + // Test case 16 >> 2 == 4; + const uintptr_t lhsInput = 16; + const uintptr_t rhsInput = 2; + const uintptr_t result = 4; + + bool res = shiftTest( + cx, "flexibleRshift32", + [](StackMacroAssembler& masm, Register rhs, Register lhsOutput) { + masm.flexibleRshift32(rhs, lhsOutput); + }, + &lhsInput, &rhsInput, &result); + if (!res) { + return false; + } + } + + { + // Test case 16 >> 16 == 0 -- this helps cover the case where the same + // register can be passed for source and dest. + const uintptr_t lhsInput = 16; + const uintptr_t rhsInput = 16; + const uintptr_t result = 0; + + bool res = shiftTest( + cx, "flexibleRshift32", + [](StackMacroAssembler& masm, Register rhs, Register lhsOutput) { + masm.flexibleRshift32(rhs, lhsOutput); + }, + &lhsInput, &rhsInput, &result); + if (!res) { + return false; + } + } + + return true; +} +END_TEST(testJitMacroAssembler_flexibleRshift) + +BEGIN_TEST(testJitMacroAssembler_flexibleRshiftArithmetic) { + { + // Test case 4294967295 >> 2 == 4294967295; + const uintptr_t lhsInput = 4294967295; + const uintptr_t rhsInput = 2; + const uintptr_t result = 4294967295; + bool res = shiftTest( + cx, "flexibleRshift32Arithmetic", + [](StackMacroAssembler& masm, Register rhs, Register lhsOutput) { + masm.flexibleRshift32Arithmetic(rhs, lhsOutput); + }, + &lhsInput, &rhsInput, &result); + if (!res) { + return false; + } + } + + { + // Test case 16 >> 16 == 0 -- this helps cover the case where the same + // register can be passed for source and dest. + const uintptr_t lhsInput = 16; + const uintptr_t rhsInput = 16; + const uintptr_t result = 0; + + bool res = shiftTest( + cx, "flexibleRshift32Arithmetic", + [](StackMacroAssembler& masm, Register rhs, Register lhsOutput) { + masm.flexibleRshift32Arithmetic(rhs, lhsOutput); + }, + &lhsInput, &rhsInput, &result); + if (!res) { + return false; + } + } + + return true; +} +END_TEST(testJitMacroAssembler_flexibleRshiftArithmetic) + +BEGIN_TEST(testJitMacroAssembler_flexibleLshift) { + { + // Test case 16 << 2 == 64; + const uintptr_t lhsInput = 16; + const uintptr_t rhsInput = 2; + const uintptr_t result = 64; + + bool res = shiftTest( + cx, "flexibleLshift32", + [](StackMacroAssembler& masm, Register rhs, Register lhsOutput) { + masm.flexibleLshift32(rhs, lhsOutput); + }, + &lhsInput, &rhsInput, &result); + if (!res) { + return false; + } + } + + { + // Test case 4 << 4 == 64; duplicated input case + const uintptr_t lhsInput = 4; + const uintptr_t rhsInput = 4; + const uintptr_t result = 64; + + bool res = shiftTest( + cx, "flexibleLshift32", + [](StackMacroAssembler& masm, Register rhs, Register lhsOutput) { + masm.flexibleLshift32(rhs, lhsOutput); + }, + &lhsInput, &rhsInput, &result); + if (!res) { + return false; + } + } + + return true; +} +END_TEST(testJitMacroAssembler_flexibleLshift) + +BEGIN_TEST(testJitMacroAssembler_truncateDoubleToInt64) { + TempAllocator tempAlloc(&cx->tempLifoAlloc()); + JitContext jcx(cx); + StackMacroAssembler masm(cx, tempAlloc); + AutoCreatedBy acb(masm, __func__); + + PrepareJit(masm); + + AllocatableGeneralRegisterSet allRegs(GeneralRegisterSet::All()); + AllocatableFloatRegisterSet allFloatRegs(FloatRegisterSet::All()); + FloatRegister input = allFloatRegs.takeAny(); +# ifdef JS_NUNBOX32 + Register64 output(allRegs.takeAny(), allRegs.takeAny()); +# else + Register64 output(allRegs.takeAny()); +# endif + Register temp = allRegs.takeAny(); + + masm.reserveStack(sizeof(int32_t)); + +# define TEST(INPUT, OUTPUT) \ + { \ + Label next; \ + masm.loadConstantDouble(double(INPUT), input); \ + masm.storeDouble(input, Operand(esp, 0)); \ + masm.truncateDoubleToInt64(Address(esp, 0), Address(esp, 0), temp); \ + masm.branch64(Assembler::Equal, Address(esp, 0), Imm64(OUTPUT), &next); \ + masm.printf("truncateDoubleToInt64(" #INPUT ") failed\n"); \ + masm.breakpoint(); \ + masm.bind(&next); \ + } + + TEST(0, 0); + TEST(-0, 0); + TEST(1, 1); + TEST(9223372036854774784.0, 9223372036854774784); + TEST(-9223372036854775808.0, 0x8000000000000000); + TEST(9223372036854775808.0, 0x8000000000000000); + TEST(JS::GenericNaN(), 0x8000000000000000); + TEST(PositiveInfinity<double>(), 0x8000000000000000); + TEST(NegativeInfinity<double>(), 0x8000000000000000); +# undef TEST + + masm.freeStack(sizeof(int32_t)); + + return ExecuteJit(cx, masm); +} +END_TEST(testJitMacroAssembler_truncateDoubleToInt64) + +BEGIN_TEST(testJitMacroAssembler_truncateDoubleToUInt64) { + TempAllocator tempAlloc(&cx->tempLifoAlloc()); + JitContext jcx(cx); + StackMacroAssembler masm(cx, tempAlloc); + AutoCreatedBy acb(masm, __func__); + + PrepareJit(masm); + + AllocatableGeneralRegisterSet allRegs(GeneralRegisterSet::All()); + AllocatableFloatRegisterSet allFloatRegs(FloatRegisterSet::All()); + FloatRegister input = allFloatRegs.takeAny(); + FloatRegister floatTemp = allFloatRegs.takeAny(); +# ifdef JS_NUNBOX32 + Register64 output(allRegs.takeAny(), allRegs.takeAny()); +# else + Register64 output(allRegs.takeAny()); +# endif + Register temp = allRegs.takeAny(); + + masm.reserveStack(sizeof(int32_t)); + +# define TEST(INPUT, OUTPUT) \ + { \ + Label next; \ + masm.loadConstantDouble(double(INPUT), input); \ + masm.storeDouble(input, Operand(esp, 0)); \ + masm.truncateDoubleToUInt64(Address(esp, 0), Address(esp, 0), temp, \ + floatTemp); \ + masm.branch64(Assembler::Equal, Address(esp, 0), Imm64(OUTPUT), &next); \ + masm.printf("truncateDoubleToUInt64(" #INPUT ") failed\n"); \ + masm.breakpoint(); \ + masm.bind(&next); \ + } + + TEST(0, 0); + TEST(1, 1); + TEST(9223372036854774784.0, 9223372036854774784); + TEST((uint64_t)0x8000000000000000, 0x8000000000000000); + TEST((uint64_t)0x8000000000000001, 0x8000000000000000); + TEST((uint64_t)0x8006004000000001, 0x8006004000000000); + TEST(-0.0, 0); + TEST(-0.5, 0); + TEST(-0.99, 0); + TEST(JS::GenericNaN(), 0x8000000000000000); + TEST(PositiveInfinity<double>(), 0x8000000000000000); + TEST(NegativeInfinity<double>(), 0x8000000000000000); +# undef TEST + + masm.freeStack(sizeof(int32_t)); + + return ExecuteJit(cx, masm); +} +END_TEST(testJitMacroAssembler_truncateDoubleToUInt64) + +BEGIN_TEST(testJitMacroAssembler_branchDoubleNotInInt64Range) { + TempAllocator tempAlloc(&cx->tempLifoAlloc()); + JitContext jcx(cx); + StackMacroAssembler masm(cx, tempAlloc); + AutoCreatedBy acb(masm, __func__); + + PrepareJit(masm); + + AllocatableGeneralRegisterSet allRegs(GeneralRegisterSet::All()); + AllocatableFloatRegisterSet allFloatRegs(FloatRegisterSet::All()); + FloatRegister input = allFloatRegs.takeAny(); +# ifdef JS_NUNBOX32 + Register64 output(allRegs.takeAny(), allRegs.takeAny()); +# else + Register64 output(allRegs.takeAny()); +# endif + Register temp = allRegs.takeAny(); + + masm.reserveStack(sizeof(int32_t)); + +# define TEST(INPUT, OUTPUT) \ + { \ + Label next; \ + masm.loadConstantDouble(double(INPUT), input); \ + masm.storeDouble(input, Operand(esp, 0)); \ + if (OUTPUT) { \ + masm.branchDoubleNotInInt64Range(Address(esp, 0), temp, &next); \ + } else { \ + Label fail; \ + masm.branchDoubleNotInInt64Range(Address(esp, 0), temp, &fail); \ + masm.jump(&next); \ + masm.bind(&fail); \ + } \ + masm.printf("branchDoubleNotInInt64Range(" #INPUT ") failed\n"); \ + masm.breakpoint(); \ + masm.bind(&next); \ + } + + TEST(0, false); + TEST(-0, false); + TEST(1, false); + TEST(9223372036854774784.0, false); + TEST(-9223372036854775808.0, true); + TEST(9223372036854775808.0, true); + TEST(JS::GenericNaN(), true); + TEST(PositiveInfinity<double>(), true); + TEST(NegativeInfinity<double>(), true); +# undef TEST + + masm.freeStack(sizeof(int32_t)); + + return ExecuteJit(cx, masm); +} +END_TEST(testJitMacroAssembler_branchDoubleNotInInt64Range) + +BEGIN_TEST(testJitMacroAssembler_branchDoubleNotInUInt64Range) { + TempAllocator tempAlloc(&cx->tempLifoAlloc()); + JitContext jcx(cx); + StackMacroAssembler masm(cx, tempAlloc); + AutoCreatedBy acb(masm, __func__); + + PrepareJit(masm); + + AllocatableGeneralRegisterSet allRegs(GeneralRegisterSet::All()); + AllocatableFloatRegisterSet allFloatRegs(FloatRegisterSet::All()); + FloatRegister input = allFloatRegs.takeAny(); +# ifdef JS_NUNBOX32 + Register64 output(allRegs.takeAny(), allRegs.takeAny()); +# else + Register64 output(allRegs.takeAny()); +# endif + Register temp = allRegs.takeAny(); + + masm.reserveStack(sizeof(int32_t)); + +# define TEST(INPUT, OUTPUT) \ + { \ + Label next; \ + masm.loadConstantDouble(double(INPUT), input); \ + masm.storeDouble(input, Operand(esp, 0)); \ + if (OUTPUT) { \ + masm.branchDoubleNotInUInt64Range(Address(esp, 0), temp, &next); \ + } else { \ + Label fail; \ + masm.branchDoubleNotInUInt64Range(Address(esp, 0), temp, &fail); \ + masm.jump(&next); \ + masm.bind(&fail); \ + } \ + masm.printf("branchDoubleNotInUInt64Range(" #INPUT ") failed\n"); \ + masm.breakpoint(); \ + masm.bind(&next); \ + } + + TEST(0, false); + TEST(1, false); + TEST(9223372036854774784.0, false); + TEST((uint64_t)0x8000000000000000, false); + TEST((uint64_t)0x8000000000000001, false); + TEST((uint64_t)0x8006004000000001, false); + TEST(-0.0, true); + TEST(-0.5, true); + TEST(-0.99, true); + TEST(JS::GenericNaN(), true); + TEST(PositiveInfinity<double>(), true); + TEST(NegativeInfinity<double>(), true); +# undef TEST + + masm.freeStack(sizeof(int32_t)); + + return ExecuteJit(cx, masm); +} +END_TEST(testJitMacroAssembler_branchDoubleNotInUInt64Range) + +BEGIN_TEST(testJitMacroAssembler_lshift64) { + TempAllocator tempAlloc(&cx->tempLifoAlloc()); + JitContext jcx(cx); + StackMacroAssembler masm(cx, tempAlloc); + AutoCreatedBy acb(masm, __func__); + + PrepareJit(masm); + + AllocatableGeneralRegisterSet allRegs(GeneralRegisterSet::All()); + AllocatableFloatRegisterSet allFloatRegs(FloatRegisterSet::All()); +# if defined(JS_CODEGEN_X86) + Register shift = ecx; + allRegs.take(shift); +# elif defined(JS_CODEGEN_X64) + Register shift = rcx; + allRegs.take(shift); +# else + Register shift = allRegs.takeAny(); +# endif + +# ifdef JS_NUNBOX32 + Register64 input(allRegs.takeAny(), allRegs.takeAny()); +# else + Register64 input(allRegs.takeAny()); +# endif + + masm.reserveStack(sizeof(int32_t)); + +# define TEST(SHIFT, INPUT, OUTPUT) \ + { \ + Label next; \ + masm.move64(Imm64(INPUT), input); \ + masm.move32(Imm32(SHIFT), shift); \ + masm.lshift64(shift, input); \ + masm.branch64(Assembler::Equal, input, Imm64(OUTPUT), &next); \ + masm.printf("lshift64(" #SHIFT ", " #INPUT ") failed\n"); \ + masm.breakpoint(); \ + masm.bind(&next); \ + } \ + { \ + Label next; \ + masm.move64(Imm64(INPUT), input); \ + masm.lshift64(Imm32(SHIFT & 0x3f), input); \ + masm.branch64(Assembler::Equal, input, Imm64(OUTPUT), &next); \ + masm.printf("lshift64(Imm32(" #SHIFT "&0x3f), " #INPUT ") failed\n"); \ + masm.breakpoint(); \ + masm.bind(&next); \ + } + + TEST(0, 1, 1); + TEST(1, 1, 2); + TEST(2, 1, 4); + TEST(32, 1, 0x0000000100000000); + TEST(33, 1, 0x0000000200000000); + TEST(0, -1, 0xffffffffffffffff); + TEST(1, -1, 0xfffffffffffffffe); + TEST(2, -1, 0xfffffffffffffffc); + TEST(32, -1, 0xffffffff00000000); + TEST(0xffffffff, 1, 0x8000000000000000); + TEST(0xfffffffe, 1, 0x4000000000000000); + TEST(0xfffffffd, 1, 0x2000000000000000); + TEST(0x80000001, 1, 2); +# undef TEST + + masm.freeStack(sizeof(int32_t)); + + return ExecuteJit(cx, masm); +} +END_TEST(testJitMacroAssembler_lshift64) + +BEGIN_TEST(testJitMacroAssembler_rshift64Arithmetic) { + TempAllocator tempAlloc(&cx->tempLifoAlloc()); + JitContext jcx(cx); + StackMacroAssembler masm(cx, tempAlloc); + AutoCreatedBy acb(masm, __func__); + + PrepareJit(masm); + + AllocatableGeneralRegisterSet allRegs(GeneralRegisterSet::All()); + AllocatableFloatRegisterSet allFloatRegs(FloatRegisterSet::All()); +# if defined(JS_CODEGEN_X86) + Register shift = ecx; + allRegs.take(shift); +# elif defined(JS_CODEGEN_X64) + Register shift = rcx; + allRegs.take(shift); +# else + Register shift = allRegs.takeAny(); +# endif + +# ifdef JS_NUNBOX32 + Register64 input(allRegs.takeAny(), allRegs.takeAny()); +# else + Register64 input(allRegs.takeAny()); +# endif + + masm.reserveStack(sizeof(int32_t)); + +# define TEST(SHIFT, INPUT, OUTPUT) \ + { \ + Label next; \ + masm.move64(Imm64(INPUT), input); \ + masm.move32(Imm32(SHIFT), shift); \ + masm.rshift64Arithmetic(shift, input); \ + masm.branch64(Assembler::Equal, input, Imm64(OUTPUT), &next); \ + masm.printf("rshift64Arithmetic(" #SHIFT ", " #INPUT ") failed\n"); \ + masm.breakpoint(); \ + masm.bind(&next); \ + } \ + { \ + Label next; \ + masm.move64(Imm64(INPUT), input); \ + masm.rshift64Arithmetic(Imm32(SHIFT & 0x3f), input); \ + masm.branch64(Assembler::Equal, input, Imm64(OUTPUT), &next); \ + masm.printf("rshift64Arithmetic(Imm32(" #SHIFT "&0x3f), " #INPUT \ + ") failed\n"); \ + masm.breakpoint(); \ + masm.bind(&next); \ + } + + TEST(0, 0x4000000000000000, 0x4000000000000000); + TEST(1, 0x4000000000000000, 0x2000000000000000); + TEST(2, 0x4000000000000000, 0x1000000000000000); + TEST(32, 0x4000000000000000, 0x0000000040000000); + TEST(0, 0x8000000000000000, 0x8000000000000000); + TEST(1, 0x8000000000000000, 0xc000000000000000); + TEST(2, 0x8000000000000000, 0xe000000000000000); + TEST(32, 0x8000000000000000, 0xffffffff80000000); + TEST(0xffffffff, 0x8000000000000000, 0xffffffffffffffff); + TEST(0xfffffffe, 0x8000000000000000, 0xfffffffffffffffe); + TEST(0xfffffffd, 0x8000000000000000, 0xfffffffffffffffc); + TEST(0x80000001, 0x8000000000000000, 0xc000000000000000); +# undef TEST + + masm.freeStack(sizeof(int32_t)); + + return ExecuteJit(cx, masm); +} +END_TEST(testJitMacroAssembler_rshift64Arithmetic) + +BEGIN_TEST(testJitMacroAssembler_rshift64) { + TempAllocator tempAlloc(&cx->tempLifoAlloc()); + JitContext jcx(cx); + StackMacroAssembler masm(cx, tempAlloc); + AutoCreatedBy acb(masm, __func__); + + PrepareJit(masm); + + AllocatableGeneralRegisterSet allRegs(GeneralRegisterSet::All()); + AllocatableFloatRegisterSet allFloatRegs(FloatRegisterSet::All()); +# if defined(JS_CODEGEN_X86) + Register shift = ecx; + allRegs.take(shift); +# elif defined(JS_CODEGEN_X64) + Register shift = rcx; + allRegs.take(shift); +# else + Register shift = allRegs.takeAny(); +# endif + +# ifdef JS_NUNBOX32 + Register64 input(allRegs.takeAny(), allRegs.takeAny()); +# else + Register64 input(allRegs.takeAny()); +# endif + + masm.reserveStack(sizeof(int32_t)); + +# define TEST(SHIFT, INPUT, OUTPUT) \ + { \ + Label next; \ + masm.move64(Imm64(INPUT), input); \ + masm.move32(Imm32(SHIFT), shift); \ + masm.rshift64(shift, input); \ + masm.branch64(Assembler::Equal, input, Imm64(OUTPUT), &next); \ + masm.printf("rshift64(" #SHIFT ", " #INPUT ") failed\n"); \ + masm.breakpoint(); \ + masm.bind(&next); \ + } \ + { \ + Label next; \ + masm.move64(Imm64(INPUT), input); \ + masm.rshift64(Imm32(SHIFT & 0x3f), input); \ + masm.branch64(Assembler::Equal, input, Imm64(OUTPUT), &next); \ + masm.printf("rshift64(Imm32(" #SHIFT "&0x3f), " #INPUT ") failed\n"); \ + masm.breakpoint(); \ + masm.bind(&next); \ + } + + TEST(0, 0x4000000000000000, 0x4000000000000000); + TEST(1, 0x4000000000000000, 0x2000000000000000); + TEST(2, 0x4000000000000000, 0x1000000000000000); + TEST(32, 0x4000000000000000, 0x0000000040000000); + TEST(0, 0x8000000000000000, 0x8000000000000000); + TEST(1, 0x8000000000000000, 0x4000000000000000); + TEST(2, 0x8000000000000000, 0x2000000000000000); + TEST(32, 0x8000000000000000, 0x0000000080000000); + TEST(0xffffffff, 0x8000000000000000, 0x0000000000000001); + TEST(0xfffffffe, 0x8000000000000000, 0x0000000000000002); + TEST(0xfffffffd, 0x8000000000000000, 0x0000000000000004); + TEST(0x80000001, 0x8000000000000000, 0x4000000000000000); +# undef TEST + + masm.freeStack(sizeof(int32_t)); + + return ExecuteJit(cx, masm); +} +END_TEST(testJitMacroAssembler_rshift64) + +#endif |