commit e716a6eaa68a7f2abef18e60df96722780f37433
parent c9c43eeaccd398e493a05ff34bbbf8e92b4f6f94
Author: André Bargull <andre.bargull@gmail.com>
Date: Fri, 24 Oct 2025 14:58:54 +0000
Bug 1996083 - Part 5: Use at-start and don't reuse input for ALU operations on {mips,loong,riscv}64. r=spidermonkey-reviewers,jandem
Differential Revision: https://phabricator.services.mozilla.com/D269838
Diffstat:
5 files changed, 81 insertions(+), 115 deletions(-)
diff --git a/js/src/jit/LIROps.yaml b/js/src/jit/LIROps.yaml
@@ -1344,7 +1344,9 @@
operands:
lhs: Int64
rhs: Int64
+#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_ARM)
num_temps: 1
+#endif
defer_init: true
- name: MulIntPtr
diff --git a/js/src/jit/arm64/Lowering-arm64.cpp b/js/src/jit/arm64/Lowering-arm64.cpp
@@ -139,13 +139,6 @@ void LIRGeneratorARM64::lowerForALUInt64(
defineInt64(ins, mir);
}
-// These all currently have codegen that depends on reuse but only because the
-// masm API depends on that. We need new three-address masm APIs, for both
-// constant and variable rhs.
-//
-// MAdd => LAddI64
-// MSub => LSubI64
-// MBitAnd, MBitOr, MBitXor => LBitOpI64
void LIRGeneratorARM64::lowerForALUInt64(
LInstructionHelper<INT64_PIECES, 2 * INT64_PIECES, 0>* ins,
MDefinition* mir, MDefinition* lhs, MDefinition* rhs) {
@@ -156,9 +149,7 @@ void LIRGeneratorARM64::lowerForALUInt64(
void LIRGeneratorARM64::lowerForMulInt64(LMulI64* ins, MMul* mir,
MDefinition* lhs, MDefinition* rhs) {
- ins->setLhs(useInt64RegisterAtStart(lhs));
- ins->setRhs(useInt64RegisterOrConstantAtStart(rhs));
- defineInt64(ins, mir);
+ lowerForALUInt64(ins, mir, lhs, rhs);
}
template <class LInstr>
diff --git a/js/src/jit/loong64/Lowering-loong64.cpp b/js/src/jit/loong64/Lowering-loong64.cpp
@@ -31,9 +31,7 @@ LTableSwitchV* LIRGeneratorLOONG64::newLTableSwitchV(const LBoxAllocation& in) {
void LIRGeneratorLOONG64::lowerForShift(LInstructionHelper<1, 2, 0>* ins,
MDefinition* mir, MDefinition* lhs,
MDefinition* rhs) {
- ins->setOperand(0, useRegister(lhs));
- ins->setOperand(1, useRegisterOrConstant(rhs));
- define(ins, mir);
+ lowerForALU(ins, mir, lhs, rhs);
}
template <class LInstr>
@@ -42,13 +40,12 @@ void LIRGeneratorLOONG64::lowerForShiftInt64(LInstr* ins, MDefinition* mir,
MDefinition* rhs) {
if constexpr (std::is_same_v<LInstr, LShiftI64>) {
ins->setLhs(useInt64RegisterAtStart(lhs));
- ins->setRhs(useRegisterOrConstant(rhs));
- defineInt64ReuseInput(ins, mir, LShiftI64::LhsIndex);
+ ins->setRhs(useRegisterOrConstantAtStart(rhs));
} else {
ins->setInput(useInt64RegisterAtStart(lhs));
- ins->setCount(useRegisterOrConstant(rhs));
- defineInt64ReuseInput(ins, mir, LRotateI64::InputIndex);
+ ins->setCount(useRegisterOrConstantAtStart(rhs));
}
+ defineInt64(ins, mir);
}
template void LIRGeneratorLOONG64::lowerForShiftInt64(LShiftI64* ins,
@@ -63,7 +60,9 @@ template void LIRGeneratorLOONG64::lowerForShiftInt64(LRotateI64* ins,
// x = !y
void LIRGeneratorLOONG64::lowerForALU(LInstructionHelper<1, 1, 0>* ins,
MDefinition* mir, MDefinition* input) {
- ins->setOperand(0, useRegister(input));
+ // Unary ALU operations don't read the input after writing to the output, even
+ // for fallible operations, so we can use at-start allocations.
+ ins->setOperand(0, useRegisterAtStart(input));
define(ins, mir);
}
@@ -71,8 +70,10 @@ void LIRGeneratorLOONG64::lowerForALU(LInstructionHelper<1, 1, 0>* ins,
void LIRGeneratorLOONG64::lowerForALU(LInstructionHelper<1, 2, 0>* ins,
MDefinition* mir, MDefinition* lhs,
MDefinition* rhs) {
- ins->setOperand(0, useRegister(lhs));
- ins->setOperand(1, useRegisterOrConstant(rhs));
+ // Binary ALU operations don't read any input after writing to the output,
+ // even for fallible operations, so we can use at-start allocations.
+ ins->setOperand(0, useRegisterAtStart(lhs));
+ ins->setOperand(1, useRegisterOrConstantAtStart(rhs));
define(ins, mir);
}
@@ -80,39 +81,20 @@ void LIRGeneratorLOONG64::lowerForALUInt64(
LInstructionHelper<INT64_PIECES, INT64_PIECES, 0>* ins, MDefinition* mir,
MDefinition* input) {
ins->setInt64Operand(0, useInt64RegisterAtStart(input));
- defineInt64ReuseInput(ins, mir, 0);
+ defineInt64(ins, mir);
}
void LIRGeneratorLOONG64::lowerForALUInt64(
LInstructionHelper<INT64_PIECES, 2 * INT64_PIECES, 0>* ins,
MDefinition* mir, MDefinition* lhs, MDefinition* rhs) {
ins->setInt64Operand(0, useInt64RegisterAtStart(lhs));
- ins->setInt64Operand(INT64_PIECES,
- willHaveDifferentLIRNodes(lhs, rhs)
- ? useInt64RegisterOrConstant(rhs)
- : useInt64RegisterOrConstantAtStart(rhs));
- defineInt64ReuseInput(ins, mir, 0);
+ ins->setInt64Operand(INT64_PIECES, useInt64RegisterOrConstantAtStart(rhs));
+ defineInt64(ins, mir);
}
void LIRGeneratorLOONG64::lowerForMulInt64(LMulI64* ins, MMul* mir,
MDefinition* lhs, MDefinition* rhs) {
- bool needsTemp = false;
- bool cannotAliasRhs = false;
- bool reuseInput = true;
-
- ins->setLhs(useInt64RegisterAtStart(lhs));
- ins->setRhs((willHaveDifferentLIRNodes(lhs, rhs) || cannotAliasRhs)
- ? useInt64RegisterOrConstant(rhs)
- : useInt64RegisterOrConstantAtStart(rhs));
-
- if (needsTemp) {
- ins->setTemp0(temp());
- }
- if (reuseInput) {
- defineInt64ReuseInput(ins, mir, 0);
- } else {
- defineInt64(ins, mir);
- }
+ lowerForALUInt64(ins, mir, lhs, rhs);
}
void LIRGeneratorLOONG64::lowerForFPU(LInstructionHelper<1, 1, 0>* ins,
@@ -183,6 +165,15 @@ void LIRGeneratorLOONG64::lowerMulI(MMul* mul, MDefinition* lhs,
assignSnapshot(lir, mul->bailoutKind());
}
+ // Negative zero check reads |lhs| and |rhs| after writing to the output, so
+ // we can't use at-start allocations.
+ if (mul->canBeNegativeZero() && !rhs->isConstant()) {
+ lir->setOperand(0, useRegister(lhs));
+ lir->setOperand(1, useRegister(rhs));
+ define(lir, mul);
+ return;
+ }
+
lowerForALU(lir, mul, lhs, rhs);
}
@@ -326,8 +317,8 @@ void LIRGeneratorLOONG64::lowerUrshD(MUrsh* mir) {
MOZ_ASSERT(lhs->type() == MIRType::Int32);
MOZ_ASSERT(rhs->type() == MIRType::Int32);
- LUrshD* lir = new (alloc())
- LUrshD(useRegister(lhs), useRegisterOrConstant(rhs), temp());
+ auto* lir = new (alloc()) LUrshD(useRegisterAtStart(lhs),
+ useRegisterOrConstantAtStart(rhs), temp());
define(lir, mir);
}
diff --git a/js/src/jit/mips-shared/Lowering-mips-shared.cpp b/js/src/jit/mips-shared/Lowering-mips-shared.cpp
@@ -37,7 +37,9 @@ LDefinition LIRGeneratorMIPSShared::tempByteOpRegister() { return temp(); }
// x = !y
void LIRGeneratorMIPSShared::lowerForALU(LInstructionHelper<1, 1, 0>* ins,
MDefinition* mir, MDefinition* input) {
- ins->setOperand(0, useRegister(input));
+ // Unary ALU operations don't read the input after writing to the output, even
+ // for fallible operations, so we can use at-start allocations.
+ ins->setOperand(0, useRegisterAtStart(input));
define(ins, mir);
}
@@ -45,8 +47,10 @@ void LIRGeneratorMIPSShared::lowerForALU(LInstructionHelper<1, 1, 0>* ins,
void LIRGeneratorMIPSShared::lowerForALU(LInstructionHelper<1, 2, 0>* ins,
MDefinition* mir, MDefinition* lhs,
MDefinition* rhs) {
- ins->setOperand(0, useRegister(lhs));
- ins->setOperand(1, useRegisterOrConstant(rhs));
+ // Binary ALU operations don't read any input after writing to the output,
+ // even for fallible operations, so we can use at-start allocations.
+ ins->setOperand(0, useRegisterAtStart(lhs));
+ ins->setOperand(1, useRegisterOrConstantAtStart(rhs));
define(ins, mir);
}
@@ -54,40 +58,21 @@ void LIRGeneratorMIPSShared::lowerForALUInt64(
LInstructionHelper<INT64_PIECES, INT64_PIECES, 0>* ins, MDefinition* mir,
MDefinition* input) {
ins->setInt64Operand(0, useInt64RegisterAtStart(input));
- defineInt64ReuseInput(ins, mir, 0);
+ defineInt64(ins, mir);
}
void LIRGeneratorMIPSShared::lowerForALUInt64(
LInstructionHelper<INT64_PIECES, 2 * INT64_PIECES, 0>* ins,
MDefinition* mir, MDefinition* lhs, MDefinition* rhs) {
ins->setInt64Operand(0, useInt64RegisterAtStart(lhs));
- ins->setInt64Operand(INT64_PIECES,
- willHaveDifferentLIRNodes(lhs, rhs)
- ? useInt64RegisterOrConstant(rhs)
- : useInt64RegisterOrConstantAtStart(rhs));
- defineInt64ReuseInput(ins, mir, 0);
+ ins->setInt64Operand(INT64_PIECES, useInt64RegisterOrConstantAtStart(rhs));
+ defineInt64(ins, mir);
}
void LIRGeneratorMIPSShared::lowerForMulInt64(LMulI64* ins, MMul* mir,
MDefinition* lhs,
MDefinition* rhs) {
- bool needsTemp = false;
- bool cannotAliasRhs = false;
- bool reuseInput = true;
-
- ins->setLhs(useInt64RegisterAtStart(lhs));
- ins->setRhs((willHaveDifferentLIRNodes(lhs, rhs) || cannotAliasRhs)
- ? useInt64RegisterOrConstant(rhs)
- : useInt64RegisterOrConstantAtStart(rhs));
-
- if (needsTemp) {
- ins->setTemp0(temp());
- }
- if (reuseInput) {
- defineInt64ReuseInput(ins, mir, 0);
- } else {
- defineInt64(ins, mir);
- }
+ lowerForALUInt64(ins, mir, lhs, rhs);
}
template <class LInstr>
@@ -96,13 +81,12 @@ void LIRGeneratorMIPSShared::lowerForShiftInt64(LInstr* ins, MDefinition* mir,
MDefinition* rhs) {
if constexpr (std::is_same_v<LInstr, LShiftI64>) {
ins->setLhs(useInt64RegisterAtStart(lhs));
- ins->setRhs(useRegisterOrConstant(rhs));
- defineInt64ReuseInput(ins, mir, LShiftI64::LhsIndex);
+ ins->setRhs(useRegisterOrConstantAtStart(rhs));
} else {
ins->setInput(useInt64RegisterAtStart(lhs));
- ins->setCount(useRegisterOrConstant(rhs));
- defineInt64ReuseInput(ins, mir, LRotateI64::InputIndex);
+ ins->setCount(useRegisterOrConstantAtStart(rhs));
}
+ defineInt64(ins, mir);
}
template void LIRGeneratorMIPSShared::lowerForShiftInt64(LShiftI64* ins,
@@ -150,9 +134,7 @@ void LIRGeneratorMIPSShared::lowerWasmBuiltinTruncateToInt32(
void LIRGeneratorMIPSShared::lowerForShift(LInstructionHelper<1, 2, 0>* ins,
MDefinition* mir, MDefinition* lhs,
MDefinition* rhs) {
- ins->setOperand(0, useRegister(lhs));
- ins->setOperand(1, useRegisterOrConstant(rhs));
- define(ins, mir);
+ lowerForALU(ins, mir, lhs, rhs);
}
void LIRGeneratorMIPSShared::lowerDivI(MDiv* div) {
@@ -211,6 +193,15 @@ void LIRGeneratorMIPSShared::lowerMulI(MMul* mul, MDefinition* lhs,
assignSnapshot(lir, mul->bailoutKind());
}
+ // Negative zero check reads |lhs| and |rhs| after writing to the output, so
+ // we can't use at-start allocations.
+ if (mul->canBeNegativeZero() && !rhs->isConstant()) {
+ lir->setOperand(0, useRegister(lhs));
+ lir->setOperand(1, useRegister(rhs));
+ define(lir, mul);
+ return;
+ }
+
lowerForALU(lir, mul, lhs, rhs);
}
@@ -281,8 +272,8 @@ void LIRGeneratorMIPSShared::lowerUrshD(MUrsh* mir) {
MOZ_ASSERT(lhs->type() == MIRType::Int32);
MOZ_ASSERT(rhs->type() == MIRType::Int32);
- LUrshD* lir = new (alloc())
- LUrshD(useRegister(lhs), useRegisterOrConstant(rhs), temp());
+ auto* lir = new (alloc()) LUrshD(useRegisterAtStart(lhs),
+ useRegisterOrConstantAtStart(rhs), temp());
define(lir, mir);
}
diff --git a/js/src/jit/riscv64/Lowering-riscv64.cpp b/js/src/jit/riscv64/Lowering-riscv64.cpp
@@ -32,9 +32,7 @@ LTableSwitchV* LIRGeneratorRiscv64::newLTableSwitchV(const LBoxAllocation& in) {
void LIRGeneratorRiscv64::lowerForShift(LInstructionHelper<1, 2, 0>* ins,
MDefinition* mir, MDefinition* lhs,
MDefinition* rhs) {
- ins->setOperand(0, useRegister(lhs));
- ins->setOperand(1, useRegisterOrConstant(rhs));
- define(ins, mir);
+ lowerForALU(ins, mir, lhs, rhs);
}
template <class LInstr>
@@ -43,13 +41,12 @@ void LIRGeneratorRiscv64::lowerForShiftInt64(LInstr* ins, MDefinition* mir,
MDefinition* rhs) {
if constexpr (std::is_same_v<LInstr, LShiftI64>) {
ins->setLhs(useInt64RegisterAtStart(lhs));
- ins->setRhs(useRegisterOrConstant(rhs));
- defineInt64ReuseInput(ins, mir, LShiftI64::LhsIndex);
+ ins->setRhs(useRegisterOrConstantAtStart(rhs));
} else {
ins->setInput(useInt64RegisterAtStart(lhs));
- ins->setCount(useRegisterOrConstant(rhs));
- defineInt64ReuseInput(ins, mir, LRotateI64::InputIndex);
+ ins->setCount(useRegisterOrConstantAtStart(rhs));
}
+ defineInt64(ins, mir);
}
template void LIRGeneratorRiscv64::lowerForShiftInt64(LShiftI64* ins,
@@ -64,7 +61,9 @@ template void LIRGeneratorRiscv64::lowerForShiftInt64(LRotateI64* ins,
// x = !y
void LIRGeneratorRiscv64::lowerForALU(LInstructionHelper<1, 1, 0>* ins,
MDefinition* mir, MDefinition* input) {
- ins->setOperand(0, useRegister(input));
+ // Unary ALU operations don't read the input after writing to the output, even
+ // for fallible operations, so we can use at-start allocations.
+ ins->setOperand(0, useRegisterAtStart(input));
define(ins, mir);
}
@@ -72,8 +71,10 @@ void LIRGeneratorRiscv64::lowerForALU(LInstructionHelper<1, 1, 0>* ins,
void LIRGeneratorRiscv64::lowerForALU(LInstructionHelper<1, 2, 0>* ins,
MDefinition* mir, MDefinition* lhs,
MDefinition* rhs) {
- ins->setOperand(0, useRegister(lhs));
- ins->setOperand(1, useRegisterOrConstant(rhs));
+ // Binary ALU operations don't read any input after writing to the output,
+ // even for fallible operations, so we can use at-start allocations.
+ ins->setOperand(0, useRegisterAtStart(lhs));
+ ins->setOperand(1, useRegisterOrConstantAtStart(rhs));
define(ins, mir);
}
@@ -81,39 +82,20 @@ void LIRGeneratorRiscv64::lowerForALUInt64(
LInstructionHelper<INT64_PIECES, INT64_PIECES, 0>* ins, MDefinition* mir,
MDefinition* input) {
ins->setInt64Operand(0, useInt64RegisterAtStart(input));
- defineInt64ReuseInput(ins, mir, 0);
+ defineInt64(ins, mir);
}
void LIRGeneratorRiscv64::lowerForALUInt64(
LInstructionHelper<INT64_PIECES, 2 * INT64_PIECES, 0>* ins,
MDefinition* mir, MDefinition* lhs, MDefinition* rhs) {
ins->setInt64Operand(0, useInt64RegisterAtStart(lhs));
- ins->setInt64Operand(INT64_PIECES,
- willHaveDifferentLIRNodes(lhs, rhs)
- ? useInt64RegisterOrConstant(rhs)
- : useInt64RegisterOrConstantAtStart(rhs));
- defineInt64ReuseInput(ins, mir, 0);
+ ins->setInt64Operand(INT64_PIECES, useInt64RegisterOrConstantAtStart(rhs));
+ defineInt64(ins, mir);
}
void LIRGeneratorRiscv64::lowerForMulInt64(LMulI64* ins, MMul* mir,
MDefinition* lhs, MDefinition* rhs) {
- bool needsTemp = false;
- bool cannotAliasRhs = false;
- bool reuseInput = true;
-
- ins->setLhs(useInt64RegisterAtStart(lhs));
- ins->setRhs((willHaveDifferentLIRNodes(lhs, rhs) || cannotAliasRhs)
- ? useInt64RegisterOrConstant(rhs)
- : useInt64RegisterOrConstantAtStart(rhs));
-
- if (needsTemp) {
- ins->setTemp0(temp());
- }
- if (reuseInput) {
- defineInt64ReuseInput(ins, mir, 0);
- } else {
- defineInt64(ins, mir);
- }
+ lowerForALUInt64(ins, mir, lhs, rhs);
}
void LIRGeneratorRiscv64::lowerForFPU(LInstructionHelper<1, 1, 0>* ins,
@@ -183,6 +165,15 @@ void LIRGeneratorRiscv64::lowerMulI(MMul* mul, MDefinition* lhs,
assignSnapshot(lir, mul->bailoutKind());
}
+ // Negative zero check reads |lhs| and |rhs| after writing to the output, so
+ // we can't use at-start allocations.
+ if (mul->canBeNegativeZero() && !rhs->isConstant()) {
+ lir->setOperand(0, useRegister(lhs));
+ lir->setOperand(1, useRegister(rhs));
+ define(lir, mul);
+ return;
+ }
+
lowerForALU(lir, mul, lhs, rhs);
}
@@ -326,8 +317,8 @@ void LIRGeneratorRiscv64::lowerUrshD(MUrsh* mir) {
MOZ_ASSERT(lhs->type() == MIRType::Int32);
MOZ_ASSERT(rhs->type() == MIRType::Int32);
- LUrshD* lir = new (alloc())
- LUrshD(useRegister(lhs), useRegisterOrConstant(rhs), temp());
+ auto* lir = new (alloc()) LUrshD(useRegisterAtStart(lhs),
+ useRegisterOrConstantAtStart(rhs), temp());
define(lir, mir);
}