diff options
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/dex/mir_optimization.cc | 4 | ||||
| -rw-r--r-- | compiler/image_writer.cc | 131 | ||||
| -rw-r--r-- | compiler/optimizing/builder.cc | 10 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_arm.cc | 43 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_x86.cc | 64 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_x86_64.cc | 68 | ||||
| -rw-r--r-- | compiler/utils/x86_64/assembler_x86_64.cc | 12 | ||||
| -rw-r--r-- | compiler/utils/x86_64/assembler_x86_64.h | 1 |
8 files changed, 212 insertions, 121 deletions
diff --git a/compiler/dex/mir_optimization.cc b/compiler/dex/mir_optimization.cc index 55f2abcd3f..3c6b61de89 100644 --- a/compiler/dex/mir_optimization.cc +++ b/compiler/dex/mir_optimization.cc @@ -795,10 +795,6 @@ bool MIRGraph::LayoutBlocks(BasicBlock* bb) { break; } walker = prev; - - if (walker->visited) { - break; - } } return false; } diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc index ab5c6c77de..a45c2d1bab 100644 --- a/compiler/image_writer.cc +++ b/compiler/image_writer.cc @@ -480,34 +480,29 @@ class StringCollector { }; // Compare strings based on length, used for sorting strings by length / reverse length. -class StringLengthComparator { +class LexicographicalStringComparator { public: - explicit StringLengthComparator(Handle<mirror::ObjectArray<mirror::String>> strings) - : strings_(strings) { + bool operator()(const mirror::HeapReference<mirror::String>& lhs, + const mirror::HeapReference<mirror::String>& rhs) const + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + mirror::String* lhs_s = lhs.AsMirrorPtr(); + mirror::String* rhs_s = rhs.AsMirrorPtr(); + uint16_t* lhs_begin = lhs_s->GetCharArray()->GetData() + lhs_s->GetOffset(); + uint16_t* rhs_begin = rhs_s->GetCharArray()->GetData() + rhs_s->GetOffset(); + return std::lexicographical_compare(lhs_begin, lhs_begin + lhs_s->GetLength(), + rhs_begin, rhs_begin + rhs_s->GetLength()); } - bool operator()(size_t a, size_t b) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - return strings_->GetWithoutChecks(a)->GetLength() < strings_->GetWithoutChecks(b)->GetLength(); - } - - private: - Handle<mirror::ObjectArray<mirror::String>> strings_; }; -// Normal string < comparison through the chars_ array. -class SubstringComparator { - public: - explicit SubstringComparator(const std::vector<uint16_t>* const chars) : chars_(chars) { - } - bool operator()(const std::pair<size_t, size_t>& a, const std::pair<size_t, size_t>& b) { - return std::lexicographical_compare(chars_->begin() + a.first, - chars_->begin() + a.first + a.second, - chars_->begin() + b.first, - chars_->begin() + b.first + b.second); +static bool IsPrefix(mirror::String* pref, mirror::String* full) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + if (pref->GetLength() > full->GetLength()) { + return false; } - - private: - const std::vector<uint16_t>* const chars_; -}; + uint16_t* pref_begin = pref->GetCharArray()->GetData() + pref->GetOffset(); + uint16_t* full_begin = full->GetCharArray()->GetData() + full->GetOffset(); + return std::equal(pref_begin, pref_begin + pref->GetLength(), full_begin); +} void ImageWriter::ProcessStrings() { size_t total_strings = 0; @@ -529,67 +524,51 @@ void ImageWriter::ProcessStrings() { // Some strings could have gotten freed if AllocStringArray caused a GC. CHECK_LE(string_collector.GetIndex(), total_strings); total_strings = string_collector.GetIndex(); - size_t total_length = 0; - std::vector<size_t> reverse_sorted_strings; - for (size_t i = 0; i < total_strings; ++i) { - mirror::String* s = strings->GetWithoutChecks(i); - // Look up the string in the array. - total_length += s->GetLength(); - reverse_sorted_strings.push_back(i); - } - // Sort by reverse length. - StringLengthComparator comparator(strings); - std::sort(reverse_sorted_strings.rbegin(), reverse_sorted_strings.rend(), comparator); - // Deduplicate prefixes and add strings to the char array. - std::vector<uint16_t> combined_chars(total_length, 0U); - size_t num_chars = 0; + auto* strings_begin = reinterpret_cast<mirror::HeapReference<mirror::String>*>( + strings->GetRawData(sizeof(mirror::HeapReference<mirror::String>), 0)); + std::sort(strings_begin, strings_begin + total_strings, LexicographicalStringComparator()); // Characters of strings which are non equal prefix of another string (not the same string). // We don't count the savings from equal strings since these would get interned later anyways. size_t prefix_saved_chars = 0; - std::set<std::pair<size_t, size_t>, SubstringComparator> existing_strings(( - SubstringComparator(&combined_chars))); - for (size_t i = 0; i < total_strings; ++i) { - mirror::String* s = strings->GetWithoutChecks(reverse_sorted_strings[i]); - // Add the string to the end of the char array. + // Count characters needed for the strings. + size_t num_chars = 0u; + mirror::String* prev_s = nullptr; + for (size_t idx = 0; idx != total_strings; ++idx) { + mirror::String* s = strings->GetWithoutChecks(idx); size_t length = s->GetLength(); - for (size_t j = 0; j < length; ++j) { - combined_chars[num_chars++] = s->CharAt(j); - } - // Try to see if the string exists as a prefix of an existing string. - size_t new_offset = 0; - std::pair<size_t, size_t> new_string(num_chars - length, length); - auto it = existing_strings.lower_bound(new_string); - bool is_prefix = false; - if (it != existing_strings.end()) { - CHECK_LE(length, it->second); - is_prefix = std::equal(combined_chars.begin() + new_string.first, - combined_chars.begin() + new_string.first + new_string.second, - combined_chars.begin() + it->first); - } - if (is_prefix) { - // Shares a prefix, set the offset to where the new offset will be. - new_offset = it->first; - // Remove the added chars. - num_chars -= length; - if (it->second != length) { - prefix_saved_chars += length; + num_chars += length; + if (prev_s != nullptr && IsPrefix(prev_s, s)) { + size_t prev_length = prev_s->GetLength(); + num_chars -= prev_length; + if (prev_length != length) { + prefix_saved_chars += prev_length; } - } else { - new_offset = new_string.first; - existing_strings.insert(new_string); } - s->SetOffset(new_offset); - } - // Allocate and update the char arrays. - auto* array = mirror::CharArray::Alloc(self, num_chars); - for (size_t i = 0; i < num_chars; ++i) { - array->SetWithoutChecks<false>(i, combined_chars[i]); - } - for (size_t i = 0; i < total_strings; ++i) { - strings->GetWithoutChecks(i)->SetArray(array); + prev_s = s; + } + // Create character array, copy characters and point the strings there. + mirror::CharArray* array = mirror::CharArray::Alloc(self, num_chars); + uint16_t* array_data = array->GetData(); + size_t pos = 0u; + prev_s = nullptr; + for (size_t idx = 0; idx != total_strings; ++idx) { + mirror::String* s = strings->GetWithoutChecks(idx); + uint16_t* s_data = s->GetCharArray()->GetData() + s->GetOffset(); + int32_t s_length = s->GetLength(); + int32_t prefix_length = 0u; + if (idx != 0u && IsPrefix(prev_s, s)) { + prefix_length = prev_s->GetLength(); + } + memcpy(array_data + pos, s_data + prefix_length, (s_length - prefix_length) * sizeof(*s_data)); + s->SetOffset(pos - prefix_length); + s->SetArray(array); + pos += s_length - prefix_length; + prev_s = s; } + CHECK_EQ(pos, num_chars); + LOG(INFO) << "Total # image strings=" << total_strings << " combined length=" - << total_length << " prefix saved chars=" << prefix_saved_chars; + << num_chars << " prefix saved chars=" << prefix_saved_chars; ComputeEagerResolvedStrings(); } diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index 9561054b69..ca72f3f242 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -1306,6 +1306,16 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 break; } + case Instruction::DOUBLE_TO_INT: { + Conversion_12x(instruction, Primitive::kPrimDouble, Primitive::kPrimInt, dex_pc); + break; + } + + case Instruction::DOUBLE_TO_LONG: { + Conversion_12x(instruction, Primitive::kPrimDouble, Primitive::kPrimLong, dex_pc); + break; + } + case Instruction::DOUBLE_TO_FLOAT: { Conversion_12x(instruction, Primitive::kPrimDouble, Primitive::kPrimFloat, dex_pc); break; diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index 5076c85885..36af393e3b 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -44,7 +44,7 @@ static constexpr int kCurrentMethodStackOffset = 0; static constexpr Register kRuntimeParameterCoreRegisters[] = { R0, R1, R2, R3 }; static constexpr size_t kRuntimeParameterCoreRegistersLength = arraysize(kRuntimeParameterCoreRegisters); -static constexpr SRegister kRuntimeParameterFpuRegisters[] = { S0 }; +static constexpr SRegister kRuntimeParameterFpuRegisters[] = { S0, S1 }; static constexpr size_t kRuntimeParameterFpuRegistersLength = arraysize(kRuntimeParameterFpuRegisters); @@ -1365,9 +1365,11 @@ void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) { Primitive::Type input_type = conversion->GetInputType(); DCHECK_NE(result_type, input_type); - // Float-to-long conversions invoke the runtime. + // The float-to-long and double-to-long type conversions rely on a + // call to the runtime. LocationSummary::CallKind call_kind = - (input_type == Primitive::kPrimFloat && result_type == Primitive::kPrimLong) + ((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble) + && result_type == Primitive::kPrimLong) ? LocationSummary::kCall : LocationSummary::kNoCall; LocationSummary* locations = @@ -1422,8 +1424,10 @@ void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) { break; case Primitive::kPrimDouble: - LOG(FATAL) << "Type conversion from " << input_type - << " to " << result_type << " not yet implemented"; + // Processing a Dex `double-to-int' instruction. + locations->SetInAt(0, Location::RequiresFpuRegister()); + locations->SetOut(Location::RequiresRegister()); + locations->AddTemp(Location::RequiresFpuRegister()); break; default: @@ -1452,10 +1456,15 @@ void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) { break; } - case Primitive::kPrimDouble: - LOG(FATAL) << "Type conversion from " << input_type << " to " - << result_type << " not yet implemented"; + case Primitive::kPrimDouble: { + // Processing a Dex `double-to-long' instruction. + InvokeRuntimeCallingConvention calling_convention; + locations->SetInAt(0, Location::FpuRegisterPairLocation( + calling_convention.GetFpuRegisterAt(0), + calling_convention.GetFpuRegisterAt(1))); + locations->SetOut(Location::RegisterPairLocation(R0, R1)); break; + } default: LOG(FATAL) << "Unexpected type conversion from " << input_type @@ -1614,10 +1623,15 @@ void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversio break; } - case Primitive::kPrimDouble: - LOG(FATAL) << "Type conversion from " << input_type - << " to " << result_type << " not yet implemented"; + case Primitive::kPrimDouble: { + // Processing a Dex `double-to-int' instruction. + SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>(); + DRegister temp_d = FromLowSToD(temp_s); + __ vmovd(temp_d, FromLowSToD(in.AsFpuRegisterPairLow<SRegister>())); + __ vcvtid(temp_s, temp_d); + __ vmovrs(out.AsRegister<Register>(), temp_s); break; + } default: LOG(FATAL) << "Unexpected type conversion from " << input_type @@ -1643,15 +1657,16 @@ void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversio 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"; + // Processing a Dex `double-to-long' instruction. + codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pD2l), + conversion, + conversion->GetDexPc()); break; default: diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index 2aa121d04b..2fd712f7e2 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -1330,9 +1330,11 @@ void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) { Primitive::Type input_type = conversion->GetInputType(); DCHECK_NE(result_type, input_type); - // Float-to-long conversions invoke the runtime. + // The float-to-long and double-to-long type conversions rely on a + // call to the runtime. LocationSummary::CallKind call_kind = - (input_type == Primitive::kPrimFloat && result_type == Primitive::kPrimLong) + ((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble) + && result_type == Primitive::kPrimLong) ? LocationSummary::kCall : LocationSummary::kNoCall; LocationSummary* locations = @@ -1387,8 +1389,10 @@ void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) { break; case Primitive::kPrimDouble: - LOG(FATAL) << "Type conversion from " << input_type - << " to " << result_type << " not yet implemented"; + // Processing a Dex `double-to-int' instruction. + locations->SetInAt(0, Location::RequiresFpuRegister()); + locations->SetOut(Location::RequiresRegister()); + locations->AddTemp(Location::RequiresFpuRegister()); break; default: @@ -1411,15 +1415,27 @@ void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) { case Primitive::kPrimFloat: { // Processing a Dex `float-to-long' instruction. InvokeRuntimeCallingConvention calling_convention; - locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); + // Note that on x86 floating-point parameters are passed + // through core registers (here, EAX). + 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"; + case Primitive::kPrimDouble: { + // Processing a Dex `double-to-long' instruction. + InvokeRuntimeCallingConvention calling_convention; + // Note that on x86 floating-point parameters are passed + // through core registers (here, EAX and ECX). + locations->SetInAt(0, Location::RegisterPairLocation( + calling_convention.GetRegisterAt(0), + calling_convention.GetRegisterAt(1))); + // The runtime helper puts the result in EAX, EDX. + locations->SetOut(Location::RegisterPairLocation(EAX, EDX)); + break; + } break; default: @@ -1607,10 +1623,30 @@ void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversio break; } - case Primitive::kPrimDouble: - LOG(FATAL) << "Type conversion from " << input_type - << " to " << result_type << " not yet implemented"; + case Primitive::kPrimDouble: { + // Processing a Dex `double-to-int' instruction. + XmmRegister input = in.AsFpuRegister<XmmRegister>(); + Register output = out.AsRegister<Register>(); + XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>(); + Label done, nan; + + __ movl(output, Immediate(kPrimIntMax)); + // temp = int-to-double(output) + __ cvtsi2sd(temp, output); + // if input >= temp goto done + __ comisd(input, temp); + __ j(kAboveEqual, &done); + // if input == NaN goto nan + __ j(kUnordered, &nan); + // output = double-to-int-truncate(input) + __ cvttsd2si(output, input); + __ jmp(&done); + __ Bind(&nan); + // output = 0 + __ xorl(output, output); + __ Bind(&done); break; + } default: LOG(FATAL) << "Unexpected type conversion from " << input_type @@ -1634,13 +1670,13 @@ void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversio 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"; + // Processing a Dex `double-to-long' instruction. + __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pD2l))); + codegen_->RecordPcInfo(conversion, conversion->GetDexPc()); break; default: diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index 5761fb1bda..39a97661c9 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -1370,8 +1370,10 @@ void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) { break; case Primitive::kPrimDouble: - LOG(FATAL) << "Type conversion from " << input_type - << " to " << result_type << " not yet implemented"; + // Processing a Dex `double-to-int' instruction. + locations->SetInAt(0, Location::RequiresFpuRegister()); + locations->SetOut(Location::RequiresRegister()); + locations->AddTemp(Location::RequiresFpuRegister()); break; default: @@ -1401,8 +1403,10 @@ void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) { break; case Primitive::kPrimDouble: - LOG(FATAL) << "Type conversion from " << input_type << " to " - << result_type << " not yet implemented"; + // Processing a Dex `double-to-long' instruction. + locations->SetInAt(0, Location::RequiresFpuRegister()); + locations->SetOut(Location::RequiresRegister()); + locations->AddTemp(Location::RequiresFpuRegister()); break; default: @@ -1589,10 +1593,30 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver break; } - case Primitive::kPrimDouble: - LOG(FATAL) << "Type conversion from " << input_type - << " to " << result_type << " not yet implemented"; + case Primitive::kPrimDouble: { + // Processing a Dex `double-to-int' instruction. + XmmRegister input = in.AsFpuRegister<XmmRegister>(); + CpuRegister output = out.AsRegister<CpuRegister>(); + XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>(); + Label done, nan; + + __ movl(output, Immediate(kPrimIntMax)); + // temp = int-to-double(output) + __ cvtsi2sd(temp, output); + // if input >= temp goto done + __ comisd(input, temp); + __ j(kAboveEqual, &done); + // if input == NaN goto nan + __ j(kUnordered, &nan); + // output = double-to-int-truncate(input) + __ cvttsd2si(output, input); + __ jmp(&done); + __ Bind(&nan); + // output = 0 + __ xorl(output, output); + __ Bind(&done); break; + } default: LOG(FATAL) << "Unexpected type conversion from " << input_type @@ -1620,14 +1644,14 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver Label done, nan; __ movq(output, Immediate(kPrimLongMax)); - // temp = int-to-float(output) + // temp = long-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) + // output = float-to-long-truncate(input) __ cvttss2si(output, input, true); __ jmp(&done); __ Bind(&nan); @@ -1637,10 +1661,30 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver break; } - case Primitive::kPrimDouble: - LOG(FATAL) << "Type conversion from " << input_type << " to " - << result_type << " not yet implemented"; + case Primitive::kPrimDouble: { + // Processing a Dex `double-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 = long-to-double(output) + __ cvtsi2sd(temp, output, true); + // if input >= temp goto done + __ comisd(input, temp); + __ j(kAboveEqual, &done); + // if input == NaN goto nan + __ j(kUnordered, &nan); + // output = double-to-long-truncate(input) + __ cvttsd2si(output, input, true); + __ jmp(&done); + __ Bind(&nan); + // output = 0 + __ xorq(output, output); + __ Bind(&done); break; + } default: LOG(FATAL) << "Unexpected type conversion from " << input_type diff --git a/compiler/utils/x86_64/assembler_x86_64.cc b/compiler/utils/x86_64/assembler_x86_64.cc index 3c21236a8a..2a6c58e128 100644 --- a/compiler/utils/x86_64/assembler_x86_64.cc +++ b/compiler/utils/x86_64/assembler_x86_64.cc @@ -683,9 +683,19 @@ void X86_64Assembler::cvttss2si(CpuRegister dst, XmmRegister src, bool is64bit) void X86_64Assembler::cvttsd2si(CpuRegister dst, XmmRegister src) { + cvttsd2si(dst, src, false); +} + + +void X86_64Assembler::cvttsd2si(CpuRegister dst, XmmRegister src, bool is64bit) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0xF2); - EmitOptionalRex32(dst, src); + if (is64bit) { + // Emit a REX.W prefix if the operand size is 64 bits. + EmitRex64(dst, src); + } else { + EmitOptionalRex32(dst, src); + } EmitUint8(0x0F); EmitUint8(0x2C); EmitXmmRegisterOperand(dst.LowBits(), src); diff --git a/compiler/utils/x86_64/assembler_x86_64.h b/compiler/utils/x86_64/assembler_x86_64.h index 4c2836665d..51d1de2c0f 100644 --- a/compiler/utils/x86_64/assembler_x86_64.h +++ b/compiler/utils/x86_64/assembler_x86_64.h @@ -342,6 +342,7 @@ class X86_64Assembler FINAL : public Assembler { void cvttss2si(CpuRegister dst, XmmRegister src); // Note: this is the r32 version. void cvttss2si(CpuRegister dst, XmmRegister src, bool is64bit); void cvttsd2si(CpuRegister dst, XmmRegister src); // Note: this is the r32 version. + void cvttsd2si(CpuRegister dst, XmmRegister src, bool is64bit); void cvtdq2pd(XmmRegister dst, XmmRegister src); |