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

Unified Diff: runtime/vm/intermediate_language_mips.cc

Issue 13884017: Adds support for UseDartApi 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/simulator_mips.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 21386)
+++ runtime/vm/intermediate_language_mips.cc (working copy)
@@ -405,6 +405,25 @@
}
+static void LoadValueCid(FlowGraphCompiler* compiler,
+ Register value_cid_reg,
+ Register value_reg,
+ Label* value_is_smi = NULL) {
+ Label done;
+ if (value_is_smi == NULL) {
+ __ LoadImmediate(value_cid_reg, kSmiCid);
+ }
+ __ andi(TMP1, value_reg, Immediate(kSmiTagMask));
+ if (value_is_smi == NULL) {
+ __ beq(TMP1, ZR, &done);
+ } else {
+ __ beq(TMP1, ZR, value_is_smi);
+ }
+ __ LoadClassId(value_cid_reg, value_reg);
+ __ Bind(&done);
+}
+
+
// Emit code when ICData's targets are all Object == (which is ===).
static void EmitCheckedStrictEqual(FlowGraphCompiler* compiler,
const ICData& ic_data,
@@ -430,11 +449,62 @@
}
+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;
+ }
+}
+
+
static void EmitSmiComparisonOp(FlowGraphCompiler* compiler,
const LocationSummary& locs,
Token::Kind kind,
BranchInstr* branch) {
- UNIMPLEMENTED();
+ Location left = locs.in(0);
+ Location right = locs.in(1);
+ ASSERT(!left.IsConstant() || !right.IsConstant());
+
+ Condition true_condition = TokenKindToSmiCondition(kind);
+
+ if (left.IsConstant()) {
+ __ CompareObject(CMPRES, right.reg(), left.constant());
regis 2013/04/12 21:18:04 Do you still have a reason to dedicate a register
zra 2013/04/12 22:19:59 Yah, I think it's probably less error-prone to kee
+ true_condition = FlowGraphCompiler::FlipCondition(true_condition);
+ } else if (right.IsConstant()) {
+ __ CompareObject(CMPRES, left.reg(), right.constant());
+ } else {
+ __ subu(CMPRES, left.reg(), right.reg());
+ }
+
+ if (branch != NULL) {
+ branch->EmitBranchOnCondition(compiler, true_condition);
+ } else {
+ Register result = locs.out().reg();
+ Label done, is_true;
+ switch (true_condition) {
+ case EQ: __ beq(CMPRES, ZR, &is_true); break;
+ case NE: __ bne(CMPRES, ZR, &is_true); break;
+ case GT: __ bgtz(CMPRES, &is_true); break;
+ case GE: __ bgez(CMPRES, &is_true); break;
+ case LT: __ bltz(CMPRES, &is_true); break;
+ case LE: __ blez(CMPRES, &is_true); break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ __ LoadObject(result, Bool::False());
+ __ b(&done);
+ __ Bind(&is_true);
+ __ LoadObject(result, Bool::True());
+ __ Bind(&done);
+ }
}
@@ -446,6 +516,14 @@
}
+static void EmitUnboxedMintComparisonOp(FlowGraphCompiler* compiler,
+ const LocationSummary& locs,
+ Token::Kind kind,
+ BranchInstr* branch) {
+ UNIMPLEMENTED();
+}
+
+
static void EmitDoubleComparisonOp(FlowGraphCompiler* compiler,
const LocationSummary& locs,
Token::Kind kind,
@@ -543,19 +621,135 @@
LocationSummary* RelationalOpInstr::MakeLocationSummary() const {
- UNIMPLEMENTED();
- return NULL;
+ const intptr_t kNumInputs = 2;
+ const intptr_t kNumTemps = 0;
+ if (operands_class_id() == kMintCid) {
+ const intptr_t kNumTemps = 2;
+ 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_temp(1, Location::RequiresRegister());
+ locs->set_out(Location::RequiresRegister());
+ return locs;
+ }
+ if (operands_class_id() == kDoubleCid) {
+ LocationSummary* summary =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ summary->set_in(0, Location::RequiresFpuRegister());
+ summary->set_in(1, Location::RequiresFpuRegister());
+ summary->set_out(Location::RequiresRegister());
+ return summary;
+ } else if (operands_class_id() == kSmiCid) {
+ LocationSummary* summary =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ summary->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.
+ summary->set_in(1, summary->in(0).IsConstant()
+ ? Location::RequiresRegister()
+ : Location::RegisterOrConstant(right()));
+ summary->set_out(Location::RequiresRegister());
+ return summary;
+ }
+ LocationSummary* locs =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
+ // Pick arbitrary fixed input registers because this is a call.
+ locs->set_in(0, Location::RegisterLocation(A0));
+ locs->set_in(1, Location::RegisterLocation(A1));
+ locs->set_out(Location::RegisterLocation(V0));
+ return locs;
}
void RelationalOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ if (operands_class_id() == kSmiCid) {
+ EmitSmiComparisonOp(compiler, *locs(), kind(), NULL);
+ return;
+ }
+ if (operands_class_id() == kMintCid) {
+ EmitUnboxedMintComparisonOp(compiler, *locs(), kind(), NULL);
+ return;
+ }
+ if (operands_class_id() == kDoubleCid) {
+ EmitDoubleComparisonOp(compiler, *locs(), kind(), NULL);
+ return;
+ }
+
+ // Push arguments for the call.
+ // TODO(fschneider): Split this instruction into different types to avoid
+ // explicitly pushing arguments to the call here.
+ Register left = locs()->in(0).reg();
+ Register right = locs()->in(1).reg();
+ __ Push(left);
+ __ Push(right);
+ if (HasICData() && (ic_data()->NumberOfChecks() > 0)) {
+ Label* deopt = compiler->AddDeoptStub(deopt_id(), kDeoptRelationalOp);
+ // Load class into A2.
+ const intptr_t kNumArguments = 2;
+ LoadValueCid(compiler, A2, left);
+ compiler->EmitTestAndCall(ICData::Handle(ic_data()->AsUnaryClassChecks()),
+ A2, // Class id register.
+ kNumArguments,
+ Array::Handle(), // No named arguments.
+ deopt, // Deoptimize target.
+ deopt_id(),
+ token_pos(),
+ locs());
+ return;
+ }
+ const String& function_name =
+ String::ZoneHandle(Symbols::New(Token::Str(kind())));
+ if (!compiler->is_optimizing()) {
+ compiler->AddCurrentDescriptor(PcDescriptors::kDeopt,
+ deopt_id(),
+ token_pos());
+ }
+ const intptr_t kNumArguments = 2;
+ const intptr_t kNumArgsChecked = 2; // Type-feedback.
+ ICData& relational_ic_data = ICData::ZoneHandle(ic_data()->raw());
+ if (compiler->is_optimizing() && FLAG_propagate_ic_data) {
+ ASSERT(!ic_data()->IsNull());
+ if (ic_data()->NumberOfChecks() == 0) {
+ // IC call for reoptimization populates original ICData.
+ relational_ic_data = ic_data()->raw();
+ } else {
+ // Megamorphic call.
+ relational_ic_data = ic_data()->AsUnaryClassChecks();
+ }
+ } else {
+ relational_ic_data = ICData::New(compiler->parsed_function().function(),
+ function_name,
+ deopt_id(),
+ kNumArgsChecked);
+ }
+ compiler->GenerateInstanceCall(deopt_id(),
+ token_pos(),
+ kNumArguments,
+ Array::ZoneHandle(), // No optional arguments.
+ locs(),
+ relational_ic_data);
}
void RelationalOpInstr::EmitBranchCode(FlowGraphCompiler* compiler,
BranchInstr* branch) {
- UNIMPLEMENTED();
+ if (operands_class_id() == kSmiCid) {
+ EmitSmiComparisonOp(compiler, *locs(), kind(), branch);
+ return;
+ }
+ if (operands_class_id() == kMintCid) {
+ EmitUnboxedMintComparisonOp(compiler, *locs(), kind(), branch);
+ return;
+ }
+ if (operands_class_id() == kDoubleCid) {
+ EmitDoubleComparisonOp(compiler, *locs(), kind(), branch);
+ return;
+ }
+ EmitNativeCode(compiler);
+ __ CompareObject(CMPRES, V0, Bool::True());
+ branch->EmitBranchOnCondition(compiler, EQ);
}
@@ -880,13 +1074,191 @@
LocationSummary* BinarySmiOpInstr::MakeLocationSummary() const {
- UNIMPLEMENTED();
- return NULL;
+ const intptr_t kNumInputs = 2;
+ if (op_kind() == Token::kTRUNCDIV) {
+ UNIMPLEMENTED();
+ return NULL;
+ } else {
+ const intptr_t kNumTemps = 0;
+ LocationSummary* summary =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ summary->set_in(0, Location::RequiresRegister());
+ summary->set_in(1, Location::RegisterOrSmiConstant(right()));
+ // We make use of 3-operand instructions by not requiring result register
+ // to be identical to first input register as on Intel.
+ summary->set_out(Location::RequiresRegister());
+ return summary;
+ }
}
void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ if (op_kind() == Token::kSHL) {
+ UNIMPLEMENTED();
+ return;
+ }
+
+ ASSERT(!is_truncating());
+ Register left = locs()->in(0).reg();
+ Register result = locs()->out().reg();
+ Label* deopt = NULL;
+ if (CanDeoptimize()) {
+ deopt = compiler->AddDeoptStub(deopt_id(), kDeoptBinarySmiOp);
+ }
+
+ if (locs()->in(1).IsConstant()) {
+ const Object& constant = locs()->in(1).constant();
+ ASSERT(constant.IsSmi());
+ int32_t imm = reinterpret_cast<int32_t>(constant.raw());
+ switch (op_kind()) {
+ case Token::kSUB: {
+ imm = -imm; // TODO(regis): What if deopt != NULL && imm == 0x80000000?
+ // Fall through.
regis 2013/04/12 21:18:04 I merged the kSUB case with kADD case on ARM. Sinc
zra 2013/04/12 22:19:59 Done.
+ }
+ case Token::kADD: {
+ if (deopt == NULL) {
+ __ AddImmediate(result, left, imm);
+ } else {
+ __ AddImmediateDetectOverflow(result, left, imm, CMPRES);
+ __ bltz(CMPRES, deopt);
+ }
+ break;
+ }
+ case Token::kMUL: {
+ // Keep left value tagged and untag right value.
+ const intptr_t value = Smi::Cast(constant).Value();
+ if (value == 2) {
+ __ sll(result, left, 1);
+ } else {
+ __ LoadImmediate(TMP, value);
+ __ mult(left, TMP);
+ __ mflo(result);
+ }
+ if (deopt != NULL) {
+ UNIMPLEMENTED();
+ }
+ break;
+ }
+ case Token::kTRUNCDIV: {
+ UNIMPLEMENTED();
+ break;
+ }
+ case Token::kBIT_AND: {
+ // No overflow check.
+ if (Utils::IsUint(kImmBits, imm)) {
+ __ andi(result, left, Immediate(imm));
+ } else {
+ __ LoadImmediate(TMP1, imm);
+ __ and_(result, left, TMP1);
+ }
+ break;
+ }
+ case Token::kBIT_OR: {
+ // No overflow check.
+ if (Utils::IsUint(kImmBits, imm)) {
+ __ ori(result, left, Immediate(imm));
+ } else {
+ __ LoadImmediate(TMP1, imm);
+ __ or_(result, left, TMP1);
+ }
+ break;
+ }
+ case Token::kBIT_XOR: {
+ // No overflow check.
+ if (Utils::IsUint(kImmBits, imm)) {
+ __ xori(result, left, Immediate(imm));
+ } else {
+ __ LoadImmediate(TMP1, imm);
+ __ xor_(result, left, TMP1);
+ }
+ break;
+ }
+ case Token::kSHR: {
+ UNIMPLEMENTED();
+ break;
+ }
+
+ default:
+ UNREACHABLE();
+ break;
+ }
+ return;
+ }
+
+ Register right = locs()->in(1).reg();
+ switch (op_kind()) {
+ case Token::kADD: {
+ if (deopt == NULL) {
+ __ addu(result, left, right);
+ } else {
+ __ AdduDetectOverflow(result, left, right, CMPRES);
+ __ bltz(CMPRES, deopt);
+ }
+ break;
+ }
+ case Token::kSUB: {
+ if (deopt == NULL) {
+ __ subu(result, left, right);
+ } else {
+ __ SubuDetectOverflow(result, left, right, CMPRES);
+ __ bltz(CMPRES, deopt);
+ }
+ break;
+ }
+ case Token::kMUL: {
+ __ SmiUntag(left);
+ __ mult(left, right);
+ __ mflo(result);
+ if (deopt != NULL) {
+ UNIMPLEMENTED();
+ }
+ break;
+ }
+ case Token::kBIT_AND: {
+ // No overflow check.
+ __ and_(result, left, right);
+ break;
+ }
+ case Token::kBIT_OR: {
+ // No overflow check.
+ __ or_(result, left, right);
+ break;
+ }
+ case Token::kBIT_XOR: {
+ // No overflow check.
+ __ xor_(result, left, right);
+ break;
+ }
+ case Token::kTRUNCDIV: {
+ UNIMPLEMENTED();
+ break;
+ }
+ case Token::kSHR: {
+ UNIMPLEMENTED();
+ 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;
+ }
}
@@ -1034,13 +1406,44 @@
LocationSummary* PolymorphicInstanceCallInstr::MakeLocationSummary() const {
- UNIMPLEMENTED();
- return NULL;
+ return MakeCallSummary();
}
void PolymorphicInstanceCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ Label* deopt = compiler->AddDeoptStub(instance_call()->deopt_id(),
+ kDeoptPolymorphicInstanceCallTestFail);
+ if (ic_data().NumberOfChecks() == 0) {
+ __ b(deopt);
+ return;
+ }
+ ASSERT(ic_data().num_args_tested() == 1);
+ if (!with_checks()) {
+ ASSERT(ic_data().HasOneTarget());
+ const Function& target = Function::ZoneHandle(ic_data().GetTargetAt(0));
+ compiler->GenerateStaticCall(instance_call()->deopt_id(),
+ instance_call()->token_pos(),
+ target,
+ instance_call()->ArgumentCount(),
+ instance_call()->argument_names(),
+ locs());
+ return;
+ }
+
+ // Load receiver into R0.
+ __ lw(T0, Address(SP, (instance_call()->ArgumentCount() - 1) * kWordSize));
+
+ LoadValueCid(compiler, T2, T0,
+ (ic_data().GetReceiverClassIdAt(0) == kSmiCid) ? NULL : deopt);
+
+ compiler->EmitTestAndCall(ic_data(),
+ T2, // Class id register.
+ instance_call()->ArgumentCount(),
+ instance_call()->argument_names(),
+ deopt,
+ instance_call()->deopt_id(),
+ instance_call()->token_pos(),
+ locs());
}
@@ -1067,13 +1470,21 @@
LocationSummary* CheckSmiInstr::MakeLocationSummary() const {
- UNIMPLEMENTED();
- return NULL;
+ const intptr_t kNumInputs = 1;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* summary =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ summary->set_in(0, Location::RequiresRegister());
+ return summary;
}
void CheckSmiInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ Register value = locs()->in(0).reg();
+ Label* deopt = compiler->AddDeoptStub(deopt_id(),
+ kDeoptCheckSmi);
+ __ andi(TMP1, value, Immediate(kSmiTagMask));
+ __ bne(TMP1, ZR, deopt);
}
@@ -1196,6 +1607,10 @@
switch (condition) {
case EQ: return NE;
case NE: return EQ;
+ case LT: return GE;
+ case LE: return GT;
+ case GT: return LE;
+ case GE: return LT;
default:
OS::Print("Error: Condition not recognized: %d\n", condition);
UNIMPLEMENTED();
@@ -1219,21 +1634,33 @@
Condition true_condition) {
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()));
+ Label* label = compiler->GetJumpLabel(true_successor());
+ switch (true_condition) {
+ case EQ: __ beq(CMPRES, ZR, label); break;
+ case NE: __ bne(CMPRES, ZR, label); break;
+ case GT: __ bgtz(CMPRES, label); break;
+ case GE: __ bgez(CMPRES, label); break;
+ case LT: __ bltz(CMPRES, label); break;
+ case LE: __ blez(CMPRES, label); break;
+ default:
+ UNREACHABLE();
+ break;
}
} 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()));
+ Label* label = compiler->GetJumpLabel(false_successor());
+ switch (false_condition) {
+ case EQ: __ beq(CMPRES, ZR, label); break;
+ case NE: __ bne(CMPRES, ZR, label); break;
+ case GT: __ bgtz(CMPRES, label); break;
+ case GE: __ bgez(CMPRES, label); break;
+ case LT: __ bltz(CMPRES, label); break;
+ case LE: __ blez(CMPRES, label); break;
+ default:
+ UNREACHABLE();
+ break;
}
// Fall through or jump to the true successor.
if (!compiler->CanFallThroughTo(true_successor())) {
« no previous file with comments | « runtime/vm/flow_graph_compiler_mips.cc ('k') | runtime/vm/simulator_mips.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698