diff options
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/optimizing/code_generator_arm.cc | 251 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_arm.h | 14 | ||||
| -rw-r--r-- | compiler/utils/arm/assembler_arm.h | 3 | ||||
| -rw-r--r-- | compiler/utils/arm/assembler_thumb2.cc | 24 | ||||
| -rw-r--r-- | compiler/utils/arm/assembler_thumb2.h | 2 |
5 files changed, 257 insertions, 37 deletions
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index 8b2d6fd838..3b2758bc42 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -63,9 +63,188 @@ static constexpr uint32_t kPackedSwitchCompareJumpThreshold = 7; #define __ down_cast<ArmAssembler*>(codegen->GetAssembler())-> // NOLINT #define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kArmPointerSize, x).Int32Value() -class NullCheckSlowPathARM : public SlowPathCode { +static constexpr int kRegListThreshold = 4; + +// SaveLiveRegisters and RestoreLiveRegisters from SlowPathCodeARM operate on sets of S registers, +// for each live D registers they treat two corresponding S registers as live ones. +// +// Two following functions (SaveContiguousSRegisterList, RestoreContiguousSRegisterList) build +// from a list of contiguous S registers a list of contiguous D registers (processing first/last +// S registers corner cases) and save/restore this new list treating them as D registers. +// - decreasing code size +// - avoiding hazards on Cortex-A57, when a pair of S registers for an actual live D register is +// restored and then used in regular non SlowPath code as D register. +// +// For the following example (v means the S register is live): +// D names: | D0 | D1 | D2 | D4 | ... +// S names: | S0 | S1 | S2 | S3 | S4 | S5 | S6 | S7 | ... +// Live? | | v | v | v | v | v | v | | ... +// +// S1 and S6 will be saved/restored independently; D registers list (D1, D2) will be processed +// as D registers. +static size_t SaveContiguousSRegisterList(size_t first, + size_t last, + CodeGenerator* codegen, + size_t stack_offset) { + DCHECK_LE(first, last); + if ((first == last) && (first == 0)) { + stack_offset += codegen->SaveFloatingPointRegister(stack_offset, first); + return stack_offset; + } + if (first % 2 == 1) { + stack_offset += codegen->SaveFloatingPointRegister(stack_offset, first++); + } + + bool save_last = false; + if (last % 2 == 0) { + save_last = true; + --last; + } + + if (first < last) { + DRegister d_reg = static_cast<DRegister>(first / 2); + DCHECK_EQ((last - first + 1) % 2, 0u); + size_t number_of_d_regs = (last - first + 1) / 2; + + if (number_of_d_regs == 1) { + __ StoreDToOffset(d_reg, SP, stack_offset); + } else if (number_of_d_regs > 1) { + __ add(IP, SP, ShifterOperand(stack_offset)); + __ vstmiad(IP, d_reg, number_of_d_regs); + } + stack_offset += number_of_d_regs * kArmWordSize * 2; + } + + if (save_last) { + stack_offset += codegen->SaveFloatingPointRegister(stack_offset, last + 1); + } + + return stack_offset; +} + +static size_t RestoreContiguousSRegisterList(size_t first, + size_t last, + CodeGenerator* codegen, + size_t stack_offset) { + DCHECK_LE(first, last); + if ((first == last) && (first == 0)) { + stack_offset += codegen->RestoreFloatingPointRegister(stack_offset, first); + return stack_offset; + } + if (first % 2 == 1) { + stack_offset += codegen->RestoreFloatingPointRegister(stack_offset, first++); + } + + bool restore_last = false; + if (last % 2 == 0) { + restore_last = true; + --last; + } + + if (first < last) { + DRegister d_reg = static_cast<DRegister>(first / 2); + DCHECK_EQ((last - first + 1) % 2, 0u); + size_t number_of_d_regs = (last - first + 1) / 2; + if (number_of_d_regs == 1) { + __ LoadDFromOffset(d_reg, SP, stack_offset); + } else if (number_of_d_regs > 1) { + __ add(IP, SP, ShifterOperand(stack_offset)); + __ vldmiad(IP, d_reg, number_of_d_regs); + } + stack_offset += number_of_d_regs * kArmWordSize * 2; + } + + if (restore_last) { + stack_offset += codegen->RestoreFloatingPointRegister(stack_offset, last + 1); + } + + return stack_offset; +} + +void SlowPathCodeARM::SaveLiveRegisters(CodeGenerator* codegen, LocationSummary* locations) { + size_t stack_offset = codegen->GetFirstRegisterSlotInSlowPath(); + size_t orig_offset = stack_offset; + + const uint32_t core_spills = codegen->GetSlowPathSpills(locations, /* core_registers */ true); + for (uint32_t i : LowToHighBits(core_spills)) { + // If the register holds an object, update the stack mask. + if (locations->RegisterContainsObject(i)) { + locations->SetStackBit(stack_offset / kVRegSize); + } + DCHECK_LT(stack_offset, codegen->GetFrameSize() - codegen->FrameEntrySpillSize()); + DCHECK_LT(i, kMaximumNumberOfExpectedRegisters); + saved_core_stack_offsets_[i] = stack_offset; + stack_offset += kArmWordSize; + } + + int reg_num = POPCOUNT(core_spills); + if (reg_num != 0) { + if (reg_num > kRegListThreshold) { + __ StoreList(RegList(core_spills), orig_offset); + } else { + stack_offset = orig_offset; + for (uint32_t i : LowToHighBits(core_spills)) { + stack_offset += codegen->SaveCoreRegister(stack_offset, i); + } + } + } + + uint32_t fp_spills = codegen->GetSlowPathSpills(locations, /* core_registers */ false); + orig_offset = stack_offset; + for (size_t i : LowToHighBits(fp_spills)) { + DCHECK_LT(i, kMaximumNumberOfExpectedRegisters); + saved_fpu_stack_offsets_[i] = stack_offset; + stack_offset += kArmWordSize; + } + + stack_offset = orig_offset; + while (fp_spills != 0u) { + uint32_t begin = CTZ(fp_spills); + uint32_t tmp = fp_spills + (1u << begin); + fp_spills &= tmp; // Clear the contiguous range of 1s. + uint32_t end = (tmp == 0u) ? 32u : CTZ(tmp); // CTZ(0) is undefined. + stack_offset = SaveContiguousSRegisterList(begin, end - 1, codegen, stack_offset); + } + DCHECK_LE(stack_offset, codegen->GetFrameSize() - codegen->FrameEntrySpillSize()); +} + +void SlowPathCodeARM::RestoreLiveRegisters(CodeGenerator* codegen, LocationSummary* locations) { + size_t stack_offset = codegen->GetFirstRegisterSlotInSlowPath(); + size_t orig_offset = stack_offset; + + const uint32_t core_spills = codegen->GetSlowPathSpills(locations, /* core_registers */ true); + for (uint32_t i : LowToHighBits(core_spills)) { + DCHECK_LT(stack_offset, codegen->GetFrameSize() - codegen->FrameEntrySpillSize()); + DCHECK_LT(i, kMaximumNumberOfExpectedRegisters); + stack_offset += kArmWordSize; + } + + int reg_num = POPCOUNT(core_spills); + if (reg_num != 0) { + if (reg_num > kRegListThreshold) { + __ LoadList(RegList(core_spills), orig_offset); + } else { + stack_offset = orig_offset; + for (uint32_t i : LowToHighBits(core_spills)) { + stack_offset += codegen->RestoreCoreRegister(stack_offset, i); + } + } + } + + uint32_t fp_spills = codegen->GetSlowPathSpills(locations, /* core_registers */ false); + while (fp_spills != 0u) { + uint32_t begin = CTZ(fp_spills); + uint32_t tmp = fp_spills + (1u << begin); + fp_spills &= tmp; // Clear the contiguous range of 1s. + uint32_t end = (tmp == 0u) ? 32u : CTZ(tmp); // CTZ(0) is undefined. + stack_offset = RestoreContiguousSRegisterList(begin, end - 1, codegen, stack_offset); + } + DCHECK_LE(stack_offset, codegen->GetFrameSize() - codegen->FrameEntrySpillSize()); +} + +class NullCheckSlowPathARM : public SlowPathCodeARM { public: - explicit NullCheckSlowPathARM(HNullCheck* instruction) : SlowPathCode(instruction) {} + explicit NullCheckSlowPathARM(HNullCheck* instruction) : SlowPathCodeARM(instruction) {} void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen); @@ -89,9 +268,9 @@ class NullCheckSlowPathARM : public SlowPathCode { DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathARM); }; -class DivZeroCheckSlowPathARM : public SlowPathCode { +class DivZeroCheckSlowPathARM : public SlowPathCodeARM { public: - explicit DivZeroCheckSlowPathARM(HDivZeroCheck* instruction) : SlowPathCode(instruction) {} + explicit DivZeroCheckSlowPathARM(HDivZeroCheck* instruction) : SlowPathCodeARM(instruction) {} void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen); @@ -112,10 +291,10 @@ class DivZeroCheckSlowPathARM : public SlowPathCode { DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathARM); }; -class SuspendCheckSlowPathARM : public SlowPathCode { +class SuspendCheckSlowPathARM : public SlowPathCodeARM { public: SuspendCheckSlowPathARM(HSuspendCheck* instruction, HBasicBlock* successor) - : SlowPathCode(instruction), successor_(successor) {} + : SlowPathCodeARM(instruction), successor_(successor) {} void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen); @@ -150,10 +329,10 @@ class SuspendCheckSlowPathARM : public SlowPathCode { DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathARM); }; -class BoundsCheckSlowPathARM : public SlowPathCode { +class BoundsCheckSlowPathARM : public SlowPathCodeARM { public: explicit BoundsCheckSlowPathARM(HBoundsCheck* instruction) - : SlowPathCode(instruction) {} + : SlowPathCodeARM(instruction) {} void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen); @@ -190,13 +369,13 @@ class BoundsCheckSlowPathARM : public SlowPathCode { DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM); }; -class LoadClassSlowPathARM : public SlowPathCode { +class LoadClassSlowPathARM : public SlowPathCodeARM { public: LoadClassSlowPathARM(HLoadClass* cls, HInstruction* at, uint32_t dex_pc, bool do_clinit) - : SlowPathCode(at), cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) { + : SlowPathCodeARM(at), cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) { DCHECK(at->IsLoadClass() || at->IsClinitCheck()); } @@ -247,10 +426,10 @@ class LoadClassSlowPathARM : public SlowPathCode { DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathARM); }; -class TypeCheckSlowPathARM : public SlowPathCode { +class TypeCheckSlowPathARM : public SlowPathCodeARM { public: TypeCheckSlowPathARM(HInstruction* instruction, bool is_fatal) - : SlowPathCode(instruction), is_fatal_(is_fatal) {} + : SlowPathCodeARM(instruction), is_fatal_(is_fatal) {} void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { LocationSummary* locations = instruction_->GetLocations(); @@ -307,10 +486,10 @@ class TypeCheckSlowPathARM : public SlowPathCode { DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathARM); }; -class DeoptimizationSlowPathARM : public SlowPathCode { +class DeoptimizationSlowPathARM : public SlowPathCodeARM { public: explicit DeoptimizationSlowPathARM(HDeoptimize* instruction) - : SlowPathCode(instruction) {} + : SlowPathCodeARM(instruction) {} void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen); @@ -325,9 +504,9 @@ class DeoptimizationSlowPathARM : public SlowPathCode { DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathARM); }; -class ArraySetSlowPathARM : public SlowPathCode { +class ArraySetSlowPathARM : public SlowPathCodeARM { public: - explicit ArraySetSlowPathARM(HInstruction* instruction) : SlowPathCode(instruction) {} + explicit ArraySetSlowPathARM(HInstruction* instruction) : SlowPathCodeARM(instruction) {} void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { LocationSummary* locations = instruction_->GetLocations(); @@ -367,10 +546,10 @@ class ArraySetSlowPathARM : public SlowPathCode { }; // Slow path marking an object during a read barrier. -class ReadBarrierMarkSlowPathARM : public SlowPathCode { +class ReadBarrierMarkSlowPathARM : public SlowPathCodeARM { public: ReadBarrierMarkSlowPathARM(HInstruction* instruction, Location obj) - : SlowPathCode(instruction), obj_(obj) { + : SlowPathCodeARM(instruction), obj_(obj) { DCHECK(kEmitCompilerReadBarrier); } @@ -434,7 +613,7 @@ class ReadBarrierMarkSlowPathARM : public SlowPathCode { }; // Slow path generating a read barrier for a heap reference. -class ReadBarrierForHeapReferenceSlowPathARM : public SlowPathCode { +class ReadBarrierForHeapReferenceSlowPathARM : public SlowPathCodeARM { public: ReadBarrierForHeapReferenceSlowPathARM(HInstruction* instruction, Location out, @@ -442,7 +621,7 @@ class ReadBarrierForHeapReferenceSlowPathARM : public SlowPathCode { Location obj, uint32_t offset, Location index) - : SlowPathCode(instruction), + : SlowPathCodeARM(instruction), out_(out), ref_(ref), obj_(obj), @@ -614,10 +793,10 @@ class ReadBarrierForHeapReferenceSlowPathARM : public SlowPathCode { }; // Slow path generating a read barrier for a GC root. -class ReadBarrierForRootSlowPathARM : public SlowPathCode { +class ReadBarrierForRootSlowPathARM : public SlowPathCodeARM { public: ReadBarrierForRootSlowPathARM(HInstruction* instruction, Location out, Location root) - : SlowPathCode(instruction), out_(out), root_(root) { + : SlowPathCodeARM(instruction), out_(out), root_(root) { DCHECK(kEmitCompilerReadBarrier); } @@ -1509,7 +1688,7 @@ void LocationsBuilderARM::VisitDeoptimize(HDeoptimize* deoptimize) { } void InstructionCodeGeneratorARM::VisitDeoptimize(HDeoptimize* deoptimize) { - SlowPathCode* slow_path = deopt_slow_paths_.NewSlowPath<DeoptimizationSlowPathARM>(deoptimize); + SlowPathCodeARM* slow_path = deopt_slow_paths_.NewSlowPath<DeoptimizationSlowPathARM>(deoptimize); GenerateTestAndBranch(deoptimize, /* condition_input_index */ 0, slow_path->GetEntryLabel(), @@ -3096,7 +3275,7 @@ void LocationsBuilderARM::VisitDivZeroCheck(HDivZeroCheck* instruction) { } void InstructionCodeGeneratorARM::VisitDivZeroCheck(HDivZeroCheck* instruction) { - SlowPathCode* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathARM(instruction); + SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathARM(instruction); codegen_->AddSlowPath(slow_path); LocationSummary* locations = instruction->GetLocations(); @@ -4265,7 +4444,7 @@ void CodeGeneratorARM::GenerateImplicitNullCheck(HNullCheck* instruction) { } void CodeGeneratorARM::GenerateExplicitNullCheck(HNullCheck* instruction) { - SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction); + SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction); AddSlowPath(slow_path); LocationSummary* locations = instruction->GetLocations(); @@ -4683,7 +4862,7 @@ void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) { uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value(); uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value(); Label done; - SlowPathCode* slow_path = nullptr; + SlowPathCodeARM* slow_path = nullptr; if (may_need_runtime_call_for_type_check) { slow_path = new (GetGraph()->GetArena()) ArraySetSlowPathARM(instruction); @@ -4901,7 +5080,7 @@ void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) { void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) { LocationSummary* locations = instruction->GetLocations(); - SlowPathCode* slow_path = + SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(instruction); codegen_->AddSlowPath(slow_path); @@ -5370,7 +5549,7 @@ void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) { if (generate_null_check || cls->MustGenerateClinitCheck()) { DCHECK(cls->CanCallRuntime()); - SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM( + SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM( cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck()); codegen_->AddSlowPath(slow_path); if (generate_null_check) { @@ -5395,7 +5574,7 @@ void LocationsBuilderARM::VisitClinitCheck(HClinitCheck* check) { void InstructionCodeGeneratorARM::VisitClinitCheck(HClinitCheck* check) { // We assume the class is not null. - SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM( + SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM( check->GetLoadClass(), check, check->GetDexPc(), true); codegen_->AddSlowPath(slow_path); GenerateClassInitializationCheck(slow_path, @@ -5403,7 +5582,7 @@ void InstructionCodeGeneratorARM::VisitClinitCheck(HClinitCheck* check) { } void InstructionCodeGeneratorARM::GenerateClassInitializationCheck( - SlowPathCode* slow_path, Register class_reg) { + SlowPathCodeARM* slow_path, Register class_reg) { __ LoadFromOffset(kLoadWord, IP, class_reg, mirror::Class::StatusOffset().Int32Value()); __ cmp(IP, ShifterOperand(mirror::Class::kStatusInitialized)); __ b(slow_path->GetEntryLabel(), LT); @@ -5596,7 +5775,7 @@ void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) { uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value(); uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value(); Label done, zero; - SlowPathCode* slow_path = nullptr; + SlowPathCodeARM* slow_path = nullptr; // Return 0 if `obj` is null. // avoid null check if we know obj is not null. @@ -5788,7 +5967,7 @@ void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) { type_check_kind == TypeCheckKind::kClassHierarchyCheck || type_check_kind == TypeCheckKind::kArrayObjectCheck) && !instruction->CanThrowIntoCatchBlock(); - SlowPathCode* type_check_slow_path = + SlowPathCodeARM* type_check_slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction, is_type_check_slow_path_fatal); codegen_->AddSlowPath(type_check_slow_path); @@ -6282,7 +6461,7 @@ void InstructionCodeGeneratorARM::GenerateGcRootFieldLoad(HInstruction* instruct "have different sizes."); // Slow path marking the GC root `root`. - SlowPathCode* slow_path = + SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathARM(instruction, root); codegen_->AddSlowPath(slow_path); @@ -6423,7 +6602,7 @@ void CodeGeneratorARM::GenerateReferenceLoadWithBakerReadBarrier(HInstruction* i __ MaybeUnpoisonHeapReference(ref_reg); // Slow path marking the object `ref` when it is gray. - SlowPathCode* slow_path = + SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathARM(instruction, ref); AddSlowPath(slow_path); @@ -6459,7 +6638,7 @@ void CodeGeneratorARM::GenerateReadBarrierSlow(HInstruction* instruction, // not used by the artReadBarrierSlow entry point. // // TODO: Unpoison `ref` when it is used by artReadBarrierSlow. - SlowPathCode* slow_path = new (GetGraph()->GetArena()) + SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) ReadBarrierForHeapReferenceSlowPathARM(instruction, out, ref, obj, offset, index); AddSlowPath(slow_path); @@ -6494,7 +6673,7 @@ void CodeGeneratorARM::GenerateReadBarrierForRootSlow(HInstruction* instruction, // // Note that GC roots are not affected by heap poisoning, so we do // not need to do anything special for this here. - SlowPathCode* slow_path = + SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) ReadBarrierForRootSlowPathARM(instruction, out, root); AddSlowPath(slow_path); diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h index 38a2410f9a..424a1a1455 100644 --- a/compiler/optimizing/code_generator_arm.h +++ b/compiler/optimizing/code_generator_arm.h @@ -50,6 +50,18 @@ static constexpr SRegister kRuntimeParameterFpuRegisters[] = { S0, S1, S2, S3 }; static constexpr size_t kRuntimeParameterFpuRegistersLength = arraysize(kRuntimeParameterFpuRegisters); +class SlowPathCodeARM : public SlowPathCode { + public: + explicit SlowPathCodeARM(HInstruction* instruction) : SlowPathCode(instruction) {} + + void SaveLiveRegisters(CodeGenerator* codegen, LocationSummary* locations) FINAL; + void RestoreLiveRegisters(CodeGenerator* codegen, LocationSummary* locations) FINAL; + + private: + DISALLOW_COPY_AND_ASSIGN(SlowPathCodeARM); +}; + + class InvokeRuntimeCallingConvention : public CallingConvention<Register, SRegister> { public: InvokeRuntimeCallingConvention() @@ -216,7 +228,7 @@ class InstructionCodeGeneratorARM : public InstructionCodeGenerator { // is the block to branch to if the suspend check is not needed, and after // the suspend call. void GenerateSuspendCheck(HSuspendCheck* check, HBasicBlock* successor); - void GenerateClassInitializationCheck(SlowPathCode* slow_path, Register class_reg); + void GenerateClassInitializationCheck(SlowPathCodeARM* slow_path, Register class_reg); void GenerateAndConst(Register out, Register first, uint32_t value); void GenerateOrrConst(Register out, Register first, uint32_t value); void GenerateEorConst(Register out, Register first, uint32_t value); diff --git a/compiler/utils/arm/assembler_arm.h b/compiler/utils/arm/assembler_arm.h index aefbf26db7..ee5811c3c0 100644 --- a/compiler/utils/arm/assembler_arm.h +++ b/compiler/utils/arm/assembler_arm.h @@ -763,6 +763,9 @@ class ArmAssembler : public Assembler { virtual void PushList(RegList regs, Condition cond = AL) = 0; virtual void PopList(RegList regs, Condition cond = AL) = 0; + virtual void StoreList(RegList regs, size_t stack_offset) = 0; + virtual void LoadList(RegList regs, size_t stack_offset) = 0; + virtual void Mov(Register rd, Register rm, Condition cond = AL) = 0; // Convenience shift instructions. Use mov instruction with shifter operand diff --git a/compiler/utils/arm/assembler_thumb2.cc b/compiler/utils/arm/assembler_thumb2.cc index f5ccf409fc..2269ba2d20 100644 --- a/compiler/utils/arm/assembler_thumb2.cc +++ b/compiler/utils/arm/assembler_thumb2.cc @@ -3372,6 +3372,30 @@ void Thumb2Assembler::PopList(RegList regs, Condition cond) { ldm(IA_W, SP, regs, cond); } +void Thumb2Assembler::StoreList(RegList regs, size_t stack_offset) { + DCHECK_NE(regs, 0u); + DCHECK_EQ(regs & (1u << IP), 0u); + if (IsPowerOfTwo(regs)) { + Register reg = static_cast<Register>(CTZ(static_cast<uint32_t>(regs))); + str(reg, Address(SP, stack_offset)); + } else { + add(IP, SP, ShifterOperand(stack_offset)); + stm(IA, IP, regs); + } +} + +void Thumb2Assembler::LoadList(RegList regs, size_t stack_offset) { + DCHECK_NE(regs, 0u); + DCHECK_EQ(regs & (1u << IP), 0u); + if (IsPowerOfTwo(regs)) { + Register reg = static_cast<Register>(CTZ(static_cast<uint32_t>(regs))); + ldr(reg, Address(SP, stack_offset)); + } else { + Register lowest_reg = static_cast<Register>(CTZ(static_cast<uint32_t>(regs))); + add(lowest_reg, SP, ShifterOperand(stack_offset)); + ldm(IA, lowest_reg, regs); + } +} void Thumb2Assembler::Mov(Register rd, Register rm, Condition cond) { if (cond != AL || rd != rm) { diff --git a/compiler/utils/arm/assembler_thumb2.h b/compiler/utils/arm/assembler_thumb2.h index 917c947aa4..1c495aa7a7 100644 --- a/compiler/utils/arm/assembler_thumb2.h +++ b/compiler/utils/arm/assembler_thumb2.h @@ -293,6 +293,8 @@ class Thumb2Assembler FINAL : public ArmAssembler { void PushList(RegList regs, Condition cond = AL) OVERRIDE; void PopList(RegList regs, Condition cond = AL) OVERRIDE; + void StoreList(RegList regs, size_t stack_offset) OVERRIDE; + void LoadList(RegList regs, size_t stack_offset) OVERRIDE; void Mov(Register rd, Register rm, Condition cond = AL) OVERRIDE; |