[vm/compiler] Remove overflow checks from 64-bit int operations

This is a follow-up cleanup after '--limit-ints-to-64-bits' was removed.

Change-Id: Ifb02ca8055ddb830cf0bd5dd2a591d6ae5a1ab74
Reviewed-on: https://dart-review.googlesource.com/58921
Reviewed-by: Zach Anderson <zra@google.com>
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
diff --git a/runtime/vm/compiler/backend/il.h b/runtime/vm/compiler/backend/il.h
index d80ec7c..3ce1bb1 100644
--- a/runtime/vm/compiler/backend/il.h
+++ b/runtime/vm/compiler/backend/il.h
@@ -6035,8 +6035,6 @@
     can_overflow_ = overflow;
   }
 
-  // TODO(alexmarkov): Figure out if we still need !is_truncating operations.
-  // If not, then remove is_truncating_ flag and simplify code.
   bool is_truncating() const { return is_truncating_; }
   void mark_truncating() {
     is_truncating_ = true;
@@ -6220,22 +6218,13 @@
   }
 
   virtual bool ComputeCanDeoptimize() const {
-    switch (op_kind()) {
-      case Token::kADD:
-      case Token::kSUB:
-        return can_overflow();
-      case Token::kMUL:
-// Note that ARM64 does not support operations with unboxed mints,
-// so it is not handled here.
-#if defined(TARGET_ARCH_X64)
-        return can_overflow();  // Deopt if overflow.
-#else
-        // IA32, ARM
-        return true;  // Deopt if inputs are not int32.
-#endif
-      default:
-        return false;
+    ASSERT(!can_overflow());
+#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_ARM)
+    if (op_kind() == Token::kMUL) {
+      return true;  // Deopt if inputs are not int32.
     }
+#endif
+    return false;
   }
 
   virtual Representation representation() const { return kUnboxedInt64; }
@@ -6277,8 +6266,8 @@
   Range* shift_range() const { return shift_range_; }
 
   virtual bool ComputeCanDeoptimize() const {
-    return (!IsShiftCountInRange()) ||
-           (can_overflow() && (op_kind() == Token::kSHL));
+    ASSERT(!can_overflow());
+    return !IsShiftCountInRange();
   }
 
   virtual Representation representation() const { return kUnboxedInt64; }
diff --git a/runtime/vm/compiler/backend/il_arm.cc b/runtime/vm/compiler/backend/il_arm.cc
index 3fab23e..269f1b4 100644
--- a/runtime/vm/compiler/backend/il_arm.cc
+++ b/runtime/vm/compiler/backend/il_arm.cc
@@ -5750,6 +5750,7 @@
   PairLocation* out_pair = locs()->out(0).AsPairLocation();
   Register out_lo = out_pair->At(0).reg();
   Register out_hi = out_pair->At(1).reg();
+  ASSERT(!can_overflow());
 
   Label* deopt = NULL;
   if (CanDeoptimize()) {
@@ -5781,10 +5782,6 @@
         __ subs(out_lo, left_lo, Operand(right_lo));
         __ sbcs(out_hi, left_hi, Operand(right_hi));
       }
-      if (can_overflow()) {
-        // Deopt on overflow.
-        __ b(deopt, VS);
-      }
       break;
     }
     case Token::kMUL: {
@@ -5824,6 +5821,7 @@
   PairLocation* out_pair = locs()->out(0).AsPairLocation();
   Register out_lo = out_pair->At(0).reg();
   Register out_hi = out_pair->At(1).reg();
+  ASSERT(!can_overflow());
 
   Label* deopt = NULL;
   if (CanDeoptimize()) {
@@ -5866,22 +5864,6 @@
           }
           __ mov(out_lo, Operand(0));
         }
-        // Check for overflow.
-        if (can_overflow()) {
-          // Compare high word from input with shifted high word from output.
-          // If shift > 32, also compare low word from input with high word from
-          // output shifted back shift - 32.
-          if (shift > 32) {
-            __ cmp(left_lo, Operand(out_hi, ASR, shift - 32));
-            __ cmp(left_hi, Operand(out_hi, ASR, 31), EQ);
-          } else if (shift == 32) {
-            __ cmp(left_hi, Operand(out_hi, ASR, 31));
-          } else {
-            __ cmp(left_hi, Operand(out_hi, ASR, shift));
-          }
-          // Overflow if they aren't equal.
-          __ b(deopt, NE);
-        }
         break;
       }
       default:
