Bug 1289054 - Part 9: Implement the 64bit variant of Shift on arm, r=bbouvier
authorHannes Verschore <hv1989@gmail.com>
Fri, 29 Jul 2016 16:53:49 +0200
changeset 347358 65981e46881a04d3b36fd9fbd69cb79169d75e83
parent 347357 df8f35c1858453850c471339bf3e7687f30cf8b6
child 347359 d2e991415189568ea0f906e0912aa8d1de44694c
push id6389
push userraliiev@mozilla.com
push dateMon, 19 Sep 2016 13:38:22 +0000
treeherdermozilla-beta@01d67bfe6c81 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbbouvier
bugs1289054
milestone50.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1289054 - Part 9: Implement the 64bit variant of Shift on arm, r=bbouvier
js/src/jit/MacroAssembler.h
js/src/jit/arm/CodeGenerator-arm.cpp
js/src/jit/arm/CodeGenerator-arm.h
js/src/jit/arm/Lowering-arm.cpp
js/src/jit/arm/MacroAssembler-arm-inl.h
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -863,26 +863,26 @@ class MacroAssembler : public MacroAssem
 
     inline void lshiftPtr(Imm32 imm, Register dest) PER_ARCH;
     inline void rshiftPtr(Imm32 imm, Register dest) PER_ARCH;
     inline void rshiftPtr(Imm32 imm, Register src, Register dest) DEFINED_ON(arm64);
     inline void rshiftPtrArithmetic(Imm32 imm, Register dest) PER_ARCH;
 
     inline void lshift64(Imm32 imm, Register64 dest) PER_ARCH;
     inline void rshift64(Imm32 imm, Register64 dest) PER_ARCH;
-    inline void rshift64Arithmetic(Imm32 imm, Register64 dest) DEFINED_ON(x86, x64);
+    inline void rshift64Arithmetic(Imm32 imm, Register64 dest) DEFINED_ON(x86, x64, arm);
 
     // On x86_shared these have the constraint that shift must be in CL.
     inline void lshift32(Register shift, Register srcDest) PER_SHARED_ARCH;
     inline void rshift32(Register shift, Register srcDest) PER_SHARED_ARCH;
     inline void rshift32Arithmetic(Register shift, Register srcDest) PER_SHARED_ARCH;
 
-    inline void lshift64(Register shift, Register64 srcDest) DEFINED_ON(x86, x64);
-    inline void rshift64(Register shift, Register64 srcDest) DEFINED_ON(x86, x64);
-    inline void rshift64Arithmetic(Register shift, Register64 srcDest) DEFINED_ON(x86, x64);
+    inline void lshift64(Register shift, Register64 srcDest) DEFINED_ON(x86, x64, arm);
+    inline void rshift64(Register shift, Register64 srcDest) DEFINED_ON(x86, x64, arm);
+    inline void rshift64Arithmetic(Register shift, Register64 srcDest) DEFINED_ON(x86, x64, arm);
 
     // ===============================================================
     // Rotation functions
     // Note: - on x86 and x64 the count register must be in CL.
     //       - on x64 the temp register should be InvalidReg.
 
     inline void rotateLeft(Imm32 count, Register input, Register dest) PER_SHARED_ARCH;
     inline void rotateLeft(Register count, Register input, Register dest) PER_SHARED_ARCH;
--- a/js/src/jit/arm/CodeGenerator-arm.cpp
+++ b/js/src/jit/arm/CodeGenerator-arm.cpp
@@ -3248,8 +3248,52 @@ CodeGeneratorARM::visitCompareI64AndBran
     if (IsConstant(rhs)) {
         Imm64 imm = Imm64(ToInt64(rhs));
         masm.branch64(condition, lhsRegs, imm, trueLabel, falseLabel);
     } else {
         Register64 rhsRegs = ToRegister64(rhs);
         masm.branch64(condition, lhsRegs, rhsRegs, trueLabel, falseLabel);
     }
 }
