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

Unified Diff: runtime/vm/intermediate_language_x64.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_x64.cc
===================================================================
--- runtime/vm/intermediate_language_x64.cc (revision 18705)
+++ runtime/vm/intermediate_language_x64.cc (working copy)
@@ -1817,6 +1817,132 @@
}
+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 6 bits.
+ const intptr_t kCountLimit = 0x3F;
+ 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) {
+ __ xorq(result, result);
+ } else {
+ // Result is Mint or exception.
+ __ jmp(deopt);
+ }
+ } else {
+ if (is_truncating) {
+ __ shlq(left, Immediate(value));
+ } else {
+ Register temp = locs.temp(0).reg();
+ __ movq(temp, left);
+ __ shlq(left, Immediate(value));
+ __ sarq(left, Immediate(value));
+ __ cmpq(left, temp);
+ __ j(NOT_EQUAL, deopt); // Overflow.
+ // Shift for result now we know there is no overflow.
+ __ shlq(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) {
+ __ cmpq(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) {
+ __ cmpq(right,
+ Immediate(reinterpret_cast<int64_t>(Smi::New(max_right))));
+ __ j(ABOVE_EQUAL, deopt);
+ }
+ __ SmiUntag(right);
+ __ shlq(left, right);
+ }
+ return;
+ }
+
+ const bool right_needs_check =
+ (right_range == NULL) || !right_range->IsWithin(0, (Smi::kBits - 1));
+ ASSERT(right == RCX); // Count must be in RCX
+ 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());
+ __ cmpq(right, Immediate(0));
+ __ j(NEGATIVE, deopt);
+ }
+ Label done, is_not_zero;
+ __ cmpq(right,
+ Immediate(reinterpret_cast<int64_t>(Smi::New(Smi::kBits))));
+ __ j(BELOW, &is_not_zero, Assembler::kNearJump);
+ __ xorq(left, left);
+ __ jmp(&done, Assembler::kNearJump);
+ __ Bind(&is_not_zero);
+ __ SmiUntag(right);
+ __ shlq(left, right);
+ __ Bind(&done);
+ } else {
+ __ SmiUntag(right);
+ __ shlq(left, right);
+ }
+ } else {
+ if (right_needs_check) {
+ ASSERT(shift_left->CanDeoptimize());
+ __ cmpq(right,
+ Immediate(reinterpret_cast<int64_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.
+ __ movq(temp, left);
+ __ SmiUntag(right);
+ // Overflow test (preserve temp and right);
+ __ shlq(left, right);
+ __ sarq(left, right);
+ __ cmpq(left, temp);
+ __ j(NOT_EQUAL, deopt); // Overflow.
+ // Shift for result now we know there is no overflow.
+ __ shlq(left, right);
+ }
+}
+
+
static bool CanBeImmediate(const Object& constant) {
return constant.IsSmi() &&
Immediate(reinterpret_cast<int64_t>(constant.raw())).is_int32();
@@ -1869,12 +1995,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(), RCX));
- summary->set_temp(0, Location::RequiresRegister());
+ if (!is_truncating()) {
+ summary->set_temp(0, Location::RequiresRegister());
+ }
summary->set_out(Location::SameAsFirstInput());
return summary;
} else {
@@ -1889,6 +2017,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);
@@ -1990,27 +2124,6 @@
__ SmiTag(left);
break;
}
- case Token::kSHL: {
- // shlq operation masks the count to 6 bits.
- const intptr_t kCountLimit = 0x3F;
- 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();
- __ movq(temp, left);
- __ shlq(left, Immediate(value));
- __ sarq(left, Immediate(value));
- __ cmpq(left, temp);
- __ j(NOT_EQUAL, deopt); // Overflow.
- // Shift for result now we know there is no overflow.
- __ shlq(left, Immediate(value));
- break;
- }
default:
UNREACHABLE();
@@ -2094,57 +2207,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) {
- __ cmpq(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) {
- __ cmpq(right,
- Immediate(reinterpret_cast<int64_t>(Smi::New(max_right))));
- __ j(ABOVE_EQUAL, deopt);
- }
- __ SmiUntag(right);
- __ shlq(left, right);
- break;
- }
- }
- Register temp = locs()->temp(0).reg();
- // Check if count too large for handling it inlined.
- __ movq(temp, left);
- const bool right_needs_check =
- (right_range == NULL) || !right_range->IsWithin(0, (Smi::kBits - 1));
- if (right_needs_check) {
- __ cmpq(right,
- Immediate(reinterpret_cast<int64_t>(Smi::New(Smi::kBits))));
- __ j(ABOVE_EQUAL, deopt);
- }
- ASSERT(right == RCX); // Count must be in RCX
- __ SmiUntag(right);
- // Overflow test (preserve temp and right);
- __ shlq(left, right);
- __ sarq(left, right);
- __ cmpq(left, temp);
- __ j(NOT_EQUAL, deopt); // Overflow.
- // Shift for result now we know there is no overflow.
- __ shlq(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