Bug 1522276 - IonMonkey ARM64: Add generic UDiv implementation. r=sstangl
authorNicolas B. Pierron <nicolas.b.pierron@nbp.name>
Thu, 31 Jan 2019 10:47:54 +0000
changeset 517103 6785ac75ef2642643090a6279c52c6c2f710f1d3
parent 517102 6a22ba01cdfbe4dbc4b0cee28d008b2bc7f53958
child 517104 646991effcda3bdc5e9d06a442c69b310ec494fe
push id2032
push userffxbld-merge
push dateMon, 13 May 2019 09:36:57 +0000
treeherdermozilla-release@455c1065dcbe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssstangl
bugs1522276
milestone67.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 1522276 - IonMonkey ARM64: Add generic UDiv implementation. r=sstangl Differential Revision: https://phabricator.services.mozilla.com/D17929
js/src/jit/arm64/CodeGenerator-arm64.cpp
js/src/jit/arm64/LIR-arm64.h
js/src/jit/arm64/Lowering-arm64.cpp
--- a/js/src/jit/arm64/CodeGenerator-arm64.cpp
+++ b/js/src/jit/arm64/CodeGenerator-arm64.cpp
@@ -1569,17 +1569,62 @@ void CodeGenerator::visitWasmCompareExch
 void CodeGenerator::visitWasmAtomicBinopHeap(LWasmAtomicBinopHeap* ins) {
   MOZ_CRASH("visitWasmAtomicBinopHeap");
 }
 
 void CodeGenerator::visitWasmStackArg(LWasmStackArg* ins) {
   MOZ_CRASH("visitWasmStackArg");
 }
 
-void CodeGenerator::visitUDiv(LUDiv* ins) { MOZ_CRASH("visitUDiv"); }
+void CodeGenerator::visitUDiv(LUDiv* ins) {
+  MDiv* mir = ins->mir();
+  Register lhs = ToRegister(ins->lhs());
+  Register rhs = ToRegister(ins->rhs());
+  Register output = ToRegister(ins->output());
+  ARMRegister lhs32 = ARMRegister(lhs, 32);
+  ARMRegister rhs32 = ARMRegister(rhs, 32);
+  ARMRegister output32 = ARMRegister(output, 32);
+
+  // Prevent divide by zero.
+  if (mir->canBeDivideByZero()) {
+    if (mir->isTruncated()) {
+      if (mir->trapOnError()) {
+        Label nonZero;
+        masm.branchTest32(Assembler::NonZero, rhs, rhs, &nonZero);
+        masm.wasmTrap(wasm::Trap::IntegerDivideByZero, mir->bytecodeOffset());
+        masm.bind(&nonZero);
+      } else {
+        // ARM64 UDIV instruction will return 0 when divided by 0.
+        // No need for extra tests.
+      }
+    } else {
+      bailoutTest32(Assembler::Zero, rhs, rhs, ins->snapshot());
+    }
+  }
+
+  // Unsigned division.
+  masm.Udiv(output32, lhs32, rhs32);
+
+  // If the remainder is > 0, bailout since this must be a double.
+  if (!mir->canTruncateRemainder()) {
+    Register remainder = ToRegister(ins->remainder());
+    ARMRegister remainder32 = ARMRegister(remainder, 32);
+
+    // Compute the remainder: remainder = lhs - (output * rhs).
+    masm.Msub(remainder32, output32, rhs32, lhs32);
+
+    bailoutTest32(Assembler::NonZero, remainder, remainder, ins->snapshot());
+  }
+
+  // Unsigned div can return a value that's not a signed int32.
+  // If our users aren't expecting that, bail.
+  if (!mir->isTruncated()) {
+    bailoutTest32(Assembler::Signed, output, output, ins->snapshot());
+  }
+}
 
 void CodeGenerator::visitUMod(LUMod* ins) {
   MMod* mir = ins->mir();
   ARMRegister lhs = toWRegister(ins->lhs());
   ARMRegister rhs = toWRegister(ins->rhs());
   ARMRegister output = toWRegister(ins->output());
   Label done;
 
--- a/js/src/jit/arm64/LIR-arm64.h
+++ b/js/src/jit/arm64/LIR-arm64.h
@@ -200,20 +200,29 @@ class LMulI : public LBinaryMath<0> {
  public:
   LIR_HEADER(MulI);
 
   LMulI() : LBinaryMath(classOpcode) {}
 
   MMul* mir() { return mir_->toMul(); }
 };
 
-class LUDiv : public LBinaryMath<0> {
+class LUDiv : public LBinaryMath<1> {
  public:
   LIR_HEADER(UDiv);
 
+  LUDiv(const LAllocation& lhs, const LAllocation& rhs, const LDefinition& remainder)
+    : LBinaryMath(classOpcode) {
+    setOperand(0, lhs);
+    setOperand(1, rhs);
+    setTemp(0, remainder);
+  }
+
+  const LDefinition* remainder() { return getTemp(0); }
+
   MDiv* mir() { return mir_->toDiv(); }
 };
 
 class LUMod : public LBinaryMath<0> {
  public:
   LIR_HEADER(UMod);
 
   LUMod(const LAllocation& lhs, const LAllocation& rhs)
--- a/js/src/jit/arm64/Lowering-arm64.cpp
+++ b/js/src/jit/arm64/Lowering-arm64.cpp
@@ -198,17 +198,18 @@ void LIRGeneratorARM64::lowerForShift(LI
 }
 
 void LIRGeneratorARM64::lowerDivI(MDiv* div) {
   if (div->isUnsigned()) {
     lowerUDiv(div);
     return;
   }
 
-  // TODO: Implement the division-avoidance paths when rhs is constant.
+  // TODO (Bug 1523568): Implement the division-avoidance paths when rhs is
+  // constant.
 
   LDivI* lir = new (alloc())
       LDivI(useRegister(div->lhs()), useRegister(div->rhs()), temp());
   if (div->fallible()) {
     assignSnapshot(lir, Bailout_DoubleOutput);
   }
   define(lir, div);
 }
@@ -306,17 +307,34 @@ void LIRGenerator::visitWasmNeg(MWasmNeg
       MOZ_CRASH("unexpected type");
   }
 }
 
 void LIRGenerator::visitWasmSelect(MWasmSelect* ins) {
   MOZ_CRASH("visitWasmSelect");
 }
 
-void LIRGeneratorARM64::lowerUDiv(MDiv* div) { MOZ_CRASH("lowerUDiv"); }
+void LIRGeneratorARM64::lowerUDiv(MDiv* div) {
+  LAllocation lhs = useRegister(div->lhs());
+  // TODO (Bug 1523568): Implement the division-avoidance paths when rhs is
+  // constant.
+
+  // Generate UDiv
+  LAllocation rhs = useRegister(div->rhs());
+  LDefinition remainder = LDefinition::BogusTemp();
+  if (!div->canTruncateRemainder()) {
+    remainder = temp();
+  }
+
+  LUDiv* lir = new (alloc()) LUDiv(lhs, rhs, remainder);
+  if (div->fallible()) {
+    assignSnapshot(lir, Bailout_DoubleOutput);
+  }
+  define(lir, div);
+}
 
 void LIRGeneratorARM64::lowerUMod(MMod* mod) {
   LUMod* lir = new (alloc())
       LUMod(useRegister(mod->getOperand(0)), useRegister(mod->getOperand(1)));
   if (mod->fallible()) {
     assignSnapshot(lir, Bailout_DoubleOutput);
   }
   define(lir, mod);