+
+void
+CodeGeneratorARM::visitShiftI64(LShiftI64* lir)
+{
+    const LInt64Allocation lhs = lir->getInt64Operand(LShiftI64::Lhs);
+    LAllocation* rhs = lir->getOperand(LShiftI64::Rhs);
+
+    MOZ_ASSERT(ToOutRegister64(lir) == ToRegister64(lhs));
+
+    if (rhs->isConstant()) {
+        int32_t shift = int32_t(rhs->toConstant()->toInt64() & 0x3F);
+        switch (lir->bitop()) {
+          case JSOP_LSH:
+            if (shift)
+                masm.lshift64(Imm32(shift), ToRegister64(lhs));
+            break;
+          case JSOP_RSH:
+            if (shift)
+                masm.rshift64Arithmetic(Imm32(shift), ToRegister64(lhs));
+            break;
+          case JSOP_URSH:
+            if (shift)
+                masm.rshift64(Imm32(shift), ToRegister64(lhs));
+            break;
+          default:
+            MOZ_CRASH("Unexpected shift op");
+        }
+        return;
+    }
+
+    switch (lir->bitop()) {
+      case JSOP_LSH:
+        masm.lshift64(ToRegister(rhs), ToRegister64(lhs));
+        break;
+      case JSOP_RSH:
+        masm.rshift64Arithmetic(ToRegister(rhs), ToRegister64(lhs));
+        break;
+      case JSOP_URSH:
+        masm.rshift64(ToRegister(rhs), ToRegister64(lhs));
+        break;
+      default:
+        MOZ_CRASH("Unexpected shift op");
+    }
+}
--- a/js/src/jit/arm/CodeGenerator-arm.h
+++ b/js/src/jit/arm/CodeGenerator-arm.h
@@ -115,16 +115,17 @@ class CodeGeneratorARM : public CodeGene
     virtual void visitSoftDivI(LSoftDivI* ins);
     virtual void visitDivPowTwoI(LDivPowTwoI* ins);
     virtual void visitModI(LModI* ins);
     virtual void visitSoftModI(LSoftModI* ins);
     virtual void visitModPowTwoI(LModPowTwoI* ins);
     virtual void visitModMaskI(LModMaskI* ins);
     virtual void visitPowHalfD(LPowHalfD* ins);
     virtual void visitShiftI(LShiftI* ins);
+    virtual void visitShiftI64(LShiftI64* ins);
     virtual void visitUrshD(LUrshD* ins);
 
     virtual void visitClzI(LClzI* ins);
     virtual void visitCtzI(LCtzI* ins);
     virtual void visitPopcntI(LPopcntI* ins);
 
     virtual void visitTestIAndBranch(LTestIAndBranch* test);
     virtual void visitCompare(LCompare* comp);
--- a/js/src/jit/arm/Lowering-arm.cpp
+++ b/js/src/jit/arm/Lowering-arm.cpp
@@ -291,17 +291,19 @@ LIRGeneratorARM::lowerForShift(LInstruct
     define(ins, mir);
 }
 
 template<size_t Temps>
 void
 LIRGeneratorARM::lowerForShiftInt64(LInstructionHelper<INT64_PIECES, INT64_PIECES + 1, Temps>* ins,
                                     MDefinition* mir, MDefinition* lhs, MDefinition* rhs)
 {
-    MOZ_CRASH("NYI");
+    ins->setInt64Operand(0, useInt64RegisterAtStart(lhs));
+    ins->setOperand(INT64_PIECES, useRegisterOrConstant(rhs));
+    defineInt64ReuseInput(ins, mir, 0);
 }
 
 template void LIRGeneratorARM::lowerForShiftInt64(
     LInstructionHelper<INT64_PIECES, INT64_PIECES+1, 0>* ins, MDefinition* mir,
     MDefinition* lhs, MDefinition* rhs);
 template void LIRGeneratorARM::lowerForShiftInt64(
     LInstructionHelper<INT64_PIECES, INT64_PIECES+1, 1>* ins, MDefinition* mir,
     MDefinition* lhs, MDefinition* rhs);
--- a/js/src/jit/arm/MacroAssembler-arm-inl.h
+++ b/js/src/jit/arm/MacroAssembler-arm-inl.h
@@ -582,19 +582,43 @@ MacroAssembler::lshiftPtr(Imm32 imm, Reg
     MOZ_ASSERT(0 <= imm.value && imm.value < 32);
     ma_lsl(imm, dest, dest);
 }
 
 void
 MacroAssembler::lshift64(Imm32 imm, Register64 dest)
 {
     MOZ_ASSERT(0 <= imm.value && imm.value < 64);
-    as_mov(dest.high, lsl(dest.high, imm.value));
-    as_orr(dest.high, dest.high, lsr(dest.low, 32 - imm.value));
-    as_mov(dest.low, lsl(dest.low, imm.value));
+    if (imm.value == 0) {
+        return;
+    } else if (imm.value < 32) {
+        as_mov(dest.high, lsl(dest.high, imm.value));
+        as_orr(dest.high, dest.high, lsr(dest.low, 32 - imm.value));
+        as_mov(dest.low, lsl(dest.low, imm.value));
+    } else {
+        as_mov(dest.high, lsl(dest.low, imm.value - 32));
+        ma_mov(Imm32(0), dest.low);
+    }
+}
+
+void
+MacroAssembler::lshift64(Register unmaskedShift, Register64 dest)
+{
+    // dest.high = dest.high << shift | dest.low << shift - 32 | dest.low >> 32 - shift
+    // Note: one of the two dest.low shift will always yield zero due to negative shift.
+
+    ScratchRegisterScope shift(*this);
+    ma_and(Imm32(0x3f), unmaskedShift, shift);
+    as_mov(dest.high, lsl(dest.high, shift));
+    ma_sub(shift, Imm32(32), shift);
+    as_orr(dest.high, dest.high, lsl(dest.low, shift));
+    ma_neg(shift, shift);
+    as_orr(dest.high, dest.high, lsr(dest.low, shift));
+    ma_and(Imm32(0x3f), unmaskedShift, shift);
+    as_mov(dest.low, lsl(dest.low, shift));
 }
 
 void
 MacroAssembler::lshift32(Register src, Register dest)
 {
     ma_lsl(src, dest, dest);
 }
 
