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

Unified Diff: runtime/vm/intermediate_language_mips.cc

Issue 14076005: Supports FrameLookup vm test on MIPS (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 8 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/flow_graph_compiler_mips.cc ('k') | runtime/vm/resolver_test.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 21219)
+++ runtime/vm/intermediate_language_mips.cc (working copy)
@@ -13,6 +13,7 @@
#include "vm/locations.h"
#include "vm/object_store.h"
#include "vm/parser.h"
+#include "vm/simulator.h"
#include "vm/stub_code.h"
#include "vm/symbols.h"
@@ -194,13 +195,45 @@
LocationSummary* AssertBooleanInstr::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(A0));
+ locs->set_out(Location::RegisterLocation(A0));
+ return locs;
}
+static void EmitAssertBoolean(Register reg,
+ intptr_t token_pos,
+ intptr_t deopt_id,
+ LocationSummary* locs,
+ FlowGraphCompiler* compiler) {
+ // Check that the type of the value is allowed in conditional context.
+ // Call the runtime if the object is not bool::true or bool::false.
+ ASSERT(locs->always_calls());
+ Label done;
+ __ BranchEqual(reg, Bool::True(), &done);
+ __ BranchEqual(reg, Bool::False(), &done);
+
+ __ Push(reg); // Push the source object.
+ compiler->GenerateCallRuntime(token_pos,
+ deopt_id,
+ kConditionTypeErrorRuntimeEntry,
+ locs);
+ // We should never return here.
+ __ break_(0);
+ __ Bind(&done);
+}
+
+
void AssertBooleanInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ Register obj = locs()->in(0).reg();
+ Register result = locs()->out().reg();
+
+ EmitAssertBoolean(obj, token_pos(), deopt_id(), locs(), compiler);
+ ASSERT(obj == result);
}
@@ -216,19 +249,296 @@
LocationSummary* EqualityCompareInstr::MakeLocationSummary() const {
+ const intptr_t kNumInputs = 2;
+ const bool is_checked_strict_equal =
+ HasICData() && ic_data()->AllTargetsHaveSameOwner(kInstanceCid);
+ if (receiver_class_id() == kMintCid) {
+ const intptr_t kNumTemps = 1;
+ LocationSummary* locs =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ locs->set_in(0, Location::RequiresFpuRegister());
+ locs->set_in(1, Location::RequiresFpuRegister());
+ locs->set_temp(0, Location::RequiresRegister());
+ locs->set_out(Location::RequiresRegister());
+ return locs;
+ }
+ if (receiver_class_id() == kDoubleCid) {
+ const intptr_t kNumTemps = 0;
+ LocationSummary* locs =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ locs->set_in(0, Location::RequiresFpuRegister());
+ locs->set_in(1, Location::RequiresFpuRegister());
+ locs->set_out(Location::RequiresRegister());
+ return locs;
+ }
+ if (receiver_class_id() == kSmiCid) {
+ const intptr_t kNumTemps = 0;
+ LocationSummary* locs =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ locs->set_in(0, Location::RegisterOrConstant(left()));
+ // Only one input can be a constant operand. The case of two constant
+ // operands should be handled by constant propagation.
+ locs->set_in(1, locs->in(0).IsConstant()
+ ? Location::RequiresRegister()
+ : Location::RegisterOrConstant(right()));
+ locs->set_out(Location::RequiresRegister());
+ return locs;
+ }
+ if (is_checked_strict_equal) {
+ const intptr_t kNumTemps = 1;
+ LocationSummary* locs =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ locs->set_in(0, Location::RequiresRegister());
+ locs->set_in(1, Location::RequiresRegister());
+ locs->set_temp(0, Location::RequiresRegister());
+ locs->set_out(Location::RequiresRegister());
+ return locs;
+ }
+ if (IsPolymorphic()) {
+ const intptr_t kNumTemps = 1;
+ LocationSummary* locs =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
+ UNIMPLEMENTED(); // TODO(regis): Verify register allocation.
+ return locs;
+ }
+ const intptr_t kNumTemps = 1;
+ LocationSummary* locs =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
+ locs->set_in(0, Location::RegisterLocation(A1));
+ locs->set_in(1, Location::RegisterLocation(A0));
+ locs->set_temp(0, Location::RegisterLocation(T0));
+ locs->set_out(Location::RegisterLocation(V0));
+ return locs;
+}
+
+
+// A1: left.
+// A0: right.
+// Uses T0 to load ic_call_data.
+// Result in V0.
+static void EmitEqualityAsInstanceCall(FlowGraphCompiler* compiler,
+ intptr_t deopt_id,
+ intptr_t token_pos,
+ Token::Kind kind,
+ LocationSummary* locs,
+ const ICData& original_ic_data) {
+ if (!compiler->is_optimizing()) {
+ compiler->AddCurrentDescriptor(PcDescriptors::kDeoptBefore,
+ deopt_id,
+ token_pos);
+ }
+ const int kNumberOfArguments = 2;
+ const Array& kNoArgumentNames = Array::Handle();
+ const int kNumArgumentsChecked = 2;
+
+ Label check_identity;
+ __ LoadImmediate(TMP1, reinterpret_cast<intptr_t>(Object::null()));
+ __ beq(A1, TMP1, &check_identity);
+ __ beq(A0, TMP1, &check_identity);
+
+ ICData& equality_ic_data = ICData::ZoneHandle();
+ if (compiler->is_optimizing() && FLAG_propagate_ic_data) {
+ ASSERT(!original_ic_data.IsNull());
+ if (original_ic_data.NumberOfChecks() == 0) {
+ // IC call for reoptimization populates original ICData.
+ equality_ic_data = original_ic_data.raw();
+ } else {
+ // Megamorphic call.
+ equality_ic_data = original_ic_data.AsUnaryClassChecks();
+ }
+ } else {
+ equality_ic_data = ICData::New(compiler->parsed_function().function(),
+ Symbols::EqualOperator(),
+ 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,
+ kNoArgumentNames,
+ locs,
+ equality_ic_data);
+ Label check_ne;
+ __ b(&check_ne);
+
+ __ Bind(&check_identity);
+ Label equality_done;
+ if (compiler->is_optimizing()) {
+ // No need to update IC data.
+ Label is_true;
+ __ beq(A1, A0, &is_true);
+ __ LoadObject(V0, (kind == Token::kEQ) ? Bool::False() : Bool::True());
+ __ b(&equality_done);
+ __ Bind(&is_true);
+ __ LoadObject(V0, (kind == Token::kEQ) ? Bool::True() : Bool::False());
+ if (kind == Token::kNE) {
+ // Skip not-equal result conversion.
+ __ b(&equality_done);
+ }
+ } else {
+ // Call stub, load IC data in register. The stub will update ICData if
+ // necessary.
+ Register ic_data_reg = locs->temp(0).reg();
+ ASSERT(ic_data_reg == T0); // Stub depends on it.
+ __ LoadObject(ic_data_reg, equality_ic_data);
+ // Pass left in A1 and right in A0.
+ compiler->GenerateCall(token_pos,
+ &StubCode::EqualityWithNullArgLabel(),
+ PcDescriptors::kOther,
+ locs);
+ }
+ __ Bind(&check_ne);
+ if (kind == Token::kNE) {
+ Label true_label, done;
+ // Negate the condition: true label returns false and vice versa.
+ __ BranchEqual(V0, Bool::True(), &true_label);
+ __ LoadObject(V0, Bool::True());
+ __ b(&done);
+ __ Bind(&true_label);
+ __ LoadObject(V0, Bool::False());
+ __ Bind(&done);
+ }
+ __ Bind(&equality_done);
+}
+
+
+// Emit code when ICData's targets are all Object == (which is ===).
+static void EmitCheckedStrictEqual(FlowGraphCompiler* compiler,
+ const ICData& ic_data,
+ const LocationSummary& locs,
+ Token::Kind kind,
+ BranchInstr* branch,
+ intptr_t deopt_id) {
UNIMPLEMENTED();
- return NULL;
}
-void EqualityCompareInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+// First test if receiver is NULL, in which case === is applied.
+// If type feedback was provided (lists of <class-id, target>), do a
+// type by type check (either === or static call to the operator.
+static void EmitGenericEqualityCompare(FlowGraphCompiler* compiler,
+ LocationSummary* locs,
+ Token::Kind kind,
+ BranchInstr* branch,
+ const ICData& ic_data,
+ intptr_t deopt_id,
+ intptr_t token_pos) {
UNIMPLEMENTED();
}
+static void EmitSmiComparisonOp(FlowGraphCompiler* compiler,
+ const LocationSummary& locs,
+ Token::Kind kind,
+ BranchInstr* branch) {
+ UNIMPLEMENTED();
+}
+
+
+static void EmitUnboxedMintEqualityOp(FlowGraphCompiler* compiler,
+ const LocationSummary& locs,
+ Token::Kind kind,
+ BranchInstr* branch) {
+ UNIMPLEMENTED();
+}
+
+
+static void EmitDoubleComparisonOp(FlowGraphCompiler* compiler,
+ const LocationSummary& locs,
+ Token::Kind kind,
+ BranchInstr* branch) {
+ UNIMPLEMENTED();
+}
+
+
+void EqualityCompareInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ ASSERT((kind() == Token::kNE) || (kind() == Token::kEQ));
+ BranchInstr* kNoBranch = NULL;
+ if (receiver_class_id() == kSmiCid) {
+ EmitSmiComparisonOp(compiler, *locs(), kind(), kNoBranch);
+ return;
+ }
+ if (receiver_class_id() == kMintCid) {
+ EmitUnboxedMintEqualityOp(compiler, *locs(), kind(), kNoBranch);
+ return;
+ }
+ if (receiver_class_id() == kDoubleCid) {
+ EmitDoubleComparisonOp(compiler, *locs(), kind(), kNoBranch);
+ return;
+ }
+ const bool is_checked_strict_equal =
+ HasICData() && ic_data()->AllTargetsHaveSameOwner(kInstanceCid);
+ if (is_checked_strict_equal) {
+ EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), kNoBranch,
+ deopt_id());
+ return;
+ }
+ if (IsPolymorphic()) {
+ EmitGenericEqualityCompare(compiler, locs(), kind(), kNoBranch, *ic_data(),
+ deopt_id(), token_pos());
+ return;
+ }
+ Register left = locs()->in(0).reg();
+ Register right = locs()->in(1).reg();
+ ASSERT(left == A1);
+ ASSERT(right == A0);
+ EmitEqualityAsInstanceCall(compiler,
+ deopt_id(),
+ token_pos(),
+ kind(),
+ locs(),
+ *ic_data());
+ ASSERT(locs()->out().reg() == V0);
+}
+
+
void EqualityCompareInstr::EmitBranchCode(FlowGraphCompiler* compiler,
BranchInstr* branch) {
- UNIMPLEMENTED();
+ ASSERT((kind() == Token::kNE) || (kind() == Token::kEQ));
+ if (receiver_class_id() == kSmiCid) {
+ // Deoptimizes if both arguments not Smi.
+ EmitSmiComparisonOp(compiler, *locs(), kind(), branch);
+ return;
+ }
+ if (receiver_class_id() == kMintCid) {
+ EmitUnboxedMintEqualityOp(compiler, *locs(), kind(), branch);
+ return;
+ }
+ if (receiver_class_id() == kDoubleCid) {
+ EmitDoubleComparisonOp(compiler, *locs(), kind(), branch);
+ return;
+ }
+ const bool is_checked_strict_equal =
+ HasICData() && ic_data()->AllTargetsHaveSameOwner(kInstanceCid);
+ if (is_checked_strict_equal) {
+ EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), branch,
+ deopt_id());
+ return;
+ }
+ if (IsPolymorphic()) {
+ EmitGenericEqualityCompare(compiler, locs(), kind(), branch, *ic_data(),
+ deopt_id(), token_pos());
+ return;
+ }
+ Register left = locs()->in(0).reg();
+ Register right = locs()->in(1).reg();
+ ASSERT(left == A1);
+ ASSERT(right == A0);
+ EmitEqualityAsInstanceCall(compiler,
+ deopt_id(),
+ token_pos(),
+ Token::kEQ, // kNE reverse occurs at branch.
+ locs(),
+ *ic_data());
+ if (branch->is_checked()) {
+ EmitAssertBoolean(V0, token_pos(), deopt_id(), locs(), compiler);
+ }
+ Condition branch_condition = (kind() == Token::kNE) ? NE : EQ;
+ __ CompareObject(CMPRES, V0, Bool::True());
+ branch->EmitBranchOnCondition(compiler, branch_condition);
}
@@ -272,10 +582,10 @@
__ PushObject(Object::ZoneHandle());
// Pass a pointer to the first argument in A2.
if (!function().HasOptionalParameters()) {
- __ addiu(A2, FP, Immediate((kLastParamSlotIndex +
- function().NumParameters() - 1) * kWordSize));
+ __ AddImmediate(A2, FP, (kLastParamSlotIndex +
+ function().NumParameters() - 1) * kWordSize);
} else {
- __ addiu(A2, FP, Immediate(kFirstLocalSlotIndex * kWordSize));
+ __ AddImmediate(A2, FP, kFirstLocalSlotIndex * kWordSize);
}
// Compute the effective address. When running under the simulator,
// this is a redirection address that forces the simulator to call
@@ -719,7 +1029,7 @@
void BranchInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ comparison()->EmitBranchCode(compiler, this);
}
@@ -835,25 +1145,79 @@
LocationSummary* GotoInstr::MakeLocationSummary() const {
- UNIMPLEMENTED();
- return NULL;
+ return new LocationSummary(0, 0, LocationSummary::kNoCall);
}
void GotoInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ // Add deoptimization descriptor for deoptimizing instructions
+ // that may be inserted before this instruction.
+ if (!compiler->is_optimizing()) {
+ compiler->AddCurrentDescriptor(PcDescriptors::kDeoptBefore,
+ GetDeoptId(),
+ 0); // No token position.
+ }
+
+ if (HasParallelMove()) {
+ compiler->parallel_move_resolver()->EmitNativeCode(parallel_move());
+ }
+
+ // We can fall through if the successor is the next block in the list.
+ // Otherwise, we need a jump.
+ if (!compiler->CanFallThroughTo(successor())) {
+ __ b(compiler->GetJumpLabel(successor()));
+ }
}
+static Condition NegateCondition(Condition condition) {
+ switch (condition) {
+ case EQ: return NE;
+ case NE: return EQ;
+ default:
+ OS::Print("Error: Condition not recognized: %d\n", condition);
+ UNIMPLEMENTED();
+ return EQ;
+ }
+}
+
+
void ControlInstruction::EmitBranchOnValue(FlowGraphCompiler* compiler,
bool value) {
- UNIMPLEMENTED();
+ if (value && !compiler->CanFallThroughTo(true_successor())) {
+ __ b(compiler->GetJumpLabel(true_successor()));
+ } else if (!value && !compiler->CanFallThroughTo(false_successor())) {
+ __ b(compiler->GetJumpLabel(false_successor()));
+ }
}
+// The comparison result is in CMPRES.
void ControlInstruction::EmitBranchOnCondition(FlowGraphCompiler* compiler,
Condition true_condition) {
- UNIMPLEMENTED();
+ if (compiler->CanFallThroughTo(false_successor())) {
+ // If the next block is the false successor we will fall through to it.
+ if (true_condition == EQ) {
+ __ beq(CMPRES, ZR, compiler->GetJumpLabel(true_successor()));
+ } else {
+ ASSERT(true_condition == NE);
+ __ bne(CMPRES, ZR, compiler->GetJumpLabel(true_successor()));
+ }
+ } else {
+ // If the next block is the true successor we negate comparison and fall
+ // through to it.
+ Condition false_condition = NegateCondition(true_condition);
+ if (false_condition == EQ) {
+ __ beq(CMPRES, ZR, compiler->GetJumpLabel(false_successor()));
+ } else {
+ ASSERT(false_condition == NE);
+ __ bne(CMPRES, ZR, compiler->GetJumpLabel(false_successor()));
+ }
+ // Fall through or jump to the true successor.
+ if (!compiler->CanFallThroughTo(true_successor())) {
+ __ b(compiler->GetJumpLabel(true_successor()));
+ }
+ }
}
@@ -869,19 +1233,89 @@
LocationSummary* StrictCompareInstr::MakeLocationSummary() const {
- UNIMPLEMENTED();
- return NULL;
+ const intptr_t kNumInputs = 2;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* locs =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ locs->set_in(0, Location::RegisterOrConstant(left()));
+ locs->set_in(1, Location::RegisterOrConstant(right()));
+ locs->set_out(Location::RequiresRegister());
+ return locs;
}
+// Special code for numbers (compare values instead of references.)
void StrictCompareInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ ASSERT(kind() == Token::kEQ_STRICT || kind() == Token::kNE_STRICT);
+ Location left = locs()->in(0);
+ Location right = locs()->in(1);
+ if (left.IsConstant() && right.IsConstant()) {
+ // TODO(vegorov): should be eliminated earlier by constant propagation.
+ const bool result = (kind() == Token::kEQ_STRICT) ?
+ left.constant().raw() == right.constant().raw() :
+ left.constant().raw() != right.constant().raw();
+ __ LoadObject(locs()->out().reg(), result ? Bool::True() : Bool::False());
+ return;
+ }
+ if (left.IsConstant()) {
+ compiler->EmitEqualityRegConstCompare(right.reg(),
+ left.constant(),
+ needs_number_check());
+ } else if (right.IsConstant()) {
+ compiler->EmitEqualityRegConstCompare(left.reg(),
+ right.constant(),
+ needs_number_check());
+ } else {
+ compiler->EmitEqualityRegRegCompare(left.reg(),
+ right.reg(),
+ needs_number_check());
+ }
+
+ Register result = locs()->out().reg();
+ Label load_true, done;
+ if (kind() == Token::kEQ_STRICT) {
+ __ beq(CMPRES, ZR, &load_true);
+ } else {
+ ASSERT(kind() == Token::kNE_STRICT);
+ __ bne(CMPRES, ZR, &load_true);
+ }
+ __ LoadObject(result, Bool::False());
+ __ b(&done);
+ __ Bind(&load_true);
+ __ LoadObject(result, Bool::True());
+ __ Bind(&done);
}
void StrictCompareInstr::EmitBranchCode(FlowGraphCompiler* compiler,
BranchInstr* branch) {
- UNIMPLEMENTED();
+ ASSERT(kind() == Token::kEQ_STRICT || kind() == Token::kNE_STRICT);
+ Location left = locs()->in(0);
+ Location right = locs()->in(1);
+ if (left.IsConstant() && right.IsConstant()) {
+ // TODO(vegorov): should be eliminated earlier by constant propagation.
+ const bool result = (kind() == Token::kEQ_STRICT) ?
+ left.constant().raw() == right.constant().raw() :
+ left.constant().raw() != right.constant().raw();
+ branch->EmitBranchOnValue(compiler, result);
+ return;
+ }
+ if (left.IsConstant()) {
+ compiler->EmitEqualityRegConstCompare(right.reg(),
+ left.constant(),
+ needs_number_check());
+ } else if (right.IsConstant()) {
+ compiler->EmitEqualityRegConstCompare(left.reg(),
+ right.constant(),
+ needs_number_check());
+ } else {
+ compiler->EmitEqualityRegRegCompare(left.reg(),
+ right.reg(),
+ needs_number_check());
+ }
+
+ Condition true_condition = (kind() == Token::kEQ_STRICT) ? EQ : NE;
+ branch->EmitBranchOnCondition(compiler, true_condition);
}
@@ -924,13 +1358,19 @@
LocationSummary* AllocateObjectInstr::MakeLocationSummary() const {
- UNIMPLEMENTED();
- return NULL;
+ return MakeCallSummary();
}
void AllocateObjectInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ const Class& cls = Class::ZoneHandle(constructor().Owner());
+ const Code& stub = Code::Handle(StubCode::GetAllocationStubForClass(cls));
+ const ExternalLabel label(cls.ToCString(), stub.EntryPoint());
+ compiler->GenerateCall(token_pos(),
+ &label,
+ PcDescriptors::kOther,
+ locs());
+ __ Drop(ArgumentCount()); // Discard arguments.
}
« no previous file with comments | « runtime/vm/flow_graph_compiler_mips.cc ('k') | runtime/vm/resolver_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698