blob: 56342aa684924aee5d36989e6960e261080a2e7f [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#include "code_generator.h"
18
19#include "code_generator_arm.h"
20#include "code_generator_x86.h"
21#include "utils/assembler.h"
22#include "utils/arm/assembler_arm.h"
23#include "utils/mips/assembler_mips.h"
24#include "utils/x86/assembler_x86.h"
25
26namespace art {
27
28void CodeGenerator::Compile(CodeAllocator* allocator) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000029 const GrowableArray<HBasicBlock*>* blocks = graph()->blocks();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +000030 DCHECK(blocks->Get(0) == graph()->entry_block());
31 DCHECK(GoesToNextBlock(graph()->entry_block(), blocks->Get(1)));
32 CompileEntryBlock();
33 for (size_t i = 1; i < blocks->Size(); i++) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000034 CompileBlock(blocks->Get(i));
35 }
36 size_t code_size = assembler_->CodeSize();
37 uint8_t* buffer = allocator->Allocate(code_size);
38 MemoryRegion code(buffer, code_size);
39 assembler_->FinalizeInstructions(code);
40}
41
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +000042void CodeGenerator::CompileEntryBlock() {
43 HGraphVisitor* location_builder = GetLocationBuilder();
44 // The entry block contains all locals for this method. By visiting the entry block,
45 // we're computing the required frame size.
46 for (HInstructionIterator it(graph()->entry_block()); !it.Done(); it.Advance()) {
47 HInstruction* current = it.Current();
48 // Instructions in the entry block should not generate code.
49 if (kIsDebugBuild) {
50 current->Accept(location_builder);
51 DCHECK(current->locations() == nullptr);
52 }
53 current->Accept(this);
54 }
55 GenerateFrameEntry();
56}
57
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000058void CodeGenerator::CompileBlock(HBasicBlock* block) {
59 Bind(GetLabelOf(block));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +000060 HGraphVisitor* location_builder = GetLocationBuilder();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000061 for (HInstructionIterator it(block); !it.Done(); it.Advance()) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +000062 // For each instruction, we emulate a stack-based machine, where the inputs are popped from
63 // the runtime stack, and the result is pushed on the stack. We currently can do this because
64 // we do not perform any code motion, and the Dex format does not reference individual
65 // instructions but uses registers instead (our equivalent of HLocal).
66 HInstruction* current = it.Current();
67 current->Accept(location_builder);
68 InitLocations(current);
69 current->Accept(this);
70 if (current->locations() != nullptr && current->locations()->Out().IsValid()) {
71 Push(current, current->locations()->Out());
72 }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000073 }
74}
75
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +000076void CodeGenerator::InitLocations(HInstruction* instruction) {
77 if (instruction->locations() == nullptr) return;
78 for (int i = 0; i < instruction->InputCount(); i++) {
79 Location location = instruction->locations()->InAt(i);
80 if (location.IsValid()) {
81 // Move the input to the desired location.
82 Move(instruction->InputAt(i), location);
83 }
84 }
85}
86
87bool CodeGenerator::GoesToNextBlock(HBasicBlock* current, HBasicBlock* next) const {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000088 // We currently iterate over the block in insertion order.
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +000089 return current->block_id() + 1 == next->block_id();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000090}
91
92Label* CodeGenerator::GetLabelOf(HBasicBlock* block) const {
93 return block_labels_.GetRawStorage() + block->block_id();
94}
95
96bool CodeGenerator::CompileGraph(HGraph* graph,
97 InstructionSet instruction_set,
98 CodeAllocator* allocator) {
99 switch (instruction_set) {
100 case kArm:
101 case kThumb2: {
102 arm::ArmAssembler assembler;
103 arm::CodeGeneratorARM(&assembler, graph).Compile(allocator);
104 return true;
105 }
106 case kMips:
107 return false;
108 case kX86: {
109 x86::X86Assembler assembler;
110 x86::CodeGeneratorX86(&assembler, graph).Compile(allocator);
111 return true;
112 }
113 default:
114 return false;
115 }
116}
117
118} // namespace art