@@ -628,35 +652,106 @@ MacroAssembler::rshift32(Imm32 imm, Regi
 void
 MacroAssembler::rshiftPtrArithmetic(Imm32 imm, Register dest)
 {
     MOZ_ASSERT(0 <= imm.value && imm.value < 32);
     ma_asr(imm, dest, dest);
 }
 
 void
+MacroAssembler::rshift64Arithmetic(Imm32 imm, Register64 dest)
+{
+    MOZ_ASSERT(0 <= imm.value && imm.value < 64);
+
+    if (imm.value < 32) {
+        as_mov(dest.low, lsr(dest.low, imm.value));
+        as_orr(dest.low, dest.low, lsl(dest.high, 32 - imm.value));
+        as_mov(dest.high, asr(dest.high, imm.value));
+    } else if (imm.value == 32) {
+        as_mov(dest.low, O2Reg(dest.high));
+        as_mov(dest.high, asr(dest.high, 31));
+    } else {
+        as_mov(dest.low, asr(dest.high, imm.value - 32));
+        as_mov(dest.high, asr(dest.high, 31));
+    }
+}
+
+void
+MacroAssembler::rshift64Arithmetic(Register unmaskedShift, Register64 dest)
+{
+    Label proceed;
+
+    // dest.low = dest.low >>> shift | dest.high <<< 32 - shift
+    // if (shift - 32 >= 0)
+    //   dest.low |= dest.high >>> shift - 32
+    // Note: Negative shifts yield a zero as result, except for the signed
+    //       right shift. Therefore we need to test for it and only do it if
+    //       it isn't negative.
+
+    ScratchRegisterScope shift(*this);
+    ma_and(Imm32(0x3f), unmaskedShift, shift);
+    as_mov(dest.low, lsr(dest.low, shift));
+    ma_rsb(shift, Imm32(32), shift);
+    as_orr(dest.low, dest.low, lsl(dest.high, shift));
+    ma_neg(shift, shift, SetCC);
+    ma_b(&proceed, Signed);
+
+    as_orr(dest.low, dest.low, asr(dest.high, shift));
+
+    bind(&proceed);
+    ma_and(Imm32(0x3f), unmaskedShift, shift);
+    as_mov(dest.high, asr(dest.high, shift));
+}
+
+void
 MacroAssembler::rshift32Arithmetic(Register src, Register dest)
 {
     ma_asr(src, dest, dest);
 }
 
 void
 MacroAssembler::rshift32Arithmetic(Imm32 imm, Register dest)
 {
     MOZ_ASSERT(0 <= imm.value && imm.value < 32);
     rshiftPtrArithmetic(imm, dest);
 }
 
 void
 MacroAssembler::rshift64(Imm32 imm, Register64 dest)
 {
     MOZ_ASSERT(0 <= imm.value && imm.value < 64);
-    as_mov(dest.low, lsr(dest.low, imm.value));
-    as_orr(dest.low, dest.low, lsl(dest.high, 32 - imm.value));
-    as_mov(dest.high, lsr(dest.high, imm.value));
+    MOZ_ASSERT(0 <= imm.value && imm.value < 64);
+    if (imm.value < 32) {
+        as_mov(dest.low, lsr(dest.low, imm.value));
+        as_orr(dest.low, dest.low, lsl(dest.high, 32 - imm.value));
+        as_mov(dest.high, lsr(dest.high, imm.value));
+    } else if (imm.value == 32) {
+        ma_mov(dest.high, dest.low);
+        ma_mov(Imm32(0), dest.high);
+    } else {
+        ma_lsr(Imm32(imm.value - 32), dest.high, dest.low);
+        ma_mov(Imm32(0), dest.high);
+    }
+}
+
+void
+MacroAssembler::rshift64(Register unmaskedShift, Register64 dest)
+{
+    // dest.low = dest.low >> shift | dest.high >> shift - 32 | dest.high << 32 - shift
+    // Note: one of the two dest.high shifts will always yield zero due to negative shift.
+
+    ScratchRegisterScope shift(*this);
+    ma_and(Imm32(0x3f), unmaskedShift, shift);
+    as_mov(dest.low, lsr(dest.low, shift));
+    ma_sub(shift, Imm32(32), shift);
+    as_orr(dest.low, dest.low, lsr(dest.high, shift));
+    ma_neg(shift, shift);
+    as_orr(dest.low, dest.low, lsl(dest.high, shift));
+    ma_and(Imm32(0x3f), unmaskedShift, shift);
+    as_mov(dest.high, lsr(dest.high, shift));
 }
 
 // ===============================================================
 // Rotate functions
 void
 MacroAssembler::rotateLeft(Imm32 count, Register input, Register dest)
 {
     if (count.value)