Bug 1313336 - ARM64 integer masm instructions. r=jolesen
authorLars T Hansen <lhansen@mozilla.com>
Tue, 16 Jan 2018 14:00:36 +0100
changeset 405328 a37627e154f3c3d599ce439b18ff2a7a5d4c6f94
parent 405327 0d3462c103e91b79c79a58564582a866d4f5cbd6
child 405329 48452a36fc1413862de66af9dc40a61926eecde6
push id33518
push usertoros@mozilla.com
push dateMon, 26 Feb 2018 22:20:13 +0000
treeherdermozilla-central@580d833df9c4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjolesen
bugs1313336
milestone60.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 1313336 - ARM64 integer masm instructions. r=jolesen
js/src/jit/arm64/MacroAssembler-arm64-inl.h
--- a/js/src/jit/arm64/MacroAssembler-arm64-inl.h
+++ b/js/src/jit/arm64/MacroAssembler-arm64-inl.h
@@ -159,17 +159,17 @@ MacroAssembler::and64(Imm64 imm, Registe
     const Register scratch = temps.AcquireX().asUnsized();
     mov(ImmWord(imm.value), scratch);
     andPtr(scratch, dest.reg);
 }
 
 void
 MacroAssembler::and64(Register64 src, Register64 dest)
 {
-    MOZ_CRASH("NYI: and64");
+    And(ARMRegister(dest.reg, 64), ARMRegister(dest.reg, 64), ARMRegister(src.reg, 64));
 }
 
 void
 MacroAssembler::or64(Imm64 imm, Register64 dest)
 {
     vixl::UseScratchRegisterScope temps(this);
     const Register scratch = temps.AcquireX().asUnsized();
     mov(ImmWord(imm.value), scratch);
@@ -433,23 +433,23 @@ MacroAssembler::subPtr(const Address& ad
 
     Ldr(scratch64, toMemOperand(addr));
     Sub(ARMRegister(dest, 64), ARMRegister(dest, 64), Operand(scratch64));
 }
 
 void
 MacroAssembler::sub64(Register64 src, Register64 dest)
 {
-    MOZ_CRASH("NYI: sub64");
+    Sub(ARMRegister(dest.reg, 64), ARMRegister(dest.reg, 64), ARMRegister(src.reg, 64));
 }
 
 void
 MacroAssembler::sub64(Imm64 imm, Register64 dest)
 {
-    MOZ_CRASH("NYI: sub64");
+    Sub(ARMRegister(dest.reg, 64), ARMRegister(dest.reg, 64), Operand(imm.value));
 }
 
 void
 MacroAssembler::subDouble(FloatRegister src, FloatRegister dest)
 {
     fsub(ARMFPRegister(dest, 64), ARMFPRegister(dest, 64), ARMFPRegister(src, 64));
 }
 
@@ -457,17 +457,17 @@ void
 MacroAssembler::subFloat32(FloatRegister src, FloatRegister dest)
 {
     fsub(ARMFPRegister(dest, 32), ARMFPRegister(dest, 32), ARMFPRegister(src, 32));
 }
 
 void
 MacroAssembler::mul32(Register rhs, Register srcDest)
 {
-    MOZ_CRASH("NYI - mul32");
+    mul32(srcDest, rhs, srcDest, nullptr, nullptr);
 }
 
 void
 MacroAssembler::mul32(Register src1, Register src2, Register dest, Label* onOver, Label* onZero)
 {
     Smull(ARMRegister(dest, 64), ARMRegister(src1, 32), ARMRegister(src2, 32));
     if (onOver) {
         Cmp(ARMRegister(dest, 64), Operand(ARMRegister(dest, 32), vixl::SXTW));
@@ -488,17 +488,18 @@ MacroAssembler::mul64(Imm64 imm, const R
     MOZ_ASSERT(dest.reg != scratch64.asUnsized());
     mov(ImmWord(imm.value), scratch64.asUnsized());
     Mul(ARMRegister(dest.reg, 64), ARMRegister(dest.reg, 64), scratch64);
 }
 
 void
 MacroAssembler::mul64(const Register64& src, const Register64& dest, const Register temp)
 {
-    MOZ_CRASH("NYI: mul64");
+    MOZ_ASSERT(temp == Register::Invalid());
+    Mul(ARMRegister(dest.reg, 64), ARMRegister(dest.reg, 64), ARMRegister(src.reg, 64));
 }
 
 void
 MacroAssembler::mulBy3(Register src, Register dest)
 {
     ARMRegister xdest(dest, 64);
     ARMRegister xsrc(src, 64);
     Add(xdest, xsrc, Operand(xsrc, vixl::LSL, 1));
@@ -526,23 +527,36 @@ MacroAssembler::mulDoublePtr(ImmPtr imm,
     const ARMFPRegister scratchDouble = temps.AcquireD();
     Ldr(scratchDouble, MemOperand(Address(scratch, 0)));
     fmul(ARMFPRegister(dest, 64), ARMFPRegister(dest, 64), scratchDouble);
 }
 
 void
 MacroAssembler::quotient32(Register rhs, Register srcDest, bool isUnsigned)
 {
-    MOZ_CRASH("NYI - quotient32");
+    if (isUnsigned)
+        Udiv(ARMRegister(srcDest, 32), ARMRegister(srcDest, 32), ARMRegister(rhs, 32));
+    else
+        Sdiv(ARMRegister(srcDest, 32), ARMRegister(srcDest, 32), ARMRegister(rhs, 32));
 }
 
+// This does not deal with x % 0 or INT_MIN % -1, the caller needs to filter
+// those cases when they may occur.
+
 void
 MacroAssembler::remainder32(Register rhs, Register srcDest, bool isUnsigned)
 {
-    MOZ_CRASH("NYI - remainder32");
+    vixl::UseScratchRegisterScope temps(this);
+    ARMRegister scratch = temps.AcquireW();
+    if (isUnsigned)
+        Udiv(scratch, ARMRegister(srcDest, 32), ARMRegister(rhs, 32));
+    else
+        Sdiv(scratch, ARMRegister(srcDest, 32), ARMRegister(rhs, 32));
+    Mul(scratch, scratch, ARMRegister(rhs, 32));
+    Sub(ARMRegister(srcDest, 32), ARMRegister(srcDest, 32), scratch);
 }
 
 void
 MacroAssembler::divFloat32(FloatRegister src, FloatRegister dest)
 {
     fdiv(ARMFPRegister(dest, 32), ARMFPRegister(dest, 32), ARMFPRegister(src, 32));
 }
 
@@ -646,17 +660,17 @@ MacroAssembler::lshift64(Imm32 imm, Regi
 {
     MOZ_ASSERT(0 <= imm.value && imm.value < 64);
     lshiftPtr(imm, dest.reg);
 }
 
 void
 MacroAssembler::lshift64(Register shift, Register64 srcDest)
 {
-    MOZ_CRASH("NYI: lshift64");
+    Lsl(ARMRegister(srcDest.reg, 64), ARMRegister(srcDest.reg, 64), ARMRegister(shift, 64));
 }
 
 void
 MacroAssembler::lshift32(Register shift, Register dest)
 {
     Lsl(ARMRegister(dest, 32), ARMRegister(dest, 32), ARMRegister(shift, 32));
 }
 
@@ -719,29 +733,29 @@ MacroAssembler::rshift64(Imm32 imm, Regi
 {
     MOZ_ASSERT(0 <= imm.value && imm.value < 64);
     rshiftPtr(imm, dest.reg);
 }
 
 void
 MacroAssembler::rshift64(Register shift, Register64 srcDest)
 {
-    MOZ_CRASH("NYI: rshift64");
+    Lsr(ARMRegister(srcDest.reg, 64), ARMRegister(srcDest.reg, 64), ARMRegister(shift, 64));
 }
 
 void
 MacroAssembler::rshift64Arithmetic(Imm32 imm, Register64 dest)
 {
-    MOZ_CRASH("NYI: rshift64Arithmetic");
+    Asr(ARMRegister(dest.reg, 64), ARMRegister(dest.reg, 64), imm.value);
 }
 
 void
 MacroAssembler::rshift64Arithmetic(Register shift, Register64 srcDest)
 {
-    MOZ_CRASH("NYI: rshift64Arithmetic");
+    Asr(ARMRegister(srcDest.reg, 64), ARMRegister(srcDest.reg, 64), ARMRegister(shift, 64));
 }
 
 // ===============================================================
 // Condition functions
 
 template <typename T1, typename T2>
 void
 MacroAssembler::cmp32Set(Condition cond, T1 lhs, T2 rhs, Register dest)
@@ -759,98 +773,161 @@ MacroAssembler::cmpPtrSet(Condition cond
 }
 
 // ===============================================================
 // Rotation functions
 
 void
 MacroAssembler::rotateLeft(Imm32 count, Register input, Register dest)
 {
-    MOZ_CRASH("NYI: rotateLeft by immediate");
+    Ror(ARMRegister(dest, 32), ARMRegister(input, 32), (32 - count.value) & 31);
 }
 
 void
 MacroAssembler::rotateLeft(Register count, Register input, Register dest)
 {
-    MOZ_CRASH("NYI: rotateLeft by register");
+    vixl::UseScratchRegisterScope temps(this);
+    const ARMRegister scratch = temps.AcquireW();
+    // Really 32 - count, but the upper bits of the result are ignored.
+    Neg(scratch, ARMRegister(count, 32));
+    Ror(ARMRegister(dest, 32), ARMRegister(input, 32), scratch);
 }
 
 void
 MacroAssembler::rotateRight(Imm32 count, Register input, Register dest)
 {
-    MOZ_CRASH("NYI: rotateRight by immediate");
+    Ror(ARMRegister(dest, 32), ARMRegister(input, 32), count.value & 31);
 }
 
 void
 MacroAssembler::rotateRight(Register count, Register input, Register dest)
 {
-    MOZ_CRASH("NYI: rotateRight by register");
+    Ror(ARMRegister(dest, 32), ARMRegister(input, 32), ARMRegister(count, 32));
 }
 
 void
 MacroAssembler::rotateLeft64(Register count, Register64 input, Register64 dest, Register temp)
 {
-    MOZ_CRASH("NYI: rotateLeft64");
+    MOZ_ASSERT(temp == Register::Invalid());
+
+    vixl::UseScratchRegisterScope temps(this);
+    const ARMRegister scratch = temps.AcquireX();
+    // Really 64 - count, but the upper bits of the result are ignored.
+    Neg(scratch, ARMRegister(count, 64));
+    Ror(ARMRegister(dest.reg, 64), ARMRegister(input.reg, 64), scratch);
 }
 
 void
 MacroAssembler::rotateLeft64(Imm32 count, Register64 input, Register64 dest, Register temp)
 {
-    MOZ_CRASH("NYI: rotateLeft64");
+    MOZ_ASSERT(temp == Register::Invalid());
+
+    Ror(ARMRegister(dest.reg, 64), ARMRegister(input.reg, 64), (64 - count.value) & 63);
 }
 
 void
 MacroAssembler::rotateRight64(Register count, Register64 input, Register64 dest, Register temp)
 {
-    MOZ_CRASH("NYI: rotateRight64");
+    MOZ_ASSERT(temp == Register::Invalid());
+
+    Ror(ARMRegister(dest.reg, 64), ARMRegister(input.reg, 64), ARMRegister(count, 64));
 }
 
 void
 MacroAssembler::rotateRight64(Imm32 count, Register64 input, Register64 dest, Register temp)
 {
-    MOZ_CRASH("NYI: rotateRight64");
+    MOZ_ASSERT(temp == Register::Invalid());
+
+    Ror(ARMRegister(dest.reg, 64), ARMRegister(input.reg, 64), count.value & 63);
 }
 
 // ===============================================================
 // Bit counting functions
 
 void
 MacroAssembler::clz32(Register src, Register dest, bool knownNotZero)
 {
-    MOZ_CRASH("NYI: clz32");
+    Clz(ARMRegister(dest, 32), ARMRegister(src, 32));
 }
 
 void
 MacroAssembler::ctz32(Register src, Register dest, bool knownNotZero)
 {
-    MOZ_CRASH("NYI: ctz32");
+    Rbit(ARMRegister(dest, 32), ARMRegister(src, 32));
+    Clz(ARMRegister(dest, 32), ARMRegister(dest, 32));
 }
 
 void
 MacroAssembler::clz64(Register64 src, Register dest)
 {
-    MOZ_CRASH("NYI: clz64");
+    Clz(ARMRegister(dest, 64), ARMRegister(src.reg, 64));
 }
 
 void
 MacroAssembler::ctz64(Register64 src, Register dest)
 {
-    MOZ_CRASH("NYI: ctz64");
+    Rbit(ARMRegister(dest, 64), ARMRegister(src.reg, 64));
+    Clz(ARMRegister(dest, 64), ARMRegister(dest, 64));
 }
 
 void
-MacroAssembler::popcnt32(Register src, Register dest, Register temp)
+MacroAssembler::popcnt32(Register src_, Register dest_, Register tmp_)
 {
-    MOZ_CRASH("NYI: popcnt32");
+    MOZ_ASSERT(tmp_ != Register::Invalid());
+
+    // Equivalent to mozilla::CountPopulation32().
+
+    ARMRegister src(src_, 32);
+    ARMRegister dest(dest_, 32);
+    ARMRegister tmp(tmp_, 32);
+
+    Mov(tmp, src);
+    if (src_ != dest_)
+        Mov(dest, src);
+    Lsr(dest, dest, 1);
+    And(dest, dest, 0x55555555);
+    Sub(dest, tmp, dest);
+    Lsr(tmp, dest, 2);
+    And(tmp, tmp, 0x33333333);
+    And(dest, dest, 0x33333333);
+    Add(dest, tmp, dest);
+    Add(dest, dest, Operand(dest, vixl::LSR, 4));
+    And(dest, dest, 0x0F0F0F0F);
+    Add(dest, dest, Operand(dest, vixl::LSL, 8));
+    Add(dest, dest, Operand(dest, vixl::LSL, 16));
+    Lsr(dest, dest, 24);
 }
 
 void
-MacroAssembler::popcnt64(Register64 src, Register64 dest, Register temp)
+MacroAssembler::popcnt64(Register64 src_, Register64 dest_, Register tmp_)
 {
-    MOZ_CRASH("NYI: popcnt64");
+    MOZ_ASSERT(tmp_ != Register::Invalid());
+
+    // Equivalent to mozilla::CountPopulation64(), though likely more efficient.
+
+    ARMRegister src(src_.reg, 64);
+    ARMRegister dest(dest_.reg, 64);
+    ARMRegister tmp(tmp_, 64);
+
+    Mov(tmp, src);
+    if (src_ != dest_)
+        Mov(dest, src);
+    Lsr(dest, dest, 1);
+    And(dest, dest, 0x5555555555555555);
+    Sub(dest, tmp, dest);
+    Lsr(tmp, dest, 2);
+    And(tmp, tmp, 0x3333333333333333);
+    And(dest, dest, 0x3333333333333333);
+    Add(dest, tmp, dest);
+    Add(dest, dest, Operand(dest, vixl::LSR, 4));
+    And(dest, dest, 0x0F0F0F0F0F0F0F0F);
+    Add(dest, dest, Operand(dest, vixl::LSL, 8));
+    Add(dest, dest, Operand(dest, vixl::LSL, 16));
+    Add(dest, dest, Operand(dest, vixl::LSL, 32));
+    Lsr(dest, dest, 56);
 }
 
 // ===============================================================
 // Branch functions
 
 template <class L>
 void
 MacroAssembler::branch32(Condition cond, Register lhs, Register rhs, L label)