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

Unified Diff: runtime/vm/intermediate_language_mips.cc

Issue 15934025: Enables more VM tests for SIMMIPS. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 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
« no previous file with comments | « runtime/vm/intermediate_language_arm.cc ('k') | runtime/vm/intrinsifier_arm.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/intermediate_language_mips.cc
===================================================================
--- runtime/vm/intermediate_language_mips.cc (revision 23873)
+++ runtime/vm/intermediate_language_mips.cc (working copy)
@@ -268,13 +268,37 @@
LocationSummary* ArgumentDefinitionTestInstr::MakeLocationSummary() const {
- UNIMPLEMENTED();
- return NULL;
+ const intptr_t kNumInputs = 1;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* locs =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
+ locs->set_in(0, Location::RegisterLocation(T0));
+ locs->set_out(Location::RegisterLocation(T0));
+ return locs;
}
void ArgumentDefinitionTestInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ Register saved_args_desc = locs()->in(0).reg();
+ Register result = locs()->out().reg();
+
+ __ TraceSimMsg("ArgumentDefinitionTestInstr");
+
+ __ addiu(SP, SP, Immediate(-4 * kWordSize));
+ // Push the result place holder initialized to NULL.
+ __ LoadObject(TMP1, Object::ZoneHandle());
+ __ sw(TMP1, Address(SP, 3 * kWordSize));
+ __ LoadImmediate(TMP1, Smi::RawValue(formal_parameter_index()));
+ __ sw(TMP1, Address(SP, 2 * kWordSize));
+ __ LoadObject(TMP1, formal_parameter_name());
+ __ sw(TMP1, Address(SP, 1 * kWordSize));
+ __ sw(saved_args_desc, Address(SP, 0 * kWordSize));
+ compiler->GenerateCallRuntime(token_pos(),
+ deopt_id(),
+ kArgumentDefinitionTestRuntimeEntry,
+ locs());
+ __ lw(result, Address(SP, 3 * kWordSize)); // Pop bool result.
+ __ addiu(SP, SP, Immediate(4 * kWordSize));
}
@@ -355,7 +379,6 @@
Token::Kind kind,
LocationSummary* locs,
const ICData& original_ic_data) {
- __ TraceSimMsg("EmitEqualityAsInstanceCall");
if (!compiler->is_optimizing()) {
compiler->AddCurrentDescriptor(PcDescriptors::kDeopt,
deopt_id,
@@ -365,7 +388,10 @@
const Array& kNoArgumentNames = Array::Handle();
const int kNumArgumentsChecked = 2;
+ __ TraceSimMsg("EmitEqualityAsInstanceCall");
Label check_identity;
+ __ lw(A1, Address(SP, 1 * kWordSize));
+ __ lw(A0, Address(SP, 0 * kWordSize));
__ beq(A1, NULLREG, &check_identity);
__ beq(A0, NULLREG, &check_identity);
@@ -385,9 +411,6 @@
deopt_id,
kNumArgumentsChecked);
}
- __ addiu(SP, SP, Immediate(-2 * kWordSize));
- __ sw(A1, Address(SP, 1 * kWordSize));
- __ sw(A0, Address(SP, 0 * kWordSize));
compiler->GenerateInstanceCall(deopt_id,
token_pos,
kNumberOfArguments,
@@ -402,6 +425,9 @@
if (compiler->is_optimizing()) {
// No need to update IC data.
Label is_true;
+ __ lw(A1, Address(SP, 1 * kWordSize));
+ __ lw(A0, Address(SP, 0 * kWordSize));
+ __ addiu(SP, SP, Immediate(2 * kWordSize));
__ beq(A1, A0, &is_true);
__ LoadObject(V0, (kind == Token::kEQ) ? Bool::False() : Bool::True());
__ b(&equality_done);
@@ -422,6 +448,7 @@
&StubCode::EqualityWithNullArgLabel(),
PcDescriptors::kRuntimeCall,
locs);
+ __ Drop(2);
}
__ Bind(&check_ne);
if (kind == Token::kNE) {
@@ -458,6 +485,129 @@
}
+static Condition TokenKindToSmiCondition(Token::Kind kind) {
+ switch (kind) {
+ case Token::kEQ: return EQ;
+ case Token::kNE: return NE;
+ case Token::kLT: return LT;
+ case Token::kGT: return GT;
+ case Token::kLTE: return LE;
+ case Token::kGTE: return GE;
+ default:
+ UNREACHABLE();
+ return VS;
+ }
+}
+
+
+// Branches on condition c assuming comparison results in CMPRES and TMP1.
+static void EmitBranchAfterCompare(
+ FlowGraphCompiler* compiler, Condition c, Label* is_true) {
+ switch (c) {
+ case EQ: __ beq(CMPRES, TMP1, is_true); break;
+ case NE: __ bne(CMPRES, TMP1, is_true); break;
+ case GT: __ bne(TMP1, ZR, is_true); break;
+ case GE: __ beq(CMPRES, ZR, is_true); break;
+ case LT: __ bne(CMPRES, ZR, is_true); break;
+ case LE: __ beq(TMP1, ZR, is_true); break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+}
+
+
+// A1: left, also on stack.
+// A0: right, also on stack.
+static void EmitEqualityAsPolymorphicCall(FlowGraphCompiler* compiler,
+ const ICData& orig_ic_data,
+ LocationSummary* locs,
+ BranchInstr* branch,
+ Token::Kind kind,
+ intptr_t deopt_id,
+ intptr_t token_pos) {
+ ASSERT((kind == Token::kEQ) || (kind == Token::kNE));
+ const ICData& ic_data = ICData::Handle(orig_ic_data.AsUnaryClassChecks());
+ ASSERT(ic_data.NumberOfChecks() > 0);
+ ASSERT(ic_data.num_args_tested() == 1);
+ Label* deopt = compiler->AddDeoptStub(deopt_id, kDeoptEquality);
+ Register left = locs->in(0).reg();
+ Register right = locs->in(1).reg();
+ ASSERT(left == A1);
+ ASSERT(right == A0);
+ Register temp = locs->temp(0).reg();
+
+ __ TraceSimMsg("EmitEqualityAsPolymorphicCall");
+
+ LoadValueCid(compiler, temp, left,
+ (ic_data.GetReceiverClassIdAt(0) == kSmiCid) ? NULL : deopt);
+ // 'temp' contains class-id of the left argument.
+ ObjectStore* object_store = Isolate::Current()->object_store();
+ Condition cond = TokenKindToSmiCondition(kind);
+ Label done;
+ const intptr_t len = ic_data.NumberOfChecks();
+ for (intptr_t i = 0; i < len; i++) {
+ // Assert that the Smi is at position 0, if at all.
+ ASSERT((ic_data.GetReceiverClassIdAt(i) != kSmiCid) || (i == 0));
+ Label next_test;
+ if (i < len - 1) {
+ __ BranchNotEqual(temp, ic_data.GetReceiverClassIdAt(i), &next_test);
+ } else {
+ __ BranchNotEqual(temp, ic_data.GetReceiverClassIdAt(i), deopt);
+ }
+ const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(i));
+ if (target.Owner() == object_store->object_class()) {
+ // Object.== is same as ===.
+ __ Drop(2);
+ __ slt(CMPRES, left, right);
+ __ slt(TMP1, right, left);
+ if (branch != NULL) {
+ branch->EmitBranchOnCondition(compiler, cond);
+ } else {
+ Register result = locs->out().reg();
+ Label load_true;
+ EmitBranchAfterCompare(compiler, cond, &load_true);
+ __ LoadObject(result, Bool::False());
+ __ b(&done);
+ __ Bind(&load_true);
+ __ LoadObject(result, Bool::True());
+ }
+ } else {
+ const int kNumberOfArguments = 2;
+ const Array& kNoArgumentNames = Array::Handle();
+ compiler->GenerateStaticCall(deopt_id,
+ token_pos,
+ target,
+ kNumberOfArguments,
+ kNoArgumentNames,
+ locs);
+ if (branch == NULL) {
+ if (kind == Token::kNE) {
+ Label is_true;
+ __ CompareObject(CMPRES, TMP1, V0, Bool::True());
+ __ beq(CMPRES, TMP1, &is_true);
+ __ LoadObject(V0, Bool::True());
+ __ b(&done);
+ __ Bind(&is_true);
+ __ LoadObject(V0, Bool::False());
+ }
+ } else {
+ if (branch->is_checked()) {
+ EmitAssertBoolean(V0, token_pos, deopt_id, locs, compiler);
+ }
+ __ CompareObject(CMPRES, TMP1, V0, Bool::True());
+ branch->EmitBranchOnCondition(compiler, cond);
+ }
+ }
+ if (i < len - 1) {
+ __ b(&done);
+ __ Bind(&next_test);
+ }
+ }
+ __ Bind(&done);
+}
+
+
// Emit code when ICData's targets are all Object == (which is ===).
static void EmitCheckedStrictEqual(FlowGraphCompiler* compiler,
const ICData& ic_data,
@@ -479,48 +629,59 @@
const ICData& ic_data,
intptr_t deopt_id,
intptr_t token_pos) {
- UNIMPLEMENTED();
+ ASSERT((kind == Token::kEQ) || (kind == Token::kNE));
+ ASSERT(!ic_data.IsNull() && (ic_data.NumberOfChecks() > 0));
+ Register left = locs->in(0).reg();
+ Register right = locs->in(1).reg();
+ Label done, identity_compare, non_null_compare;
+ __ TraceSimMsg("EmitGenericEqualityCompare");
+ __ beq(right, NULLREG, &identity_compare);
+ __ bne(left, NULLREG, &non_null_compare);
+
+ // Comparison with NULL is "===".
+ __ Bind(&identity_compare);
+ Condition cond = TokenKindToSmiCondition(kind);
+ __ slt(CMPRES, left, right);
+ __ slt(TMP1, right, left);
+ if (branch != NULL) {
+ branch->EmitBranchOnCondition(compiler, cond);
+ } else {
+ Register result = locs->out().reg();
+ Label load_true;
+ EmitBranchAfterCompare(compiler, cond, &load_true);
+ __ LoadObject(result, Bool::False());
+ __ b(&done);
+ __ Bind(&load_true);
+ __ LoadObject(result, Bool::True());
+ }
+ __ b(&done);
+ __ Bind(&non_null_compare); // Receiver is not null.
+ ASSERT(left == A1);
+ ASSERT(right == A0);
+ __ addiu(SP, SP, Immediate(-2 * kWordSize));
+ __ sw(A1, Address(SP, 1 * kWordSize));
+ __ sw(A0, Address(SP, 0 * kWordSize));
+ EmitEqualityAsPolymorphicCall(compiler, ic_data, locs, branch, kind,
+ deopt_id, token_pos);
+ __ Bind(&done);
}
-static Condition TokenKindToSmiCondition(Token::Kind kind) {
- switch (kind) {
- case Token::kEQ: return EQ;
- case Token::kNE: return NE;
- case Token::kLT: return LT;
- case Token::kGT: return GT;
- case Token::kLTE: return LE;
- case Token::kGTE: return GE;
+static Condition FlipCondition(Condition condition) {
+ switch (condition) {
+ case EQ: return EQ;
+ case NE: return NE;
+ case LT: return GT;
+ case LE: return GE;
+ case GT: return LT;
+ case GE: return LE;
default:
UNREACHABLE();
- return VS;
+ return EQ;
}
}
-// Branches on condition c assuming comparison results in CMPRES and TMP1.
-static void EmitBranchAfterCompare(
- FlowGraphCompiler* compiler, Condition c, Label* is_true) {
- switch (c) {
- case EQ: __ beq(CMPRES, TMP1, is_true); break;
- case NE: __ bne(CMPRES, TMP1, is_true); break;
- case GT: __ bne(TMP1, ZR, is_true); break;
- case GE: __ beq(CMPRES, ZR, is_true); break;
- case LT: __ bne(CMPRES, ZR, is_true); break;
- case LE: __ beq(TMP1, ZR, is_true); break;
- default:
- UNREACHABLE();
- break;
- }
-}
-
-
-static Condition FlipCondition(Condition condition) {
- UNIMPLEMENTED();
- return condition;
-}
-
-
static void EmitSmiComparisonOp(FlowGraphCompiler* compiler,
const LocationSummary& locs,
Token::Kind kind,
@@ -612,6 +773,9 @@
Register right = locs()->in(1).reg();
ASSERT(left == A1);
ASSERT(right == A0);
+ __ addiu(SP, SP, Immediate(-2 * kWordSize));
+ __ sw(A1, Address(SP, 1 * kWordSize));
+ __ sw(A0, Address(SP, 0 * kWordSize));
EmitEqualityAsInstanceCall(compiler,
deopt_id(),
token_pos(),
@@ -655,6 +819,9 @@
Register right = locs()->in(1).reg();
ASSERT(left == A1);
ASSERT(right == A0);
+ __ addiu(SP, SP, Immediate(-2 * kWordSize));
+ __ sw(A1, Address(SP, 1 * kWordSize));
+ __ sw(A0, Address(SP, 0 * kWordSize));
EmitEqualityAsInstanceCall(compiler,
deopt_id(),
token_pos(),
@@ -853,13 +1020,26 @@
LocationSummary* StringFromCharCodeInstr::MakeLocationSummary() const {
- UNIMPLEMENTED();
- return NULL;
+ const intptr_t kNumInputs = 1;
+ // TODO(fschneider): Allow immediate operands for the char code.
+ return LocationSummary::Make(kNumInputs,
+ Location::RequiresRegister(),
+ LocationSummary::kNoCall);
}
void StringFromCharCodeInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ Register char_code = locs()->in(0).reg();
+ Register result = locs()->out().reg();
+
+ __ TraceSimMsg("StringFromCharCodeInstr");
+
+ __ LoadImmediate(result,
+ reinterpret_cast<uword>(Symbols::PredefinedAddress()));
+ __ AddImmediate(result, Symbols::kNullCharCodeSymbolOffset * kWordSize);
+ __ sll(TMP1, char_code, 1); // Char code is a smi.
+ __ addu(TMP1, TMP1, result);
+ __ lw(result, Address(TMP1));
}
@@ -986,6 +1166,7 @@
void LoadIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ __ TraceSimMsg("LoadIndexedInstr");
Register array = locs()->in(0).reg();
Location index = locs()->in(1);
@@ -1745,13 +1926,33 @@
LocationSummary* CloneContextInstr::MakeLocationSummary() const {
- UNIMPLEMENTED();
- return NULL;
+ const intptr_t kNumInputs = 1;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* locs =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
+ locs->set_in(0, Location::RegisterLocation(T0));
+ locs->set_out(Location::RegisterLocation(T0));
+ return locs;
}
void CloneContextInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ Register context_value = locs()->in(0).reg();
+ Register result = locs()->out().reg();
+
+ __ TraceSimMsg("CloneContextInstr");
+
+ __ addiu(SP, SP, Immediate(-2 * kWordSize));
+ __ LoadObject(TMP1, Object::ZoneHandle()); // Make room for the result.
+ __ sw(TMP1, Address(SP, 1 * kWordSize));
+ __ sw(context_value, Address(SP, 0 * kWordSize));
+
+ compiler->GenerateCallRuntime(token_pos(),
+ deopt_id(),
+ kCloneContextRuntimeEntry,
+ locs());
+ __ lw(result, Address(SP, 1 * kWordSize)); // Get result (cloned context).
+ __ addiu(SP, SP, Immediate(2 * kWordSize));
}
@@ -1850,6 +2051,118 @@
}
+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();
+ Label* deopt = shift_left->CanDeoptimize() ?
+ compiler->AddDeoptStub(shift_left->deopt_id(), kDeoptBinarySmiOp) : NULL;
+
+ __ TraceSimMsg("EmitSmiShiftLeft");
+
+ if (locs.in(1).IsConstant()) {
+ const Object& constant = locs.in(1).constant();
+ ASSERT(constant.IsSmi());
+ // Immediate shift operation takes 5 bits for the count.
+ 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) {
+ __ mov(result, ZR);
+ } else {
+ // Result is Mint or exception.
+ __ b(deopt);
+ }
+ } else {
+ if (!is_truncating) {
+ // Check for overflow (preserve left).
+ __ sll(TMP1, left, value);
+ __ sra(TMP1, TMP1, value);
+ __ bne(TMP1, left, deopt); // Overflow.
+ }
+ // Shift for result now we know there is no overflow.
+ __ sll(result, left, 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) {
+ __ bltz(right, deopt);
+ return;
+ }
+ const intptr_t max_right = kSmiBits - Utils::HighestBit(left_int);
+ const bool right_needs_check =
+ (right_range == NULL) ||
+ !right_range->IsWithin(0, max_right - 1);
+ if (right_needs_check) {
+ __ BranchUnsignedGreaterEqual(
+ right, reinterpret_cast<int32_t>(Smi::New(max_right)), deopt);
+ }
+ __ SmiUntag(right);
+ __ sllv(result, left, right);
+ }
+ return;
+ }
+
+ const bool right_needs_check =
+ (right_range == NULL) || !right_range->IsWithin(0, (Smi::kBits - 1));
+ 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());
+ __ bltz(right, deopt);
+ }
+ Label done, is_not_zero;
+
+ __ sltiu(CMPRES,
+ right, Immediate(reinterpret_cast<int32_t>(Smi::New(Smi::kBits))));
+ __ movz(result, ZR, CMPRES); // result = right >= kBits ? 0 : result.
+ __ mov(TMP1, right);
+ __ SmiUntag(TMP1);
+ __ sllv(TMP1, left, TMP1);
+ // result = right < kBits ? left << right : result.
+ __ movn(result, TMP1, CMPRES);
+ } else {
+ __ SmiUntag(right);
+ __ sllv(result, left, right);
+ }
+ } else {
+ if (right_needs_check) {
+ ASSERT(shift_left->CanDeoptimize());
+ __ BranchUnsignedGreaterEqual(
+ right, reinterpret_cast<int32_t>(Smi::New(Smi::kBits)), deopt);
+ }
+ // Left is not a constant.
+ // Check if count too large for handling it inlined.
+ __ SmiUntag(right);
+ // Overflow test (preserve left and right);
+ __ sllv(TMP1, left, right);
+ __ srav(TMP1, TMP1, right);
+ __ bne(TMP1, left, deopt); // Overflow.
+ // Shift for result now we know there is no overflow.
+ __ sllv(result, left, right);
+ }
+}
+
+
LocationSummary* BinarySmiOpInstr::MakeLocationSummary() const {
const intptr_t kNumInputs = 2;
if (op_kind() == Token::kTRUNCDIV) {
@@ -1876,7 +2189,7 @@
void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
__ TraceSimMsg("BinarySmiOpInstr");
if (op_kind() == Token::kSHL) {
- UNIMPLEMENTED();
+ EmitSmiShiftLeft(compiler, this);
return;
}
@@ -1894,6 +2207,7 @@
int32_t imm = reinterpret_cast<int32_t>(constant.raw());
switch (op_kind()) {
case Token::kSUB: {
+ __ TraceSimMsg("kSUB imm");
if (deopt == NULL) {
__ AddImmediate(result, left, -imm);
} else {
@@ -1973,7 +2287,27 @@
break;
}
case Token::kSHR: {
- UNIMPLEMENTED();
+ // sarl operation masks the count to 5 bits.
+ const intptr_t kCountLimit = 0x1F;
+ intptr_t value = Smi::Cast(constant).Value();
+
+ __ TraceSimMsg("kSHR");
+
+ if (value == 0) {
+ // TODO(vegorov): should be handled outside.
+ __ break_(0);
+ break;
+ } else if (value < 0) {
+ // TODO(vegorov): should be handled outside.
+ __ b(deopt);
+ break;
+ }
+
+ value = value + kSmiTagSize;
+ if (value >= kCountLimit) value = kCountLimit;
+
+ __ sra(result, left, value);
+ __ SmiTag(result);
break;
}
@@ -1997,6 +2331,7 @@
break;
}
case Token::kSUB: {
+ __ TraceSimMsg("kSUB");
if (deopt == NULL) {
__ subu(result, left, right);
} else {
@@ -2006,11 +2341,14 @@
break;
}
case Token::kMUL: {
+ __ TraceSimMsg("kMUL");
__ SmiUntag(left);
__ mult(left, right);
__ mflo(result);
if (deopt != NULL) {
- UNIMPLEMENTED();
+ __ mfhi(TMP1);
+ __ sra(CMPRES, result, 31);
+ __ bne(TMP1, CMPRES, deopt);
}
break;
}
@@ -2442,9 +2780,9 @@
void PolymorphicInstanceCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- __ TraceSimMsg("PolymorphicInstanceCallInstr");
Label* deopt = compiler->AddDeoptStub(deopt_id(),
kDeoptPolymorphicInstanceCallTestFail);
+ __ TraceSimMsg("PolymorphicInstanceCallInstr");
if (ic_data().NumberOfChecks() == 0) {
__ b(deopt);
return;
@@ -2826,10 +3164,10 @@
Register result = locs()->out().reg();
Label load_true, done;
if (kind() == Token::kEQ_STRICT) {
- __ beq(CMPRES, ZR, &load_true);
+ __ beq(CMPRES, TMP1, &load_true);
} else {
ASSERT(kind() == Token::kNE_STRICT);
- __ bne(CMPRES, ZR, &load_true);
+ __ bne(CMPRES, TMP1, &load_true);
}
__ LoadObject(result, Bool::False());
__ b(&done);
« no previous file with comments | « runtime/vm/intermediate_language_arm.cc ('k') | runtime/vm/intrinsifier_arm.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698