| Index: runtime/vm/intermediate_language_mips.cc
|
| ===================================================================
|
| --- runtime/vm/intermediate_language_mips.cc (revision 24063)
|
| +++ runtime/vm/intermediate_language_mips.cc (working copy)
|
| @@ -387,11 +387,13 @@
|
| const int kNumArgumentsChecked = 2;
|
|
|
| __ TraceSimMsg("EmitEqualityAsInstanceCall");
|
| + __ Comment("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);
|
| + __ LoadImmediate(TMP, reinterpret_cast<int32_t>(Object::null()));
|
| + __ beq(A1, TMP, &check_identity);
|
| + __ beq(A0, TMP, &check_identity);
|
|
|
| ICData& equality_ic_data = ICData::ZoneHandle();
|
| if (compiler->is_optimizing() && FLAG_propagate_ic_data) {
|
| @@ -536,6 +538,7 @@
|
| Register temp = locs->temp(0).reg();
|
|
|
| __ TraceSimMsg("EmitEqualityAsPolymorphicCall");
|
| + __ Comment("EmitEqualityAsPolymorphicCall");
|
|
|
| LoadValueCid(compiler, temp, left,
|
| (ic_data.GetReceiverClassIdAt(0) == kSmiCid) ? NULL : deopt);
|
| @@ -608,12 +611,57 @@
|
|
|
| // Emit code when ICData's targets are all Object == (which is ===).
|
| static void EmitCheckedStrictEqual(FlowGraphCompiler* compiler,
|
| - const ICData& ic_data,
|
| + const ICData& orig_ic_data,
|
| const LocationSummary& locs,
|
| Token::Kind kind,
|
| BranchInstr* branch,
|
| intptr_t deopt_id) {
|
| - UNIMPLEMENTED();
|
| + ASSERT((kind == Token::kEQ) || (kind == Token::kNE));
|
| + Register left = locs.in(0).reg();
|
| + Register right = locs.in(1).reg();
|
| + Register temp = locs.temp(0).reg();
|
| + Label* deopt = compiler->AddDeoptStub(deopt_id, kDeoptEquality);
|
| +
|
| + __ Comment("CheckedStrictEqual");
|
| +
|
| + __ andi(CMPRES, left, Immediate(kSmiTagMask));
|
| + __ beq(CMPRES, ZR, deopt);
|
| + // 'left' is not Smi.
|
| + Label identity_compare;
|
| + __ LoadImmediate(TMP, reinterpret_cast<int32_t>(Object::null()));
|
| + __ beq(right, TMP, &identity_compare);
|
| + __ beq(left, TMP, &identity_compare);
|
| +
|
| + __ LoadClassId(temp, left);
|
| + const ICData& ic_data = ICData::Handle(orig_ic_data.AsUnaryClassChecks());
|
| + const intptr_t len = ic_data.NumberOfChecks();
|
| + for (intptr_t i = 0; i < len; i++) {
|
| + if (i == (len - 1)) {
|
| + __ BranchNotEqual(temp, ic_data.GetReceiverClassIdAt(i), deopt);
|
| + } else {
|
| + __ BranchEqual(temp, ic_data.GetReceiverClassIdAt(i), &identity_compare);
|
| + }
|
| + }
|
| + __ Bind(&identity_compare);
|
| + __ subu(CMPRES, left, right);
|
| + if (branch == NULL) {
|
| + Label done, is_equal;
|
| + Register result = locs.out().reg();
|
| + __ beq(CMPRES, ZR, &is_equal);
|
| + // Not equal.
|
| + __ LoadObject(result,
|
| + (kind == Token::kEQ) ? Bool::False() : Bool::True());
|
| + __ b(&done);
|
| + __ Bind(&is_equal);
|
| + __ LoadObject(result,
|
| + (kind == Token::kEQ) ? Bool::True() : Bool::False());
|
| + __ Bind(&done);
|
| +
|
| + } else {
|
| + Condition cond = TokenKindToSmiCondition(kind);
|
| + __ mov(TMP, ZR);
|
| + branch->EmitBranchOnCondition(compiler, cond);
|
| + }
|
| }
|
|
|
|
|
| @@ -633,8 +681,10 @@
|
| 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);
|
| + __ Comment("EmitGenericEqualityCompare");
|
| + __ LoadImmediate(TMP, reinterpret_cast<int32_t>(Object::null()));
|
| + __ beq(right, TMP, &identity_compare);
|
| + __ bne(left, TMP, &non_null_compare);
|
|
|
| // Comparison with NULL is "===".
|
| __ Bind(&identity_compare);
|
| @@ -685,6 +735,7 @@
|
| Token::Kind kind,
|
| BranchInstr* branch) {
|
| __ TraceSimMsg("EmitSmiComparisonOp");
|
| + __ Comment("EmitSmiComparisonOp");
|
| Location left = locs.in(0);
|
| Location right = locs.in(1);
|
| ASSERT(!left.IsConstant() || !right.IsConstant());
|
| @@ -732,17 +783,45 @@
|
| }
|
|
|
|
|
| +static Condition TokenKindToDoubleCondition(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 EmitDoubleComparisonOp(FlowGraphCompiler* compiler,
|
| const LocationSummary& locs,
|
| Token::Kind kind,
|
| BranchInstr* branch) {
|
| - UNIMPLEMENTED();
|
| + DRegister left = locs.in(0).fpu_reg();
|
| + DRegister right = locs.in(1).fpu_reg();
|
| +
|
| + __ Comment("DoubleComparisonOp(left=%d, right=%d)", left, right);
|
| +
|
| + Condition true_condition = TokenKindToDoubleCondition(kind);
|
| + if (branch != NULL) {
|
| + compiler->EmitDoubleCompareBranch(
|
| + true_condition, left, right, branch);
|
| + } else {
|
| + compiler->EmitDoubleCompareBool(
|
| + true_condition, left, right, locs.out().reg());
|
| + }
|
| }
|
|
|
|
|
| void EqualityCompareInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
| ASSERT((kind() == Token::kNE) || (kind() == Token::kEQ));
|
| BranchInstr* kNoBranch = NULL;
|
| + __ Comment("EqualityCompareInstr");
|
| if (receiver_class_id() == kSmiCid) {
|
| EmitSmiComparisonOp(compiler, *locs(), kind(), kNoBranch);
|
| return;
|
| @@ -785,6 +864,7 @@
|
| void EqualityCompareInstr::EmitBranchCode(FlowGraphCompiler* compiler,
|
| BranchInstr* branch) {
|
| __ TraceSimMsg("EqualityCompareInstr");
|
| + __ Comment("EqualityCompareInstr:BranchCode");
|
| ASSERT((kind() == Token::kNE) || (kind() == Token::kEQ));
|
| if (receiver_class_id() == kSmiCid) {
|
| // Deoptimizes if both arguments not Smi.
|
| @@ -1001,7 +1081,9 @@
|
| // into the runtime system.
|
| uword entry = reinterpret_cast<uword>(native_c_function());
|
| #if defined(USING_SIMULATOR)
|
| - entry = Simulator::RedirectExternalReference(entry, Simulator::kNativeCall);
|
| + entry = Simulator::RedirectExternalReference(entry,
|
| + Simulator::kNativeCall,
|
| + function().NumParameters());
|
| #endif
|
| __ LoadImmediate(T5, entry);
|
| __ LoadImmediate(A1, NativeArguments::ComputeArgcTag(function()));
|
| @@ -1205,7 +1287,28 @@
|
| if ((representation() == kUnboxedDouble) ||
|
| (representation() == kUnboxedMint) ||
|
| (representation() == kUnboxedFloat32x4)) {
|
| - UNIMPLEMENTED();
|
| + DRegister result = locs()->out().fpu_reg();
|
| + switch (class_id()) {
|
| + case kTypedDataInt32ArrayCid:
|
| + UNIMPLEMENTED();
|
| + break;
|
| + case kTypedDataUint32ArrayCid:
|
| + UNIMPLEMENTED();
|
| + break;
|
| + case kTypedDataFloat32ArrayCid:
|
| + // Load single precision float and promote to double.
|
| + __ lwc1(STMP1, element_address);
|
| + __ cvtds(result, STMP1);
|
| + break;
|
| + case kTypedDataFloat64ArrayCid:
|
| + __ LoadDFromOffset(result, index.reg(),
|
| + FlowGraphCompiler::DataOffsetFor(class_id()) - kHeapObjectTag);
|
| + break;
|
| + case kTypedDataFloat32x4ArrayCid:
|
| + UNIMPLEMENTED();
|
| + break;
|
| + }
|
| + return;
|
| }
|
|
|
| Register result = locs()->out().reg();
|
| @@ -1582,7 +1685,8 @@
|
|
|
| if (field().is_nullable() && (field_cid != kNullCid)) {
|
| __ beq(CMPRES, ZR, &ok);
|
| - __ subu(CMPRES, value_reg, NULLREG);
|
| + __ LoadImmediate(TMP, reinterpret_cast<int32_t>(Object::null()));
|
| + __ subu(CMPRES, value_reg, TMP);
|
| }
|
|
|
| if (ok_is_fall_through) {
|
| @@ -1703,13 +1807,30 @@
|
|
|
|
|
| LocationSummary* InstanceOfInstr::MakeLocationSummary() const {
|
| - UNIMPLEMENTED();
|
| - return NULL;
|
| + const intptr_t kNumInputs = 3;
|
| + const intptr_t kNumTemps = 0;
|
| + LocationSummary* summary =
|
| + new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
|
| + summary->set_in(0, Location::RegisterLocation(A0));
|
| + summary->set_in(1, Location::RegisterLocation(A2));
|
| + summary->set_in(2, Location::RegisterLocation(A1));
|
| + summary->set_out(Location::RegisterLocation(V0));
|
| + return summary;
|
| }
|
|
|
|
|
| void InstanceOfInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
| - UNIMPLEMENTED();
|
| + ASSERT(locs()->in(0).reg() == A0); // Value.
|
| + ASSERT(locs()->in(1).reg() == A2); // Instantiator.
|
| + ASSERT(locs()->in(2).reg() == A1); // Instantiator type arguments.
|
| +
|
| + __ Comment("InstanceOfInstr");
|
| + compiler->GenerateInstanceOf(token_pos(),
|
| + deopt_id(),
|
| + type(),
|
| + negate_result(),
|
| + locs());
|
| + ASSERT(locs()->out().reg() == V0);
|
| }
|
|
|
|
|
| @@ -1739,14 +1860,19 @@
|
|
|
| LocationSummary*
|
| AllocateObjectWithBoundsCheckInstr::MakeLocationSummary() const {
|
| - UNIMPLEMENTED();
|
| - return NULL;
|
| + return MakeCallSummary();
|
| }
|
|
|
|
|
| void AllocateObjectWithBoundsCheckInstr::EmitNativeCode(
|
| FlowGraphCompiler* compiler) {
|
| - UNIMPLEMENTED();
|
| + compiler->GenerateCallRuntime(token_pos(),
|
| + deopt_id(),
|
| + kAllocateObjectWithBoundsCheckRuntimeEntry,
|
| + locs());
|
| + __ Drop(3);
|
| + ASSERT(locs()->out().reg() == V0);
|
| + __ Pop(V0); // Pop new instance.
|
| }
|
|
|
|
|
| @@ -1793,7 +1919,8 @@
|
| Label type_arguments_instantiated;
|
| const intptr_t len = type_arguments().Length();
|
| if (type_arguments().IsRawInstantiatedRaw(len)) {
|
| - __ beq(instantiator_reg, NULLREG, &type_arguments_instantiated);
|
| + __ BranchEqual(instantiator_reg, reinterpret_cast<int32_t>(Object::null()),
|
| + &type_arguments_instantiated);
|
| }
|
| // Instantiate non-null type arguments.
|
| // A runtime call to instantiate the type arguments is required.
|
| @@ -1846,7 +1973,8 @@
|
| // the type arguments.
|
| Label type_arguments_instantiated;
|
| ASSERT(type_arguments().IsRawInstantiatedRaw(type_arguments().Length()));
|
| - __ beq(instantiator_reg, NULLREG, &type_arguments_instantiated);
|
| + __ BranchEqual(instantiator_reg, reinterpret_cast<int32_t>(Object::null()),
|
| + &type_arguments_instantiated);
|
| // Instantiate non-null type arguments.
|
| // In the non-factory case, we rely on the allocation stub to
|
| // instantiate the type arguments.
|
| @@ -1886,7 +2014,8 @@
|
| // the type arguments and do not pass the instantiator.
|
| ASSERT(type_arguments().IsRawInstantiatedRaw(type_arguments().Length()));
|
| Label instantiator_not_null;
|
| - __ bne(instantiator_reg, NULLREG, &instantiator_not_null);
|
| + __ BranchNotEqual(instantiator_reg, reinterpret_cast<int32_t>(Object::null()),
|
| + &instantiator_not_null);
|
| // Null was used in VisitExtractConstructorTypeArguments as the
|
| // instantiated type arguments, no proper instantiator needed.
|
| __ LoadImmediate(instantiator_reg,
|
| @@ -2067,7 +2196,9 @@
|
| const intptr_t kCountLimit = 0x1F;
|
| const intptr_t value = Smi::Cast(constant).Value();
|
| if (value == 0) {
|
| - // No code needed.
|
| + if (result != left) {
|
| + __ mov(result, left);
|
| + }
|
| } else if ((value < 0) || (value >= kCountLimit)) {
|
| // This condition may not be known earlier in some cases because
|
| // of constant propagation, inlining, etc.
|
| @@ -2101,6 +2232,7 @@
|
| const intptr_t left_int = Smi::Cast(obj).Value();
|
| if (left_int == 0) {
|
| __ bltz(right, deopt);
|
| + __ mov(result, ZR);
|
| return;
|
| }
|
| const intptr_t max_right = kSmiBits - Utils::HighestBit(left_int);
|
| @@ -2163,24 +2295,33 @@
|
|
|
| LocationSummary* BinarySmiOpInstr::MakeLocationSummary() const {
|
| const intptr_t kNumInputs = 2;
|
| + const intptr_t kNumTemps = op_kind() == Token::kADD ? 1 : 0;
|
| + LocationSummary* summary =
|
| + new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
| if (op_kind() == Token::kTRUNCDIV) {
|
| - UNIMPLEMENTED();
|
| - return NULL;
|
| - } else {
|
| - const intptr_t kNumTemps = op_kind() == Token::kADD ? 1 : 0;
|
| - LocationSummary* summary =
|
| - new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
| - summary->set_in(0, Location::RequiresRegister());
|
| - summary->set_in(1, Location::RegisterOrSmiConstant(right()));
|
| - if (op_kind() == Token::kADD) {
|
| - // Need an extra temp for the overflow detection code.
|
| - summary->set_temp(0, Location::RequiresRegister());
|
| + if (RightIsPowerOfTwoConstant()) {
|
| + summary->set_in(0, Location::RequiresRegister());
|
| + ConstantInstr* right_constant = right()->definition()->AsConstant();
|
| + summary->set_in(1, Location::Constant(right_constant->value()));
|
| + summary->set_out(Location::RequiresRegister());
|
| + } else {
|
| + // Both inputs must be writable because they will be untagged.
|
| + summary->set_in(0, Location::WritableRegister());
|
| + summary->set_in(1, Location::WritableRegister());
|
| + summary->set_out(Location::RequiresRegister());
|
| }
|
| - // 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;
|
| }
|
| + summary->set_in(0, Location::RequiresRegister());
|
| + summary->set_in(1, Location::RegisterOrSmiConstant(right()));
|
| + if (op_kind() == Token::kADD) {
|
| + // Need an extra temp for the overflow detection code.
|
| + summary->set_temp(0, Location::RequiresRegister());
|
| + }
|
| + // 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;
|
| }
|
|
|
|
|
| @@ -2251,7 +2392,33 @@
|
| break;
|
| }
|
| case Token::kTRUNCDIV: {
|
| - UNIMPLEMENTED();
|
| + const intptr_t value = Smi::Cast(constant).Value();
|
| + if (value == 1) {
|
| + if (result != left) {
|
| + __ mov(result, left);
|
| + }
|
| + break;
|
| + } else if (value == -1) {
|
| + // Check the corner case of dividing the 'MIN_SMI' with -1, in which
|
| + // case we cannot negate the result.
|
| + __ BranchEqual(left, 0x80000000, deopt);
|
| + __ subu(result, ZR, left);
|
| + break;
|
| + }
|
| + ASSERT((value != 0) && Utils::IsPowerOfTwo(Utils::Abs(value)));
|
| + const intptr_t shift_count =
|
| + Utils::ShiftForPowerOfTwo(Utils::Abs(value)) + kSmiTagSize;
|
| + ASSERT(kSmiTagSize == 1);
|
| + __ sra(TMP, left, 31);
|
| + ASSERT(shift_count > 1); // 1, -1 case handled above.
|
| + __ sll(TMP, TMP, 32 - shift_count);
|
| + __ addu(left, left, TMP);
|
| + ASSERT(shift_count > 0);
|
| + __ sra(result, left, shift_count);
|
| + if (value < 0) {
|
| + __ subu(result, ZR, result);
|
| + }
|
| + __ SmiTag(result);
|
| break;
|
| }
|
| case Token::kBIT_AND: {
|
| @@ -2293,7 +2460,9 @@
|
|
|
| if (value == 0) {
|
| // TODO(vegorov): should be handled outside.
|
| - __ break_(0);
|
| + if (result != left) {
|
| + __ mov(result, left);
|
| + }
|
| break;
|
| } else if (value < 0) {
|
| // TODO(vegorov): should be handled outside.
|
| @@ -2366,7 +2535,16 @@
|
| break;
|
| }
|
| case Token::kTRUNCDIV: {
|
| - UNIMPLEMENTED();
|
| + // Handle divide by zero in runtime.
|
| + __ beq(right, ZR, deopt);
|
| + __ SmiUntag(left);
|
| + __ SmiUntag(right);
|
| + __ div(left, right);
|
| + __ mflo(result);
|
| + // Check the corner case of dividing the 'MIN_SMI' with -1, in which
|
| + // case we cannot tag the result.
|
| + __ BranchEqual(V0, 0x40000000, deopt);
|
| + __ SmiTag(result);
|
| break;
|
| }
|
| case Token::kSHR: {
|
| @@ -2399,35 +2577,142 @@
|
|
|
|
|
| LocationSummary* CheckEitherNonSmiInstr::MakeLocationSummary() const {
|
| - UNIMPLEMENTED();
|
| - return NULL;
|
| + intptr_t left_cid = left()->Type()->ToCid();
|
| + intptr_t right_cid = right()->Type()->ToCid();
|
| + ASSERT((left_cid != kDoubleCid) && (right_cid != kDoubleCid));
|
| + const intptr_t kNumInputs = 2;
|
| + const intptr_t kNumTemps = 0;
|
| + LocationSummary* summary =
|
| + new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
| + summary->set_in(0, Location::RequiresRegister());
|
| + summary->set_in(1, Location::RequiresRegister());
|
| + return summary;
|
| }
|
|
|
|
|
| void CheckEitherNonSmiInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
| - UNIMPLEMENTED();
|
| + Label* deopt = compiler->AddDeoptStub(deopt_id(), kDeoptBinaryDoubleOp);
|
| + intptr_t left_cid = left()->Type()->ToCid();
|
| + intptr_t right_cid = right()->Type()->ToCid();
|
| + Register left = locs()->in(0).reg();
|
| + Register right = locs()->in(1).reg();
|
| + if (left_cid == kSmiCid) {
|
| + __ andi(CMPRES, right, Immediate(kSmiTagMask));
|
| + } else if (right_cid == kSmiCid) {
|
| + __ andi(CMPRES, left, Immediate(kSmiTagMask));
|
| + } else {
|
| + __ or_(TMP, left, right);
|
| + __ andi(CMPRES, TMP, Immediate(kSmiTagMask));
|
| + }
|
| + __ beq(CMPRES, ZR, deopt);
|
| }
|
|
|
|
|
| LocationSummary* BoxDoubleInstr::MakeLocationSummary() const {
|
| - UNIMPLEMENTED();
|
| - return NULL;
|
| + const intptr_t kNumInputs = 1;
|
| + const intptr_t kNumTemps = 0;
|
| + LocationSummary* summary =
|
| + new LocationSummary(kNumInputs,
|
| + kNumTemps,
|
| + LocationSummary::kCallOnSlowPath);
|
| + summary->set_in(0, Location::RequiresFpuRegister());
|
| + summary->set_out(Location::RequiresRegister());
|
| + return summary;
|
| }
|
|
|
|
|
| +class BoxDoubleSlowPath : public SlowPathCode {
|
| + public:
|
| + explicit BoxDoubleSlowPath(BoxDoubleInstr* instruction)
|
| + : instruction_(instruction) { }
|
| +
|
| + virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
|
| + __ Comment("BoxDoubleSlowPath");
|
| + __ Bind(entry_label());
|
| + const Class& double_class = compiler->double_class();
|
| + const Code& stub =
|
| + Code::Handle(StubCode::GetAllocationStubForClass(double_class));
|
| + const ExternalLabel label(double_class.ToCString(), stub.EntryPoint());
|
| +
|
| + LocationSummary* locs = instruction_->locs();
|
| + locs->live_registers()->Remove(locs->out());
|
| +
|
| + compiler->SaveLiveRegisters(locs);
|
| + compiler->GenerateCall(Scanner::kDummyTokenIndex, // No token position.
|
| + &label,
|
| + PcDescriptors::kOther,
|
| + locs);
|
| + if (locs->out().reg() != V0) {
|
| + __ mov(locs->out().reg(), V0);
|
| + }
|
| + compiler->RestoreLiveRegisters(locs);
|
| +
|
| + __ b(exit_label());
|
| + }
|
| +
|
| + private:
|
| + BoxDoubleInstr* instruction_;
|
| +};
|
| +
|
| +
|
| void BoxDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
| - UNIMPLEMENTED();
|
| + BoxDoubleSlowPath* slow_path = new BoxDoubleSlowPath(this);
|
| + compiler->AddSlowPathCode(slow_path);
|
| +
|
| + Register out_reg = locs()->out().reg();
|
| + DRegister value = locs()->in(0).fpu_reg();
|
| +
|
| + __ TryAllocate(compiler->double_class(),
|
| + slow_path->entry_label(),
|
| + out_reg);
|
| + __ Bind(slow_path->exit_label());
|
| + __ StoreDToOffset(value, out_reg, Double::value_offset() - kHeapObjectTag);
|
| }
|
|
|
|
|
| LocationSummary* UnboxDoubleInstr::MakeLocationSummary() const {
|
| - UNIMPLEMENTED();
|
| - return NULL;
|
| + const intptr_t kNumInputs = 1;
|
| + const intptr_t value_cid = value()->Type()->ToCid();
|
| + const bool needs_writable_input = (value_cid == kSmiCid);
|
| + const intptr_t kNumTemps = 0;
|
| + LocationSummary* summary =
|
| + new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
| + summary->set_in(0, needs_writable_input
|
| + ? Location::WritableRegister()
|
| + : Location::RequiresRegister());
|
| + summary->set_out(Location::RequiresFpuRegister());
|
| + return summary;
|
| }
|
|
|
|
|
| void UnboxDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
| - UNIMPLEMENTED();
|
| + const intptr_t value_cid = value()->Type()->ToCid();
|
| + const Register value = locs()->in(0).reg();
|
| + const DRegister result = locs()->out().fpu_reg();
|
| +
|
| + if (value_cid == kDoubleCid) {
|
| + __ LoadDFromOffset(result, value, Double::value_offset() - kHeapObjectTag);
|
| + } else if (value_cid == kSmiCid) {
|
| + __ SmiUntag(value); // Untag input before conversion.
|
| + __ mtc1(value, STMP1);
|
| + __ cvtdw(result, STMP1);
|
| + } else {
|
| + Label* deopt = compiler->AddDeoptStub(deopt_id_, kDeoptBinaryDoubleOp);
|
| + Label is_smi, done;
|
| +
|
| + __ andi(CMPRES, value, Immediate(kSmiTagMask));
|
| + __ beq(CMPRES, ZR, &is_smi);
|
| + __ LoadClassId(TMP, value);
|
| + __ BranchNotEqual(TMP, kDoubleCid, deopt);
|
| + __ LoadDFromOffset(result, value, Double::value_offset() - kHeapObjectTag);
|
| + __ b(&done);
|
| + __ Bind(&is_smi);
|
| + // TODO(regis): Why do we preserve value here but not above?
|
| + __ sra(TMP, value, 1);
|
| + __ mtc1(TMP, STMP1);
|
| + __ cvtdw(result, STMP1);
|
| + __ Bind(&done);
|
| + }
|
| }
|
|
|
|
|
| @@ -2476,13 +2761,28 @@
|
|
|
|
|
| LocationSummary* BinaryDoubleOpInstr::MakeLocationSummary() const {
|
| - UNIMPLEMENTED();
|
| - return NULL;
|
| + const intptr_t kNumInputs = 2;
|
| + const intptr_t kNumTemps = 0;
|
| + LocationSummary* summary =
|
| + new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
| + summary->set_in(0, Location::RequiresFpuRegister());
|
| + summary->set_in(1, Location::RequiresFpuRegister());
|
| + summary->set_out(Location::RequiresFpuRegister());
|
| + return summary;
|
| }
|
|
|
|
|
| void BinaryDoubleOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
| - UNIMPLEMENTED();
|
| + DRegister left = locs()->in(0).fpu_reg();
|
| + DRegister right = locs()->in(1).fpu_reg();
|
| + DRegister result = locs()->out().fpu_reg();
|
| + switch (op_kind()) {
|
| + case Token::kADD: __ addd(result, left, right); break;
|
| + case Token::kSUB: __ subd(result, left, right); break;
|
| + case Token::kMUL: __ muld(result, left, right); break;
|
| + case Token::kDIV: __ divd(result, left, right); break;
|
| + default: UNREACHABLE();
|
| + }
|
| }
|
|
|
|
|
| @@ -2707,24 +3007,56 @@
|
|
|
|
|
| LocationSummary* UnarySmiOpInstr::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());
|
| + // 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 UnarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
| - UNIMPLEMENTED();
|
| + Register value = locs()->in(0).reg();
|
| + Register result = locs()->out().reg();
|
| + switch (op_kind()) {
|
| + case Token::kNEGATE: {
|
| + Label* deopt = compiler->AddDeoptStub(deopt_id(),
|
| + kDeoptUnaryOp);
|
| + __ SubuDetectOverflow(result, ZR, value, CMPRES);
|
| + __ bltz(CMPRES, deopt);
|
| + break;
|
| + }
|
| + case Token::kBIT_NOT:
|
| + __ nor(result, value, ZR);
|
| + __ addiu(result, result, Immediate(-1)); // Remove inverted smi-tag.
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| }
|
|
|
|
|
| LocationSummary* SmiToDoubleInstr::MakeLocationSummary() const {
|
| - UNIMPLEMENTED();
|
| - return NULL;
|
| + const intptr_t kNumInputs = 1;
|
| + const intptr_t kNumTemps = 0;
|
| + LocationSummary* result =
|
| + new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
| + result->set_in(0, Location::WritableRegister());
|
| + result->set_out(Location::RequiresFpuRegister());
|
| + return result;
|
| }
|
|
|
|
|
| void SmiToDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
| - UNIMPLEMENTED();
|
| + Register value = locs()->in(0).reg();
|
| + FpuRegister result = locs()->out().fpu_reg();
|
| + __ SmiUntag(value);
|
| + __ mtc1(value, STMP1);
|
| + __ cvtdw(result, STMP1);
|
| }
|
|
|
|
|
| @@ -2762,13 +3094,34 @@
|
|
|
|
|
| LocationSummary* InvokeMathCFunctionInstr::MakeLocationSummary() const {
|
| - UNIMPLEMENTED();
|
| - return NULL;
|
| + ASSERT((InputCount() == 1) || (InputCount() == 2));
|
| + const intptr_t kNumTemps = 0;
|
| + LocationSummary* result =
|
| + new LocationSummary(InputCount(), kNumTemps, LocationSummary::kCall);
|
| + result->set_in(0, Location::FpuRegisterLocation(D6));
|
| + if (InputCount() == 2) {
|
| + result->set_in(1, Location::FpuRegisterLocation(D7));
|
| + }
|
| + result->set_out(Location::FpuRegisterLocation(D0));
|
| + return result;
|
| }
|
|
|
|
|
| void InvokeMathCFunctionInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
| - UNIMPLEMENTED();
|
| + // For pow-function return NAN if exponent is NAN.
|
| + Label do_call, skip_call;
|
| + if (recognized_kind() == MethodRecognizer::kDoublePow) {
|
| + DRegister exp = locs()->in(1).fpu_reg();
|
| + __ cund(exp, exp);
|
| + __ bc1f(&do_call);
|
| + // Exponent is NaN, return NaN.
|
| + __ movd(locs()->out().fpu_reg(), exp);
|
| + __ b(&skip_call);
|
| + }
|
| + __ Bind(&do_call);
|
| + // double values are passed and returned in vfp registers.
|
| + __ CallRuntime(TargetFunction());
|
| + __ Bind(&skip_call);
|
| }
|
|
|
|
|
| @@ -2844,7 +3197,8 @@
|
| if (null_check()) {
|
| Label* deopt = compiler->AddDeoptStub(deopt_id(),
|
| kDeoptCheckClass);
|
| - __ beq(locs()->in(0).reg(), NULLREG, deopt);
|
| + __ BranchEqual(locs()->in(0).reg(),
|
| + reinterpret_cast<int32_t>(Object::null()), deopt);
|
| return;
|
| }
|
|
|
| @@ -3131,6 +3485,7 @@
|
| // Special code for numbers (compare values instead of references.)
|
| void StrictCompareInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
| __ TraceSimMsg("StrictCompareInstr");
|
| + __ Comment("StrictCompareInstr");
|
| ASSERT(kind() == Token::kEQ_STRICT || kind() == Token::kNE_STRICT);
|
| Location left = locs()->in(0);
|
| Location right = locs()->in(1);
|
| @@ -3281,6 +3636,7 @@
|
|
|
| void AllocateObjectInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
| __ TraceSimMsg("AllocateObjectInstr");
|
| + __ Comment("AllocateObjectInstr");
|
| const Class& cls = Class::ZoneHandle(constructor().Owner());
|
| const Code& stub = Code::Handle(StubCode::GetAllocationStubForClass(cls));
|
| const ExternalLabel label(cls.ToCString(), stub.EntryPoint());
|
| @@ -3298,6 +3654,7 @@
|
|
|
|
|
| void CreateClosureInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
| + __ Comment("CreateClosureInstr");
|
| const Function& closure_function = function();
|
| ASSERT(!closure_function.IsImplicitStaticClosureFunction());
|
| const Code& stub = Code::Handle(
|
|
|