Bug 1289054 - Part 11: Implement the 64bit variant of Rotate on arm, r=luke
authorHannes Verschore <hv1989@gmail.com>
Fri, 29 Jul 2016 16:53:49 +0200
changeset 349430 9ae4ad38a4b390c75efddb3a4f718c997248b5e8
parent 349429 d2e991415189568ea0f906e0912aa8d1de44694c
child 349431 6e959f39e82f004c602a550c691c37552398d2db
push id1230
push userjlund@mozilla.com
push dateMon, 31 Oct 2016 18:13:35 +0000
treeherdermozilla-release@5e06e3766db2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke
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 11: Implement the 64bit variant of Rotate on arm, r=luke
js/src/jit-test/tests/wasm/basic-integer.js
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-test/tests/wasm/basic-integer.js
+++ b/js/src/jit-test/tests/wasm/basic-integer.js
@@ -123,16 +123,18 @@ testTrap32('div_s', 0x80000000 | 0, -1, 
 testTrap32('div_u', 42, 0, /integer divide by zero/);
 testTrap32('rem_s', 42, 0, /integer divide by zero/);
 testTrap32('rem_u', 42, 0, /integer divide by zero/);
 
 testBinary32('rotl', 40, 2, 160);
 testBinary32('rotl', 40, 34, 160);
 testBinary32('rotr', 40, 2, 10);
 testBinary32('rotr', 40, 34, 10);
+testBinary32('rotr', 40, 0, 40);
+testBinary32('rotl', 40, 0, 40);
 
 testComparison32('eq', 40, 40, 1);
 testComparison32('ne', 40, 40, 0);
 testComparison32('lt_s', 40, 40, 0);
 testComparison32('lt_u', 40, 40, 0);
 testComparison32('le_s', 40, 40, 1);
 testComparison32('le_u', 40, 40, 1);
 testComparison32('gt_s', 40, 40, 0);
@@ -197,16 +199,22 @@ if (hasI64()) {
     testBinary64('shr_u', -40, 2, "0x3ffffffffffffff6");
     testBinary64('shl', 0xff00ff, 28, "0xff00ff0000000");
     testBinary64('shl', 1, 63, "0x8000000000000000");
     testBinary64('shl', 1, 64, 1);
     testBinary64('shr_s', "0xff00ff0000000", 28, 0xff00ff);
     testBinary64('shr_u', "0x8ffff00ff0000000", 56, 0x8f);
     testBinary64('rotl', 40, 2, 160);
     testBinary64('rotr', 40, 2, 10);
+    testBinary64('rotr', "0x1234567812345678", 4, "0x8123456781234567");
+    testBinary64('rotl', "0x1234567812345678", 4, "0x2345678123456781");
+    testBinary64('rotl', "0x1234567812345678", 60, "0x8123456781234567");
+    testBinary64('rotr', "0x1234567812345678", 60, "0x2345678123456781");
+    testBinary64('rotr', 40, 0, 40);
+    testBinary64('rotl', 40, 0, 40);
     testBinary64('and', 42, 0, 0);
     testBinary64('and', "0x0000000012345678", "0xffff0000ffff0000", "0x0000000012340000");
 
     testComparison64('eq', 40, 40, 1);
     testComparison64('ne', 40, 40, 0);
     testComparison64('lt_s', 40, 40, 0);
     testComparison64('lt_u', 40, 40, 0);
     testComparison64('le_s', 40, 40, 1);
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -884,28 +884,28 @@ class MacroAssembler : public MacroAssem
     // 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;
     inline void rotateLeft64(Imm32 count, Register64 input, Register64 dest) DEFINED_ON(x64);
     inline void rotateLeft64(Register count, Register64 input, Register64 dest) DEFINED_ON(x64);
     inline void rotateLeft64(Imm32 count, Register64 input, Register64 dest, Register temp)
-        DEFINED_ON(x86, x64);
+        DEFINED_ON(x86, x64, arm);
     inline void rotateLeft64(Register count, Register64 input, Register64 dest, Register temp)
-        DEFINED_ON(x86, x64);
+        DEFINED_ON(x86, x64, arm);
 
     inline void rotateRight(Imm32 count, Register input, Register dest) PER_SHARED_ARCH;
     inline void rotateRight(Register count, Register input, Register dest) PER_SHARED_ARCH;
     inline void rotateRight64(Imm32 count, Register64 input, Register64 dest) DEFINED_ON(x64);
     inline void rotateRight64(Register count, Register64 input, Register64 dest) DEFINED_ON(x64);
     inline void rotateRight64(Imm32 count, Register64 input, Register64 dest, Register temp)
-        DEFINED_ON(x86, x64);
+        DEFINED_ON(x86, x64, arm);
     inline void rotateRight64(Register count, Register64 input, Register64 dest, Register temp)
-        DEFINED_ON(x86, x64);
+        DEFINED_ON(x86, x64, arm);
 
     // ===============================================================
     // Bit counting functions
 
     // knownNotZero may be true only if the src is known not to be zero.
     inline void clz32(Register src, Register dest, bool knownNotZero) PER_SHARED_ARCH;
     inline void ctz32(Register src, Register dest, bool knownNotZero) PER_SHARED_ARCH;
 
--- a/js/src/jit/arm/CodeGenerator-arm.cpp
+++ b/js/src/jit/arm/CodeGenerator-arm.cpp
@@ -3324,8 +3324,36 @@ CodeGeneratorARM::visitBitOpI64(LBitOpI6
             masm.and64(Imm64(ToInt64(rhs)), ToRegister64(lhs));
         else
             masm.and64(ToOperandOrRegister64(rhs), ToRegister64(lhs));
         break;
       default:
         MOZ_CRASH("unexpected binary opcode");
     }
 }
+
+void
+CodeGeneratorARM::visitRotateI64(LRotateI64* lir)
+{
+    MRotate* mir = lir->mir();
+    LAllocation* count = lir->count();
+
+    Register64 input = ToRegister64(lir->input());
+    Register64 output = ToOutRegister64(lir);
+    Register temp = ToTempRegisterOrInvalid(lir->temp());
+
+    if (count->isConstant()) {
+        int32_t c = int32_t(count->toConstant()->toInt64() & 0x3F);
+        if (!c) {
+            masm.move64(input, output);
+            return;
+        }
+        if (mir->isLeftRotate())
+            masm.rotateLeft64(Imm32(c), input, output, temp);
+        else
+            masm.rotateRight64(Imm32(c), input, output, temp);
+    } else {
+        if (mir->isLeftRotate())
+            masm.rotateLeft64(ToRegister(count), input, output, temp);
+        else
+            masm.rotateRight64(ToRegister(count), input, output, temp);
+    }
+}
--- a/js/src/jit/arm/CodeGenerator-arm.h
+++ b/js/src/jit/arm/CodeGenerator-arm.h
@@ -163,16 +163,17 @@ class CodeGeneratorARM : public CodeGene
     virtual void visitAddI64(LAddI64* lir);
     virtual void visitSubI64(LSubI64* lir);
     virtual void visitMulI64(LMulI64* lir);
     virtual void visitDivOrModI64(LDivOrModI64* lir);
     virtual void visitUDivOrModI64(LUDivOrModI64* lir);
     virtual void visitCompareI64(LCompareI64* lir);
     virtual void visitCompareI64AndBranch(LCompareI64AndBranch* lir);
     virtual void visitBitOpI64(LBitOpI64* lir);
+    virtual void visitRotateI64(LRotateI64* lir);
 
     // Out of line visitors.
     void visitOutOfLineBailout(OutOfLineBailout* ool);
     void visitOutOfLineTableSwitch(OutOfLineTableSwitch* ool);
 
   protected:
     ValueOperand ToValue(LInstruction* ins, size_t pos);
     ValueOperand ToOutValue(LInstruction* ins);
--- a/js/src/jit/arm/Lowering-arm.cpp
+++ b/js/src/jit/arm/Lowering-arm.cpp
@@ -291,16 +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)
 {
+    if (mir->isRotate() && !rhs->isConstant())
+        ins->setTemp(0, temp());
+
     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);
