Reland "MIPS64: Fix lithium arithmetic operations for integers to sign-extend result."
authordusan.milosavljevic <dusan.milosavljevic@imgtec.com>
Wed, 17 Jun 2015 10:58:48 +0000 (03:58 -0700)
committerCommit bot <commit-bot@chromium.org>
Wed, 17 Jun 2015 10:58:53 +0000 (10:58 +0000)
TEST==mjsunit/asm/double-lo
BUG=

Review URL: https://codereview.chromium.org/1170923004

Cr-Commit-Position: refs/heads/master@{#29078}

src/mips64/full-codegen-mips64.cc
src/mips64/lithium-codegen-mips64.cc
src/mips64/lithium-mips64.cc
src/mips64/lithium-mips64.h
src/mips64/macro-assembler-mips64.cc
src/mips64/macro-assembler-mips64.h

index e608013..39abc3f 100644 (file)
@@ -2487,11 +2487,11 @@ void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
       break;
     }
     case Token::ADD:
-      __ AdduAndCheckForOverflow(v0, left, right, scratch1);
+      __ DadduAndCheckForOverflow(v0, left, right, scratch1);
       __ BranchOnOverflow(&stub_call, scratch1);
       break;
     case Token::SUB:
-      __ SubuAndCheckForOverflow(v0, left, right, scratch1);
+      __ DsubuAndCheckForOverflow(v0, left, right, scratch1);
       __ BranchOnOverflow(&stub_call, scratch1);
       break;
     case Token::MUL: {
@@ -4506,7 +4506,7 @@ void FullCodeGenerator::EmitFastOneByteArrayJoin(CallRuntime* expr) {
   __ lbu(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
   __ JumpIfInstanceTypeIsNotSequentialOneByte(scratch1, scratch2, &bailout);
   __ ld(scratch1, FieldMemOperand(string, SeqOneByteString::kLengthOffset));
-  __ AdduAndCheckForOverflow(string_length, string_length, scratch1, scratch3);
+  __ DadduAndCheckForOverflow(string_length, string_length, scratch1, scratch3);
   __ BranchOnOverflow(&bailout, scratch3);
   __ Branch(&loop, lt, element, Operand(elements_end));
 
@@ -5022,7 +5022,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
     Register scratch1 = a1;
     Register scratch2 = a4;
     __ li(scratch1, Operand(Smi::FromInt(count_value)));
-    __ AdduAndCheckForOverflow(v0, v0, scratch1, scratch2);
+    __ DadduAndCheckForOverflow(v0, v0, scratch1, scratch2);
     __ BranchOnNoOverflow(&done, scratch2);
     // Call stub. Undo operation first.
     __ Move(v0, a0);
index 90c4450..0082a3f 100644 (file)
@@ -1419,7 +1419,7 @@ void LCodeGen::DoFlooringDivI(LFlooringDivI* instr) {
 }
 
 
-void LCodeGen::DoMulI(LMulI* instr) {
+void LCodeGen::DoMulS(LMulS* instr) {
   Register scratch = scratch0();
   Register result = ToRegister(instr->result());
   // Note that result may alias left.
@@ -1442,9 +1442,9 @@ void LCodeGen::DoMulI(LMulI* instr) {
     switch (constant) {
       case -1:
         if (overflow) {
-          __ SubuAndCheckForOverflow(result, zero_reg, left, scratch);
-          DeoptimizeIf(gt, instr, Deoptimizer::kOverflow, scratch,
-                       Operand(kMaxInt));
+          __ DsubuAndCheckForOverflow(result, zero_reg, left, scratch);
+          DeoptimizeIf(lt, instr, Deoptimizer::kOverflow, scratch,
+                       Operand(zero_reg));
         } else {
           __ Dsubu(result, zero_reg, left);
         }
@@ -1479,19 +1479,121 @@ void LCodeGen::DoMulI(LMulI* instr) {
           __ dsll(scratch, left, shift);
           __ Daddu(result, scratch, left);
           // Correct the sign of the result if the constant is negative.
-          if (constant < 0)  __ Dsubu(result, zero_reg, result);
+          if (constant < 0) __ Dsubu(result, zero_reg, result);
         } else if (base::bits::IsPowerOfTwo32(constant_abs + 1)) {
           int32_t shift = WhichPowerOf2(constant_abs + 1);
           __ dsll(scratch, left, shift);
           __ Dsubu(result, scratch, left);
           // Correct the sign of the result if the constant is negative.
-          if (constant < 0)  __ Dsubu(result, zero_reg, result);
+          if (constant < 0) __ Dsubu(result, zero_reg, result);
         } else {
           // Generate standard code.
           __ li(at, constant);
           __ Dmul(result, left, at);
         }
     }
+  } else {
+    DCHECK(right_op->IsRegister());
+    Register right = ToRegister(right_op);
+
+    if (overflow) {
+      // hi:lo = left * right.
+      __ Dmulh(result, left, right);
+      __ dsra32(scratch, result, 0);
+      __ sra(at, result, 31);
+      __ SmiTag(result);
+      DeoptimizeIf(ne, instr, Deoptimizer::kOverflow, scratch, Operand(at));
+    } else {
+      __ SmiUntag(result, left);
+      __ dmul(result, result, right);
+    }
+
+    if (bailout_on_minus_zero) {
+      Label done;
+      __ Xor(at, left, right);
+      __ Branch(&done, ge, at, Operand(zero_reg));
+      // Bail out if the result is minus zero.
+      DeoptimizeIf(eq, instr, Deoptimizer::kMinusZero, result,
+                   Operand(zero_reg));
+      __ bind(&done);
+    }
+  }
+}
+
+
+void LCodeGen::DoMulI(LMulI* instr) {
+  Register scratch = scratch0();
+  Register result = ToRegister(instr->result());
+  // Note that result may alias left.
+  Register left = ToRegister(instr->left());
+  LOperand* right_op = instr->right();
+
+  bool bailout_on_minus_zero =
+      instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero);
+  bool overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
+
+  if (right_op->IsConstantOperand()) {
+    int32_t constant = ToInteger32(LConstantOperand::cast(right_op));
+
+    if (bailout_on_minus_zero && (constant < 0)) {
+      // The case of a null constant will be handled separately.
+      // If constant is negative and left is null, the result should be -0.
+      DeoptimizeIf(eq, instr, Deoptimizer::kMinusZero, left, Operand(zero_reg));
+    }
+
+    switch (constant) {
+      case -1:
+        if (overflow) {
+          __ SubuAndCheckForOverflow(result, zero_reg, left, scratch);
+          DeoptimizeIf(lt, instr, Deoptimizer::kOverflow, scratch,
+                       Operand(zero_reg));
+        } else {
+          __ Subu(result, zero_reg, left);
+        }
+        break;
+      case 0:
+        if (bailout_on_minus_zero) {
+          // If left is strictly negative and the constant is null, the
+          // result is -0. Deoptimize if required, otherwise return 0.
+          DeoptimizeIf(lt, instr, Deoptimizer::kMinusZero, left,
+                       Operand(zero_reg));
+        }
+        __ mov(result, zero_reg);
+        break;
+      case 1:
+        // Nothing to do.
+        __ Move(result, left);
+        break;
+      default:
+        // Multiplying by powers of two and powers of two plus or minus
+        // one can be done faster with shifted operands.
+        // For other constants we emit standard code.
+        int32_t mask = constant >> 31;
+        uint32_t constant_abs = (constant + mask) ^ mask;
+
+        if (base::bits::IsPowerOfTwo32(constant_abs)) {
+          int32_t shift = WhichPowerOf2(constant_abs);
+          __ sll(result, left, shift);
+          // Correct the sign of the result if the constant is negative.
+          if (constant < 0) __ Subu(result, zero_reg, result);
+        } else if (base::bits::IsPowerOfTwo32(constant_abs - 1)) {
+          int32_t shift = WhichPowerOf2(constant_abs - 1);
+          __ sll(scratch, left, shift);
+          __ addu(result, scratch, left);
+          // Correct the sign of the result if the constant is negative.
+          if (constant < 0) __ Subu(result, zero_reg, result);
+        } else if (base::bits::IsPowerOfTwo32(constant_abs + 1)) {
+          int32_t shift = WhichPowerOf2(constant_abs + 1);
+          __ sll(scratch, left, shift);
+          __ Subu(result, scratch, left);
+          // Correct the sign of the result if the constant is negative.
+          if (constant < 0) __ Subu(result, zero_reg, result);
+        } else {
+          // Generate standard code.
+          __ li(at, constant);
+          __ Mul(result, left, at);
+        }
+    }
 
   } else {
     DCHECK(right_op->IsRegister());
@@ -1499,24 +1601,13 @@ void LCodeGen::DoMulI(LMulI* instr) {
 
     if (overflow) {
       // hi:lo = left * right.
-      if (instr->hydrogen()->representation().IsSmi()) {
-        __ Dmulh(result, left, right);
-      } else {
-        __ Dmul(result, left, right);
-      }
+      __ Dmul(result, left, right);
       __ dsra32(scratch, result, 0);
       __ sra(at, result, 31);
-      if (instr->hydrogen()->representation().IsSmi()) {
-        __ SmiTag(result);
-      }
+
       DeoptimizeIf(ne, instr, Deoptimizer::kOverflow, scratch, Operand(at));
     } else {
-      if (instr->hydrogen()->representation().IsSmi()) {
-        __ SmiUntag(result, left);
-        __ Dmul(result, result, right);
-      } else {
-        __ Dmul(result, left, right);
-      }
+      __ mul(result, left, right);
     }
 
     if (bailout_on_minus_zero) {
@@ -1652,6 +1743,27 @@ void LCodeGen::DoShiftI(LShiftI* instr) {
 }
 
 
+void LCodeGen::DoSubS(LSubS* instr) {
+  LOperand* left = instr->left();
+  LOperand* right = instr->right();
+  LOperand* result = instr->result();
+  bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
+
+  if (!can_overflow) {
+    DCHECK(right->IsRegister() || right->IsConstantOperand());
+    __ Dsubu(ToRegister(result), ToRegister(left), ToOperand(right));
+  } else {  // can_overflow.
+    Register overflow = scratch0();
+    Register scratch = scratch1();
+    DCHECK(right->IsRegister() || right->IsConstantOperand());
+    __ DsubuAndCheckForOverflow(ToRegister(result), ToRegister(left),
+                                ToOperand(right), overflow, scratch);
+    DeoptimizeIf(lt, instr, Deoptimizer::kOverflow, overflow,
+                 Operand(zero_reg));
+  }
+}
+
+
 void LCodeGen::DoSubI(LSubI* instr) {
   LOperand* left = instr->left();
   LOperand* right = instr->right();
@@ -1659,39 +1771,16 @@ void LCodeGen::DoSubI(LSubI* instr) {
   bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
 
   if (!can_overflow) {
-    if (right->IsStackSlot()) {
-      Register right_reg = EmitLoadRegister(right, at);
-      __ Dsubu(ToRegister(result), ToRegister(left), Operand(right_reg));
-    } else {
-      DCHECK(right->IsRegister() || right->IsConstantOperand());
-      __ Dsubu(ToRegister(result), ToRegister(left), ToOperand(right));
-    }
+    DCHECK(right->IsRegister() || right->IsConstantOperand());
+    __ Subu(ToRegister(result), ToRegister(left), ToOperand(right));
   } else {  // can_overflow.
     Register overflow = scratch0();
     Register scratch = scratch1();
-    if (right->IsStackSlot() || right->IsConstantOperand()) {
-      Register right_reg = EmitLoadRegister(right, scratch);
-      __ SubuAndCheckForOverflow(ToRegister(result),
-                                 ToRegister(left),
-                                 right_reg,
-                                 overflow);  // Reg at also used as scratch.
-    } else {
-      DCHECK(right->IsRegister());
-      // Due to overflow check macros not supporting constant operands,
-      // handling the IsConstantOperand case was moved to prev if clause.
-      __ SubuAndCheckForOverflow(ToRegister(result),
-                                 ToRegister(left),
-                                 ToRegister(right),
-                                 overflow);  // Reg at also used as scratch.
-    }
+    DCHECK(right->IsRegister() || right->IsConstantOperand());
+    __ SubuAndCheckForOverflow(ToRegister(result), ToRegister(left),
+                               ToOperand(right), overflow, scratch);
     DeoptimizeIf(lt, instr, Deoptimizer::kOverflow, overflow,
                  Operand(zero_reg));
-    if (!instr->hydrogen()->representation().IsSmi()) {
-      DeoptimizeIf(gt, instr, Deoptimizer::kOverflow, ToRegister(result),
-                   Operand(kMaxInt));
-      DeoptimizeIf(lt, instr, Deoptimizer::kOverflow, ToRegister(result),
-                   Operand(kMinInt));
-    }
   }
 }
 
@@ -1855,7 +1944,7 @@ void LCodeGen::DoAddE(LAddE* instr) {
 }
 
 
-void LCodeGen::DoAddI(LAddI* instr) {
+void LCodeGen::DoAddS(LAddS* instr) {
   LOperand* left = instr->left();
   LOperand* right = instr->right();
   LOperand* result = instr->result();
@@ -1867,30 +1956,32 @@ void LCodeGen::DoAddI(LAddI* instr) {
   } else {  // can_overflow.
     Register overflow = scratch0();
     Register scratch = scratch1();
-    if (right->IsConstantOperand()) {
-      Register right_reg = EmitLoadRegister(right, scratch);
-      __ AdduAndCheckForOverflow(ToRegister(result),
-                                 ToRegister(left),
-                                 right_reg,
-                                 overflow);  // Reg at also used as scratch.
-    } else {
-      DCHECK(right->IsRegister());
-      // Due to overflow check macros not supporting constant operands,
-      // handling the IsConstantOperand case was moved to prev if clause.
-      __ AdduAndCheckForOverflow(ToRegister(result),
-                                 ToRegister(left),
-                                 ToRegister(right),
-                                 overflow);  // Reg at also used as scratch.
-    }
+    DCHECK(right->IsRegister() || right->IsConstantOperand());
+    __ DadduAndCheckForOverflow(ToRegister(result), ToRegister(left),
+                                ToOperand(right), overflow, scratch);
+    DeoptimizeIf(lt, instr, Deoptimizer::kOverflow, overflow,
+                 Operand(zero_reg));
+  }
+}
+
+
+void LCodeGen::DoAddI(LAddI* instr) {
+  LOperand* left = instr->left();
+  LOperand* right = instr->right();
+  LOperand* result = instr->result();
+  bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
+
+  if (!can_overflow) {
+    DCHECK(right->IsRegister() || right->IsConstantOperand());
+    __ Addu(ToRegister(result), ToRegister(left), ToOperand(right));
+  } else {  // can_overflow.
+    Register overflow = scratch0();
+    Register scratch = scratch1();
+    DCHECK(right->IsRegister() || right->IsConstantOperand());
+    __ AdduAndCheckForOverflow(ToRegister(result), ToRegister(left),
+                               ToOperand(right), overflow, scratch);
     DeoptimizeIf(lt, instr, Deoptimizer::kOverflow, overflow,
                  Operand(zero_reg));
-    // if not smi, it must int32.
-    if (!instr->hydrogen()->representation().IsSmi()) {
-      DeoptimizeIf(gt, instr, Deoptimizer::kOverflow, ToRegister(result),
-                   Operand(kMaxInt));
-      DeoptimizeIf(lt, instr, Deoptimizer::kOverflow, ToRegister(result),
-                   Operand(kMinInt));
-    }
   }
 }
 
index cf96058..6cf6674 100644 (file)
@@ -1527,14 +1527,17 @@ LInstruction* LChunkBuilder::DoMul(HMul* instr) {
       }
       right_op = UseRegister(right);
     }
-    LMulI* mul = new(zone()) LMulI(left_op, right_op);
+    LInstruction* result =
+        instr->representation().IsSmi()
+            ? DefineAsRegister(new (zone()) LMulS(left_op, right_op))
+            : DefineAsRegister(new (zone()) LMulI(left_op, right_op));
     if (right_op->IsConstantOperand()
             ? ((can_overflow && constant_value == -1) ||
                (bailout_on_minus_zero && constant_value <= 0))
             : (can_overflow || bailout_on_minus_zero)) {
-      AssignEnvironment(mul);
+      AssignEnvironment(result);
     }
-    return DefineAsRegister(mul);
+    return result;
 
   } else if (instr->representation().IsDouble()) {
     if (kArchVariant == kMips64r2) {
@@ -1564,9 +1567,11 @@ LInstruction* LChunkBuilder::DoSub(HSub* instr) {
     DCHECK(instr->left()->representation().Equals(instr->representation()));
     DCHECK(instr->right()->representation().Equals(instr->representation()));
     LOperand* left = UseRegisterAtStart(instr->left());
-    LOperand* right = UseOrConstantAtStart(instr->right());
-    LSubI* sub = new(zone()) LSubI(left, right);
-    LInstruction* result = DefineAsRegister(sub);
+    LOperand* right = UseRegisterOrConstantAtStart(instr->right());
+    LInstruction* result =
+        instr->representation().IsSmi()
+            ? DefineAsRegister(new (zone()) LSubS(left, right))
+            : DefineAsRegister(new (zone()) LSubI(left, right));
     if (instr->CheckFlag(HValue::kCanOverflow)) {
       result = AssignEnvironment(result);
     }
@@ -1594,8 +1599,10 @@ LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
     DCHECK(instr->right()->representation().Equals(instr->representation()));
     LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
     LOperand* right = UseRegisterOrConstantAtStart(instr->BetterRightOperand());
-    LAddI* add = new(zone()) LAddI(left, right);
-    LInstruction* result = DefineAsRegister(add);
+    LInstruction* result =
+        instr->representation().IsSmi()
+            ? DefineAsRegister(new (zone()) LAddS(left, right))
+            : DefineAsRegister(new (zone()) LAddI(left, right));
     if (instr->CheckFlag(HValue::kCanOverflow)) {
       result = AssignEnvironment(result);
     }
index 6928ae4..fc3bcae 100644 (file)
@@ -19,8 +19,9 @@ class LCodeGen;
 
 #define LITHIUM_CONCRETE_INSTRUCTION_LIST(V) \
   V(AccessArgumentsAt)                       \
-  V(AddI)                                    \
   V(AddE)                                    \
+  V(AddI)                                    \
+  V(AddS)                                    \
   V(Allocate)                                \
   V(AllocateBlockContext)                    \
   V(ApplyArguments)                          \
@@ -123,6 +124,7 @@ class LCodeGen;
   V(ModByPowerOf2I)                          \
   V(ModI)                                    \
   V(MulI)                                    \
+  V(MulS)                                    \
   V(MultiplyAddD)                            \
   V(NumberTagD)                              \
   V(NumberTagU)                              \
@@ -151,6 +153,7 @@ class LCodeGen;
   V(StringCharFromCode)                      \
   V(StringCompareAndBranch)                  \
   V(SubI)                                    \
+  V(SubS)                                    \
   V(TaggedToI)                               \
   V(ThisFunction)                            \
   V(ToFastProperties)                        \
@@ -754,6 +757,21 @@ class LFlooringDivI final : public LTemplateInstruction<1, 2, 0> {
 };
 
 
+class LMulS final : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LMulS(LOperand* left, LOperand* right) {
+    inputs_[0] = left;
+    inputs_[1] = right;
+  }
+
+  LOperand* left() { return inputs_[0]; }
+  LOperand* right() { return inputs_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MulS, "mul-s")
+  DECLARE_HYDROGEN_ACCESSOR(Mul)
+};
+
+
 class LMulI final : public LTemplateInstruction<1, 2, 0> {
  public:
   LMulI(LOperand* left, LOperand* right) {
@@ -1274,6 +1292,21 @@ class LSubI final : public LTemplateInstruction<1, 2, 0> {
 };
 
 
+class LSubS final : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LSubS(LOperand* left, LOperand* right) {
+    inputs_[0] = left;
+    inputs_[1] = right;
+  }
+
+  LOperand* left() { return inputs_[0]; }
+  LOperand* right() { return inputs_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(SubS, "sub-s")
+  DECLARE_HYDROGEN_ACCESSOR(Sub)
+};
+
+
 class LConstantI final : public LTemplateInstruction<1, 0, 0> {
  public:
   DECLARE_CONCRETE_INSTRUCTION(ConstantI, "constant-i")
@@ -1452,6 +1485,21 @@ class LAddI final : public LTemplateInstruction<1, 2, 0> {
 };
 
 
+class LAddS final : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LAddS(LOperand* left, LOperand* right) {
+    inputs_[0] = left;
+    inputs_[1] = right;
+  }
+
+  LOperand* left() { return inputs_[0]; }
+  LOperand* right() { return inputs_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(AddS, "add-s")
+  DECLARE_HYDROGEN_ACCESSOR(Add)
+};
+
+
 class LMathMinMax final : public LTemplateInstruction<1, 2, 0> {
  public:
   LMathMinMax(LOperand* left, LOperand* right) {
index a505f4a..6a947e1 100644 (file)
@@ -4447,7 +4447,6 @@ void MacroAssembler::ObjectToDoubleFPURegister(Register object,
 void MacroAssembler::SmiToDoubleFPURegister(Register smi,
                                             FPURegister value,
                                             Register scratch1) {
-  // dsra(scratch1, smi, kSmiTagSize);
   dsra32(scratch1, smi, 0);
   mtc1(scratch1, value);
   cvt_d_w(value, value);
@@ -4462,19 +4461,16 @@ void MacroAssembler::AdduAndCheckForOverflow(Register dst, Register left,
     AdduAndCheckForOverflow(dst, left, right.rm(), overflow_dst, scratch);
   } else {
     if (dst.is(left)) {
+      li(t9, right);                         // Load right.
       mov(scratch, left);                    // Preserve left.
-      daddiu(dst, left,
-             static_cast<int32_t>(right.immediate()));  // Left is overwritten.
+      addu(dst, left, t9);                   // Left is overwritten.
       xor_(scratch, dst, scratch);           // Original left.
-      // Load right since xori takes uint16 as immediate.
-      daddiu(t9, zero_reg, static_cast<int32_t>(right.immediate()));
       xor_(overflow_dst, dst, t9);
       and_(overflow_dst, overflow_dst, scratch);
     } else {
-      daddiu(dst, left, static_cast<int32_t>(right.immediate()));
+      li(t9, right);
+      addu(dst, left, t9);
       xor_(overflow_dst, dst, left);
-      // Load right since xori takes uint16 as immediate.
-      daddiu(t9, zero_reg, static_cast<int32_t>(right.immediate()));
       xor_(scratch, dst, t9);
       and_(overflow_dst, scratch, overflow_dst);
     }
@@ -4482,8 +4478,7 @@ void MacroAssembler::AdduAndCheckForOverflow(Register dst, Register left,
 }
 
 
-void MacroAssembler::AdduAndCheckForOverflow(Register dst,
-                                             Register left,
+void MacroAssembler::AdduAndCheckForOverflow(Register dst, Register left,
                                              Register right,
                                              Register overflow_dst,
                                              Register scratch) {
@@ -4504,6 +4499,72 @@ void MacroAssembler::AdduAndCheckForOverflow(Register dst,
   }
 
   if (dst.is(left)) {
+    mov(scratch, left);           // Preserve left.
+    addu(dst, left, right);       // Left is overwritten.
+    xor_(scratch, dst, scratch);  // Original left.
+    xor_(overflow_dst, dst, right);
+    and_(overflow_dst, overflow_dst, scratch);
+  } else if (dst.is(right)) {
+    mov(scratch, right);          // Preserve right.
+    addu(dst, left, right);       // Right is overwritten.
+    xor_(scratch, dst, scratch);  // Original right.
+    xor_(overflow_dst, dst, left);
+    and_(overflow_dst, overflow_dst, scratch);
+  } else {
+    addu(dst, left, right);
+    xor_(overflow_dst, dst, left);
+    xor_(scratch, dst, right);
+    and_(overflow_dst, scratch, overflow_dst);
+  }
+}
+
+
+void MacroAssembler::DadduAndCheckForOverflow(Register dst, Register left,
+                                              const Operand& right,
+                                              Register overflow_dst,
+                                              Register scratch) {
+  if (right.is_reg()) {
+    DadduAndCheckForOverflow(dst, left, right.rm(), overflow_dst, scratch);
+  } else {
+    if (dst.is(left)) {
+      li(t9, right);                // Load right.
+      mov(scratch, left);           // Preserve left.
+      daddu(dst, left, t9);         // Left is overwritten.
+      xor_(scratch, dst, scratch);  // Original left.
+      xor_(overflow_dst, dst, t9);
+      and_(overflow_dst, overflow_dst, scratch);
+    } else {
+      li(t9, right);  // Load right.
+      Daddu(dst, left, t9);
+      xor_(overflow_dst, dst, left);
+      xor_(scratch, dst, t9);
+      and_(overflow_dst, scratch, overflow_dst);
+    }
+  }
+}
+
+
+void MacroAssembler::DadduAndCheckForOverflow(Register dst, Register left,
+                                              Register right,
+                                              Register overflow_dst,
+                                              Register scratch) {
+  DCHECK(!dst.is(overflow_dst));
+  DCHECK(!dst.is(scratch));
+  DCHECK(!overflow_dst.is(scratch));
+  DCHECK(!overflow_dst.is(left));
+  DCHECK(!overflow_dst.is(right));
+
+  if (left.is(right) && dst.is(left)) {
+    DCHECK(!dst.is(t9));
+    DCHECK(!scratch.is(t9));
+    DCHECK(!left.is(t9));
+    DCHECK(!right.is(t9));
+    DCHECK(!overflow_dst.is(t9));
+    mov(t9, right);
+    right = t9;
+  }
+
+  if (dst.is(left)) {
     mov(scratch, left);  // Preserve left.
     daddu(dst, left, right);  // Left is overwritten.
     xor_(scratch, dst, scratch);  // Original left.
@@ -4532,19 +4593,16 @@ void MacroAssembler::SubuAndCheckForOverflow(Register dst, Register left,
     SubuAndCheckForOverflow(dst, left, right.rm(), overflow_dst, scratch);
   } else {
     if (dst.is(left)) {
+      li(t9, right);                            // Load right.
       mov(scratch, left);                       // Preserve left.
-      daddiu(dst, left,
-             static_cast<int32_t>(-right.immediate()));  // Left is overwritten.
+      Subu(dst, left, t9);                      // Left is overwritten.
       xor_(overflow_dst, dst, scratch);         // scratch is original left.
-      // Load right since xori takes uint16 as immediate.
-      daddiu(t9, zero_reg, static_cast<int32_t>(right.immediate()));
       xor_(scratch, scratch, t9);  // scratch is original left.
       and_(overflow_dst, scratch, overflow_dst);
     } else {
-      daddiu(dst, left, static_cast<int32_t>(-right.immediate()));
+      li(t9, right);
+      subu(dst, left, t9);
       xor_(overflow_dst, dst, left);
-      // Load right since xori takes uint16 as immediate.
-      daddiu(t9, zero_reg, static_cast<int32_t>(right.immediate()));
       xor_(scratch, left, t9);
       and_(overflow_dst, scratch, overflow_dst);
     }
@@ -4552,8 +4610,7 @@ void MacroAssembler::SubuAndCheckForOverflow(Register dst, Register left,
 }
 
 
-void MacroAssembler::SubuAndCheckForOverflow(Register dst,
-                                             Register left,
+void MacroAssembler::SubuAndCheckForOverflow(Register dst, Register left,
                                              Register right,
                                              Register overflow_dst,
                                              Register scratch) {
@@ -4574,6 +4631,72 @@ void MacroAssembler::SubuAndCheckForOverflow(Register dst,
   }
 
   if (dst.is(left)) {
+    mov(scratch, left);                // Preserve left.
+    subu(dst, left, right);            // Left is overwritten.
+    xor_(overflow_dst, dst, scratch);  // scratch is original left.
+    xor_(scratch, scratch, right);     // scratch is original left.
+    and_(overflow_dst, scratch, overflow_dst);
+  } else if (dst.is(right)) {
+    mov(scratch, right);     // Preserve right.
+    subu(dst, left, right);  // Right is overwritten.
+    xor_(overflow_dst, dst, left);
+    xor_(scratch, left, scratch);  // Original right.
+    and_(overflow_dst, scratch, overflow_dst);
+  } else {
+    subu(dst, left, right);
+    xor_(overflow_dst, dst, left);
+    xor_(scratch, left, right);
+    and_(overflow_dst, scratch, overflow_dst);
+  }
+}
+
+
+void MacroAssembler::DsubuAndCheckForOverflow(Register dst, Register left,
+                                              const Operand& right,
+                                              Register overflow_dst,
+                                              Register scratch) {
+  if (right.is_reg()) {
+    DsubuAndCheckForOverflow(dst, left, right.rm(), overflow_dst, scratch);
+  } else {
+    if (dst.is(left)) {
+      li(t9, right);                     // Load right.
+      mov(scratch, left);                // Preserve left.
+      dsubu(dst, left, t9);              // Left is overwritten.
+      xor_(overflow_dst, dst, scratch);  // scratch is original left.
+      xor_(scratch, scratch, t9);        // scratch is original left.
+      and_(overflow_dst, scratch, overflow_dst);
+    } else {
+      li(t9, right);
+      dsubu(dst, left, t9);
+      xor_(overflow_dst, dst, left);
+      xor_(scratch, left, t9);
+      and_(overflow_dst, scratch, overflow_dst);
+    }
+  }
+}
+
+
+void MacroAssembler::DsubuAndCheckForOverflow(Register dst, Register left,
+                                              Register right,
+                                              Register overflow_dst,
+                                              Register scratch) {
+  DCHECK(!dst.is(overflow_dst));
+  DCHECK(!dst.is(scratch));
+  DCHECK(!overflow_dst.is(scratch));
+  DCHECK(!overflow_dst.is(left));
+  DCHECK(!overflow_dst.is(right));
+  DCHECK(!scratch.is(left));
+  DCHECK(!scratch.is(right));
+
+  // This happens with some crankshaft code. Since Subu works fine if
+  // left == right, let's not make that restriction here.
+  if (left.is(right)) {
+    mov(dst, zero_reg);
+    mov(overflow_dst, zero_reg);
+    return;
+  }
+
+  if (dst.is(left)) {
     mov(scratch, left);  // Preserve left.
     dsubu(dst, left, right);  // Left is overwritten.
     xor_(overflow_dst, dst, scratch);  // scratch is original left.
@@ -4593,7 +4716,6 @@ void MacroAssembler::SubuAndCheckForOverflow(Register dst,
   }
 }
 
-
 void MacroAssembler::CallRuntime(const Runtime::Function* f,
                                  int num_arguments,
                                  SaveFPRegsMode save_doubles) {
index dc22eff..7de3300 100644 (file)
@@ -1203,7 +1203,7 @@ class MacroAssembler: public Assembler {
 
   void AdduAndCheckForOverflow(Register dst, Register left,
                                const Operand& right, Register overflow_dst,
-                               Register scratch = at);
+                               Register scratch);
 
   void SubuAndCheckForOverflow(Register dst,
                                Register left,
@@ -1213,7 +1213,21 @@ class MacroAssembler: public Assembler {
 
   void SubuAndCheckForOverflow(Register dst, Register left,
                                const Operand& right, Register overflow_dst,
-                               Register scratch = at);
+                               Register scratch);
+
+  void DadduAndCheckForOverflow(Register dst, Register left, Register right,
+                                Register overflow_dst, Register scratch = at);
+
+  void DadduAndCheckForOverflow(Register dst, Register left,
+                                const Operand& right, Register overflow_dst,
+                                Register scratch);
+
+  void DsubuAndCheckForOverflow(Register dst, Register left, Register right,
+                                Register overflow_dst, Register scratch = at);
+
+  void DsubuAndCheckForOverflow(Register dst, Register left,
+                                const Operand& right, Register overflow_dst,
+                                Register scratch);
 
   void BranchOnOverflow(Label* label,
                         Register overflow_check,