diff options
Diffstat (limited to 'compiler/optimizing')
-rw-r--r-- | compiler/optimizing/builder.cc | 30 | ||||
-rw-r--r-- | compiler/optimizing/builder.h | 3 | ||||
-rw-r--r-- | compiler/optimizing/code_generator.cc | 15 | ||||
-rw-r--r-- | compiler/optimizing/code_generator.h | 2 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_arm.cc | 34 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86.cc | 27 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86_64.cc | 36 | ||||
-rw-r--r-- | compiler/optimizing/nodes.h | 10 |
8 files changed, 131 insertions, 26 deletions
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index eb6181c71..0ac93a24f 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -337,9 +337,10 @@ void HGraphBuilder::Unop_12x(const Instruction& instruction, Primitive::Type typ void HGraphBuilder::Conversion_12x(const Instruction& instruction, Primitive::Type input_type, - Primitive::Type result_type) { + Primitive::Type result_type, + uint32_t dex_pc) { HInstruction* first = LoadLocal(instruction.VRegB(), input_type); - current_block_->AddInstruction(new (arena_) HTypeConversion(result_type, first)); + current_block_->AddInstruction(new (arena_) HTypeConversion(result_type, first, dex_pc)); UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction()); } @@ -1079,52 +1080,57 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 } case Instruction::INT_TO_LONG: { - Conversion_12x(instruction, Primitive::kPrimInt, Primitive::kPrimLong); + Conversion_12x(instruction, Primitive::kPrimInt, Primitive::kPrimLong, dex_pc); break; } case Instruction::INT_TO_FLOAT: { - Conversion_12x(instruction, Primitive::kPrimInt, Primitive::kPrimFloat); + Conversion_12x(instruction, Primitive::kPrimInt, Primitive::kPrimFloat, dex_pc); break; } case Instruction::INT_TO_DOUBLE: { - Conversion_12x(instruction, Primitive::kPrimInt, Primitive::kPrimDouble); + Conversion_12x(instruction, Primitive::kPrimInt, Primitive::kPrimDouble, dex_pc); break; } case Instruction::LONG_TO_INT: { - Conversion_12x(instruction, Primitive::kPrimLong, Primitive::kPrimInt); + Conversion_12x(instruction, Primitive::kPrimLong, Primitive::kPrimInt, dex_pc); break; } case Instruction::LONG_TO_FLOAT: { - Conversion_12x(instruction, Primitive::kPrimLong, Primitive::kPrimFloat); + Conversion_12x(instruction, Primitive::kPrimLong, Primitive::kPrimFloat, dex_pc); break; } case Instruction::LONG_TO_DOUBLE: { - Conversion_12x(instruction, Primitive::kPrimLong, Primitive::kPrimDouble); + Conversion_12x(instruction, Primitive::kPrimLong, Primitive::kPrimDouble, dex_pc); break; } case Instruction::FLOAT_TO_INT: { - Conversion_12x(instruction, Primitive::kPrimFloat, Primitive::kPrimInt); + Conversion_12x(instruction, Primitive::kPrimFloat, Primitive::kPrimInt, dex_pc); + break; + } + + case Instruction::FLOAT_TO_LONG: { + Conversion_12x(instruction, Primitive::kPrimFloat, Primitive::kPrimLong, dex_pc); break; } case Instruction::INT_TO_BYTE: { - Conversion_12x(instruction, Primitive::kPrimInt, Primitive::kPrimByte); + Conversion_12x(instruction, Primitive::kPrimInt, Primitive::kPrimByte, dex_pc); break; } case Instruction::INT_TO_SHORT: { - Conversion_12x(instruction, Primitive::kPrimInt, Primitive::kPrimShort); + Conversion_12x(instruction, Primitive::kPrimInt, Primitive::kPrimShort, dex_pc); break; } case Instruction::INT_TO_CHAR: { - Conversion_12x(instruction, Primitive::kPrimInt, Primitive::kPrimChar); + Conversion_12x(instruction, Primitive::kPrimInt, Primitive::kPrimChar, dex_pc); break; } diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h index 8519bcba6..59aba6a97 100644 --- a/compiler/optimizing/builder.h +++ b/compiler/optimizing/builder.h @@ -135,7 +135,8 @@ class HGraphBuilder : public ValueObject { void Conversion_12x(const Instruction& instruction, Primitive::Type input_type, - Primitive::Type result_type); + Primitive::Type result_type, + uint32_t dex_pc); void BuildCheckedDivRem(uint16_t out_reg, uint16_t first_reg, diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc index e581af22a..7f358eaa6 100644 --- a/compiler/optimizing/code_generator.cc +++ b/compiler/optimizing/code_generator.cc @@ -499,6 +499,21 @@ void CodeGenerator::BuildStackMaps(std::vector<uint8_t>* data) { } void CodeGenerator::RecordPcInfo(HInstruction* instruction, uint32_t dex_pc) { + if (instruction != nullptr && instruction->IsTypeConversion()) { + // The code generated for some type conversions may call the + // runtime, thus normally requiring a subsequent call to this + // method. However, the method verifier does not produce PC + // information for Dex type conversion instructions, as it + // considers them as "atomic" (they cannot join a GC). + // Therefore we do not currently record PC information for such + // instructions. As this may change later, we added this special + // case so that code generators may nevertheless call + // CodeGenerator::RecordPcInfo without triggering an error in + // CodeGenerator::BuildNativeGCMap ("Missing ref for dex pc 0x") + // thereafter. + return; + } + // Collect PC infos for the mapping table. struct PcInfo pc_info; pc_info.dex_pc = dex_pc; diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h index 7c8f6a2d2..1d42c47d5 100644 --- a/compiler/optimizing/code_generator.h +++ b/compiler/optimizing/code_generator.h @@ -37,6 +37,8 @@ static int64_t constexpr k2Pow31EncodingForDouble = INT64_C(0x41E0000000000000); // Maximum value for a primitive integer. static int32_t constexpr kPrimIntMax = 0x7fffffff; +// Maximum value for a primitive long. +static int64_t constexpr kPrimLongMax = 0x7fffffffffffffff; class Assembler; class CodeGenerator; diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index 448a5a070..f0506051c 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -44,8 +44,9 @@ static constexpr int kCurrentMethodStackOffset = 0; static constexpr Register kRuntimeParameterCoreRegisters[] = { R0, R1, R2, R3 }; static constexpr size_t kRuntimeParameterCoreRegistersLength = arraysize(kRuntimeParameterCoreRegisters); -static constexpr SRegister kRuntimeParameterFpuRegisters[] = { }; -static constexpr size_t kRuntimeParameterFpuRegistersLength = 0; +static constexpr SRegister kRuntimeParameterFpuRegisters[] = { S0 }; +static constexpr size_t kRuntimeParameterFpuRegistersLength = + arraysize(kRuntimeParameterFpuRegisters); class InvokeRuntimeCallingConvention : public CallingConvention<Register, SRegister> { public: @@ -874,6 +875,7 @@ void CodeGeneratorARM::InvokeRuntime(int32_t entry_point_offset, || instruction->IsBoundsCheck() || instruction->IsNullCheck() || instruction->IsDivZeroCheck() + || instruction->GetLocations()->CanCall() || !IsLeafMethod()); } @@ -1359,11 +1361,18 @@ void InstructionCodeGeneratorARM::VisitNeg(HNeg* neg) { } void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) { - LocationSummary* locations = - new (GetGraph()->GetArena()) LocationSummary(conversion, LocationSummary::kNoCall); Primitive::Type result_type = conversion->GetResultType(); Primitive::Type input_type = conversion->GetInputType(); DCHECK_NE(result_type, input_type); + + // Float-to-long conversions invoke the runtime. + LocationSummary::CallKind call_kind = + (input_type == Primitive::kPrimFloat && result_type == Primitive::kPrimLong) + ? LocationSummary::kCall + : LocationSummary::kNoCall; + LocationSummary* locations = + new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind); + switch (result_type) { case Primitive::kPrimByte: switch (input_type) { @@ -1434,7 +1443,15 @@ void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) { locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); break; - case Primitive::kPrimFloat: + case Primitive::kPrimFloat: { + // Processing a Dex `float-to-long' instruction. + InvokeRuntimeCallingConvention calling_convention; + locations->SetInAt(0, Location::FpuRegisterLocation( + calling_convention.GetFpuRegisterAt(0))); + locations->SetOut(Location::RegisterPairLocation(R0, R1)); + break; + } + case Primitive::kPrimDouble: LOG(FATAL) << "Type conversion from " << input_type << " to " << result_type << " not yet implemented"; @@ -1623,6 +1640,13 @@ void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversio break; case Primitive::kPrimFloat: + // Processing a Dex `float-to-long' instruction. + // This call does not actually record PC information. + codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pF2l), + conversion, + conversion->GetDexPc()); + break; + case Primitive::kPrimDouble: LOG(FATAL) << "Type conversion from " << input_type << " to " << result_type << " not yet implemented"; diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index 6f83d9faf..38dc8c564 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -1326,11 +1326,18 @@ void InstructionCodeGeneratorX86::VisitNeg(HNeg* neg) { } void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) { - LocationSummary* locations = - new (GetGraph()->GetArena()) LocationSummary(conversion, LocationSummary::kNoCall); Primitive::Type result_type = conversion->GetResultType(); Primitive::Type input_type = conversion->GetInputType(); DCHECK_NE(result_type, input_type); + + // Float-to-long conversions invoke the runtime. + LocationSummary::CallKind call_kind = + (input_type == Primitive::kPrimFloat && result_type == Primitive::kPrimLong) + ? LocationSummary::kCall + : LocationSummary::kNoCall; + LocationSummary* locations = + new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind); + switch (result_type) { case Primitive::kPrimByte: switch (input_type) { @@ -1401,7 +1408,15 @@ void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) { locations->SetOut(Location::RegisterPairLocation(EAX, EDX)); break; - case Primitive::kPrimFloat: + case Primitive::kPrimFloat: { + // Processing a Dex `float-to-long' instruction. + InvokeRuntimeCallingConvention calling_convention; + locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); + // The runtime helper puts the result in EAX, EDX. + locations->SetOut(Location::RegisterPairLocation(EAX, EDX)); + break; + } + case Primitive::kPrimDouble: LOG(FATAL) << "Type conversion from " << input_type << " to " << result_type << " not yet implemented"; @@ -1615,6 +1630,12 @@ void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversio break; case Primitive::kPrimFloat: + // Processing a Dex `float-to-long' instruction. + __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pF2l))); + // This call does not actually record PC information. + codegen_->RecordPcInfo(conversion, conversion->GetDexPc()); + break; + case Primitive::kPrimDouble: LOG(FATAL) << "Type conversion from " << input_type << " to " << result_type << " not yet implemented"; diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index 47fd30496..7eecac1b5 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -1394,6 +1394,12 @@ void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) { break; case Primitive::kPrimFloat: + // Processing a Dex `float-to-long' instruction. + locations->SetInAt(0, Location::RequiresFpuRegister()); + locations->SetOut(Location::RequiresRegister()); + locations->AddTemp(Location::RequiresFpuRegister()); + break; + case Primitive::kPrimDouble: LOG(FATAL) << "Type conversion from " << input_type << " to " << result_type << " not yet implemented"; @@ -1565,14 +1571,14 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver __ movl(output, Immediate(kPrimIntMax)); // temp = int-to-float(output) - __ cvtsi2ss(temp, output); + __ cvtsi2ss(temp, output, false); // if input >= temp goto done __ comiss(input, temp); __ j(kAboveEqual, &done); // if input == NaN goto nan __ j(kUnordered, &nan); // output = float-to-int-truncate(input) - __ cvttss2si(output, input); + __ cvttss2si(output, input, false); __ jmp(&done); __ Bind(&nan); // output = 0 @@ -1604,7 +1610,31 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver __ movsxd(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>()); break; - case Primitive::kPrimFloat: + case Primitive::kPrimFloat: { + // Processing a Dex `float-to-long' instruction. + XmmRegister input = in.AsFpuRegister<XmmRegister>(); + CpuRegister output = out.AsRegister<CpuRegister>(); + XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>(); + Label done, nan; + + __ movq(output, Immediate(kPrimLongMax)); + // temp = int-to-float(output) + __ cvtsi2ss(temp, output, true); + // if input >= temp goto done + __ comiss(input, temp); + __ j(kAboveEqual, &done); + // if input == NaN goto nan + __ j(kUnordered, &nan); + // output = float-to-int-truncate(input) + __ cvttss2si(output, input, true); + __ jmp(&done); + __ Bind(&nan); + // output = 0 + __ xorq(output, output); + __ Bind(&done); + break; + } + case Primitive::kPrimDouble: LOG(FATAL) << "Type conversion from " << input_type << " to " << result_type << " not yet implemented"; diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 3908a6191..8a25de19d 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -2001,8 +2001,8 @@ class HNot : public HUnaryOperation { class HTypeConversion : public HExpression<1> { public: // Instantiate a type conversion of `input` to `result_type`. - HTypeConversion(Primitive::Type result_type, HInstruction* input) - : HExpression(result_type, SideEffects::None()) { + HTypeConversion(Primitive::Type result_type, HInstruction* input, uint32_t dex_pc) + : HExpression(result_type, SideEffects::None()), dex_pc_(dex_pc) { SetRawInputAt(0, input); DCHECK_NE(input->GetType(), result_type); } @@ -2011,12 +2011,18 @@ class HTypeConversion : public HExpression<1> { Primitive::Type GetInputType() const { return GetInput()->GetType(); } Primitive::Type GetResultType() const { return GetType(); } + // Required by the x86 and ARM code generators when producing calls + // to the runtime. + uint32_t GetDexPc() const { return dex_pc_; } + bool CanBeMoved() const OVERRIDE { return true; } bool InstructionDataEquals(HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE { return true; } DECLARE_INSTRUCTION(TypeConversion); private: + const uint32_t dex_pc_; + DISALLOW_COPY_AND_ASSIGN(HTypeConversion); }; |