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:
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;