[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;
}