tor-browser

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

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:
Mjs/src/jit/LIR.h | 11++++-------
Mjs/src/jit/LIROps.yaml | 102+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------
Mjs/src/jit/x64/CodeGenerator-x64.cpp | 111+++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------
Mjs/src/jit/x64/LIR-x64.h | 81-------------------------------------------------------------------------------
Mjs/src/jit/x64/Lowering-x64.cpp | 16++++++++--------
Mjs/src/jit/x86-shared/CodeGenerator-x86-shared.cpp | 415++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
Mjs/src/jit/x86-shared/CodeGenerator-x86-shared.h | 5+++++
Djs/src/jit/x86-shared/LIR-x86-shared.h | 130-------------------------------------------------------------------------------
Mjs/src/jit/x86-shared/Lowering-x86-shared.cpp | 77+++++++++++++++++++++++++++++++++++++----------------------------------------
Mjs/src/jit/x86/CodeGenerator-x86.cpp | 2+-
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), &notOverflow); + masm.branchPtr(Assembler::NotEqual, rhs, ImmWord(-1), &notOverflow); + masm.wasmTrap(wasm::Trap::IntegerOverflow, mir->trapSiteDesc()); + masm.bind(&notOverflow); + } // 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), &notOverflow); masm.branchPtr(Assembler::NotEqual, rhs, ImmWord(-1), &notOverflow); - if (lir->mir()->isMod()) { + { masm.xorl(output, output); - } else { - masm.wasmTrap(wasm::Trap::IntegerOverflow, lir->trapSiteDesc()); + masm.jump(&done); } - masm.jump(&done); masm.bind(&notOverflow); } + // 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, &notOverflow); - masm.cmp32(rhs, Imm32(-1)); + masm.branch32(Assembler::NotEqual, lhs, Imm32(INT32_MIN), &notOverflow); if (mir->trapOnError()) { - masm.j(Assembler::NotEqual, &notOverflow); + masm.branch32(Assembler::NotEqual, rhs, Imm32(-1), &notOverflow); 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(&notOverflow); } @@ -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), &notOverflow); if (mir->isWasmBuiltinModI64()) { masm.xor64(output, output); + masm.jump(&done); } else { masm.wasmTrap(wasm::Trap::IntegerOverflow, lir->trapSiteDesc()); } - masm.jump(&done); masm.bind(&notOverflow); }