tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit c9c43eeaccd398e493a05ff34bbbf8e92b4f6f94
parent 5d73a4ba5e8860da93b843cddfe08a3155e04958
Author: André Bargull <andre.bargull@gmail.com>
Date:   Fri, 24 Oct 2025 14:58:53 +0000

Bug 1996083 - Part 4: Don't require reuse-input allocations for mul instructions on {mips,loong,riscv}64. r=spidermonkey-reviewers,jandem

Adds `emitMulI64` to share codegen for `Int64` and `IntPtr`.

Lowering changes happen in part 5.

Differential Revision: https://phabricator.services.mozilla.com/D269836

Diffstat:
Mjs/src/jit/loong64/CodeGenerator-loong64.cpp | 271+++++++++++++++++++++++++++++++++++++------------------------------------------
Mjs/src/jit/loong64/CodeGenerator-loong64.h | 2++
Mjs/src/jit/mips-shared/CodeGenerator-mips-shared.cpp | 257+++++++++++++++++++++++++++++++++++++------------------------------------------
Mjs/src/jit/mips-shared/CodeGenerator-mips-shared.h | 2++
Mjs/src/jit/riscv64/CodeGenerator-riscv64.cpp | 298++++++++++++++++++++++++++++++++++---------------------------------------------
Mjs/src/jit/riscv64/CodeGenerator-riscv64.h | 2++
6 files changed, 380 insertions(+), 452 deletions(-)

