Chromium Code Reviews| Index: runtime/vm/intermediate_language_arm.cc |
| =================================================================== |
| --- runtime/vm/intermediate_language_arm.cc (revision 23368) |
| +++ 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(); |
| @@ -2057,19 +2083,31 @@ |
| LocationSummary* BinarySmiOpInstr::MakeLocationSummary() const { |
| 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()); |
| + 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; |
| } |
| + const intptr_t kNumTemps = 0; |
|
zra
2013/05/29 22:54:07
Could you have just one kNumTemps and one summary
regis
2013/05/29 23:10:14
Done.
|
| + 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; |
| } |
| @@ -2130,7 +2168,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 +2307,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 +2353,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) { |
| + __ vldrd(result, FieldAddress(value, Double::value_offset())); |
|
zra
2013/05/29 22:54:07
You can't use FieldAddress in vldrd, right?
regis
2013/05/29 23:10:14
Done.
|
| + } else if (value_cid == kSmiCid) { |
| + __ SmiUntag(value); // Untag input before conversion. |
| + __ vmovsr(S0, value); |
|
zra
2013/05/29 22:54:07
I didn't check, but if there is a problem with reg
regis
2013/05/29 23:10:14
FpuTMP is set to D0 on ARM. So D0 will not be used
|
| + __ 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 +2537,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 +2782,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(); |
| + } |
| } |