code_generator_x86.cc revision b55f835d66a61e5da6fc1895ba5a0482868c9552
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_x86.h" 18#include "utils/assembler.h" 19#include "utils/x86/assembler_x86.h" 20 21#include "mirror/array.h" 22#include "mirror/art_method.h" 23 24#define __ reinterpret_cast<X86Assembler*>(GetAssembler())-> 25 26namespace art { 27namespace x86 { 28 29static constexpr int kNumberOfPushedRegistersAtEntry = 1; 30static constexpr int kCurrentMethodStackOffset = 0; 31 32InstructionCodeGeneratorX86::InstructionCodeGeneratorX86(HGraph* graph, CodeGeneratorX86* codegen) 33 : HGraphVisitor(graph), 34 assembler_(codegen->GetAssembler()), 35 codegen_(codegen) {} 36 37void CodeGeneratorX86::GenerateFrameEntry() { 38 // Create a fake register to mimic Quick. 39 static const int kFakeReturnRegister = 8; 40 core_spill_mask_ |= (1 << kFakeReturnRegister); 41 42 // Add the current ART method to the frame size, the return PC, and the filler. 43 SetFrameSize(RoundUp(( 44 GetGraph()->GetMaximumNumberOfOutVRegs() + GetGraph()->GetNumberOfVRegs() + 3) * kX86WordSize, 45 kStackAlignment)); 46 // The return PC has already been pushed on the stack. 47 __ subl(ESP, Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86WordSize)); 48 __ movl(Address(ESP, kCurrentMethodStackOffset), EAX); 49} 50 51void CodeGeneratorX86::GenerateFrameExit() { 52 __ addl(ESP, Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86WordSize)); 53} 54 55void CodeGeneratorX86::Bind(Label* label) { 56 __ Bind(label); 57} 58 59void InstructionCodeGeneratorX86::LoadCurrentMethod(Register reg) { 60 __ movl(reg, Address(ESP, kCurrentMethodStackOffset)); 61} 62 63int32_t CodeGeneratorX86::GetStackSlot(HLocal* local) const { 64 uint16_t reg_number = local->GetRegNumber(); 65 uint16_t number_of_vregs = GetGraph()->GetNumberOfVRegs(); 66 uint16_t number_of_in_vregs = GetGraph()->GetNumberOfInVRegs(); 67 if (reg_number >= number_of_vregs - number_of_in_vregs) { 68 // Local is a parameter of the method. It is stored in the caller's frame. 69 return GetFrameSize() + kX86WordSize // ART method 70 + (reg_number - number_of_vregs + number_of_in_vregs) * kX86WordSize; 71 } else { 72 // Local is a temporary in this method. It is stored in this method's frame. 73 return GetFrameSize() - (kNumberOfPushedRegistersAtEntry * kX86WordSize) 74 - kX86WordSize // filler. 75 - (number_of_vregs * kX86WordSize) 76 + (reg_number * kX86WordSize); 77 } 78} 79 80void CodeGeneratorX86::Move(HInstruction* instruction, Location location, HInstruction* move_for) { 81 if (instruction->AsIntConstant() != nullptr) { 82 __ movl(location.reg<Register>(), Immediate(instruction->AsIntConstant()->GetValue())); 83 } else if (instruction->AsLoadLocal() != nullptr) { 84 __ movl(location.reg<Register>(), 85 Address(ESP, GetStackSlot(instruction->AsLoadLocal()->GetLocal()))); 86 } else { 87 // This can currently only happen when the instruction that requests the move 88 // is the next to be compiled. 89 DCHECK_EQ(instruction->GetNext(), move_for); 90 __ movl(location.reg<Register>(), 91 instruction->GetLocations()->Out().reg<Register>()); 92 } 93} 94 95void LocationsBuilderX86::VisitGoto(HGoto* got) { 96 got->SetLocations(nullptr); 97} 98 99void InstructionCodeGeneratorX86::VisitGoto(HGoto* got) { 100 HBasicBlock* successor = got->GetSuccessor(); 101 if (GetGraph()->GetExitBlock() == successor) { 102 codegen_->GenerateFrameExit(); 103 } else if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) { 104 __ jmp(codegen_->GetLabelOf(successor)); 105 } 106} 107 108void LocationsBuilderX86::VisitExit(HExit* exit) { 109 exit->SetLocations(nullptr); 110} 111 112void InstructionCodeGeneratorX86::VisitExit(HExit* exit) { 113 if (kIsDebugBuild) { 114 __ Comment("Unreachable"); 115 __ int3(); 116 } 117} 118 119void LocationsBuilderX86::VisitIf(HIf* if_instr) { 120 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr); 121 locations->SetInAt(0, Location(EAX)); 122 if_instr->SetLocations(locations); 123} 124 125void InstructionCodeGeneratorX86::VisitIf(HIf* if_instr) { 126 // TODO: Generate the input as a condition, instead of materializing in a register. 127 __ cmpl(if_instr->GetLocations()->InAt(0).reg<Register>(), Immediate(0)); 128 __ j(kEqual, codegen_->GetLabelOf(if_instr->IfFalseSuccessor())); 129 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfTrueSuccessor())) { 130 __ jmp(codegen_->GetLabelOf(if_instr->IfTrueSuccessor())); 131 } 132} 133 134void LocationsBuilderX86::VisitLocal(HLocal* local) { 135 local->SetLocations(nullptr); 136} 137 138void InstructionCodeGeneratorX86::VisitLocal(HLocal* local) { 139 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock()); 140} 141 142void LocationsBuilderX86::VisitLoadLocal(HLoadLocal* local) { 143 local->SetLocations(nullptr); 144} 145 146void InstructionCodeGeneratorX86::VisitLoadLocal(HLoadLocal* load) { 147 // Nothing to do, this is driven by the code generator. 148} 149 150void LocationsBuilderX86::VisitStoreLocal(HStoreLocal* local) { 151 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(local); 152 locations->SetInAt(1, Location(EAX)); 153 local->SetLocations(locations); 154} 155 156void InstructionCodeGeneratorX86::VisitStoreLocal(HStoreLocal* store) { 157 __ movl(Address(ESP, codegen_->GetStackSlot(store->GetLocal())), 158 store->GetLocations()->InAt(1).reg<Register>()); 159} 160 161void LocationsBuilderX86::VisitEqual(HEqual* equal) { 162 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(equal); 163 locations->SetInAt(0, Location(EAX)); 164 locations->SetInAt(1, Location(ECX)); 165 locations->SetOut(Location(EAX)); 166 equal->SetLocations(locations); 167} 168 169void InstructionCodeGeneratorX86::VisitEqual(HEqual* equal) { 170 __ cmpl(equal->GetLocations()->InAt(0).reg<Register>(), 171 equal->GetLocations()->InAt(1).reg<Register>()); 172 __ setb(kEqual, equal->GetLocations()->Out().reg<Register>()); 173} 174 175void LocationsBuilderX86::VisitIntConstant(HIntConstant* constant) { 176 constant->SetLocations(nullptr); 177} 178 179void InstructionCodeGeneratorX86::VisitIntConstant(HIntConstant* constant) { 180 // Will be generated at use site. 181} 182 183void LocationsBuilderX86::VisitReturnVoid(HReturnVoid* ret) { 184 ret->SetLocations(nullptr); 185} 186 187void InstructionCodeGeneratorX86::VisitReturnVoid(HReturnVoid* ret) { 188 codegen_->GenerateFrameExit(); 189 __ ret(); 190} 191 192void LocationsBuilderX86::VisitReturn(HReturn* ret) { 193 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(ret); 194 locations->SetInAt(0, Location(EAX)); 195 ret->SetLocations(locations); 196} 197 198void InstructionCodeGeneratorX86::VisitReturn(HReturn* ret) { 199 DCHECK_EQ(ret->GetLocations()->InAt(0).reg<Register>(), EAX); 200 codegen_->GenerateFrameExit(); 201 __ ret(); 202} 203 204static constexpr Register kParameterCoreRegisters[] = { ECX, EDX, EBX }; 205static constexpr size_t kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters); 206 207class InvokeDexCallingConvention : public CallingConvention<Register> { 208 public: 209 InvokeDexCallingConvention() 210 : CallingConvention(kParameterCoreRegisters, kParameterCoreRegistersLength) {} 211 212 private: 213 DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConvention); 214}; 215 216static constexpr Register kRuntimeParameterCoreRegisters[] = { EAX, ECX, EDX }; 217static constexpr size_t kRuntimeParameterCoreRegistersLength = 218 arraysize(kRuntimeParameterCoreRegisters); 219 220class InvokeRuntimeCallingConvention : public CallingConvention<Register> { 221 public: 222 InvokeRuntimeCallingConvention() 223 : CallingConvention(kRuntimeParameterCoreRegisters, 224 kRuntimeParameterCoreRegistersLength) {} 225 226 private: 227 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention); 228}; 229 230void LocationsBuilderX86::VisitPushArgument(HPushArgument* argument) { 231 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(argument); 232 InvokeDexCallingConvention calling_convention; 233 if (argument->GetArgumentIndex() < calling_convention.GetNumberOfRegisters()) { 234 Location location = Location(calling_convention.GetRegisterAt(argument->GetArgumentIndex())); 235 locations->SetInAt(0, location); 236 locations->SetOut(location); 237 } else { 238 locations->SetInAt(0, Location(EAX)); 239 } 240 argument->SetLocations(locations); 241} 242 243void InstructionCodeGeneratorX86::VisitPushArgument(HPushArgument* argument) { 244 uint8_t argument_index = argument->GetArgumentIndex(); 245 InvokeDexCallingConvention calling_convention; 246 size_t parameter_registers = calling_convention.GetNumberOfRegisters(); 247 if (argument_index >= parameter_registers) { 248 uint8_t offset = calling_convention.GetStackOffsetOf(argument_index); 249 __ movl(Address(ESP, offset), 250 argument->GetLocations()->InAt(0).reg<Register>()); 251 252 } else { 253 DCHECK_EQ(argument->GetLocations()->Out().reg<Register>(), 254 argument->GetLocations()->InAt(0).reg<Register>()); 255 } 256} 257 258void LocationsBuilderX86::VisitInvokeStatic(HInvokeStatic* invoke) { 259 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(invoke); 260 locations->AddTemp(Location(EAX)); 261 invoke->SetLocations(locations); 262} 263 264void InstructionCodeGeneratorX86::VisitInvokeStatic(HInvokeStatic* invoke) { 265 Register temp = invoke->GetLocations()->GetTemp(0).reg<Register>(); 266 size_t index_in_cache = mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() + 267 invoke->GetIndexInDexCache() * kX86WordSize; 268 269 // TODO: Implement all kinds of calls: 270 // 1) boot -> boot 271 // 2) app -> boot 272 // 3) app -> app 273 // 274 // Currently we implement the app -> app logic, which looks up in the resolve cache. 275 276 // temp = method; 277 LoadCurrentMethod(temp); 278 // temp = temp->dex_cache_resolved_methods_; 279 __ movl(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value())); 280 // temp = temp[index_in_cache] 281 __ movl(temp, Address(temp, index_in_cache)); 282 // (temp + offset_of_quick_compiled_code)() 283 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value())); 284 285 codegen_->RecordPcInfo(invoke->GetDexPc()); 286} 287 288void LocationsBuilderX86::VisitAdd(HAdd* add) { 289 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(add); 290 switch (add->GetResultType()) { 291 case Primitive::kPrimInt: { 292 locations->SetInAt(0, Location(EAX)); 293 locations->SetInAt(1, Location(ECX)); 294 locations->SetOut(Location(EAX)); 295 break; 296 } 297 default: 298 LOG(FATAL) << "Unimplemented"; 299 } 300 add->SetLocations(locations); 301} 302 303void InstructionCodeGeneratorX86::VisitAdd(HAdd* add) { 304 LocationSummary* locations = add->GetLocations(); 305 switch (add->GetResultType()) { 306 case Primitive::kPrimInt: 307 DCHECK_EQ(locations->InAt(0).reg<Register>(), locations->Out().reg<Register>()); 308 __ addl(locations->InAt(0).reg<Register>(), locations->InAt(1).reg<Register>()); 309 break; 310 default: 311 LOG(FATAL) << "Unimplemented"; 312 } 313} 314 315void LocationsBuilderX86::VisitSub(HSub* sub) { 316 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(sub); 317 switch (sub->GetResultType()) { 318 case Primitive::kPrimInt: { 319 locations->SetInAt(0, Location(EAX)); 320 locations->SetInAt(1, Location(ECX)); 321 locations->SetOut(Location(EAX)); 322 break; 323 } 324 default: 325 LOG(FATAL) << "Unimplemented"; 326 } 327 sub->SetLocations(locations); 328} 329 330void InstructionCodeGeneratorX86::VisitSub(HSub* sub) { 331 LocationSummary* locations = sub->GetLocations(); 332 switch (sub->GetResultType()) { 333 case Primitive::kPrimInt: 334 DCHECK_EQ(locations->InAt(0).reg<Register>(), locations->Out().reg<Register>()); 335 __ subl(locations->InAt(0).reg<Register>(), locations->InAt(1).reg<Register>()); 336 break; 337 default: 338 LOG(FATAL) << "Unimplemented"; 339 } 340} 341 342void LocationsBuilderX86::VisitNewInstance(HNewInstance* instruction) { 343 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction); 344 locations->SetOut(Location(EAX)); 345 instruction->SetLocations(locations); 346} 347 348void InstructionCodeGeneratorX86::VisitNewInstance(HNewInstance* instruction) { 349 InvokeRuntimeCallingConvention calling_convention; 350 LoadCurrentMethod(calling_convention.GetRegisterAt(1)); 351 __ movl(calling_convention.GetRegisterAt(0), 352 Immediate(instruction->GetTypeIndex())); 353 354 __ fs()->call( 355 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pAllocObjectWithAccessCheck))); 356 357 codegen_->RecordPcInfo(instruction->GetDexPc()); 358} 359 360void LocationsBuilderX86::VisitParameterValue(HParameterValue* instruction) { 361 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction); 362 InvokeDexCallingConvention calling_convention; 363 uint32_t argument_index = instruction->GetIndex(); 364 if (argument_index < calling_convention.GetNumberOfRegisters()) { 365 locations->SetOut(Location(calling_convention.GetRegisterAt(argument_index))); 366 } else { 367 locations->SetOut(Location(EAX)); 368 } 369 instruction->SetLocations(locations); 370} 371 372void InstructionCodeGeneratorX86::VisitParameterValue(HParameterValue* instruction) { 373 LocationSummary* locations = instruction->GetLocations(); 374 InvokeDexCallingConvention calling_convention; 375 uint32_t argument_index = instruction->GetIndex(); 376 if (argument_index >= calling_convention.GetNumberOfRegisters()) { 377 uint8_t offset = calling_convention.GetStackOffsetOf(argument_index); 378 __ movl(locations->Out().reg<Register>(), Address(ESP, offset + codegen_->GetFrameSize())); 379 } 380} 381 382void LocationsBuilderX86::VisitNot(HNot* instruction) { 383 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction); 384 locations->SetInAt(0, Location(EAX)); 385 locations->SetOut(Location(EAX)); 386 instruction->SetLocations(locations); 387} 388 389void InstructionCodeGeneratorX86::VisitNot(HNot* instruction) { 390 LocationSummary* locations = instruction->GetLocations(); 391 DCHECK_EQ(locations->InAt(0).reg<Register>(), locations->Out().reg<Register>()); 392 __ xorl(locations->Out().reg<Register>(), Immediate(1)); 393} 394 395} // namespace x86 396} // namespace art 397