| Index: runtime/vm/intermediate_language_arm.cc
|
| ===================================================================
|
| --- runtime/vm/intermediate_language_arm.cc (revision 23369)
|
| +++ runtime/vm/intermediate_language_arm.cc (working copy)
|
| @@ -1135,7 +1135,33 @@
|
| 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.
|
| + // vldrs does not support indexed addressing.
|
| + __ add(index.reg(), index.reg(), ShifterOperand(array));
|
| + element_address = Address(index.reg(), 0);
|
| + __ vldrs(S0, element_address);
|
| + __ vcvtds(result, S0);
|
| + break;
|
| + case kTypedDataFloat64ArrayCid:
|
| + // vldrd does not support indexed addressing.
|
| + __ add(index.reg(), index.reg(), ShifterOperand(array));
|
| + element_address = Address(index.reg(), 0);
|
| + __ vldrd(result, element_address);
|
| + break;
|
| + case kTypedDataFloat32x4ArrayCid:
|
| + UNIMPLEMENTED();
|
| + break;
|
| + }
|
| + return;
|
| }
|
|
|
| Register result = locs()->out().reg();
|
| @@ -2056,20 +2082,29 @@
|
|
|
| LocationSummary* BinarySmiOpInstr::MakeLocationSummary() const {
|
| const intptr_t kNumInputs = 2;
|
| + const intptr_t kNumTemps = 0;
|
| + LocationSummary* summary =
|
| + new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
| 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());
|
| + 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());
|
| + }
|
| return summary;
|
| }
|
| + 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;
|
| }
|
|
|
|
|
| @@ -2130,7 +2165,31 @@
|
| break;
|
| }
|
| case Token::kTRUNCDIV: {
|
| - UNIMPLEMENTED();
|
| + const intptr_t value = Smi::Cast(constant).Value();
|
| + if (value == 1) {
|
| + // Do nothing.
|
| + break;
|
| + } else if (value == -1) {
|
| + // Check the corner case of dividing the 'MIN_SMI' with -1, in which
|
| + // case we cannot negate the result.
|
| + __ CompareImmediate(left, 0x80000000);
|
| + __ b(deopt, EQ);
|
| + __ rsb(result, left, ShifterOperand(0));
|
| + break;
|
| + }
|
| + ASSERT((value != 0) && Utils::IsPowerOfTwo(Utils::Abs(value)));
|
| + const intptr_t shift_count =
|
| + Utils::ShiftForPowerOfTwo(Utils::Abs(value)) + kSmiTagSize;
|
| + ASSERT(kSmiTagSize == 1);
|
| + __ mov(IP, ShifterOperand(left, ASR, 31));
|
| + ASSERT(shift_count > 1); // 1, -1 case handled above.
|
| + __ add(left, left, ShifterOperand(IP, LSR, 32 - shift_count));
|
| + ASSERT(shift_count > 0);
|
| + __ mov(result, ShifterOperand(left, ASR, shift_count));
|
| + if (value < 0) {
|
| + __ rsb(result, result, ShifterOperand(0));
|
| + }
|
| + __ SmiTag(result);
|
| break;
|
| }
|
| case Token::kBIT_AND: {
|
| @@ -2245,7 +2304,20 @@
|
| break;
|
| }
|
| case Token::kTRUNCDIV: {
|
| - UNIMPLEMENTED();
|
| + // Handle divide by zero in runtime.
|
| + __ cmp(right, ShifterOperand(0));
|
| + __ b(deopt, EQ);
|
| + __ SmiUntag(left);
|
| + __ SmiUntag(right);
|
| + if (!CPUFeatures::integer_division_supported()) {
|
| + UNIMPLEMENTED();
|
| + }
|
| + __ sdiv(result, left, right);
|
| + // Check the corner case of dividing the 'MIN_SMI' with -1, in which
|
| + // case we cannot tag the result.
|
| + __ CompareImmediate(result, 0x40000000);
|
| + __ b(deopt, EQ);
|
| + __ SmiTag(result);
|
| break;
|
| }
|
| case Token::kSHR: {
|
| @@ -2278,35 +2350,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) {
|
| + __ tst(right, ShifterOperand(kSmiTagMask));
|
| + } else if (right_cid == kSmiCid) {
|
| + __ tst(left, ShifterOperand(kSmiTagMask));
|
| + } else {
|
| + __ orr(IP, left, ShifterOperand(right));
|
| + __ tst(IP, ShifterOperand(kSmiTagMask));
|
| + }
|
| + __ b(deopt, EQ);
|
| }
|
|
|
|
|
| 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);
|
| + __ MoveRegister(locs->out().reg(), R0);
|
| + 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_temp = ((value_cid != kSmiCid) && (value_cid != kDoubleCid));
|
| + const bool needs_writable_input = (value_cid == kSmiCid);
|
| + const intptr_t kNumTemps = needs_temp ? 1 : 0;
|
| + LocationSummary* summary =
|
| + new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
| + summary->set_in(0, needs_writable_input
|
| + ? Location::WritableRegister()
|
| + : Location::RequiresRegister());
|
| + if (needs_temp) summary->set_temp(0, 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.
|
| + __ vmovsr(S0, value);
|
| + __ vcvtdi(result, S0);
|
| + } else {
|
| + Label* deopt = compiler->AddDeoptStub(deopt_id_, kDeoptBinaryDoubleOp);
|
| + Register temp = locs()->temp(0).reg();
|
| + Label is_smi, done;
|
| + __ tst(value, ShifterOperand(kSmiTagMask));
|
| + __ b(&is_smi, EQ);
|
| + __ CompareClassId(value, kDoubleCid, temp);
|
| + __ b(deopt, NE);
|
| + __ LoadDFromOffset(result, value, Double::value_offset() - kHeapObjectTag);
|
| + __ b(&done);
|
| + __ Bind(&is_smi);
|
| + // TODO(regis): Why do we preserve value here but not above?
|
| + __ mov(IP, ShifterOperand(value, ASR, 1)); // Copy and untag.
|
| + __ vmovsr(S0, IP);
|
| + __ vcvtdi(result, S0);
|
| + __ Bind(&done);
|
| + }
|
| }
|
|
|
|
|
| @@ -2355,13 +2534,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: __ vaddd(result, left, right); break;
|
| + case Token::kSUB: __ vsubd(result, left, right); break;
|
| + case Token::kMUL: __ vmuld(result, left, right); break;
|
| + case Token::kDIV: __ vdivd(result, left, right); break;
|
| + default: UNREACHABLE();
|
| + }
|
| }
|
|
|
|
|
| @@ -2585,13 +2779,37 @@
|
|
|
|
|
| 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);
|
| + __ rsbs(result, value, ShifterOperand(0));
|
| + __ b(deopt, VS);
|
| + break;
|
| + }
|
| + case Token::kBIT_NOT:
|
| + __ mvn(result, ShifterOperand(value));
|
| + // Remove inverted smi-tag.
|
| + __ bic(result, result, ShifterOperand(kSmiTagMask));
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| }
|
|
|
|
|
|
|