/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ART_COMPILER_OPTIMIZING_CODE_GENERATOR_H_ #define ART_COMPILER_OPTIMIZING_CODE_GENERATOR_H_ #include "base/bit_field.h" #include "globals.h" #include "instruction_set.h" #include "memory_region.h" #include "nodes.h" #include "utils/assembler.h" namespace art { static size_t constexpr kVRegSize = 4; class DexCompilationUnit; class CodeAllocator { public: CodeAllocator() { } virtual ~CodeAllocator() { } virtual uint8_t* Allocate(size_t size) = 0; private: DISALLOW_COPY_AND_ASSIGN(CodeAllocator); }; struct PcInfo { uint32_t dex_pc; uintptr_t native_pc; }; /** * A Location is an abstraction over the potential location * of an instruction. It could be in register or stack. */ class Location : public ValueObject { public: enum Kind { kInvalid = 0, kStackSlot = 1, // Word size slot. kDoubleStackSlot = 2, // 64bit stack slot. kRegister = 3, // On 32bits architectures, quick can pass a long where the // low bits are in the last parameter register, and the high // bits are in a stack slot. The kQuickParameter kind is for // handling this special case. kQuickParameter = 4, }; Location() : value_(kInvalid) { DCHECK(!IsValid()); } Location(const Location& other) : ValueObject(), value_(other.value_) {} Location& operator=(const Location& other) { value_ = other.value_; return *this; } bool IsValid() const { return value_ != kInvalid; } // Register locations. static Location RegisterLocation(ManagedRegister reg) { return Location(kRegister, reg.RegId()); } bool IsRegister() const { return GetKind() == kRegister; } ManagedRegister reg() const { DCHECK(IsRegister()); return static_cast(GetPayload()); } static uword EncodeStackIndex(intptr_t stack_index) { DCHECK(-kStackIndexBias <= stack_index); DCHECK(stack_index < kStackIndexBias); return static_cast(kStackIndexBias + stack_index); } static Location StackSlot(intptr_t stack_index) { uword payload = EncodeStackIndex(stack_index); Location loc(kStackSlot, payload); // Ensure that sign is preserved. DCHECK_EQ(loc.GetStackIndex(), stack_index); return loc; } bool IsStackSlot() const { return GetKind() == kStackSlot; } static Location DoubleStackSlot(intptr_t stack_index) { uword payload = EncodeStackIndex(stack_index); Location loc(kDoubleStackSlot, payload); // Ensure that sign is preserved. DCHECK_EQ(loc.GetStackIndex(), stack_index); return loc; } bool IsDoubleStackSlot() const { return GetKind() == kDoubleStackSlot; } intptr_t GetStackIndex() const { DCHECK(IsStackSlot() || IsDoubleStackSlot()); // Decode stack index manually to preserve sign. return GetPayload() - kStackIndexBias; } intptr_t GetHighStackIndex(uintptr_t word_size) const { DCHECK(IsDoubleStackSlot()); // Decode stack index manually to preserve sign. return GetPayload() - kStackIndexBias + word_size; } static Location QuickParameter(uint32_t parameter_index) { return Location(kQuickParameter, parameter_index); } uint32_t GetQuickParameterIndex() const { DCHECK(IsQuickParameter()); return GetPayload(); } bool IsQuickParameter() const { return GetKind() == kQuickParameter; } arm::ArmManagedRegister AsArm() const; x86::X86ManagedRegister AsX86() const; Kind GetKind() const { return KindField::Decode(value_); } bool Equals(Location other) const { return value_ == other.value_; } const char* DebugString() const { switch (GetKind()) { case kInvalid: return "?"; case kRegister: return "R"; case kStackSlot: return "S"; case kDoubleStackSlot: return "DS"; case kQuickParameter: return "Q"; } return "?"; } private: // Number of bits required to encode Kind value. static constexpr uint32_t kBitsForKind = 4; static constexpr uint32_t kBitsForPayload = kWordSize * kBitsPerByte - kBitsForKind; explicit Location(uword value) : value_(value) {} Location(Kind kind, uword payload) : value_(KindField::Encode(kind) | PayloadField::Encode(payload)) {} uword GetPayload() const { return PayloadField::Decode(value_); } typedef BitField KindField; typedef BitField PayloadField; // Layout for stack slots. static const intptr_t kStackIndexBias = static_cast(1) << (kBitsForPayload - 1); // Location either contains kind and payload fields or a tagged handle for // a constant locations. Values of enumeration Kind are selected in such a // way that none of them can be interpreted as a kConstant tag. uword value_; }; /** * The code generator computes LocationSummary for each instruction so that * the instruction itself knows what code to generate: where to find the inputs * and where to place the result. * * The intent is to have the code for generating the instruction independent of * register allocation. A register allocator just has to provide a LocationSummary. */ class LocationSummary : public ArenaObject { public: explicit LocationSummary(HInstruction* instruction) : inputs(instruction->GetBlock()->GetGraph()->GetArena(), instruction->InputCount()), temps(instruction->GetBlock()->GetGraph()->GetArena(), 0) { inputs.SetSize(instruction->InputCount()); for (int i = 0; i < instruction->InputCount(); i++) { inputs.Put(i, Location()); } } void SetInAt(uint32_t at, Location location) { inputs.Put(at, location); } Location InAt(uint32_t at) const { return inputs.Get(at); } void SetOut(Location location) { output = Location(location); } void AddTemp(Location location) { temps.Add(location); } Location GetTemp(uint32_t at) const { return temps.Get(at); } Location Out() const { return output; } private: GrowableArray inputs; GrowableArray temps; Location output; DISALLOW_COPY_AND_ASSIGN(LocationSummary); }; class CodeGenerator : public ArenaObject { public: // Compiles the graph to executable instructions. Returns whether the compilation // succeeded. void Compile(CodeAllocator* allocator); static CodeGenerator* Create(ArenaAllocator* allocator, HGraph* graph, InstructionSet instruction_set); HGraph* GetGraph() const { return graph_; } Label* GetLabelOf(HBasicBlock* block) const; bool GoesToNextBlock(HBasicBlock* current, HBasicBlock* next) const; virtual void GenerateFrameEntry() = 0; virtual void GenerateFrameExit() = 0; virtual void Bind(Label* label) = 0; virtual void Move(HInstruction* instruction, Location location, HInstruction* move_for) = 0; virtual HGraphVisitor* GetLocationBuilder() = 0; virtual HGraphVisitor* GetInstructionVisitor() = 0; virtual Assembler* GetAssembler() = 0; virtual size_t GetWordSize() const = 0; uint32_t GetFrameSize() const { return frame_size_; } void SetFrameSize(uint32_t size) { frame_size_ = size; } uint32_t GetCoreSpillMask() const { return core_spill_mask_; } void RecordPcInfo(uint32_t dex_pc) { struct PcInfo pc_info; pc_info.dex_pc = dex_pc; pc_info.native_pc = GetAssembler()->CodeSize(); pc_infos_.Add(pc_info); } void BuildMappingTable(std::vector* vector) const; void BuildVMapTable(std::vector* vector) const; void BuildNativeGCMap( std::vector* vector, const DexCompilationUnit& dex_compilation_unit) const; protected: explicit CodeGenerator(HGraph* graph) : frame_size_(0), graph_(graph), block_labels_(graph->GetArena(), 0), pc_infos_(graph->GetArena(), 32) { block_labels_.SetSize(graph->GetBlocks()->Size()); } ~CodeGenerator() { } // Frame size required for this method. uint32_t frame_size_; uint32_t core_spill_mask_; private: void InitLocations(HInstruction* instruction); void CompileBlock(HBasicBlock* block); HGraph* const graph_; // Labels for each block that will be compiled. GrowableArray