--- a/js/src/jit/arm/MacroAssembler-arm-inl.h
+++ b/js/src/jit/arm/MacroAssembler-arm-inl.h
@@ -775,30 +775,182 @@ MacroAssembler::rotateLeft(Imm32 count, 
 
 void
 MacroAssembler::rotateLeft(Register count, Register input, Register dest)
 {
     ma_rol(count, input, dest);
 }
 
 void
+MacroAssembler::rotateLeft64(Imm32 count, Register64 input, Register64 dest, Register temp)
+{
+    MOZ_ASSERT(temp == InvalidReg);
+    MOZ_ASSERT(input.low != dest.high && input.high != dest.low);
+
+    int32_t amount = count.value & 0x3f;
+    if (amount > 32) {
+        rotateRight64(Imm32(64 - amount), input, dest, temp);
+    } else {
+        ScratchRegisterScope scratch(*this);
+        if (amount == 0) {
+            ma_mov(input.low, dest.low);
+            ma_mov(input.high, dest.high);
+        } else if (amount == 32) {
+            ma_mov(input.low, scratch);
+            ma_mov(input.high, dest.low);
+            ma_mov(scratch, dest.high);
+        } else {
+            MOZ_ASSERT(0 < amount && amount < 32);
+            ma_mov(dest.high, scratch);
+            as_mov(dest.high, lsl(dest.high, amount));
+            as_orr(dest.high, dest.high, lsr(dest.low, 32 - amount));
+            as_mov(dest.low, lsl(dest.low, amount));
+            as_orr(dest.low, dest.low, lsr(scratch, 32 - amount));
+        }
+    }
+}
+
+void
+MacroAssembler::rotateLeft64(Register shift, Register64 src, Register64 dest, Register temp)
+{
+    MOZ_ASSERT(shift != temp);
+    MOZ_ASSERT(src == dest);
+    MOZ_ASSERT(temp != src.low && temp != src.high);
+    MOZ_ASSERT(shift != src.low && shift != src.high);
+    MOZ_ASSERT(temp != InvalidReg);
+
+    ScratchRegisterScope shift_value(*this);
+    Label high, done;
+
+    ma_mov(src.high, temp);
+    ma_and(Imm32(0x3f), shift, shift_value);
+
+    ma_cmp(shift_value, Imm32(32));
+    ma_b(&high, GreaterThanOrEqual);
+
+    // high = high << shift | low >> 32 - shift
+    // low = low << shift | high >> 32 - shift
+    as_mov(dest.high, lsl(src.high, shift_value));
+    ma_rsb(Imm32(32), shift_value);
+    as_orr(dest.high, dest.high, lsr(src.low, shift_value));
+
+    ma_rsb(Imm32(32), shift_value);
+    as_mov(dest.low, lsl(src.low, shift_value));
+    ma_rsb(Imm32(32), shift_value);
+    as_orr(dest.low, dest.low, lsr(temp, shift_value));
+
+    ma_b(&done);
+
+    // A 32 - 64 shift is a 0 - 32 shift in the other direction.
+    bind(&high);
+    ma_rsb(Imm32(64), shift_value);
+
+    as_mov(dest.high, lsr(src.high, shift_value));
+    ma_rsb(Imm32(32), shift_value);
+    as_orr(dest.high, dest.high, lsl(src.low, shift_value));
+
+    ma_rsb(Imm32(32), shift_value);
+    as_mov(dest.low, lsr(src.low, shift_value));
+    ma_rsb(Imm32(32), shift_value);
+    as_orr(dest.low, dest.low, lsl(temp, shift_value));
+
+    bind(&done);
+}
+
+void
 MacroAssembler::rotateRight(Imm32 count, Register input, Register dest)
 {
     if (count.value)
         ma_ror(count, input, dest);
     else
         ma_mov(input, dest);
 }
 
 void
 MacroAssembler::rotateRight(Register count, Register input, Register dest)
 {
     ma_ror(count, input, dest);
 }
 
+void
+MacroAssembler::rotateRight64(Imm32 count, Register64 input, Register64 dest, Register temp)
+{
+    MOZ_ASSERT(temp == InvalidReg);
+    MOZ_ASSERT(input.low != dest.high && input.high != dest.low);
+
+    int32_t amount = count.value & 0x3f;
+    if (amount > 32) {
+        rotateLeft64(Imm32(64 - amount), input, dest, temp);
+    } else {
+        ScratchRegisterScope scratch(*this);
+        if (amount == 0) {
+            ma_mov(input.low, dest.low);
+            ma_mov(input.high, dest.high);
+        } else if (amount == 32) {
+            ma_mov(input.low, scratch);
+            ma_mov(input.high, dest.low);
+            ma_mov(scratch, dest.high);
+        } else {
+            MOZ_ASSERT(0 < amount && amount < 32);
+            ma_mov(dest.high, scratch);
+            as_mov(dest.high, lsr(dest.high, amount));
+            as_orr(dest.high, dest.high, lsl(dest.low, 32 - amount));
+            as_mov(dest.low, lsr(dest.low, amount));
+            as_orr(dest.low, dest.low, lsl(scratch, 32 - amount));
+        }
+    }
+}
+
+void
+MacroAssembler::rotateRight64(Register shift, Register64 src, Register64 dest, Register temp)
+{
+    MOZ_ASSERT(shift != temp);
+    MOZ_ASSERT(src == dest);
+    MOZ_ASSERT(temp != src.low && temp != src.high);
+    MOZ_ASSERT(shift != src.low && shift != src.high);
+    MOZ_ASSERT(temp != InvalidReg);
+
+    ScratchRegisterScope shift_value(*this);
+    Label high, done;
+
+    ma_mov(src.high, temp);
+    ma_and(Imm32(0x3f), shift, shift_value);
+
+    ma_cmp(shift_value, Imm32(32));
+    ma_b(&high, GreaterThanOrEqual);
+
+    // high = high >> shift | low << 32 - shift
+    // low = low >> shift | high << 32 - shift
+    as_mov(dest.high, lsr(src.high, shift_value));
+    ma_rsb(Imm32(32), shift_value);
+    as_orr(dest.high, dest.high, lsl(src.low, shift_value));
+
+    ma_rsb(Imm32(32), shift_value);
+    as_mov(dest.low, lsr(src.low, shift_value));
+    ma_rsb(Imm32(32), shift_value);
+    as_orr(dest.low, dest.low, lsl(temp, shift_value));
+
+    ma_b(&done);
+
+    // A 32 - 64 shift is a 0 - 32 shift in the other direction.
+    bind(&high);
+    ma_rsb(Imm32(64), shift_value);
+
+    as_mov(dest.high, lsl(src.high, shift_value));
+    ma_rsb(Imm32(32), shift_value);
+    as_orr(dest.high, dest.high, lsr(src.low, shift_value));
+
+    ma_rsb(Imm32(32), shift_value);
+    as_mov(dest.low, lsl(src.low, shift_value));
+    ma_rsb(Imm32(32), shift_value);
+    as_orr(dest.low, dest.low, lsr(temp, shift_value));
+
+    bind(&done);
+}
+
 // ===============================================================
 // Bit counting functions
 
 void
 MacroAssembler::clz32(Register src, Register dest, bool knownNotZero)
 {
     ma_clz(src, dest);
 }