commit 897281b10610d7f70362971d8e1ddeb658e5ae9a
parent bbd8cdc9597195f9ee8361ae82a370879d61b3e9
Author: André Bargull <andre.bargull@gmail.com>
Date: Mon, 27 Oct 2025 15:22:13 +0000
Bug 1996346 - Part 1: Don't reuse input for shift instructions when BMI2 is available. r=spidermonkey-reviewers,iain
Improves codegen for:
```js
function f(x, y) {
return ((x << y) + x)|0;
}
```
From:
```asm
movl %eax, %ecx
shlxl %eax, %edx, %eax
addl %ecx, %eax
```
To:
```asm
shlxl %eax, %ecx, %ecx
addl %eax, %ecx
```
Differential Revision: https://phabricator.services.mozilla.com/D270025
Diffstat:
4 files changed, 152 insertions(+), 57 deletions(-)
diff --git a/js/src/jit/x64/CodeGenerator-x64.cpp b/js/src/jit/x64/CodeGenerator-x64.cpp
@@ -305,6 +305,66 @@ void CodeGeneratorX64::emitBigIntPtrMod(LBigIntPtrMod* ins, Register dividend,
masm.idivq(divisor);
}
+void CodeGenerator::visitShiftIntPtr(LShiftIntPtr* ins) {
+ Register lhs = ToRegister(ins->lhs());
+ const LAllocation* rhs = ins->rhs();
+ Register out = ToRegister(ins->output());
+
+ if (rhs->isConstant()) {
+ MOZ_ASSERT(out == lhs);
+
+ int32_t shift = ToIntPtr(rhs) & 0x3f;
+ switch (ins->bitop()) {
+ case JSOp::Lsh:
+ if (shift) {
+ masm.lshiftPtr(Imm32(shift), lhs);
+ }
+ break;
+ case JSOp::Rsh:
+ if (shift) {
+ masm.rshiftPtrArithmetic(Imm32(shift), lhs);
+ }
+ break;
+ case JSOp::Ursh:
+ if (shift) {
+ masm.rshiftPtr(Imm32(shift), lhs);
+ }
+ break;
+ default:
+ MOZ_CRASH("Unexpected shift op");
+ }
+ } else {
+ Register shift = ToRegister(rhs);
+ MOZ_ASSERT_IF(out != lhs, Assembler::HasBMI2());
+
+ switch (ins->bitop()) {
+ case JSOp::Lsh:
+ if (out != lhs) {
+ masm.shlxq(lhs, shift, out);
+ } else {
+ masm.lshiftPtr(shift, lhs);
+ }
+ break;
+ case JSOp::Rsh:
+ if (out != lhs) {
+ masm.sarxq(lhs, shift, out);
+ } else {
+ masm.rshiftPtrArithmetic(shift, lhs);
+ }
+ break;
+ case JSOp::Ursh:
+ if (out != lhs) {
+ masm.shrxq(lhs, shift, out);
+ } else {
+ masm.rshiftPtr(shift, lhs);
+ }
+ break;
+ default:
+ MOZ_CRASH("Unexpected shift op");
+ }
+ }
+}
+
void CodeGenerator::visitAtomicLoad64(LAtomicLoad64* lir) {
Register elements = ToRegister(lir->elements());
Register64 out = ToOutRegister64(lir);
diff --git a/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp b/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp
@@ -1528,10 +1528,11 @@ void CodeGenerator::visitBitOpI64(LBitOpI64* lir) {
void CodeGenerator::visitShiftI(LShiftI* ins) {
Register lhs = ToRegister(ins->lhs());
const LAllocation* rhs = ins->rhs();
-
- MOZ_ASSERT(ToRegister(ins->output()) == lhs);
+ Register out = ToRegister(ins->output());
if (rhs->isConstant()) {
+ MOZ_ASSERT(out == lhs);
+
int32_t shift = ToInt32(rhs) & 0x1F;
switch (ins->bitop()) {
case JSOp::Lsh:
@@ -1558,66 +1559,34 @@ void CodeGenerator::visitShiftI(LShiftI* ins) {
}
} else {
Register shift = ToRegister(rhs);
- switch (ins->bitop()) {
- case JSOp::Lsh:
- masm.lshift32(shift, lhs);
- break;
- case JSOp::Rsh:
- masm.rshift32Arithmetic(shift, lhs);
- break;
- case JSOp::Ursh:
- masm.rshift32(shift, lhs);
- if (ins->mir()->toUrsh()->fallible()) {
- // x >>> 0 can overflow.
- masm.test32(lhs, lhs);
- bailoutIf(Assembler::Signed, ins->snapshot());
- }
- break;
- default:
- MOZ_CRASH("Unexpected shift op");
- }
- }
-}
+ MOZ_ASSERT_IF(out != lhs, Assembler::HasBMI2());
-void CodeGenerator::visitShiftIntPtr(LShiftIntPtr* ins) {
- Register lhs = ToRegister(ins->lhs());
- const LAllocation* rhs = ins->rhs();
-
- MOZ_ASSERT(ToRegister(ins->output()) == lhs);
-
- if (rhs->isConstant()) {
- constexpr intptr_t mask = (sizeof(intptr_t) * CHAR_BIT) - 1;
- int32_t shift = ToIntPtr(rhs) & mask;
switch (ins->bitop()) {
case JSOp::Lsh:
- if (shift) {
- masm.lshiftPtr(Imm32(shift), lhs);
+ if (out != lhs) {
+ masm.shlxl(lhs, shift, out);
+ } else {
+ masm.lshift32(shift, lhs);
}
break;
case JSOp::Rsh:
- if (shift) {
- masm.rshiftPtrArithmetic(Imm32(shift), lhs);
+ if (out != lhs) {
+ masm.sarxl(lhs, shift, out);
+ } else {
+ masm.rshift32Arithmetic(shift, lhs);
}
break;
case JSOp::Ursh:
- if (shift) {
- masm.rshiftPtr(Imm32(shift), lhs);
+ if (out != lhs) {
+ masm.shrxl(lhs, shift, out);
+ } else {
+ masm.rshift32(shift, lhs);
+ }
+ if (ins->mir()->toUrsh()->fallible()) {
+ // x >>> 0 can overflow.
+ masm.test32(out, out);
+ bailoutIf(Assembler::Signed, ins->snapshot());
}
- break;
- default:
- MOZ_CRASH("Unexpected shift op");
- }
- } else {
- Register shift = ToRegister(rhs);
- switch (ins->bitop()) {
- case JSOp::Lsh:
- masm.lshiftPtr(shift, lhs);
- break;
- case JSOp::Rsh:
- masm.rshiftPtrArithmetic(shift, lhs);
- break;
- case JSOp::Ursh:
- masm.rshiftPtr(shift, lhs);
break;
default:
MOZ_CRASH("Unexpected shift op");
diff --git a/js/src/jit/x86-shared/Lowering-x86-shared.cpp b/js/src/jit/x86-shared/Lowering-x86-shared.cpp
@@ -68,17 +68,23 @@ void LIRGeneratorX86Shared::lowerForShift(LInstructionHelper<1, 2, 0>* ins,
if (rhs->isConstant()) {
ins->setOperand(1, useOrConstantAtStart(rhs));
+ defineReuseInput(ins, mir, 0);
} else if (!mir->isRotate()) {
- ins->setOperand(1, willHaveDifferentLIRNodes(lhs, rhs)
- ? useShiftRegister(rhs)
- : useShiftRegisterAtStart(rhs));
+ if (Assembler::HasBMI2()) {
+ ins->setOperand(1, useRegisterAtStart(rhs));
+ define(ins, mir);
+ } else {
+ ins->setOperand(1, willHaveDifferentLIRNodes(lhs, rhs)
+ ? useShiftRegister(rhs)
+ : useShiftRegisterAtStart(rhs));
+ defineReuseInput(ins, mir, 0);
+ }
} else {
ins->setOperand(1, willHaveDifferentLIRNodes(lhs, rhs)
? useFixed(rhs, ecx)
: useFixedAtStart(rhs, ecx));
+ defineReuseInput(ins, mir, 0);
}
-
- defineReuseInput(ins, mir, 0);
}
template <class LInstr>
diff --git a/js/src/jit/x86/CodeGenerator-x86.cpp b/js/src/jit/x86/CodeGenerator-x86.cpp
@@ -996,6 +996,66 @@ void CodeGeneratorX86::emitBigIntPtrMod(LBigIntPtrMod* ins, Register dividend,
masm.idiv(divisor);
}
+void CodeGenerator::visitShiftIntPtr(LShiftIntPtr* ins) {
+ Register lhs = ToRegister(ins->lhs());
+ const LAllocation* rhs = ins->rhs();
+ Register out = ToRegister(ins->output());
+
+ if (rhs->isConstant()) {
+ MOZ_ASSERT(out == lhs);
+
+ int32_t shift = ToIntPtr(rhs) & 0x1F;
+ switch (ins->bitop()) {
+ case JSOp::Lsh:
+ if (shift) {
+ masm.lshiftPtr(Imm32(shift), lhs);
+ }
+ break;
+ case JSOp::Rsh:
+ if (shift) {
+ masm.rshiftPtrArithmetic(Imm32(shift), lhs);
+ }
+ break;
+ case JSOp::Ursh:
+ if (shift) {
+ masm.rshiftPtr(Imm32(shift), lhs);
+ }
+ break;
+ default:
+ MOZ_CRASH("Unexpected shift op");
+ }
+ } else {
+ Register shift = ToRegister(rhs);
+ MOZ_ASSERT_IF(out != lhs, Assembler::HasBMI2());
+
+ switch (ins->bitop()) {
+ case JSOp::Lsh:
+ if (out != lhs) {
+ masm.shlxl(lhs, shift, out);
+ } else {
+ masm.lshiftPtr(shift, lhs);
+ }
+ break;
+ case JSOp::Rsh:
+ if (out != lhs) {
+ masm.sarxl(lhs, shift, out);
+ } else {
+ masm.rshiftPtrArithmetic(shift, lhs);
+ }
+ break;
+ case JSOp::Ursh:
+ if (out != lhs) {
+ masm.shrxl(lhs, shift, out);
+ } else {
+ masm.rshiftPtr(shift, lhs);
+ }
+ break;
+ default:
+ MOZ_CRASH("Unexpected shift op");
+ }
+ }
+}
+
void CodeGenerator::visitWasmSelectI64(LWasmSelectI64* lir) {
MOZ_ASSERT(lir->mir()->type() == MIRType::Int64);