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

Unified Diff: runtime/vm/intermediate_language_ia32.cc

Issue 10542079: Implement Smi binops ia32 (new compiler). (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 6 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 8442)
+++ runtime/vm/intermediate_language_ia32.cc (working copy)
@@ -754,25 +754,212 @@
LocationSummary* BinaryOpComp::MakeLocationSummary() const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
- LocationSummary* summary = new LocationSummary(kNumInputs, kNumTemps);
- summary->set_in(0, Location::RequiresRegister());
- summary->set_in(1, Location::RequiresRegister());
- summary->set_out(Location::SameAsFirstInput());
- return summary;
+ if (operands_type() == kDoubleOperands) {
+ LocationSummary* summary = new LocationSummary(kNumInputs, kNumTemps);
+ summary->set_in(0, Location::RequiresRegister());
+ summary->set_in(1, Location::RequiresRegister());
+ summary->set_out(Location::SameAsFirstInput());
+ return summary;
+ }
+ ASSERT(operands_type() == kSmiOperands);
+ if (op_kind() == Token::kTRUNCDIV) {
+ const intptr_t kNumTemps = 3;
+ LocationSummary* summary = new LocationSummary(kNumInputs, kNumTemps);
+ summary->set_in(0, Location::RegisterLocation(EAX));
+ summary->set_in(1, Location::RegisterLocation(ECX));
+ summary->set_out(Location::SameAsFirstInput());
+ summary->set_temp(0, Location::RegisterLocation(EBX));
+ // Will be used for for sign extension.
+ summary->set_temp(1, Location::RegisterLocation(EDX));
+ summary->set_temp(2, Location::RequiresRegister());
+ return summary;
+ } else if (op_kind() == Token::kSHR) {
+ const intptr_t kNumTemps = 1;
+ LocationSummary* summary = new LocationSummary(kNumInputs, kNumTemps);
+ summary->set_in(0, Location::RequiresRegister());
+ summary->set_in(1, Location::RegisterLocation(ECX));
+ summary->set_out(Location::SameAsFirstInput());
+ summary->set_temp(0, Location::RequiresRegister());
+ return summary;
+ } else if (op_kind() == Token::kSHL) {
+ const intptr_t kNumTemps = 2;
+ LocationSummary* summary = new LocationSummary(kNumInputs, kNumTemps);
+ summary->set_in(0, Location::RequiresRegister());
+ summary->set_in(1, Location::RequiresRegister());
+ summary->set_out(Location::SameAsFirstInput());
+ summary->set_temp(0, Location::RequiresRegister());
+ summary->set_temp(1, Location::RegisterLocation(ECX));
+ return summary;
+ } else {
+ const intptr_t kNumTemps = 1;
+ LocationSummary* summary = new LocationSummary(kNumInputs, kNumTemps);
+ summary->set_in(0, Location::RequiresRegister());
+ summary->set_in(1, Location::RequiresRegister());
+ summary->set_out(Location::SameAsFirstInput());
+ summary->set_temp(0, Location::RequiresRegister());
+ return summary;
+ }
}
-void BinaryOpComp::EmitNativeCode(FlowGraphCompiler* compiler) {
+static void EmitSmiBinaryOp(FlowGraphCompiler* compiler, BinaryOpComp* comp) {
+ Register left = comp->locs()->in(0).reg();
+ Register right = comp->locs()->in(1).reg();
+ Register result = comp->locs()->out().reg();
+ Register temp = comp->locs()->temp(0).reg();
+ ASSERT(left == result);
+ Label* deopt = compiler->AddDeoptStub(comp->instance_call()->cid(),
+ comp->instance_call()->token_index(),
+ comp->instance_call()->try_index(),
+ kDeoptSmiBinaryOp,
+ temp,
+ right);
+ __ movl(temp, left);
+ __ orl(left, right);
+ __ testl(left, Immediate(kSmiTagMask));
+ __ j(NOT_ZERO, deopt);
+ __ movl(left, temp);
+ switch (comp->op_kind()) {
+ case Token::kADD: {
+ __ addl(left, right);
+ __ j(OVERFLOW, deopt);
+ break;
+ }
+ case Token::kSUB: {
+ __ subl(left, right);
+ __ j(OVERFLOW, deopt);
+ break;
+ }
+ case Token::kMUL: {
+ __ SmiUntag(left);
+ __ imull(left, right);
+ __ 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: {
+ // Handle divide by zero in runtime.
+ // Deoptimization requires that temp and right are preserved.
+ __ testl(right, right);
+ __ j(ZERO, deopt);
+ ASSERT(left == EAX);
+ ASSERT((right != EDX) && (right != EAX));
+ ASSERT((temp != EDX) && (temp != EAX));
+ ASSERT(comp->locs()->temp(1).reg() == EDX);
+ ASSERT(result == EAX);
+ Register right_temp = comp->locs()->temp(2).reg();
+ __ movl(right_temp, right);
+ __ SmiUntag(left);
+ __ SmiUntag(right_temp);
+ __ cdq(); // Sign extend EAX -> EDX:EAX.
+ __ idivl(right_temp); // EAX: quotient, EDX: remainder.
+ // Check the corner case of dividing the 'MIN_SMI' with -1, in which
+ // case we cannot tag the result.
+ __ cmpl(result, Immediate(0x40000000));
+ __ j(EQUAL, deopt);
+ __ SmiTag(result);
+ break;
+ }
+ case Token::kSHR: {
+ // The count is masked to 5 bits on ia32.
+ const Immediate kCountLimit = Immediate(0x1F);
+ __ cmpl(right, Immediate(0));
+ __ j(LESS, deopt);
+ __ SmiUntag(right);
+ __ cmpl(right, kCountLimit);
+ Label count_ok;
+ __ j(LESS, &count_ok, Assembler::kNearJump);
+ __ movl(right, kCountLimit);
+ __ Bind(&count_ok);
+ ASSERT(right == ECX); // Count must be in ECX
+ __ SmiUntag(left);
+ __ sarl(left, right);
+ __ SmiTag(left);
+ break;
+ }
+ case Token::kSHL: {
+ // Check if count too large for handling it inlined.
+ __ cmpl(right,
+ Immediate(reinterpret_cast<int64_t>(Smi::New(Smi::kBits))));
+ __ j(ABOVE_EQUAL, deopt);
+ Register right_temp = comp->locs()->temp(1).reg();
+ ASSERT(right_temp == ECX); // Count must be in ECX
+ __ movl(right_temp, right);
+ __ SmiUntag(right_temp);
+ // Overflow test (preserve temp and right);
+ __ shll(left, right_temp);
+ __ sarl(left, right_temp);
+ __ cmpl(left, temp);
+ __ j(NOT_EQUAL, deopt); // Overflow.
+ // Shift for result now we know there is no overflow.
+ __ shll(left, right_temp);
+ break;
+ }
+ case Token::kDIV: {
+ // Dispatches to 'Double./'.
+ // TODO(srdjan): Implement as conversion to double and double division.
+ UNREACHABLE();
+ break;
+ }
+ case Token::kMOD: {
+ // TODO(srdjan): Implement.
+ UNREACHABLE();
+ break;
+ }
+ case Token::kOR:
+ case Token::kAND: {
+ // Flow graph builder has dissected this operation to guarantee correct
+ // behavior (short-circuit evaluation).
+ UNREACHABLE();
+ break;
+ }
+ default:
+ UNREACHABLE();
+ break;
+ }
+}
+
+
+static void EmitDoubleBinaryOp(FlowGraphCompiler* compiler,
+ BinaryOpComp* comp) {
// TODO(srdjan): Remove this code once BinaryOpComp has been implemeneted
// for all intended operations.
- Register left = locs()->in(0).reg();
- Register right = locs()->in(1).reg();
+ Register left = comp->locs()->in(0).reg();
+ Register right = comp->locs()->in(1).reg();
__ pushl(left);
__ pushl(right);
- InstanceCallComp* instance_call_comp = instance_call();
+ InstanceCallComp* instance_call_comp = comp->instance_call();
instance_call_comp->EmitNativeCode(compiler);
- if (locs()->out().reg() != EAX) {
- __ movl(locs()->out().reg(), EAX);
+ __ MoveRegister(comp->locs()->out().reg(), EAX);
+}
+
+
+void BinaryOpComp::EmitNativeCode(FlowGraphCompiler* compiler) {
+ switch (operands_type()) {
+ case kSmiOperands:
+ EmitSmiBinaryOp(compiler, this);
+ break;
+
+ case kDoubleOperands:
+ EmitDoubleBinaryOp(compiler, this);
+ break;
+
+ default:
+ UNREACHABLE();
}
}

Powered by Google App Engine
This is Rietveld 408576698