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 332392 65981e46881a04d3b36fd9fbd69cb79169d75e83
parent 332391 df8f35c1858453850c471339bf3e7687f30cf8b6
child 332393 d2e991415189568ea0f906e0912aa8d1de44694c
push id9858
push userjlund@mozilla.com
push dateMon, 01 Aug 2016 14:37:10 +0000
treeherdermozilla-aurora@203106ef6cb6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbbouvier
bugs1289054
milestone50.0a1
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)