code_generator.h revision c32e770f21540e4e9eda6dc7f770e745d33f1b9f
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_H_
18#define ART_COMPILER_OPTIMIZING_CODE_GENERATOR_H_
19
20#include "base/bit_field.h"
21#include "globals.h"
22#include "instruction_set.h"
23#include "memory_region.h"
24#include "nodes.h"
25#include "utils/assembler.h"
26
27namespace art {
28
29static size_t constexpr kVRegSize = 4;
30
31class DexCompilationUnit;
32
33class CodeAllocator {
34 public:
35  CodeAllocator() { }
36  virtual ~CodeAllocator() { }
37
38  virtual uint8_t* Allocate(size_t size) = 0;
39
40 private:
41  DISALLOW_COPY_AND_ASSIGN(CodeAllocator);
42};
43
44struct PcInfo {
45  uint32_t dex_pc;
46  uintptr_t native_pc;
47};
48
49/**
50 * A Location is an abstraction over the potential location
51 * of an instruction. It could be in register or stack.
52 */
53class Location : public ValueObject {
54 public:
55  enum Kind {
56    kInvalid = 0,
57    kStackSlot = 1,  // Word size slot.
58    kDoubleStackSlot = 2,  // 64bit stack slot.
59    kRegister = 3,
60    // On 32bits architectures, quick can pass a long where the
61    // low bits are in the last parameter register, and the high
62    // bits are in a stack slot. The kQuickParameter kind is for
63    // handling this special case.
64    kQuickParameter = 4,
65  };
66
67  Location() : value_(kInvalid) {
68    DCHECK(!IsValid());
69  }
70
71  Location(const Location& other) : ValueObject(), value_(other.value_) {}
72
73  Location& operator=(const Location& other) {
74    value_ = other.value_;
75    return *this;
76  }
77
78  bool IsValid() const {
79    return value_ != kInvalid;
80  }
81
82  // Register locations.
83  static Location RegisterLocation(ManagedRegister reg) {
84    return Location(kRegister, reg.RegId());
85  }
86
87  bool IsRegister() const {
88    return GetKind() == kRegister;
89  }
90
91  ManagedRegister reg() const {
92    DCHECK(IsRegister());
93    return static_cast<ManagedRegister>(GetPayload());
94  }
95
96  static uword EncodeStackIndex(intptr_t stack_index) {
97    DCHECK(-kStackIndexBias <= stack_index);
98    DCHECK(stack_index < kStackIndexBias);
99    return static_cast<uword>(kStackIndexBias + stack_index);
100  }
101
102  static Location StackSlot(intptr_t stack_index) {
103    uword payload = EncodeStackIndex(stack_index);
104    Location loc(kStackSlot, payload);
105    // Ensure that sign is preserved.
106    DCHECK_EQ(loc.GetStackIndex(), stack_index);
107    return loc;
108  }
109
110  bool IsStackSlot() const {
111    return GetKind() == kStackSlot;
112  }
113
114  static Location DoubleStackSlot(intptr_t stack_index) {
115    uword payload = EncodeStackIndex(stack_index);
116    Location loc(kDoubleStackSlot, payload);
117    // Ensure that sign is preserved.
118    DCHECK_EQ(loc.GetStackIndex(), stack_index);
119    return loc;
120  }
121
122  bool IsDoubleStackSlot() const {
123    return GetKind() == kDoubleStackSlot;
124  }
125
126  intptr_t GetStackIndex() const {
127    DCHECK(IsStackSlot() || IsDoubleStackSlot());
128    // Decode stack index manually to preserve sign.
129    return GetPayload() - kStackIndexBias;
130  }
131
132  intptr_t GetHighStackIndex(uintptr_t word_size) const {
133    DCHECK(IsDoubleStackSlot());
134    // Decode stack index manually to preserve sign.
135    return GetPayload() - kStackIndexBias + word_size;
136  }
137
138  static Location QuickParameter(uint32_t parameter_index) {
139    return Location(kQuickParameter, parameter_index);
140  }
141
142  uint32_t GetQuickParameterIndex() const {
143    DCHECK(IsQuickParameter());
144    return GetPayload();
145  }
146
147  bool IsQuickParameter() const {
148    return GetKind() == kQuickParameter;
149  }
150
151  arm::ArmManagedRegister AsArm() const;
152  x86::X86ManagedRegister AsX86() const;
153
154  Kind GetKind() const {
155    return KindField::Decode(value_);
156  }
157
158  bool Equals(Location other) const {
159    return value_ == other.value_;
160  }
161
162  const char* DebugString() const {
163    switch (GetKind()) {
164      case kInvalid: return "?";
165      case kRegister: return "R";
166      case kStackSlot: return "S";
167      case kDoubleStackSlot: return "DS";
168      case kQuickParameter: return "Q";
169    }
170    return "?";
171  }
172
173 private:
174  // Number of bits required to encode Kind value.
175  static constexpr uint32_t kBitsForKind = 4;
176  static constexpr uint32_t kBitsForPayload = kWordSize * kBitsPerByte - kBitsForKind;
177
178  explicit Location(uword value) : value_(value) {}
179
180  Location(Kind kind, uword payload)
181      : value_(KindField::Encode(kind) | PayloadField::Encode(payload)) {}
182
183  uword GetPayload() const {
184    return PayloadField::Decode(value_);
185  }
186
187  typedef BitField<Kind, 0, kBitsForKind> KindField;
188  typedef BitField<uword, kBitsForKind, kBitsForPayload> PayloadField;
189
190  // Layout for stack slots.
191  static const intptr_t kStackIndexBias =
192      static_cast<intptr_t>(1) << (kBitsForPayload - 1);
193
194  // Location either contains kind and payload fields or a tagged handle for
195  // a constant locations. Values of enumeration Kind are selected in such a
196  // way that none of them can be interpreted as a kConstant tag.
197  uword value_;
198};
199
200/**
201 * The code generator computes LocationSummary for each instruction so that
202 * the instruction itself knows what code to generate: where to find the inputs
203 * and where to place the result.
204 *
205 * The intent is to have the code for generating the instruction independent of
206 * register allocation. A register allocator just has to provide a LocationSummary.
207 */
208class LocationSummary : public ArenaObject {
209 public:
210  explicit LocationSummary(HInstruction* instruction)
211      : inputs(instruction->GetBlock()->GetGraph()->GetArena(), instruction->InputCount()),
212        temps(instruction->GetBlock()->GetGraph()->GetArena(), 0) {
213    inputs.SetSize(instruction->InputCount());
214    for (size_t i = 0; i < instruction->InputCount(); i++) {
215      inputs.Put(i, Location());
216    }
217  }
218
219  void SetInAt(uint32_t at, Location location) {
220    inputs.Put(at, location);
221  }
222
223  Location InAt(uint32_t at) const {
224    return inputs.Get(at);
225  }
226
227  void SetOut(Location location) {
228    output = Location(location);
229  }
230
231  void AddTemp(Location location) {
232    temps.Add(location);
233  }
234
235  Location GetTemp(uint32_t at) const {
236    return temps.Get(at);
237  }
238
239  Location Out() const { return output; }
240
241 private:
242  GrowableArray<Location> inputs;
243  GrowableArray<Location> temps;
244  Location output;
245
246  DISALLOW_COPY_AND_ASSIGN(LocationSummary);
247};
248
249class CodeGenerator : public ArenaObject {
250 public:
251  // Compiles the graph to executable instructions. Returns whether the compilation
252  // succeeded.
253  void Compile(CodeAllocator* allocator);
254  static CodeGenerator* Create(ArenaAllocator* allocator,
255                               HGraph* graph,
256                               InstructionSet instruction_set);
257
258  HGraph* GetGraph() const { return graph_; }
259
260  Label* GetLabelOf(HBasicBlock* block) const;
261  bool GoesToNextBlock(HBasicBlock* current, HBasicBlock* next) const;
262
263  virtual void GenerateFrameEntry() = 0;
264  virtual void GenerateFrameExit() = 0;
265  virtual void Bind(Label* label) = 0;
266  virtual void Move(HInstruction* instruction, Location location, HInstruction* move_for) = 0;
267  virtual HGraphVisitor* GetLocationBuilder() = 0;
268  virtual HGraphVisitor* GetInstructionVisitor() = 0;
269  virtual Assembler* GetAssembler() = 0;
270  virtual size_t GetWordSize() const = 0;
271
272  uint32_t GetFrameSize() const { return frame_size_; }
273  void SetFrameSize(uint32_t size) { frame_size_ = size; }
274  uint32_t GetCoreSpillMask() const { return core_spill_mask_; }
275
276  void RecordPcInfo(uint32_t dex_pc) {
277    struct PcInfo pc_info;
278    pc_info.dex_pc = dex_pc;
279    pc_info.native_pc = GetAssembler()->CodeSize();
280    pc_infos_.Add(pc_info);
281  }
282
283  void BuildMappingTable(std::vector<uint8_t>* vector) const;
284  void BuildVMapTable(std::vector<uint8_t>* vector) const;
285  void BuildNativeGCMap(
286      std::vector<uint8_t>* vector, const DexCompilationUnit& dex_compilation_unit) const;
287
288 protected:
289  explicit CodeGenerator(HGraph* graph)
290      : frame_size_(0),
291        graph_(graph),
292        block_labels_(graph->GetArena(), 0),
293        pc_infos_(graph->GetArena(), 32) {
294    block_labels_.SetSize(graph->GetBlocks()->Size());
295  }
296  ~CodeGenerator() { }
297
298  // Frame size required for this method.
299  uint32_t frame_size_;
300  uint32_t core_spill_mask_;
301
302 private:
303  void InitLocations(HInstruction* instruction);
304  void CompileBlock(HBasicBlock* block);
305
306  HGraph* const graph_;
307
308  // Labels for each block that will be compiled.
309  GrowableArray<Label> block_labels_;
310  GrowableArray<PcInfo> pc_infos_;
311
312  DISALLOW_COPY_AND_ASSIGN(CodeGenerator);
313};
314
315template <typename T>
316class CallingConvention {
317 public:
318  CallingConvention(const T* registers, int number_of_registers)
319      : registers_(registers), number_of_registers_(number_of_registers) {}
320
321  size_t GetNumberOfRegisters() const { return number_of_registers_; }
322
323  T GetRegisterAt(size_t index) const {
324    DCHECK_LT(index, number_of_registers_);
325    return registers_[index];
326  }
327
328  uint8_t GetStackOffsetOf(size_t index, size_t word_size) const {
329    // We still reserve the space for parameters passed by registers.
330    // Add word_size for the method pointer.
331    return index * kVRegSize + word_size;
332  }
333
334 private:
335  const T* registers_;
336  const size_t number_of_registers_;
337
338  DISALLOW_COPY_AND_ASSIGN(CallingConvention);
339};
340
341}  // namespace art
342
343#endif  // ART_COMPILER_OPTIMIZING_CODE_GENERATOR_H_
344