code_generator_arm.cc revision 8e3964b766652a0478e8e0e303e8556c997675f1
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 19#include "entrypoints/quick/quick_entrypoints.h" 20#include "gc/accounting/card_table.h" 21#include "mirror/array-inl.h" 22#include "mirror/art_method.h" 23#include "mirror/class.h" 24#include "thread.h" 25#include "utils/assembler.h" 26#include "utils/arm/assembler_arm.h" 27#include "utils/arm/managed_register_arm.h" 28#include "utils/stack_checks.h" 29 30namespace art { 31 32namespace arm { 33 34static SRegister FromDToLowS(DRegister reg) { 35 return static_cast<SRegister>(reg * 2); 36} 37 38static constexpr bool kExplicitStackOverflowCheck = false; 39 40static constexpr int kNumberOfPushedRegistersAtEntry = 1 + 2; // LR, R6, R7 41static constexpr int kCurrentMethodStackOffset = 0; 42 43static constexpr Register kRuntimeParameterCoreRegisters[] = { R0, R1, R2 }; 44static constexpr size_t kRuntimeParameterCoreRegistersLength = 45 arraysize(kRuntimeParameterCoreRegisters); 46static constexpr DRegister kRuntimeParameterFpuRegisters[] = { }; 47static constexpr size_t kRuntimeParameterFpuRegistersLength = 0; 48 49class InvokeRuntimeCallingConvention : public CallingConvention<Register, DRegister> { 50 public: 51 InvokeRuntimeCallingConvention() 52 : CallingConvention(kRuntimeParameterCoreRegisters, 53 kRuntimeParameterCoreRegistersLength, 54 kRuntimeParameterFpuRegisters, 55 kRuntimeParameterFpuRegistersLength) {} 56 57 private: 58 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention); 59}; 60 61#define __ reinterpret_cast<ArmAssembler*>(codegen->GetAssembler())-> 62 63class SlowPathCodeARM : public SlowPathCode { 64 public: 65 SlowPathCodeARM() : entry_label_(), exit_label_() {} 66 67 Label* GetEntryLabel() { return &entry_label_; } 68 Label* GetExitLabel() { return &exit_label_; } 69 70 private: 71 Label entry_label_; 72 Label exit_label_; 73 74 DISALLOW_COPY_AND_ASSIGN(SlowPathCodeARM); 75}; 76 77class NullCheckSlowPathARM : public SlowPathCodeARM { 78 public: 79 explicit NullCheckSlowPathARM(HNullCheck* instruction) : instruction_(instruction) {} 80 81 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { 82 __ Bind(GetEntryLabel()); 83 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pThrowNullPointer).Int32Value(); 84 __ LoadFromOffset(kLoadWord, LR, TR, offset); 85 __ blx(LR); 86 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc()); 87 } 88 89 private: 90 HNullCheck* const instruction_; 91 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathARM); 92}; 93 94class StackOverflowCheckSlowPathARM : public SlowPathCodeARM { 95 public: 96 StackOverflowCheckSlowPathARM() {} 97 98 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { 99 __ Bind(GetEntryLabel()); 100 __ LoadFromOffset(kLoadWord, PC, TR, 101 QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pThrowStackOverflow).Int32Value()); 102 } 103 104 private: 105 DISALLOW_COPY_AND_ASSIGN(StackOverflowCheckSlowPathARM); 106}; 107 108class SuspendCheckSlowPathARM : public SlowPathCodeARM { 109 public: 110 explicit SuspendCheckSlowPathARM(HSuspendCheck* instruction, HBasicBlock* successor) 111 : instruction_(instruction), successor_(successor) {} 112 113 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { 114 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen); 115 __ Bind(GetEntryLabel()); 116 codegen->SaveLiveRegisters(instruction_->GetLocations()); 117 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pTestSuspend).Int32Value(); 118 __ LoadFromOffset(kLoadWord, LR, TR, offset); 119 __ blx(LR); 120 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc()); 121 codegen->RestoreLiveRegisters(instruction_->GetLocations()); 122 if (successor_ == nullptr) { 123 __ b(GetReturnLabel()); 124 } else { 125 __ b(arm_codegen->GetLabelOf(successor_)); 126 } 127 } 128 129 Label* GetReturnLabel() { 130 DCHECK(successor_ == nullptr); 131 return &return_label_; 132 } 133 134 private: 135 HSuspendCheck* const instruction_; 136 // If not null, the block to branch to after the suspend check. 137 HBasicBlock* const successor_; 138 139 // If `successor_` is null, the label to branch to after the suspend check. 140 Label return_label_; 141 142 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathARM); 143}; 144 145class BoundsCheckSlowPathARM : public SlowPathCodeARM { 146 public: 147 BoundsCheckSlowPathARM(HBoundsCheck* instruction, 148 Location index_location, 149 Location length_location) 150 : instruction_(instruction), 151 index_location_(index_location), 152 length_location_(length_location) {} 153 154 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { 155 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen); 156 __ Bind(GetEntryLabel()); 157 InvokeRuntimeCallingConvention calling_convention; 158 arm_codegen->Move32(Location::RegisterLocation(calling_convention.GetRegisterAt(0)), index_location_); 159 arm_codegen->Move32(Location::RegisterLocation(calling_convention.GetRegisterAt(1)), length_location_); 160 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pThrowArrayBounds).Int32Value(); 161 __ LoadFromOffset(kLoadWord, LR, TR, offset); 162 __ blx(LR); 163 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc()); 164 } 165 166 private: 167 HBoundsCheck* const instruction_; 168 const Location index_location_; 169 const Location length_location_; 170 171 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM); 172}; 173 174#undef __ 175#define __ reinterpret_cast<ArmAssembler*>(GetAssembler())-> 176 177inline Condition ARMCondition(IfCondition cond) { 178 switch (cond) { 179 case kCondEQ: return EQ; 180 case kCondNE: return NE; 181 case kCondLT: return LT; 182 case kCondLE: return LE; 183 case kCondGT: return GT; 184 case kCondGE: return GE; 185 default: 186 LOG(FATAL) << "Unknown if condition"; 187 } 188 return EQ; // Unreachable. 189} 190 191inline Condition ARMOppositeCondition(IfCondition cond) { 192 switch (cond) { 193 case kCondEQ: return NE; 194 case kCondNE: return EQ; 195 case kCondLT: return GE; 196 case kCondLE: return GT; 197 case kCondGT: return LE; 198 case kCondGE: return LT; 199 default: 200 LOG(FATAL) << "Unknown if condition"; 201 } 202 return EQ; // Unreachable. 203} 204 205void CodeGeneratorARM::DumpCoreRegister(std::ostream& stream, int reg) const { 206 stream << ArmManagedRegister::FromCoreRegister(Register(reg)); 207} 208 209void CodeGeneratorARM::DumpFloatingPointRegister(std::ostream& stream, int reg) const { 210 stream << ArmManagedRegister::FromDRegister(DRegister(reg)); 211} 212 213void CodeGeneratorARM::SaveCoreRegister(Location stack_location, uint32_t reg_id) { 214 __ StoreToOffset(kStoreWord, static_cast<Register>(reg_id), SP, stack_location.GetStackIndex()); 215} 216 217void CodeGeneratorARM::RestoreCoreRegister(Location stack_location, uint32_t reg_id) { 218 __ LoadFromOffset(kLoadWord, static_cast<Register>(reg_id), SP, stack_location.GetStackIndex()); 219} 220 221CodeGeneratorARM::CodeGeneratorARM(HGraph* graph) 222 : CodeGenerator(graph, kNumberOfCoreRegisters, kNumberOfDRegisters, kNumberOfRegisterPairs), 223 block_labels_(graph->GetArena(), 0), 224 location_builder_(graph, this), 225 instruction_visitor_(graph, this), 226 move_resolver_(graph->GetArena(), this), 227 assembler_(true) {} 228 229size_t CodeGeneratorARM::FrameEntrySpillSize() const { 230 return kNumberOfPushedRegistersAtEntry * kArmWordSize; 231} 232 233Location CodeGeneratorARM::AllocateFreeRegister(Primitive::Type type) const { 234 switch (type) { 235 case Primitive::kPrimLong: { 236 size_t reg = FindFreeEntry(blocked_register_pairs_, kNumberOfRegisterPairs); 237 ArmManagedRegister pair = 238 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg)); 239 DCHECK(!blocked_core_registers_[pair.AsRegisterPairLow()]); 240 DCHECK(!blocked_core_registers_[pair.AsRegisterPairHigh()]); 241 242 blocked_core_registers_[pair.AsRegisterPairLow()] = true; 243 blocked_core_registers_[pair.AsRegisterPairHigh()] = true; 244 UpdateBlockedPairRegisters(); 245 return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh()); 246 } 247 248 case Primitive::kPrimByte: 249 case Primitive::kPrimBoolean: 250 case Primitive::kPrimChar: 251 case Primitive::kPrimShort: 252 case Primitive::kPrimInt: 253 case Primitive::kPrimNot: { 254 int reg = FindFreeEntry(blocked_core_registers_, kNumberOfCoreRegisters); 255 // Block all register pairs that contain `reg`. 256 for (int i = 0; i < kNumberOfRegisterPairs; i++) { 257 ArmManagedRegister current = 258 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i)); 259 if (current.AsRegisterPairLow() == reg || current.AsRegisterPairHigh() == reg) { 260 blocked_register_pairs_[i] = true; 261 } 262 } 263 return Location::RegisterLocation(reg); 264 } 265 266 case Primitive::kPrimFloat: 267 case Primitive::kPrimDouble: { 268 int reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfDRegisters); 269 return Location::FpuRegisterLocation(reg); 270 } 271 272 case Primitive::kPrimVoid: 273 LOG(FATAL) << "Unreachable type " << type; 274 } 275 276 return Location(); 277} 278 279void CodeGeneratorARM::SetupBlockedRegisters() const { 280 // Don't allocate the dalvik style register pair passing. 281 blocked_register_pairs_[R1_R2] = true; 282 283 // Stack register, LR and PC are always reserved. 284 blocked_core_registers_[SP] = true; 285 blocked_core_registers_[LR] = true; 286 blocked_core_registers_[PC] = true; 287 288 // Reserve R4 for suspend check. 289 blocked_core_registers_[R4] = true; 290 291 // Reserve thread register. 292 blocked_core_registers_[TR] = true; 293 294 // Reserve temp register. 295 blocked_core_registers_[IP] = true; 296 297 // TODO: We currently don't use Quick's callee saved registers. 298 // We always save and restore R6 and R7 to make sure we can use three 299 // register pairs for long operations. 300 blocked_core_registers_[R5] = true; 301 blocked_core_registers_[R8] = true; 302 blocked_core_registers_[R10] = true; 303 blocked_core_registers_[R11] = true; 304 305 blocked_fpu_registers_[D8] = true; 306 blocked_fpu_registers_[D9] = true; 307 blocked_fpu_registers_[D10] = true; 308 blocked_fpu_registers_[D11] = true; 309 blocked_fpu_registers_[D12] = true; 310 blocked_fpu_registers_[D13] = true; 311 blocked_fpu_registers_[D14] = true; 312 blocked_fpu_registers_[D15] = true; 313 314 UpdateBlockedPairRegisters(); 315} 316 317void CodeGeneratorARM::UpdateBlockedPairRegisters() const { 318 for (int i = 0; i < kNumberOfRegisterPairs; i++) { 319 ArmManagedRegister current = 320 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i)); 321 if (blocked_core_registers_[current.AsRegisterPairLow()] 322 || blocked_core_registers_[current.AsRegisterPairHigh()]) { 323 blocked_register_pairs_[i] = true; 324 } 325 } 326} 327 328InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen) 329 : HGraphVisitor(graph), 330 assembler_(codegen->GetAssembler()), 331 codegen_(codegen) {} 332 333void CodeGeneratorARM::GenerateFrameEntry() { 334 bool skip_overflow_check = IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kArm); 335 if (!skip_overflow_check) { 336 if (kExplicitStackOverflowCheck) { 337 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) StackOverflowCheckSlowPathARM(); 338 AddSlowPath(slow_path); 339 340 __ LoadFromOffset(kLoadWord, IP, TR, Thread::StackEndOffset<kArmWordSize>().Int32Value()); 341 __ cmp(SP, ShifterOperand(IP)); 342 __ b(slow_path->GetEntryLabel(), CC); 343 } else { 344 __ AddConstant(IP, SP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm))); 345 __ LoadFromOffset(kLoadWord, IP, IP, 0); 346 RecordPcInfo(nullptr, 0); 347 } 348 } 349 350 core_spill_mask_ |= (1 << LR | 1 << R6 | 1 << R7); 351 __ PushList(1 << LR | 1 << R6 | 1 << R7); 352 353 // The return PC has already been pushed on the stack. 354 __ AddConstant(SP, -(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize)); 355 __ StoreToOffset(kStoreWord, R0, SP, 0); 356} 357 358void CodeGeneratorARM::GenerateFrameExit() { 359 __ AddConstant(SP, GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize); 360 __ PopList(1 << PC | 1 << R6 | 1 << R7); 361} 362 363void CodeGeneratorARM::Bind(HBasicBlock* block) { 364 __ Bind(GetLabelOf(block)); 365} 366 367Location CodeGeneratorARM::GetStackLocation(HLoadLocal* load) const { 368 switch (load->GetType()) { 369 case Primitive::kPrimLong: 370 case Primitive::kPrimDouble: 371 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal())); 372 break; 373 374 case Primitive::kPrimInt: 375 case Primitive::kPrimNot: 376 case Primitive::kPrimFloat: 377 return Location::StackSlot(GetStackSlot(load->GetLocal())); 378 379 case Primitive::kPrimBoolean: 380 case Primitive::kPrimByte: 381 case Primitive::kPrimChar: 382 case Primitive::kPrimShort: 383 case Primitive::kPrimVoid: 384 LOG(FATAL) << "Unexpected type " << load->GetType(); 385 } 386 387 LOG(FATAL) << "Unreachable"; 388 return Location(); 389} 390 391Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) { 392 switch (type) { 393 case Primitive::kPrimBoolean: 394 case Primitive::kPrimByte: 395 case Primitive::kPrimChar: 396 case Primitive::kPrimShort: 397 case Primitive::kPrimInt: 398 case Primitive::kPrimFloat: 399 case Primitive::kPrimNot: { 400 uint32_t index = gp_index_++; 401 if (index < calling_convention.GetNumberOfRegisters()) { 402 return Location::RegisterLocation(calling_convention.GetRegisterAt(index)); 403 } else { 404 return Location::StackSlot(calling_convention.GetStackOffsetOf(index)); 405 } 406 } 407 408 case Primitive::kPrimLong: 409 case Primitive::kPrimDouble: { 410 uint32_t index = gp_index_; 411 gp_index_ += 2; 412 if (index + 1 < calling_convention.GetNumberOfRegisters()) { 413 ArmManagedRegister pair = ArmManagedRegister::FromRegisterPair( 414 calling_convention.GetRegisterPairAt(index)); 415 return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh()); 416 } else if (index + 1 == calling_convention.GetNumberOfRegisters()) { 417 return Location::QuickParameter(index); 418 } else { 419 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(index)); 420 } 421 } 422 423 case Primitive::kPrimVoid: 424 LOG(FATAL) << "Unexpected parameter type " << type; 425 break; 426 } 427 return Location(); 428} 429 430void CodeGeneratorARM::Move32(Location destination, Location source) { 431 if (source.Equals(destination)) { 432 return; 433 } 434 if (destination.IsRegister()) { 435 if (source.IsRegister()) { 436 __ Mov(destination.As<Register>(), source.As<Register>()); 437 } else if (source.IsFpuRegister()) { 438 __ vmovrs(destination.As<Register>(), FromDToLowS(source.As<DRegister>())); 439 } else { 440 __ LoadFromOffset(kLoadWord, destination.As<Register>(), SP, source.GetStackIndex()); 441 } 442 } else if (destination.IsFpuRegister()) { 443 if (source.IsRegister()) { 444 __ vmovsr(FromDToLowS(destination.As<DRegister>()), source.As<Register>()); 445 } else if (source.IsFpuRegister()) { 446 __ vmovs(FromDToLowS(destination.As<DRegister>()), FromDToLowS(source.As<DRegister>())); 447 } else { 448 __ vldrs(FromDToLowS(destination.As<DRegister>()), Address(SP, source.GetStackIndex())); 449 } 450 } else { 451 DCHECK(destination.IsStackSlot()); 452 if (source.IsRegister()) { 453 __ StoreToOffset(kStoreWord, source.As<Register>(), SP, destination.GetStackIndex()); 454 } else if (source.IsFpuRegister()) { 455 __ vstrs(FromDToLowS(source.As<DRegister>()), Address(SP, destination.GetStackIndex())); 456 } else { 457 DCHECK(source.IsStackSlot()); 458 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex()); 459 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex()); 460 } 461 } 462} 463 464void CodeGeneratorARM::Move64(Location destination, Location source) { 465 if (source.Equals(destination)) { 466 return; 467 } 468 if (destination.IsRegisterPair()) { 469 if (source.IsRegisterPair()) { 470 __ Mov(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>()); 471 __ Mov(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>()); 472 } else if (source.IsFpuRegister()) { 473 LOG(FATAL) << "Unimplemented"; 474 } else if (source.IsQuickParameter()) { 475 uint32_t argument_index = source.GetQuickParameterIndex(); 476 InvokeDexCallingConvention calling_convention; 477 __ Mov(destination.AsRegisterPairLow<Register>(), 478 calling_convention.GetRegisterAt(argument_index)); 479 __ LoadFromOffset(kLoadWord, destination.AsRegisterPairHigh<Register>(), 480 SP, calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize()); 481 } else { 482 DCHECK(source.IsDoubleStackSlot()); 483 if (destination.AsRegisterPairLow<Register>() == R1) { 484 DCHECK_EQ(destination.AsRegisterPairHigh<Register>(), R2); 485 __ LoadFromOffset(kLoadWord, R1, SP, source.GetStackIndex()); 486 __ LoadFromOffset(kLoadWord, R2, SP, source.GetHighStackIndex(kArmWordSize)); 487 } else { 488 __ LoadFromOffset(kLoadWordPair, destination.AsRegisterPairLow<Register>(), 489 SP, source.GetStackIndex()); 490 } 491 } 492 } else if (destination.IsFpuRegister()) { 493 if (source.IsDoubleStackSlot()) { 494 __ vldrd(destination.As<DRegister>(), Address(SP, source.GetStackIndex())); 495 } else { 496 LOG(FATAL) << "Unimplemented"; 497 } 498 } else if (destination.IsQuickParameter()) { 499 InvokeDexCallingConvention calling_convention; 500 uint32_t argument_index = destination.GetQuickParameterIndex(); 501 if (source.IsRegisterPair()) { 502 __ Mov(calling_convention.GetRegisterAt(argument_index), 503 source.AsRegisterPairLow<Register>()); 504 __ StoreToOffset(kStoreWord, source.AsRegisterPairHigh<Register>(), 505 SP, calling_convention.GetStackOffsetOf(argument_index + 1)); 506 } else if (source.IsFpuRegister()) { 507 LOG(FATAL) << "Unimplemented"; 508 } else { 509 DCHECK(source.IsDoubleStackSlot()); 510 __ LoadFromOffset(kLoadWord, calling_convention.GetRegisterAt(argument_index), SP, source.GetStackIndex()); 511 __ LoadFromOffset(kLoadWord, R0, SP, source.GetHighStackIndex(kArmWordSize)); 512 __ StoreToOffset(kStoreWord, R0, SP, calling_convention.GetStackOffsetOf(argument_index + 1)); 513 } 514 } else { 515 DCHECK(destination.IsDoubleStackSlot()); 516 if (source.IsRegisterPair()) { 517 if (source.AsRegisterPairLow<Register>() == R1) { 518 DCHECK_EQ(source.AsRegisterPairHigh<Register>(), R2); 519 __ StoreToOffset(kStoreWord, R1, SP, destination.GetStackIndex()); 520 __ StoreToOffset(kStoreWord, R2, SP, destination.GetHighStackIndex(kArmWordSize)); 521 } else { 522 __ StoreToOffset(kStoreWordPair, source.AsRegisterPairLow<Register>(), 523 SP, destination.GetStackIndex()); 524 } 525 } else if (source.IsQuickParameter()) { 526 InvokeDexCallingConvention calling_convention; 527 uint32_t argument_index = source.GetQuickParameterIndex(); 528 __ StoreToOffset(kStoreWord, calling_convention.GetRegisterAt(argument_index), 529 SP, destination.GetStackIndex()); 530 __ LoadFromOffset(kLoadWord, R0, 531 SP, calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize()); 532 __ StoreToOffset(kStoreWord, R0, SP, destination.GetHighStackIndex(kArmWordSize)); 533 } else if (source.IsFpuRegister()) { 534 __ vstrd(source.As<DRegister>(), Address(SP, destination.GetStackIndex())); 535 } else { 536 DCHECK(source.IsDoubleStackSlot()); 537 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex()); 538 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex()); 539 __ LoadFromOffset(kLoadWord, IP, SP, source.GetHighStackIndex(kArmWordSize)); 540 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize)); 541 } 542 } 543} 544 545void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) { 546 LocationSummary* locations = instruction->GetLocations(); 547 if (locations != nullptr && locations->Out().Equals(location)) { 548 return; 549 } 550 551 if (instruction->IsIntConstant()) { 552 int32_t value = instruction->AsIntConstant()->GetValue(); 553 if (location.IsRegister()) { 554 __ LoadImmediate(location.As<Register>(), value); 555 } else { 556 DCHECK(location.IsStackSlot()); 557 __ LoadImmediate(IP, value); 558 __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex()); 559 } 560 } else if (instruction->IsLongConstant()) { 561 int64_t value = instruction->AsLongConstant()->GetValue(); 562 if (location.IsRegisterPair()) { 563 __ LoadImmediate(location.AsRegisterPairLow<Register>(), Low32Bits(value)); 564 __ LoadImmediate(location.AsRegisterPairHigh<Register>(), High32Bits(value)); 565 } else { 566 DCHECK(location.IsDoubleStackSlot()); 567 __ LoadImmediate(IP, Low32Bits(value)); 568 __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex()); 569 __ LoadImmediate(IP, High32Bits(value)); 570 __ StoreToOffset(kStoreWord, IP, SP, location.GetHighStackIndex(kArmWordSize)); 571 } 572 } else if (instruction->IsLoadLocal()) { 573 uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal()); 574 switch (instruction->GetType()) { 575 case Primitive::kPrimBoolean: 576 case Primitive::kPrimByte: 577 case Primitive::kPrimChar: 578 case Primitive::kPrimShort: 579 case Primitive::kPrimInt: 580 case Primitive::kPrimNot: 581 case Primitive::kPrimFloat: 582 Move32(location, Location::StackSlot(stack_slot)); 583 break; 584 585 case Primitive::kPrimLong: 586 case Primitive::kPrimDouble: 587 Move64(location, Location::DoubleStackSlot(stack_slot)); 588 break; 589 590 default: 591 LOG(FATAL) << "Unexpected type " << instruction->GetType(); 592 } 593 } else { 594 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary()); 595 switch (instruction->GetType()) { 596 case Primitive::kPrimBoolean: 597 case Primitive::kPrimByte: 598 case Primitive::kPrimChar: 599 case Primitive::kPrimShort: 600 case Primitive::kPrimNot: 601 case Primitive::kPrimInt: 602 case Primitive::kPrimFloat: 603 Move32(location, locations->Out()); 604 break; 605 606 case Primitive::kPrimLong: 607 case Primitive::kPrimDouble: 608 Move64(location, locations->Out()); 609 break; 610 611 default: 612 LOG(FATAL) << "Unexpected type " << instruction->GetType(); 613 } 614 } 615} 616 617void LocationsBuilderARM::VisitGoto(HGoto* got) { 618 got->SetLocations(nullptr); 619} 620 621void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) { 622 HBasicBlock* successor = got->GetSuccessor(); 623 DCHECK(!successor->IsExitBlock()); 624 625 HBasicBlock* block = got->GetBlock(); 626 HInstruction* previous = got->GetPrevious(); 627 628 HLoopInformation* info = block->GetLoopInformation(); 629 if (info != nullptr && info->IsBackEdge(block) && info->HasSuspendCheck()) { 630 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck()); 631 GenerateSuspendCheck(info->GetSuspendCheck(), successor); 632 return; 633 } 634 635 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) { 636 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr); 637 } 638 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) { 639 __ b(codegen_->GetLabelOf(successor)); 640 } 641} 642 643void LocationsBuilderARM::VisitExit(HExit* exit) { 644 exit->SetLocations(nullptr); 645} 646 647void InstructionCodeGeneratorARM::VisitExit(HExit* exit) { 648 if (kIsDebugBuild) { 649 __ Comment("Unreachable"); 650 __ bkpt(0); 651 } 652} 653 654void LocationsBuilderARM::VisitIf(HIf* if_instr) { 655 LocationSummary* locations = 656 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall); 657 HInstruction* cond = if_instr->InputAt(0); 658 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) { 659 locations->SetInAt(0, Location::RequiresRegister()); 660 } 661} 662 663void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) { 664 HInstruction* cond = if_instr->InputAt(0); 665 if (cond->IsIntConstant()) { 666 // Constant condition, statically compared against 1. 667 int32_t cond_value = cond->AsIntConstant()->GetValue(); 668 if (cond_value == 1) { 669 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), 670 if_instr->IfTrueSuccessor())) { 671 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor())); 672 } 673 return; 674 } else { 675 DCHECK_EQ(cond_value, 0); 676 } 677 } else { 678 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) { 679 // Condition has been materialized, compare the output to 0 680 DCHECK(if_instr->GetLocations()->InAt(0).IsRegister()); 681 __ cmp(if_instr->GetLocations()->InAt(0).As<Register>(), 682 ShifterOperand(0)); 683 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()), NE); 684 } else { 685 // Condition has not been materialized, use its inputs as the 686 // comparison and its condition as the branch condition. 687 LocationSummary* locations = cond->GetLocations(); 688 if (locations->InAt(1).IsRegister()) { 689 __ cmp(locations->InAt(0).As<Register>(), 690 ShifterOperand(locations->InAt(1).As<Register>())); 691 } else { 692 DCHECK(locations->InAt(1).IsConstant()); 693 int32_t value = 694 locations->InAt(1).GetConstant()->AsIntConstant()->GetValue(); 695 ShifterOperand operand; 696 if (ShifterOperand::CanHoldArm(value, &operand)) { 697 __ cmp(locations->InAt(0).As<Register>(), ShifterOperand(value)); 698 } else { 699 Register temp = IP; 700 __ LoadImmediate(temp, value); 701 __ cmp(locations->InAt(0).As<Register>(), ShifterOperand(temp)); 702 } 703 } 704 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()), 705 ARMCondition(cond->AsCondition()->GetCondition())); 706 } 707 } 708 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), 709 if_instr->IfFalseSuccessor())) { 710 __ b(codegen_->GetLabelOf(if_instr->IfFalseSuccessor())); 711 } 712} 713 714 715void LocationsBuilderARM::VisitCondition(HCondition* comp) { 716 LocationSummary* locations = 717 new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall); 718 locations->SetInAt(0, Location::RequiresRegister()); 719 locations->SetInAt(1, Location::RegisterOrConstant(comp->InputAt(1))); 720 if (comp->NeedsMaterialization()) { 721 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 722 } 723} 724 725void InstructionCodeGeneratorARM::VisitCondition(HCondition* comp) { 726 if (!comp->NeedsMaterialization()) return; 727 728 LocationSummary* locations = comp->GetLocations(); 729 if (locations->InAt(1).IsRegister()) { 730 __ cmp(locations->InAt(0).As<Register>(), 731 ShifterOperand(locations->InAt(1).As<Register>())); 732 } else { 733 DCHECK(locations->InAt(1).IsConstant()); 734 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue(); 735 ShifterOperand operand; 736 if (ShifterOperand::CanHoldArm(value, &operand)) { 737 __ cmp(locations->InAt(0).As<Register>(), ShifterOperand(value)); 738 } else { 739 Register temp = IP; 740 __ LoadImmediate(temp, value); 741 __ cmp(locations->InAt(0).As<Register>(), ShifterOperand(temp)); 742 } 743 } 744 __ it(ARMCondition(comp->GetCondition()), kItElse); 745 __ mov(locations->Out().As<Register>(), ShifterOperand(1), 746 ARMCondition(comp->GetCondition())); 747 __ mov(locations->Out().As<Register>(), ShifterOperand(0), 748 ARMOppositeCondition(comp->GetCondition())); 749} 750 751void LocationsBuilderARM::VisitEqual(HEqual* comp) { 752 VisitCondition(comp); 753} 754 755void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) { 756 VisitCondition(comp); 757} 758 759void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) { 760 VisitCondition(comp); 761} 762 763void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) { 764 VisitCondition(comp); 765} 766 767void LocationsBuilderARM::VisitLessThan(HLessThan* comp) { 768 VisitCondition(comp); 769} 770 771void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) { 772 VisitCondition(comp); 773} 774 775void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) { 776 VisitCondition(comp); 777} 778 779void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) { 780 VisitCondition(comp); 781} 782 783void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) { 784 VisitCondition(comp); 785} 786 787void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) { 788 VisitCondition(comp); 789} 790 791void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) { 792 VisitCondition(comp); 793} 794 795void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) { 796 VisitCondition(comp); 797} 798 799void LocationsBuilderARM::VisitLocal(HLocal* local) { 800 local->SetLocations(nullptr); 801} 802 803void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) { 804 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock()); 805} 806 807void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) { 808 load->SetLocations(nullptr); 809} 810 811void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) { 812 // Nothing to do, this is driven by the code generator. 813} 814 815void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) { 816 LocationSummary* locations = 817 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall); 818 switch (store->InputAt(1)->GetType()) { 819 case Primitive::kPrimBoolean: 820 case Primitive::kPrimByte: 821 case Primitive::kPrimChar: 822 case Primitive::kPrimShort: 823 case Primitive::kPrimInt: 824 case Primitive::kPrimNot: 825 case Primitive::kPrimFloat: 826 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal()))); 827 break; 828 829 case Primitive::kPrimLong: 830 case Primitive::kPrimDouble: 831 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal()))); 832 break; 833 834 default: 835 LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType(); 836 } 837} 838 839void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) { 840} 841 842void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) { 843 LocationSummary* locations = 844 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall); 845 locations->SetOut(Location::ConstantLocation(constant)); 846} 847 848void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) { 849 // Will be generated at use site. 850} 851 852void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) { 853 LocationSummary* locations = 854 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall); 855 locations->SetOut(Location::ConstantLocation(constant)); 856} 857 858void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant) { 859 // Will be generated at use site. 860} 861 862void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) { 863 ret->SetLocations(nullptr); 864} 865 866void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) { 867 codegen_->GenerateFrameExit(); 868} 869 870void LocationsBuilderARM::VisitReturn(HReturn* ret) { 871 LocationSummary* locations = 872 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall); 873 switch (ret->InputAt(0)->GetType()) { 874 case Primitive::kPrimBoolean: 875 case Primitive::kPrimByte: 876 case Primitive::kPrimChar: 877 case Primitive::kPrimShort: 878 case Primitive::kPrimInt: 879 case Primitive::kPrimNot: 880 case Primitive::kPrimFloat: 881 locations->SetInAt(0, Location::RegisterLocation(R0)); 882 break; 883 884 case Primitive::kPrimLong: 885 case Primitive::kPrimDouble: 886 locations->SetInAt(0, Location::RegisterPairLocation(R0, R1)); 887 break; 888 889 default: 890 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType(); 891 } 892} 893 894void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) { 895 if (kIsDebugBuild) { 896 switch (ret->InputAt(0)->GetType()) { 897 case Primitive::kPrimBoolean: 898 case Primitive::kPrimByte: 899 case Primitive::kPrimChar: 900 case Primitive::kPrimShort: 901 case Primitive::kPrimInt: 902 case Primitive::kPrimNot: 903 case Primitive::kPrimFloat: 904 DCHECK_EQ(ret->GetLocations()->InAt(0).As<Register>(), R0); 905 break; 906 907 case Primitive::kPrimLong: 908 case Primitive::kPrimDouble: 909 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegisterPairLow<Register>(), R0); 910 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegisterPairHigh<Register>(), R1); 911 break; 912 913 default: 914 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType(); 915 } 916 } 917 codegen_->GenerateFrameExit(); 918} 919 920void LocationsBuilderARM::VisitInvokeStatic(HInvokeStatic* invoke) { 921 HandleInvoke(invoke); 922} 923 924void InstructionCodeGeneratorARM::LoadCurrentMethod(Register reg) { 925 __ LoadFromOffset(kLoadWord, reg, SP, kCurrentMethodStackOffset); 926} 927 928void InstructionCodeGeneratorARM::VisitInvokeStatic(HInvokeStatic* invoke) { 929 Register temp = invoke->GetLocations()->GetTemp(0).As<Register>(); 930 uint32_t heap_reference_size = sizeof(mirror::HeapReference<mirror::Object>); 931 size_t index_in_cache = mirror::Array::DataOffset(heap_reference_size).Int32Value() + 932 invoke->GetIndexInDexCache() * kArmWordSize; 933 934 // TODO: Implement all kinds of calls: 935 // 1) boot -> boot 936 // 2) app -> boot 937 // 3) app -> app 938 // 939 // Currently we implement the app -> app logic, which looks up in the resolve cache. 940 941 // temp = method; 942 LoadCurrentMethod(temp); 943 // temp = temp->dex_cache_resolved_methods_; 944 __ LoadFromOffset(kLoadWord, temp, temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value()); 945 // temp = temp[index_in_cache] 946 __ LoadFromOffset(kLoadWord, temp, temp, index_in_cache); 947 // LR = temp[offset_of_quick_compiled_code] 948 __ LoadFromOffset(kLoadWord, LR, temp, 949 mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value()); 950 // LR() 951 __ blx(LR); 952 953 codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); 954 DCHECK(!codegen_->IsLeafMethod()); 955} 956 957void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) { 958 HandleInvoke(invoke); 959} 960 961void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) { 962 LocationSummary* locations = 963 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall); 964 locations->AddTemp(Location::RegisterLocation(R0)); 965 966 InvokeDexCallingConventionVisitor calling_convention_visitor; 967 for (size_t i = 0; i < invoke->InputCount(); i++) { 968 HInstruction* input = invoke->InputAt(i); 969 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType())); 970 } 971 972 switch (invoke->GetType()) { 973 case Primitive::kPrimBoolean: 974 case Primitive::kPrimByte: 975 case Primitive::kPrimChar: 976 case Primitive::kPrimShort: 977 case Primitive::kPrimInt: 978 case Primitive::kPrimNot: 979 case Primitive::kPrimFloat: 980 locations->SetOut(Location::RegisterLocation(R0)); 981 break; 982 983 case Primitive::kPrimLong: 984 case Primitive::kPrimDouble: 985 locations->SetOut(Location::RegisterPairLocation(R0, R1)); 986 break; 987 988 case Primitive::kPrimVoid: 989 break; 990 } 991} 992 993 994void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) { 995 Register temp = invoke->GetLocations()->GetTemp(0).As<Register>(); 996 uint32_t method_offset = mirror::Class::EmbeddedVTableOffset().Uint32Value() + 997 invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry); 998 LocationSummary* locations = invoke->GetLocations(); 999 Location receiver = locations->InAt(0); 1000 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value(); 1001 // temp = object->GetClass(); 1002 if (receiver.IsStackSlot()) { 1003 __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex()); 1004 __ LoadFromOffset(kLoadWord, temp, temp, class_offset); 1005 } else { 1006 __ LoadFromOffset(kLoadWord, temp, receiver.As<Register>(), class_offset); 1007 } 1008 // temp = temp->GetMethodAt(method_offset); 1009 uint32_t entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value(); 1010 __ LoadFromOffset(kLoadWord, temp, temp, method_offset); 1011 // LR = temp->GetEntryPoint(); 1012 __ LoadFromOffset(kLoadWord, LR, temp, entry_point); 1013 // LR(); 1014 __ blx(LR); 1015 DCHECK(!codegen_->IsLeafMethod()); 1016 codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); 1017} 1018 1019void LocationsBuilderARM::VisitAdd(HAdd* add) { 1020 LocationSummary* locations = 1021 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall); 1022 switch (add->GetResultType()) { 1023 case Primitive::kPrimInt: 1024 case Primitive::kPrimLong: { 1025 bool output_overlaps = (add->GetResultType() == Primitive::kPrimLong); 1026 locations->SetInAt(0, Location::RequiresRegister()); 1027 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1))); 1028 locations->SetOut(Location::RequiresRegister(), output_overlaps); 1029 break; 1030 } 1031 1032 case Primitive::kPrimFloat: 1033 case Primitive::kPrimDouble: { 1034 locations->SetInAt(0, Location::RequiresFpuRegister()); 1035 locations->SetInAt(1, Location::RequiresFpuRegister()); 1036 locations->SetOut(Location::RequiresFpuRegister()); 1037 break; 1038 } 1039 1040 default: 1041 LOG(FATAL) << "Unexpected add type " << add->GetResultType(); 1042 } 1043} 1044 1045void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) { 1046 LocationSummary* locations = add->GetLocations(); 1047 Location out = locations->Out(); 1048 Location first = locations->InAt(0); 1049 Location second = locations->InAt(1); 1050 switch (add->GetResultType()) { 1051 case Primitive::kPrimInt: 1052 if (second.IsRegister()) { 1053 __ add(out.As<Register>(), first.As<Register>(), ShifterOperand(second.As<Register>())); 1054 } else { 1055 __ AddConstant(out.As<Register>(), 1056 first.As<Register>(), 1057 second.GetConstant()->AsIntConstant()->GetValue()); 1058 } 1059 break; 1060 1061 case Primitive::kPrimLong: 1062 __ adds(out.AsRegisterPairLow<Register>(), 1063 first.AsRegisterPairLow<Register>(), 1064 ShifterOperand(second.AsRegisterPairLow<Register>())); 1065 __ adc(out.AsRegisterPairHigh<Register>(), 1066 first.AsRegisterPairHigh<Register>(), 1067 ShifterOperand(second.AsRegisterPairHigh<Register>())); 1068 break; 1069 1070 case Primitive::kPrimFloat: 1071 __ vadds(FromDToLowS(out.As<DRegister>()), 1072 FromDToLowS(first.As<DRegister>()), 1073 FromDToLowS(second.As<DRegister>())); 1074 break; 1075 1076 case Primitive::kPrimDouble: 1077 __ vaddd(out.As<DRegister>(), first.As<DRegister>(), second.As<DRegister>()); 1078 break; 1079 1080 default: 1081 LOG(FATAL) << "Unexpected add type " << add->GetResultType(); 1082 } 1083} 1084 1085void LocationsBuilderARM::VisitSub(HSub* sub) { 1086 LocationSummary* locations = 1087 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall); 1088 switch (sub->GetResultType()) { 1089 case Primitive::kPrimInt: 1090 case Primitive::kPrimLong: { 1091 bool output_overlaps = (sub->GetResultType() == Primitive::kPrimLong); 1092 locations->SetInAt(0, Location::RequiresRegister()); 1093 locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1))); 1094 locations->SetOut(Location::RequiresRegister(), output_overlaps); 1095 break; 1096 } 1097 1098 case Primitive::kPrimBoolean: 1099 case Primitive::kPrimByte: 1100 case Primitive::kPrimChar: 1101 case Primitive::kPrimShort: 1102 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType(); 1103 break; 1104 1105 default: 1106 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType(); 1107 } 1108} 1109 1110void InstructionCodeGeneratorARM::VisitSub(HSub* sub) { 1111 LocationSummary* locations = sub->GetLocations(); 1112 switch (sub->GetResultType()) { 1113 case Primitive::kPrimInt: { 1114 if (locations->InAt(1).IsRegister()) { 1115 __ sub(locations->Out().As<Register>(), 1116 locations->InAt(0).As<Register>(), 1117 ShifterOperand(locations->InAt(1).As<Register>())); 1118 } else { 1119 __ AddConstant(locations->Out().As<Register>(), 1120 locations->InAt(0).As<Register>(), 1121 -locations->InAt(1).GetConstant()->AsIntConstant()->GetValue()); 1122 } 1123 break; 1124 } 1125 1126 case Primitive::kPrimLong: 1127 __ subs(locations->Out().AsRegisterPairLow<Register>(), 1128 locations->InAt(0).AsRegisterPairLow<Register>(), 1129 ShifterOperand(locations->InAt(1).AsRegisterPairLow<Register>())); 1130 __ sbc(locations->Out().AsRegisterPairHigh<Register>(), 1131 locations->InAt(0).AsRegisterPairHigh<Register>(), 1132 ShifterOperand(locations->InAt(1).AsRegisterPairHigh<Register>())); 1133 break; 1134 1135 case Primitive::kPrimBoolean: 1136 case Primitive::kPrimByte: 1137 case Primitive::kPrimChar: 1138 case Primitive::kPrimShort: 1139 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType(); 1140 break; 1141 1142 default: 1143 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType(); 1144 } 1145} 1146 1147void LocationsBuilderARM::VisitMul(HMul* mul) { 1148 LocationSummary* locations = 1149 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall); 1150 switch (mul->GetResultType()) { 1151 case Primitive::kPrimInt: 1152 case Primitive::kPrimLong: { 1153 locations->SetInAt(0, Location::RequiresRegister()); 1154 locations->SetInAt(1, Location::RequiresRegister()); 1155 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 1156 break; 1157 } 1158 1159 case Primitive::kPrimBoolean: 1160 case Primitive::kPrimByte: 1161 case Primitive::kPrimChar: 1162 case Primitive::kPrimShort: 1163 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType(); 1164 break; 1165 1166 default: 1167 LOG(FATAL) << "Unimplemented mul type " << mul->GetResultType(); 1168 } 1169} 1170 1171void InstructionCodeGeneratorARM::VisitMul(HMul* mul) { 1172 LocationSummary* locations = mul->GetLocations(); 1173 Location out = locations->Out(); 1174 Location first = locations->InAt(0); 1175 Location second = locations->InAt(1); 1176 switch (mul->GetResultType()) { 1177 case Primitive::kPrimInt: { 1178 __ mul(out.As<Register>(), first.As<Register>(), second.As<Register>()); 1179 break; 1180 } 1181 case Primitive::kPrimLong: { 1182 Register out_hi = out.AsRegisterPairHigh<Register>(); 1183 Register out_lo = out.AsRegisterPairLow<Register>(); 1184 Register in1_hi = first.AsRegisterPairHigh<Register>(); 1185 Register in1_lo = first.AsRegisterPairLow<Register>(); 1186 Register in2_hi = second.AsRegisterPairHigh<Register>(); 1187 Register in2_lo = second.AsRegisterPairLow<Register>(); 1188 1189 // Extra checks to protect caused by the existence of R1_R2. 1190 // The algorithm is wrong if out.hi is either in1.lo or in2.lo: 1191 // (e.g. in1=r0_r1, in2=r2_r3 and out=r1_r2); 1192 DCHECK_NE(out_hi, in1_lo); 1193 DCHECK_NE(out_hi, in2_lo); 1194 1195 // input: in1 - 64 bits, in2 - 64 bits 1196 // output: out 1197 // formula: out.hi : out.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo 1198 // parts: out.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32] 1199 // parts: out.lo = (in1.lo * in2.lo)[31:0] 1200 1201 // IP <- in1.lo * in2.hi 1202 __ mul(IP, in1_lo, in2_hi); 1203 // out.hi <- in1.lo * in2.hi + in1.hi * in2.lo 1204 __ mla(out_hi, in1_hi, in2_lo, IP); 1205 // out.lo <- (in1.lo * in2.lo)[31:0]; 1206 __ umull(out_lo, IP, in1_lo, in2_lo); 1207 // out.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32] 1208 __ add(out_hi, out_hi, ShifterOperand(IP)); 1209 break; 1210 } 1211 case Primitive::kPrimBoolean: 1212 case Primitive::kPrimByte: 1213 case Primitive::kPrimChar: 1214 case Primitive::kPrimShort: 1215 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType(); 1216 break; 1217 1218 default: 1219 LOG(FATAL) << "Unimplemented mul type " << mul->GetResultType(); 1220 } 1221} 1222 1223void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) { 1224 LocationSummary* locations = 1225 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall); 1226 InvokeRuntimeCallingConvention calling_convention; 1227 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 1228 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 1229 locations->SetOut(Location::RegisterLocation(R0)); 1230} 1231 1232void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) { 1233 InvokeRuntimeCallingConvention calling_convention; 1234 LoadCurrentMethod(calling_convention.GetRegisterAt(1)); 1235 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex()); 1236 1237 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocObjectWithAccessCheck).Int32Value(); 1238 __ LoadFromOffset(kLoadWord, LR, TR, offset); 1239 __ blx(LR); 1240 1241 codegen_->RecordPcInfo(instruction, instruction->GetDexPc()); 1242 DCHECK(!codegen_->IsLeafMethod()); 1243} 1244 1245void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) { 1246 LocationSummary* locations = 1247 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 1248 Location location = parameter_visitor_.GetNextLocation(instruction->GetType()); 1249 if (location.IsStackSlot()) { 1250 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize()); 1251 } else if (location.IsDoubleStackSlot()) { 1252 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize()); 1253 } 1254 locations->SetOut(location); 1255} 1256 1257void InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instruction) { 1258 // Nothing to do, the parameter is already at its location. 1259} 1260 1261void LocationsBuilderARM::VisitNot(HNot* instruction) { 1262 LocationSummary* locations = 1263 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 1264 locations->SetInAt(0, Location::RequiresRegister()); 1265 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 1266} 1267 1268void InstructionCodeGeneratorARM::VisitNot(HNot* instruction) { 1269 LocationSummary* locations = instruction->GetLocations(); 1270 __ eor(locations->Out().As<Register>(), 1271 locations->InAt(0).As<Register>(), ShifterOperand(1)); 1272} 1273 1274void LocationsBuilderARM::VisitCompare(HCompare* compare) { 1275 LocationSummary* locations = 1276 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall); 1277 locations->SetInAt(0, Location::RequiresRegister()); 1278 locations->SetInAt(1, Location::RequiresRegister()); 1279 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 1280} 1281 1282void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) { 1283 Label greater, done; 1284 LocationSummary* locations = compare->GetLocations(); 1285 switch (compare->InputAt(0)->GetType()) { 1286 case Primitive::kPrimLong: { 1287 Register output = locations->Out().As<Register>(); 1288 Location left = locations->InAt(0); 1289 Location right = locations->InAt(1); 1290 Label less, greater, done; 1291 __ cmp(left.AsRegisterPairHigh<Register>(), 1292 ShifterOperand(right.AsRegisterPairHigh<Register>())); // Signed compare. 1293 __ b(&less, LT); 1294 __ b(&greater, GT); 1295 // Do LoadImmediate before any `cmp`, as LoadImmediate might affect 1296 // the status flags. 1297 __ LoadImmediate(output, 0); 1298 __ cmp(left.AsRegisterPairLow<Register>(), 1299 ShifterOperand(right.AsRegisterPairLow<Register>())); // Unsigned compare. 1300 __ b(&done, EQ); 1301 __ b(&less, CC); 1302 1303 __ Bind(&greater); 1304 __ LoadImmediate(output, 1); 1305 __ b(&done); 1306 1307 __ Bind(&less); 1308 __ LoadImmediate(output, -1); 1309 1310 __ Bind(&done); 1311 break; 1312 } 1313 default: 1314 LOG(FATAL) << "Unimplemented compare type " << compare->InputAt(0)->GetType(); 1315 } 1316} 1317 1318void LocationsBuilderARM::VisitPhi(HPhi* instruction) { 1319 LocationSummary* locations = 1320 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 1321 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) { 1322 locations->SetInAt(i, Location::Any()); 1323 } 1324 locations->SetOut(Location::Any()); 1325} 1326 1327void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) { 1328 LOG(FATAL) << "Unreachable"; 1329} 1330 1331void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) { 1332 LocationSummary* locations = 1333 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 1334 bool is_object_type = instruction->GetFieldType() == Primitive::kPrimNot; 1335 locations->SetInAt(0, Location::RequiresRegister()); 1336 locations->SetInAt(1, Location::RequiresRegister()); 1337 // Temporary registers for the write barrier. 1338 if (is_object_type) { 1339 locations->AddTemp(Location::RequiresRegister()); 1340 locations->AddTemp(Location::RequiresRegister()); 1341 } 1342} 1343 1344void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) { 1345 LocationSummary* locations = instruction->GetLocations(); 1346 Register obj = locations->InAt(0).As<Register>(); 1347 uint32_t offset = instruction->GetFieldOffset().Uint32Value(); 1348 Primitive::Type field_type = instruction->GetFieldType(); 1349 1350 switch (field_type) { 1351 case Primitive::kPrimBoolean: 1352 case Primitive::kPrimByte: { 1353 Register value = locations->InAt(1).As<Register>(); 1354 __ StoreToOffset(kStoreByte, value, obj, offset); 1355 break; 1356 } 1357 1358 case Primitive::kPrimShort: 1359 case Primitive::kPrimChar: { 1360 Register value = locations->InAt(1).As<Register>(); 1361 __ StoreToOffset(kStoreHalfword, value, obj, offset); 1362 break; 1363 } 1364 1365 case Primitive::kPrimInt: 1366 case Primitive::kPrimNot: { 1367 Register value = locations->InAt(1).As<Register>(); 1368 __ StoreToOffset(kStoreWord, value, obj, offset); 1369 if (field_type == Primitive::kPrimNot) { 1370 Register temp = locations->GetTemp(0).As<Register>(); 1371 Register card = locations->GetTemp(1).As<Register>(); 1372 codegen_->MarkGCCard(temp, card, obj, value); 1373 } 1374 break; 1375 } 1376 1377 case Primitive::kPrimLong: { 1378 Location value = locations->InAt(1); 1379 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), obj, offset); 1380 break; 1381 } 1382 1383 case Primitive::kPrimFloat: 1384 case Primitive::kPrimDouble: 1385 LOG(FATAL) << "Unimplemented register type " << field_type; 1386 UNREACHABLE(); 1387 case Primitive::kPrimVoid: 1388 LOG(FATAL) << "Unreachable type " << field_type; 1389 UNREACHABLE(); 1390 } 1391} 1392 1393void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) { 1394 LocationSummary* locations = 1395 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 1396 locations->SetInAt(0, Location::RequiresRegister()); 1397 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 1398} 1399 1400void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) { 1401 LocationSummary* locations = instruction->GetLocations(); 1402 Register obj = locations->InAt(0).As<Register>(); 1403 uint32_t offset = instruction->GetFieldOffset().Uint32Value(); 1404 1405 switch (instruction->GetType()) { 1406 case Primitive::kPrimBoolean: { 1407 Register out = locations->Out().As<Register>(); 1408 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset); 1409 break; 1410 } 1411 1412 case Primitive::kPrimByte: { 1413 Register out = locations->Out().As<Register>(); 1414 __ LoadFromOffset(kLoadSignedByte, out, obj, offset); 1415 break; 1416 } 1417 1418 case Primitive::kPrimShort: { 1419 Register out = locations->Out().As<Register>(); 1420 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset); 1421 break; 1422 } 1423 1424 case Primitive::kPrimChar: { 1425 Register out = locations->Out().As<Register>(); 1426 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset); 1427 break; 1428 } 1429 1430 case Primitive::kPrimInt: 1431 case Primitive::kPrimNot: { 1432 Register out = locations->Out().As<Register>(); 1433 __ LoadFromOffset(kLoadWord, out, obj, offset); 1434 break; 1435 } 1436 1437 case Primitive::kPrimLong: { 1438 // TODO: support volatile. 1439 Location out = locations->Out(); 1440 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), obj, offset); 1441 break; 1442 } 1443 1444 case Primitive::kPrimFloat: 1445 case Primitive::kPrimDouble: 1446 LOG(FATAL) << "Unimplemented register type " << instruction->GetType(); 1447 UNREACHABLE(); 1448 case Primitive::kPrimVoid: 1449 LOG(FATAL) << "Unreachable type " << instruction->GetType(); 1450 UNREACHABLE(); 1451 } 1452} 1453 1454void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) { 1455 LocationSummary* locations = 1456 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 1457 locations->SetInAt(0, Location::RequiresRegister()); 1458 if (instruction->HasUses()) { 1459 locations->SetOut(Location::SameAsFirstInput()); 1460 } 1461} 1462 1463void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) { 1464 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction); 1465 codegen_->AddSlowPath(slow_path); 1466 1467 LocationSummary* locations = instruction->GetLocations(); 1468 Location obj = locations->InAt(0); 1469 1470 if (obj.IsRegister()) { 1471 __ cmp(obj.As<Register>(), ShifterOperand(0)); 1472 __ b(slow_path->GetEntryLabel(), EQ); 1473 } else { 1474 DCHECK(obj.IsConstant()) << obj; 1475 DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0); 1476 __ b(slow_path->GetEntryLabel()); 1477 } 1478} 1479 1480void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) { 1481 LocationSummary* locations = 1482 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 1483 locations->SetInAt(0, Location::RequiresRegister()); 1484 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1))); 1485 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 1486} 1487 1488void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) { 1489 LocationSummary* locations = instruction->GetLocations(); 1490 Register obj = locations->InAt(0).As<Register>(); 1491 Location index = locations->InAt(1); 1492 1493 switch (instruction->GetType()) { 1494 case Primitive::kPrimBoolean: { 1495 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value(); 1496 Register out = locations->Out().As<Register>(); 1497 if (index.IsConstant()) { 1498 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset; 1499 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset); 1500 } else { 1501 __ add(IP, obj, ShifterOperand(index.As<Register>())); 1502 __ LoadFromOffset(kLoadUnsignedByte, out, IP, data_offset); 1503 } 1504 break; 1505 } 1506 1507 case Primitive::kPrimByte: { 1508 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value(); 1509 Register out = locations->Out().As<Register>(); 1510 if (index.IsConstant()) { 1511 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset; 1512 __ LoadFromOffset(kLoadSignedByte, out, obj, offset); 1513 } else { 1514 __ add(IP, obj, ShifterOperand(index.As<Register>())); 1515 __ LoadFromOffset(kLoadSignedByte, out, IP, data_offset); 1516 } 1517 break; 1518 } 1519 1520 case Primitive::kPrimShort: { 1521 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value(); 1522 Register out = locations->Out().As<Register>(); 1523 if (index.IsConstant()) { 1524 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset; 1525 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset); 1526 } else { 1527 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_2)); 1528 __ LoadFromOffset(kLoadSignedHalfword, out, IP, data_offset); 1529 } 1530 break; 1531 } 1532 1533 case Primitive::kPrimChar: { 1534 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value(); 1535 Register out = locations->Out().As<Register>(); 1536 if (index.IsConstant()) { 1537 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset; 1538 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset); 1539 } else { 1540 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_2)); 1541 __ LoadFromOffset(kLoadUnsignedHalfword, out, IP, data_offset); 1542 } 1543 break; 1544 } 1545 1546 case Primitive::kPrimInt: 1547 case Primitive::kPrimNot: { 1548 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t)); 1549 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value(); 1550 Register out = locations->Out().As<Register>(); 1551 if (index.IsConstant()) { 1552 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset; 1553 __ LoadFromOffset(kLoadWord, out, obj, offset); 1554 } else { 1555 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_4)); 1556 __ LoadFromOffset(kLoadWord, out, IP, data_offset); 1557 } 1558 break; 1559 } 1560 1561 case Primitive::kPrimLong: { 1562 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value(); 1563 Location out = locations->Out(); 1564 if (index.IsConstant()) { 1565 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset; 1566 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), obj, offset); 1567 } else { 1568 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_8)); 1569 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), IP, data_offset); 1570 } 1571 break; 1572 } 1573 1574 case Primitive::kPrimFloat: 1575 case Primitive::kPrimDouble: 1576 LOG(FATAL) << "Unimplemented register type " << instruction->GetType(); 1577 UNREACHABLE(); 1578 case Primitive::kPrimVoid: 1579 LOG(FATAL) << "Unreachable type " << instruction->GetType(); 1580 UNREACHABLE(); 1581 } 1582} 1583 1584void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) { 1585 Primitive::Type value_type = instruction->GetComponentType(); 1586 bool is_object = value_type == Primitive::kPrimNot; 1587 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary( 1588 instruction, is_object ? LocationSummary::kCall : LocationSummary::kNoCall); 1589 if (is_object) { 1590 InvokeRuntimeCallingConvention calling_convention; 1591 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 1592 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 1593 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2))); 1594 } else { 1595 locations->SetInAt(0, Location::RequiresRegister()); 1596 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1))); 1597 locations->SetInAt(2, Location::RequiresRegister()); 1598 } 1599} 1600 1601void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) { 1602 LocationSummary* locations = instruction->GetLocations(); 1603 Register obj = locations->InAt(0).As<Register>(); 1604 Location index = locations->InAt(1); 1605 Primitive::Type value_type = instruction->GetComponentType(); 1606 1607 switch (value_type) { 1608 case Primitive::kPrimBoolean: 1609 case Primitive::kPrimByte: { 1610 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value(); 1611 Register value = locations->InAt(2).As<Register>(); 1612 if (index.IsConstant()) { 1613 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset; 1614 __ StoreToOffset(kStoreByte, value, obj, offset); 1615 } else { 1616 __ add(IP, obj, ShifterOperand(index.As<Register>())); 1617 __ StoreToOffset(kStoreByte, value, IP, data_offset); 1618 } 1619 break; 1620 } 1621 1622 case Primitive::kPrimShort: 1623 case Primitive::kPrimChar: { 1624 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value(); 1625 Register value = locations->InAt(2).As<Register>(); 1626 if (index.IsConstant()) { 1627 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset; 1628 __ StoreToOffset(kStoreHalfword, value, obj, offset); 1629 } else { 1630 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_2)); 1631 __ StoreToOffset(kStoreHalfword, value, IP, data_offset); 1632 } 1633 break; 1634 } 1635 1636 case Primitive::kPrimInt: { 1637 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value(); 1638 Register value = locations->InAt(2).As<Register>(); 1639 if (index.IsConstant()) { 1640 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset; 1641 __ StoreToOffset(kStoreWord, value, obj, offset); 1642 } else { 1643 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_4)); 1644 __ StoreToOffset(kStoreWord, value, IP, data_offset); 1645 } 1646 break; 1647 } 1648 1649 case Primitive::kPrimNot: { 1650 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAputObject).Int32Value(); 1651 __ LoadFromOffset(kLoadWord, LR, TR, offset); 1652 __ blx(LR); 1653 codegen_->RecordPcInfo(instruction, instruction->GetDexPc()); 1654 DCHECK(!codegen_->IsLeafMethod()); 1655 break; 1656 } 1657 1658 case Primitive::kPrimLong: { 1659 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value(); 1660 Location value = locations->InAt(2); 1661 if (index.IsConstant()) { 1662 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset; 1663 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), obj, offset); 1664 } else { 1665 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_8)); 1666 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), IP, data_offset); 1667 } 1668 break; 1669 } 1670 1671 case Primitive::kPrimFloat: 1672 case Primitive::kPrimDouble: 1673 LOG(FATAL) << "Unimplemented register type " << instruction->GetType(); 1674 UNREACHABLE(); 1675 case Primitive::kPrimVoid: 1676 LOG(FATAL) << "Unreachable type " << instruction->GetType(); 1677 UNREACHABLE(); 1678 } 1679} 1680 1681void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) { 1682 LocationSummary* locations = 1683 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 1684 locations->SetInAt(0, Location::RequiresRegister()); 1685 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 1686} 1687 1688void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) { 1689 LocationSummary* locations = instruction->GetLocations(); 1690 uint32_t offset = mirror::Array::LengthOffset().Uint32Value(); 1691 Register obj = locations->InAt(0).As<Register>(); 1692 Register out = locations->Out().As<Register>(); 1693 __ LoadFromOffset(kLoadWord, out, obj, offset); 1694} 1695 1696void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) { 1697 LocationSummary* locations = 1698 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 1699 locations->SetInAt(0, Location::RequiresRegister()); 1700 locations->SetInAt(1, Location::RequiresRegister()); 1701 if (instruction->HasUses()) { 1702 locations->SetOut(Location::SameAsFirstInput()); 1703 } 1704} 1705 1706void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) { 1707 LocationSummary* locations = instruction->GetLocations(); 1708 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM( 1709 instruction, locations->InAt(0), locations->InAt(1)); 1710 codegen_->AddSlowPath(slow_path); 1711 1712 Register index = locations->InAt(0).As<Register>(); 1713 Register length = locations->InAt(1).As<Register>(); 1714 1715 __ cmp(index, ShifterOperand(length)); 1716 __ b(slow_path->GetEntryLabel(), CS); 1717} 1718 1719void CodeGeneratorARM::MarkGCCard(Register temp, Register card, Register object, Register value) { 1720 Label is_null; 1721 __ CompareAndBranchIfZero(value, &is_null); 1722 __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value()); 1723 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift); 1724 __ strb(card, Address(card, temp)); 1725 __ Bind(&is_null); 1726} 1727 1728void LocationsBuilderARM::VisitTemporary(HTemporary* temp) { 1729 temp->SetLocations(nullptr); 1730} 1731 1732void InstructionCodeGeneratorARM::VisitTemporary(HTemporary* temp) { 1733 // Nothing to do, this is driven by the code generator. 1734} 1735 1736void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction) { 1737 LOG(FATAL) << "Unreachable"; 1738} 1739 1740void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) { 1741 codegen_->GetMoveResolver()->EmitNativeCode(instruction); 1742} 1743 1744void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) { 1745 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath); 1746} 1747 1748void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) { 1749 HBasicBlock* block = instruction->GetBlock(); 1750 if (block->GetLoopInformation() != nullptr) { 1751 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction); 1752 // The back edge will generate the suspend check. 1753 return; 1754 } 1755 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) { 1756 // The goto will generate the suspend check. 1757 return; 1758 } 1759 GenerateSuspendCheck(instruction, nullptr); 1760} 1761 1762void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction, 1763 HBasicBlock* successor) { 1764 SuspendCheckSlowPathARM* slow_path = 1765 new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor); 1766 codegen_->AddSlowPath(slow_path); 1767 1768 __ subs(R4, R4, ShifterOperand(1)); 1769 if (successor == nullptr) { 1770 __ b(slow_path->GetEntryLabel(), EQ); 1771 __ Bind(slow_path->GetReturnLabel()); 1772 } else { 1773 __ b(codegen_->GetLabelOf(successor), NE); 1774 __ b(slow_path->GetEntryLabel()); 1775 } 1776} 1777 1778ArmAssembler* ParallelMoveResolverARM::GetAssembler() const { 1779 return codegen_->GetAssembler(); 1780} 1781 1782void ParallelMoveResolverARM::EmitMove(size_t index) { 1783 MoveOperands* move = moves_.Get(index); 1784 Location source = move->GetSource(); 1785 Location destination = move->GetDestination(); 1786 1787 if (source.IsRegister()) { 1788 if (destination.IsRegister()) { 1789 __ Mov(destination.As<Register>(), source.As<Register>()); 1790 } else { 1791 DCHECK(destination.IsStackSlot()); 1792 __ StoreToOffset(kStoreWord, source.As<Register>(), 1793 SP, destination.GetStackIndex()); 1794 } 1795 } else if (source.IsStackSlot()) { 1796 if (destination.IsRegister()) { 1797 __ LoadFromOffset(kLoadWord, destination.As<Register>(), 1798 SP, source.GetStackIndex()); 1799 } else { 1800 DCHECK(destination.IsStackSlot()); 1801 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex()); 1802 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex()); 1803 } 1804 } else { 1805 DCHECK(source.IsConstant()); 1806 DCHECK(source.GetConstant()->IsIntConstant()); 1807 int32_t value = source.GetConstant()->AsIntConstant()->GetValue(); 1808 if (destination.IsRegister()) { 1809 __ LoadImmediate(destination.As<Register>(), value); 1810 } else { 1811 DCHECK(destination.IsStackSlot()); 1812 __ LoadImmediate(IP, value); 1813 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex()); 1814 } 1815 } 1816} 1817 1818void ParallelMoveResolverARM::Exchange(Register reg, int mem) { 1819 __ Mov(IP, reg); 1820 __ LoadFromOffset(kLoadWord, reg, SP, mem); 1821 __ StoreToOffset(kStoreWord, IP, SP, mem); 1822} 1823 1824void ParallelMoveResolverARM::Exchange(int mem1, int mem2) { 1825 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters()); 1826 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0; 1827 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()), 1828 SP, mem1 + stack_offset); 1829 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset); 1830 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()), 1831 SP, mem2 + stack_offset); 1832 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset); 1833} 1834 1835void ParallelMoveResolverARM::EmitSwap(size_t index) { 1836 MoveOperands* move = moves_.Get(index); 1837 Location source = move->GetSource(); 1838 Location destination = move->GetDestination(); 1839 1840 if (source.IsRegister() && destination.IsRegister()) { 1841 DCHECK_NE(source.As<Register>(), IP); 1842 DCHECK_NE(destination.As<Register>(), IP); 1843 __ Mov(IP, source.As<Register>()); 1844 __ Mov(source.As<Register>(), destination.As<Register>()); 1845 __ Mov(destination.As<Register>(), IP); 1846 } else if (source.IsRegister() && destination.IsStackSlot()) { 1847 Exchange(source.As<Register>(), destination.GetStackIndex()); 1848 } else if (source.IsStackSlot() && destination.IsRegister()) { 1849 Exchange(destination.As<Register>(), source.GetStackIndex()); 1850 } else if (source.IsStackSlot() && destination.IsStackSlot()) { 1851 Exchange(source.GetStackIndex(), destination.GetStackIndex()); 1852 } else { 1853 LOG(FATAL) << "Unimplemented"; 1854 } 1855} 1856 1857void ParallelMoveResolverARM::SpillScratch(int reg) { 1858 __ Push(static_cast<Register>(reg)); 1859} 1860 1861void ParallelMoveResolverARM::RestoreScratch(int reg) { 1862 __ Pop(static_cast<Register>(reg)); 1863} 1864 1865} // namespace arm 1866} // namespace art 1867