blob: aafd801eab37712b68313cd06dced803a4ea29f4 [file] [log] [blame]
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001/*
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
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +010020#include "base/bit_field.h"
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +000021#include "globals.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000022#include "instruction_set.h"
23#include "memory_region.h"
24#include "nodes.h"
25#include "utils/assembler.h"
26
27namespace art {
28
Nicolas Geoffraya747a392014-04-17 14:56:23 +010029static size_t constexpr kVRegSize = 4;
30
Nicolas Geoffray92cf83e2014-03-18 17:59:20 +000031class DexCompilationUnit;
32
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000033class 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
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +000044struct PcInfo {
45 uint32_t dex_pc;
46 uintptr_t native_pc;
47};
48
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +000049/**
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:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +010055 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,
Nicolas Geoffraya7aca372014-04-28 17:47:12 +010065
66 // Unallocated location represents a location that is not fixed and can be
67 // allocated by a register allocator. Each unallocated location has
68 // a policy that specifies what kind of location is suitable. Payload
69 // contains register allocation policy.
70 kUnallocated = 5,
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +010071 };
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +000072
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +010073 Location() : value_(kInvalid) {
74 DCHECK(!IsValid());
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +000075 }
76
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +010077 Location(const Location& other) : ValueObject(), value_(other.value_) {}
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +000078
79 Location& operator=(const Location& other) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +010080 value_ = other.value_;
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +000081 return *this;
82 }
83
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +010084 bool IsValid() const {
85 return value_ != kInvalid;
86 }
87
88 // Register locations.
89 static Location RegisterLocation(ManagedRegister reg) {
90 return Location(kRegister, reg.RegId());
91 }
92
93 bool IsRegister() const {
94 return GetKind() == kRegister;
95 }
96
97 ManagedRegister reg() const {
98 DCHECK(IsRegister());
99 return static_cast<ManagedRegister>(GetPayload());
100 }
101
102 static uword EncodeStackIndex(intptr_t stack_index) {
103 DCHECK(-kStackIndexBias <= stack_index);
104 DCHECK(stack_index < kStackIndexBias);
105 return static_cast<uword>(kStackIndexBias + stack_index);
106 }
107
108 static Location StackSlot(intptr_t stack_index) {
109 uword payload = EncodeStackIndex(stack_index);
110 Location loc(kStackSlot, payload);
111 // Ensure that sign is preserved.
112 DCHECK_EQ(loc.GetStackIndex(), stack_index);
113 return loc;
114 }
115
116 bool IsStackSlot() const {
117 return GetKind() == kStackSlot;
118 }
119
120 static Location DoubleStackSlot(intptr_t stack_index) {
121 uword payload = EncodeStackIndex(stack_index);
122 Location loc(kDoubleStackSlot, payload);
123 // Ensure that sign is preserved.
124 DCHECK_EQ(loc.GetStackIndex(), stack_index);
125 return loc;
126 }
127
128 bool IsDoubleStackSlot() const {
129 return GetKind() == kDoubleStackSlot;
130 }
131
132 intptr_t GetStackIndex() const {
133 DCHECK(IsStackSlot() || IsDoubleStackSlot());
134 // Decode stack index manually to preserve sign.
135 return GetPayload() - kStackIndexBias;
136 }
137
138 intptr_t GetHighStackIndex(uintptr_t word_size) const {
139 DCHECK(IsDoubleStackSlot());
140 // Decode stack index manually to preserve sign.
141 return GetPayload() - kStackIndexBias + word_size;
142 }
143
144 static Location QuickParameter(uint32_t parameter_index) {
145 return Location(kQuickParameter, parameter_index);
146 }
147
148 uint32_t GetQuickParameterIndex() const {
149 DCHECK(IsQuickParameter());
150 return GetPayload();
151 }
152
153 bool IsQuickParameter() const {
154 return GetKind() == kQuickParameter;
155 }
156
157 arm::ArmManagedRegister AsArm() const;
158 x86::X86ManagedRegister AsX86() const;
159
160 Kind GetKind() const {
161 return KindField::Decode(value_);
162 }
163
164 bool Equals(Location other) const {
165 return value_ == other.value_;
166 }
167
168 const char* DebugString() const {
169 switch (GetKind()) {
170 case kInvalid: return "?";
171 case kRegister: return "R";
172 case kStackSlot: return "S";
173 case kDoubleStackSlot: return "DS";
174 case kQuickParameter: return "Q";
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100175 case kUnallocated: return "U";
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100176 }
177 return "?";
178 }
179
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100180 // Unallocated locations.
181 enum Policy {
182 kAny,
183 kRequiresRegister,
184 kSameAsFirstInput,
185 };
186
187 bool IsUnallocated() const {
188 return GetKind() == kUnallocated;
189 }
190
191 static Location UnallocatedLocation(Policy policy) {
192 return Location(kUnallocated, PolicyField::Encode(policy));
193 }
194
195 // Any free register is suitable to replace this unallocated location.
196 static Location Any() {
197 return UnallocatedLocation(kAny);
198 }
199
200 static Location RequiresRegister() {
201 return UnallocatedLocation(kRequiresRegister);
202 }
203
204 // The location of the first input to the instruction will be
205 // used to replace this unallocated location.
206 static Location SameAsFirstInput() {
207 return UnallocatedLocation(kSameAsFirstInput);
208 }
209
210 Policy GetPolicy() const {
211 DCHECK(IsUnallocated());
212 return PolicyField::Decode(GetPayload());
213 }
214
215 uword GetEncoding() const {
216 return GetPayload();
217 }
218
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000219 private:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100220 // Number of bits required to encode Kind value.
221 static constexpr uint32_t kBitsForKind = 4;
222 static constexpr uint32_t kBitsForPayload = kWordSize * kBitsPerByte - kBitsForKind;
223
224 explicit Location(uword value) : value_(value) {}
225
226 Location(Kind kind, uword payload)
227 : value_(KindField::Encode(kind) | PayloadField::Encode(payload)) {}
228
229 uword GetPayload() const {
230 return PayloadField::Decode(value_);
231 }
232
233 typedef BitField<Kind, 0, kBitsForKind> KindField;
234 typedef BitField<uword, kBitsForKind, kBitsForPayload> PayloadField;
235
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100236 // Layout for kUnallocated locations payload.
237 typedef BitField<Policy, 0, 3> PolicyField;
238
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100239 // Layout for stack slots.
240 static const intptr_t kStackIndexBias =
241 static_cast<intptr_t>(1) << (kBitsForPayload - 1);
242
243 // Location either contains kind and payload fields or a tagged handle for
244 // a constant locations. Values of enumeration Kind are selected in such a
245 // way that none of them can be interpreted as a kConstant tag.
246 uword value_;
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000247};
248
249/**
250 * The code generator computes LocationSummary for each instruction so that
251 * the instruction itself knows what code to generate: where to find the inputs
252 * and where to place the result.
253 *
254 * The intent is to have the code for generating the instruction independent of
255 * register allocation. A register allocator just has to provide a LocationSummary.
256 */
257class LocationSummary : public ArenaObject {
258 public:
259 explicit LocationSummary(HInstruction* instruction)
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100260 : inputs_(instruction->GetBlock()->GetGraph()->GetArena(), instruction->InputCount()),
261 temps_(instruction->GetBlock()->GetGraph()->GetArena(), 0) {
262 inputs_.SetSize(instruction->InputCount());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100263 for (size_t i = 0; i < instruction->InputCount(); i++) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100264 inputs_.Put(i, Location());
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000265 }
266 }
267
268 void SetInAt(uint32_t at, Location location) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100269 inputs_.Put(at, location);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000270 }
271
272 Location InAt(uint32_t at) const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100273 return inputs_.Get(at);
274 }
275
276 size_t GetInputCount() const {
277 return inputs_.Size();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000278 }
279
280 void SetOut(Location location) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100281 output_ = Location(location);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000282 }
283
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000284 void AddTemp(Location location) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100285 temps_.Add(location);
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000286 }
287
288 Location GetTemp(uint32_t at) const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100289 return temps_.Get(at);
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000290 }
291
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100292 void SetTempAt(uint32_t at, Location location) {
293 temps_.Put(at, location);
294 }
295
296 size_t GetTempCount() const {
297 return temps_.Size();
298 }
299
300 Location Out() const { return output_; }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000301
302 private:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100303 GrowableArray<Location> inputs_;
304 GrowableArray<Location> temps_;
305 Location output_;
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000306
307 DISALLOW_COPY_AND_ASSIGN(LocationSummary);
308};
309
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000310class CodeGenerator : public ArenaObject {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000311 public:
312 // Compiles the graph to executable instructions. Returns whether the compilation
313 // succeeded.
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000314 void Compile(CodeAllocator* allocator);
315 static CodeGenerator* Create(ArenaAllocator* allocator,
316 HGraph* graph,
317 InstructionSet instruction_set);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000318
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000319 HGraph* GetGraph() const { return graph_; }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000320
321 Label* GetLabelOf(HBasicBlock* block) const;
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000322 bool GoesToNextBlock(HBasicBlock* current, HBasicBlock* next) const;
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000323
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000324 virtual void GenerateFrameEntry() = 0;
325 virtual void GenerateFrameExit() = 0;
326 virtual void Bind(Label* label) = 0;
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100327 virtual void Move(HInstruction* instruction, Location location, HInstruction* move_for) = 0;
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000328 virtual HGraphVisitor* GetLocationBuilder() = 0;
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000329 virtual HGraphVisitor* GetInstructionVisitor() = 0;
330 virtual Assembler* GetAssembler() = 0;
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100331 virtual size_t GetWordSize() const = 0;
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000332
333 uint32_t GetFrameSize() const { return frame_size_; }
334 void SetFrameSize(uint32_t size) { frame_size_ = size; }
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000335 uint32_t GetCoreSpillMask() const { return core_spill_mask_; }
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000336
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000337 void RecordPcInfo(uint32_t dex_pc) {
338 struct PcInfo pc_info;
339 pc_info.dex_pc = dex_pc;
340 pc_info.native_pc = GetAssembler()->CodeSize();
341 pc_infos_.Add(pc_info);
342 }
343
344 void BuildMappingTable(std::vector<uint8_t>* vector) const;
345 void BuildVMapTable(std::vector<uint8_t>* vector) const;
Nicolas Geoffray92cf83e2014-03-18 17:59:20 +0000346 void BuildNativeGCMap(
347 std::vector<uint8_t>* vector, const DexCompilationUnit& dex_compilation_unit) const;
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000348
349 protected:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100350 CodeGenerator(HGraph* graph, size_t number_of_registers)
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000351 : frame_size_(0),
352 graph_(graph),
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000353 block_labels_(graph->GetArena(), 0),
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100354 pc_infos_(graph->GetArena(), 32),
355 blocked_registers_(static_cast<bool*>(
356 graph->GetArena()->Alloc(number_of_registers * sizeof(bool), kArenaAllocData))) {
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100357 block_labels_.SetSize(graph->GetBlocks().Size());
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000358 }
359 ~CodeGenerator() { }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000360
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100361 // Register allocation logic.
362 void AllocateRegistersLocally(HInstruction* instruction) const;
363
364 // Backend specific implementation for allocating a register.
365 virtual ManagedRegister AllocateFreeRegister(Primitive::Type type,
366 bool* blocked_registers) const = 0;
367
368 // Raw implementation of allocating a register: loops over blocked_registers to find
369 // the first available register.
370 size_t AllocateFreeRegisterInternal(bool* blocked_registers, size_t number_of_registers) const;
371
372 virtual void SetupBlockedRegisters(bool* blocked_registers) const = 0;
373 virtual size_t GetNumberOfRegisters() const = 0;
374
375 virtual Location GetStackLocation(HLoadLocal* load) const = 0;
376
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000377 // Frame size required for this method.
378 uint32_t frame_size_;
379 uint32_t core_spill_mask_;
380
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000381 private:
382 void InitLocations(HInstruction* instruction);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000383 void CompileBlock(HBasicBlock* block);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000384
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000385 HGraph* const graph_;
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000386
387 // Labels for each block that will be compiled.
388 GrowableArray<Label> block_labels_;
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000389 GrowableArray<PcInfo> pc_infos_;
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000390
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100391 // Temporary data structure used when doing register allocation.
392 bool* const blocked_registers_;
393
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000394 DISALLOW_COPY_AND_ASSIGN(CodeGenerator);
395};
396
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100397template <typename T>
398class CallingConvention {
399 public:
400 CallingConvention(const T* registers, int number_of_registers)
401 : registers_(registers), number_of_registers_(number_of_registers) {}
402
403 size_t GetNumberOfRegisters() const { return number_of_registers_; }
404
405 T GetRegisterAt(size_t index) const {
406 DCHECK_LT(index, number_of_registers_);
407 return registers_[index];
408 }
409
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100410 uint8_t GetStackOffsetOf(size_t index, size_t word_size) const {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100411 // We still reserve the space for parameters passed by registers.
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100412 // Add word_size for the method pointer.
413 return index * kVRegSize + word_size;
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100414 }
415
416 private:
417 const T* registers_;
418 const size_t number_of_registers_;
419
420 DISALLOW_COPY_AND_ASSIGN(CallingConvention);
421};
422
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000423} // namespace art
424
425#endif // ART_COMPILER_OPTIMIZING_CODE_GENERATOR_H_