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

Unified Diff: runtime/vm/intermediate_language_ia32.cc

Issue 12218181: Recognize pattern (a << b) & c with c being a positive Smi and allow left shift to truncate the res… (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 10 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
===================================================================
--- runtime/vm/intermediate_language_ia32.cc (revision 18774)
+++ runtime/vm/intermediate_language_ia32.cc (working copy)
@@ -1999,6 +1999,131 @@
}
+static void EmitSmiShiftLeft(FlowGraphCompiler* compiler,
+ BinarySmiOpInstr* shift_left) {
+ const bool is_truncating = shift_left->is_truncating();
+ const LocationSummary& locs = *shift_left->locs();
+ Register left = locs.in(0).reg();
+ Register result = locs.out().reg();
+ ASSERT(left == result);
+ Label* deopt = shift_left->CanDeoptimize() ?
+ compiler->AddDeoptStub(shift_left->deopt_id(), kDeoptBinarySmiOp) : NULL;
+ if (locs.in(1).IsConstant()) {
+ const Object& constant = locs.in(1).constant();
+ ASSERT(constant.IsSmi());
+ // 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.
+ __ 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 left is constant, we know the maximal allowed size for right.
+ const Object& obj = shift_left->left()->BoundConstant();
+ if (obj.IsSmi()) {
+ const intptr_t left_int = Smi::Cast(obj).Value();
+ if (left_int == 0) {
+ __ cmpl(right, Immediate(0));
+ __ j(NEGATIVE, deopt);
+ return;
+ }
+ intptr_t tmp = (left_int > 0) ? left_int : ~left_int;
+ intptr_t max_right = kSmiBits;
+ while ((tmp >>= 1) != 0) {
+ max_right--;
+ }
+ const bool right_needs_check =
+ (right_range == NULL) ||
+ !right_range->IsWithin(0, max_right - 1);
+ if (right_needs_check) {
+ __ cmpl(right,
+ Immediate(reinterpret_cast<int32_t>(Smi::New(max_right))));
+ __ j(ABOVE_EQUAL, deopt);
+ }
+ __ SmiUntag(right);
+ __ shll(left, right);
+ }
+ return;
+ }
+
+ const bool right_needs_check =
+ (right_range == NULL) || !right_range->IsWithin(0, (Smi::kBits - 1));
+ ASSERT(right == ECX); // Count must be in ECX
+ if (is_truncating) {
+ if (right_needs_check) {
+ const bool right_may_be_negative =
+ (right_range == NULL) ||
+ !right_range->IsWithin(0, RangeBoundary::kPlusInfinity);
+ if (right_may_be_negative) {
+ ASSERT(shift_left->CanDeoptimize());
+ __ cmpl(right, Immediate(0));
+ __ j(NEGATIVE, deopt);
+ }
+ Label done, is_not_zero;
+ __ cmpl(right,
+ Immediate(reinterpret_cast<int32_t>(Smi::New(Smi::kBits))));
+ __ j(BELOW, &is_not_zero, Assembler::kNearJump);
+ __ xorl(left, left);
+ __ jmp(&done, Assembler::kNearJump);
+ __ Bind(&is_not_zero);
+ __ SmiUntag(right);
+ __ shll(left, right);
+ __ Bind(&done);
+ } else {
+ __ SmiUntag(right);
+ __ shll(left, right);
+ }
+ } else {
+ if (right_needs_check) {
+ ASSERT(shift_left->CanDeoptimize());
+ __ cmpl(right,
+ Immediate(reinterpret_cast<int32_t>(Smi::New(Smi::kBits))));
+ __ j(ABOVE_EQUAL, deopt);
+ }
+ // Left is not a constant.
+ Register temp = locs.temp(0).reg();
+ // Check if count too large for handling it inlined.
+ __ movl(temp, left);
+ __ SmiUntag(right);
+ // Overflow test (preserve temp and right);
+ __ shll(left, right);
+ __ sarl(left, right);
+ __ cmpl(left, temp);
+ __ j(NOT_EQUAL, deopt); // Overflow.
+ // Shift for result now we know there is no overflow.
+ __ shll(left, right);
+ }
+}
+
+
LocationSummary* BinarySmiOpInstr::MakeLocationSummary() const {
const intptr_t kNumInputs = 2;
if (op_kind() == Token::kTRUNCDIV) {
@@ -2029,12 +2154,14 @@
summary->set_out(Location::SameAsFirstInput());
return summary;
} else if (op_kind() == Token::kSHL) {
- const intptr_t kNumTemps = 1;
+ const intptr_t kNumTemps = is_truncating() ? 0 : 1;
LocationSummary* summary =
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
summary->set_in(0, Location::RequiresRegister());
summary->set_in(1, Location::FixedRegisterOrSmiConstant(right(), ECX));
- summary->set_temp(0, Location::RequiresRegister());
+ if (!is_truncating()) {
+ summary->set_temp(0, Location::RequiresRegister());
+ }
summary->set_out(Location::SameAsFirstInput());
return summary;
} else {
@@ -2050,6 +2177,12 @@
void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ if (op_kind() == Token::kSHL) {
+ EmitSmiShiftLeft(compiler, this);
+ return;
+ }
+
+ ASSERT(!is_truncating());
Register left = locs()->in(0).reg();
Register result = locs()->out().reg();
ASSERT(left == result);
@@ -2147,27 +2280,6 @@
__ SmiTag(left);
break;
}
- case Token::kSHL: {
- // shll operation masks the count to 5 bits.
- const intptr_t kCountLimit = 0x1F;
- intptr_t value = Smi::Cast(constant).Value();
- if (value == 0) break;
- if ((value < 0) || (value >= kCountLimit)) {
- // This condition may not be known earlier in some cases because
- // of constant propagation, inlining, etc.
- __ jmp(deopt);
- break;
- }
- 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));
- break;
- }
default:
UNREACHABLE();
@@ -2251,57 +2363,6 @@
__ SmiTag(left);
break;
}
- case Token::kSHL: {
- Range* right_range = this->right()->definition()->range();
- if (this->left()->BindsToConstant()) {
- // If left is constant, we know the maximal allowed size for right.
- const Object& obj = this->left()->BoundConstant();
- if (obj.IsSmi()) {
- const intptr_t left_int = Smi::Cast(obj).Value();
- if (left_int == 0) {
- __ cmpl(right, Immediate(0));
- __ j(NEGATIVE, deopt);
- break;
- }
- intptr_t tmp = (left_int > 0) ? left_int : ~left_int;
- intptr_t max_right = kSmiBits;
- while ((tmp >>= 1) != 0) {
- max_right--;
- }
- const bool right_needs_check =
- (right_range == NULL) ||
- !right_range->IsWithin(0, max_right - 1);
- if (right_needs_check) {
- __ cmpl(right,
- Immediate(reinterpret_cast<int32_t>(Smi::New(max_right))));
- __ j(ABOVE_EQUAL, deopt);
- }
- __ SmiUntag(right);
- __ shll(left, right);
- break;
- }
- }
- Register temp = locs()->temp(0).reg();
- // Check if count too large for handling it inlined.
- __ movl(temp, left);
- const bool right_needs_check =
- (right_range == NULL) || !right_range->IsWithin(0, (Smi::kBits - 1));
- if (right_needs_check) {
- __ cmpl(right,
- Immediate(reinterpret_cast<int32_t>(Smi::New(Smi::kBits))));
- __ j(ABOVE_EQUAL, deopt);
- }
- ASSERT(right == ECX); // Count must be in ECX
- __ SmiUntag(right);
- // Overflow test (preserve temp and right);
- __ shll(left, right);
- __ sarl(left, right);
- __ cmpl(left, temp);
- __ j(NOT_EQUAL, deopt); // Overflow.
- // Shift for result now we know there is no overflow.
- __ shll(left, right);
- break;
- }
case Token::kDIV: {
// Dispatches to 'Double./'.
// TODO(srdjan): Implement as conversion to double and double division.

Powered by Google App Engine
This is Rietveld 408576698