@@ -5917,19 +5899,6 @@
         __ mov(out_hi, Operand(left_hi, LSL, shift), PL);
         __ orr(out_hi, out_hi, Operand(left_lo, LSR, IP), PL);
         __ mov(out_lo, Operand(left_lo, LSL, shift));
-
-        // Check for overflow.
-        if (can_overflow()) {
-          // If shift > 32, compare low word from input with high word from
-          // output shifted back shift - 32.
-          __ mov(IP, Operand(out_hi, ASR, IP), MI);
-          __ mov(IP, Operand(left_lo), PL);  // No test if shift <= 32.
-          __ cmp(left_lo, Operand(IP));
-          // Compare high word from input with shifted high word from output.
-          __ cmp(left_hi, Operand(out_hi, ASR, shift), EQ);
-          // Overflow if they aren't equal.
-          __ b(deopt, NE);
-        }
         break;
       }
       default:
diff --git a/runtime/vm/compiler/backend/il_arm64.cc b/runtime/vm/compiler/backend/il_arm64.cc
index 24d2e84..d8bbde3 100644
--- a/runtime/vm/compiler/backend/il_arm64.cc
+++ b/runtime/vm/compiler/backend/il_arm64.cc
@@ -4988,10 +4988,8 @@
 }
 
 void BinaryInt64OpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-  Label* deopt = NULL;
-  if (CanDeoptimize()) {
-    deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptBinaryInt64Op);
-  }
+  ASSERT(!can_overflow());
+  ASSERT(!CanDeoptimize());
 
   const Register left = locs()->in(0).reg();
   const Location right = locs()->in(1);
@@ -5008,12 +5006,6 @@
       r = right.reg();
     }
     __ mul(out, left, r);
-    if (CanDeoptimize()) {
-      __ smulh(TMP, left, r);
-      // TMP: result bits 64..127.
-      __ cmp(TMP, Operand(out, ASR, 63));
-      __ b(deopt, NE);
-    }
     return;
   }
 
