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