diff options
Diffstat (limited to 'compiler')
22 files changed, 605 insertions, 185 deletions
diff --git a/compiler/jni/quick/arm/calling_convention_arm.cc b/compiler/jni/quick/arm/calling_convention_arm.cc index 769cd4c83d..a3323e133a 100644 --- a/compiler/jni/quick/arm/calling_convention_arm.cc +++ b/compiler/jni/quick/arm/calling_convention_arm.cc @@ -16,6 +16,7 @@ #include "base/logging.h" #include "calling_convention_arm.h" +#include "handle_scope-inl.h" #include "utils/arm/managed_register_arm.h" namespace art { diff --git a/compiler/jni/quick/arm64/calling_convention_arm64.cc b/compiler/jni/quick/arm64/calling_convention_arm64.cc index 29763a2a10..b9c81787f0 100644 --- a/compiler/jni/quick/arm64/calling_convention_arm64.cc +++ b/compiler/jni/quick/arm64/calling_convention_arm64.cc @@ -16,6 +16,7 @@ #include "base/logging.h" #include "calling_convention_arm64.h" +#include "handle_scope-inl.h" #include "utils/arm64/managed_register_arm64.h" namespace art { diff --git a/compiler/jni/quick/mips/calling_convention_mips.cc b/compiler/jni/quick/mips/calling_convention_mips.cc index f7a7be7304..aefbf06fd7 100644 --- a/compiler/jni/quick/mips/calling_convention_mips.cc +++ b/compiler/jni/quick/mips/calling_convention_mips.cc @@ -17,6 +17,7 @@ #include "calling_convention_mips.h" #include "base/logging.h" +#include "handle_scope-inl.h" #include "utils/mips/managed_register_mips.h" namespace art { diff --git a/compiler/jni/quick/x86/calling_convention_x86.cc b/compiler/jni/quick/x86/calling_convention_x86.cc index 9bf7d0f071..a5686e1ac7 100644 --- a/compiler/jni/quick/x86/calling_convention_x86.cc +++ b/compiler/jni/quick/x86/calling_convention_x86.cc @@ -17,6 +17,7 @@ #include "calling_convention_x86.h" #include "base/logging.h" +#include "handle_scope-inl.h" #include "utils/x86/managed_register_x86.h" #include "utils.h" diff --git a/compiler/jni/quick/x86_64/calling_convention_x86_64.cc b/compiler/jni/quick/x86_64/calling_convention_x86_64.cc index a100552695..bbdf1fe7bb 100644 --- a/compiler/jni/quick/x86_64/calling_convention_x86_64.cc +++ b/compiler/jni/quick/x86_64/calling_convention_x86_64.cc @@ -17,6 +17,7 @@ #include "calling_convention_x86_64.h" #include "base/logging.h" +#include "handle_scope-inl.h" #include "utils/x86_64/managed_register_x86_64.h" #include "utils.h" diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc index a5d82a8ccc..0c1ff9bff5 100644 --- a/compiler/optimizing/code_generator.cc +++ b/compiler/optimizing/code_generator.cc @@ -619,6 +619,14 @@ void CodeGenerator::RecordPcInfo(HInstruction* instruction, uint32_t dex_pc) { break; } + case Location::kFpuRegisterPair : { + stack_map_stream_.AddDexRegisterEntry(DexRegisterMap::kInFpuRegister, location.low()); + stack_map_stream_.AddDexRegisterEntry(DexRegisterMap::kInFpuRegister, location.high()); + ++i; + DCHECK_LT(i, environment_size); + break; + } + default: LOG(FATAL) << "Unexpected kind " << location.GetKind(); } diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h index bb0dda0170..8d28f3da25 100644 --- a/compiler/optimizing/code_generator.h +++ b/compiler/optimizing/code_generator.h @@ -142,6 +142,7 @@ class CodeGenerator { UNIMPLEMENTED(FATAL); UNREACHABLE(); } + virtual bool NeedsTwoRegisters(Primitive::Type type) const = 0; void RecordPcInfo(HInstruction* instruction, uint32_t dex_pc); diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index 3b3fb64763..d0a72bb42a 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -373,6 +373,16 @@ size_t CodeGeneratorARM::RestoreCoreRegister(size_t stack_index, uint32_t reg_id return kArmWordSize; } +size_t CodeGeneratorARM::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) { + __ StoreSToOffset(static_cast<SRegister>(reg_id), SP, stack_index); + return kArmWordSize; +} + +size_t CodeGeneratorARM::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) { + __ LoadSFromOffset(static_cast<SRegister>(reg_id), SP, stack_index); + return kArmWordSize; +} + CodeGeneratorARM::CodeGeneratorARM(HGraph* graph, const ArmInstructionSetFeatures* isa_features) : CodeGenerator(graph, kNumberOfCoreRegisters, kNumberOfSRegisters, kNumberOfRegisterPairs), @@ -802,7 +812,8 @@ void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstr __ LoadImmediate(IP, value); __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex()); } - } else if (const_to_move->IsLongConstant()) { + } else { + DCHECK(const_to_move->IsLongConstant()) << const_to_move; int64_t value = const_to_move->AsLongConstant()->GetValue(); if (location.IsRegisterPair()) { __ LoadImmediate(location.AsRegisterPairLow<Register>(), Low32Bits(value)); @@ -2585,7 +2596,8 @@ void InstructionCodeGeneratorARM::GenerateWideAtomicLoad(Register addr, Register out_hi) { if (offset != 0) { __ LoadImmediate(out_lo, offset); - __ add(addr, addr, ShifterOperand(out_lo)); + __ add(IP, addr, ShifterOperand(out_lo)); + addr = IP; } __ ldrexd(out_lo, out_hi, addr); } @@ -2599,7 +2611,8 @@ void InstructionCodeGeneratorARM::GenerateWideAtomicStore(Register addr, Label fail; if (offset != 0) { __ LoadImmediate(temp1, offset); - __ add(addr, addr, ShifterOperand(temp1)); + __ add(IP, addr, ShifterOperand(temp1)); + addr = IP; } __ Bind(&fail); // We need a load followed by store. (The address used in a STREX instruction must @@ -2994,10 +3007,34 @@ void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) { break; } - case Primitive::kPrimFloat: - case Primitive::kPrimDouble: - LOG(FATAL) << "Unimplemented register type " << instruction->GetType(); - UNREACHABLE(); + case Primitive::kPrimFloat: { + uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value(); + Location out = locations->Out(); + DCHECK(out.IsFpuRegister()); + if (index.IsConstant()) { + size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset; + __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), obj, offset); + } else { + __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4)); + __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), IP, data_offset); + } + break; + } + + case Primitive::kPrimDouble: { + uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value(); + Location out = locations->Out(); + DCHECK(out.IsFpuRegisterPair()); + if (index.IsConstant()) { + size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset; + __ LoadDFromOffset(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), obj, offset); + } else { + __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8)); + __ LoadDFromOffset(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), IP, data_offset); + } + break; + } + case Primitive::kPrimVoid: LOG(FATAL) << "Unreachable type " << instruction->GetType(); UNREACHABLE(); @@ -3114,12 +3151,36 @@ void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) { break; } - case Primitive::kPrimFloat: - case Primitive::kPrimDouble: - LOG(FATAL) << "Unimplemented register type " << instruction->GetType(); - UNREACHABLE(); + case Primitive::kPrimFloat: { + uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value(); + Location value = locations->InAt(2); + DCHECK(value.IsFpuRegister()); + if (index.IsConstant()) { + size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset; + __ StoreSToOffset(value.AsFpuRegister<SRegister>(), obj, offset); + } else { + __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4)); + __ StoreSToOffset(value.AsFpuRegister<SRegister>(), IP, data_offset); + } + break; + } + + case Primitive::kPrimDouble: { + uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value(); + Location value = locations->InAt(2); + DCHECK(value.IsFpuRegisterPair()); + if (index.IsConstant()) { + size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset; + __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), obj, offset); + } else { + __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8)); + __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), IP, data_offset); + } + break; + } + case Primitive::kPrimVoid: - LOG(FATAL) << "Unreachable type " << instruction->GetType(); + LOG(FATAL) << "Unreachable type " << value_type; UNREACHABLE(); } } @@ -3247,21 +3308,62 @@ void ParallelMoveResolverARM::EmitMove(size_t index) { if (destination.IsRegister()) { __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(), SP, source.GetStackIndex()); + } else if (destination.IsFpuRegister()) { + __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex()); } else { DCHECK(destination.IsStackSlot()); __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex()); __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex()); } - } else { - DCHECK(source.IsConstant()); - DCHECK(source.GetConstant()->IsIntConstant()); - int32_t value = source.GetConstant()->AsIntConstant()->GetValue(); - if (destination.IsRegister()) { - __ LoadImmediate(destination.AsRegister<Register>(), value); + } else if (source.IsFpuRegister()) { + if (destination.IsFpuRegister()) { + __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>()); } else { DCHECK(destination.IsStackSlot()); - __ LoadImmediate(IP, value); + __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex()); + } + } else if (source.IsFpuRegisterPair()) { + if (destination.IsFpuRegisterPair()) { + __ vmovd(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()), + FromLowSToD(source.AsFpuRegisterPairLow<SRegister>())); + } else { + DCHECK(destination.IsDoubleStackSlot()) << destination; + __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()), + SP, destination.GetStackIndex()); + } + } else if (source.IsDoubleStackSlot()) { + if (destination.IsFpuRegisterPair()) { + __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()), + SP, source.GetStackIndex()); + } else { + DCHECK(destination.IsDoubleStackSlot()) << destination; + __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex()); __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex()); + __ LoadFromOffset(kLoadWord, IP, SP, source.GetHighStackIndex(kArmWordSize)); + __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize)); + } + } else { + DCHECK(source.IsConstant()) << source; + HInstruction* constant = source.GetConstant(); + if (constant->IsIntConstant()) { + int32_t value = constant->AsIntConstant()->GetValue(); + if (destination.IsRegister()) { + __ LoadImmediate(destination.AsRegister<Register>(), value); + } else { + DCHECK(destination.IsStackSlot()); + __ LoadImmediate(IP, value); + __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex()); + } + } else { + DCHECK(constant->IsFloatConstant()); + float value = constant->AsFloatConstant()->GetValue(); + if (destination.IsFpuRegister()) { + __ LoadSImmediate(destination.AsFpuRegister<SRegister>(), value); + } else { + DCHECK(destination.IsStackSlot()); + __ LoadImmediate(IP, bit_cast<int32_t, float>(value)); + __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex()); + } } } } @@ -3300,6 +3402,20 @@ void ParallelMoveResolverARM::EmitSwap(size_t index) { Exchange(destination.AsRegister<Register>(), source.GetStackIndex()); } else if (source.IsStackSlot() && destination.IsStackSlot()) { Exchange(source.GetStackIndex(), destination.GetStackIndex()); + } else if (source.IsFpuRegister() && destination.IsFpuRegister()) { + __ vmovrs(IP, source.AsFpuRegister<SRegister>()); + __ vmovs(source.AsFpuRegister<SRegister>(), destination.AsFpuRegister<SRegister>()); + __ vmovsr(destination.AsFpuRegister<SRegister>(), IP); + } else if (source.IsFpuRegister() || destination.IsFpuRegister()) { + SRegister reg = source.IsFpuRegister() ? source.AsFpuRegister<SRegister>() + : destination.AsFpuRegister<SRegister>(); + int mem = source.IsFpuRegister() + ? destination.GetStackIndex() + : source.GetStackIndex(); + + __ vmovrs(IP, reg); + __ LoadSFromOffset(reg, SP, mem); + __ StoreToOffset(kStoreWord, IP, SP, mem); } else { LOG(FATAL) << "Unimplemented"; } diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h index 40f4edc4eb..c1b4eda3a4 100644 --- a/compiler/optimizing/code_generator_arm.h +++ b/compiler/optimizing/code_generator_arm.h @@ -168,6 +168,8 @@ class CodeGeneratorARM : public CodeGenerator { void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE; size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; + size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; + size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; size_t GetWordSize() const OVERRIDE { return kArmWordSize; @@ -237,6 +239,10 @@ class CodeGeneratorARM : public CodeGenerator { return isa_features_; } + bool NeedsTwoRegisters(Primitive::Type type) const OVERRIDE { + return type == Primitive::kPrimDouble || type == Primitive::kPrimLong; + } + private: // Labels for each block that will be compiled. GrowableArray<Label> block_labels_; diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h index 19488a4ba2..e4da07be43 100644 --- a/compiler/optimizing/code_generator_arm64.h +++ b/compiler/optimizing/code_generator_arm64.h @@ -267,6 +267,10 @@ class CodeGeneratorARM64 : public CodeGenerator { ParallelMoveResolverARM64* GetMoveResolver() { return &move_resolver_; } + bool NeedsTwoRegisters(Primitive::Type type ATTRIBUTE_UNUSED) const OVERRIDE { + return false; + } + private: // Labels for each block that will be compiled. vixl::Label* block_labels_; diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h index 636f8845e5..acde122917 100644 --- a/compiler/optimizing/code_generator_x86.h +++ b/compiler/optimizing/code_generator_x86.h @@ -222,6 +222,10 @@ class CodeGeneratorX86 : public CodeGenerator { block_labels_.SetSize(GetGraph()->GetBlocks().Size()); } + bool NeedsTwoRegisters(Primitive::Type type) const OVERRIDE { + return type == Primitive::kPrimLong; + } + private: // Labels for each block that will be compiled. GrowableArray<Label> block_labels_; diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h index 070886460b..87f6b0f779 100644 --- a/compiler/optimizing/code_generator_x86_64.h +++ b/compiler/optimizing/code_generator_x86_64.h @@ -218,6 +218,10 @@ class CodeGeneratorX86_64 : public CodeGenerator { block_labels_.SetSize(GetGraph()->GetBlocks().Size()); } + bool NeedsTwoRegisters(Primitive::Type type ATTRIBUTE_UNUSED) const OVERRIDE { + return false; + } + private: // Labels for each block that will be compiled. GrowableArray<Label> block_labels_; diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc index 9ed1e4528c..9e0a5b89e9 100644 --- a/compiler/optimizing/graph_visualizer.cc +++ b/compiler/optimizing/graph_visualizer.cc @@ -30,10 +30,12 @@ class HGraphVisualizerPrinter : public HGraphVisitor { HGraphVisualizerPrinter(HGraph* graph, std::ostream& output, const char* pass_name, + bool is_after_pass, const CodeGenerator& codegen) : HGraphVisitor(graph), output_(output), pass_name_(pass_name), + is_after_pass_(is_after_pass), codegen_(codegen), indent_(0) {} @@ -136,6 +138,10 @@ class HGraphVisualizerPrinter : public HGraphVisitor { output_ << "invalid"; } else if (location.IsStackSlot()) { output_ << location.GetStackIndex() << "(sp)"; + } else if (location.IsFpuRegisterPair()) { + codegen_.DumpFloatingPointRegister(output_, location.low()); + output_ << " and "; + codegen_.DumpFloatingPointRegister(output_, location.high()); } else { DCHECK(location.IsDoubleStackSlot()); output_ << "2x" << location.GetStackIndex() << "(sp)"; @@ -157,19 +163,19 @@ class HGraphVisualizerPrinter : public HGraphVisitor { output_ << " (liveness: " << instruction->GetLifetimePosition() << ")"; } - void VisitIntConstant(HIntConstant *instruction) OVERRIDE { + void VisitIntConstant(HIntConstant* instruction) OVERRIDE { output_ << " " << instruction->GetValue(); } - void VisitLongConstant(HLongConstant *instruction) OVERRIDE { + void VisitLongConstant(HLongConstant* instruction) OVERRIDE { output_ << " " << instruction->GetValue(); } - void VisitFloatConstant(HFloatConstant *instruction) OVERRIDE { + void VisitFloatConstant(HFloatConstant* instruction) OVERRIDE { output_ << " " << instruction->GetValue(); } - void VisitDoubleConstant(HDoubleConstant *instruction) OVERRIDE { + void VisitDoubleConstant(HDoubleConstant* instruction) OVERRIDE { output_ << " " << instruction->GetValue(); } @@ -224,7 +230,8 @@ class HGraphVisualizerPrinter : public HGraphVisitor { void Run() { StartTag("cfg"); - PrintProperty("name", pass_name_); + std::string pass_desc = std::string(pass_name_) + (is_after_pass_ ? " (after)" : " (before)"); + PrintProperty("name", pass_desc.c_str()); VisitInsertionOrder(); EndTag("cfg"); } @@ -275,6 +282,7 @@ class HGraphVisualizerPrinter : public HGraphVisitor { private: std::ostream& output_; const char* pass_name_; + const bool is_after_pass_; const CodeGenerator& codegen_; size_t indent_; @@ -295,7 +303,7 @@ HGraphVisualizer::HGraphVisualizer(std::ostream* output, } is_enabled_ = true; - HGraphVisualizerPrinter printer(graph_, *output_, "", codegen_); + HGraphVisualizerPrinter printer(graph_, *output_, "", true, codegen_); printer.StartTag("compilation"); printer.PrintProperty("name", method_name); printer.PrintProperty("method", method_name); @@ -305,8 +313,7 @@ HGraphVisualizer::HGraphVisualizer(std::ostream* output, void HGraphVisualizer::DumpGraph(const char* pass_name, bool is_after_pass) const { if (is_enabled_) { - std::string pass_desc = std::string(pass_name) + (is_after_pass ? " (after)" : " (before)"); - HGraphVisualizerPrinter printer(graph_, *output_, pass_desc.c_str(), codegen_); + HGraphVisualizerPrinter printer(graph_, *output_, pass_name, is_after_pass, codegen_); printer.Run(); } } diff --git a/compiler/optimizing/locations.h b/compiler/optimizing/locations.h index 1ff26d914c..7df99d4b6f 100644 --- a/compiler/optimizing/locations.h +++ b/compiler/optimizing/locations.h @@ -160,6 +160,16 @@ class Location : public ValueObject { return GetPayload(); } + int low() const { + DCHECK(IsPair()); + return GetPayload() >> 16; + } + + int high() const { + DCHECK(IsPair()); + return GetPayload() & 0xFFFF; + } + template <typename T> T AsRegister() const { DCHECK(IsRegister()); @@ -175,25 +185,41 @@ class Location : public ValueObject { template <typename T> T AsRegisterPairLow() const { DCHECK(IsRegisterPair()); - return static_cast<T>(GetPayload() >> 16); + return static_cast<T>(low()); } template <typename T> T AsRegisterPairHigh() const { DCHECK(IsRegisterPair()); - return static_cast<T>(GetPayload() & 0xFFFF); + return static_cast<T>(high()); } template <typename T> T AsFpuRegisterPairLow() const { DCHECK(IsFpuRegisterPair()); - return static_cast<T>(GetPayload() >> 16); + return static_cast<T>(low()); } template <typename T> T AsFpuRegisterPairHigh() const { DCHECK(IsFpuRegisterPair()); - return static_cast<T>(GetPayload() & 0xFFFF); + return static_cast<T>(high()); + } + + bool IsPair() const { + return IsRegisterPair() || IsFpuRegisterPair(); + } + + Location ToLow() const { + return IsRegisterPair() + ? Location::RegisterLocation(low()) + : Location::FpuRegisterLocation(low()); + } + + Location ToHigh() const { + return IsRegisterPair() + ? Location::RegisterLocation(high()) + : Location::FpuRegisterLocation(high()); } static uintptr_t EncodeStackIndex(intptr_t stack_index) { @@ -264,6 +290,18 @@ class Location : public ValueObject { return value_ == other.value_; } + // Returns whether this location contains `other`. + bool Contains(Location other) const { + if (Equals(other)) return true; + if (IsRegisterPair() && other.IsRegister()) { + return low() == other.reg() || high() == other.reg(); + } + if (IsFpuRegisterPair() && other.IsFpuRegister()) { + return low() == other.reg() || high() == other.reg(); + } + return false; + } + const char* DebugString() const { switch (GetKind()) { case kInvalid: return "I"; @@ -525,7 +563,8 @@ class LocationSummary : public ArenaObject<kArenaAllocMisc> { && (output_.GetPolicy() == Location::kSameAsFirstInput)) { return false; } - if (inputs_.Get(input_index).IsRegister() || inputs_.Get(input_index).IsFpuRegister()) { + Location input = inputs_.Get(input_index); + if (input.IsRegister() || input.IsFpuRegister() || input.IsPair()) { return false; } return true; diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 0fc1fd8663..b98bc70a9f 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -2734,7 +2734,7 @@ class MoveOperands : public ArenaObject<kArenaAllocMisc> { // True if this blocks a move from the given location. bool Blocks(Location loc) const { - return !IsEliminated() && source_.Equals(loc); + return !IsEliminated() && source_.Contains(loc); } // A move is redundant if it's been eliminated, if its source and diff --git a/compiler/optimizing/register_allocator.cc b/compiler/optimizing/register_allocator.cc index c1c805dc56..1efc52b9ec 100644 --- a/compiler/optimizing/register_allocator.cc +++ b/compiler/optimizing/register_allocator.cc @@ -27,6 +27,12 @@ namespace art { static constexpr size_t kMaxLifetimePosition = -1; static constexpr size_t kDefaultNumberOfSpillSlots = 4; +// For simplicity, we implement register pairs as (reg, reg + 1). +// Note that this is a requirement for double registers on ARM, since we +// allocate SRegister. +static int GetHighForLowRegister(int reg) { return reg + 1; } +static bool IsLowRegister(int reg) { return (reg & 1) == 0; } + RegisterAllocator::RegisterAllocator(ArenaAllocator* allocator, CodeGenerator* codegen, const SsaLivenessAnalysis& liveness) @@ -72,10 +78,16 @@ bool RegisterAllocator::CanAllocateRegistersFor(const HGraph& graph, !it.Done(); it.Advance()) { HInstruction* current = it.Current(); - if (current->GetType() == Primitive::kPrimLong || - current->GetType() == Primitive::kPrimFloat || - current->GetType() == Primitive::kPrimDouble) { - return false; + if (instruction_set == kX86) { + if (current->GetType() == Primitive::kPrimLong || + current->GetType() == Primitive::kPrimFloat || + current->GetType() == Primitive::kPrimDouble) { + return false; + } + } else if (instruction_set == kArm || instruction_set == kThumb2) { + if (current->GetType() == Primitive::kPrimLong) { + return false; + } } } } @@ -130,7 +142,7 @@ void RegisterAllocator::BlockRegister(Location location, : physical_fp_register_intervals_.Get(reg); Primitive::Type type = location.IsRegister() ? Primitive::kPrimInt - : Primitive::kPrimDouble; + : Primitive::kPrimFloat; if (interval == nullptr) { interval = LiveInterval::MakeFixedInterval(allocator_, reg, type); if (location.IsRegister()) { @@ -226,6 +238,12 @@ void RegisterAllocator::ProcessInstruction(HInstruction* instruction) { LiveInterval::MakeTempInterval(allocator_, Primitive::kPrimDouble); temp_intervals_.Add(interval); interval->AddRange(position, position + 1); + if (codegen_->NeedsTwoRegisters(Primitive::kPrimDouble)) { + interval->AddHighInterval(true); + LiveInterval* high = interval->GetHighInterval(); + temp_intervals_.Add(high); + unhandled_fp_intervals_.Add(high); + } unhandled_fp_intervals_.Add(interval); break; } @@ -279,6 +297,9 @@ void RegisterAllocator::ProcessInstruction(HInstruction* instruction) { Location input = locations->InAt(i); if (input.IsRegister() || input.IsFpuRegister()) { BlockRegister(input, position, position + 1); + } else if (input.IsPair()) { + BlockRegister(input.ToLow(), position, position + 1); + BlockRegister(input.ToHigh(), position, position + 1); } } @@ -291,6 +312,10 @@ void RegisterAllocator::ProcessInstruction(HInstruction* instruction) { DCHECK(unhandled.IsEmpty() || current->StartsBeforeOrAt(unhandled.Peek())); + if (codegen_->NeedsTwoRegisters(current->GetType())) { + current->AddHighInterval(); + } + // Some instructions define their output in fixed register/stack slot. We need // to ensure we know these locations before doing register allocation. For a // given register, we create an interval that covers these locations. The register @@ -304,14 +329,30 @@ void RegisterAllocator::ProcessInstruction(HInstruction* instruction) { if (first.IsRegister() || first.IsFpuRegister()) { current->SetFrom(position + 1); current->SetRegister(first.reg()); + } else if (first.IsPair()) { + current->SetFrom(position + 1); + current->SetRegister(first.low()); + LiveInterval* high = current->GetHighInterval(); + high->SetRegister(first.high()); + high->SetFrom(position + 1); } } else if (output.IsRegister() || output.IsFpuRegister()) { // Shift the interval's start by one to account for the blocked register. current->SetFrom(position + 1); current->SetRegister(output.reg()); BlockRegister(output, position, position + 1); + } else if (output.IsPair()) { + current->SetFrom(position + 1); + current->SetRegister(output.low()); + LiveInterval* high = current->GetHighInterval(); + high->SetRegister(output.high()); + high->SetFrom(position + 1); + BlockRegister(output.ToLow(), position, position + 1); + BlockRegister(output.ToHigh(), position, position + 1); } else if (output.IsStackSlot() || output.IsDoubleStackSlot()) { current->SetSpillSlot(output.GetStackIndex()); + } else { + DCHECK(output.IsUnallocated() || output.IsConstant()); } // If needed, add interval to the list of unhandled intervals. @@ -516,6 +557,7 @@ void RegisterAllocator::LinearScan() { LiveInterval* current = unhandled_->Pop(); DCHECK(!current->IsFixed() && !current->HasSpillSlot()); DCHECK(unhandled_->IsEmpty() || unhandled_->Peek()->GetStart() >= current->GetStart()); + DCHECK(!current->IsLowInterval() || unhandled_->Peek()->IsHighInterval()); size_t position = current->GetStart(); @@ -566,6 +608,13 @@ void RegisterAllocator::LinearScan() { continue; } + if (current->IsHighInterval() && !current->GetLowInterval()->HasRegister()) { + DCHECK(!current->HasRegister()); + // Allocating the low part was unsucessful. The splitted interval for the high part + // will be handled next (it is in the `unhandled_` list). + continue; + } + // (4) Try to find an available register. bool success = TryAllocateFreeReg(current); @@ -578,6 +627,9 @@ void RegisterAllocator::LinearScan() { // intervals. if (success) { active_.Add(current); + if (current->HasHighInterval() && !current->GetHighInterval()->HasRegister()) { + current->GetHighInterval()->SetRegister(GetHighForLowRegister(current->GetRegister())); + } } } } @@ -630,26 +682,31 @@ bool RegisterAllocator::TryAllocateFreeReg(LiveInterval* current) { if (current->HasRegister()) { // Some instructions have a fixed register output. reg = current->GetRegister(); - DCHECK_NE(free_until[reg], 0u); + if (free_until[reg] == 0) { + DCHECK(current->IsHighInterval()); + // AllocateBlockedReg will spill the holder of the register. + return false; + } } else { + DCHECK(!current->IsHighInterval()); int hint = current->FindFirstRegisterHint(free_until); if (hint != kNoRegister) { DCHECK(!IsBlocked(hint)); reg = hint; + } else if (current->IsLowInterval()) { + reg = FindAvailableRegisterPair(free_until); } else { - // Pick the register that is free the longest. - for (size_t i = 0; i < number_of_registers_; ++i) { - if (IsBlocked(i)) continue; - if (reg == -1 || free_until[i] > free_until[reg]) { - reg = i; - if (free_until[i] == kMaxLifetimePosition) break; - } - } + reg = FindAvailableRegister(free_until); } } + DCHECK_NE(reg, -1); // If we could not find a register, we need to spill. - if (reg == -1 || free_until[reg] == 0) { + if (free_until[reg] == 0) { + return false; + } + + if (current->IsLowInterval() && free_until[GetHighForLowRegister(reg)] == 0) { return false; } @@ -671,6 +728,40 @@ bool RegisterAllocator::IsBlocked(int reg) const { : blocked_fp_registers_[reg]; } +int RegisterAllocator::FindAvailableRegisterPair(size_t* next_use) const { + int reg = -1; + // Pick the register pair that is used the last. + for (size_t i = 0; i < number_of_registers_; ++i) { + if (IsBlocked(i)) continue; + if (!IsLowRegister(i)) continue; + int high_register = GetHighForLowRegister(i); + if (IsBlocked(high_register)) continue; + int existing_high_register = GetHighForLowRegister(reg); + if ((reg == -1) || (next_use[i] >= next_use[reg] + && next_use[high_register] >= next_use[existing_high_register])) { + reg = i; + if (next_use[i] == kMaxLifetimePosition + && next_use[high_register] == kMaxLifetimePosition) { + break; + } + } + } + return reg; +} + +int RegisterAllocator::FindAvailableRegister(size_t* next_use) const { + int reg = -1; + // Pick the register that is used the last. + for (size_t i = 0; i < number_of_registers_; ++i) { + if (IsBlocked(i)) continue; + if (reg == -1 || next_use[i] > next_use[reg]) { + reg = i; + if (next_use[i] == kMaxLifetimePosition) break; + } + } + return reg; +} + // Find the register that is used the last, and spill the interval // that holds it. If the first use of `current` is after that register // we spill `current` instead. @@ -731,17 +822,20 @@ bool RegisterAllocator::AllocateBlockedReg(LiveInterval* current) { } } - // Pick the register that is used the last. int reg = -1; - for (size_t i = 0; i < number_of_registers_; ++i) { - if (IsBlocked(i)) continue; - if (reg == -1 || next_use[i] > next_use[reg]) { - reg = i; - if (next_use[i] == kMaxLifetimePosition) break; - } + if (current->HasRegister()) { + DCHECK(current->IsHighInterval()); + reg = current->GetRegister(); + } else if (current->IsLowInterval()) { + reg = FindAvailableRegisterPair(next_use); + } else { + DCHECK(!current->IsHighInterval()); + reg = FindAvailableRegister(next_use); } - if (first_register_use >= next_use[reg]) { + if ((first_register_use >= next_use[reg]) + || (current->IsLowInterval() && first_register_use >= next_use[GetHighForLowRegister(reg)])) { + DCHECK(!current->IsHighInterval()); // If the first use of that instruction is after the last use of the found // register, we split this interval just before its first register use. AllocateSpillSlotFor(current); @@ -815,23 +909,49 @@ void RegisterAllocator::AddSorted(GrowableArray<LiveInterval*>* array, LiveInter break; } } + array->InsertAt(insert_at, interval); + // Insert the high interval before the low, to ensure the low is processed before. + if (interval->HasHighInterval()) { + array->InsertAt(insert_at, interval->GetHighInterval()); + } else if (interval->HasLowInterval()) { + array->InsertAt(insert_at + 1, interval->GetLowInterval()); + } } LiveInterval* RegisterAllocator::Split(LiveInterval* interval, size_t position) { - DCHECK(position >= interval->GetStart()); + DCHECK_GE(position, interval->GetStart()); DCHECK(!interval->IsDeadAt(position)); if (position == interval->GetStart()) { // Spill slot will be allocated when handling `interval` again. interval->ClearRegister(); + if (interval->HasHighInterval()) { + interval->GetHighInterval()->ClearRegister(); + } else if (interval->HasLowInterval()) { + interval->GetLowInterval()->ClearRegister(); + } return interval; } else { LiveInterval* new_interval = interval->SplitAt(position); + if (interval->HasHighInterval()) { + LiveInterval* high = interval->GetHighInterval()->SplitAt(position); + new_interval->SetHighInterval(high); + high->SetLowInterval(new_interval); + } else if (interval->HasLowInterval()) { + LiveInterval* low = interval->GetLowInterval()->SplitAt(position); + new_interval->SetLowInterval(low); + low->SetHighInterval(new_interval); + } return new_interval; } } void RegisterAllocator::AllocateSpillSlotFor(LiveInterval* interval) { + if (interval->IsHighInterval()) { + // The low interval will contain the spill slot. + return; + } + LiveInterval* parent = interval->GetParent(); // An instruction gets a spill slot for its entire lifetime. If the parent @@ -898,6 +1018,7 @@ void RegisterAllocator::AllocateSpillSlotFor(LiveInterval* interval) { static bool IsValidDestination(Location destination) { return destination.IsRegister() || destination.IsFpuRegister() + || destination.IsFpuRegisterPair() || destination.IsStackSlot() || destination.IsDoubleStackSlot(); } @@ -905,7 +1026,6 @@ static bool IsValidDestination(Location destination) { void RegisterAllocator::AddInputMoveFor(HInstruction* user, Location source, Location destination) const { - DCHECK(IsValidDestination(destination)); if (source.Equals(destination)) return; DCHECK(!user->IsPhi()); @@ -1075,9 +1195,7 @@ void RegisterAllocator::ConnectSiblings(LiveInterval* interval) { if (current->HasSpillSlot() && current->HasRegister()) { // We spill eagerly, so move must be at definition. InsertMoveAfter(interval->GetDefinedBy(), - interval->IsFloatingPoint() - ? Location::FpuRegisterLocation(interval->GetRegister()) - : Location::RegisterLocation(interval->GetRegister()), + interval->ToLocation(), interval->NeedsTwoSpillSlots() ? Location::DoubleStackSlot(interval->GetParent()->GetSpillSlot()) : Location::StackSlot(interval->GetParent()->GetSpillSlot())); @@ -1148,6 +1266,11 @@ void RegisterAllocator::ConnectSiblings(LiveInterval* interval) { locations->AddLiveRegister(source); break; } + case Location::kFpuRegisterPair: { + locations->AddLiveRegister(source.ToLow()); + locations->AddLiveRegister(source.ToHigh()); + break; + } case Location::kStackSlot: // Fall-through case Location::kDoubleStackSlot: // Fall-through case Location::kConstant: { @@ -1307,6 +1430,10 @@ void RegisterAllocator::Resolve() { size_t temp_index = 0; for (size_t i = 0; i < temp_intervals_.Size(); ++i) { LiveInterval* temp = temp_intervals_.Get(i); + if (temp->IsHighInterval()) { + // High intervals can be skipped, they are already handled by the low interval. + continue; + } HInstruction* at = liveness_.GetTempUser(temp); if (at != current) { temp_index = 0; @@ -1320,14 +1447,14 @@ void RegisterAllocator::Resolve() { break; case Primitive::kPrimDouble: - // TODO: Support the case of ARM, where a double value - // requires an FPU register pair (note that the ARM back end - // does not yet use this register allocator when a method uses - // floats or doubles). - DCHECK(codegen_->GetInstructionSet() != kArm - && codegen_->GetInstructionSet() != kThumb2); - locations->SetTempAt( - temp_index++, Location::FpuRegisterLocation(temp->GetRegister())); + if (codegen_->NeedsTwoRegisters(Primitive::kPrimDouble)) { + Location location = Location::FpuRegisterPairLocation( + temp->GetRegister(), temp->GetHighInterval()->GetRegister()); + locations->SetTempAt(temp_index++, location); + } else { + locations->SetTempAt( + temp_index++, Location::FpuRegisterLocation(temp->GetRegister())); + } break; default: diff --git a/compiler/optimizing/register_allocator.h b/compiler/optimizing/register_allocator.h index cbe741c2b3..c152a8bf67 100644 --- a/compiler/optimizing/register_allocator.h +++ b/compiler/optimizing/register_allocator.h @@ -128,6 +128,8 @@ class RegisterAllocator { bool ValidateInternal(bool log_fatal_on_failure) const; void DumpInterval(std::ostream& stream, LiveInterval* interval) const; void DumpAllIntervals(std::ostream& stream) const; + int FindAvailableRegisterPair(size_t* next_use) const; + int FindAvailableRegister(size_t* next_use) const; ArenaAllocator* const allocator_; CodeGenerator* const codegen_; diff --git a/compiler/optimizing/ssa_liveness_analysis.cc b/compiler/optimizing/ssa_liveness_analysis.cc index 660a5c5f60..d41157b8d8 100644 --- a/compiler/optimizing/ssa_liveness_analysis.cc +++ b/compiler/optimizing/ssa_liveness_analysis.cc @@ -419,10 +419,21 @@ bool LiveInterval::NeedsTwoSpillSlots() const { } Location LiveInterval::ToLocation() const { + DCHECK(!IsHighInterval()); if (HasRegister()) { - return IsFloatingPoint() - ? Location::FpuRegisterLocation(GetRegister()) - : Location::RegisterLocation(GetRegister()); + if (IsFloatingPoint()) { + if (HasHighInterval()) { + return Location::FpuRegisterPairLocation(GetRegister(), GetHighInterval()->GetRegister()); + } else { + return Location::FpuRegisterLocation(GetRegister()); + } + } else { + if (HasHighInterval()) { + return Location::RegisterPairLocation(GetRegister(), GetHighInterval()->GetRegister()); + } else { + return Location::RegisterLocation(GetRegister()); + } + } } else { HInstruction* defined_by = GetParent()->GetDefinedBy(); if (defined_by->IsConstant()) { diff --git a/compiler/optimizing/ssa_liveness_analysis.h b/compiler/optimizing/ssa_liveness_analysis.h index 23123891ef..74611e1cbb 100644 --- a/compiler/optimizing/ssa_liveness_analysis.h +++ b/compiler/optimizing/ssa_liveness_analysis.h @@ -77,6 +77,15 @@ class LiveRange FINAL : public ArenaObject<kArenaAllocMisc> { stream << "[" << start_ << ", " << end_ << ")"; } + LiveRange* Dup(ArenaAllocator* allocator) const { + return new (allocator) LiveRange( + start_, end_, next_ == nullptr ? nullptr : next_->Dup(allocator)); + } + + LiveRange* GetLastRange() { + return next_ == nullptr ? this : next_->GetLastRange(); + } + private: size_t start_; size_t end_; @@ -123,6 +132,12 @@ class UsePosition : public ArenaObject<kArenaAllocMisc> { stream << position_; } + UsePosition* Dup(ArenaAllocator* allocator) const { + return new (allocator) UsePosition( + user_, input_index_, is_environment_, position_, + next_ == nullptr ? nullptr : next_->Dup(allocator)); + } + private: HInstruction* const user_; const size_t input_index_; @@ -478,6 +493,8 @@ class LiveInterval : public ArenaObject<kArenaAllocMisc> { } stream << "}"; stream << " is_fixed: " << is_fixed_ << ", is_split: " << IsSplit(); + stream << " is_high: " << IsHighInterval(); + stream << " is_low: " << IsLowInterval(); } LiveInterval* GetNextSibling() const { return next_sibling_; } @@ -512,6 +529,58 @@ class LiveInterval : public ArenaObject<kArenaAllocMisc> { // Returns whether `other` and `this` share the same kind of register. bool SameRegisterKind(Location other) const; + bool HasHighInterval() const { + return !IsHighInterval() && (GetParent()->high_or_low_interval_ != nullptr); + } + + bool HasLowInterval() const { + return IsHighInterval(); + } + + LiveInterval* GetLowInterval() const { + DCHECK(HasLowInterval()); + return high_or_low_interval_; + } + + LiveInterval* GetHighInterval() const { + DCHECK(HasHighInterval()); + return high_or_low_interval_; + } + + bool IsHighInterval() const { + return GetParent()->is_high_interval_; + } + + bool IsLowInterval() const { + return !IsHighInterval() && (GetParent()->high_or_low_interval_ != nullptr); + } + + void SetLowInterval(LiveInterval* low) { + DCHECK(IsHighInterval()); + high_or_low_interval_ = low; + } + + void SetHighInterval(LiveInterval* high) { + DCHECK(IsLowInterval()); + high_or_low_interval_ = high; + } + + void AddHighInterval(bool is_temp = false) { + DCHECK_EQ(GetParent(), this); + DCHECK(!HasHighInterval()); + DCHECK(!HasLowInterval()); + high_or_low_interval_ = new (allocator_) LiveInterval( + allocator_, type_, defined_by_, false, kNoRegister, is_temp, false, true); + high_or_low_interval_->high_or_low_interval_ = this; + if (first_range_ != nullptr) { + high_or_low_interval_->first_range_ = first_range_->Dup(allocator_); + high_or_low_interval_->last_range_ = first_range_->GetLastRange(); + } + if (first_use_ != nullptr) { + high_or_low_interval_->first_use_ = first_use_->Dup(allocator_); + } + } + private: LiveInterval(ArenaAllocator* allocator, Primitive::Type type, @@ -519,7 +588,8 @@ class LiveInterval : public ArenaObject<kArenaAllocMisc> { bool is_fixed = false, int reg = kNoRegister, bool is_temp = false, - bool is_slow_path_safepoint = false) + bool is_slow_path_safepoint = false, + bool is_high_interval = false) : allocator_(allocator), first_range_(nullptr), last_range_(nullptr), @@ -532,6 +602,8 @@ class LiveInterval : public ArenaObject<kArenaAllocMisc> { is_fixed_(is_fixed), is_temp_(is_temp), is_slow_path_safepoint_(is_slow_path_safepoint), + is_high_interval_(is_high_interval), + high_or_low_interval_(nullptr), defined_by_(defined_by) {} ArenaAllocator* const allocator_; @@ -568,6 +640,13 @@ class LiveInterval : public ArenaObject<kArenaAllocMisc> { // Whether the interval is for a safepoint that calls on slow path. const bool is_slow_path_safepoint_; + // Whether this interval is a synthesized interval for register pair. + const bool is_high_interval_; + + // If this interval needs a register pair, the high or low equivalent. + // `is_high_interval_` tells whether this holds the low or the high. + LiveInterval* high_or_low_interval_; + // The instruction represented by this interval. HInstruction* const defined_by_; diff --git a/compiler/optimizing/test/ConstantFolding.java b/compiler/optimizing/test/ConstantFolding.java index 92f2a775b9..d08006b4d5 100644 --- a/compiler/optimizing/test/ConstantFolding.java +++ b/compiler/optimizing/test/ConstantFolding.java @@ -22,13 +22,13 @@ public class ConstantFolding { */ // CHECK-START: int ConstantFolding.IntNegation() constant_folding (before) - // CHECK-DAG: [[Const42:i[0-9]+]] IntConstant 42 - // CHECK-DAG: [[Neg:i[0-9]+]] Neg [ [[Const42]] ] - // CHECK-DAG: Return [ [[Neg]] ] + // CHECK-DAG: [[Const42:i\d+]] IntConstant 42 + // CHECK-DAG: [[Neg:i\d+]] Neg [ [[Const42]] ] + // CHECK-DAG: Return [ [[Neg]] ] // CHECK-START: int ConstantFolding.IntNegation() constant_folding (after) - // CHECK-DAG: [[ConstN42:i[0-9]+]] IntConstant -42 - // CHECK-DAG: Return [ [[ConstN42]] ] + // CHECK-DAG: [[ConstN42:i\d+]] IntConstant -42 + // CHECK-DAG: Return [ [[ConstN42]] ] public static int IntNegation() { int x, y; @@ -43,14 +43,14 @@ public class ConstantFolding { */ // CHECK-START: int ConstantFolding.IntAddition1() constant_folding (before) - // CHECK-DAG: [[Const1:i[0-9]+]] IntConstant 1 - // CHECK-DAG: [[Const2:i[0-9]+]] IntConstant 2 - // CHECK-DAG: [[Add:i[0-9]+]] Add [ [[Const1]] [[Const2]] ] - // CHECK-DAG: Return [ [[Add]] ] + // CHECK-DAG: [[Const1:i\d+]] IntConstant 1 + // CHECK-DAG: [[Const2:i\d+]] IntConstant 2 + // CHECK-DAG: [[Add:i\d+]] Add [ [[Const1]] [[Const2]] ] + // CHECK-DAG: Return [ [[Add]] ] // CHECK-START: int ConstantFolding.IntAddition1() constant_folding (after) - // CHECK-DAG: [[Const3:i[0-9]+]] IntConstant 3 - // CHECK-DAG: Return [ [[Const3]] ] + // CHECK-DAG: [[Const3:i\d+]] IntConstant 3 + // CHECK-DAG: Return [ [[Const3]] ] public static int IntAddition1() { int a, b, c; @@ -66,18 +66,18 @@ public class ConstantFolding { */ // CHECK-START: int ConstantFolding.IntAddition2() constant_folding (before) - // CHECK-DAG: [[Const1:i[0-9]+]] IntConstant 1 - // CHECK-DAG: [[Const2:i[0-9]+]] IntConstant 2 - // CHECK-DAG: [[Const5:i[0-9]+]] IntConstant 5 - // CHECK-DAG: [[Const6:i[0-9]+]] IntConstant 6 - // CHECK-DAG: [[Add1:i[0-9]+]] Add [ [[Const1]] [[Const2]] ] - // CHECK-DAG: [[Add2:i[0-9]+]] Add [ [[Const5]] [[Const6]] ] - // CHECK-DAG: [[Add3:i[0-9]+]] Add [ [[Add1]] [[Add2]] ] - // CHECK-DAG: Return [ [[Add3]] ] + // CHECK-DAG: [[Const1:i\d+]] IntConstant 1 + // CHECK-DAG: [[Const2:i\d+]] IntConstant 2 + // CHECK-DAG: [[Const5:i\d+]] IntConstant 5 + // CHECK-DAG: [[Const6:i\d+]] IntConstant 6 + // CHECK-DAG: [[Add1:i\d+]] Add [ [[Const1]] [[Const2]] ] + // CHECK-DAG: [[Add2:i\d+]] Add [ [[Const5]] [[Const6]] ] + // CHECK-DAG: [[Add3:i\d+]] Add [ [[Add1]] [[Add2]] ] + // CHECK-DAG: Return [ [[Add3]] ] // CHECK-START: int ConstantFolding.IntAddition2() constant_folding (after) - // CHECK-DAG: [[Const14:i[0-9]+]] IntConstant 14 - // CHECK-DAG: Return [ [[Const14]] ] + // CHECK-DAG: [[Const14:i\d+]] IntConstant 14 + // CHECK-DAG: Return [ [[Const14]] ] public static int IntAddition2() { int a, b, c; @@ -97,14 +97,14 @@ public class ConstantFolding { */ // CHECK-START: int ConstantFolding.IntSubtraction() constant_folding (before) - // CHECK-DAG: [[Const5:i[0-9]+]] IntConstant 5 - // CHECK-DAG: [[Const2:i[0-9]+]] IntConstant 2 - // CHECK-DAG: [[Sub:i[0-9]+]] Sub [ [[Const5]] [[Const2]] ] - // CHECK-DAG: Return [ [[Sub]] ] + // CHECK-DAG: [[Const5:i\d+]] IntConstant 5 + // CHECK-DAG: [[Const2:i\d+]] IntConstant 2 + // CHECK-DAG: [[Sub:i\d+]] Sub [ [[Const5]] [[Const2]] ] + // CHECK-DAG: Return [ [[Sub]] ] // CHECK-START: int ConstantFolding.IntSubtraction() constant_folding (after) - // CHECK-DAG: [[Const3:i[0-9]+]] IntConstant 3 - // CHECK-DAG: Return [ [[Const3]] ] + // CHECK-DAG: [[Const3:i\d+]] IntConstant 3 + // CHECK-DAG: Return [ [[Const3]] ] public static int IntSubtraction() { int a, b, c; @@ -120,14 +120,14 @@ public class ConstantFolding { */ // CHECK-START: long ConstantFolding.LongAddition() constant_folding (before) - // CHECK-DAG: [[Const1:j[0-9]+]] LongConstant 1 - // CHECK-DAG: [[Const2:j[0-9]+]] LongConstant 2 - // CHECK-DAG: [[Add:j[0-9]+]] Add [ [[Const1]] [[Const2]] ] - // CHECK-DAG: Return [ [[Add]] ] + // CHECK-DAG: [[Const1:j\d+]] LongConstant 1 + // CHECK-DAG: [[Const2:j\d+]] LongConstant 2 + // CHECK-DAG: [[Add:j\d+]] Add [ [[Const1]] [[Const2]] ] + // CHECK-DAG: Return [ [[Add]] ] // CHECK-START: long ConstantFolding.LongAddition() constant_folding (after) - // CHECK-DAG: [[Const3:j[0-9]+]] LongConstant 3 - // CHECK-DAG: Return [ [[Const3]] ] + // CHECK-DAG: [[Const3:j\d+]] LongConstant 3 + // CHECK-DAG: Return [ [[Const3]] ] public static long LongAddition() { long a, b, c; @@ -143,14 +143,14 @@ public class ConstantFolding { */ // CHECK-START: long ConstantFolding.LongSubtraction() constant_folding (before) - // CHECK-DAG: [[Const5:j[0-9]+]] LongConstant 5 - // CHECK-DAG: [[Const2:j[0-9]+]] LongConstant 2 - // CHECK-DAG: [[Sub:j[0-9]+]] Sub [ [[Const5]] [[Const2]] ] - // CHECK-DAG: Return [ [[Sub]] ] + // CHECK-DAG: [[Const5:j\d+]] LongConstant 5 + // CHECK-DAG: [[Const2:j\d+]] LongConstant 2 + // CHECK-DAG: [[Sub:j\d+]] Sub [ [[Const5]] [[Const2]] ] + // CHECK-DAG: Return [ [[Sub]] ] // CHECK-START: long ConstantFolding.LongSubtraction() constant_folding (after) - // CHECK-DAG: [[Const3:j[0-9]+]] LongConstant 3 - // CHECK-DAG: Return [ [[Const3]] ] + // CHECK-DAG: [[Const3:j\d+]] LongConstant 3 + // CHECK-DAG: Return [ [[Const3]] ] public static long LongSubtraction() { long a, b, c; @@ -165,14 +165,14 @@ public class ConstantFolding { */ // CHECK-START: int ConstantFolding.StaticCondition() constant_folding (before) - // CHECK-DAG: [[Const5:i[0-9]+]] IntConstant 5 - // CHECK-DAG: [[Const2:i[0-9]+]] IntConstant 2 - // CHECK-DAG: [[Cond:z[0-9]+]] GreaterThanOrEqual [ [[Const5]] [[Const2]] ] - // CHECK-DAG: If [ [[Cond]] ] + // CHECK-DAG: [[Const5:i\d+]] IntConstant 5 + // CHECK-DAG: [[Const2:i\d+]] IntConstant 2 + // CHECK-DAG: [[Cond:z\d+]] GreaterThanOrEqual [ [[Const5]] [[Const2]] ] + // CHECK-DAG: If [ [[Cond]] ] // CHECK-START: int ConstantFolding.StaticCondition() constant_folding (after) - // CHECK-DAG: [[Const1:i[0-9]+]] IntConstant 1 - // CHECK-DAG: If [ [[Const1]] ] + // CHECK-DAG: [[Const1:i\d+]] IntConstant 1 + // CHECK-DAG: If [ [[Const1]] ] public static int StaticCondition() { int a, b, c; @@ -195,18 +195,18 @@ public class ConstantFolding { */ // CHECK-START: int ConstantFolding.JumpsAndConditionals(boolean) constant_folding (before) - // CHECK-DAG: [[Const2:i[0-9]+]] IntConstant 2 - // CHECK-DAG: [[Const5:i[0-9]+]] IntConstant 5 - // CHECK-DAG: [[Add:i[0-9]+]] Add [ [[Const5]] [[Const2]] ] - // CHECK-DAG: [[Sub:i[0-9]+]] Sub [ [[Const5]] [[Const2]] ] - // CHECK-DAG: [[Phi:i[0-9]+]] Phi [ [[Add]] [[Sub]] ] - // CHECK-DAG: Return [ [[Phi]] ] + // CHECK-DAG: [[Const2:i\d+]] IntConstant 2 + // CHECK-DAG: [[Const5:i\d+]] IntConstant 5 + // CHECK-DAG: [[Add:i\d+]] Add [ [[Const5]] [[Const2]] ] + // CHECK-DAG: [[Sub:i\d+]] Sub [ [[Const5]] [[Const2]] ] + // CHECK-DAG: [[Phi:i\d+]] Phi [ [[Add]] [[Sub]] ] + // CHECK-DAG: Return [ [[Phi]] ] // CHECK-START: int ConstantFolding.JumpsAndConditionals(boolean) constant_folding (after) - // CHECK-DAG: [[Const3:i[0-9]+]] IntConstant 3 - // CHECK-DAG: [[Const7:i[0-9]+]] IntConstant 7 - // CHECK-DAG: [[Phi:i[0-9]+]] Phi [ [[Const7]] [[Const3]] ] - // CHECK-DAG: Return [ [[Phi]] ] + // CHECK-DAG: [[Const3:i\d+]] IntConstant 3 + // CHECK-DAG: [[Const7:i\d+]] IntConstant 7 + // CHECK-DAG: [[Phi:i\d+]] Phi [ [[Const7]] [[Const3]] ] + // CHECK-DAG: Return [ [[Phi]] ] public static int JumpsAndConditionals(boolean cond) { int a, b, c; diff --git a/compiler/optimizing/test/Inliner.java b/compiler/optimizing/test/Inliner.java index ce7409c958..54cce62a57 100644 --- a/compiler/optimizing/test/Inliner.java +++ b/compiler/optimizing/test/Inliner.java @@ -17,12 +17,12 @@ public class Inliner { // CHECK-START: void Inliner.InlineVoid() inliner (before) - // CHECK-DAG: [[Const42:i[0-9]+]] IntConstant 42 - // CHECK-DAG: InvokeStaticOrDirect - // CHECK-DAG: InvokeStaticOrDirect [ [[Const42]] ] + // CHECK-DAG: [[Const42:i\d+]] IntConstant 42 + // CHECK-DAG: InvokeStaticOrDirect + // CHECK-DAG: InvokeStaticOrDirect [ [[Const42]] ] // CHECK-START: void Inliner.InlineVoid() inliner (after) - // CHECK-NOT: InvokeStaticOrDirect + // CHECK-NOT: InvokeStaticOrDirect public static void InlineVoid() { returnVoid(); @@ -30,119 +30,119 @@ public class Inliner { } // CHECK-START: int Inliner.InlineParameter(int) inliner (before) - // CHECK-DAG: [[Param:i[0-9]+]] ParameterValue - // CHECK-DAG: [[Result:i[0-9]+]] InvokeStaticOrDirect [ [[Param]] ] - // CHECK-DAG: Return [ [[Result]] ] + // CHECK-DAG: [[Param:i\d+]] ParameterValue + // CHECK-DAG: [[Result:i\d+]] InvokeStaticOrDirect [ [[Param]] ] + // CHECK-DAG: Return [ [[Result]] ] // CHECK-START: int Inliner.InlineParameter(int) inliner (after) - // CHECK-DAG: [[Param:i[0-9]+]] ParameterValue - // CHECK-DAG: Return [ [[Param]] ] + // CHECK-DAG: [[Param:i\d+]] ParameterValue + // CHECK-DAG: Return [ [[Param]] ] public static int InlineParameter(int a) { return returnParameter(a); } // CHECK-START: long Inliner.InlineWideParameter(long) inliner (before) - // CHECK-DAG: [[Param:j[0-9]+]] ParameterValue - // CHECK-DAG: [[Result:j[0-9]+]] InvokeStaticOrDirect [ [[Param]] ] - // CHECK-DAG: Return [ [[Result]] ] + // CHECK-DAG: [[Param:j\d+]] ParameterValue + // CHECK-DAG: [[Result:j\d+]] InvokeStaticOrDirect [ [[Param]] ] + // CHECK-DAG: Return [ [[Result]] ] // CHECK-START: long Inliner.InlineWideParameter(long) inliner (after) - // CHECK-DAG: [[Param:j[0-9]+]] ParameterValue - // CHECK-DAG: Return [ [[Param]] ] + // CHECK-DAG: [[Param:j\d+]] ParameterValue + // CHECK-DAG: Return [ [[Param]] ] public static long InlineWideParameter(long a) { return returnWideParameter(a); } // CHECK-START: java.lang.Object Inliner.InlineReferenceParameter(java.lang.Object) inliner (before) - // CHECK-DAG: [[Param:l[0-9]+]] ParameterValue - // CHECK-DAG: [[Result:l[0-9]+]] InvokeStaticOrDirect [ [[Param]] ] - // CHECK-DAG: Return [ [[Result]] ] + // CHECK-DAG: [[Param:l\d+]] ParameterValue + // CHECK-DAG: [[Result:l\d+]] InvokeStaticOrDirect [ [[Param]] ] + // CHECK-DAG: Return [ [[Result]] ] // CHECK-START: java.lang.Object Inliner.InlineReferenceParameter(java.lang.Object) inliner (after) - // CHECK-DAG: [[Param:l[0-9]+]] ParameterValue - // CHECK-DAG: Return [ [[Param]] ] + // CHECK-DAG: [[Param:l\d+]] ParameterValue + // CHECK-DAG: Return [ [[Param]] ] public static Object InlineReferenceParameter(Object o) { return returnReferenceParameter(o); } // CHECK-START: int Inliner.InlineInt() inliner (before) - // CHECK-DAG: [[Result:i[0-9]+]] InvokeStaticOrDirect - // CHECK-DAG: Return [ [[Result]] ] + // CHECK-DAG: [[Result:i\d+]] InvokeStaticOrDirect + // CHECK-DAG: Return [ [[Result]] ] // CHECK-START: int Inliner.InlineInt() inliner (after) - // CHECK-DAG: [[Const4:i[0-9]+]] IntConstant 4 - // CHECK-DAG: Return [ [[Const4]] ] + // CHECK-DAG: [[Const4:i\d+]] IntConstant 4 + // CHECK-DAG: Return [ [[Const4]] ] public static int InlineInt() { return returnInt(); } // CHECK-START: long Inliner.InlineWide() inliner (before) - // CHECK-DAG: [[Result:j[0-9]+]] InvokeStaticOrDirect - // CHECK-DAG: Return [ [[Result]] ] + // CHECK-DAG: [[Result:j\d+]] InvokeStaticOrDirect + // CHECK-DAG: Return [ [[Result]] ] // CHECK-START: long Inliner.InlineWide() inliner (after) - // CHECK-DAG: [[Const8:j[0-9]+]] LongConstant 8 - // CHECK-DAG: Return [ [[Const8]] ] + // CHECK-DAG: [[Const8:j\d+]] LongConstant 8 + // CHECK-DAG: Return [ [[Const8]] ] public static long InlineWide() { return returnWide(); } // CHECK-START: int Inliner.InlineAdd() inliner (before) - // CHECK-DAG: [[Const3:i[0-9]+]] IntConstant 3 - // CHECK-DAG: [[Const5:i[0-9]+]] IntConstant 5 - // CHECK-DAG: [[Result:i[0-9]+]] InvokeStaticOrDirect - // CHECK-DAG: Return [ [[Result]] ] + // CHECK-DAG: [[Const3:i\d+]] IntConstant 3 + // CHECK-DAG: [[Const5:i\d+]] IntConstant 5 + // CHECK-DAG: [[Result:i\d+]] InvokeStaticOrDirect + // CHECK-DAG: Return [ [[Result]] ] // CHECK-START: int Inliner.InlineAdd() inliner (after) - // CHECK-DAG: [[Const3:i[0-9]+]] IntConstant 3 - // CHECK-DAG: [[Const5:i[0-9]+]] IntConstant 5 - // CHECK-DAG: [[Add:i[0-9]+]] Add [ [[Const3]] [[Const5]] ] - // CHECK-DAG: Return [ [[Add]] ] + // CHECK-DAG: [[Const3:i\d+]] IntConstant 3 + // CHECK-DAG: [[Const5:i\d+]] IntConstant 5 + // CHECK-DAG: [[Add:i\d+]] Add [ [[Const3]] [[Const5]] ] + // CHECK-DAG: Return [ [[Add]] ] public static int InlineAdd() { return returnAdd(3, 5); } // CHECK-START: int Inliner.InlineFieldAccess() inliner (before) - // CHECK-DAG: [[After:i[0-9]+]] InvokeStaticOrDirect - // CHECK-DAG: Return [ [[After]] ] + // CHECK-DAG: [[After:i\d+]] InvokeStaticOrDirect + // CHECK-DAG: Return [ [[After]] ] // CHECK-START: int Inliner.InlineFieldAccess() inliner (after) - // CHECK-DAG: [[Const1:i[0-9]+]] IntConstant 1 - // CHECK-DAG: [[Before:i[0-9]+]] StaticFieldGet - // CHECK-DAG: [[After:i[0-9]+]] Add [ [[Before]] [[Const1]] ] - // CHECK-DAG: StaticFieldSet [ {{l[0-9]+}} [[After]] ] - // CHECK-DAG: Return [ [[After]] ] + // CHECK-DAG: [[Const1:i\d+]] IntConstant 1 + // CHECK-DAG: [[Before:i\d+]] StaticFieldGet + // CHECK-DAG: [[After:i\d+]] Add [ [[Before]] [[Const1]] ] + // CHECK-DAG: StaticFieldSet [ {{l\d+}} [[After]] ] + // CHECK-DAG: Return [ [[After]] ] // CHECK-START: int Inliner.InlineFieldAccess() inliner (after) - // CHECK-NOT: InvokeStaticOrDirect + // CHECK-NOT: InvokeStaticOrDirect public static int InlineFieldAccess() { return incCounter(); } // CHECK-START: int Inliner.InlineWithControlFlow(boolean) inliner (before) - // CHECK-DAG: [[Const1:i[0-9]+]] IntConstant 1 - // CHECK-DAG: [[Const3:i[0-9]+]] IntConstant 3 - // CHECK-DAG: [[Const5:i[0-9]+]] IntConstant 5 - // CHECK-DAG: [[Add:i[0-9]+]] InvokeStaticOrDirect [ [[Const1]] [[Const3]] ] - // CHECK-DAG: [[Sub:i[0-9]+]] InvokeStaticOrDirect [ [[Const5]] [[Const3]] ] - // CHECK-DAG: [[Phi:i[0-9]+]] Phi [ [[Add]] [[Sub]] ] - // CHECK-DAG: Return [ [[Phi]] ] + // CHECK-DAG: [[Const1:i\d+]] IntConstant 1 + // CHECK-DAG: [[Const3:i\d+]] IntConstant 3 + // CHECK-DAG: [[Const5:i\d+]] IntConstant 5 + // CHECK-DAG: [[Add:i\d+]] InvokeStaticOrDirect [ [[Const1]] [[Const3]] ] + // CHECK-DAG: [[Sub:i\d+]] InvokeStaticOrDirect [ [[Const5]] [[Const3]] ] + // CHECK-DAG: [[Phi:i\d+]] Phi [ [[Add]] [[Sub]] ] + // CHECK-DAG: Return [ [[Phi]] ] // CHECK-START: int Inliner.InlineWithControlFlow(boolean) inliner (after) - // CHECK-DAG: [[Const1:i[0-9]+]] IntConstant 1 - // CHECK-DAG: [[Const3:i[0-9]+]] IntConstant 3 - // CHECK-DAG: [[Const5:i[0-9]+]] IntConstant 5 - // CHECK-DAG: [[Add:i[0-9]+]] Add [ [[Const1]] [[Const3]] ] - // CHECK-DAG: [[Sub:i[0-9]+]] Sub [ [[Const5]] [[Const3]] ] - // CHECK-DAG: [[Phi:i[0-9]+]] Phi [ [[Add]] [[Sub]] ] - // CHECK-DAG: Return [ [[Phi]] ] + // CHECK-DAG: [[Const1:i\d+]] IntConstant 1 + // CHECK-DAG: [[Const3:i\d+]] IntConstant 3 + // CHECK-DAG: [[Const5:i\d+]] IntConstant 5 + // CHECK-DAG: [[Add:i\d+]] Add [ [[Const1]] [[Const3]] ] + // CHECK-DAG: [[Sub:i\d+]] Sub [ [[Const5]] [[Const3]] ] + // CHECK-DAG: [[Phi:i\d+]] Phi [ [[Add]] [[Sub]] ] + // CHECK-DAG: Return [ [[Phi]] ] public static int InlineWithControlFlow(boolean cond) { int x, const1, const3, const5; diff --git a/compiler/utils/arm/assembler_arm.h b/compiler/utils/arm/assembler_arm.h index 87b38133fb..d9122764d0 100644 --- a/compiler/utils/arm/assembler_arm.h +++ b/compiler/utils/arm/assembler_arm.h @@ -534,6 +534,13 @@ class ArmAssembler : public Assembler { // Load and Store. May clobber IP. virtual void LoadImmediate(Register rd, int32_t value, Condition cond = AL) = 0; + void LoadSImmediate(SRegister sd, float value, Condition cond = AL) { + if (!vmovs(sd, value, cond)) { + LoadImmediate(IP, bit_cast<int32_t, float>(value), cond); + vmovsr(sd, IP, cond); + } + } + virtual void MarkExceptionHandler(Label* label) = 0; virtual void LoadFromOffset(LoadOperandType type, Register reg, |