@@ -5023,20 +5015,10 @@
         constant_instr->GetUnboxedSignedIntegerConstantValue();
     switch (op_kind()) {
       case Token::kADD:
-        if (CanDeoptimize()) {
-          __ AddImmediateSetFlags(out, left, value);
-          __ b(deopt, VS);
-        } else {
-          __ AddImmediate(out, left, value);
-        }
+        __ AddImmediate(out, left, value);
         break;
       case Token::kSUB:
-        if (CanDeoptimize()) {
-          __ SubImmediateSetFlags(out, left, value);
-          __ b(deopt, VS);
-        } else {
-          __ AddImmediate(out, left, -value);
-        }
+        __ AddImmediate(out, left, -value);
         break;
       case Token::kBIT_AND:
         __ AndImmediate(out, left, value);
@@ -5054,20 +5036,10 @@
     Operand r = Operand(right.reg());
     switch (op_kind()) {
       case Token::kADD:
-        if (CanDeoptimize()) {
-          __ adds(out, left, r);
-          __ b(deopt, VS);
-        } else {
-          __ add(out, left, r);
-        }
+        __ add(out, left, r);
         break;
       case Token::kSUB:
-        if (CanDeoptimize()) {
-          __ subs(out, left, r);
-          __ b(deopt, VS);
-        } else {
-          __ sub(out, left, r);
-        }
+        __ sub(out, left, r);
         break;
       case Token::kBIT_AND:
         __ and_(out, left, r);
@@ -5099,6 +5071,7 @@
 void ShiftInt64OpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
   const Register left = locs()->in(0).reg();
   const Register out = locs()->out(0).reg();
+  ASSERT(!can_overflow());
 
   Label* deopt = NULL;
   if (CanDeoptimize()) {
@@ -5117,11 +5090,6 @@
       case Token::kSHL: {
         ASSERT(shift < 64);
         __ LslImmediate(out, left, shift);
-        // Check for overflow.
-        if (can_overflow()) {
-          __ cmp(left, Operand(out, ASR, shift));
-          __ b(deopt, NE);
-        }
         break;
       }
       default:
@@ -5147,13 +5115,6 @@
       }
       case Token::kSHL: {
         __ lslv(out, left, TMP);
-
-        // Check for overflow.
-        if (can_overflow()) {
-          __ asrv(TMP2, out, TMP);
-          __ cmp(left, Operand(TMP2));
-          __ b(deopt, NE);
-        }
         break;
       }
       default:
diff --git a/runtime/vm/compiler/backend/il_ia32.cc b/runtime/vm/compiler/backend/il_ia32.cc
index 94652d9..e400614 100644
--- a/runtime/vm/compiler/backend/il_ia32.cc
+++ b/runtime/vm/compiler/backend/il_ia32.cc
@@ -5191,6 +5191,7 @@
   Register out_hi = out_pair->At(1).reg();
   ASSERT(out_lo == left_lo);
   ASSERT(out_hi == left_hi);
+  ASSERT(!can_overflow());
 
   Label* deopt = NULL;
   if (CanDeoptimize()) {
@@ -5218,9 +5219,6 @@
         __ subl(left_lo, right_lo);
         __ sbbl(left_hi, right_hi);
       }
-      if (can_overflow()) {
-        __ j(OVERFLOW, deopt);
-      }
       break;
     }
     case Token::kMUL: {
@@ -5251,17 +5249,12 @@
 LocationSummary* ShiftInt64OpInstr::MakeLocationSummary(Zone* zone,
                                                         bool opt) const {
   const intptr_t kNumInputs = 2;
-  const intptr_t kNumTemps =
-      (op_kind() == Token::kSHL) && CanDeoptimize() ? 2 : 0;
+  const intptr_t kNumTemps = 0;
   LocationSummary* summary = new (zone)
       LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
   summary->set_in(0, Location::Pair(Location::RequiresRegister(),
                                     Location::RequiresRegister()));
   summary->set_in(1, Location::FixedRegisterOrSmiConstant(right(), ECX));
-  if ((op_kind() == Token::kSHL) && CanDeoptimize()) {
-    summary->set_temp(0, Location::RequiresRegister());
-    summary->set_temp(1, Location::RequiresRegister());
-  }
   summary->set_out(0, Location::SameAsFirstInput());
   return summary;
 }
@@ -5275,6 +5268,7 @@
   Register out_hi = out_pair->At(1).reg();
   ASSERT(out_lo == left_lo);
   ASSERT(out_hi == left_hi);
+  ASSERT(!can_overflow());
 
   Label* deopt = NULL;
   if (CanDeoptimize()) {
@@ -5301,51 +5295,15 @@
       }
       case Token::kSHL: {
         ASSERT(shift < 64);
-        if (can_overflow()) {
-          Register temp1 = locs()->temp(0).reg();
-          Register temp2 = locs()->temp(1).reg();
-          __ movl(temp1, left_hi);  // Preserve high 32 bits.
-          if (shift > 31) {
-            __ movl(left_hi, left_lo);  // Shift by 32.
-            if (shift > 32) {
-              __ shll(left_hi, Immediate(shift - 32));
-            }
-            // Check for overflow by sign extending the high 32 bits
-            // and comparing with the input.
-            __ movl(temp2, left_hi);
-            __ sarl(temp2, Immediate(31));
-            __ cmpl(temp1, temp2);
-            __ j(NOT_EQUAL, deopt);
-            if (shift > 32) {
-              // Also compare low word from input with high word from
-              // output shifted back shift - 32.
-              __ movl(temp2, left_hi);
-              __ sarl(temp2, Immediate(shift - 32));
-              __ cmpl(left_lo, temp2);
-              __ j(NOT_EQUAL, deopt);
-            }
-            __ xorl(left_lo, left_lo);  // Zero left_lo.
-          } else {
-            __ shldl(left_hi, left_lo, Immediate(shift));
-            __ shll(left_lo, Immediate(shift));
-            // Check for overflow by shifting back the high 32 bits
-            // and comparing with the input.
-            __ movl(temp2, left_hi);
-            __ sarl(temp2, Immediate(shift));
-            __ cmpl(temp1, temp2);
-            __ j(NOT_EQUAL, deopt);
+        if (shift > 31) {
+          __ movl(left_hi, left_lo);  // Shift by 32.
+          __ xorl(left_lo, left_lo);  // Zero left_lo.
+          if (shift > 32) {
+            __ shll(left_hi, Immediate(shift - 32));
           }
         } else {
-          if (shift > 31) {
-            __ movl(left_hi, left_lo);  // Shift by 32.
-            __ xorl(left_lo, left_lo);  // Zero left_lo.
-            if (shift > 32) {
-              __ shll(left_hi, Immediate(shift - 32));
-            }
-          } else {
-            __ shldl(left_hi, left_lo, Immediate(shift));
-            __ shll(left_lo, Immediate(shift));
-          }
+          __ shldl(left_hi, left_lo, Immediate(shift));
+          __ shll(left_lo, Immediate(shift));
         }
         break;
       }
@@ -5380,54 +5338,18 @@
         break;
       }
       case Token::kSHL: {
-        if (can_overflow()) {
-          Register temp1 = locs()->temp(0).reg();
-          Register temp2 = locs()->temp(1).reg();
-          __ movl(temp1, left_hi);  // Preserve high 32 bits.
-          __ cmpl(ECX, Immediate(31));
-          __ j(ABOVE, &large_shift);
+        __ cmpl(ECX, Immediate(31));
+        __ j(ABOVE, &large_shift);
 
-          __ shldl(left_hi, left_lo, ECX);  // Shift count in CL.
-          __ shll(left_lo, ECX);            // Shift count in CL.
-          // Check for overflow by shifting back the high 32 bits
-          // and comparing with the input.
-          __ movl(temp2, left_hi);
-          __ sarl(temp2, ECX);
-          __ cmpl(temp1, temp2);
-          __ j(NOT_EQUAL, deopt);
-          __ jmp(&done, Assembler::kNearJump);
+        __ shldl(left_hi, left_lo, ECX);  // Shift count in CL.
+        __ shll(left_lo, ECX);            // Shift count in CL.
+        __ jmp(&done, Assembler::kNearJump);
 
-          __ Bind(&large_shift);
-          // No need to subtract 32 from CL, only 5 bits used by shll.
-          __ movl(left_hi, left_lo);  // Shift by 32.
-          __ shll(left_hi, ECX);      // Shift count: CL % 32.
-          // Check for overflow by sign extending the high 32 bits
-          // and comparing with the input.
-          __ movl(temp2, left_hi);
-          __ sarl(temp2, Immediate(31));
-          __ cmpl(temp1, temp2);
-          __ j(NOT_EQUAL, deopt);
-          // Also compare low word from input with high word from
-          // output shifted back shift - 32.
-          __ movl(temp2, left_hi);
-          __ sarl(temp2, ECX);  // Shift count: CL % 32.
-          __ cmpl(left_lo, temp2);
-          __ j(NOT_EQUAL, deopt);
-          __ xorl(left_lo, left_lo);  // Zero left_lo.
-        } else {
-          __ cmpl(ECX, Immediate(31));
-          __ j(ABOVE, &large_shift);
-
-          __ shldl(left_hi, left_lo, ECX);  // Shift count in CL.
-          __ shll(left_lo, ECX);            // Shift count in CL.
-          __ jmp(&done, Assembler::kNearJump);
-
-          __ Bind(&large_shift);
-          // No need to subtract 32 from CL, only 5 bits used by shll.
-          __ movl(left_hi, left_lo);  // Shift by 32.
-          __ xorl(left_lo, left_lo);  // Zero left_lo.
-          __ shll(left_hi, ECX);      // Shift count: CL % 32.
-        }
+        __ Bind(&large_shift);
+        // No need to subtract 32 from CL, only 5 bits used by shll.
+        __ movl(left_hi, left_lo);  // Shift by 32.
+        __ xorl(left_lo, left_lo);  // Zero left_lo.
+        __ shll(left_hi, ECX);      // Shift count: CL % 32.
         break;
       }
       default:
diff --git a/runtime/vm/compiler/backend/il_x64.cc b/runtime/vm/compiler/backend/il_x64.cc
index e46cd88..2d410db 100644
--- a/runtime/vm/compiler/backend/il_x64.cc
+++ b/runtime/vm/compiler/backend/il_x64.cc
@@ -5151,8 +5151,7 @@
 static void EmitInt64Arithmetic(FlowGraphCompiler* compiler,
                                 Token::Kind op_kind,
                                 Register left,
-                                const OperandType& right,
-                                Label* deopt) {
+                                const OperandType& right) {
   switch (op_kind) {
     case Token::kADD:
       __ addq(left, right);
@@ -5175,7 +5174,6 @@
     default:
       UNREACHABLE();
   }
-  if (deopt != NULL) __ j(OVERFLOW, deopt);
 }
 
 LocationSummary* BinaryInt64OpInstr::MakeLocationSummary(Zone* zone,
@@ -5191,23 +5189,20 @@
 }
 
 void BinaryInt64OpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-  Label* deopt = NULL;
-  if (CanDeoptimize()) {
-    deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptBinaryInt64Op);
-  }
   const Location left = locs()->in(0);
   const Location right = locs()->in(1);
   const Location out = locs()->out(0);
   ASSERT(out.reg() == left.reg());
+  ASSERT(!can_overflow());
+  ASSERT(!CanDeoptimize());
 
   if (right.IsConstant()) {
     ConstantInstr* constant_instr = right.constant_instruction();
     const int64_t value =
         constant_instr->GetUnboxedSignedIntegerConstantValue();
-    EmitInt64Arithmetic(compiler, op_kind(), left.reg(), Immediate(value),
-                        deopt);
+    EmitInt64Arithmetic(compiler, op_kind(), left.reg(), Immediate(value));
   } else {
-    EmitInt64Arithmetic(compiler, op_kind(), left.reg(), right.reg(), deopt);
+    EmitInt64Arithmetic(compiler, op_kind(), left.reg(), right.reg());
   }
 }
 
@@ -5233,14 +5228,11 @@
 LocationSummary* ShiftInt64OpInstr::MakeLocationSummary(Zone* zone,
                                                         bool opt) const {
   const intptr_t kNumInputs = 2;
-  const intptr_t kNumTemps = can_overflow() ? 1 : 0;
+  const intptr_t kNumTemps = 0;
   LocationSummary* summary = new (zone)
       LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
   summary->set_in(0, Location::RequiresRegister());
   summary->set_in(1, Location::FixedRegisterOrSmiConstant(right(), RCX));
-  if (kNumTemps > 0) {
-    summary->set_temp(0, Location::RequiresRegister());
-  }
   summary->set_out(0, Location::SameAsFirstInput());
   return summary;
 }
@@ -5249,6 +5241,7 @@
   const Register left = locs()->in(0).reg();
   const Register out = locs()->out(0).reg();
   ASSERT(left == out);
+  ASSERT(!can_overflow());
 
   Label* deopt = NULL;
   if (CanDeoptimize()) {
@@ -5266,16 +5259,6 @@
         break;
       case Token::kSHL: {
         ASSERT(shift < 64);
-        if (can_overflow()) {
-          // Check for overflow.
-          Register temp = locs()->temp(0).reg();
-          __ movq(temp, left);
-          __ shlq(left, Immediate(shift));
-          __ sarq(left, Immediate(shift));
-          __ cmpq(left, temp);
-          __ j(NOT_EQUAL, deopt);  // Overflow.
-        }
-        // Shift for result now we know there is no overflow.
         __ shlq(left, Immediate(shift));
         break;
       }
@@ -5298,16 +5281,6 @@
         break;
       }
       case Token::kSHL: {
-        if (can_overflow()) {
-          // Check for overflow.
-          Register temp = locs()->temp(0).reg();
-          __ movq(temp, left);
-          __ shlq(left, RCX);
-          __ sarq(left, RCX);
-          __ cmpq(left, temp);
-          __ j(NOT_EQUAL, deopt);  // Overflow.
-        }
-        // Shift for result now we know there is no overflow.
         __ shlq(left, RCX);
         break;
       }