Chromium Code Reviews| Index: runtime/vm/intermediate_language_ia32.cc |
| =================================================================== |
| --- runtime/vm/intermediate_language_ia32.cc (revision 12765) |
| +++ runtime/vm/intermediate_language_ia32.cc (working copy) |
| @@ -262,6 +262,16 @@ |
| 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::RequiresXmmRegister()); |
| + locs->set_in(1, Location::RequiresXmmRegister()); |
| + 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 = |
| @@ -617,6 +627,47 @@ |
| } |
| +static Condition TokenKindToMintCondition(Token::Kind kind) { |
| + switch (kind) { |
| + case Token::kEQ: return EQUAL; |
| + case Token::kNE: return NOT_EQUAL; |
| + default: |
| + UNREACHABLE(); |
| + return OVERFLOW; |
| + } |
| +} |
| + |
| + |
| +static void EmitUnboxedMintEqualityOp(FlowGraphCompiler* compiler, |
| + const LocationSummary& locs, |
| + Token::Kind kind, |
| + BranchInstr* branch) { |
| + ASSERT(Token::IsEqualityOperator(kind)); |
| + XmmRegister left = locs.in(0).xmm_reg(); |
| + XmmRegister right = locs.in(1).xmm_reg(); |
| + Register temp = locs.temp(0).reg(); |
| + __ movaps(XMM0, left); |
| + __ pcmpeqq(XMM0, right); |
| + __ movd(temp, XMM0); |
| + |
| + Condition true_condition = TokenKindToMintCondition(kind); |
| + __ cmpl(temp, Immediate(-1)); |
|
Vyacheslav Egorov (Google)
2012/09/24 14:53:42
you can also use test(temp, temp) and branch on ne
|
| + |
| + if (branch != NULL) { |
| + branch->EmitBranchOnCondition(compiler, true_condition); |
| + } else { |
| + Register result = locs.out().reg(); |
| + Label done, is_true; |
| + __ j(true_condition, &is_true); |
| + __ LoadObject(result, compiler->bool_false()); |
| + __ jmp(&done); |
| + __ Bind(&is_true); |
| + __ LoadObject(result, compiler->bool_true()); |
| + __ Bind(&done); |
| + } |
| +} |
| + |
| + |
| static Condition TokenKindToDoubleCondition(Token::Kind kind) { |
| switch (kind) { |
| case Token::kEQ: return EQUAL; |
| @@ -658,6 +709,10 @@ |
| 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; |
| @@ -691,6 +746,10 @@ |
| 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; |
| @@ -1688,110 +1747,6 @@ |
| } |
| -LocationSummary* BinaryMintOpInstr::MakeLocationSummary() const { |
| - const intptr_t kNumInputs = 2; |
| - ASSERT(op_kind() == Token::kBIT_AND); |
| - const intptr_t kNumTemps = 1; |
| - LocationSummary* summary = |
| - new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); |
| - summary->set_in(0, Location::RegisterLocation(EAX)); |
| - summary->set_in(1, Location::RegisterLocation(ECX)); |
| - summary->set_temp(0, Location::RegisterLocation(EDX)); |
| - summary->set_out(Location::RegisterLocation(EAX)); |
| - return summary; |
| -} |
| - |
| - |
| -void BinaryMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| - // TODO(regis): For now, we only support Token::kBIT_AND for a Mint or Smi |
| - // receiver and a Mint or Smi argument. We fall back to the run time call if |
| - // both receiver and argument are Mint or if one of them is Mint and the other |
| - // is a negative Smi. |
| - Register left = locs()->in(0).reg(); |
| - Register right = locs()->in(1).reg(); |
| - Register result = locs()->out().reg(); |
| - Register temp = locs()->temp(0).reg(); |
| - ASSERT(left == result); |
| - ASSERT(op_kind() == Token::kBIT_AND); |
| - Label* deopt = compiler->AddDeoptStub(instance_call()->deopt_id(), |
| - kDeoptBinaryMintOp); |
| - Label mint_static_call, smi_static_call, non_smi, smi_smi, done; |
| - __ testl(left, Immediate(kSmiTagMask)); // Is receiver Smi? |
| - __ j(NOT_ZERO, &non_smi); |
| - __ testl(right, Immediate(kSmiTagMask)); // Is argument Smi? |
| - __ j(ZERO, &smi_smi); |
| - __ CompareClassId(right, kMintCid, temp); // Is argument Mint? |
| - __ j(NOT_EQUAL, deopt); // Argument neither Smi nor Mint. |
| - __ cmpl(left, Immediate(0)); |
| - __ j(LESS, &smi_static_call); // Negative Smi receiver, Mint argument. |
| - |
| - // Positive Smi receiver, Mint argument. |
| - // Load lower argument Mint word, convert to Smi. It is OK to loose bits. |
| - __ movl(right, FieldAddress(right, Mint::value_offset())); |
| - __ SmiTag(right); |
| - __ andl(result, right); |
| - __ jmp(&done); |
| - |
| - __ Bind(&non_smi); // Receiver is non-Smi. |
| - __ CompareClassId(left, kMintCid, temp); // Is receiver Mint? |
| - __ j(NOT_EQUAL, deopt); // Receiver neither Smi nor Mint. |
| - __ testl(right, Immediate(kSmiTagMask)); // Is argument Smi? |
| - __ j(NOT_ZERO, &mint_static_call); // Mint receiver, non-Smi argument. |
| - __ cmpl(right, Immediate(0)); |
| - __ j(LESS, &mint_static_call); // Mint receiver, negative Smi argument. |
| - |
| - // Mint receiver, positive Smi argument. |
| - // Load lower receiver Mint word, convert to Smi. It is OK to loose bits. |
| - __ movl(result, FieldAddress(left, Mint::value_offset())); |
| - __ SmiTag(result); |
| - __ Bind(&smi_smi); |
| - __ andl(result, right); |
| - __ jmp(&done); |
| - |
| - __ Bind(&smi_static_call); |
| - { |
| - Function& target = Function::ZoneHandle( |
| - ic_data()->GetTargetForReceiverClassId(kSmiCid)); |
| - if (target.IsNull()) { |
| - __ jmp(deopt); |
| - } else { |
| - __ pushl(left); |
| - __ pushl(right); |
| - compiler->GenerateStaticCall( |
| - instance_call()->deopt_id(), |
| - instance_call()->token_pos(), |
| - target, |
| - instance_call()->ArgumentCount(), |
| - instance_call()->argument_names(), |
| - locs()); |
| - ASSERT(result == EAX); |
| - __ jmp(&done); |
| - } |
| - } |
| - |
| - __ Bind(&mint_static_call); |
| - { |
| - Function& target = Function::ZoneHandle( |
| - ic_data()->GetTargetForReceiverClassId(kMintCid)); |
| - if (target.IsNull()) { |
| - __ jmp(deopt); |
| - } else { |
| - __ pushl(left); |
| - __ pushl(right); |
| - compiler->GenerateStaticCall( |
| - instance_call()->deopt_id(), |
| - instance_call()->token_pos(), |
| - target, |
| - instance_call()->ArgumentCount(), |
| - instance_call()->argument_names(), |
| - locs()); |
| - ASSERT(result == EAX); |
| - } |
| - } |
| - __ Bind(&done); |
| -} |
| - |
| - |
| LocationSummary* CheckEitherNonSmiInstr::MakeLocationSummary() const { |
| ASSERT((left()->ResultCid() != kDoubleCid) && |
| (right()->ResultCid() != kDoubleCid)); |
| @@ -2221,6 +2176,160 @@ |
| } |
| +LocationSummary* UnboxIntegerInstr::MakeLocationSummary() const { |
| + const intptr_t kNumInputs = 1; |
| + const intptr_t kNumTemps = CanDeoptimize() ? 1 : 0; |
| + LocationSummary* summary = |
| + new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| + summary->set_in(0, Location::RequiresRegister()); |
| + if (CanDeoptimize()) summary->set_temp(0, Location::RequiresRegister()); |
| + summary->set_out(Location::RequiresXmmRegister()); |
| + return summary; |
| +} |
| + |
| + |
| +void UnboxIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| + const intptr_t value_cid = value()->ResultCid(); |
| + const Register value = locs()->in(0).reg(); |
| + const XmmRegister result = locs()->out().xmm_reg(); |
| + |
| + if (value_cid == kMintCid) { |
| + __ movsd(result, FieldAddress(value, Mint::value_offset())); |
| + } else if (value_cid == kSmiCid) { |
| + __ SmiUntag(value); // Untag input before conversion. |
| + __ movd(result, value); |
| + __ pmovsxdq(result, result); |
| + __ SmiTag(value); // Restore input register. |
| + } else { |
| + Register temp = locs()->temp(0).reg(); |
| + Label* deopt = compiler->AddDeoptStub(deopt_id_, kDeoptBinaryDoubleOp); |
| + Label is_smi, done; |
| + __ testl(value, Immediate(kSmiTagMask)); |
| + __ j(ZERO, &is_smi); |
| + __ CompareClassId(value, kMintCid, temp); |
| + __ j(NOT_EQUAL, deopt); |
| + __ movsd(result, FieldAddress(value, Mint::value_offset())); |
| + __ jmp(&done); |
| + __ Bind(&is_smi); |
| + __ movl(temp, value); |
| + __ SmiUntag(temp); |
| + __ movd(result, temp); |
| + __ pmovsxdq(result, result); |
| + __ Bind(&done); |
| + } |
| +} |
| + |
| + |
| +LocationSummary* BoxIntegerInstr::MakeLocationSummary() const { |
| + const intptr_t kNumInputs = 1; |
| + const intptr_t kNumTemps = 2; |
| + LocationSummary* summary = |
| + new LocationSummary(kNumInputs, |
| + kNumTemps, |
| + LocationSummary::kCallOnSlowPath); |
| + summary->set_in(0, Location::RequiresXmmRegister()); |
| + summary->set_temp(0, Location::RegisterLocation(EAX)); |
| + summary->set_temp(1, Location::RegisterLocation(EDX)); |
| + // TODO(fschneider): Save one temp by using result register as a temp. |
| + summary->set_out(Location::RequiresRegister()); |
| + return summary; |
| +} |
| + |
| + |
| +class BoxIntegerSlowPath : public SlowPathCode { |
| + public: |
| + explicit BoxIntegerSlowPath(BoxIntegerInstr* instruction) |
| + : instruction_(instruction) { } |
| + |
| + virtual void EmitNativeCode(FlowGraphCompiler* compiler) { |
| + __ Bind(entry_label()); |
| + const Class& mint_class = |
| + Class::ZoneHandle(Isolate::Current()->object_store()->mint_class()); |
| + const Code& stub = |
| + Code::Handle(StubCode::GetAllocationStubForClass(mint_class)); |
| + const ExternalLabel label(mint_class.ToCString(), stub.EntryPoint()); |
| + |
| + LocationSummary* locs = instruction_->locs(); |
| + locs->live_registers()->Remove(locs->out()); |
| + // Temps contain untagged values. Must only save tagged values. |
| + locs->live_registers()->Remove(locs->temp(0)); |
| + locs->live_registers()->Remove(locs->temp(1)); |
|
Vyacheslav Egorov (Google)
2012/09/24 14:53:42
I think we don't assigned safepoints for temporary
Florian Schneider
2012/09/26 11:51:32
Done.
|
| + |
| + compiler->SaveLiveRegisters(locs); |
| + compiler->GenerateCall(0, // No token pos. |
| + &label, |
| + PcDescriptors::kOther, |
| + locs); |
| + if (EAX != locs->out().reg()) __ movl(locs->out().reg(), EAX); |
| + compiler->RestoreLiveRegisters(locs); |
| + |
| + __ jmp(exit_label()); |
| + } |
| + |
| + private: |
| + BoxIntegerInstr* instruction_; |
| +}; |
| + |
| + |
| +void BoxIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| + BoxIntegerSlowPath* slow_path = new BoxIntegerSlowPath(this); |
| + compiler->AddSlowPathCode(slow_path); |
| + |
| + Register out_reg = locs()->out().reg(); |
| + XmmRegister value = locs()->in(0).xmm_reg(); |
| + |
| + // Check if result fits into a smi. |
| + Label not_smi, done; |
| + __ pextrd(EDX, value, Immediate(1)); // Upper half. |
| + __ pextrd(EAX, value, Immediate(0)); // Lower half. |
| + __ xorl(EDX, EAX); |
| + __ testl(EDX, Immediate(0xc0000000)); |
|
Vyacheslav Egorov (Google)
2012/09/24 14:53:42
0x0000000100000001 is not a smi but passes this ch
Florian Schneider
2012/09/26 11:51:32
Thanks for catching. I'll fix it and add a test.
|
| + __ j(NOT_ZERO, ¬_smi); |
| + __ SmiTag(EAX); |
| + __ movl(out_reg, EAX); |
| + __ jmp(&done); |
| + |
| + __ Bind(¬_smi); |
| + AssemblerMacros::TryAllocate( |
| + compiler->assembler(), |
| + Class::ZoneHandle(Isolate::Current()->object_store()->mint_class()), |
| + slow_path->entry_label(), |
| + Assembler::kFarJump, |
| + out_reg); |
| + __ Bind(slow_path->exit_label()); |
| + __ movsd(FieldAddress(out_reg, Mint::value_offset()), value); |
| + __ Bind(&done); |
| +} |
| + |
| + |
| +LocationSummary* UnboxedMintBinaryOpInstr::MakeLocationSummary() const { |
| + const intptr_t kNumInputs = 2; |
| + const intptr_t kNumTemps = 0; |
| + LocationSummary* summary = |
| + new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| + summary->set_in(0, Location::RequiresXmmRegister()); |
| + summary->set_in(1, Location::RequiresXmmRegister()); |
| + summary->set_out(Location::SameAsFirstInput()); |
| + return summary; |
| +} |
| + |
| + |
| +void UnboxedMintBinaryOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| + XmmRegister left = locs()->in(0).xmm_reg(); |
| + XmmRegister right = locs()->in(1).xmm_reg(); |
| + |
| + ASSERT(locs()->out().xmm_reg() == left); |
| + |
| + switch (op_kind()) { |
| + case Token::kBIT_AND: __ andpd(left, right); break; |
| + case Token::kBIT_OR: __ orpd(left, right); break; |
| + case Token::kBIT_XOR: __ xorpd(left, right); break; |
| + default: UNREACHABLE(); |
| + } |
| +} |
| + |
| + |
| + |
| } // namespace dart |
| #undef __ |