commit 92f6d9ca04e5c9e48c3c9b1eed3b2bdb2615be72
parent db9d4542de5bf31bba1efeb385065f8a525110fa
Author: André Bargull <andre.bargull@gmail.com>
Date: Mon, 10 Nov 2025 15:13:40 +0000
Bug 1998161 - Part 1: Port arm64 changes to x86/x64. r=spidermonkey-reviewers,iain
Ports the changes from bug 1997975 to x86/x64.
Changes:
- Splits the `DivOrMod` instructions into separate instructions.
- Change `L{Div,Mod}ConstantI` to support zero for consistency with their
unsigned counterparts.
- Reduce code duplication by adding `TrapIfDivideByZero` and
`emitOutOfLineZeroForDivideByZero`.
- Prefer `bailoutTest32` and `bailoutCmp32` over `bailoutIf`.
- Consistently handle `trapOnError`, then truncated, and finally non-truncated.
Differential Revision: https://phabricator.services.mozilla.com/D271218
Diffstat:
10 files changed, 482 insertions(+), 468 deletions(-)
diff --git a/js/src/jit/LIR.h b/js/src/jit/LIR.h
@@ -2169,13 +2169,10 @@ AnyRegister LAllocation::toAnyRegister() const {
} // namespace js
#include "jit/shared/LIR-shared.h"
-#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
-# if defined(JS_CODEGEN_X86)
-# include "jit/x86/LIR-x86.h"
-# elif defined(JS_CODEGEN_X64)
-# include "jit/x64/LIR-x64.h"
-# endif
-# include "jit/x86-shared/LIR-x86-shared.h"
+#if defined(JS_CODEGEN_X86)
+# include "jit/x86/LIR-x86.h"
+#elif defined(JS_CODEGEN_X64)
+# include "jit/x64/LIR-x64.h"
#elif defined(JS_CODEGEN_ARM)
# include "jit/arm/LIR-arm.h"
#elif defined(JS_CODEGEN_ARM64)
diff --git a/js/src/jit/LIROps.yaml b/js/src/jit/LIROps.yaml
@@ -4160,6 +4160,60 @@
defer_init: true
#endif
+#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
+- name: DivConstantI
+ result_type: WordSized
+ operands:
+ numerator: WordSized
+ arguments:
+ denominator: int32_t
+ num_temps: 1
+ mir_op: Div
+
+- name: ModConstantI
+ result_type: WordSized
+ operands:
+ numerator: WordSized
+ arguments:
+ denominator: int32_t
+ num_temps: 1
+ mir_op: Mod
+
+- name: UDivConstant
+ result_type: WordSized
+ operands:
+ numerator: WordSized
+ arguments:
+ denominator: uint32_t
+ num_temps: 1
+ mir_op: Div
+
+- name: UModConstant
+ result_type: WordSized
+ operands:
+ numerator: WordSized
+ arguments:
+ denominator: uint32_t
+ num_temps: 1
+ mir_op: Mod
+
+- name: UDiv
+ result_type: WordSized
+ operands:
+ lhs: WordSized
+ rhs: WordSized
+ num_temps: 1
+ mir_op: Div
+
+- name: UMod
+ result_type: WordSized
+ operands:
+ lhs: WordSized
+ rhs: WordSized
+ num_temps: 1
+ mir_op: Mod
+#endif
+
#ifdef JS_CODEGEN_X86
- name: BoxFloatingPoint
result_type: BoxedValue
@@ -4176,15 +4230,6 @@
- name: UDivOrModI64
gen_boilerplate: false
-- name: DivOrModConstantI
- gen_boilerplate: false
-
-- name: UDivOrMod
- gen_boilerplate: false
-
-- name: UDivOrModConstant
- gen_boilerplate: false
-
- name: WasmTruncateToInt64
result_type: Int64
operands:
@@ -4245,20 +4290,37 @@
#endif
#ifdef JS_CODEGEN_X64
-- name: DivOrModI64
- gen_boilerplate: false
-
-- name: UDivOrModI64
- gen_boilerplate: false
+- name: DivI64
+ result_type: Int64
+ operands:
+ lhs: WordSized
+ rhs: WordSized
+ num_temps: 1
+ mir_op: Div
-- name: DivOrModConstantI
- gen_boilerplate: false
+- name: ModI64
+ result_type: Int64
+ operands:
+ lhs: WordSized
+ rhs: WordSized
+ num_temps: 1
+ mir_op: Mod
-- name: UDivOrMod
- gen_boilerplate: false
+- name: UDivI64
+ result_type: Int64
+ operands:
+ lhs: WordSized
+ rhs: WordSized
+ num_temps: 1
+ mir_op: Div
-- name: UDivOrModConstant
- gen_boilerplate: false
+- name: UModI64
+ result_type: Int64
+ operands:
+ lhs: WordSized
+ rhs: WordSized
+ num_temps: 1
+ mir_op: Mod
- name: WasmTruncateToInt64
result_type: Int64
diff --git a/js/src/jit/x64/CodeGenerator-x64.cpp b/js/src/jit/x64/CodeGenerator-x64.cpp
@@ -20,8 +20,6 @@
using namespace js;
using namespace js::jit;
-using mozilla::DebugOnly;
-
CodeGeneratorX64::CodeGeneratorX64(MIRGenerator* gen, LIRGraph* graph,
MacroAssembler* masm,
const wasm::CodeMetadata* wasmCodeMeta)
@@ -197,45 +195,86 @@ void CodeGenerator::visitMulI64(LMulI64* lir) {
}
}
-void CodeGenerator::visitDivOrModI64(LDivOrModI64* lir) {
+template <class LIR>
+static void TrapIfDivideByZero(MacroAssembler& masm, LIR* lir, Register rhs) {
+ auto* mir = lir->mir();
+ MOZ_ASSERT(mir->trapOnError());
+
+ if (mir->canBeDivideByZero()) {
+ Label nonZero;
+ masm.branchTestPtr(Assembler::NonZero, rhs, rhs, &nonZero);
+ masm.wasmTrap(wasm::Trap::IntegerDivideByZero, mir->trapSiteDesc());
+ masm.bind(&nonZero);
+ }
+}
+
+void CodeGenerator::visitDivI64(LDivI64* lir) {
Register lhs = ToRegister(lir->lhs());
Register rhs = ToRegister(lir->rhs());
- Register output = ToRegister(lir->output());
MOZ_ASSERT_IF(lhs != rhs, rhs != rax);
MOZ_ASSERT(rhs != rdx);
- MOZ_ASSERT_IF(output == rax, ToRegister(lir->remainder()) == rdx);
- MOZ_ASSERT_IF(output == rdx, ToRegister(lir->remainder()) == rax);
+ MOZ_ASSERT(ToRegister(lir->output()) == rax);
+ MOZ_ASSERT(ToRegister(lir->temp0()) == rdx);
- Label done;
+ MDiv* mir = lir->mir();
+
+ // Handle divide by zero.
+ TrapIfDivideByZero(masm, lir, rhs);
+
+ // Handle an integer overflow exception from INT64_MIN / -1.
+ if (mir->canBeNegativeOverflow()) {
+ Label notOverflow;
+ masm.branchPtr(Assembler::NotEqual, lhs, ImmWord(INT64_MIN), ¬Overflow);
+ masm.branchPtr(Assembler::NotEqual, rhs, ImmWord(-1), ¬Overflow);
+ masm.wasmTrap(wasm::Trap::IntegerOverflow, mir->trapSiteDesc());
+ masm.bind(¬Overflow);
+ }
// Put the lhs in rax.
if (lhs != rax) {
masm.mov(lhs, rax);
}
+ // Sign extend the lhs into rdx to make rdx:rax.
+ masm.cqo();
+ masm.idivq(rhs);
+}
+
+void CodeGenerator::visitModI64(LModI64* lir) {
+ Register lhs = ToRegister(lir->lhs());
+ Register rhs = ToRegister(lir->rhs());
+ Register output = ToRegister(lir->output());
+
+ MOZ_ASSERT_IF(lhs != rhs, rhs != rax);
+ MOZ_ASSERT(rhs != rdx);
+ MOZ_ASSERT(ToRegister(lir->output()) == rdx);
+ MOZ_ASSERT(ToRegister(lir->temp0()) == rax);
+
+ MMod* mir = lir->mir();
+
+ Label done;
+
// Handle divide by zero.
- if (lir->canBeDivideByZero()) {
- Label nonZero;
- masm.branchTestPtr(Assembler::NonZero, rhs, rhs, &nonZero);
- masm.wasmTrap(wasm::Trap::IntegerDivideByZero, lir->trapSiteDesc());
- masm.bind(&nonZero);
- }
+ TrapIfDivideByZero(masm, lir, rhs);
// Handle an integer overflow exception from INT64_MIN / -1.
- if (lir->canBeNegativeOverflow()) {
+ if (mir->canBeNegativeDividend()) {
Label notOverflow;
masm.branchPtr(Assembler::NotEqual, lhs, ImmWord(INT64_MIN), ¬Overflow);
masm.branchPtr(Assembler::NotEqual, rhs, ImmWord(-1), ¬Overflow);
- if (lir->mir()->isMod()) {
+ {
masm.xorl(output, output);
- } else {
- masm.wasmTrap(wasm::Trap::IntegerOverflow, lir->trapSiteDesc());
+ masm.jump(&done);
}
- masm.jump(&done);
masm.bind(¬Overflow);
}
+ // Put the lhs in rax.
+ if (lhs != rax) {
+ masm.mov(lhs, rax);
+ }
+
// Sign extend the lhs into rdx to make rdx:rax.
masm.cqo();
masm.idivq(rhs);
@@ -243,36 +282,48 @@ void CodeGenerator::visitDivOrModI64(LDivOrModI64* lir) {
masm.bind(&done);
}
-void CodeGenerator::visitUDivOrModI64(LUDivOrModI64* lir) {
+void CodeGenerator::visitUDivI64(LUDivI64* lir) {
Register lhs = ToRegister(lir->lhs());
Register rhs = ToRegister(lir->rhs());
- DebugOnly<Register> output = ToRegister(lir->output());
MOZ_ASSERT_IF(lhs != rhs, rhs != rax);
MOZ_ASSERT(rhs != rdx);
- MOZ_ASSERT_IF(output.value == rax, ToRegister(lir->remainder()) == rdx);
- MOZ_ASSERT_IF(output.value == rdx, ToRegister(lir->remainder()) == rax);
+ MOZ_ASSERT(ToRegister(lir->output()) == rax);
+ MOZ_ASSERT(ToRegister(lir->temp0()) == rdx);
+
+ // Prevent divide by zero.
+ TrapIfDivideByZero(masm, lir, rhs);
// Put the lhs in rax.
if (lhs != rax) {
masm.mov(lhs, rax);
}
- Label done;
+ // Zero extend the lhs into rdx to make (rdx:rax).
+ masm.xorl(rdx, rdx);
+ masm.udivq(rhs);
+}
+
+void CodeGenerator::visitUModI64(LUModI64* lir) {
+ Register lhs = ToRegister(lir->lhs());
+ Register rhs = ToRegister(lir->rhs());
+
+ MOZ_ASSERT_IF(lhs != rhs, rhs != rax);
+ MOZ_ASSERT(rhs != rdx);
+ MOZ_ASSERT(ToRegister(lir->output()) == rdx);
+ MOZ_ASSERT(ToRegister(lir->temp0()) == rax);
// Prevent divide by zero.
- if (lir->canBeDivideByZero()) {
- Label nonZero;
- masm.branchTestPtr(Assembler::NonZero, rhs, rhs, &nonZero);
- masm.wasmTrap(wasm::Trap::IntegerDivideByZero, lir->trapSiteDesc());
- masm.bind(&nonZero);
+ TrapIfDivideByZero(masm, lir, rhs);
+
+ // Put the lhs in rax.
+ if (lhs != rax) {
+ masm.mov(lhs, rax);
}
// Zero extend the lhs into rdx to make (rdx:rax).
masm.xorl(rdx, rdx);
masm.udivq(rhs);
-
- masm.bind(&done);
}
void CodeGeneratorX64::emitBigIntPtrDiv(LBigIntPtrDiv* ins, Register dividend,
diff --git a/js/src/jit/x64/LIR-x64.h b/js/src/jit/x64/LIR-x64.h
@@ -28,87 +28,6 @@ class LUnbox : public LInstructionHelper<1, BOX_PIECES, 0> {
const char* extraName() const { return StringFromMIRType(mir()->type()); }
};
-class LDivOrModI64 : public LBinaryMath<1> {
- public:
- LIR_HEADER(DivOrModI64)
-
- LDivOrModI64(const LAllocation& lhs, const LAllocation& rhs,
- const LDefinition& temp)
- : LBinaryMath(classOpcode) {
- setOperand(0, lhs);
- setOperand(1, rhs);
- setTemp(0, temp);
- }
-
- const LDefinition* remainder() { return getTemp(0); }
-
- MBinaryArithInstruction* mir() const {
- MOZ_ASSERT(mir_->isDiv() || mir_->isMod());
- return static_cast<MBinaryArithInstruction*>(mir_);
- }
- bool canBeDivideByZero() const {
- if (mir_->isMod()) {
- return mir_->toMod()->canBeDivideByZero();
- }
- return mir_->toDiv()->canBeDivideByZero();
- }
- bool canBeNegativeOverflow() const {
- if (mir_->isMod()) {
- return mir_->toMod()->canBeNegativeDividend();
- }
- return mir_->toDiv()->canBeNegativeOverflow();
- }
- const wasm::TrapSiteDesc& trapSiteDesc() const {
- MOZ_ASSERT(mir_->isDiv() || mir_->isMod());
- if (mir_->isMod()) {
- return mir_->toMod()->trapSiteDesc();
- }
- return mir_->toDiv()->trapSiteDesc();
- }
-};
-
-// This class performs a simple x86 'div', yielding either a quotient or
-// remainder depending on whether this instruction is defined to output
-// rax (quotient) or rdx (remainder).
-class LUDivOrModI64 : public LBinaryMath<1> {
- public:
- LIR_HEADER(UDivOrModI64);
-
- LUDivOrModI64(const LAllocation& lhs, const LAllocation& rhs,
- const LDefinition& temp)
- : LBinaryMath(classOpcode) {
- setOperand(0, lhs);
- setOperand(1, rhs);
- setTemp(0, temp);
- }
-
- const LDefinition* remainder() { return getTemp(0); }
-
- const char* extraName() const {
- return mir()->isTruncated() ? "Truncated" : nullptr;
- }
-
- MBinaryArithInstruction* mir() const {
- MOZ_ASSERT(mir_->isDiv() || mir_->isMod());
- return static_cast<MBinaryArithInstruction*>(mir_);
- }
-
- bool canBeDivideByZero() const {
- if (mir_->isMod()) {
- return mir_->toMod()->canBeDivideByZero();
- }
- return mir_->toDiv()->canBeDivideByZero();
- }
-
- const wasm::TrapSiteDesc& trapSiteDesc() const {
- MOZ_ASSERT(mir_->isDiv() || mir_->isMod());
- if (mir_->isMod()) {
- return mir_->toMod()->trapSiteDesc();
- }
- return mir_->toDiv()->trapSiteDesc();
- }
-};
-
} // namespace jit
} // namespace js
diff --git a/js/src/jit/x64/Lowering-x64.cpp b/js/src/jit/x64/Lowering-x64.cpp
@@ -526,8 +526,8 @@ void LIRGenerator::visitSubstr(MSubstr* ins) {
}
void LIRGeneratorX64::lowerDivI64(MDiv* div) {
- LDivOrModI64* lir = new (alloc()) LDivOrModI64(
- useRegister(div->lhs()), useRegister(div->rhs()), tempFixed(rdx));
+ auto* lir = new (alloc())
+ LDivI64(useRegister(div->lhs()), useRegister(div->rhs()), tempFixed(rdx));
defineInt64Fixed(lir, div, LInt64Allocation(LAllocation(AnyRegister(rax))));
}
@@ -536,8 +536,8 @@ void LIRGeneratorX64::lowerWasmBuiltinDivI64(MWasmBuiltinDivI64* div) {
}
void LIRGeneratorX64::lowerModI64(MMod* mod) {
- LDivOrModI64* lir = new (alloc()) LDivOrModI64(
- useRegister(mod->lhs()), useRegister(mod->rhs()), tempFixed(rax));
+ auto* lir = new (alloc())
+ LModI64(useRegister(mod->lhs()), useRegister(mod->rhs()), tempFixed(rax));
defineInt64Fixed(lir, mod, LInt64Allocation(LAllocation(AnyRegister(rdx))));
}
@@ -546,14 +546,14 @@ void LIRGeneratorX64::lowerWasmBuiltinModI64(MWasmBuiltinModI64* mod) {
}
void LIRGeneratorX64::lowerUDivI64(MDiv* div) {
- LUDivOrModI64* lir = new (alloc()) LUDivOrModI64(
- useRegister(div->lhs()), useRegister(div->rhs()), tempFixed(rdx));
+ auto* lir = new (alloc()) LUDivI64(useRegister(div->lhs()),
+ useRegister(div->rhs()), tempFixed(rdx));
defineInt64Fixed(lir, div, LInt64Allocation(LAllocation(AnyRegister(rax))));
}
void LIRGeneratorX64::lowerUModI64(MMod* mod) {
- LUDivOrModI64* lir = new (alloc()) LUDivOrModI64(
- useRegister(mod->lhs()), useRegister(mod->rhs()), tempFixed(rax));
+ auto* lir = new (alloc()) LUModI64(useRegister(mod->lhs()),
+ useRegister(mod->rhs()), tempFixed(rax));
defineInt64Fixed(lir, mod, LInt64Allocation(LAllocation(AnyRegister(rdx))));
}
diff --git a/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp b/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp
@@ -872,14 +872,42 @@ void CodeGenerator::visitMulI(LMulI* ins) {
}
}
-void CodeGenerator::visitUDivOrMod(LUDivOrMod* ins) {
+template <class LIR>
+static void TrapIfDivideByZero(MacroAssembler& masm, LIR* lir, Register rhs) {
+ auto* mir = lir->mir();
+ MOZ_ASSERT(mir->trapOnError());
+ MOZ_ASSERT(mir->canBeDivideByZero());
+
+ Label nonZero;
+ masm.branchTest32(Assembler::NonZero, rhs, rhs, &nonZero);
+ masm.wasmTrap(wasm::Trap::IntegerDivideByZero, mir->trapSiteDesc());
+ masm.bind(&nonZero);
+}
+
+OutOfLineCode* CodeGeneratorX86Shared::emitOutOfLineZeroForDivideByZero(
+ Register rhs, Register output) {
+ // Truncated division by zero is zero: (±Infinity|0 == 0) and (NaN|0 == 0).
+ auto* ool = new (alloc()) LambdaOutOfLineCode([=](OutOfLineCode& ool) {
+ masm.mov(ImmWord(0), output);
+ masm.jmp(ool.rejoin());
+ });
+ masm.branchTest32(Assembler::Zero, rhs, rhs, ool->entry());
+
+ return ool;
+}
+
+void CodeGenerator::visitUDiv(LUDiv* ins) {
Register lhs = ToRegister(ins->lhs());
Register rhs = ToRegister(ins->rhs());
Register output = ToRegister(ins->output());
+ Register remainder = ToRegister(ins->temp0());
MOZ_ASSERT_IF(lhs != rhs, rhs != eax);
MOZ_ASSERT(rhs != edx);
- MOZ_ASSERT_IF(output == eax, ToRegister(ins->remainder()) == edx);
+ MOZ_ASSERT(output == eax);
+ MOZ_ASSERT(remainder == edx);
+
+ MDiv* mir = ins->mir();
OutOfLineCode* ool = nullptr;
@@ -889,23 +917,14 @@ void CodeGenerator::visitUDivOrMod(LUDivOrMod* ins) {
}
// Prevent divide by zero.
- if (ins->canBeDivideByZero()) {
- masm.test32(rhs, rhs);
- if (ins->mir()->isTruncated()) {
- if (ins->trapOnError()) {
- Label nonZero;
- masm.j(Assembler::NonZero, &nonZero);
- masm.wasmTrap(wasm::Trap::IntegerDivideByZero, ins->trapSiteDesc());
- masm.bind(&nonZero);
- } else {
- ool = new (alloc()) LambdaOutOfLineCode([=](OutOfLineCode& ool) {
- masm.mov(ImmWord(0), output);
- masm.jmp(ool.rejoin());
- });
- masm.j(Assembler::Zero, ool->entry());
- }
+ if (mir->canBeDivideByZero()) {
+ if (mir->trapOnError()) {
+ TrapIfDivideByZero(masm, ins, rhs);
+ } else if (mir->isTruncated()) {
+ ool = emitOutOfLineZeroForDivideByZero(rhs, output);
} else {
- bailoutIf(Assembler::Zero, ins->snapshot());
+ MOZ_ASSERT(mir->fallible());
+ bailoutTest32(Assembler::Zero, rhs, rhs, ins->snapshot());
}
}
@@ -914,50 +933,81 @@ void CodeGenerator::visitUDivOrMod(LUDivOrMod* ins) {
masm.udiv(rhs);
// If the remainder is > 0, bailout since this must be a double.
- if (ins->mir()->isDiv() && !ins->mir()->toDiv()->canTruncateRemainder()) {
- Register remainder = ToRegister(ins->remainder());
- masm.test32(remainder, remainder);
- bailoutIf(Assembler::NonZero, ins->snapshot());
+ if (!mir->canTruncateRemainder()) {
+ bailoutTest32(Assembler::NonZero, remainder, remainder, ins->snapshot());
}
- // Unsigned div or mod can return a value that's not a signed int32.
+ // Unsigned div can return a value that's not a signed int32.
// If our users aren't expecting that, bail.
- if (!ins->mir()->isTruncated()) {
- masm.test32(output, output);
- bailoutIf(Assembler::Signed, ins->snapshot());
+ if (!mir->isTruncated()) {
+ bailoutTest32(Assembler::Signed, output, output, ins->snapshot());
}
if (ool) {
- addOutOfLineCode(ool, ins->mir());
+ addOutOfLineCode(ool, mir);
masm.bind(ool->rejoin());
}
}
-void CodeGenerator::visitUDivOrModConstant(LUDivOrModConstant* ins) {
- Register lhs = ToRegister(ins->numerator());
+void CodeGenerator::visitUMod(LUMod* ins) {
+ Register lhs = ToRegister(ins->lhs());
+ Register rhs = ToRegister(ins->rhs());
Register output = ToRegister(ins->output());
- uint32_t d = ins->denominator();
- // This emits the division answer into edx or the modulus answer into eax.
- MOZ_ASSERT(output == eax || output == edx);
- MOZ_ASSERT(lhs != eax && lhs != edx);
- bool isDiv = (output == edx);
+ MOZ_ASSERT_IF(lhs != rhs, rhs != eax);
+ MOZ_ASSERT(rhs != edx);
+ MOZ_ASSERT(output == edx);
+ MOZ_ASSERT(ToRegister(ins->temp0()) == eax);
- if (d == 0) {
- if (ins->mir()->isTruncated()) {
- if (ins->trapOnError()) {
- masm.wasmTrap(wasm::Trap::IntegerDivideByZero, ins->trapSiteDesc());
- } else {
- masm.xorl(output, output);
- }
+ MMod* mir = ins->mir();
+
+ OutOfLineCode* ool = nullptr;
+
+ // Put the lhs in eax.
+ if (lhs != eax) {
+ masm.mov(lhs, eax);
+ }
+
+ // Prevent divide by zero.
+ if (mir->canBeDivideByZero()) {
+ if (mir->trapOnError()) {
+ TrapIfDivideByZero(masm, ins, rhs);
+ } else if (mir->isTruncated()) {
+ ool = emitOutOfLineZeroForDivideByZero(rhs, output);
} else {
- bailout(ins->snapshot());
+ MOZ_ASSERT(mir->fallible());
+ bailoutTest32(Assembler::Zero, rhs, rhs, ins->snapshot());
}
- return;
}
+ // Zero extend the lhs into edx to make (edx:eax), since udiv is 64-bit.
+ masm.mov(ImmWord(0), edx);
+ masm.udiv(rhs);
+
+ // Unsigned mod can return a value that's not a signed int32.
+ // If our users aren't expecting that, bail.
+ if (!mir->isTruncated()) {
+ bailoutTest32(Assembler::Signed, output, output, ins->snapshot());
+ }
+
+ if (ool) {
+ addOutOfLineCode(ool, mir);
+ masm.bind(ool->rejoin());
+ }
+}
+
+template <class LUDivOrUMod>
+static void UnsignedDivideWithConstant(MacroAssembler& masm, LUDivOrUMod* ins) {
+ Register lhs = ToRegister(ins->numerator());
+ [[maybe_unused]] Register output = ToRegister(ins->output());
+ [[maybe_unused]] Register temp = ToRegister(ins->temp0());
+ uint32_t d = ins->denominator();
+
+ MOZ_ASSERT(lhs != eax && lhs != edx);
+ MOZ_ASSERT((output == eax && temp == edx) || (output == edx && temp == eax));
+
// The denominator isn't a power of 2 (see LDivPowTwoI and LModPowTwoI).
- MOZ_ASSERT((d & (d - 1)) != 0);
+ MOZ_ASSERT(!mozilla::IsPowerOfTwo(d));
auto rmc = ReciprocalMulConstants::computeUnsignedDivisionConstants(d);
@@ -989,27 +1039,77 @@ void CodeGenerator::visitUDivOrModConstant(LUDivOrModConstant* ins) {
} else {
masm.shrl(Imm32(rmc.shiftAmount), edx);
}
+}
- // We now have the truncated division value in edx. If we're
- // computing a modulus or checking whether the division resulted
- // in an integer, we need to multiply the obtained value by d and
- // finish the computation/check.
- if (!isDiv) {
- masm.imull(Imm32(d), edx, edx);
- masm.movl(lhs, eax);
- masm.subl(edx, eax);
+void CodeGenerator::visitUDivConstant(LUDivConstant* ins) {
+ Register lhs = ToRegister(ins->numerator());
+ Register output = ToRegister(ins->output());
+ uint32_t d = ins->denominator();
- // The final result of the modulus op, just computed above by the
- // sub instruction, can be a number in the range [2^31, 2^32). If
- // this is the case and the modulus is not truncated, we must bail
- // out.
- if (!ins->mir()->isTruncated()) {
- bailoutIf(Assembler::Signed, ins->snapshot());
+ MDiv* mir = ins->mir();
+
+ // This emits the division answer into edx.
+ MOZ_ASSERT(output == edx);
+
+ if (d == 0) {
+ if (mir->trapOnError()) {
+ masm.wasmTrap(wasm::Trap::IntegerDivideByZero, mir->trapSiteDesc());
+ } else if (mir->isTruncated()) {
+ masm.xorl(output, output);
+ } else {
+ bailout(ins->snapshot());
}
- } else if (!ins->mir()->isTruncated()) {
+ return;
+ }
+
+ // Compute the truncated division result in |edx|.
+ UnsignedDivideWithConstant(masm, ins);
+
+ if (!mir->isTruncated()) {
masm.imull(Imm32(d), edx, eax);
- masm.cmpl(lhs, eax);
- bailoutIf(Assembler::NotEqual, ins->snapshot());
+ bailoutCmp32(Assembler::NotEqual, lhs, eax, ins->snapshot());
+ }
+}
+
+void CodeGenerator::visitUModConstant(LUModConstant* ins) {
+ Register lhs = ToRegister(ins->numerator());
+ Register output = ToRegister(ins->output());
+ uint32_t d = ins->denominator();
+
+ MMod* mir = ins->mir();
+
+ // This emits the modulus answer into eax.
+ MOZ_ASSERT(output == eax);
+
+ if (d == 0) {
+ if (mir->trapOnError()) {
+ masm.wasmTrap(wasm::Trap::IntegerDivideByZero, mir->trapSiteDesc());
+ } else if (mir->isTruncated()) {
+ masm.xorl(output, output);
+ } else {
+ bailout(ins->snapshot());
+ }
+ return;
+ }
+
+ // Compute the truncated division result in |edx|.
+ UnsignedDivideWithConstant(masm, ins);
+
+ // We now have the truncated division value in edx. If we're computing a
+ // modulus or checking whether the division resulted in an integer, we need
+ // to multiply the obtained value by d and finish the computation/check.
+ //
+ // eax = lhs - d * edx
+ masm.imull(Imm32(d), edx, edx);
+ masm.movl(lhs, eax);
+ masm.subl(edx, eax);
+
+ // The final result of the modulus op, just computed above by the
+ // sub instruction, can be a number in the range [2^31, 2^32). If
+ // this is the case and the modulus is not truncated, we must bail
+ // out.
+ if (!mir->isTruncated()) {
+ bailoutIf(Assembler::Signed, ins->snapshot());
}
}
@@ -1027,15 +1127,14 @@ void CodeGenerator::visitDivPowTwoI(LDivPowTwoI* ins) {
if (!mir->isTruncated() && negativeDivisor) {
// 0 divided by a negative number must return a double.
- masm.test32(lhs, lhs);
- bailoutIf(Assembler::Zero, ins->snapshot());
+ bailoutTest32(Assembler::Zero, lhs, lhs, ins->snapshot());
}
if (shift) {
if (!mir->isTruncated()) {
// If the remainder is != 0, bailout since this must be a double.
- masm.test32(lhs, Imm32(UINT32_MAX >> (32 - shift)));
- bailoutIf(Assembler::NonZero, ins->snapshot());
+ bailoutTest32(Assembler::NonZero, lhs, Imm32(UINT32_MAX >> (32 - shift)),
+ ins->snapshot());
}
if (mir->isUnsigned()) {
@@ -1084,27 +1183,27 @@ void CodeGenerator::visitDivPowTwoI(LDivPowTwoI* ins) {
masm.bind(&ok);
}
} else if (mir->isUnsigned() && !mir->isTruncated()) {
- // Unsigned division by 1 can overflow if output is not
- // truncated.
- masm.test32(lhs, lhs);
- bailoutIf(Assembler::Signed, ins->snapshot());
+ // Unsigned division by 1 can overflow if output is not truncated.
+ bailoutTest32(Assembler::Signed, lhs, lhs, ins->snapshot());
}
}
-void CodeGenerator::visitDivOrModConstantI(LDivOrModConstantI* ins) {
+template <class LDivOrMod>
+static void DivideWithConstant(MacroAssembler& masm, LDivOrMod* ins) {
Register lhs = ToRegister(ins->numerator());
- Register output = ToRegister(ins->output());
+ [[maybe_unused]] Register output = ToRegister(ins->output());
+ [[maybe_unused]] Register temp = ToRegister(ins->temp0());
int32_t d = ins->denominator();
- // This emits the division answer into edx or the modulus answer into eax.
- MOZ_ASSERT(output == eax || output == edx);
MOZ_ASSERT(lhs != eax && lhs != edx);
- bool isDiv = (output == edx);
+ MOZ_ASSERT((output == eax && temp == edx) || (output == edx && temp == eax));
// The absolute value of the denominator isn't a power of 2 (see LDivPowTwoI
// and LModPowTwoI).
MOZ_ASSERT(!mozilla::IsPowerOfTwo(mozilla::Abs(d)));
+ auto* mir = ins->mir();
+
// We will first divide by Abs(d), and negate the answer if d is negative.
// If desired, this can be avoided by generalizing computeDivisionConstants.
auto rmc = ReciprocalMulConstants::computeSignedDivisionConstants(d);
@@ -1128,7 +1227,7 @@ void CodeGenerator::visitDivOrModConstantI(LDivOrModConstantI* ins) {
// We'll subtract -1 instead of adding 1, because (n < 0 ? -1 : 0) can be
// computed with just a sign-extending shift of 31 bits.
- if (ins->canBeNegativeDividend()) {
+ if (mir->canBeNegativeDividend()) {
masm.movl(lhs, eax);
masm.sarl(Imm32(31), eax);
masm.subl(eax, edx);
@@ -1138,39 +1237,81 @@ void CodeGenerator::visitDivOrModConstantI(LDivOrModConstantI* ins) {
if (d < 0) {
masm.negl(edx);
}
+}
+
+void CodeGenerator::visitDivConstantI(LDivConstantI* ins) {
+ Register lhs = ToRegister(ins->numerator());
+ Register output = ToRegister(ins->output());
+ int32_t d = ins->denominator();
+
+ MDiv* mir = ins->mir();
- if (!isDiv) {
- masm.imull(Imm32(-d), edx, eax);
- masm.addl(lhs, eax);
+ // This emits the division answer into edx.
+ MOZ_ASSERT(output == edx);
+
+ if (d == 0) {
+ if (mir->trapOnError()) {
+ masm.wasmTrap(wasm::Trap::IntegerDivideByZero, mir->trapSiteDesc());
+ } else if (mir->isTruncated()) {
+ masm.xorl(output, output);
+ } else {
+ bailout(ins->snapshot());
+ }
+ return;
}
- if (!ins->mir()->isTruncated()) {
- if (isDiv) {
- // This is a division op. Multiply the obtained value by d to check if
- // the correct answer is an integer. This cannot overflow, since |d| > 1.
- masm.imull(Imm32(d), edx, eax);
- masm.cmp32(lhs, eax);
- bailoutIf(Assembler::NotEqual, ins->snapshot());
+ // Compute the truncated division result in |edx|.
+ DivideWithConstant(masm, ins);
- // If lhs is zero and the divisor is negative, the answer should have
- // been -0.
- if (d < 0) {
- masm.test32(lhs, lhs);
- bailoutIf(Assembler::Zero, ins->snapshot());
- }
- } else if (ins->canBeNegativeDividend()) {
- // This is a mod op. If the computed value is zero and lhs
- // is negative, the answer should have been -0.
- Label done;
+ if (!mir->isTruncated()) {
+ // This is a division op. Multiply the obtained value by d to check if
+ // the correct answer is an integer. This cannot overflow, since |d| > 1.
+ masm.imull(Imm32(d), edx, eax);
+ bailoutCmp32(Assembler::NotEqual, lhs, eax, ins->snapshot());
- masm.cmp32(lhs, Imm32(0));
- masm.j(Assembler::GreaterThanOrEqual, &done);
+ // If lhs is zero and the divisor is negative, the answer should have
+ // been -0.
+ if (d < 0) {
+ bailoutTest32(Assembler::Zero, lhs, lhs, ins->snapshot());
+ }
+ }
+}
- masm.test32(eax, eax);
- bailoutIf(Assembler::Zero, ins->snapshot());
+void CodeGenerator::visitModConstantI(LModConstantI* ins) {
+ Register lhs = ToRegister(ins->numerator());
+ Register output = ToRegister(ins->output());
+ int32_t d = ins->denominator();
+
+ MMod* mir = ins->mir();
+
+ // This emits the modulus answer into eax.
+ MOZ_ASSERT(output == eax);
- masm.bind(&done);
+ if (d == 0) {
+ if (mir->trapOnError()) {
+ masm.wasmTrap(wasm::Trap::IntegerDivideByZero, mir->trapSiteDesc());
+ } else if (mir->isTruncated()) {
+ masm.xorl(output, output);
+ } else {
+ bailout(ins->snapshot());
}
+ return;
+ }
+
+ // Compute the truncated division result in |edx|.
+ DivideWithConstant(masm, ins);
+
+ // Compute the remainder in |eax|: eax = lhs - d * edx
+ masm.imull(Imm32(-d), edx, eax);
+ masm.addl(lhs, eax);
+
+ if (!mir->isTruncated() && mir->canBeNegativeDividend()) {
+ // This is a mod op. If the computed value is zero and lhs
+ // is negative, the answer should have been -0.
+ Label done;
+ masm.branch32(Assembler::GreaterThanOrEqual, lhs, Imm32(0), &done);
+ bailoutTest32(Assembler::Zero, eax, eax, ins->snapshot());
+ masm.bind(&done);
}
}
@@ -1180,13 +1321,13 @@ void CodeGenerator::visitDivI(LDivI* ins) {
Register rhs = ToRegister(ins->rhs());
Register output = ToRegister(ins->output());
- MDiv* mir = ins->mir();
-
MOZ_ASSERT_IF(lhs != rhs, rhs != eax);
MOZ_ASSERT(rhs != edx);
MOZ_ASSERT(remainder == edx);
MOZ_ASSERT(output == eax);
+ MDiv* mir = ins->mir();
+
Label done;
OutOfLineCode* ool = nullptr;
@@ -1198,43 +1339,30 @@ void CodeGenerator::visitDivI(LDivI* ins) {
// Handle divide by zero.
if (mir->canBeDivideByZero()) {
- masm.test32(rhs, rhs);
if (mir->trapOnError()) {
- Label nonZero;
- masm.j(Assembler::NonZero, &nonZero);
- masm.wasmTrap(wasm::Trap::IntegerDivideByZero, mir->trapSiteDesc());
- masm.bind(&nonZero);
+ TrapIfDivideByZero(masm, ins, rhs);
} else if (mir->canTruncateInfinities()) {
- // Truncated division by zero is zero (Infinity|0 == 0)
- if (!ool) {
- ool = new (alloc()) LambdaOutOfLineCode([=](OutOfLineCode& ool) {
- masm.mov(ImmWord(0), output);
- masm.jmp(ool.rejoin());
- });
- }
- masm.j(Assembler::Zero, ool->entry());
+ ool = emitOutOfLineZeroForDivideByZero(rhs, output);
} else {
MOZ_ASSERT(mir->fallible());
- bailoutIf(Assembler::Zero, ins->snapshot());
+ bailoutTest32(Assembler::Zero, rhs, rhs, ins->snapshot());
}
}
// Handle an integer overflow exception from -2147483648 / -1.
if (mir->canBeNegativeOverflow()) {
Label notOverflow;
- masm.cmp32(lhs, Imm32(INT32_MIN));
- masm.j(Assembler::NotEqual, ¬Overflow);
- masm.cmp32(rhs, Imm32(-1));
+ masm.branch32(Assembler::NotEqual, lhs, Imm32(INT32_MIN), ¬Overflow);
if (mir->trapOnError()) {
- masm.j(Assembler::NotEqual, ¬Overflow);
+ masm.branch32(Assembler::NotEqual, rhs, Imm32(-1), ¬Overflow);
masm.wasmTrap(wasm::Trap::IntegerOverflow, mir->trapSiteDesc());
} else if (mir->canTruncateOverflow()) {
// (-INT32_MIN)|0 == INT32_MIN and INT32_MIN is already in the
// output register (lhs == eax).
- masm.j(Assembler::Equal, &done);
+ masm.branch32(Assembler::Equal, rhs, Imm32(-1), &done);
} else {
MOZ_ASSERT(mir->fallible());
- bailoutIf(Assembler::Equal, ins->snapshot());
+ bailoutCmp32(Assembler::Equal, rhs, Imm32(-1), ins->snapshot());
}
masm.bind(¬Overflow);
}
@@ -1242,10 +1370,8 @@ void CodeGenerator::visitDivI(LDivI* ins) {
// Handle negative 0.
if (!mir->canTruncateNegativeZero() && mir->canBeNegativeZero()) {
Label nonzero;
- masm.test32(lhs, lhs);
- masm.j(Assembler::NonZero, &nonzero);
- masm.cmp32(rhs, Imm32(0));
- bailoutIf(Assembler::LessThan, ins->snapshot());
+ masm.branchTest32(Assembler::NonZero, lhs, lhs, &nonzero);
+ bailoutCmp32(Assembler::LessThan, rhs, Imm32(0), ins->snapshot());
masm.bind(&nonzero);
}
@@ -1258,8 +1384,7 @@ void CodeGenerator::visitDivI(LDivI* ins) {
if (!mir->canTruncateRemainder()) {
// If the remainder is > 0, bailout since this must be a double.
- masm.test32(remainder, remainder);
- bailoutIf(Assembler::NonZero, ins->snapshot());
+ bailoutTest32(Assembler::NonZero, remainder, remainder, ins->snapshot());
}
masm.bind(&done);
@@ -1349,6 +1474,8 @@ void CodeGenerator::visitModI(LModI* ins) {
MOZ_ASSERT(remainder == edx);
MOZ_ASSERT(ToRegister(ins->temp0()) == eax);
+ MMod* mir = ins->mir();
+
Label done;
OutOfLineCode* ool = nullptr;
ModOverflowCheck* overflow = nullptr;
@@ -1358,28 +1485,15 @@ void CodeGenerator::visitModI(LModI* ins) {
masm.mov(lhs, eax);
}
- MMod* mir = ins->mir();
-
// Prevent divide by zero.
if (mir->canBeDivideByZero()) {
- masm.test32(rhs, rhs);
- if (mir->isTruncated()) {
- if (mir->trapOnError()) {
- Label nonZero;
- masm.j(Assembler::NonZero, &nonZero);
- masm.wasmTrap(wasm::Trap::IntegerDivideByZero, mir->trapSiteDesc());
- masm.bind(&nonZero);
- } else {
- if (!ool) {
- ool = new (alloc()) LambdaOutOfLineCode([=](OutOfLineCode& ool) {
- masm.mov(ImmWord(0), edx);
- masm.jmp(ool.rejoin());
- });
- }
- masm.j(Assembler::Zero, ool->entry());
- }
+ if (mir->trapOnError()) {
+ TrapIfDivideByZero(masm, ins, rhs);
+ } else if (mir->isTruncated()) {
+ ool = emitOutOfLineZeroForDivideByZero(rhs, remainder);
} else {
- bailoutIf(Assembler::Zero, ins->snapshot());
+ MOZ_ASSERT(mir->fallible());
+ bailoutTest32(Assembler::Zero, rhs, rhs, ins->snapshot());
}
}
@@ -1425,17 +1539,16 @@ void CodeGenerator::visitModI(LModI* ins) {
masm.bind(&negative);
// Prevent an integer overflow exception from -2147483648 % -1
- masm.cmp32(lhs, Imm32(INT32_MIN));
overflow = new (alloc()) ModOverflowCheck(ins, rhs);
- masm.j(Assembler::Equal, overflow->entry());
+ masm.branch32(Assembler::Equal, lhs, Imm32(INT32_MIN), overflow->entry());
masm.bind(overflow->rejoin());
+
masm.cdq();
masm.idiv(rhs);
if (!mir->isTruncated()) {
// A remainder of 0 means that the rval must be -0, which is a double.
- masm.test32(remainder, remainder);
- bailoutIf(Assembler::Zero, ins->snapshot());
+ bailoutTest32(Assembler::Zero, remainder, remainder, ins->snapshot());
}
}
diff --git a/js/src/jit/x86-shared/CodeGenerator-x86-shared.h b/js/src/jit/x86-shared/CodeGenerator-x86-shared.h
@@ -84,6 +84,11 @@ class CodeGeneratorX86Shared : public CodeGeneratorShared {
void emitTableSwitchDispatch(MTableSwitch* mir, Register index,
Register base);
+ // Emit out-of-line code to zero |output| if |rhs| is zero. Used for truncated
+ // division and modulus instructions.
+ OutOfLineCode* emitOutOfLineZeroForDivideByZero(Register rhs,
+ Register output);
+
void generateInvalidateEpilogue();
template <typename T>
diff --git a/js/src/jit/x86-shared/LIR-x86-shared.h b/js/src/jit/x86-shared/LIR-x86-shared.h
@@ -1,130 +0,0 @@
-/* -*- 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/. */
-
-#ifndef jit_x86_shared_LIR_x86_shared_h
-#define jit_x86_shared_LIR_x86_shared_h
-
-namespace js {
-namespace jit {
-
-class LDivOrModConstantI : public LInstructionHelper<1, 1, 1> {
- const int32_t denominator_;
-
- public:
- LIR_HEADER(DivOrModConstantI)
-
- LDivOrModConstantI(const LAllocation& lhs, int32_t denominator,
- const LDefinition& temp)
- : LInstructionHelper(classOpcode), denominator_(denominator) {
- setOperand(0, lhs);
- setTemp(0, temp);
- }
-
- const LAllocation* numerator() { return getOperand(0); }
- int32_t denominator() const { return denominator_; }
- MBinaryArithInstruction* mir() const {
- MOZ_ASSERT(mir_->isDiv() || mir_->isMod());
- return static_cast<MBinaryArithInstruction*>(mir_);
- }
- bool canBeNegativeDividend() const {
- if (mir_->isMod()) {
- return mir_->toMod()->canBeNegativeDividend();
- }
- return mir_->toDiv()->canBeNegativeDividend();
- }
-};
-
-// This class performs a simple x86 'div', yielding either a quotient or
-// remainder depending on whether this instruction is defined to output eax
-// (quotient) or edx (remainder).
-class LUDivOrMod : public LBinaryMath<1> {
- public:
- LIR_HEADER(UDivOrMod);
-
- LUDivOrMod(const LAllocation& lhs, const LAllocation& rhs,
- const LDefinition& temp)
- : LBinaryMath(classOpcode) {
- setOperand(0, lhs);
- setOperand(1, rhs);
- setTemp(0, temp);
- }
-
- const LDefinition* remainder() { return getTemp(0); }
-
- const char* extraName() const {
- return mir()->isTruncated() ? "Truncated" : nullptr;
- }
-
- MBinaryArithInstruction* mir() const {
- MOZ_ASSERT(mir_->isDiv() || mir_->isMod());
- return static_cast<MBinaryArithInstruction*>(mir_);
- }
-
- bool canBeDivideByZero() const {
- if (mir_->isMod()) {
- return mir_->toMod()->canBeDivideByZero();
- }
- return mir_->toDiv()->canBeDivideByZero();
- }
-
- bool trapOnError() const {
- if (mir_->isMod()) {
- return mir_->toMod()->trapOnError();
- }
- return mir_->toDiv()->trapOnError();
- }
-
- wasm::TrapSiteDesc trapSiteDesc() const {
- if (mir_->isMod()) {
- return mir_->toMod()->trapSiteDesc();
- }
- return mir_->toDiv()->trapSiteDesc();
- }
-};
-
-class LUDivOrModConstant : public LInstructionHelper<1, 1, 1> {
- const uint32_t denominator_;
-
- public:
- LIR_HEADER(UDivOrModConstant)
-
- LUDivOrModConstant(const LAllocation& lhs, uint32_t denominator,
- const LDefinition& temp)
- : LInstructionHelper(classOpcode), denominator_(denominator) {
- setOperand(0, lhs);
- setTemp(0, temp);
- }
-
- const LAllocation* numerator() { return getOperand(0); }
- uint32_t denominator() const { return denominator_; }
- MBinaryArithInstruction* mir() const {
- MOZ_ASSERT(mir_->isDiv() || mir_->isMod());
- return static_cast<MBinaryArithInstruction*>(mir_);
- }
- bool canBeNegativeDividend() const {
- if (mir_->isMod()) {
- return mir_->toMod()->canBeNegativeDividend();
- }
- return mir_->toDiv()->canBeNegativeDividend();
- }
- bool trapOnError() const {
- if (mir_->isMod()) {
- return mir_->toMod()->trapOnError();
- }
- return mir_->toDiv()->trapOnError();
- }
- wasm::TrapSiteDesc trapSiteDesc() const {
- if (mir_->isMod()) {
- return mir_->toMod()->trapSiteDesc();
- }
- return mir_->toDiv()->trapSiteDesc();
- }
-};
-
-} // namespace jit
-} // namespace js
-
-#endif /* jit_x86_shared_LIR_x86_shared_h */
diff --git a/js/src/jit/x86-shared/Lowering-x86-shared.cpp b/js/src/jit/x86-shared/Lowering-x86-shared.cpp
@@ -179,36 +179,35 @@ void LIRGeneratorX86Shared::lowerDivI(MDiv* div) {
int32_t shift = FloorLog2(Abs(rhs));
if (rhs != 0 && uint32_t(1) << shift == Abs(rhs)) {
LAllocation lhs = useRegisterAtStart(div->lhs());
- LDivPowTwoI* lir;
+
// When truncated with maybe a non-zero remainder, we have to round the
// result toward 0. This requires an extra register to round up/down
// whether the left-hand-side is signed.
+ //
+ // If the numerator might be signed, and needs adjusting, then an extra
+ // lhs copy is needed to round the result of the integer division towards
+ // zero.
+ //
+ // Otherwise the numerator is unsigned, so does not need adjusting.
bool needRoundNeg = div->canBeNegativeDividend() && div->isTruncated();
- if (!needRoundNeg) {
- // Numerator is unsigned, so does not need adjusting.
- lir = new (alloc()) LDivPowTwoI(lhs, lhs, shift, rhs < 0);
- } else {
- // Numerator might be signed, and needs adjusting, and an extra lhs copy
- // is needed to round the result of the integer division towards zero.
- lir = new (alloc())
- LDivPowTwoI(lhs, useRegister(div->lhs()), shift, rhs < 0);
- }
+ LAllocation lhsCopy =
+ needRoundNeg ? useRegister(div->lhs()) : LAllocation();
+
+ auto* lir = new (alloc()) LDivPowTwoI(lhs, lhsCopy, shift, rhs < 0);
if (div->fallible()) {
assignSnapshot(lir, div->bailoutKind());
}
defineReuseInput(lir, div, 0);
return;
}
- if (rhs != 0) {
- LDivOrModConstantI* lir;
- lir = new (alloc())
- LDivOrModConstantI(useRegister(div->lhs()), rhs, tempFixed(eax));
- if (div->fallible()) {
- assignSnapshot(lir, div->bailoutKind());
- }
- defineFixed(lir, div, LAllocation(AnyRegister(edx)));
- return;
+
+ auto* lir = new (alloc())
+ LDivConstantI(useRegister(div->lhs()), tempFixed(eax), rhs);
+ if (div->fallible()) {
+ assignSnapshot(lir, div->bailoutKind());
}
+ defineFixed(lir, div, LAllocation(AnyRegister(edx)));
+ return;
}
LDivI* lir = new (alloc())
@@ -224,7 +223,7 @@ void LIRGeneratorX86Shared::lowerModI(MMod* mod) {
int32_t rhs = mod->rhs()->toConstant()->toInt32();
int32_t shift = FloorLog2(Abs(rhs));
if (rhs != 0 && uint32_t(1) << shift == Abs(rhs)) {
- LModPowTwoI* lir =
+ auto* lir =
new (alloc()) LModPowTwoI(useRegisterAtStart(mod->lhs()), shift);
if (mod->fallible()) {
assignSnapshot(lir, mod->bailoutKind());
@@ -232,16 +231,14 @@ void LIRGeneratorX86Shared::lowerModI(MMod* mod) {
defineReuseInput(lir, mod, 0);
return;
}
- if (rhs != 0) {
- LDivOrModConstantI* lir;
- lir = new (alloc())
- LDivOrModConstantI(useRegister(mod->lhs()), rhs, tempFixed(edx));
- if (mod->fallible()) {
- assignSnapshot(lir, mod->bailoutKind());
- }
- defineFixed(lir, mod, LAllocation(AnyRegister(eax)));
- return;
+
+ auto* lir = new (alloc())
+ LModConstantI(useRegister(mod->lhs()), tempFixed(edx), rhs);
+ if (mod->fallible()) {
+ assignSnapshot(lir, mod->bailoutKind());
}
+ defineFixed(lir, mod, LAllocation(AnyRegister(eax)));
+ return;
}
LModI* lir = new (alloc())
@@ -358,16 +355,16 @@ void LIRGeneratorX86Shared::lowerUDiv(MDiv* div) {
uint32_t rhs = div->rhs()->toConstant()->toInt32();
int32_t shift = FloorLog2(rhs);
- LAllocation lhs = useRegisterAtStart(div->lhs());
if (rhs != 0 && uint32_t(1) << shift == rhs) {
- LDivPowTwoI* lir = new (alloc()) LDivPowTwoI(lhs, lhs, shift, false);
+ auto* lir = new (alloc()) LDivPowTwoI(useRegisterAtStart(div->lhs()),
+ LAllocation(), shift, false);
if (div->fallible()) {
assignSnapshot(lir, div->bailoutKind());
}
defineReuseInput(lir, div, 0);
} else {
- LUDivOrModConstant* lir = new (alloc())
- LUDivOrModConstant(useRegister(div->lhs()), rhs, tempFixed(eax));
+ auto* lir = new (alloc())
+ LUDivConstant(useRegister(div->lhs()), tempFixed(eax), rhs);
if (div->fallible()) {
assignSnapshot(lir, div->bailoutKind());
}
@@ -376,8 +373,8 @@ void LIRGeneratorX86Shared::lowerUDiv(MDiv* div) {
return;
}
- LUDivOrMod* lir = new (alloc()) LUDivOrMod(
- useRegister(div->lhs()), useRegister(div->rhs()), tempFixed(edx));
+ auto* lir = new (alloc())
+ LUDiv(useRegister(div->lhs()), useRegister(div->rhs()), tempFixed(edx));
if (div->fallible()) {
assignSnapshot(lir, div->bailoutKind());
}
@@ -390,15 +387,15 @@ void LIRGeneratorX86Shared::lowerUMod(MMod* mod) {
int32_t shift = FloorLog2(rhs);
if (rhs != 0 && uint32_t(1) << shift == rhs) {
- LModPowTwoI* lir =
+ auto* lir =
new (alloc()) LModPowTwoI(useRegisterAtStart(mod->lhs()), shift);
if (mod->fallible()) {
assignSnapshot(lir, mod->bailoutKind());
}
defineReuseInput(lir, mod, 0);
} else {
- LUDivOrModConstant* lir = new (alloc())
- LUDivOrModConstant(useRegister(mod->lhs()), rhs, tempFixed(edx));
+ auto* lir = new (alloc())
+ LUModConstant(useRegister(mod->lhs()), tempFixed(edx), rhs);
if (mod->fallible()) {
assignSnapshot(lir, mod->bailoutKind());
}
@@ -407,8 +404,8 @@ void LIRGeneratorX86Shared::lowerUMod(MMod* mod) {
return;
}
- LUDivOrMod* lir = new (alloc()) LUDivOrMod(
- useRegister(mod->lhs()), useRegister(mod->rhs()), tempFixed(eax));
+ auto* lir = new (alloc())
+ LUMod(useRegister(mod->lhs()), useRegister(mod->rhs()), tempFixed(eax));
if (mod->fallible()) {
assignSnapshot(lir, mod->bailoutKind());
}
diff --git a/js/src/jit/x86/CodeGenerator-x86.cpp b/js/src/jit/x86/CodeGenerator-x86.cpp
@@ -886,10 +886,10 @@ void CodeGenerator::visitDivOrModI64(LDivOrModI64* lir) {
masm.branch64(Assembler::NotEqual, rhs, Imm64(-1), ¬Overflow);
if (mir->isWasmBuiltinModI64()) {
masm.xor64(output, output);
+ masm.jump(&done);
} else {
masm.wasmTrap(wasm::Trap::IntegerOverflow, lir->trapSiteDesc());
}
- masm.jump(&done);
masm.bind(¬Overflow);
}