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
27namespace art {
28namespace arm {
29
30class CodeGeneratorARM;
31class SlowPathCodeARM;
32
33// Use a local definition to prevent copying mistakes.
34static constexpr size_t kArmWordSize = kArmPointerSize;
35static constexpr size_t kArmBitsPerWord = kArmWordSize * kBitsPerByte;
36
37static constexpr Register kParameterCoreRegisters[] = { R1, R2, R3 };
38static constexpr size_t kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters);
39static constexpr SRegister kParameterFpuRegisters[] =
40    { S0, S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11, S12, S13, S14, S15 };
41static constexpr size_t kParameterFpuRegistersLength = arraysize(kParameterFpuRegisters);
42
43static constexpr Register kArtMethodRegister = R0;
44
45static constexpr Register kRuntimeParameterCoreRegisters[] = { R0, R1, R2, R3 };
46static constexpr size_t kRuntimeParameterCoreRegistersLength =
47    arraysize(kRuntimeParameterCoreRegisters);
48static constexpr SRegister kRuntimeParameterFpuRegisters[] = { S0, S1, S2, S3 };
49static constexpr size_t kRuntimeParameterFpuRegistersLength =
50    arraysize(kRuntimeParameterFpuRegisters);
51
52class InvokeRuntimeCallingConvention : public CallingConvention<Register, SRegister> {
53 public:
54  InvokeRuntimeCallingConvention()
55      : CallingConvention(kRuntimeParameterCoreRegisters,
56                          kRuntimeParameterCoreRegistersLength,
57                          kRuntimeParameterFpuRegisters,
58                          kRuntimeParameterFpuRegistersLength,
59                          kArmPointerSize) {}
60
61 private:
62  DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
63};
64
65static constexpr DRegister FromLowSToD(SRegister reg) {
66  return DCHECK_CONSTEXPR(reg % 2 == 0, , D0)
67      static_cast<DRegister>(reg / 2);
68}
69
70
71class InvokeDexCallingConvention : public CallingConvention<Register, SRegister> {
72 public:
73  InvokeDexCallingConvention()
74      : CallingConvention(kParameterCoreRegisters,
75                          kParameterCoreRegistersLength,
76                          kParameterFpuRegisters,
77                          kParameterFpuRegistersLength,
78                          kArmPointerSize) {}
79
80 private:
81  DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConvention);
82};
83
84class InvokeDexCallingConventionVisitorARM : public InvokeDexCallingConventionVisitor {
85 public:
86  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
99class ParallelMoveResolverARM : public ParallelMoveResolverWithSwap {
100 public:
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
120class SlowPathCodeARM : public SlowPathCode {
121 public:
122  SlowPathCodeARM() : entry_label_(), exit_label_() {}
123
124  Label* GetEntryLabel() { return &entry_label_; }
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
134class LocationsBuilderARM : public HGraphVisitor {
135 public:
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
159class 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
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
202class CodeGeneratorARM : public CodeGenerator {
203 public:
204  CodeGeneratorARM(HGraph* graph,
205                   const ArmInstructionSetFeatures& isa_features,
206                   const CompilerOptions& compiler_options);
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
218  size_t GetWordSize() const OVERRIDE {
219    return kArmWordSize;
220  }
221
222  size_t GetFloatingPointSpillSlotSize() const OVERRIDE {
223    // Allocated in S registers, which are word sized.
224    return kArmWordSize;
225  }
226
227  HGraphVisitor* GetLocationBuilder() OVERRIDE {
228    return &location_builder_;
229  }
230
231  HGraphVisitor* GetInstructionVisitor() OVERRIDE {
232    return &instruction_visitor_;
233  }
234
235  ArmAssembler* GetAssembler() OVERRIDE {
236    return &assembler_;
237  }
238
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
255  ParallelMoveResolverARM* GetMoveResolver() OVERRIDE {
256    return &move_resolver_;
257  }
258
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
278  Label* GetLabelOf(HBasicBlock* block) const {
279    return CommonGetLabelOf<Label>(block_labels_.GetRawStorage(), block);
280  }
281
282  void Initialize() OVERRIDE {
283    block_labels_.SetSize(GetGraph()->GetBlocks().Size());
284  }
285
286  const ArmInstructionSetFeatures& GetInstructionSetFeatures() const {
287    return isa_features_;
288  }
289
290  bool NeedsTwoRegisters(Primitive::Type type) const OVERRIDE {
291    return type == Primitive::kPrimDouble || type == Primitive::kPrimLong;
292  }
293
294  void ComputeSpillMask() OVERRIDE;
295
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