diff options
Diffstat (limited to 'compiler')
43 files changed, 604 insertions, 692 deletions
diff --git a/compiler/dex/bb_optimizations.cc b/compiler/dex/bb_optimizations.cc index e5358139d8..11a7e44f98 100644 --- a/compiler/dex/bb_optimizations.cc +++ b/compiler/dex/bb_optimizations.cc @@ -51,4 +51,32 @@ bool BBCombine::Worker(PassDataHolder* data) const { return false; } +/* + * MethodUseCount pass implementation start. + */ +bool MethodUseCount::Gate(const PassDataHolder* data) const { + DCHECK(data != nullptr); + CompilationUnit* c_unit = down_cast<const PassMEDataHolder*>(data)->c_unit; + DCHECK(c_unit != nullptr); + // First initialize the data. + c_unit->mir_graph->InitializeMethodUses(); + + // Now check if the pass is to be ignored. + bool res = ((c_unit->disable_opt & (1 << kPromoteRegs)) == 0); + + return res; +} + +bool MethodUseCount::Worker(PassDataHolder* data) const { + DCHECK(data != nullptr); + PassMEDataHolder* pass_me_data_holder = down_cast<PassMEDataHolder*>(data); + CompilationUnit* c_unit = pass_me_data_holder->c_unit; + DCHECK(c_unit != nullptr); + BasicBlock* bb = pass_me_data_holder->bb; + DCHECK(bb != nullptr); + c_unit->mir_graph->CountUses(bb); + // No need of repeating, so just return false. + return false; +} + } // namespace art diff --git a/compiler/dex/bb_optimizations.h b/compiler/dex/bb_optimizations.h index b07a415d4a..aac2644e9b 100644 --- a/compiler/dex/bb_optimizations.h +++ b/compiler/dex/bb_optimizations.h @@ -171,27 +171,6 @@ class NullCheckElimination : public PassME { } }; -/** - * @class TypeInference - * @brief Type inference pass. - */ -class TypeInference : public PassME { - public: - TypeInference() - : PassME("TypeInference", kRepeatingPreOrderDFSTraversal, "4_post_type_cfg") { - } - - bool Worker(PassDataHolder* data) const { - DCHECK(data != nullptr); - PassMEDataHolder* pass_me_data_holder = down_cast<PassMEDataHolder*>(data); - CompilationUnit* c_unit = pass_me_data_holder->c_unit; - DCHECK(c_unit != nullptr); - BasicBlock* bb = pass_me_data_holder->bb; - DCHECK(bb != nullptr); - return c_unit->mir_graph->InferTypes(bb); - } -}; - class ClassInitCheckElimination : public PassME { public: ClassInitCheckElimination() @@ -279,6 +258,48 @@ class BBCombine : public PassME { }; /** + * @class ConstantPropagation + * @brief Perform a constant propagation pass. + */ +class ConstantPropagation : public PassME { + public: + ConstantPropagation() : PassME("ConstantPropagation") { + } + + void Start(PassDataHolder* data) const { + DCHECK(data != nullptr); + CompilationUnit* c_unit = down_cast<PassMEDataHolder*>(data)->c_unit; + DCHECK(c_unit != nullptr); + c_unit->mir_graph->InitializeConstantPropagation(); + } + + bool Worker(PassDataHolder* data) const { + DCHECK(data != nullptr); + CompilationUnit* c_unit = down_cast<PassMEDataHolder*>(data)->c_unit; + DCHECK(c_unit != nullptr); + BasicBlock* bb = down_cast<PassMEDataHolder*>(data)->bb; + DCHECK(bb != nullptr); + c_unit->mir_graph->DoConstantPropagation(bb); + // No need of repeating, so just return false. + return false; + } +}; + +/** + * @class MethodUseCount + * @brief Count the register uses of the method + */ +class MethodUseCount : public PassME { + public: + MethodUseCount() : PassME("UseCount") { + } + + bool Worker(PassDataHolder* data) const; + + bool Gate(const PassDataHolder* data) const; +}; + +/** * @class BasicBlock Optimizations * @brief Any simple BasicBlock optimization can be put here. */ diff --git a/compiler/dex/mir_optimization.cc b/compiler/dex/mir_optimization.cc index 15b83413b7..ebbd28f6c4 100644 --- a/compiler/dex/mir_optimization.cc +++ b/compiler/dex/mir_optimization.cc @@ -35,6 +35,7 @@ static unsigned int Predecessors(BasicBlock* bb) { void MIRGraph::SetConstant(int32_t ssa_reg, int32_t value) { is_constant_v_->SetBit(ssa_reg); constant_values_[ssa_reg] = value; + reg_location_[ssa_reg].is_const = true; } void MIRGraph::SetConstantWide(int32_t ssa_reg, int64_t value) { @@ -42,6 +43,8 @@ void MIRGraph::SetConstantWide(int32_t ssa_reg, int64_t value) { is_constant_v_->SetBit(ssa_reg + 1); constant_values_[ssa_reg] = Low32Bits(value); constant_values_[ssa_reg + 1] = High32Bits(value); + reg_location_[ssa_reg].is_const = true; + reg_location_[ssa_reg + 1].is_const = true; } void MIRGraph::DoConstantPropagation(BasicBlock* bb) { diff --git a/compiler/dex/pass_driver_me_opts.cc b/compiler/dex/pass_driver_me_opts.cc index c476b2aabc..6bb94c3c0e 100644 --- a/compiler/dex/pass_driver_me_opts.cc +++ b/compiler/dex/pass_driver_me_opts.cc @@ -43,8 +43,9 @@ const Pass* const PassDriver<PassDriverMEOpts>::g_passes[] = { GetPassInstance<NullCheckElimination>(), GetPassInstance<BBCombine>(), GetPassInstance<CodeLayout>(), - GetPassInstance<TypeInference>(), GetPassInstance<GlobalValueNumberingPass>(), + GetPassInstance<ConstantPropagation>(), + GetPassInstance<MethodUseCount>(), GetPassInstance<BBOptimizations>(), GetPassInstance<SuspendCheckElimination>(), }; diff --git a/compiler/dex/pass_driver_me_post_opt.cc b/compiler/dex/pass_driver_me_post_opt.cc index 9b56c0da87..5e2140d393 100644 --- a/compiler/dex/pass_driver_me_post_opt.cc +++ b/compiler/dex/pass_driver_me_post_opt.cc @@ -40,9 +40,8 @@ const Pass* const PassDriver<PassDriverMEPostOpt>::g_passes[] = { GetPassInstance<CreatePhiNodes>(), GetPassInstance<SSAConversion>(), GetPassInstance<PhiNodeOperands>(), - GetPassInstance<ConstantPropagation>(), GetPassInstance<PerformInitRegLocations>(), - GetPassInstance<MethodUseCount>(), + GetPassInstance<TypeInference>(), GetPassInstance<FinishSSATransformation>(), }; diff --git a/compiler/dex/post_opt_passes.cc b/compiler/dex/post_opt_passes.cc index 675dbcf91d..92078b471b 100644 --- a/compiler/dex/post_opt_passes.cc +++ b/compiler/dex/post_opt_passes.cc @@ -20,35 +20,6 @@ namespace art { -/* - * MethodUseCount pass implementation start. - */ -bool MethodUseCount::Gate(const PassDataHolder* data) const { - DCHECK(data != nullptr); - CompilationUnit* c_unit = down_cast<const PassMEDataHolder*>(data)->c_unit; - DCHECK(c_unit != nullptr); - // First initialize the data. - c_unit->mir_graph->InitializeMethodUses(); - - // Now check if the pass is to be ignored. - bool res = ((c_unit->disable_opt & (1 << kPromoteRegs)) == 0); - - return res; -} - -bool MethodUseCount::Worker(PassDataHolder* data) const { - DCHECK(data != nullptr); - PassMEDataHolder* pass_me_data_holder = down_cast<PassMEDataHolder*>(data); - CompilationUnit* c_unit = pass_me_data_holder->c_unit; - DCHECK(c_unit != nullptr); - BasicBlock* bb = pass_me_data_holder->bb; - DCHECK(bb != nullptr); - c_unit->mir_graph->CountUses(bb); - // No need of repeating, so just return false. - return false; -} - - bool ClearPhiInstructions::Worker(PassDataHolder* data) const { DCHECK(data != nullptr); PassMEDataHolder* pass_me_data_holder = down_cast<PassMEDataHolder*>(data); diff --git a/compiler/dex/post_opt_passes.h b/compiler/dex/post_opt_passes.h index 964355bb5d..55ae874451 100644 --- a/compiler/dex/post_opt_passes.h +++ b/compiler/dex/post_opt_passes.h @@ -63,20 +63,6 @@ class InitializeSSATransformation : public PassMEMirSsaRep { }; /** - * @class MethodUseCount - * @brief Count the register uses of the method - */ -class MethodUseCount : public PassME { - public: - MethodUseCount() : PassME("UseCount") { - } - - bool Worker(PassDataHolder* data) const; - - bool Gate(const PassDataHolder* data) const; -}; - -/** * @class ClearPhiInformation * @brief Clear the PHI nodes from the CFG. */ @@ -274,30 +260,22 @@ class PerformInitRegLocations : public PassMEMirSsaRep { }; /** - * @class ConstantPropagation - * @brief Perform a constant propagation pass. + * @class TypeInference + * @brief Type inference pass. */ -class ConstantPropagation : public PassMEMirSsaRep { +class TypeInference : public PassMEMirSsaRep { public: - ConstantPropagation() : PassMEMirSsaRep("ConstantPropagation") { + TypeInference() : PassMEMirSsaRep("TypeInference", kRepeatingPreOrderDFSTraversal) { } bool Worker(PassDataHolder* data) const { DCHECK(data != nullptr); - CompilationUnit* c_unit = down_cast<PassMEDataHolder*>(data)->c_unit; + PassMEDataHolder* pass_me_data_holder = down_cast<PassMEDataHolder*>(data); + CompilationUnit* c_unit = pass_me_data_holder->c_unit; DCHECK(c_unit != nullptr); - BasicBlock* bb = down_cast<PassMEDataHolder*>(data)->bb; + BasicBlock* bb = pass_me_data_holder->bb; DCHECK(bb != nullptr); - c_unit->mir_graph->DoConstantPropagation(bb); - // No need of repeating, so just return false. - return false; - } - - void Start(PassDataHolder* data) const { - DCHECK(data != nullptr); - CompilationUnit* c_unit = down_cast<PassMEDataHolder*>(data)->c_unit; - DCHECK(c_unit != nullptr); - c_unit->mir_graph->InitializeConstantPropagation(); + return c_unit->mir_graph->InferTypes(bb); } }; diff --git a/compiler/dex/quick/arm/int_arm.cc b/compiler/dex/quick/arm/int_arm.cc index 860a987c2c..7970bd823d 100644 --- a/compiler/dex/quick/arm/int_arm.cc +++ b/compiler/dex/quick/arm/int_arm.cc @@ -573,6 +573,7 @@ bool ArmMir2Lir::GetEasyMultiplyOp(int lit, ArmMir2Lir::EasyMultiplyOp* op) { // GenArithOpIntLit will directly generate exception-throwing code, and multiply-by-zero will // have been optimized away earlier. op->op = kOpInvalid; + op->shift = 0; return true; } diff --git a/compiler/dex/vreg_analysis.cc b/compiler/dex/vreg_analysis.cc index a541c7d7a7..62c40892cf 100644 --- a/compiler/dex/vreg_analysis.cc +++ b/compiler/dex/vreg_analysis.cc @@ -442,7 +442,7 @@ void MIRGraph::InitRegLocations() { for (int i = 0; i < GetNumSSARegs(); i++) { loc[i] = fresh_loc; loc[i].s_reg_low = i; - loc[i].is_const = is_constant_v_->IsBitSet(i); + loc[i].is_const = false; // Constants will be marked by constant propagation pass later. loc[i].wide = false; } diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc index 9e8907078b..cdfd989bb8 100644 --- a/compiler/optimizing/code_generator.cc +++ b/compiler/optimizing/code_generator.cc @@ -330,23 +330,25 @@ bool CodeGenerator::GoesToNextBlock(HBasicBlock* current, HBasicBlock* next) con CodeGenerator* CodeGenerator::Create(HGraph* graph, InstructionSet instruction_set, - const InstructionSetFeatures& isa_features) { + const InstructionSetFeatures& isa_features, + const CompilerOptions& compiler_options) { switch (instruction_set) { case kArm: case kThumb2: { return new arm::CodeGeneratorARM(graph, - isa_features.AsArmInstructionSetFeatures()); + *isa_features.AsArmInstructionSetFeatures(), + compiler_options); } case kArm64: { - return new arm64::CodeGeneratorARM64(graph); + return new arm64::CodeGeneratorARM64(graph, compiler_options); } case kMips: return nullptr; case kX86: { - return new x86::CodeGeneratorX86(graph); + return new x86::CodeGeneratorX86(graph, compiler_options); } case kX86_64: { - return new x86_64::CodeGeneratorX86_64(graph); + return new x86_64::CodeGeneratorX86_64(graph, compiler_options); } default: return nullptr; @@ -696,11 +698,9 @@ void CodeGenerator::ClearSpillSlotsFromLoopPhisInStackMap(HSuspendCheck* suspend } void CodeGenerator::EmitParallelMoves(Location from1, Location to1, Location from2, Location to2) { - MoveOperands move1(from1, to1, nullptr); - MoveOperands move2(from2, to2, nullptr); HParallelMove parallel_move(GetGraph()->GetArena()); - parallel_move.AddMove(&move1); - parallel_move.AddMove(&move2); + parallel_move.AddMove(from1, to1, nullptr); + parallel_move.AddMove(from2, to2, nullptr); GetMoveResolver()->EmitNativeCode(¶llel_move); } diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h index 88e50b6c88..682c260585 100644 --- a/compiler/optimizing/code_generator.h +++ b/compiler/optimizing/code_generator.h @@ -20,6 +20,7 @@ #include "arch/instruction_set.h" #include "arch/instruction_set_features.h" #include "base/bit_field.h" +#include "driver/compiler_options.h" #include "globals.h" #include "locations.h" #include "memory_region.h" @@ -85,7 +86,8 @@ class CodeGenerator { void CompileOptimized(CodeAllocator* allocator); static CodeGenerator* Create(HGraph* graph, InstructionSet instruction_set, - const InstructionSetFeatures& isa_features); + const InstructionSetFeatures& isa_features, + const CompilerOptions& compiler_options); virtual ~CodeGenerator() {} HGraph* GetGraph() const { return graph_; } @@ -130,6 +132,9 @@ class CodeGenerator { virtual void DumpCoreRegister(std::ostream& stream, int reg) const = 0; virtual void DumpFloatingPointRegister(std::ostream& stream, int reg) const = 0; virtual InstructionSet GetInstructionSet() const = 0; + + const CompilerOptions& GetCompilerOptions() const { return compiler_options_; } + // Saves the register in the stack. Returns the size taken on stack. virtual size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) = 0; // Restores the register from the stack. Returns the size taken on stack. @@ -200,7 +205,8 @@ class CodeGenerator { CodeGenerator(HGraph* graph, size_t number_of_core_registers, size_t number_of_fpu_registers, - size_t number_of_register_pairs) + size_t number_of_register_pairs, + const CompilerOptions& compiler_options) : frame_size_(kUninitializedFrameSize), core_spill_mask_(0), first_register_slot_in_slow_path_(0), @@ -211,6 +217,7 @@ class CodeGenerator { number_of_fpu_registers_(number_of_fpu_registers), number_of_register_pairs_(number_of_register_pairs), graph_(graph), + compiler_options_(compiler_options), pc_infos_(graph->GetArena(), 32), slow_paths_(graph->GetArena(), 8), is_leaf_(true), @@ -249,6 +256,7 @@ class CodeGenerator { size_t GetStackOffsetOfSavedRegister(size_t index); HGraph* const graph_; + const CompilerOptions& compiler_options_; GrowableArray<PcInfo> pc_infos_; GrowableArray<SlowPathCode*> slow_paths_; diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index c4ba0fd3e5..1ca1cee275 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -49,9 +49,6 @@ static constexpr SRegister kRuntimeParameterFpuRegisters[] = { S0, S1, S2, S3 }; static constexpr size_t kRuntimeParameterFpuRegistersLength = arraysize(kRuntimeParameterFpuRegisters); -static constexpr DRegister DTMP = D7; -static constexpr SRegister STMP = S14; - class InvokeRuntimeCallingConvention : public CallingConvention<Register, SRegister> { public: InvokeRuntimeCallingConvention() @@ -387,8 +384,10 @@ size_t CodeGeneratorARM::RestoreFloatingPointRegister(size_t stack_index, uint32 } CodeGeneratorARM::CodeGeneratorARM(HGraph* graph, - const ArmInstructionSetFeatures* isa_features) - : CodeGenerator(graph, kNumberOfCoreRegisters, kNumberOfSRegisters, kNumberOfRegisterPairs), + const ArmInstructionSetFeatures& isa_features, + const CompilerOptions& compiler_options) + : CodeGenerator(graph, kNumberOfCoreRegisters, kNumberOfSRegisters, + kNumberOfRegisterPairs, compiler_options), block_labels_(graph->GetArena(), 0), location_builder_(graph, this), instruction_visitor_(graph, this), @@ -475,11 +474,6 @@ void CodeGeneratorARM::SetupBlockedRegisters() const { blocked_core_registers_[R10] = true; blocked_core_registers_[R11] = true; - // Don't allocate our temporary double register. - blocked_fpu_registers_[STMP] = true; - blocked_fpu_registers_[STMP + 1] = true; - DCHECK_EQ(FromLowSToD(STMP), DTMP); - blocked_fpu_registers_[S16] = true; blocked_fpu_registers_[S17] = true; blocked_fpu_registers_[S18] = true; @@ -793,7 +787,7 @@ void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstr __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex()); } } else { - DCHECK(const_to_move->IsLongConstant()) << const_to_move; + DCHECK(const_to_move->IsLongConstant()) << const_to_move->DebugName(); int64_t value = const_to_move->AsLongConstant()->GetValue(); if (location.IsRegisterPair()) { __ LoadImmediate(location.AsRegisterPairLow<Register>(), Low32Bits(value)); @@ -2616,7 +2610,7 @@ void LocationsBuilderARM::HandleFieldSet(HInstruction* instruction, const FieldI bool is_wide = field_type == Primitive::kPrimLong || field_type == Primitive::kPrimDouble; bool generate_volatile = field_info.IsVolatile() && is_wide - && !codegen_->GetInstructionSetFeatures()->HasAtomicLdrdAndStrd(); + && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd(); // Temporary registers for the write barrier. // TODO: consider renaming StoreNeedsWriteBarrier to StoreNeedsGCMark. if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) { @@ -2649,7 +2643,7 @@ void InstructionCodeGeneratorARM::HandleFieldSet(HInstruction* instruction, Location value = locations->InAt(1); bool is_volatile = field_info.IsVolatile(); - bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures()->HasAtomicLdrdAndStrd(); + bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd(); Primitive::Type field_type = field_info.GetFieldType(); uint32_t offset = field_info.GetFieldOffset().Uint32Value(); @@ -2738,7 +2732,7 @@ void LocationsBuilderARM::HandleFieldGet(HInstruction* instruction, const FieldI bool generate_volatile = field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimDouble) - && !codegen_->GetInstructionSetFeatures()->HasAtomicLdrdAndStrd(); + && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd(); if (generate_volatile) { // Arm encoding have some additional constraints for ldrexd/strexd: // - registers need to be consecutive @@ -2759,7 +2753,7 @@ void InstructionCodeGeneratorARM::HandleFieldGet(HInstruction* instruction, Register base = locations->InAt(0).AsRegister<Register>(); Location out = locations->Out(); bool is_volatile = field_info.IsVolatile(); - bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures()->HasAtomicLdrdAndStrd(); + bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd(); Primitive::Type field_type = field_info.GetFieldType(); uint32_t offset = field_info.GetFieldOffset().Uint32Value(); @@ -2864,13 +2858,22 @@ void InstructionCodeGeneratorARM::VisitStaticFieldSet(HStaticFieldSet* instructi void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); - locations->SetInAt(0, Location::RequiresRegister()); + Location loc = codegen_->GetCompilerOptions().GetImplicitNullChecks() + ? Location::RequiresRegister() + : Location::RegisterOrConstant(instruction->InputAt(0)); + locations->SetInAt(0, loc); if (instruction->HasUses()) { locations->SetOut(Location::SameAsFirstInput()); } } -void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) { +void InstructionCodeGeneratorARM::GenerateImplicitNullCheck(HNullCheck* instruction) { + Location obj = instruction->GetLocations()->InAt(0); + __ LoadFromOffset(kLoadWord, IP, obj.AsRegister<Register>(), 0); + codegen_->RecordPcInfo(instruction, instruction->GetDexPc()); +} + +void InstructionCodeGeneratorARM::GenerateExplicitNullCheck(HNullCheck* instruction) { SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction); codegen_->AddSlowPath(slow_path); @@ -2887,6 +2890,14 @@ void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) { } } +void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) { + if (codegen_->GetCompilerOptions().GetImplicitNullChecks()) { + GenerateImplicitNullCheck(instruction); + } else { + GenerateExplicitNullCheck(instruction); + } +} + void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); @@ -3302,15 +3313,6 @@ void ParallelMoveResolverARM::EmitMove(size_t index) { DCHECK(destination.IsStackSlot()); __ 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>()), @@ -3383,9 +3385,9 @@ void ParallelMoveResolverARM::EmitSwap(size_t index) { } else if (source.IsStackSlot() && destination.IsStackSlot()) { Exchange(source.GetStackIndex(), destination.GetStackIndex()); } else if (source.IsFpuRegister() && destination.IsFpuRegister()) { - __ vmovs(STMP, source.AsFpuRegister<SRegister>()); + __ vmovrs(IP, source.AsFpuRegister<SRegister>()); __ vmovs(source.AsFpuRegister<SRegister>(), destination.AsFpuRegister<SRegister>()); - __ vmovs(destination.AsFpuRegister<SRegister>(), STMP); + __ vmovsr(destination.AsFpuRegister<SRegister>(), IP); } else if (source.IsFpuRegister() || destination.IsFpuRegister()) { SRegister reg = source.IsFpuRegister() ? source.AsFpuRegister<SRegister>() : destination.AsFpuRegister<SRegister>(); @@ -3393,29 +3395,10 @@ void ParallelMoveResolverARM::EmitSwap(size_t index) { ? destination.GetStackIndex() : source.GetStackIndex(); - __ vmovs(STMP, reg); - __ LoadSFromOffset(reg, SP, mem); - __ StoreSToOffset(STMP, SP, mem); - } else if (source.IsFpuRegisterPair() && destination.IsFpuRegisterPair()) { - __ vmovd(DTMP, FromLowSToD(source.AsFpuRegisterPairLow<SRegister>())); - __ vmovd(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()), - FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>())); - __ vmovd(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()), DTMP); - } else if (source.IsFpuRegisterPair() || destination.IsFpuRegisterPair()) { - DRegister reg = source.IsFpuRegisterPair() - ? FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()) - : FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()); - int mem = source.IsFpuRegisterPair() - ? destination.GetStackIndex() - : source.GetStackIndex(); - - __ vmovd(DTMP, reg); - __ LoadDFromOffset(reg, SP, mem); - __ StoreDToOffset(DTMP, SP, mem); + __ vmovrs(IP, reg); + __ LoadFromOffset(kLoadWord, IP, SP, mem); + __ StoreToOffset(kStoreWord, IP, SP, mem); } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) { - // TODO: We could use DTMP and ask for a pair scratch register (float or core). - // This would save four instructions if two scratch registers are available, and - // two instructions if not. Exchange(source.GetStackIndex(), destination.GetStackIndex()); Exchange(source.GetHighStackIndex(kArmWordSize), destination.GetHighStackIndex(kArmWordSize)); } else { diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h index 267d9a2cef..fe373d54e3 100644 --- a/compiler/optimizing/code_generator_arm.h +++ b/compiler/optimizing/code_generator_arm.h @@ -19,6 +19,7 @@ #include "code_generator.h" #include "dex/compiler_enums.h" +#include "driver/compiler_options.h" #include "nodes.h" #include "parallel_move_resolver.h" #include "utils/arm/assembler_thumb2.h" @@ -143,7 +144,8 @@ class InstructionCodeGeneratorARM : public HGraphVisitor { Register out_lo, Register out_hi); void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info); void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info); - + void GenerateImplicitNullCheck(HNullCheck* instruction); + void GenerateExplicitNullCheck(HNullCheck* instruction); ArmAssembler* const assembler_; CodeGeneratorARM* const codegen_; @@ -153,7 +155,9 @@ class InstructionCodeGeneratorARM : public HGraphVisitor { class CodeGeneratorARM : public CodeGenerator { public: - CodeGeneratorARM(HGraph* graph, const ArmInstructionSetFeatures* isa_features); + CodeGeneratorARM(HGraph* graph, + const ArmInstructionSetFeatures& isa_features, + const CompilerOptions& compiler_options); virtual ~CodeGeneratorARM() {} void GenerateFrameEntry() OVERRIDE; @@ -234,7 +238,7 @@ class CodeGeneratorARM : public CodeGenerator { block_labels_.SetSize(GetGraph()->GetBlocks().Size()); } - const ArmInstructionSetFeatures* GetInstructionSetFeatures() const { + const ArmInstructionSetFeatures& GetInstructionSetFeatures() const { return isa_features_; } @@ -249,7 +253,7 @@ class CodeGeneratorARM : public CodeGenerator { InstructionCodeGeneratorARM instruction_visitor_; ParallelMoveResolverARM move_resolver_; Thumb2Assembler assembler_; - const ArmInstructionSetFeatures* isa_features_; + const ArmInstructionSetFeatures& isa_features_; DISALLOW_COPY_AND_ASSIGN(CodeGeneratorARM); }; diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index 6d2c3de5d5..c1bce2a077 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -22,6 +22,7 @@ #include "mirror/array-inl.h" #include "mirror/art_method.h" #include "mirror/class.h" +#include "offsets.h" #include "thread.h" #include "utils/arm64/assembler_arm64.h" #include "utils/assembler.h" @@ -562,11 +563,12 @@ Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type return next_location; } -CodeGeneratorARM64::CodeGeneratorARM64(HGraph* graph) +CodeGeneratorARM64::CodeGeneratorARM64(HGraph* graph, const CompilerOptions& compiler_options) : CodeGenerator(graph, kNumberOfAllocatableRegisters, kNumberOfAllocatableFPRegisters, - kNumberOfAllocatableRegisterPairs), + kNumberOfAllocatableRegisterPairs, + compiler_options), block_labels_(nullptr), location_builder_(graph, this), instruction_visitor_(graph, this), @@ -2291,7 +2293,14 @@ void LocationsBuilderARM64::VisitNullCheck(HNullCheck* instruction) { } } -void InstructionCodeGeneratorARM64::VisitNullCheck(HNullCheck* instruction) { +void InstructionCodeGeneratorARM64::GenerateImplicitNullCheck(HNullCheck* instruction) { + Location obj = instruction->GetLocations()->InAt(0); + + __ Ldr(wzr, HeapOperandFrom(obj, Offset(0))); + codegen_->RecordPcInfo(instruction, instruction->GetDexPc()); +} + +void InstructionCodeGeneratorARM64::GenerateExplicitNullCheck(HNullCheck* instruction) { SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM64(instruction); codegen_->AddSlowPath(slow_path); @@ -2306,6 +2315,14 @@ void InstructionCodeGeneratorARM64::VisitNullCheck(HNullCheck* instruction) { } } +void InstructionCodeGeneratorARM64::VisitNullCheck(HNullCheck* instruction) { + if (codegen_->GetCompilerOptions().GetImplicitNullChecks()) { + GenerateImplicitNullCheck(instruction); + } else { + GenerateExplicitNullCheck(instruction); + } +} + void LocationsBuilderARM64::VisitOr(HOr* instruction) { HandleBinaryOp(instruction); } diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h index 590bc1d778..e20d02ee2d 100644 --- a/compiler/optimizing/code_generator_arm64.h +++ b/compiler/optimizing/code_generator_arm64.h @@ -19,6 +19,7 @@ #include "code_generator.h" #include "dex/compiler_enums.h" +#include "driver/compiler_options.h" #include "nodes.h" #include "parallel_move_resolver.h" #include "utils/arm64/assembler_arm64.h" @@ -113,6 +114,8 @@ class InstructionCodeGeneratorARM64 : public HGraphVisitor { void GenerateSuspendCheck(HSuspendCheck* instruction, HBasicBlock* successor); void HandleBinaryOp(HBinaryOperation* instr); void HandleShift(HBinaryOperation* instr); + void GenerateImplicitNullCheck(HNullCheck* instruction); + void GenerateExplicitNullCheck(HNullCheck* instruction); Arm64Assembler* const assembler_; CodeGeneratorARM64* const codegen_; @@ -164,7 +167,7 @@ class ParallelMoveResolverARM64 : public ParallelMoveResolver { class CodeGeneratorARM64 : public CodeGenerator { public: - explicit CodeGeneratorARM64(HGraph* graph); + CodeGeneratorARM64(HGraph* graph, const CompilerOptions& compiler_options); virtual ~CodeGeneratorARM64() {} void GenerateFrameEntry() OVERRIDE; diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index 1a0df44ea6..9052b8fdec 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -373,8 +373,9 @@ size_t CodeGeneratorX86::RestoreCoreRegister(size_t stack_index, uint32_t reg_id return kX86WordSize; } -CodeGeneratorX86::CodeGeneratorX86(HGraph* graph) - : CodeGenerator(graph, kNumberOfCpuRegisters, kNumberOfXmmRegisters, kNumberOfRegisterPairs), +CodeGeneratorX86::CodeGeneratorX86(HGraph* graph, const CompilerOptions& compiler_options) + : CodeGenerator(graph, kNumberOfCpuRegisters, kNumberOfXmmRegisters, + kNumberOfRegisterPairs, compiler_options), block_labels_(graph->GetArena(), 0), location_builder_(graph, this), instruction_visitor_(graph, this), @@ -2924,13 +2925,23 @@ void InstructionCodeGeneratorX86::VisitInstanceFieldGet(HInstanceFieldGet* instr void LocationsBuilderX86::VisitNullCheck(HNullCheck* instruction) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); - locations->SetInAt(0, Location::Any()); + Location loc = codegen_->GetCompilerOptions().GetImplicitNullChecks() + ? Location::RequiresRegister() + : Location::Any(); + locations->SetInAt(0, loc); if (instruction->HasUses()) { locations->SetOut(Location::SameAsFirstInput()); } } -void InstructionCodeGeneratorX86::VisitNullCheck(HNullCheck* instruction) { +void InstructionCodeGeneratorX86::GenerateImplicitNullCheck(HNullCheck* instruction) { + LocationSummary* locations = instruction->GetLocations(); + Location obj = locations->InAt(0); + __ testl(EAX, Address(obj.AsRegister<Register>(), 0)); + codegen_->RecordPcInfo(instruction, instruction->GetDexPc()); +} + +void InstructionCodeGeneratorX86::GenerateExplicitNullCheck(HNullCheck* instruction) { SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86(instruction); codegen_->AddSlowPath(slow_path); @@ -2950,6 +2961,14 @@ void InstructionCodeGeneratorX86::VisitNullCheck(HNullCheck* instruction) { __ j(kEqual, slow_path->GetEntryLabel()); } +void InstructionCodeGeneratorX86::VisitNullCheck(HNullCheck* instruction) { + if (codegen_->GetCompilerOptions().GetImplicitNullChecks()) { + GenerateImplicitNullCheck(instruction); + } else { + GenerateExplicitNullCheck(instruction); + } +} + void LocationsBuilderX86::VisitArrayGet(HArrayGet* instruction) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); @@ -3363,7 +3382,7 @@ void ParallelMoveResolverX86::EmitMove(size_t index) { __ movl(Address(ESP, destination.GetStackIndex()), imm); } } else { - LOG(FATAL) << "Unimplemented"; + LOG(FATAL) << "Unimplemented move: " << destination << " <- " << source; } } diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h index 2d8adb2cf1..b77a1aa856 100644 --- a/compiler/optimizing/code_generator_x86.h +++ b/compiler/optimizing/code_generator_x86.h @@ -19,6 +19,7 @@ #include "code_generator.h" #include "dex/compiler_enums.h" +#include "driver/compiler_options.h" #include "nodes.h" #include "parallel_move_resolver.h" #include "utils/x86/assembler_x86.h" @@ -144,6 +145,9 @@ class InstructionCodeGeneratorX86 : public HGraphVisitor { void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info); void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info); + void GenerateImplicitNullCheck(HNullCheck* instruction); + void GenerateExplicitNullCheck(HNullCheck* instruction); + X86Assembler* const assembler_; CodeGeneratorX86* const codegen_; @@ -152,7 +156,7 @@ class InstructionCodeGeneratorX86 : public HGraphVisitor { class CodeGeneratorX86 : public CodeGenerator { public: - explicit CodeGeneratorX86(HGraph* graph); + CodeGeneratorX86(HGraph* graph, const CompilerOptions& compiler_options); virtual ~CodeGeneratorX86() {} void GenerateFrameEntry() OVERRIDE; diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index 3d7f122d36..723573afa0 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -416,8 +416,8 @@ size_t CodeGeneratorX86_64::RestoreFloatingPointRegister(size_t stack_index, uin return kX86_64WordSize; } -CodeGeneratorX86_64::CodeGeneratorX86_64(HGraph* graph) - : CodeGenerator(graph, kNumberOfCpuRegisters, kNumberOfFloatRegisters, 0), +CodeGeneratorX86_64::CodeGeneratorX86_64(HGraph* graph, const CompilerOptions& compiler_options) + : CodeGenerator(graph, kNumberOfCpuRegisters, kNumberOfFloatRegisters, 0, compiler_options), block_labels_(graph->GetArena(), 0), location_builder_(graph, this), instruction_visitor_(graph, this), @@ -2623,13 +2623,24 @@ void InstructionCodeGeneratorX86_64::VisitStaticFieldSet(HStaticFieldSet* instru void LocationsBuilderX86_64::VisitNullCheck(HNullCheck* instruction) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); - locations->SetInAt(0, Location::Any()); + Location loc = codegen_->GetCompilerOptions().GetImplicitNullChecks() + ? Location::RequiresRegister() + : Location::Any(); + locations->SetInAt(0, loc); if (instruction->HasUses()) { locations->SetOut(Location::SameAsFirstInput()); } } -void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) { +void InstructionCodeGeneratorX86_64::GenerateImplicitNullCheck(HNullCheck* instruction) { + LocationSummary* locations = instruction->GetLocations(); + Location obj = locations->InAt(0); + + __ testl(CpuRegister(RAX), Address(obj.AsRegister<CpuRegister>(), 0)); + codegen_->RecordPcInfo(instruction, instruction->GetDexPc()); +} + +void InstructionCodeGeneratorX86_64::GenerateExplicitNullCheck(HNullCheck* instruction) { SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86_64(instruction); codegen_->AddSlowPath(slow_path); @@ -2649,6 +2660,14 @@ void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) { __ j(kEqual, slow_path->GetEntryLabel()); } +void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) { + if (codegen_->GetCompilerOptions().GetImplicitNullChecks()) { + GenerateImplicitNullCheck(instruction); + } else { + GenerateExplicitNullCheck(instruction); + } +} + void LocationsBuilderX86_64::VisitArrayGet(HArrayGet* instruction) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h index c501568a89..befe994efb 100644 --- a/compiler/optimizing/code_generator_x86_64.h +++ b/compiler/optimizing/code_generator_x86_64.h @@ -19,6 +19,7 @@ #include "code_generator.h" #include "dex/compiler_enums.h" +#include "driver/compiler_options.h" #include "nodes.h" #include "parallel_move_resolver.h" #include "utils/x86_64/assembler_x86_64.h" @@ -159,6 +160,8 @@ class InstructionCodeGeneratorX86_64 : public HGraphVisitor { void GenerateMemoryBarrier(MemBarrierKind kind); void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info); void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info); + void GenerateImplicitNullCheck(HNullCheck* instruction); + void GenerateExplicitNullCheck(HNullCheck* instruction); X86_64Assembler* const assembler_; CodeGeneratorX86_64* const codegen_; @@ -168,7 +171,7 @@ class InstructionCodeGeneratorX86_64 : public HGraphVisitor { class CodeGeneratorX86_64 : public CodeGenerator { public: - explicit CodeGeneratorX86_64(HGraph* graph); + CodeGeneratorX86_64(HGraph* graph, const CompilerOptions& compiler_options); virtual ~CodeGeneratorX86_64() {} void GenerateFrameEntry() OVERRIDE; diff --git a/compiler/optimizing/codegen_test.cc b/compiler/optimizing/codegen_test.cc index 18722f732b..aa4fc8f611 100644 --- a/compiler/optimizing/codegen_test.cc +++ b/compiler/optimizing/codegen_test.cc @@ -27,6 +27,7 @@ #include "common_compiler_test.h" #include "dex_file.h" #include "dex_instruction.h" +#include "driver/compiler_options.h" #include "nodes.h" #include "optimizing_unit_test.h" #include "prepare_for_register_allocation.h" @@ -80,7 +81,8 @@ template <typename Expected> static void RunCodeBaseline(HGraph* graph, bool has_result, Expected expected) { InternalCodeAllocator allocator; - x86::CodeGeneratorX86 codegenX86(graph); + CompilerOptions compiler_options; + x86::CodeGeneratorX86 codegenX86(graph, compiler_options); // We avoid doing a stack overflow check that requires the runtime being setup, // by making sure the compiler knows the methods we are running are leaf methods. codegenX86.CompileBaseline(&allocator, true); @@ -90,19 +92,19 @@ static void RunCodeBaseline(HGraph* graph, bool has_result, Expected expected) { std::unique_ptr<const ArmInstructionSetFeatures> features( ArmInstructionSetFeatures::FromCppDefines()); - arm::CodeGeneratorARM codegenARM(graph, features.get()); + arm::CodeGeneratorARM codegenARM(graph, *features.get(), compiler_options); codegenARM.CompileBaseline(&allocator, true); if (kRuntimeISA == kArm || kRuntimeISA == kThumb2) { Run(allocator, codegenARM, has_result, expected); } - x86_64::CodeGeneratorX86_64 codegenX86_64(graph); + x86_64::CodeGeneratorX86_64 codegenX86_64(graph, compiler_options); codegenX86_64.CompileBaseline(&allocator, true); if (kRuntimeISA == kX86_64) { Run(allocator, codegenX86_64, has_result, expected); } - arm64::CodeGeneratorARM64 codegenARM64(graph); + arm64::CodeGeneratorARM64 codegenARM64(graph, compiler_options); codegenARM64.CompileBaseline(&allocator, true); if (kRuntimeISA == kArm64) { Run(allocator, codegenARM64, has_result, expected); @@ -132,17 +134,20 @@ static void RunCodeOptimized(HGraph* graph, std::function<void(HGraph*)> hook_before_codegen, bool has_result, Expected expected) { + CompilerOptions compiler_options; if (kRuntimeISA == kArm || kRuntimeISA == kThumb2) { - arm::CodeGeneratorARM codegenARM(graph, ArmInstructionSetFeatures::FromCppDefines()); + arm::CodeGeneratorARM codegenARM(graph, + *ArmInstructionSetFeatures::FromCppDefines(), + compiler_options); RunCodeOptimized(&codegenARM, graph, hook_before_codegen, has_result, expected); } else if (kRuntimeISA == kArm64) { - arm64::CodeGeneratorARM64 codegenARM64(graph); + arm64::CodeGeneratorARM64 codegenARM64(graph, compiler_options); RunCodeOptimized(&codegenARM64, graph, hook_before_codegen, has_result, expected); } else if (kRuntimeISA == kX86) { - x86::CodeGeneratorX86 codegenX86(graph); + x86::CodeGeneratorX86 codegenX86(graph, compiler_options); RunCodeOptimized(&codegenX86, graph, hook_before_codegen, has_result, expected); } else if (kRuntimeISA == kX86_64) { - x86_64::CodeGeneratorX86_64 codegenX86_64(graph); + x86_64::CodeGeneratorX86_64 codegenX86_64(graph, compiler_options); RunCodeOptimized(&codegenX86_64, graph, hook_before_codegen, has_result, expected); } } diff --git a/compiler/optimizing/constant_folding_test.cc b/compiler/optimizing/constant_folding_test.cc index ed7e57be7c..6ceccfbf0e 100644 --- a/compiler/optimizing/constant_folding_test.cc +++ b/compiler/optimizing/constant_folding_test.cc @@ -19,6 +19,7 @@ #include "code_generator_x86.h" #include "constant_folding.h" #include "dead_code_elimination.h" +#include "driver/compiler_options.h" #include "graph_checker.h" #include "optimizing_unit_test.h" #include "pretty_printer.h" @@ -45,7 +46,7 @@ static void TestCode(const uint16_t* data, std::string actual_before = printer_before.str(); ASSERT_EQ(expected_before, actual_before); - x86::CodeGeneratorX86 codegen(graph); + x86::CodeGeneratorX86 codegen(graph, CompilerOptions()); HConstantFolding(graph).Run(); SSAChecker ssa_checker_cf(&allocator, graph); ssa_checker_cf.Run(); diff --git a/compiler/optimizing/dead_code_elimination_test.cc b/compiler/optimizing/dead_code_elimination_test.cc index 3dbd04e250..a644719622 100644 --- a/compiler/optimizing/dead_code_elimination_test.cc +++ b/compiler/optimizing/dead_code_elimination_test.cc @@ -16,6 +16,7 @@ #include "code_generator_x86.h" #include "dead_code_elimination.h" +#include "driver/compiler_options.h" #include "graph_checker.h" #include "optimizing_unit_test.h" #include "pretty_printer.h" @@ -39,7 +40,7 @@ static void TestCode(const uint16_t* data, std::string actual_before = printer_before.str(); ASSERT_EQ(actual_before, expected_before); - x86::CodeGeneratorX86 codegen(graph); + x86::CodeGeneratorX86 codegen(graph, CompilerOptions()); HDeadCodeElimination(graph).Run(); SSAChecker ssa_checker(&allocator, graph); ssa_checker.Run(); diff --git a/compiler/optimizing/graph_checker.cc b/compiler/optimizing/graph_checker.cc index e55175faec..291b14cb52 100644 --- a/compiler/optimizing/graph_checker.cc +++ b/compiler/optimizing/graph_checker.cc @@ -363,9 +363,29 @@ static Primitive::Type PrimitiveKind(Primitive::Type type) { } } +void SSAChecker::VisitIf(HIf* instruction) { + VisitInstruction(instruction); + HInstruction* input = instruction->InputAt(0); + if (input->IsIntConstant()) { + int value = input->AsIntConstant()->GetValue(); + if (value != 0 && value != 1) { + std::stringstream error; + error << "If instruction " << instruction->GetId() + << " has a non-boolean constant input whose value is: " + << value << "."; + errors_.push_back(error.str()); + } + } else if (instruction->InputAt(0)->GetType() != Primitive::kPrimBoolean) { + std::stringstream error; + error << "If instruction " << instruction->GetId() + << " has a non-boolean input type: " + << instruction->InputAt(0)->GetType() << "."; + errors_.push_back(error.str()); + } +} + void SSAChecker::VisitCondition(HCondition* op) { VisitInstruction(op); - // TODO: check inputs types, and special case the `null` check. if (op->GetType() != Primitive::kPrimBoolean) { std::stringstream error; error << "Condition " << op->DebugName() << " " << op->GetId() @@ -373,6 +393,46 @@ void SSAChecker::VisitCondition(HCondition* op) { << op->GetType() << "."; errors_.push_back(error.str()); } + HInstruction* lhs = op->InputAt(0); + HInstruction* rhs = op->InputAt(1); + if (lhs->GetType() == Primitive::kPrimNot) { + if (!op->IsEqual() && !op->IsNotEqual()) { + std::stringstream error; + error << "Condition " << op->DebugName() << " " << op->GetId() + << " uses an object as left-hand side input."; + errors_.push_back(error.str()); + } + if (rhs->IsIntConstant() && rhs->AsIntConstant()->GetValue() != 0) { + std::stringstream error; + error << "Condition " << op->DebugName() << " " << op->GetId() + << " compares an object with a non-0 integer: " + << rhs->AsIntConstant()->GetValue() + << "."; + errors_.push_back(error.str()); + } + } else if (rhs->GetType() == Primitive::kPrimNot) { + if (!op->IsEqual() && !op->IsNotEqual()) { + std::stringstream error; + error << "Condition " << op->DebugName() << " " << op->GetId() + << " uses an object as right-hand side input."; + errors_.push_back(error.str()); + } + if (lhs->IsIntConstant() && lhs->AsIntConstant()->GetValue() != 0) { + std::stringstream error; + error << "Condition " << op->DebugName() << " " << op->GetId() + << " compares a non-0 integer with an object: " + << lhs->AsIntConstant()->GetValue() + << "."; + errors_.push_back(error.str()); + } + } else if (PrimitiveKind(lhs->GetType()) != PrimitiveKind(rhs->GetType())) { + std::stringstream error; + error << "Condition " << op->DebugName() << " " << op->GetId() + << " has inputs of different type: " + << lhs->GetType() << ", and " << rhs->GetType() + << "."; + errors_.push_back(error.str()); + } } void SSAChecker::VisitBinaryOperation(HBinaryOperation* op) { diff --git a/compiler/optimizing/graph_checker.h b/compiler/optimizing/graph_checker.h index ba60cb99c6..ae1557b57c 100644 --- a/compiler/optimizing/graph_checker.h +++ b/compiler/optimizing/graph_checker.h @@ -101,6 +101,7 @@ class SSAChecker : public GraphChecker { void VisitPhi(HPhi* phi) OVERRIDE; void VisitBinaryOperation(HBinaryOperation* op) OVERRIDE; void VisitCondition(HCondition* op) OVERRIDE; + void VisitIf(HIf* instruction) OVERRIDE; private: DISALLOW_COPY_AND_ASSIGN(SSAChecker); diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc index c1f4c94b7f..2c239458f1 100644 --- a/compiler/optimizing/intrinsics_x86_64.cc +++ b/compiler/optimizing/intrinsics_x86_64.cc @@ -116,7 +116,7 @@ static void MoveArguments(HInvoke* invoke, ArenaAllocator* arena, CodeGeneratorX Location cc_loc = calling_convention_visitor.GetNextLocation(input->GetType()); Location actual_loc = locations->InAt(i); - parallel_move.AddMove(new (arena) MoveOperands(actual_loc, cc_loc, nullptr)); + parallel_move.AddMove(actual_loc, cc_loc, nullptr); } codegen->GetMoveResolver()->EmitNativeCode(¶llel_move); diff --git a/compiler/optimizing/linearize_test.cc b/compiler/optimizing/linearize_test.cc index 59404dcb14..2ab9b571ff 100644 --- a/compiler/optimizing/linearize_test.cc +++ b/compiler/optimizing/linearize_test.cc @@ -22,6 +22,7 @@ #include "code_generator_x86.h" #include "dex_file.h" #include "dex_instruction.h" +#include "driver/compiler_options.h" #include "graph_visualizer.h" #include "nodes.h" #include "optimizing_unit_test.h" @@ -44,7 +45,7 @@ static void TestCode(const uint16_t* data, const int* expected_order, size_t num graph->TryBuildingSsa(); - x86::CodeGeneratorX86 codegen(graph); + x86::CodeGeneratorX86 codegen(graph, CompilerOptions()); SsaLivenessAnalysis liveness(*graph, &codegen); liveness.Analyze(); diff --git a/compiler/optimizing/live_ranges_test.cc b/compiler/optimizing/live_ranges_test.cc index 007c43e218..ff23eda21e 100644 --- a/compiler/optimizing/live_ranges_test.cc +++ b/compiler/optimizing/live_ranges_test.cc @@ -19,6 +19,7 @@ #include "code_generator_x86.h" #include "dex_file.h" #include "dex_instruction.h" +#include "driver/compiler_options.h" #include "nodes.h" #include "optimizing_unit_test.h" #include "prepare_for_register_allocation.h" @@ -63,7 +64,7 @@ TEST(LiveRangesTest, CFG1) { ArenaAllocator allocator(&pool); HGraph* graph = BuildGraph(data, &allocator); - x86::CodeGeneratorX86 codegen(graph); + x86::CodeGeneratorX86 codegen(graph, CompilerOptions()); SsaLivenessAnalysis liveness(*graph, &codegen); liveness.Analyze(); @@ -109,7 +110,7 @@ TEST(LiveRangesTest, CFG2) { ArenaPool pool; ArenaAllocator allocator(&pool); HGraph* graph = BuildGraph(data, &allocator); - x86::CodeGeneratorX86 codegen(graph); + x86::CodeGeneratorX86 codegen(graph, CompilerOptions()); SsaLivenessAnalysis liveness(*graph, &codegen); liveness.Analyze(); @@ -158,7 +159,7 @@ TEST(LiveRangesTest, CFG3) { ArenaPool pool; ArenaAllocator allocator(&pool); HGraph* graph = BuildGraph(data, &allocator); - x86::CodeGeneratorX86 codegen(graph); + x86::CodeGeneratorX86 codegen(graph, CompilerOptions()); SsaLivenessAnalysis liveness(*graph, &codegen); liveness.Analyze(); @@ -235,7 +236,7 @@ TEST(LiveRangesTest, Loop1) { ArenaAllocator allocator(&pool); HGraph* graph = BuildGraph(data, &allocator); RemoveSuspendChecks(graph); - x86::CodeGeneratorX86 codegen(graph); + x86::CodeGeneratorX86 codegen(graph, CompilerOptions()); SsaLivenessAnalysis liveness(*graph, &codegen); liveness.Analyze(); @@ -313,7 +314,7 @@ TEST(LiveRangesTest, Loop2) { ArenaPool pool; ArenaAllocator allocator(&pool); HGraph* graph = BuildGraph(data, &allocator); - x86::CodeGeneratorX86 codegen(graph); + x86::CodeGeneratorX86 codegen(graph, CompilerOptions()); SsaLivenessAnalysis liveness(*graph, &codegen); liveness.Analyze(); @@ -389,7 +390,7 @@ TEST(LiveRangesTest, CFG4) { ArenaPool pool; ArenaAllocator allocator(&pool); HGraph* graph = BuildGraph(data, &allocator); - x86::CodeGeneratorX86 codegen(graph); + x86::CodeGeneratorX86 codegen(graph, CompilerOptions()); SsaLivenessAnalysis liveness(*graph, &codegen); liveness.Analyze(); diff --git a/compiler/optimizing/liveness_test.cc b/compiler/optimizing/liveness_test.cc index 6f706c391d..f2d49ac397 100644 --- a/compiler/optimizing/liveness_test.cc +++ b/compiler/optimizing/liveness_test.cc @@ -19,6 +19,7 @@ #include "code_generator_x86.h" #include "dex_file.h" #include "dex_instruction.h" +#include "driver/compiler_options.h" #include "nodes.h" #include "optimizing_unit_test.h" #include "prepare_for_register_allocation.h" @@ -51,7 +52,7 @@ static void TestCode(const uint16_t* data, const char* expected) { graph->TryBuildingSsa(); // `Inline` conditions into ifs. PrepareForRegisterAllocation(graph).Run(); - x86::CodeGeneratorX86 codegen(graph); + x86::CodeGeneratorX86 codegen(graph, CompilerOptions()); SsaLivenessAnalysis liveness(*graph, &codegen); liveness.Analyze(); diff --git a/compiler/optimizing/locations.h b/compiler/optimizing/locations.h index d41b3aecfd..68d605957f 100644 --- a/compiler/optimizing/locations.h +++ b/compiler/optimizing/locations.h @@ -290,18 +290,6 @@ 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"; diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc index 4133cf676f..ade31380ec 100644 --- a/compiler/optimizing/nodes.cc +++ b/compiler/optimizing/nodes.cc @@ -643,7 +643,12 @@ HConstant* HBinaryOperation::TryStaticEvaluation() const { } else if (GetLeft()->IsLongConstant() && GetRight()->IsLongConstant()) { int64_t value = Evaluate(GetLeft()->AsLongConstant()->GetValue(), GetRight()->AsLongConstant()->GetValue()); - return new(GetBlock()->GetGraph()->GetArena()) HLongConstant(value); + if (GetResultType() == Primitive::kPrimLong) { + return new(GetBlock()->GetGraph()->GetArena()) HLongConstant(value); + } else { + DCHECK(GetResultType() == Primitive::kPrimInt); + return new(GetBlock()->GetGraph()->GetArena()) HIntConstant(value); + } } return nullptr; } diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 4838e1a97a..fa51f27f0a 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -2755,7 +2755,7 @@ class MoveOperands : public ArenaObject<kArenaAllocMisc> { // True if this blocks a move from the given location. bool Blocks(Location loc) const { - return !IsEliminated() && source_.Contains(loc); + return !IsEliminated() && source_.Equals(loc); } // A move is redundant if it's been eliminated, if its source and @@ -2784,8 +2784,6 @@ class MoveOperands : public ArenaObject<kArenaAllocMisc> { // This is only used in debug mode, to ensure we do not connect interval siblings // in the same parallel move. HInstruction* instruction_; - - DISALLOW_COPY_AND_ASSIGN(MoveOperands); }; static constexpr size_t kDefaultNumberOfMoves = 4; @@ -2795,18 +2793,46 @@ class HParallelMove : public HTemplateInstruction<0> { explicit HParallelMove(ArenaAllocator* arena) : HTemplateInstruction(SideEffects::None()), moves_(arena, kDefaultNumberOfMoves) {} - void AddMove(MoveOperands* move) { - if (kIsDebugBuild && move->GetInstruction() != nullptr) { - for (size_t i = 0, e = moves_.Size(); i < e; ++i) { - DCHECK_NE(moves_.Get(i)->GetInstruction(), move->GetInstruction()) - << "Doing parallel moves for the same instruction."; + void AddMove(Location source, Location destination, HInstruction* instruction) { + DCHECK(source.IsValid()); + DCHECK(destination.IsValid()); + // The parallel move resolver does not handle pairs. So we decompose the + // pair locations into two moves. + if (source.IsPair() && destination.IsPair()) { + AddMove(source.ToLow(), destination.ToLow(), instruction); + AddMove(source.ToHigh(), destination.ToHigh(), nullptr); + } else if (source.IsPair()) { + DCHECK(destination.IsDoubleStackSlot()); + AddMove(source.ToLow(), Location::StackSlot(destination.GetStackIndex()), instruction); + AddMove(source.ToHigh(), Location::StackSlot(destination.GetHighStackIndex(4)), nullptr); + } else if (destination.IsPair()) { + DCHECK(source.IsDoubleStackSlot()); + AddMove(Location::StackSlot(source.GetStackIndex()), destination.ToLow(), instruction); + // TODO: rewrite GetHighStackIndex to not require a word size. It's supposed to + // always be 4. + static constexpr int kHighOffset = 4; + AddMove(Location::StackSlot(source.GetHighStackIndex(kHighOffset)), + destination.ToHigh(), + nullptr); + } else { + if (kIsDebugBuild) { + if (instruction != nullptr) { + for (size_t i = 0, e = moves_.Size(); i < e; ++i) { + DCHECK_NE(moves_.Get(i).GetInstruction(), instruction) + << "Doing parallel moves for the same instruction."; + } + } + for (size_t i = 0, e = moves_.Size(); i < e; ++i) { + DCHECK(!destination.Equals(moves_.Get(i).GetDestination())) + << "Same destination for two moves in a parallel move."; + } } + moves_.Add(MoveOperands(source, destination, instruction)); } - moves_.Add(move); } MoveOperands* MoveOperandsAt(size_t index) const { - return moves_.Get(index); + return moves_.GetRawStorage() + index; } size_t NumMoves() const { return moves_.Size(); } @@ -2814,7 +2840,7 @@ class HParallelMove : public HTemplateInstruction<0> { DECLARE_INSTRUCTION(ParallelMove); private: - GrowableArray<MoveOperands*> moves_; + GrowableArray<MoveOperands> moves_; DISALLOW_COPY_AND_ASSIGN(HParallelMove); }; diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index 605637300f..1e0d65a945 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -208,11 +208,12 @@ static void RunOptimizations(HGraph* graph, SsaRedundantPhiElimination redundant_phi(graph); SsaDeadPhiElimination dead_phi(graph); HDeadCodeElimination dce(graph); - HConstantFolding fold(graph); + HConstantFolding fold1(graph); InstructionSimplifier simplify1(graph); HInliner inliner(graph, dex_compilation_unit, driver, stats); + HConstantFolding fold2(graph); GVNOptimization gvn(graph); BoundsCheckElimination bce(graph); InstructionSimplifier simplify2(graph); @@ -224,9 +225,10 @@ static void RunOptimizations(HGraph* graph, &dead_phi, &intrinsics, &dce, - &fold, + &fold1, &simplify1, &inliner, + &fold2, &gvn, &bce, &simplify2 @@ -328,7 +330,8 @@ CompiledMethod* OptimizingCompiler::Compile(const DexFile::CodeItem* code_item, const DexFile& dex_file) const { UNUSED(invoke_type); compilation_stats_.RecordStat(MethodCompilationStat::kAttemptCompilation); - InstructionSet instruction_set = GetCompilerDriver()->GetInstructionSet(); + CompilerDriver* compiler_driver = GetCompilerDriver(); + InstructionSet instruction_set = compiler_driver->GetInstructionSet(); // Always use the thumb2 assembler: some runtime functionality (like implicit stack // overflow checks) assume thumb2. if (instruction_set == kArm) { @@ -349,7 +352,7 @@ CompiledMethod* OptimizingCompiler::Compile(const DexFile::CodeItem* code_item, DexCompilationUnit dex_compilation_unit( nullptr, class_loader, art::Runtime::Current()->GetClassLinker(), dex_file, code_item, class_def_idx, method_idx, access_flags, - GetCompilerDriver()->GetVerifiedMethod(&dex_file, method_idx)); + compiler_driver->GetVerifiedMethod(&dex_file, method_idx)); std::string method_name = PrettyMethod(method_idx, dex_file); @@ -364,7 +367,7 @@ CompiledMethod* OptimizingCompiler::Compile(const DexFile::CodeItem* code_item, &dex_compilation_unit, &dex_compilation_unit, &dex_file, - GetCompilerDriver(), + compiler_driver, &compilation_stats_); VLOG(compiler) << "Building " << PrettyMethod(method_idx, dex_file); @@ -374,9 +377,11 @@ CompiledMethod* OptimizingCompiler::Compile(const DexFile::CodeItem* code_item, return nullptr; } - CompilerDriver* compiler_driver = GetCompilerDriver(); std::unique_ptr<CodeGenerator> codegen( - CodeGenerator::Create(graph, instruction_set, *compiler_driver->GetInstructionSetFeatures())); + CodeGenerator::Create(graph, + instruction_set, + *compiler_driver->GetInstructionSetFeatures(), + compiler_driver->GetCompilerOptions())); if (codegen.get() == nullptr) { CHECK(!shouldCompile) << "Could not find code generator for optimizing compiler"; compilation_stats_.RecordStat(MethodCompilationStat::kNotCompiledNoCodegen); diff --git a/compiler/optimizing/optimizing_unit_test.h b/compiler/optimizing/optimizing_unit_test.h index 04b56345c4..b3eb1e2d51 100644 --- a/compiler/optimizing/optimizing_unit_test.h +++ b/compiler/optimizing/optimizing_unit_test.h @@ -45,8 +45,12 @@ namespace art { LiveInterval* BuildInterval(const size_t ranges[][2], size_t number_of_ranges, ArenaAllocator* allocator, - int reg = -1) { - LiveInterval* interval = LiveInterval::MakeInterval(allocator, Primitive::kPrimInt); + int reg = -1, + HInstruction* defined_by = nullptr) { + LiveInterval* interval = LiveInterval::MakeInterval(allocator, Primitive::kPrimInt, defined_by); + if (defined_by != nullptr) { + defined_by->SetLiveInterval(interval); + } for (size_t i = number_of_ranges; i > 0; --i) { interval->AddRange(ranges[i - 1][0], ranges[i - 1][1]); } diff --git a/compiler/optimizing/parallel_move_resolver.cc b/compiler/optimizing/parallel_move_resolver.cc index b8f5070999..debe466560 100644 --- a/compiler/optimizing/parallel_move_resolver.cc +++ b/compiler/optimizing/parallel_move_resolver.cc @@ -57,6 +57,9 @@ void ParallelMoveResolver::BuildInitialMoveList(HParallelMove* parallel_move) { // unallocated, or the move was already eliminated). for (size_t i = 0; i < parallel_move->NumMoves(); ++i) { MoveOperands* move = parallel_move->MoveOperandsAt(i); + // The parallel move resolver algorithm does not work with register pairs. + DCHECK(!move->GetSource().IsPair()); + DCHECK(!move->GetDestination().IsPair()); if (!move->IsRedundant()) { moves_.Add(move); } diff --git a/compiler/optimizing/parallel_move_test.cc b/compiler/optimizing/parallel_move_test.cc index 210f7d7f09..28b5697bbd 100644 --- a/compiler/optimizing/parallel_move_test.cc +++ b/compiler/optimizing/parallel_move_test.cc @@ -26,20 +26,26 @@ class TestParallelMoveResolver : public ParallelMoveResolver { public: explicit TestParallelMoveResolver(ArenaAllocator* allocator) : ParallelMoveResolver(allocator) {} + void Dump(Location location) { + if (location.IsConstant()) { + message_ << "C"; + } else if (location.IsPair()) { + message_ << location.low() << "," << location.high(); + } else { + message_ << location.reg(); + } + } + virtual void EmitMove(size_t index) { MoveOperands* move = moves_.Get(index); if (!message_.str().empty()) { message_ << " "; } message_ << "("; - if (move->GetSource().IsConstant()) { - message_ << "C"; - } else { - message_ << move->GetSource().reg(); - } - message_ << " -> " - << move->GetDestination().reg() - << ")"; + Dump(move->GetSource()); + message_ << " -> "; + Dump(move->GetDestination()); + message_ << ")"; } virtual void EmitSwap(size_t index) { @@ -47,11 +53,11 @@ class TestParallelMoveResolver : public ParallelMoveResolver { if (!message_.str().empty()) { message_ << " "; } - message_ << "(" - << move->GetSource().reg() - << " <-> " - << move->GetDestination().reg() - << ")"; + message_ << "("; + Dump(move->GetSource()); + message_ << " <-> "; + Dump(move->GetDestination()); + message_ << ")"; } virtual void SpillScratch(int reg ATTRIBUTE_UNUSED) {} @@ -73,10 +79,10 @@ static HParallelMove* BuildParallelMove(ArenaAllocator* allocator, size_t number_of_moves) { HParallelMove* moves = new (allocator) HParallelMove(allocator); for (size_t i = 0; i < number_of_moves; ++i) { - moves->AddMove(new (allocator) MoveOperands( + moves->AddMove( Location::RegisterLocation(operands[i][0]), Location::RegisterLocation(operands[i][1]), - nullptr)); + nullptr); } return moves; } @@ -120,16 +126,9 @@ TEST(ParallelMoveTest, Swap) { { TestParallelMoveResolver resolver(&allocator); - static constexpr size_t moves[][2] = {{0, 1}, {1, 2}, {2, 3}, {3, 4}, {4, 1}}; + static constexpr size_t moves[][2] = {{0, 1}, {1, 2}, {2, 3}, {3, 4}, {4, 0}}; resolver.EmitNativeCode(BuildParallelMove(&allocator, moves, arraysize(moves))); - ASSERT_STREQ("(4 <-> 1) (3 <-> 4) (2 <-> 3) (0 -> 1)", resolver.GetMessage().c_str()); - } - - { - TestParallelMoveResolver resolver(&allocator); - static constexpr size_t moves[][2] = {{0, 1}, {1, 2}, {2, 3}, {3, 4}, {4, 1}, {5, 4}}; - resolver.EmitNativeCode(BuildParallelMove(&allocator, moves, arraysize(moves))); - ASSERT_STREQ("(4 <-> 1) (3 <-> 4) (2 <-> 3) (0 -> 1) (5 -> 4)", resolver.GetMessage().c_str()); + ASSERT_STREQ("(4 <-> 0) (3 <-> 4) (2 <-> 3) (1 <-> 2)", resolver.GetMessage().c_str()); } } @@ -138,16 +137,66 @@ TEST(ParallelMoveTest, ConstantLast) { ArenaAllocator allocator(&pool); TestParallelMoveResolver resolver(&allocator); HParallelMove* moves = new (&allocator) HParallelMove(&allocator); - moves->AddMove(new (&allocator) MoveOperands( + moves->AddMove( Location::ConstantLocation(new (&allocator) HIntConstant(0)), Location::RegisterLocation(0), - nullptr)); - moves->AddMove(new (&allocator) MoveOperands( + nullptr); + moves->AddMove( Location::RegisterLocation(1), Location::RegisterLocation(2), - nullptr)); + nullptr); resolver.EmitNativeCode(moves); ASSERT_STREQ("(1 -> 2) (C -> 0)", resolver.GetMessage().c_str()); } +TEST(ParallelMoveTest, Pairs) { + ArenaPool pool; + ArenaAllocator allocator(&pool); + + { + TestParallelMoveResolver resolver(&allocator); + HParallelMove* moves = new (&allocator) HParallelMove(&allocator); + moves->AddMove( + Location::RegisterLocation(2), + Location::RegisterLocation(4), + nullptr); + moves->AddMove( + Location::RegisterPairLocation(0, 1), + Location::RegisterPairLocation(2, 3), + nullptr); + resolver.EmitNativeCode(moves); + ASSERT_STREQ("(2 -> 4) (0 -> 2) (1 -> 3)", resolver.GetMessage().c_str()); + } + + { + TestParallelMoveResolver resolver(&allocator); + HParallelMove* moves = new (&allocator) HParallelMove(&allocator); + moves->AddMove( + Location::RegisterPairLocation(0, 1), + Location::RegisterPairLocation(2, 3), + nullptr); + moves->AddMove( + Location::RegisterLocation(2), + Location::RegisterLocation(4), + nullptr); + resolver.EmitNativeCode(moves); + ASSERT_STREQ("(2 -> 4) (0 -> 2) (1 -> 3)", resolver.GetMessage().c_str()); + } + + { + TestParallelMoveResolver resolver(&allocator); + HParallelMove* moves = new (&allocator) HParallelMove(&allocator); + moves->AddMove( + Location::RegisterPairLocation(0, 1), + Location::RegisterPairLocation(2, 3), + nullptr); + moves->AddMove( + Location::RegisterLocation(2), + Location::RegisterLocation(0), + nullptr); + resolver.EmitNativeCode(moves); + ASSERT_STREQ("(2 <-> 0) (1 -> 3)", resolver.GetMessage().c_str()); + } +} + } // namespace art diff --git a/compiler/optimizing/register_allocator.cc b/compiler/optimizing/register_allocator.cc index 1d155f9b5d..1b42e94960 100644 --- a/compiler/optimizing/register_allocator.cc +++ b/compiler/optimizing/register_allocator.cc @@ -857,7 +857,9 @@ bool RegisterAllocator::AllocateBlockedReg(LiveInterval* current) { DCHECK(!active->IsFixed()); LiveInterval* split = Split(active, current->GetStart()); active_.DeleteAt(i); - handled_.Add(active); + if (split != active) { + handled_.Add(active); + } AddSorted(unhandled_, split); break; } @@ -878,9 +880,14 @@ bool RegisterAllocator::AllocateBlockedReg(LiveInterval* current) { if (next_intersection != kNoLifetime) { if (inactive->IsFixed()) { LiveInterval* split = Split(current, next_intersection); + DCHECK_NE(split, current); AddSorted(unhandled_, split); } else { - LiveInterval* split = Split(inactive, next_intersection); + // Split at the start of `current`, which will lead to splitting + // at the end of the lifetime hole of `inactive`. + LiveInterval* split = Split(inactive, current->GetStart()); + // If it's inactive, it must start before the current interval. + DCHECK_NE(split, inactive); inactive_.DeleteAt(i); --i; --e; @@ -1044,7 +1051,7 @@ void RegisterAllocator::AddInputMoveFor(HInstruction* user, move = previous->AsParallelMove(); } DCHECK_EQ(move->GetLifetimePosition(), user->GetLifetimePosition()); - move->AddMove(new (allocator_) MoveOperands(source, destination, nullptr)); + move->AddMove(source, destination, nullptr); } static bool IsInstructionStart(size_t position) { @@ -1116,7 +1123,7 @@ void RegisterAllocator::InsertParallelMoveAt(size_t position, } } DCHECK_EQ(move->GetLifetimePosition(), position); - move->AddMove(new (allocator_) MoveOperands(source, destination, instruction)); + move->AddMove(source, destination, instruction); } void RegisterAllocator::InsertParallelMoveAtExitOf(HBasicBlock* block, @@ -1146,7 +1153,7 @@ void RegisterAllocator::InsertParallelMoveAtExitOf(HBasicBlock* block, } else { move = previous->AsParallelMove(); } - move->AddMove(new (allocator_) MoveOperands(source, destination, instruction)); + move->AddMove(source, destination, instruction); } void RegisterAllocator::InsertParallelMoveAtEntryOf(HBasicBlock* block, @@ -1165,7 +1172,7 @@ void RegisterAllocator::InsertParallelMoveAtEntryOf(HBasicBlock* block, move->SetLifetimePosition(block->GetLifetimeStart()); block->InsertInstructionBefore(move, first); } - move->AddMove(new (allocator_) MoveOperands(source, destination, instruction)); + move->AddMove(source, destination, instruction); } void RegisterAllocator::InsertMoveAfter(HInstruction* instruction, @@ -1189,7 +1196,7 @@ void RegisterAllocator::InsertMoveAfter(HInstruction* instruction, move->SetLifetimePosition(position); instruction->GetBlock()->InsertInstructionBefore(move, instruction->GetNext()); } - move->AddMove(new (allocator_) MoveOperands(source, destination, instruction)); + move->AddMove(source, destination, instruction); } void RegisterAllocator::ConnectSiblings(LiveInterval* interval) { diff --git a/compiler/optimizing/register_allocator.h b/compiler/optimizing/register_allocator.h index 70841b8e1f..ec46a776b5 100644 --- a/compiler/optimizing/register_allocator.h +++ b/compiler/optimizing/register_allocator.h @@ -197,6 +197,7 @@ class RegisterAllocator { size_t maximum_number_of_live_fp_registers_; ART_FRIEND_TEST(RegisterAllocatorTest, FreeUntil); + ART_FRIEND_TEST(RegisterAllocatorTest, SpillInactive); DISALLOW_COPY_AND_ASSIGN(RegisterAllocator); }; diff --git a/compiler/optimizing/register_allocator_test.cc b/compiler/optimizing/register_allocator_test.cc index c2ea80ec33..cb5010afcd 100644 --- a/compiler/optimizing/register_allocator_test.cc +++ b/compiler/optimizing/register_allocator_test.cc @@ -19,6 +19,7 @@ #include "code_generator_x86.h" #include "dex_file.h" #include "dex_instruction.h" +#include "driver/compiler_options.h" #include "nodes.h" #include "optimizing_unit_test.h" #include "register_allocator.h" @@ -40,7 +41,7 @@ static bool Check(const uint16_t* data) { const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data); HGraph* graph = builder.BuildGraph(*item); graph->TryBuildingSsa(); - x86::CodeGeneratorX86 codegen(graph); + x86::CodeGeneratorX86 codegen(graph, CompilerOptions()); SsaLivenessAnalysis liveness(*graph, &codegen); liveness.Analyze(); RegisterAllocator register_allocator(&allocator, &codegen, liveness); @@ -56,7 +57,7 @@ TEST(RegisterAllocatorTest, ValidateIntervals) { ArenaPool pool; ArenaAllocator allocator(&pool); HGraph* graph = new (&allocator) HGraph(&allocator); - x86::CodeGeneratorX86 codegen(graph); + x86::CodeGeneratorX86 codegen(graph, CompilerOptions()); GrowableArray<LiveInterval*> intervals(&allocator, 0); // Test with two intervals of the same range. @@ -295,7 +296,7 @@ TEST(RegisterAllocatorTest, Loop3) { ArenaPool pool; ArenaAllocator allocator(&pool); HGraph* graph = BuildSSAGraph(data, &allocator); - x86::CodeGeneratorX86 codegen(graph); + x86::CodeGeneratorX86 codegen(graph, CompilerOptions()); SsaLivenessAnalysis liveness(*graph, &codegen); liveness.Analyze(); RegisterAllocator register_allocator(&allocator, &codegen, liveness); @@ -327,7 +328,7 @@ TEST(RegisterAllocatorTest, FirstRegisterUse) { ArenaPool pool; ArenaAllocator allocator(&pool); HGraph* graph = BuildSSAGraph(data, &allocator); - x86::CodeGeneratorX86 codegen(graph); + x86::CodeGeneratorX86 codegen(graph, CompilerOptions()); SsaLivenessAnalysis liveness(*graph, &codegen); liveness.Analyze(); @@ -380,7 +381,7 @@ TEST(RegisterAllocatorTest, DeadPhi) { ArenaAllocator allocator(&pool); HGraph* graph = BuildSSAGraph(data, &allocator); SsaDeadPhiElimination(graph).Run(); - x86::CodeGeneratorX86 codegen(graph); + x86::CodeGeneratorX86 codegen(graph, CompilerOptions()); SsaLivenessAnalysis liveness(*graph, &codegen); liveness.Analyze(); RegisterAllocator register_allocator(&allocator, &codegen, liveness); @@ -402,7 +403,7 @@ TEST(RegisterAllocatorTest, FreeUntil) { ArenaAllocator allocator(&pool); HGraph* graph = BuildSSAGraph(data, &allocator); SsaDeadPhiElimination(graph).Run(); - x86::CodeGeneratorX86 codegen(graph); + x86::CodeGeneratorX86 codegen(graph, CompilerOptions()); SsaLivenessAnalysis liveness(*graph, &codegen); liveness.Analyze(); RegisterAllocator register_allocator(&allocator, &codegen, liveness); @@ -504,7 +505,7 @@ TEST(RegisterAllocatorTest, PhiHint) { { HGraph* graph = BuildIfElseWithPhi(&allocator, &phi, &input1, &input2); - x86::CodeGeneratorX86 codegen(graph); + x86::CodeGeneratorX86 codegen(graph, CompilerOptions()); SsaLivenessAnalysis liveness(*graph, &codegen); liveness.Analyze(); @@ -519,7 +520,7 @@ TEST(RegisterAllocatorTest, PhiHint) { { HGraph* graph = BuildIfElseWithPhi(&allocator, &phi, &input1, &input2); - x86::CodeGeneratorX86 codegen(graph); + x86::CodeGeneratorX86 codegen(graph, CompilerOptions()); SsaLivenessAnalysis liveness(*graph, &codegen); liveness.Analyze(); @@ -536,7 +537,7 @@ TEST(RegisterAllocatorTest, PhiHint) { { HGraph* graph = BuildIfElseWithPhi(&allocator, &phi, &input1, &input2); - x86::CodeGeneratorX86 codegen(graph); + x86::CodeGeneratorX86 codegen(graph, CompilerOptions()); SsaLivenessAnalysis liveness(*graph, &codegen); liveness.Analyze(); @@ -553,7 +554,7 @@ TEST(RegisterAllocatorTest, PhiHint) { { HGraph* graph = BuildIfElseWithPhi(&allocator, &phi, &input1, &input2); - x86::CodeGeneratorX86 codegen(graph); + x86::CodeGeneratorX86 codegen(graph, CompilerOptions()); SsaLivenessAnalysis liveness(*graph, &codegen); liveness.Analyze(); @@ -603,7 +604,7 @@ TEST(RegisterAllocatorTest, ExpectedInRegisterHint) { { HGraph* graph = BuildFieldReturn(&allocator, &field, &ret); - x86::CodeGeneratorX86 codegen(graph); + x86::CodeGeneratorX86 codegen(graph, CompilerOptions()); SsaLivenessAnalysis liveness(*graph, &codegen); liveness.Analyze(); @@ -616,7 +617,7 @@ TEST(RegisterAllocatorTest, ExpectedInRegisterHint) { { HGraph* graph = BuildFieldReturn(&allocator, &field, &ret); - x86::CodeGeneratorX86 codegen(graph); + x86::CodeGeneratorX86 codegen(graph, CompilerOptions()); SsaLivenessAnalysis liveness(*graph, &codegen); liveness.Analyze(); @@ -665,7 +666,7 @@ TEST(RegisterAllocatorTest, SameAsFirstInputHint) { { HGraph* graph = BuildTwoAdds(&allocator, &first_add, &second_add); - x86::CodeGeneratorX86 codegen(graph); + x86::CodeGeneratorX86 codegen(graph, CompilerOptions()); SsaLivenessAnalysis liveness(*graph, &codegen); liveness.Analyze(); @@ -679,7 +680,7 @@ TEST(RegisterAllocatorTest, SameAsFirstInputHint) { { HGraph* graph = BuildTwoAdds(&allocator, &first_add, &second_add); - x86::CodeGeneratorX86 codegen(graph); + x86::CodeGeneratorX86 codegen(graph, CompilerOptions()); SsaLivenessAnalysis liveness(*graph, &codegen); liveness.Analyze(); @@ -726,7 +727,7 @@ TEST(RegisterAllocatorTest, ExpectedExactInRegisterAndSameOutputHint) { { HGraph* graph = BuildDiv(&allocator, &div); - x86::CodeGeneratorX86 codegen(graph); + x86::CodeGeneratorX86 codegen(graph, CompilerOptions()); SsaLivenessAnalysis liveness(*graph, &codegen); liveness.Analyze(); @@ -738,4 +739,106 @@ TEST(RegisterAllocatorTest, ExpectedExactInRegisterAndSameOutputHint) { } } +// Test a bug in the register allocator, where allocating a blocked +// register would lead to spilling an inactive interval at the wrong +// position. +TEST(RegisterAllocatorTest, SpillInactive) { + ArenaPool pool; + + // Create a synthesized graph to please the register_allocator and + // ssa_liveness_analysis code. + ArenaAllocator allocator(&pool); + HGraph* graph = new (&allocator) HGraph(&allocator); + HBasicBlock* entry = new (&allocator) HBasicBlock(graph); + graph->AddBlock(entry); + graph->SetEntryBlock(entry); + HInstruction* one = new (&allocator) HParameterValue(0, Primitive::kPrimInt); + HInstruction* two = new (&allocator) HParameterValue(0, Primitive::kPrimInt); + HInstruction* three = new (&allocator) HParameterValue(0, Primitive::kPrimInt); + HInstruction* four = new (&allocator) HParameterValue(0, Primitive::kPrimInt); + entry->AddInstruction(one); + entry->AddInstruction(two); + entry->AddInstruction(three); + entry->AddInstruction(four); + + HBasicBlock* block = new (&allocator) HBasicBlock(graph); + graph->AddBlock(block); + entry->AddSuccessor(block); + block->AddInstruction(new (&allocator) HExit()); + + // We create a synthesized user requesting a register, to avoid just spilling the + // intervals. + HPhi* user = new (&allocator) HPhi(&allocator, 0, 1, Primitive::kPrimInt); + user->AddInput(one); + user->SetBlock(block); + LocationSummary* locations = new (&allocator) LocationSummary(user, LocationSummary::kNoCall); + locations->SetInAt(0, Location::RequiresRegister()); + static constexpr size_t phi_ranges[][2] = {{20, 30}}; + BuildInterval(phi_ranges, arraysize(phi_ranges), &allocator, -1, user); + + // Create an interval with lifetime holes. + static constexpr size_t ranges1[][2] = {{0, 2}, {4, 6}, {8, 10}}; + LiveInterval* first = BuildInterval(ranges1, arraysize(ranges1), &allocator, -1, one); + first->first_use_ = new(&allocator) UsePosition(user, 0, false, 8, first->first_use_); + first->first_use_ = new(&allocator) UsePosition(user, 0, false, 7, first->first_use_); + first->first_use_ = new(&allocator) UsePosition(user, 0, false, 6, first->first_use_); + + locations = new (&allocator) LocationSummary(first->GetDefinedBy(), LocationSummary::kNoCall); + locations->SetOut(Location::RequiresRegister()); + first = first->SplitAt(1); + + // Create an interval that conflicts with the next interval, to force the next + // interval to call `AllocateBlockedReg`. + static constexpr size_t ranges2[][2] = {{2, 4}}; + LiveInterval* second = BuildInterval(ranges2, arraysize(ranges2), &allocator, -1, two); + locations = new (&allocator) LocationSummary(second->GetDefinedBy(), LocationSummary::kNoCall); + locations->SetOut(Location::RequiresRegister()); + + // Create an interval that will lead to splitting the first interval. The bug occured + // by splitting at a wrong position, in this case at the next intersection between + // this interval and the first interval. We would have then put the interval with ranges + // "[0, 2(, [4, 6(" in the list of handled intervals, even though we haven't processed intervals + // before lifetime position 6 yet. + static constexpr size_t ranges3[][2] = {{2, 4}, {8, 10}}; + LiveInterval* third = BuildInterval(ranges3, arraysize(ranges3), &allocator, -1, three); + third->first_use_ = new(&allocator) UsePosition(user, 0, false, 8, third->first_use_); + third->first_use_ = new(&allocator) UsePosition(user, 0, false, 4, third->first_use_); + third->first_use_ = new(&allocator) UsePosition(user, 0, false, 3, third->first_use_); + locations = new (&allocator) LocationSummary(third->GetDefinedBy(), LocationSummary::kNoCall); + locations->SetOut(Location::RequiresRegister()); + third = third->SplitAt(3); + + // Because the first part of the split interval was considered handled, this interval + // was free to allocate the same register, even though it conflicts with it. + static constexpr size_t ranges4[][2] = {{4, 6}}; + LiveInterval* fourth = BuildInterval(ranges4, arraysize(ranges4), &allocator, -1, four); + locations = new (&allocator) LocationSummary(fourth->GetDefinedBy(), LocationSummary::kNoCall); + locations->SetOut(Location::RequiresRegister()); + + x86::CodeGeneratorX86 codegen(graph, CompilerOptions()); + SsaLivenessAnalysis liveness(*graph, &codegen); + + RegisterAllocator register_allocator(&allocator, &codegen, liveness); + register_allocator.unhandled_core_intervals_.Add(fourth); + register_allocator.unhandled_core_intervals_.Add(third); + register_allocator.unhandled_core_intervals_.Add(second); + register_allocator.unhandled_core_intervals_.Add(first); + + // Set just one register available to make all intervals compete for the same. + register_allocator.number_of_registers_ = 1; + register_allocator.registers_array_ = allocator.AllocArray<size_t>(1); + register_allocator.processing_core_registers_ = true; + register_allocator.unhandled_ = ®ister_allocator.unhandled_core_intervals_; + register_allocator.LinearScan(); + + // Test that there is no conflicts between intervals. + GrowableArray<LiveInterval*> intervals(&allocator, 0); + intervals.Add(first); + intervals.Add(second); + intervals.Add(third); + intervals.Add(fourth); + ASSERT_TRUE(RegisterAllocator::ValidateIntervals( + intervals, 0, 0, codegen, &allocator, true, false)); +} + } // namespace art diff --git a/compiler/optimizing/ssa_liveness_analysis.h b/compiler/optimizing/ssa_liveness_analysis.h index 74611e1cbb..a123313426 100644 --- a/compiler/optimizing/ssa_liveness_analysis.h +++ b/compiler/optimizing/ssa_liveness_analysis.h @@ -429,7 +429,7 @@ class LiveInterval : public ArenaObject<kArenaAllocMisc> { LiveRange* current = first_range_; LiveRange* previous = nullptr; // Iterate over the ranges, and either find a range that covers this position, or - // a two ranges in between this position (that is, the position is in a lifetime hole). + // two ranges in between this position (that is, the position is in a lifetime hole). do { if (position >= current->GetEnd()) { // Move to next range. @@ -530,7 +530,7 @@ class LiveInterval : public ArenaObject<kArenaAllocMisc> { bool SameRegisterKind(Location other) const; bool HasHighInterval() const { - return !IsHighInterval() && (GetParent()->high_or_low_interval_ != nullptr); + return IsLowInterval(); } bool HasLowInterval() const { @@ -653,6 +653,8 @@ class LiveInterval : public ArenaObject<kArenaAllocMisc> { static constexpr int kNoRegister = -1; static constexpr int kNoSpillSlot = -1; + ART_FRIEND_TEST(RegisterAllocatorTest, SpillInactive); + DISALLOW_COPY_AND_ASSIGN(LiveInterval); }; diff --git a/compiler/optimizing/test/ConstantFolding.java b/compiler/optimizing/test/ConstantFolding.java deleted file mode 100644 index d08006b4d5..0000000000 --- a/compiler/optimizing/test/ConstantFolding.java +++ /dev/null @@ -1,221 +0,0 @@ -/* -* Copyright (C) 2014 The Android Open Source Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -public class ConstantFolding { - - /** - * Tiny three-register program exercising int constant folding - * on negation. - */ - - // CHECK-START: int ConstantFolding.IntNegation() constant_folding (before) - // 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\d+]] IntConstant -42 - // CHECK-DAG: Return [ [[ConstN42]] ] - - public static int IntNegation() { - int x, y; - x = 42; - y = -x; - return y; - } - - /** - * Tiny three-register program exercising int constant folding - * on addition. - */ - - // CHECK-START: int ConstantFolding.IntAddition1() constant_folding (before) - // 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\d+]] IntConstant 3 - // CHECK-DAG: Return [ [[Const3]] ] - - public static int IntAddition1() { - int a, b, c; - a = 1; - b = 2; - c = a + b; - return c; - } - - /** - * Small three-register program exercising int constant folding - * on addition. - */ - - // CHECK-START: int ConstantFolding.IntAddition2() constant_folding (before) - // 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\d+]] IntConstant 14 - // CHECK-DAG: Return [ [[Const14]] ] - - public static int IntAddition2() { - int a, b, c; - a = 1; - b = 2; - a += b; - b = 5; - c = 6; - b += c; - c = a + b; - return c; - } - - /** - * Tiny three-register program exercising int constant folding - * on subtraction. - */ - - // CHECK-START: int ConstantFolding.IntSubtraction() constant_folding (before) - // 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\d+]] IntConstant 3 - // CHECK-DAG: Return [ [[Const3]] ] - - public static int IntSubtraction() { - int a, b, c; - a = 5; - b = 2; - c = a - b; - return c; - } - - /** - * Tiny three-register program exercising long constant folding - * on addition. - */ - - // CHECK-START: long ConstantFolding.LongAddition() constant_folding (before) - // 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\d+]] LongConstant 3 - // CHECK-DAG: Return [ [[Const3]] ] - - public static long LongAddition() { - long a, b, c; - a = 1L; - b = 2L; - c = a + b; - return c; - } - - /** - * Tiny three-register program exercising long constant folding - * on subtraction. - */ - - // CHECK-START: long ConstantFolding.LongSubtraction() constant_folding (before) - // 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\d+]] LongConstant 3 - // CHECK-DAG: Return [ [[Const3]] ] - - public static long LongSubtraction() { - long a, b, c; - a = 5L; - b = 2L; - c = a - b; - return c; - } - - /** - * Three-register program with a constant (static) condition. - */ - - // CHECK-START: int ConstantFolding.StaticCondition() constant_folding (before) - // 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\d+]] IntConstant 1 - // CHECK-DAG: If [ [[Const1]] ] - - public static int StaticCondition() { - int a, b, c; - a = 5; - b = 2; - if (a < b) - c = a + b; - else - c = a - b; - return c; - } - - /** - * Four-variable program with jumps leading to the creation of many - * blocks. - * - * The intent of this test is to ensure that all constant expressions - * are actually evaluated at compile-time, thanks to the reverse - * (forward) post-order traversal of the the dominator tree. - */ - - // CHECK-START: int ConstantFolding.JumpsAndConditionals(boolean) constant_folding (before) - // 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\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; - a = 5; - b = 2; - if (cond) - c = a + b; - else - c = a - b; - return c; - } -} diff --git a/compiler/optimizing/test/Inliner.java b/compiler/optimizing/test/Inliner.java deleted file mode 100644 index 54cce62a57..0000000000 --- a/compiler/optimizing/test/Inliner.java +++ /dev/null @@ -1,202 +0,0 @@ -/* -* Copyright (C) 2014 The Android Open Source Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -public class Inliner { - - // CHECK-START: void Inliner.InlineVoid() inliner (before) - // CHECK-DAG: [[Const42:i\d+]] IntConstant 42 - // CHECK-DAG: InvokeStaticOrDirect - // CHECK-DAG: InvokeStaticOrDirect [ [[Const42]] ] - - // CHECK-START: void Inliner.InlineVoid() inliner (after) - // CHECK-NOT: InvokeStaticOrDirect - - public static void InlineVoid() { - returnVoid(); - returnVoidWithOneParameter(42); - } - - // CHECK-START: int Inliner.InlineParameter(int) inliner (before) - // 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\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\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\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\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\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\d+]] InvokeStaticOrDirect - // CHECK-DAG: Return [ [[Result]] ] - - // CHECK-START: int Inliner.InlineInt() inliner (after) - // 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\d+]] InvokeStaticOrDirect - // CHECK-DAG: Return [ [[Result]] ] - - // CHECK-START: long Inliner.InlineWide() inliner (after) - // 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\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\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\d+]] InvokeStaticOrDirect - // CHECK-DAG: Return [ [[After]] ] - - // CHECK-START: int Inliner.InlineFieldAccess() inliner (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 - - public static int InlineFieldAccess() { - return incCounter(); - } - - // CHECK-START: int Inliner.InlineWithControlFlow(boolean) inliner (before) - // 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\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; - const1 = 1; - const3 = 3; - const5 = 5; - if (cond) { - x = returnAdd(const1, const3); - } else { - x = returnSub(const5, const3); - } - return x; - } - - - private static void returnVoid() { - return; - } - - private static void returnVoidWithOneParameter(int a) { - return; - } - - private static int returnParameter(int a) { - return a; - } - - private static long returnWideParameter(long a) { - return a; - } - - private static Object returnReferenceParameter(Object o) { - return o; - } - - private static int returnInt() { - return 4; - } - - private static long returnWide() { - return 8L; - } - - private static int returnAdd(int a, int b) { - return a + b; - } - - private static int returnSub(int a, int b) { - return a - b; - } - - private static int counter = 42; - - private static int incCounter() { - return ++counter; - } -} diff --git a/compiler/utils/x86_64/assembler_x86_64.cc b/compiler/utils/x86_64/assembler_x86_64.cc index c7414a12fc..906eabf4bb 100644 --- a/compiler/utils/x86_64/assembler_x86_64.cc +++ b/compiler/utils/x86_64/assembler_x86_64.cc @@ -1121,6 +1121,14 @@ void X86_64Assembler::testl(CpuRegister reg1, CpuRegister reg2) { } +void X86_64Assembler::testl(CpuRegister reg, const Address& address) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitOptionalRex32(reg, address); + EmitUint8(0x85); + EmitOperand(reg.LowBits(), address); +} + + void X86_64Assembler::testl(CpuRegister reg, const Immediate& immediate) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); // For registers that have a byte variant (RAX, RBX, RCX, and RDX) diff --git a/compiler/utils/x86_64/assembler_x86_64.h b/compiler/utils/x86_64/assembler_x86_64.h index 5c8d608cf2..4a509faa0c 100644 --- a/compiler/utils/x86_64/assembler_x86_64.h +++ b/compiler/utils/x86_64/assembler_x86_64.h @@ -409,6 +409,7 @@ class X86_64Assembler FINAL : public Assembler { void cmpq(const Address& address, const Immediate& imm); void testl(CpuRegister reg1, CpuRegister reg2); + void testl(CpuRegister reg, const Address& address); void testl(CpuRegister reg, const Immediate& imm); void testq(CpuRegister reg1, CpuRegister reg2); |