1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef ART_COMPILER_OPTIMIZING_CODE_GENERATOR_ARM_H_
18 #define ART_COMPILER_OPTIMIZING_CODE_GENERATOR_ARM_H_
19 
20 #include "code_generator.h"
21 #include "dex/compiler_enums.h"
22 #include "driver/compiler_options.h"
23 #include "nodes.h"
24 #include "parallel_move_resolver.h"
25 #include "utils/arm/assembler_thumb2.h"
26 
27 namespace art {
28 namespace arm {
29 
30 class CodeGeneratorARM;
31 class SlowPathCodeARM;
32 
33 // Use a local definition to prevent copying mistakes.
34 static constexpr size_t kArmWordSize = kArmPointerSize;
35 static constexpr size_t kArmBitsPerWord = kArmWordSize * kBitsPerByte;
36 
37 static constexpr Register kParameterCoreRegisters[] = { R1, R2, R3 };
38 static constexpr size_t kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters);
39 static constexpr SRegister kParameterFpuRegisters[] =
40     { S0, S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11, S12, S13, S14, S15 };
41 static constexpr size_t kParameterFpuRegistersLength = arraysize(kParameterFpuRegisters);
42 
43 static constexpr Register kArtMethodRegister = R0;
44 
45 static constexpr Register kRuntimeParameterCoreRegisters[] = { R0, R1, R2, R3 };
46 static constexpr size_t kRuntimeParameterCoreRegistersLength =
47     arraysize(kRuntimeParameterCoreRegisters);
48 static constexpr SRegister kRuntimeParameterFpuRegisters[] = { S0, S1, S2, S3 };
49 static constexpr size_t kRuntimeParameterFpuRegistersLength =
50     arraysize(kRuntimeParameterFpuRegisters);
51 
52 class InvokeRuntimeCallingConvention : public CallingConvention<Register, SRegister> {
53  public:
InvokeRuntimeCallingConvention()54   InvokeRuntimeCallingConvention()
55       : CallingConvention(kRuntimeParameterCoreRegisters,
56                           kRuntimeParameterCoreRegistersLength,
57                           kRuntimeParameterFpuRegisters,
58                           kRuntimeParameterFpuRegistersLength,
59                           kArmPointerSize) {}
60 
61  private:
62   DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
63 };
64 
FromLowSToD(SRegister reg)65 static constexpr DRegister FromLowSToD(SRegister reg) {
66   return DCHECK_CONSTEXPR(reg % 2 == 0, , D0)
67       static_cast<DRegister>(reg / 2);
68 }
69 
70 
71 class InvokeDexCallingConvention : public CallingConvention<Register, SRegister> {
72  public:
InvokeDexCallingConvention()73   InvokeDexCallingConvention()
74       : CallingConvention(kParameterCoreRegisters,
75                           kParameterCoreRegistersLength,
76                           kParameterFpuRegisters,
77                           kParameterFpuRegistersLength,
78                           kArmPointerSize) {}
79 
80  private:
81   DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConvention);
82 };
83 
84 class InvokeDexCallingConventionVisitorARM : public InvokeDexCallingConventionVisitor {
85  public:
InvokeDexCallingConventionVisitorARM()86   InvokeDexCallingConventionVisitorARM() {}
~InvokeDexCallingConventionVisitorARM()87   virtual ~InvokeDexCallingConventionVisitorARM() {}
88 
89   Location GetNextLocation(Primitive::Type type) OVERRIDE;
90   Location GetReturnLocation(Primitive::Type type);
91 
92  private:
93   InvokeDexCallingConvention calling_convention;
94   uint32_t double_index_ = 0;
95 
96   DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConventionVisitorARM);
97 };
98 
99 class ParallelMoveResolverARM : public ParallelMoveResolverWithSwap {
100  public:
ParallelMoveResolverARM(ArenaAllocator * allocator,CodeGeneratorARM * codegen)101   ParallelMoveResolverARM(ArenaAllocator* allocator, CodeGeneratorARM* codegen)
102       : ParallelMoveResolverWithSwap(allocator), codegen_(codegen) {}
103 
104   void EmitMove(size_t index) OVERRIDE;
105   void EmitSwap(size_t index) OVERRIDE;
106   void SpillScratch(int reg) OVERRIDE;
107   void RestoreScratch(int reg) OVERRIDE;
108 
109   ArmAssembler* GetAssembler() const;
110 
111  private:
112   void Exchange(Register reg, int mem);
113   void Exchange(int mem1, int mem2);
114 
115   CodeGeneratorARM* const codegen_;
116 
117   DISALLOW_COPY_AND_ASSIGN(ParallelMoveResolverARM);
118 };
119 
120 class SlowPathCodeARM : public SlowPathCode {
121  public:
SlowPathCodeARM()122   SlowPathCodeARM() : entry_label_(), exit_label_() {}
123 
GetEntryLabel()124   Label* GetEntryLabel() { return &entry_label_; }
GetExitLabel()125   Label* GetExitLabel() { return &exit_label_; }
126 
127  private:
128   Label entry_label_;
129   Label exit_label_;
130 
131   DISALLOW_COPY_AND_ASSIGN(SlowPathCodeARM);
132 };
133 
134 class LocationsBuilderARM : public HGraphVisitor {
135  public:
LocationsBuilderARM(HGraph * graph,CodeGeneratorARM * codegen)136   LocationsBuilderARM(HGraph* graph, CodeGeneratorARM* codegen)
137       : HGraphVisitor(graph), codegen_(codegen) {}
138 
139 #define DECLARE_VISIT_INSTRUCTION(name, super)     \
140   void Visit##name(H##name* instr);
141 
142   FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
143 
144 #undef DECLARE_VISIT_INSTRUCTION
145 
146  private:
147   void HandleInvoke(HInvoke* invoke);
148   void HandleBitwiseOperation(HBinaryOperation* operation);
149   void HandleShift(HBinaryOperation* operation);
150   void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info);
151   void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info);
152 
153   CodeGeneratorARM* const codegen_;
154   InvokeDexCallingConventionVisitorARM parameter_visitor_;
155 
156   DISALLOW_COPY_AND_ASSIGN(LocationsBuilderARM);
157 };
158 
159 class InstructionCodeGeneratorARM : public HGraphVisitor {
160  public:
161   InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen);
162 
163 #define DECLARE_VISIT_INSTRUCTION(name, super)     \
164   void Visit##name(H##name* instr);
165 
FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)166   FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
167 
168 #undef DECLARE_VISIT_INSTRUCTION
169 
170   ArmAssembler* GetAssembler() const { return assembler_; }
171 
172  private:
173   // Generate code for the given suspend check. If not null, `successor`
174   // is the block to branch to if the suspend check is not needed, and after
175   // the suspend call.
176   void GenerateSuspendCheck(HSuspendCheck* check, HBasicBlock* successor);
177   void GenerateClassInitializationCheck(SlowPathCodeARM* slow_path, Register class_reg);
178   void HandleBitwiseOperation(HBinaryOperation* operation);
179   void HandleShift(HBinaryOperation* operation);
180   void GenerateMemoryBarrier(MemBarrierKind kind);
181   void GenerateWideAtomicStore(Register addr, uint32_t offset,
182                                Register value_lo, Register value_hi,
183                                Register temp1, Register temp2,
184                                HInstruction* instruction);
185   void GenerateWideAtomicLoad(Register addr, uint32_t offset,
186                               Register out_lo, Register out_hi);
187   void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info);
188   void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info);
189   void GenerateImplicitNullCheck(HNullCheck* instruction);
190   void GenerateExplicitNullCheck(HNullCheck* instruction);
191   void GenerateTestAndBranch(HInstruction* instruction,
192                              Label* true_target,
193                              Label* false_target,
194                              Label* always_true_target);
195 
196   ArmAssembler* const assembler_;
197   CodeGeneratorARM* const codegen_;
198 
199   DISALLOW_COPY_AND_ASSIGN(InstructionCodeGeneratorARM);
200 };
201 
202 class CodeGeneratorARM : public CodeGenerator {
203  public:
204   CodeGeneratorARM(HGraph* graph,
205                    const ArmInstructionSetFeatures& isa_features,
206                    const CompilerOptions& compiler_options);
~CodeGeneratorARM()207   virtual ~CodeGeneratorARM() {}
208 
209   void GenerateFrameEntry() OVERRIDE;
210   void GenerateFrameExit() OVERRIDE;
211   void Bind(HBasicBlock* block) OVERRIDE;
212   void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE;
213   size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
214   size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
215   size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
216   size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
217 
GetWordSize()218   size_t GetWordSize() const OVERRIDE {
219     return kArmWordSize;
220   }
221 
GetFloatingPointSpillSlotSize()222   size_t GetFloatingPointSpillSlotSize() const OVERRIDE {
223     // Allocated in S registers, which are word sized.
224     return kArmWordSize;
225   }
226 
GetLocationBuilder()227   HGraphVisitor* GetLocationBuilder() OVERRIDE {
228     return &location_builder_;
229   }
230 
GetInstructionVisitor()231   HGraphVisitor* GetInstructionVisitor() OVERRIDE {
232     return &instruction_visitor_;
233   }
234 
GetAssembler()235   ArmAssembler* GetAssembler() OVERRIDE {
236     return &assembler_;
237   }
238 
GetAddressOf(HBasicBlock * block)239   uintptr_t GetAddressOf(HBasicBlock* block) const OVERRIDE {
240     return GetLabelOf(block)->Position();
241   }
242 
243   void SetupBlockedRegisters(bool is_baseline) const OVERRIDE;
244 
245   Location AllocateFreeRegister(Primitive::Type type) const OVERRIDE;
246 
247   Location GetStackLocation(HLoadLocal* load) const OVERRIDE;
248 
249   void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE;
250   void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE;
251 
252   // Blocks all register pairs made out of blocked core registers.
253   void UpdateBlockedPairRegisters() const;
254 
GetMoveResolver()255   ParallelMoveResolverARM* GetMoveResolver() OVERRIDE {
256     return &move_resolver_;
257   }
258 
GetInstructionSet()259   InstructionSet GetInstructionSet() const OVERRIDE {
260     return InstructionSet::kThumb2;
261   }
262 
263   // Helper method to move a 32bits value between two locations.
264   void Move32(Location destination, Location source);
265   // Helper method to move a 64bits value between two locations.
266   void Move64(Location destination, Location source);
267 
268   // Load current method into `reg`.
269   void LoadCurrentMethod(Register reg);
270 
271   // Generate code to invoke a runtime entry point.
272   void InvokeRuntime(
273       int32_t offset, HInstruction* instruction, uint32_t dex_pc, SlowPathCode* slow_path);
274 
275   // Emit a write barrier.
276   void MarkGCCard(Register temp, Register card, Register object, Register value);
277 
GetLabelOf(HBasicBlock * block)278   Label* GetLabelOf(HBasicBlock* block) const {
279     return CommonGetLabelOf<Label>(block_labels_.GetRawStorage(), block);
280   }
281 
Initialize()282   void Initialize() OVERRIDE {
283     block_labels_.SetSize(GetGraph()->GetBlocks().Size());
284   }
285 
GetInstructionSetFeatures()286   const ArmInstructionSetFeatures& GetInstructionSetFeatures() const {
287     return isa_features_;
288   }
289 
NeedsTwoRegisters(Primitive::Type type)290   bool NeedsTwoRegisters(Primitive::Type type) const OVERRIDE {
291     return type == Primitive::kPrimDouble || type == Primitive::kPrimLong;
292   }
293 
294   void ComputeSpillMask() OVERRIDE;
295 
GetFrameEntryLabel()296   Label* GetFrameEntryLabel() { return &frame_entry_label_; }
297 
298   void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Register temp);
299 
300  private:
301   // Labels for each block that will be compiled.
302   GrowableArray<Label> block_labels_;
303   Label frame_entry_label_;
304   LocationsBuilderARM location_builder_;
305   InstructionCodeGeneratorARM instruction_visitor_;
306   ParallelMoveResolverARM move_resolver_;
307   Thumb2Assembler assembler_;
308   const ArmInstructionSetFeatures& isa_features_;
309 
310   DISALLOW_COPY_AND_ASSIGN(CodeGeneratorARM);
311 };
312 
313 }  // namespace arm
314 }  // namespace art
315 
316 #endif  // ART_COMPILER_OPTIMIZING_CODE_GENERATOR_ARM_H_
317