code_generator_arm.cc revision 4a34a428c6a2588e0857ef6baf88f1b73ce65958
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#include "code_generator_arm.h" 18#include "utils/assembler.h" 19#include "utils/arm/assembler_arm.h" 20 21#include "mirror/array.h" 22#include "mirror/art_method.h" 23 24#define __ reinterpret_cast<ArmAssembler*>(GetAssembler())-> 25 26namespace art { 27namespace arm { 28 29static constexpr int kNumberOfPushedRegistersAtEntry = 1; 30static constexpr int kCurrentMethodStackOffset = 0; 31 32InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen) 33 : HGraphVisitor(graph), 34 assembler_(codegen->GetAssembler()), 35 codegen_(codegen) {} 36 37void CodeGeneratorARM::GenerateFrameEntry() { 38 core_spill_mask_ |= (1 << LR); 39 __ PushList((1 << LR)); 40 41 // Add the current ART method to the frame size and the return PC. 42 SetFrameSize(RoundUp(GetFrameSize() + 2 * kWordSize, kStackAlignment)); 43 // The retrn PC has already been pushed on the stack. 44 __ AddConstant(SP, -(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kWordSize)); 45 __ str(R0, Address(SP, 0)); 46} 47 48void CodeGeneratorARM::GenerateFrameExit() { 49 __ AddConstant(SP, GetFrameSize() - kNumberOfPushedRegistersAtEntry * kWordSize); 50 __ PopList((1 << PC)); 51} 52 53void CodeGeneratorARM::Bind(Label* label) { 54 __ Bind(label); 55} 56 57int32_t CodeGeneratorARM::GetStackSlot(HLocal* local) const { 58 return (GetGraph()->GetMaximumNumberOfOutVRegs() + local->GetRegNumber()) * kWordSize; 59} 60 61void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) { 62 if (instruction->AsIntConstant() != nullptr) { 63 __ LoadImmediate(location.reg<Register>(), instruction->AsIntConstant()->GetValue()); 64 } else if (instruction->AsLoadLocal() != nullptr) { 65 __ LoadFromOffset(kLoadWord, location.reg<Register>(), 66 SP, GetStackSlot(instruction->AsLoadLocal()->GetLocal())); 67 } else { 68 // This can currently only happen when the instruction that requests the move 69 // is the next to be compiled. 70 DCHECK_EQ(instruction->GetNext(), move_for); 71 __ mov(location.reg<Register>(), 72 ShifterOperand(instruction->GetLocations()->Out().reg<Register>())); 73 } 74} 75 76void LocationsBuilderARM::VisitGoto(HGoto* got) { 77 got->SetLocations(nullptr); 78} 79 80void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) { 81 HBasicBlock* successor = got->GetSuccessor(); 82 if (GetGraph()->GetExitBlock() == successor) { 83 codegen_->GenerateFrameExit(); 84 } else if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) { 85 __ b(codegen_->GetLabelOf(successor)); 86 } 87} 88 89void LocationsBuilderARM::VisitExit(HExit* exit) { 90 exit->SetLocations(nullptr); 91} 92 93void InstructionCodeGeneratorARM::VisitExit(HExit* exit) { 94 if (kIsDebugBuild) { 95 __ Comment("Unreachable"); 96 __ bkpt(0); 97 } 98} 99 100void LocationsBuilderARM::VisitIf(HIf* if_instr) { 101 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr); 102 locations->SetInAt(0, Location(R0)); 103 if_instr->SetLocations(locations); 104} 105 106void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) { 107 // TODO: Generate the input as a condition, instead of materializing in a register. 108 __ cmp(if_instr->GetLocations()->InAt(0).reg<Register>(), ShifterOperand(0)); 109 __ b(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()), EQ); 110 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfTrueSuccessor())) { 111 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor())); 112 } 113} 114 115void LocationsBuilderARM::VisitEqual(HEqual* equal) { 116 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(equal); 117 locations->SetInAt(0, Location(R0)); 118 locations->SetInAt(1, Location(R1)); 119 locations->SetOut(Location(R0)); 120 equal->SetLocations(locations); 121} 122 123void InstructionCodeGeneratorARM::VisitEqual(HEqual* equal) { 124 LocationSummary* locations = equal->GetLocations(); 125 __ teq(locations->InAt(0).reg<Register>(), 126 ShifterOperand(locations->InAt(1).reg<Register>())); 127 __ mov(locations->Out().reg<Register>(), ShifterOperand(1), EQ); 128 __ mov(locations->Out().reg<Register>(), ShifterOperand(0), NE); 129} 130 131void LocationsBuilderARM::VisitLocal(HLocal* local) { 132 local->SetLocations(nullptr); 133} 134 135void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) { 136 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock()); 137 codegen_->SetFrameSize(codegen_->GetFrameSize() + kWordSize); 138} 139 140void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) { 141 load->SetLocations(nullptr); 142} 143 144void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) { 145 // Nothing to do, this is driven by the code generator. 146} 147 148void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) { 149 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(store); 150 locations->SetInAt(1, Location(R0)); 151 store->SetLocations(locations); 152} 153 154void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) { 155 LocationSummary* locations = store->GetLocations(); 156 __ StoreToOffset(kStoreWord, locations->InAt(1).reg<Register>(), 157 SP, codegen_->GetStackSlot(store->GetLocal())); 158} 159 160void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) { 161 constant->SetLocations(nullptr); 162} 163 164void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) { 165 // Will be generated at use site. 166} 167 168void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) { 169 ret->SetLocations(nullptr); 170} 171 172void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) { 173 codegen_->GenerateFrameExit(); 174} 175 176void LocationsBuilderARM::VisitReturn(HReturn* ret) { 177 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(ret); 178 locations->SetInAt(0, Location(R0)); 179 ret->SetLocations(locations); 180} 181 182void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) { 183 DCHECK_EQ(ret->GetLocations()->InAt(0).reg<Register>(), R0); 184 codegen_->GenerateFrameExit(); 185} 186 187static constexpr Register kParameterCoreRegisters[] = { R1, R2, R3 }; 188static constexpr int kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters); 189 190class InvokeStaticCallingConvention : public CallingConvention<Register> { 191 public: 192 InvokeStaticCallingConvention() 193 : CallingConvention(kParameterCoreRegisters, kParameterCoreRegistersLength) {} 194 195 private: 196 DISALLOW_COPY_AND_ASSIGN(InvokeStaticCallingConvention); 197}; 198 199void LocationsBuilderARM::VisitPushArgument(HPushArgument* argument) { 200 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(argument); 201 InvokeStaticCallingConvention calling_convention; 202 if (argument->GetArgumentIndex() < calling_convention.GetNumberOfRegisters()) { 203 Location location = Location(calling_convention.GetRegisterAt(argument->GetArgumentIndex())); 204 locations->SetInAt(0, location); 205 locations->SetOut(location); 206 } else { 207 locations->SetInAt(0, Location(R0)); 208 } 209 argument->SetLocations(locations); 210} 211 212void InstructionCodeGeneratorARM::VisitPushArgument(HPushArgument* argument) { 213 uint8_t argument_index = argument->GetArgumentIndex(); 214 InvokeStaticCallingConvention calling_convention; 215 size_t parameter_registers = calling_convention.GetNumberOfRegisters(); 216 LocationSummary* locations = argument->GetLocations(); 217 if (argument_index >= parameter_registers) { 218 uint8_t offset = calling_convention.GetStackOffsetOf(argument_index); 219 __ StoreToOffset(kStoreWord, locations->InAt(0).reg<Register>(), SP, offset); 220 } else { 221 DCHECK_EQ(locations->Out().reg<Register>(), locations->InAt(0).reg<Register>()); 222 } 223} 224 225void LocationsBuilderARM::VisitInvokeStatic(HInvokeStatic* invoke) { 226 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(invoke); 227 locations->AddTemp(Location(R0)); 228 invoke->SetLocations(locations); 229} 230 231void InstructionCodeGeneratorARM::LoadCurrentMethod(Register reg) { 232 __ ldr(reg, Address(SP, kCurrentMethodStackOffset)); 233} 234 235void InstructionCodeGeneratorARM::VisitInvokeStatic(HInvokeStatic* invoke) { 236 Register temp = invoke->GetLocations()->GetTemp(0).reg<Register>(); 237 size_t index_in_cache = mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() + 238 invoke->GetIndexInDexCache() * kWordSize; 239 240 // TODO: Implement all kinds of calls: 241 // 1) boot -> boot 242 // 2) app -> boot 243 // 3) app -> app 244 // 245 // Currently we implement the app -> app logic, which looks up in the resolve cache. 246 247 // temp = method; 248 LoadCurrentMethod(temp); 249 // temp = temp->dex_cache_resolved_methods_; 250 __ ldr(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value())); 251 // temp = temp[index_in_cache] 252 __ ldr(temp, Address(temp, index_in_cache)); 253 // LR = temp[offset_of_quick_compiled_code] 254 __ ldr(LR, Address(temp, 255 mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value())); 256 // LR() 257 __ blx(LR); 258 259 codegen_->RecordPcInfo(invoke->GetDexPc()); 260} 261 262void LocationsBuilderARM::VisitAdd(HAdd* add) { 263 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(add); 264 switch (add->GetResultType()) { 265 case Primitive::kPrimInt: { 266 locations->SetInAt(0, Location(R0)); 267 locations->SetInAt(1, Location(R1)); 268 locations->SetOut(Location(R0)); 269 break; 270 } 271 default: 272 LOG(FATAL) << "Unimplemented"; 273 } 274 add->SetLocations(locations); 275} 276 277void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) { 278 LocationSummary* locations = add->GetLocations(); 279 switch (add->GetResultType()) { 280 case Primitive::kPrimInt: 281 __ add(locations->Out().reg<Register>(), 282 locations->InAt(0).reg<Register>(), 283 ShifterOperand(locations->InAt(1).reg<Register>())); 284 break; 285 default: 286 LOG(FATAL) << "Unimplemented"; 287 } 288} 289 290} // namespace arm 291} // namespace art 292