diff --git a/js/src/jit/loong64/CodeGenerator-loong64.cpp b/js/src/jit/loong64/CodeGenerator-loong64.cpp @@ -750,7 +750,7 @@ void CodeGenerator::visitSubI64(LSubI64* lir) { } void CodeGenerator::visitMulI(LMulI* ins) { - const LAllocation* lhs = ins->lhs(); + Register lhs = ToRegister(ins->lhs()); const LAllocation* rhs = ins->rhs(); Register dest = ToRegister(ins->output()); MMul* mul = ins->mir(); @@ -760,107 +760,102 @@ void CodeGenerator::visitMulI(LMulI* ins) { if (rhs->isConstant()) { int32_t constant = ToInt32(rhs); - Register src = ToRegister(lhs); // Bailout on -0.0 if (mul->canBeNegativeZero() && constant <= 0) { Assembler::Condition cond = (constant == 0) ? Assembler::LessThan : Assembler::Equal; - bailoutCmp32(cond, src, Imm32(0), ins->snapshot()); + bailoutCmp32(cond, lhs, Imm32(0), ins->snapshot()); } switch (constant) { case -1: if (mul->canOverflow()) { - bailoutCmp32(Assembler::Equal, src, Imm32(INT32_MIN), + bailoutCmp32(Assembler::Equal, lhs, Imm32(INT32_MIN), ins->snapshot()); } - masm.as_sub_w(dest, zero, src); - break; + masm.as_sub_w(dest, zero, lhs); + return; case 0: masm.move32(zero, dest); - break; + return; case 1: - masm.move32(src, dest); - break; + masm.move32(lhs, dest); + return; case 2: if (mul->canOverflow()) { Label mulTwoOverflow; - masm.ma_add32TestOverflow(dest, src, src, &mulTwoOverflow); + masm.ma_add32TestOverflow(dest, lhs, lhs, &mulTwoOverflow); bailoutFrom(&mulTwoOverflow, ins->snapshot()); } else { - masm.as_add_w(dest, src, src); + masm.as_add_w(dest, lhs, lhs); } - break; - default: - uint32_t shift = FloorLog2(constant); + return; + } - if (!mul->canOverflow() && (constant > 0)) { - // If it cannot overflow, we can do lots of optimizations. - uint32_t rest = constant - (1 << shift); + if (constant > 0) { + uint32_t shift = mozilla::FloorLog2(constant); - // See if the constant has one bit set, meaning it can be - // encoded as a bitshift. - if ((1 << shift) == constant) { - masm.as_slli_w(dest, src, shift % 32); - return; - } + if (!mul->canOverflow()) { + // If it cannot overflow, we can do lots of optimizations. + uint32_t rest = constant - (1 << shift); - // If the constant cannot be encoded as (1<<C1), see if it can - // be encoded as (1<<C1) | (1<<C2), which can be computed - // using an add and a shift. - uint32_t shift_rest = FloorLog2(rest); - if (src != dest && (1u << shift_rest) == rest) { - masm.as_slli_w(dest, src, (shift - shift_rest) % 32); - masm.add32(src, dest); - if (shift_rest != 0) { - masm.as_slli_w(dest, dest, shift_rest % 32); - } - return; - } + // See if the constant has one bit set, meaning it can be + // encoded as a bitshift. + if ((1 << shift) == constant) { + masm.as_slli_w(dest, lhs, shift % 32); + return; } - if (mul->canOverflow() && (constant > 0) && (src != dest)) { - // To stay on the safe side, only optimize things that are a - // power of 2. - - if ((1 << shift) == constant) { - UseScratchRegisterScope temps(masm); - Register scratch = temps.Acquire(); - // dest = lhs * pow(2, shift) - masm.as_slli_w(dest, src, shift % 32); - // At runtime, check (lhs == dest >> shift), if this does - // not hold, some bits were lost due to overflow, and the - // computation should be resumed as a double. - masm.as_srai_w(scratch, dest, shift % 32); - bailoutCmp32(Assembler::NotEqual, src, Register(scratch), - ins->snapshot()); - return; + // If the constant cannot be encoded as (1<<C1), see if it can + // be encoded as (1<<C1) | (1<<C2), which can be computed + // using an add and a shift. + uint32_t shift_rest = mozilla::FloorLog2(rest); + if (lhs != dest && (1u << shift_rest) == rest) { + masm.as_slli_w(dest, lhs, (shift - shift_rest) % 32); + masm.add32(lhs, dest); + if (shift_rest != 0) { + masm.as_slli_w(dest, dest, shift_rest % 32); } + return; } + } else { + // To stay on the safe side, only optimize things that are a + // power of 2. + if (lhs != dest && (1 << shift) == constant) { + UseScratchRegisterScope temps(masm); + Register scratch = temps.Acquire(); + // dest = lhs * pow(2, shift) + masm.as_slli_w(dest, lhs, shift % 32); + // At runtime, check (lhs == dest >> shift), if this does + // not hold, some bits were lost due to overflow, and the + // computation should be resumed as a double. + masm.as_srai_w(scratch, dest, shift % 32); + bailoutCmp32(Assembler::NotEqual, lhs, Register(scratch), + ins->snapshot()); + return; + } + } + } - if (mul->canOverflow()) { - Label mulConstOverflow; - masm.ma_mul32TestOverflow(dest, ToRegister(lhs), Imm32(ToInt32(rhs)), - &mulConstOverflow); + if (mul->canOverflow()) { + Label mulConstOverflow; + masm.ma_mul32TestOverflow(dest, lhs, Imm32(constant), &mulConstOverflow); - bailoutFrom(&mulConstOverflow, ins->snapshot()); - } else { - masm.ma_mul(dest, src, Imm32(ToInt32(rhs))); - } - break; + bailoutFrom(&mulConstOverflow, ins->snapshot()); + } else { + masm.ma_mul(dest, lhs, Imm32(constant)); } } else { - Label multRegOverflow; - if (mul->canOverflow()) { - masm.ma_mul32TestOverflow(dest, ToRegister(lhs), ToRegister(rhs), - &multRegOverflow); + Label multRegOverflow; + masm.ma_mul32TestOverflow(dest, lhs, ToRegister(rhs), &multRegOverflow); + bailoutFrom(&multRegOverflow, ins->snapshot()); } else { - masm.as_mul_w(dest, ToRegister(lhs), ToRegister(rhs)); + masm.as_mul_w(dest, lhs, ToRegister(rhs)); } if (mul->canBeNegativeZero()) { @@ -871,7 +866,7 @@ void CodeGenerator::visitMulI(LMulI* ins) { // In that case result must be double value so bailout UseScratchRegisterScope temps(masm); Register scratch = temps.Acquire(); - masm.as_or(scratch, ToRegister(lhs), ToRegister(rhs)); + masm.as_or(scratch, lhs, ToRegister(rhs)); bailoutCmp32(Assembler::Signed, scratch, scratch, ins->snapshot()); masm.bind(&done); @@ -879,101 +874,89 @@ void CodeGenerator::visitMulI(LMulI* ins) { } } -void CodeGenerator::visitMulIntPtr(LMulIntPtr* ins) { - Register lhs = ToRegister(ins->lhs()); - const LAllocation* rhs = ins->rhs(); - Register dest = ToRegister(ins->output()); +void CodeGeneratorLOONG64::emitMulI64(Register lhs, int64_t rhs, + Register dest) { + switch (rhs) { + case -1: + masm.as_sub_d(dest, zero, lhs); + return; + case 0: + masm.movePtr(zero, dest); + return; + case 1: + if (dest != lhs) { + masm.movePtr(lhs, dest); + } + return; + case 2: + masm.as_add_d(dest, lhs, lhs); + return; + } - if (rhs->isConstant()) { - intptr_t constant = ToIntPtr(rhs); + if (rhs > 0) { + if (mozilla::IsPowerOfTwo(static_cast<uint64_t>(rhs + 1))) { + int32_t shift = mozilla::FloorLog2(rhs + 1); - switch (constant) { - case -1: - masm.as_sub_d(dest, zero, lhs); - return; - case 0: - masm.movePtr(zero, dest); - return; - case 1: - masm.movePtr(lhs, dest); - return; - case 2: - masm.as_add_d(dest, lhs, lhs); - return; + UseScratchRegisterScope temps(masm); + Register savedLhs = lhs; + if (dest == lhs) { + savedLhs = temps.Acquire(); + masm.movePtr(lhs, savedLhs); + } + masm.as_slli_d(dest, lhs, shift); + masm.as_sub_d(dest, dest, savedLhs); + return; } - // Use shift if constant is a power of 2. - if (constant > 0 && mozilla::IsPowerOfTwo(uintptr_t(constant))) { - uint32_t shift = mozilla::FloorLog2(constant); - masm.lshiftPtr(Imm32(shift), lhs, dest); + if (mozilla::IsPowerOfTwo(static_cast<uint64_t>(rhs - 1))) { + int32_t shift = mozilla::FloorLog2(rhs - 1); + if (shift < 5) { + masm.as_alsl_d(dest, lhs, lhs, shift - 1); + } else { + UseScratchRegisterScope temps(masm); + Register savedLhs = lhs; + if (dest == lhs) { + savedLhs = temps.Acquire(); + masm.movePtr(lhs, savedLhs); + } + masm.as_slli_d(dest, lhs, shift); + masm.as_add_d(dest, dest, savedLhs); + } return; } - masm.ma_mul_d(dest, lhs, ImmWord(constant)); + // Use shift if constant is power of 2. + int32_t shift = mozilla::FloorLog2(rhs); + if (int64_t(1) << shift == rhs) { + masm.as_slli_d(dest, lhs, shift); + return; + } + } + + masm.ma_mul_d(dest, lhs, ImmWord(rhs)); +} + +void CodeGenerator::visitMulIntPtr(LMulIntPtr* ins) { + Register lhs = ToRegister(ins->lhs()); + const LAllocation* rhs = ins->rhs(); + Register dest = ToRegister(ins->output()); + + if (rhs->isConstant()) { + emitMulI64(lhs, ToIntPtr(rhs), dest); } else { masm.as_mul_d(dest, lhs, ToRegister(rhs)); } } void CodeGenerator::visitMulI64(LMulI64* lir) { - LInt64Allocation lhs = lir->lhs(); + Register lhs = ToRegister64(lir->lhs()).reg; LInt64Allocation rhs = lir->rhs(); - Register64 output = ToOutRegister64(lir); - MOZ_ASSERT(ToRegister64(lhs) == output); + Register dest = ToOutRegister64(lir).reg; if (IsConstant(rhs)) { - int64_t constant = ToInt64(rhs); - switch (constant) { - case -1: - masm.neg64(ToRegister64(lhs)); - return; - case 0: - masm.xor64(ToRegister64(lhs), ToRegister64(lhs)); - return; - case 1: - // nop - return; - case 2: - masm.as_add_d(output.reg, ToRegister64(lhs).reg, ToRegister64(lhs).reg); - return; - default: - if (constant > 0) { - if (mozilla::IsPowerOfTwo(static_cast<uint64_t>(constant + 1))) { - UseScratchRegisterScope temps(masm); - Register scratch = temps.Acquire(); - masm.movePtr(ToRegister64(lhs).reg, scratch); - masm.as_slli_d(output.reg, ToRegister64(lhs).reg, - FloorLog2(constant + 1)); - masm.sub64(scratch, output); - return; - } else if (mozilla::IsPowerOfTwo( - static_cast<uint64_t>(constant - 1))) { - int32_t shift = mozilla::FloorLog2(constant - 1); - if (shift < 5) { - masm.as_alsl_d(output.reg, ToRegister64(lhs).reg, - ToRegister64(lhs).reg, shift - 1); - } else { - UseScratchRegisterScope temps(masm); - Register scratch = temps.Acquire(); - masm.movePtr(ToRegister64(lhs).reg, scratch); - masm.as_slli_d(output.reg, ToRegister64(lhs).reg, shift); - masm.add64(scratch, output); - } - return; - } - // Use shift if constant is power of 2. - int32_t shift = mozilla::FloorLog2(constant); - if (int64_t(1) << shift == constant) { - masm.lshift64(Imm32(shift), ToRegister64(lhs)); - return; - } - } - Register temp = ToTempRegisterOrInvalid(lir->temp0()); - masm.mul64(Imm64(constant), ToRegister64(lhs), temp); - } + emitMulI64(lhs, ToInt64(rhs), dest); } else { - Register temp = ToTempRegisterOrInvalid(lir->temp0()); - masm.mul64(ToRegister64(rhs), ToRegister64(lhs), temp); + masm.as_mul_d(dest, lhs, ToRegister64(rhs).reg); } } diff --git a/js/src/jit/loong64/CodeGenerator-loong64.h b/js/src/jit/loong64/CodeGenerator-loong64.h @@ -134,6 +134,8 @@ class CodeGeneratorLOONG64 : public CodeGeneratorShared { void emitBigIntPtrMod(LBigIntPtrMod* ins, Register dividend, Register divisor, Register output); + void emitMulI64(Register lhs, int64_t rhs, Register dest); + template <typename T> void emitWasmLoadI64(T* ins); template <typename T> diff --git a/js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp b/js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp @@ -250,7 +250,7 @@ void CodeGenerator::visitSubI64(LSubI64* lir) { } void CodeGenerator::visitMulI(LMulI* ins) { - const LAllocation* lhs = ins->lhs(); + Register lhs = ToRegister(ins->lhs()); const LAllocation* rhs = ins->rhs(); Register dest = ToRegister(ins->output()); MMul* mul = ins->mir(); @@ -260,106 +260,100 @@ void CodeGenerator::visitMulI(LMulI* ins) { if (rhs->isConstant()) { int32_t constant = ToInt32(rhs); - Register src = ToRegister(lhs); // Bailout on -0.0 if (mul->canBeNegativeZero() && constant <= 0) { Assembler::Condition cond = (constant == 0) ? Assembler::LessThan : Assembler::Equal; - bailoutCmp32(cond, src, Imm32(0), ins->snapshot()); + bailoutCmp32(cond, lhs, Imm32(0), ins->snapshot()); } switch (constant) { case -1: if (mul->canOverflow()) { - bailoutCmp32(Assembler::Equal, src, Imm32(INT32_MIN), + bailoutCmp32(Assembler::Equal, lhs, Imm32(INT32_MIN), ins->snapshot()); } - masm.ma_negu(dest, src); - break; + masm.ma_negu(dest, lhs); + return; case 0: masm.move32(Imm32(0), dest); - break; + return; case 1: - masm.move32(src, dest); - break; + masm.move32(lhs, dest); + return; case 2: if (mul->canOverflow()) { Label mulTwoOverflow; - masm.ma_add32TestOverflow(dest, src, src, &mulTwoOverflow); + masm.ma_add32TestOverflow(dest, lhs, lhs, &mulTwoOverflow); bailoutFrom(&mulTwoOverflow, ins->snapshot()); } else { - masm.as_addu(dest, src, src); + masm.as_addu(dest, lhs, lhs); } - break; - default: - uint32_t shift = FloorLog2(constant); - - if (!mul->canOverflow() && (constant > 0)) { - // If it cannot overflow, we can do lots of optimizations. - uint32_t rest = constant - (1 << shift); + return; + } - // See if the constant has one bit set, meaning it can be - // encoded as a bitshift. - if ((1 << shift) == constant) { - masm.ma_sll(dest, src, Imm32(shift)); - return; - } + if (constant > 0) { + uint32_t shift = mozilla::FloorLog2(constant); + if (!mul->canOverflow()) { + // If it cannot overflow, we can do lots of optimizations. + uint32_t rest = constant - (1 << shift); - // If the constant cannot be encoded as (1<<C1), see if it can - // be encoded as (1<<C1) | (1<<C2), which can be computed - // using an add and a shift. - uint32_t shift_rest = FloorLog2(rest); - if (src != dest && (1u << shift_rest) == rest) { - masm.ma_sll(dest, src, Imm32(shift - shift_rest)); - masm.add32(src, dest); - if (shift_rest != 0) { - masm.ma_sll(dest, dest, Imm32(shift_rest)); - } - return; - } + // See if the constant has one bit set, meaning it can be + // encoded as a bitshift. + if ((1 << shift) == constant) { + masm.ma_sll(dest, lhs, Imm32(shift)); + return; } - if (mul->canOverflow() && (constant > 0) && (src != dest)) { - // To stay on the safe side, only optimize things that are a - // power of 2. - - if ((1 << shift) == constant) { - UseScratchRegisterScope temps(masm); - Register scratch = temps.Acquire(); - // dest = lhs * pow(2, shift) - masm.ma_sll(dest, src, Imm32(shift)); - // At runtime, check (lhs == dest >> shift), if this does - // not hold, some bits were lost due to overflow, and the - // computation should be resumed as a double. - masm.ma_sra(scratch, dest, Imm32(shift)); - bailoutCmp32(Assembler::NotEqual, src, scratch, ins->snapshot()); - return; + // If the constant cannot be encoded as (1<<C1), see if it can + // be encoded as (1<<C1) | (1<<C2), which can be computed + // using an add and a shift. + uint32_t shift_rest = mozilla::FloorLog2(rest); + if (lhs != dest && (1u << shift_rest) == rest) { + masm.ma_sll(dest, lhs, Imm32(shift - shift_rest)); + masm.add32(lhs, dest); + if (shift_rest != 0) { + masm.ma_sll(dest, dest, Imm32(shift_rest)); } + return; } + } else { + // To stay on the safe side, only optimize things that are a + // power of 2. + if (lhs != dest && (1 << shift) == constant) { + UseScratchRegisterScope temps(masm); + Register scratch = temps.Acquire(); + // dest = lhs * pow(2, shift) + masm.ma_sll(dest, lhs, Imm32(shift)); + // At runtime, check (lhs == dest >> shift), if this does + // not hold, some bits were lost due to overflow, and the + // computation should be resumed as a double. + masm.ma_sra(scratch, dest, Imm32(shift)); + bailoutCmp32(Assembler::NotEqual, lhs, scratch, ins->snapshot()); + return; + } + } + } - if (mul->canOverflow()) { - Label mulConstOverflow; - masm.ma_mul32TestOverflow(dest, ToRegister(lhs), Imm32(ToInt32(rhs)), - &mulConstOverflow); + if (mul->canOverflow()) { + Label mulConstOverflow; + masm.ma_mul32TestOverflow(dest, lhs, Imm32(constant), &mulConstOverflow); - bailoutFrom(&mulConstOverflow, ins->snapshot()); - } else { - masm.ma_mul(dest, src, Imm32(ToInt32(rhs))); - } - break; + bailoutFrom(&mulConstOverflow, ins->snapshot()); + } else { + masm.ma_mul(dest, lhs, Imm32(constant)); } } else { - Label multRegOverflow; - if (mul->canOverflow()) { - masm.ma_mul32TestOverflow(dest, ToRegister(lhs), ToRegister(rhs), - &multRegOverflow); + Label multRegOverflow; + masm.ma_mul32TestOverflow(dest, lhs, ToRegister(rhs), &multRegOverflow); + bailoutFrom(&multRegOverflow, ins->snapshot()); } else { - masm.as_mul(dest, ToRegister(lhs), ToRegister(rhs)); + masm.as_mul(dest, lhs, ToRegister(rhs)); } if (mul->canBeNegativeZero()) { @@ -370,7 +364,7 @@ void CodeGenerator::visitMulI(LMulI* ins) { // In that case result must be double value so bailout UseScratchRegisterScope temps(masm); Register scratch = temps.Acquire(); - masm.as_or(scratch, ToRegister(lhs), ToRegister(rhs)); + masm.as_or(scratch, lhs, ToRegister(rhs)); bailoutCmp32(Assembler::Signed, scratch, scratch, ins->snapshot()); masm.bind(&done); @@ -378,95 +372,84 @@ void CodeGenerator::visitMulI(LMulI* ins) { } } -void CodeGenerator::visitMulIntPtr(LMulIntPtr* ins) { - Register lhs = ToRegister(ins->lhs()); - const LAllocation* rhs = ins->rhs(); - Register dest = ToRegister(ins->output()); +void CodeGeneratorMIPSShared::emitMulI64(Register lhs, int64_t rhs, + Register dest) { + switch (rhs) { + case -1: + masm.as_dsubu(dest, zero, lhs); + return; + case 0: + masm.movePtr(zero, dest); + return; + case 1: + masm.movePtr(lhs, dest); + return; + case 2: + masm.as_daddu(dest, lhs, lhs); + return; + } - if (rhs->isConstant()) { - intptr_t constant = ToIntPtr(rhs); + if (rhs > 0) { + if (mozilla::IsPowerOfTwo(static_cast<uint64_t>(rhs + 1))) { + int32_t shift = mozilla::FloorLog2(rhs + 1); - switch (constant) { - case -1: - masm.as_dsubu(dest, zero, lhs); - return; - case 0: - masm.movePtr(zero, dest); - return; - case 1: - masm.movePtr(lhs, dest); - return; - case 2: - masm.as_daddu(dest, lhs, lhs); - return; + UseScratchRegisterScope temps(masm); + Register savedLhs = lhs; + if (dest == lhs) { + savedLhs = temps.Acquire(); + masm.movePtr(lhs, savedLhs); + } + masm.lshiftPtr(Imm32(shift), lhs, dest); + masm.subPtr(savedLhs, dest); + return; } - // Use shift if constant is a power of 2. - if (constant > 0 && mozilla::IsPowerOfTwo(uintptr_t(constant))) { - uint32_t shift = mozilla::FloorLog2(constant); + if (mozilla::IsPowerOfTwo(static_cast<uint64_t>(rhs - 1))) { + int32_t shift = mozilla::FloorLog2(rhs - 1u); + + UseScratchRegisterScope temps(masm); + Register savedLhs = lhs; + if (dest == lhs) { + savedLhs = temps.Acquire(); + masm.movePtr(lhs, savedLhs); + } masm.lshiftPtr(Imm32(shift), lhs, dest); + masm.addPtr(savedLhs, dest); return; } - masm.ma_dmulu(dest, lhs, ImmWord(constant)); + // Use shift if constant is power of 2. + int32_t shift = mozilla::FloorLog2(rhs); + if (int64_t(1) << shift == rhs) { + masm.lshiftPtr(Imm32(shift), lhs, dest); + return; + } + } + + masm.ma_dmulu(dest, lhs, ImmWord(rhs)); +} + +void CodeGenerator::visitMulIntPtr(LMulIntPtr* ins) { + Register lhs = ToRegister(ins->lhs()); + const LAllocation* rhs = ins->rhs(); + Register dest = ToRegister(ins->output()); + + if (rhs->isConstant()) { + emitMulI64(lhs, ToIntPtr(rhs), dest); } else { masm.ma_dmulu(dest, lhs, ToRegister(rhs)); } } void CodeGenerator::visitMulI64(LMulI64* lir) { - LInt64Allocation lhs = lir->lhs(); + Register lhs = ToRegister64(lir->lhs()).reg; LInt64Allocation rhs = lir->rhs(); - Register64 output = ToOutRegister64(lir); - MOZ_ASSERT(ToRegister64(lhs) == output); + Register dest = ToOutRegister64(lir).reg; if (IsConstant(rhs)) { - int64_t constant = ToInt64(rhs); - switch (constant) { - case -1: - masm.neg64(ToRegister64(lhs)); - return; - case 0: - masm.xor64(ToRegister64(lhs), ToRegister64(lhs)); - return; - case 1: - // nop - return; - case 2: - masm.add64(ToRegister64(lhs), ToRegister64(lhs)); - return; - default: - if (constant > 0) { - UseScratchRegisterScope temps(masm); - if (mozilla::IsPowerOfTwo(static_cast<uint64_t>(constant + 1))) { - Register scratch = temps.Acquire(); - Register64 scratch64(scratch); - masm.move64(ToRegister64(lhs), scratch64); - masm.lshift64(Imm32(FloorLog2(constant + 1)), output); - masm.sub64(scratch64, output); - return; - } else if (mozilla::IsPowerOfTwo( - static_cast<uint64_t>(constant - 1))) { - Register scratch = temps.Acquire(); - Register64 scratch64(scratch); - masm.move64(ToRegister64(lhs), scratch64); - masm.lshift64(Imm32(FloorLog2(constant - 1u)), output); - masm.add64(scratch64, output); - return; - } - // Use shift if constant is power of 2. - int32_t shift = mozilla::FloorLog2(constant); - if (int64_t(1) << shift == constant) { - masm.lshift64(Imm32(shift), ToRegister64(lhs)); - return; - } - } - Register temp = ToTempRegisterOrInvalid(lir->temp0()); - masm.mul64(Imm64(constant), ToRegister64(lhs), temp); - } + emitMulI64(lhs, ToInt64(rhs), dest); } else { - Register temp = ToTempRegisterOrInvalid(lir->temp0()); - masm.mul64(ToRegister64(rhs), ToRegister64(lhs), temp); + masm.ma_dmulu(dest, lhs, ToRegister64(rhs).reg); } } diff --git a/js/src/jit/mips-shared/CodeGenerator-mips-shared.h b/js/src/jit/mips-shared/CodeGenerator-mips-shared.h @@ -121,6 +121,8 @@ class CodeGeneratorMIPSShared : public CodeGeneratorShared { Register flagTemp, Register valueTemp, Register offsetTemp, Register maskTemp); + void emitMulI64(Register lhs, int64_t rhs, Register dest); + public: // Out of line visitors. void visitOutOfLineTableSwitch(OutOfLineTableSwitch* ool); diff --git a/js/src/jit/riscv64/CodeGenerator-riscv64.cpp b/js/src/jit/riscv64/CodeGenerator-riscv64.cpp @@ -779,7 +779,7 @@ void CodeGenerator::visitSubI64(LSubI64* lir) { } void CodeGenerator::visitMulI(LMulI* ins) { - const LAllocation* lhs = ins->lhs(); + Register lhs = ToRegister(ins->lhs()); const LAllocation* rhs = ins->rhs(); Register dest = ToRegister(ins->output()); MMul* mul = ins->mir(); @@ -789,107 +789,102 @@ void CodeGenerator::visitMulI(LMulI* ins) { if (rhs->isConstant()) { int32_t constant = ToInt32(rhs); - Register src = ToRegister(lhs); // Bailout on -0.0 if (mul->canBeNegativeZero() && constant <= 0) { Assembler::Condition cond = (constant == 0) ? Assembler::LessThan : Assembler::Equal; - bailoutCmp32(cond, src, Imm32(0), ins->snapshot()); + bailoutCmp32(cond, lhs, Imm32(0), ins->snapshot()); } switch (constant) { case -1: if (mul->canOverflow()) { - bailoutCmp32(Assembler::Equal, src, Imm32(INT32_MIN), + bailoutCmp32(Assembler::Equal, lhs, Imm32(INT32_MIN), ins->snapshot()); } - masm.ma_sub32(dest, zero, src); - break; + masm.negw(dest, lhs); + return; case 0: masm.move32(zero, dest); - break; + return; case 1: - masm.move32(src, dest); - break; + masm.move32(lhs, dest); + return; case 2: if (mul->canOverflow()) { Label mulTwoOverflow; - masm.ma_add32TestOverflow(dest, src, src, &mulTwoOverflow); + masm.ma_add32TestOverflow(dest, lhs, lhs, &mulTwoOverflow); bailoutFrom(&mulTwoOverflow, ins->snapshot()); } else { - masm.addw(dest, src, src); + masm.addw(dest, lhs, lhs); } - break; - default: - uint32_t shift = FloorLog2(constant); + return; + } - if (!mul->canOverflow() && (constant > 0)) { - // If it cannot overflow, we can do lots of optimizations. - uint32_t rest = constant - (1 << shift); + if (constant > 0) { + uint32_t shift = mozilla::FloorLog2(constant); - // See if the constant has one bit set, meaning it can be - // encoded as a bitshift. - if ((1 << shift) == constant) { - masm.slliw(dest, src, shift % 32); - return; - } + if (!mul->canOverflow()) { + // If it cannot overflow, we can do lots of optimizations. + uint32_t rest = constant - (1 << shift); - // If the constant cannot be encoded as (1<<C1), see if it can - // be encoded as (1<<C1) | (1<<C2), which can be computed - // using an add and a shift. - uint32_t shift_rest = FloorLog2(rest); - if (src != dest && (1u << shift_rest) == rest) { - masm.slliw(dest, src, (shift - shift_rest) % 32); - masm.add32(src, dest); - if (shift_rest != 0) { - masm.slliw(dest, dest, shift_rest % 32); - } - return; - } + // See if the constant has one bit set, meaning it can be + // encoded as a bitshift. + if ((1 << shift) == constant) { + masm.slliw(dest, lhs, shift % 32); + return; } - if (mul->canOverflow() && (constant > 0) && (src != dest)) { - // To stay on the safe side, only optimize things that are a - // power of 2. - - if ((1 << shift) == constant) { - UseScratchRegisterScope temps(&masm); - Register scratch = temps.Acquire(); - // dest = lhs * pow(2, shift) - masm.slliw(dest, src, shift % 32); - // At runtime, check (lhs == dest >> shift), if this does - // not hold, some bits were lost due to overflow, and the - // computation should be resumed as a double. - masm.sraiw(scratch, dest, shift % 32); - bailoutCmp32(Assembler::NotEqual, src, Register(scratch), - ins->snapshot()); - return; + // If the constant cannot be encoded as (1<<C1), see if it can + // be encoded as (1<<C1) | (1<<C2), which can be computed + // using an add and a shift. + uint32_t shift_rest = mozilla::FloorLog2(rest); + if (lhs != dest && (1u << shift_rest) == rest) { + masm.slliw(dest, lhs, (shift - shift_rest) % 32); + masm.add32(lhs, dest); + if (shift_rest != 0) { + masm.slliw(dest, dest, shift_rest % 32); } + return; + } + } else { + // To stay on the safe side, only optimize things that are a + // power of 2. + if (lhs != dest && (1 << shift) == constant) { + UseScratchRegisterScope temps(&masm); + Register scratch = temps.Acquire(); + // dest = lhs * pow(2, shift) + masm.slliw(dest, lhs, shift % 32); + // At runtime, check (lhs == dest >> shift), if this does + // not hold, some bits were lost due to overflow, and the + // computation should be resumed as a double. + masm.sraiw(scratch, dest, shift % 32); + bailoutCmp32(Assembler::NotEqual, lhs, Register(scratch), + ins->snapshot()); + return; } + } + } - if (mul->canOverflow()) { - Label mulConstOverflow; - masm.ma_mul32TestOverflow(dest, ToRegister(lhs), Imm32(ToInt32(rhs)), - &mulConstOverflow); + if (mul->canOverflow()) { + Label mulConstOverflow; + masm.ma_mul32TestOverflow(dest, lhs, Imm32(constant), &mulConstOverflow); - bailoutFrom(&mulConstOverflow, ins->snapshot()); - } else { - masm.ma_mul32(dest, src, Imm32(ToInt32(rhs))); - } - break; + bailoutFrom(&mulConstOverflow, ins->snapshot()); + } else { + masm.ma_mul32(dest, lhs, Imm32(constant)); } } else { - Label multRegOverflow; - if (mul->canOverflow()) { - masm.ma_mul32TestOverflow(dest, ToRegister(lhs), ToRegister(rhs), - &multRegOverflow); + Label multRegOverflow; + masm.ma_mul32TestOverflow(dest, lhs, ToRegister(rhs), &multRegOverflow); + bailoutFrom(&multRegOverflow, ins->snapshot()); } else { - masm.mulw(dest, ToRegister(lhs), ToRegister(rhs)); + masm.mulw(dest, lhs, ToRegister(rhs)); } if (mul->canBeNegativeZero()) { @@ -900,7 +895,7 @@ void CodeGenerator::visitMulI(LMulI* ins) { // In that case result must be double value so bailout UseScratchRegisterScope temps(&masm); Register scratch = temps.Acquire(); - masm.or_(scratch, ToRegister(lhs), ToRegister(rhs)); + masm.or_(scratch, lhs, ToRegister(rhs)); bailoutCmp32(Assembler::Signed, scratch, scratch, ins->snapshot()); masm.bind(&done); @@ -908,128 +903,89 @@ void CodeGenerator::visitMulI(LMulI* ins) { } } -void CodeGenerator::visitMulIntPtr(LMulIntPtr* ins) { - Register lhs = ToRegister(ins->lhs()); - const LAllocation* rhs = ins->rhs(); - Register dest = ToRegister(ins->output()); +void CodeGeneratorRiscv64::emitMulI64(Register lhs, int64_t rhs, + Register dest) { + switch (rhs) { + case -1: + masm.neg(dest, lhs); + return; + case 0: + masm.movePtr(zero, dest); + return; + case 1: + if (dest != lhs) { + masm.movePtr(lhs, dest); + } + return; + case 2: + masm.add(dest, lhs, lhs); + return; + } - if (rhs->isConstant()) { - intptr_t constant = ToIntPtr(rhs); + if (rhs > 0) { + if (mozilla::IsPowerOfTwo(static_cast<uint64_t>(rhs + 1))) { + int32_t shift = mozilla::FloorLog2(rhs + 1); - switch (constant) { - case -1: - masm.neg(dest, lhs); - return; - case 0: - masm.movePtr(zero, dest); - return; - case 1: - if (dest != lhs) { - masm.movePtr(lhs, dest); - } - return; - case 2: - masm.add(dest, lhs, lhs); - return; + UseScratchRegisterScope temps(&masm); + Register savedLhs = lhs; + if (dest == lhs) { + savedLhs = temps.Acquire(); + masm.mv(savedLhs, lhs); + } + masm.slli(dest, lhs, shift); + masm.sub(dest, dest, savedLhs); + return; } - if (constant > 0) { - if (mozilla::IsPowerOfTwo(static_cast<uint64_t>(constant + 1))) { - if (dest != lhs) { - masm.slli(dest, lhs, FloorLog2(constant + 1)); - masm.sub(dest, dest, lhs); - } else { - UseScratchRegisterScope temps(&masm); - Register scratch = temps.Acquire(); - masm.mv(scratch, lhs); - masm.slli(dest, lhs, FloorLog2(constant + 1)); - masm.sub(dest, dest, scratch); - } - return; - } - if (mozilla::IsPowerOfTwo(static_cast<uint64_t>(constant - 1))) { - if (dest != lhs) { - masm.slli(dest, lhs, FloorLog2(constant - 1)); - masm.add(dest, dest, lhs); - } else { - UseScratchRegisterScope temps(&masm); - Register scratch = temps.Acquire(); - masm.mv(scratch, lhs); - masm.slli(dest, lhs, FloorLog2(constant - 1)); - masm.add(dest, dest, scratch); - } - return; - } - // Use shift if constant is power of 2. - uint8_t shamt = mozilla::FloorLog2(constant); - if (int64_t(1) << shamt == constant) { - masm.slli(dest, lhs, shamt); - return; + if (mozilla::IsPowerOfTwo(static_cast<uint64_t>(rhs - 1))) { + int32_t shift = mozilla::FloorLog2(rhs - 1); + + UseScratchRegisterScope temps(&masm); + Register savedLhs = lhs; + if (dest == lhs) { + savedLhs = temps.Acquire(); + masm.mv(savedLhs, lhs); } + masm.slli(dest, lhs, shift); + masm.add(dest, dest, savedLhs); + return; + } + + // Use shift if constant is power of 2. + uint8_t shift = mozilla::FloorLog2(rhs); + if (int64_t(1) << shift == rhs) { + masm.slli(dest, lhs, shift); + return; } + } + + UseScratchRegisterScope temps(&masm); + Register scratch = temps.Acquire(); + masm.ma_li(scratch, Imm64(rhs)); + masm.mul(dest, lhs, scratch); +} + +void CodeGenerator::visitMulIntPtr(LMulIntPtr* ins) { + Register lhs = ToRegister(ins->lhs()); + const LAllocation* rhs = ins->rhs(); + Register dest = ToRegister(ins->output()); - UseScratchRegisterScope temps(&masm); - Register scratch = temps.Acquire(); - masm.ma_li(scratch, Imm64(constant)); - masm.mul(dest, lhs, scratch); + if (rhs->isConstant()) { + emitMulI64(lhs, ToIntPtr(rhs), dest); } else { masm.mul(dest, lhs, ToRegister(rhs)); } } void CodeGenerator::visitMulI64(LMulI64* lir) { - LInt64Allocation lhs = lir->lhs(); + Register lhs = ToRegister64(lir->lhs()).reg; LInt64Allocation rhs = lir->rhs(); - Register64 output = ToOutRegister64(lir); + Register dest = ToOutRegister64(lir).reg; if (IsConstant(rhs)) { - int64_t constant = ToInt64(rhs); - switch (constant) { - case -1: - masm.neg64(ToRegister64(lhs)); - return; - case 0: - masm.xor64(ToRegister64(lhs), ToRegister64(lhs)); - return; - case 1: - // nop - return; - case 2: - masm.add(output.reg, ToRegister64(lhs).reg, ToRegister64(lhs).reg); - return; - default: - if (constant > 0) { - if (mozilla::IsPowerOfTwo(static_cast<uint64_t>(constant + 1))) { - UseScratchRegisterScope temps(&masm); - Register scratch = temps.Acquire(); - masm.movePtr(ToRegister64(lhs).reg, scratch); - masm.slli(output.reg, ToRegister64(lhs).reg, - FloorLog2(constant + 1)); - masm.sub64(scratch, output); - return; - } else if (mozilla::IsPowerOfTwo( - static_cast<uint64_t>(constant - 1))) { - int32_t shift = mozilla::FloorLog2(constant - 1); - UseScratchRegisterScope temps(&masm); - Register scratch = temps.Acquire(); - masm.movePtr(ToRegister64(lhs).reg, scratch); - masm.slli(output.reg, ToRegister64(lhs).reg, shift); - masm.add64(scratch, output); - return; - } - // Use shift if constant is power of 2. - int32_t shift = mozilla::FloorLog2(constant); - if (int64_t(1) << shift == constant) { - masm.lshift64(Imm32(shift), ToRegister64(lhs)); - return; - } - } - Register temp = ToTempRegisterOrInvalid(lir->temp0()); - masm.mul64(Imm64(constant), ToRegister64(lhs), temp); - } + emitMulI64(lhs, ToInt64(rhs), dest); } else { - Register temp = ToTempRegisterOrInvalid(lir->temp0()); - masm.mul64(ToRegister64(rhs), ToRegister64(lhs), temp); + masm.mul(dest, lhs, ToRegister64(rhs).reg); } } diff --git a/js/src/jit/riscv64/CodeGenerator-riscv64.h b/js/src/jit/riscv64/CodeGenerator-riscv64.h @@ -138,6 +138,8 @@ class CodeGeneratorRiscv64 : public CodeGeneratorShared { Register output); void emitBigIntPtrMod(LBigIntPtrMod* ins, Register dividend, Register divisor, Register output); + + void emitMulI64(Register lhs, int64_t rhs, Register dest); }; typedef CodeGeneratorRiscv64 CodeGeneratorSpecific;