Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(269)

Unified Diff: runtime/vm/intermediate_language_ia32.cc

Issue 564843002: Initial steps towards cleaning up integer arithmetic IR. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: runtime/vm/intermediate_language_ia32.cc
diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc
index 0673bd5df928a9d2a973d7da966e8395430acfc9..9126415c04dd54dd5eba6479721ccd133b329532 100644
--- a/runtime/vm/intermediate_language_ia32.cc
+++ b/runtime/vm/intermediate_language_ia32.cc
@@ -2663,7 +2663,6 @@ void CheckStackOverflowInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
static void EmitSmiShiftLeft(FlowGraphCompiler* compiler,
BinarySmiOpInstr* shift_left) {
- const bool is_truncating = shift_left->IsTruncating();
const LocationSummary& locs = *shift_left->locs();
Register left = locs.in(0).reg();
Register result = locs.out(0).reg();
@@ -2677,38 +2676,26 @@ static void EmitSmiShiftLeft(FlowGraphCompiler* compiler,
// shll operation masks the count to 5 bits.
const intptr_t kCountLimit = 0x1F;
const intptr_t value = Smi::Cast(constant).Value();
- if (value == 0) {
- // No code needed.
- } else if ((value < 0) || (value >= kCountLimit)) {
- // This condition may not be known earlier in some cases because
- // of constant propagation, inlining, etc.
- if ((value >= kCountLimit) && is_truncating) {
- __ xorl(result, result);
- } else {
- // Result is Mint or exception.
- __ jmp(deopt);
- }
- } else {
- if (!is_truncating) {
- // Check for overflow.
- Register temp = locs.temp(0).reg();
- __ movl(temp, left);
- __ shll(left, Immediate(value));
- __ sarl(left, Immediate(value));
- __ cmpl(left, temp);
- __ j(NOT_EQUAL, deopt); // Overflow.
- }
- // Shift for result now we know there is no overflow.
+ ASSERT((0 < value) && (value < kCountLimit));
+ if (shift_left->can_overflow()) {
+ // Check for overflow.
+ Register temp = locs.temp(0).reg();
+ __ movl(temp, left);
__ shll(left, Immediate(value));
+ __ sarl(left, Immediate(value));
+ __ cmpl(left, temp);
+ __ j(NOT_EQUAL, deopt); // Overflow.
}
+ // Shift for result now we know there is no overflow.
+ __ shll(left, Immediate(value));
return;
}
// Right (locs.in(1)) is not constant.
Register right = locs.in(1).reg();
Range* right_range = shift_left->right()->definition()->range();
- if (shift_left->left()->BindsToConstant() && !is_truncating) {
- // TODO(srdjan): Implement code below for is_truncating().
+ if (shift_left->left()->BindsToConstant() && shift_left->can_overflow()) {
+ // TODO(srdjan): Implement code below for can_overflow().
// If left is constant, we know the maximal allowed size for right.
const Object& obj = shift_left->left()->BoundConstant();
if (obj.IsSmi()) {
@@ -2735,7 +2722,7 @@ static void EmitSmiShiftLeft(FlowGraphCompiler* compiler,
const bool right_needs_check =
!RangeUtils::IsWithin(right_range, 0, (Smi::kBits - 1));
ASSERT(right == ECX); // Count must be in ECX
- if (is_truncating) {
+ if (!shift_left->can_overflow()) {
if (right_needs_check) {
const bool right_may_be_negative =
(right_range == NULL) || !right_range->IsPositive();
@@ -2824,12 +2811,12 @@ LocationSummary* BinarySmiOpInstr::MakeLocationSummary(Isolate* isolate,
summary->set_out(0, Location::SameAsFirstInput());
return summary;
} else if (op_kind() == Token::kSHL) {
- const intptr_t kNumTemps = !IsTruncating() ? 1 : 0;
+ const intptr_t kNumTemps = can_overflow() ? 1 : 0;
LocationSummary* summary = new(isolate) LocationSummary(
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
summary->set_in(0, Location::RequiresRegister());
summary->set_in(1, Location::FixedRegisterOrSmiConstant(right(), ECX));
- if (!IsTruncating()) {
+ if (can_overflow()) {
summary->set_temp(0, Location::RequiresRegister());
}
summary->set_out(0, Location::SameAsFirstInput());
@@ -2851,6 +2838,38 @@ LocationSummary* BinarySmiOpInstr::MakeLocationSummary(Isolate* isolate,
}
+template<typename OperandType>
+static void EmitIntegerArithmetic(FlowGraphCompiler* compiler,
+ Token::Kind op_kind,
+ Register left,
+ const OperandType& right,
+ Label* deopt) {
+ switch (op_kind) {
+ case Token::kADD:
+ __ addl(left, right);
+ break;
+ case Token::kSUB:
+ __ subl(left, right);
+ break;
+ case Token::kBIT_AND:
+ __ andl(left, right);
+ break;
+ case Token::kBIT_OR:
+ __ orl(left, right);
+ break;
+ case Token::kBIT_XOR:
+ __ xorl(left, right);
+ break;
+ case Token::kMUL:
+ __ imull(left, right);
+ break;
+ default:
+ UNREACHABLE();
+ }
+ if (deopt != NULL) __ j(OVERFLOW, deopt);
+}
+
+
void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
if (op_kind() == Token::kSHL) {
EmitSmiShiftLeft(compiler, this);
@@ -2868,47 +2887,26 @@ void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
if (locs()->in(1).IsConstant()) {
const Object& constant = locs()->in(1).constant();
ASSERT(constant.IsSmi());
- const int32_t imm = reinterpret_cast<int32_t>(constant.raw());
+ // const int32_t imm = reinterpret_cast<int32_t>(constant.raw());
Cutch 2014/09/11 17:41:53 kill
+ const intptr_t value = Smi::Cast(constant).Value();
switch (op_kind()) {
- case Token::kADD:
- if (imm != 0) {
- // Checking overflow without emitting an instruction would be wrong.
- __ addl(left, Immediate(imm));
- if (deopt != NULL) __ j(OVERFLOW, deopt);
- }
- break;
- case Token::kSUB: {
- if (imm != 0) {
- // Checking overflow without emitting an instruction would be wrong.
- __ subl(left, Immediate(imm));
- if (deopt != NULL) __ j(OVERFLOW, deopt);
- }
- break;
- }
+ case Token::kADD:
+ case Token::kSUB:
+ case Token::kBIT_AND:
+ case Token::kBIT_OR:
+ case Token::kBIT_XOR:
case Token::kMUL: {
- // Keep left value tagged and untag right value.
- const intptr_t value = Smi::Cast(constant).Value();
- if (value == 2) {
- __ shll(left, Immediate(1));
- } else {
- __ imull(left, Immediate(value));
- }
- if (deopt != NULL) __ j(OVERFLOW, deopt);
+ const intptr_t imm = (op_kind() == Token::kMUL) ? value
+ : Smi::RawValue(value);
+ EmitIntegerArithmetic(compiler,
+ op_kind(),
+ left,
+ Immediate(imm),
+ deopt);
break;
}
+
case Token::kTRUNCDIV: {
- const intptr_t value = Smi::Cast(constant).Value();
- if (value == 1) {
- // Do nothing.
- break;
- } else if (value == -1) {
- // Check the corner case of dividing the 'MIN_SMI' with -1, in which
- // case we cannot negate the result.
- __ cmpl(left, Immediate(0x80000000));
- __ j(EQUAL, deopt);
- __ negl(left);
- break;
- }
ASSERT(Utils::IsPowerOfTwo(Utils::Abs(value)));
const intptr_t shift_count =
Utils::ShiftForPowerOfTwo(Utils::Abs(value)) + kSmiTagSize;
@@ -2927,39 +2925,12 @@ void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
__ SmiTag(left);
break;
}
- case Token::kBIT_AND: {
- // No overflow check.
- __ andl(left, Immediate(imm));
- break;
- }
- case Token::kBIT_OR: {
- // No overflow check.
- __ orl(left, Immediate(imm));
- break;
- }
- case Token::kBIT_XOR: {
- // No overflow check.
- __ xorl(left, Immediate(imm));
- break;
- }
+
case Token::kSHR: {
// sarl operation masks the count to 5 bits.
const intptr_t kCountLimit = 0x1F;
- intptr_t value = Smi::Cast(constant).Value();
-
- if (value == 0) {
- // TODO(vegorov): should be handled outside.
- break;
- } else if (value < 0) {
- // TODO(vegorov): should be handled outside.
- __ jmp(deopt);
- break;
- }
-
- value = value + kSmiTagSize;
- if (value >= kCountLimit) value = kCountLimit;
-
- __ sarl(left, Immediate(value));
+ __ sarl(left, Immediate(
+ Utils::Minimum(value + kSmiTagSize, kCountLimit)));
__ SmiTag(left);
break;
}
@@ -2973,79 +2944,30 @@ void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
if (locs()->in(1).IsStackSlot()) {
const Address& right = locs()->in(1).ToStackSlotAddress();
- switch (op_kind()) {
- case Token::kADD: {
- __ addl(left, right);
- if (deopt != NULL) __ j(OVERFLOW, deopt);
- break;
- }
- case Token::kSUB: {
- __ subl(left, right);
- if (deopt != NULL) __ j(OVERFLOW, deopt);
- break;
- }
- case Token::kMUL: {
- __ SmiUntag(left);
- __ imull(left, right);
- if (deopt != NULL) __ j(OVERFLOW, deopt);
- break;
- }
- case Token::kBIT_AND: {
- // No overflow check.
- __ andl(left, right);
- break;
- }
- case Token::kBIT_OR: {
- // No overflow check.
- __ orl(left, right);
- break;
- }
- case Token::kBIT_XOR: {
- // No overflow check.
- __ xorl(left, right);
- break;
- }
- default:
- UNREACHABLE();
+ if (op_kind() == Token::kMUL) {
+ __ SmiUntag(left);
}
+ EmitIntegerArithmetic(compiler, op_kind(), left, right, deopt);
return;
- } // if locs()->in(1).IsStackSlot.
+ }
// if locs()->in(1).IsRegister.
Register right = locs()->in(1).reg();
Range* right_range = this->right()->definition()->range();
switch (op_kind()) {
- case Token::kADD: {
- __ addl(left, right);
- if (deopt != NULL) __ j(OVERFLOW, deopt);
- break;
- }
- case Token::kSUB: {
- __ subl(left, right);
- if (deopt != NULL) __ j(OVERFLOW, deopt);
- break;
- }
- case Token::kMUL: {
- __ SmiUntag(left);
- __ imull(left, right);
- if (deopt != NULL) __ j(OVERFLOW, deopt);
- break;
- }
- case Token::kBIT_AND: {
- // No overflow check.
- __ andl(left, right);
- break;
- }
- case Token::kBIT_OR: {
- // No overflow check.
- __ orl(left, right);
- break;
- }
- case Token::kBIT_XOR: {
- // No overflow check.
- __ xorl(left, right);
+ case Token::kADD:
+ case Token::kSUB:
+ case Token::kBIT_AND:
+ case Token::kBIT_OR:
+ case Token::kBIT_XOR:
+ case Token::kMUL:
+ if (op_kind() == Token::kMUL) {
+ __ SmiUntag(left);
+ }
+ EmitIntegerArithmetic(compiler, op_kind(), left, right, deopt);
break;
- }
+
+
case Token::kTRUNCDIV: {
if ((right_range == NULL) || right_range->Overlaps(0, 0)) {
// Handle divide by zero in runtime.
@@ -3174,12 +3096,12 @@ LocationSummary* BinaryInt32OpInstr::MakeLocationSummary(Isolate* isolate,
summary->set_out(0, Location::SameAsFirstInput());
return summary;
} else if (op_kind() == Token::kSHL) {
- const intptr_t kNumTemps = !IsTruncating() ? 1 : 0;
+ const intptr_t kNumTemps = can_overflow() ? 1 : 0;
LocationSummary* summary = new(isolate) LocationSummary(
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
summary->set_in(0, Location::RequiresRegister());
summary->set_in(1, Location::FixedRegisterOrSmiConstant(right(), ECX));
- if (!IsTruncating()) {
+ if (can_overflow()) {
summary->set_temp(0, Location::RequiresRegister());
}
summary->set_out(0, Location::SameAsFirstInput());
@@ -3203,7 +3125,6 @@ LocationSummary* BinaryInt32OpInstr::MakeLocationSummary(Isolate* isolate,
static void EmitInt32ShiftLeft(FlowGraphCompiler* compiler,
BinaryInt32OpInstr* shift_left) {
- const bool is_truncating = shift_left->IsTruncating();
const LocationSummary& locs = *shift_left->locs();
Register left = locs.in(0).reg();
Register result = locs.out(0).reg();
@@ -3218,30 +3139,18 @@ static void EmitInt32ShiftLeft(FlowGraphCompiler* compiler,
// shll operation masks the count to 5 bits.
const intptr_t kCountLimit = 0x1F;
const intptr_t value = Smi::Cast(constant).Value();
- if (value == 0) {
- // No code needed.
- } else if ((value < 0) || (value >= kCountLimit)) {
- // This condition may not be known earlier in some cases because
- // of constant propagation, inlining, etc.
- if ((value >= kCountLimit) && is_truncating) {
- __ xorl(result, result);
- } else {
- // Result is Mint or exception.
- __ jmp(deopt);
- }
- } else {
- if (!is_truncating) {
- // Check for overflow.
- Register temp = locs.temp(0).reg();
- __ movl(temp, left);
- __ shll(left, Immediate(value));
- __ sarl(left, Immediate(value));
- __ cmpl(left, temp);
- __ j(NOT_EQUAL, deopt); // Overflow.
- }
- // Shift for result now we know there is no overflow.
+ ASSERT((0 < value) && (value < kCountLimit));
+ if (shift_left->can_overflow()) {
+ // Check for overflow.
+ Register temp = locs.temp(0).reg();
+ __ movl(temp, left);
__ shll(left, Immediate(value));
+ __ sarl(left, Immediate(value));
+ __ cmpl(left, temp);
+ __ j(NOT_EQUAL, deopt); // Overflow.
}
+ // Shift for result now we know there is no overflow.
+ __ shll(left, Immediate(value));
}
@@ -3264,67 +3173,30 @@ void BinaryInt32OpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
ASSERT(constant.IsSmi());
const intptr_t value = Smi::Cast(constant).Value();
switch (op_kind()) {
- case Token::kADD:
- if (value != 0) {
- // Checking overflow without emitting an instruction would be wrong.
- __ addl(left, Immediate(value));
- if (deopt != NULL) __ j(OVERFLOW, deopt);
- }
+ case Token::kADD:
+ case Token::kSUB:
+ case Token::kMUL:
+ case Token::kBIT_AND:
+ case Token::kBIT_OR:
+ case Token::kBIT_XOR:
+ EmitIntegerArithmetic(compiler,
+ op_kind(),
+ left,
+ Immediate(value),
+ deopt);
break;
- case Token::kSUB: {
- if (value != 0) {
- // Checking overflow without emitting an instruction would be wrong.
- __ subl(left, Immediate(value));
- if (deopt != NULL) __ j(OVERFLOW, deopt);
- }
- break;
- }
- case Token::kMUL: {
- if (value == 2) {
- __ shll(left, Immediate(1));
- } else {
- __ imull(left, Immediate(value));
- }
- if (deopt != NULL) __ j(OVERFLOW, deopt);
- break;
- }
+
+
+
case Token::kTRUNCDIV: {
UNREACHABLE();
break;
}
- case Token::kBIT_AND: {
- // No overflow check.
- __ andl(left, Immediate(value));
- break;
- }
- case Token::kBIT_OR: {
- // No overflow check.
- __ orl(left, Immediate(value));
- break;
- }
- case Token::kBIT_XOR: {
- // No overflow check.
- __ xorl(left, Immediate(value));
- break;
- }
+
case Token::kSHR: {
// sarl operation masks the count to 5 bits.
const intptr_t kCountLimit = 0x1F;
- if (value == 0) {
- // TODO(vegorov): should be handled outside.
- break;
- } else if (value < 0) {
- // TODO(vegorov): should be handled outside.
- __ jmp(deopt);
- break;
- }
-
- if (value >= kCountLimit) {
- __ sarl(left, Immediate(kCountLimit));
- } else {
- __ sarl(left, Immediate(value));
- }
-
+ __ sarl(left, Immediate(Utils::Minimum(value, kCountLimit)));
break;
}
@@ -3337,104 +3209,76 @@ void BinaryInt32OpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
if (locs()->in(1).IsStackSlot()) {
const Address& right = locs()->in(1).ToStackSlotAddress();
- switch (op_kind()) {
- case Token::kADD: {
- __ addl(left, right);
- if (deopt != NULL) __ j(OVERFLOW, deopt);
- break;
- }
- case Token::kSUB: {
- __ subl(left, right);
- if (deopt != NULL) __ j(OVERFLOW, deopt);
- break;
- }
- case Token::kMUL: {
- __ imull(left, right);
- if (deopt != NULL) __ j(OVERFLOW, deopt);
- break;
- }
- case Token::kBIT_AND: {
- // No overflow check.
- __ andl(left, right);
- break;
- }
- case Token::kBIT_OR: {
- // No overflow check.
- __ orl(left, right);
- break;
- }
- case Token::kBIT_XOR: {
- // No overflow check.
- __ xorl(left, right);
- break;
- }
- default:
- UNREACHABLE();
- }
+ EmitIntegerArithmetic(compiler,
+ op_kind(),
+ left,
+ right,
+ deopt);
return;
} // if locs()->in(1).IsStackSlot.
// if locs()->in(1).IsRegister.
Register right = locs()->in(1).reg();
switch (op_kind()) {
- case Token::kADD: {
- __ addl(left, right);
- if (deopt != NULL) __ j(OVERFLOW, deopt);
- break;
- }
- case Token::kSUB: {
- __ subl(left, right);
- if (deopt != NULL) __ j(OVERFLOW, deopt);
- break;
- }
- case Token::kMUL: {
- __ imull(left, right);
- if (deopt != NULL) __ j(OVERFLOW, deopt);
- break;
- }
- case Token::kBIT_AND: {
- // No overflow check.
- __ andl(left, right);
- break;
- }
- case Token::kBIT_OR: {
- // No overflow check.
- __ orl(left, right);
- break;
- }
- case Token::kBIT_XOR: {
- // No overflow check.
- __ xorl(left, right);
- break;
- }
- case Token::kTRUNCDIV: {
- UNREACHABLE();
- break;
- }
- case Token::kMOD: {
- UNREACHABLE();
- break;
- }
- case Token::kSHR: {
- UNREACHABLE();
+ case Token::kADD:
+ case Token::kSUB:
+ case Token::kMUL:
+ case Token::kBIT_AND:
+ case Token::kBIT_OR:
+ case Token::kBIT_XOR:
+ EmitIntegerArithmetic(compiler,
+ op_kind(),
+ left,
+ right,
+ deopt);
break;
- }
- case Token::kDIV: {
- // Dispatches to 'Double./'.
- // TODO(srdjan): Implement as conversion to double and double division.
+
+ default:
UNREACHABLE();
break;
- }
- case Token::kOR:
- case Token::kAND: {
- // Flow graph builder has dissected this operation to guarantee correct
- // behavior (short-circuit evaluation).
- UNREACHABLE();
+ }
+}
+
+
+LocationSummary* BinaryUint32OpInstr::MakeLocationSummary(Isolate* isolate,
+ bool opt) const {
+ const intptr_t kNumInputs = 2;
+ const intptr_t kNumTemps = (op_kind() == Token::kMUL) ? 1 : 0;
+ LocationSummary* summary = new(isolate) LocationSummary(
+ isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ if (op_kind() == Token::kMUL) {
+ summary->set_in(0, Location::RegisterLocation(EAX));
+ summary->set_temp(0, Location::RegisterLocation(EDX));
+ } else {
+ summary->set_in(0, Location::RequiresRegister());
+ }
+ summary->set_in(1, Location::RequiresRegister());
+ summary->set_out(0, Location::SameAsFirstInput());
+ return summary;
+}
+
+
+void BinaryUint32OpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ Register left = locs()->in(0).reg();
+ Register right = locs()->in(1).reg();
+ Register out = locs()->out(0).reg();
+ ASSERT(out == left);
+ switch (op_kind()) {
+ case Token::kBIT_AND:
+ case Token::kBIT_OR:
+ case Token::kBIT_XOR:
+ case Token::kADD:
+ case Token::kSUB:
+ EmitIntegerArithmetic(compiler, op_kind(), left, right, NULL);
+ return;
+
+ case Token::kMUL:
+ __ mull(right); // Result in EDX:EAX.
+ ASSERT(out == EAX);
+ ASSERT(locs()->temp(0).reg() == EDX);
break;
- }
default:
UNREACHABLE();
- break;
}
}
@@ -6229,56 +6073,6 @@ CompileType UnaryUint32OpInstr::ComputeType() const {
}
-LocationSummary* BinaryUint32OpInstr::MakeLocationSummary(Isolate* isolate,
- bool opt) const {
- const intptr_t kNumInputs = 2;
- const intptr_t kNumTemps = (op_kind() == Token::kMUL) ? 1 : 0;
- LocationSummary* summary = new(isolate) LocationSummary(
- isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
- if (op_kind() == Token::kMUL) {
- summary->set_in(0, Location::RegisterLocation(EAX));
- summary->set_temp(0, Location::RegisterLocation(EDX));
- } else {
- summary->set_in(0, Location::RequiresRegister());
- }
- summary->set_in(1, Location::RequiresRegister());
- summary->set_out(0, Location::SameAsFirstInput());
- return summary;
-}
-
-
-void BinaryUint32OpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- Register left = locs()->in(0).reg();
- Register right = locs()->in(1).reg();
- Register out = locs()->out(0).reg();
- ASSERT(out == left);
- switch (op_kind()) {
- case Token::kBIT_AND:
- __ andl(out, right);
- break;
- case Token::kBIT_OR:
- __ orl(out, right);
- break;
- case Token::kBIT_XOR:
- __ xorl(out, right);
- break;
- case Token::kADD:
- __ addl(out, right);
- break;
- case Token::kSUB:
- __ subl(out, right);
- break;
- case Token::kMUL:
- __ mull(right); // Result in EDX:EAX.
- ASSERT(out == EAX);
- ASSERT(locs()->temp(0).reg() == EDX);
- break;
- default:
- UNREACHABLE();
- }
-}
-
-
LocationSummary* ShiftUint32OpInstr::MakeLocationSummary(Isolate* isolate,
bool opt) const {
const intptr_t kNumInputs = 2;

Powered by Google App Engine
This is Rietveld 408576698