1 /* 2 * Copyright (C) 2023 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 #ifndef ART_COMPILER_OPTIMIZING_CODE_GENERATOR_RISCV64_H_ 18 #define ART_COMPILER_OPTIMIZING_CODE_GENERATOR_RISCV64_H_ 19 20 #include "android-base/logging.h" 21 #include "arch/riscv64/registers_riscv64.h" 22 #include "base/macros.h" 23 #include "code_generator.h" 24 #include "driver/compiler_options.h" 25 #include "intrinsics_list.h" 26 #include "optimizing/locations.h" 27 #include "parallel_move_resolver.h" 28 #include "utils/riscv64/assembler_riscv64.h" 29 30 namespace art HIDDEN { 31 namespace riscv64 { 32 33 // InvokeDexCallingConvention registers 34 static constexpr XRegister kParameterCoreRegisters[] = {A1, A2, A3, A4, A5, A6, A7}; 35 static constexpr size_t kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters); 36 37 static constexpr FRegister kParameterFpuRegisters[] = {FA0, FA1, FA2, FA3, FA4, FA5, FA6, FA7}; 38 static constexpr size_t kParameterFpuRegistersLength = arraysize(kParameterFpuRegisters); 39 40 // InvokeRuntimeCallingConvention registers 41 static constexpr XRegister kRuntimeParameterCoreRegisters[] = {A0, A1, A2, A3, A4, A5, A6, A7}; 42 static constexpr size_t kRuntimeParameterCoreRegistersLength = 43 arraysize(kRuntimeParameterCoreRegisters); 44 45 static constexpr FRegister kRuntimeParameterFpuRegisters[] = { 46 FA0, FA1, FA2, FA3, FA4, FA5, FA6, FA7 47 }; 48 static constexpr size_t kRuntimeParameterFpuRegistersLength = 49 arraysize(kRuntimeParameterFpuRegisters); 50 51 // FCLASS returns a 10-bit classification mask with the two highest bits marking NaNs 52 // (signaling and quiet). To detect a NaN, we can compare (either BGE or BGEU, the sign 53 // bit is always clear) the result with the `kFClassNaNMinValue`. 54 static_assert(kSignalingNaN == 0x100); 55 static_assert(kQuietNaN == 0x200); 56 static constexpr int32_t kFClassNaNMinValue = 0x100; 57 58 #define UNIMPLEMENTED_INTRINSIC_LIST_RISCV64(V) \ 59 V(SystemArrayCopyByte) \ 60 V(SystemArrayCopyChar) \ 61 V(SystemArrayCopyInt) \ 62 V(FP16Ceil) \ 63 V(FP16Compare) \ 64 V(FP16Floor) \ 65 V(FP16Rint) \ 66 V(FP16ToFloat) \ 67 V(FP16ToHalf) \ 68 V(FP16Greater) \ 69 V(FP16GreaterEquals) \ 70 V(FP16Less) \ 71 V(FP16LessEquals) \ 72 V(FP16Min) \ 73 V(FP16Max) \ 74 V(StringStringIndexOf) \ 75 V(StringStringIndexOfAfter) \ 76 V(StringBufferAppend) \ 77 V(StringBufferLength) \ 78 V(StringBufferToString) \ 79 V(StringBuilderAppendObject) \ 80 V(StringBuilderAppendString) \ 81 V(StringBuilderAppendCharSequence) \ 82 V(StringBuilderAppendCharArray) \ 83 V(StringBuilderAppendBoolean) \ 84 V(StringBuilderAppendChar) \ 85 V(StringBuilderAppendInt) \ 86 V(StringBuilderAppendLong) \ 87 V(StringBuilderAppendFloat) \ 88 V(StringBuilderAppendDouble) \ 89 V(StringBuilderLength) \ 90 V(StringBuilderToString) \ 91 V(CRC32Update) \ 92 V(CRC32UpdateBytes) \ 93 V(CRC32UpdateByteBuffer) \ 94 V(MethodHandleInvokeExact) \ 95 V(MethodHandleInvoke) 96 97 // Method register on invoke. 98 static const XRegister kArtMethodRegister = A0; 99 100 // Helper functions used by codegen as well as intrinsics. 101 XRegister InputXRegisterOrZero(Location location); 102 int32_t ReadBarrierMarkEntrypointOffset(Location ref); 103 104 class CodeGeneratorRISCV64; 105 106 class InvokeRuntimeCallingConvention : public CallingConvention<XRegister, FRegister> { 107 public: InvokeRuntimeCallingConvention()108 InvokeRuntimeCallingConvention() 109 : CallingConvention(kRuntimeParameterCoreRegisters, 110 kRuntimeParameterCoreRegistersLength, 111 kRuntimeParameterFpuRegisters, 112 kRuntimeParameterFpuRegistersLength, 113 kRiscv64PointerSize) {} 114 115 Location GetReturnLocation(DataType::Type return_type); 116 117 private: 118 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention); 119 }; 120 121 class InvokeDexCallingConvention : public CallingConvention<XRegister, FRegister> { 122 public: InvokeDexCallingConvention()123 InvokeDexCallingConvention() 124 : CallingConvention(kParameterCoreRegisters, 125 kParameterCoreRegistersLength, 126 kParameterFpuRegisters, 127 kParameterFpuRegistersLength, 128 kRiscv64PointerSize) {} 129 130 private: 131 DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConvention); 132 }; 133 134 class InvokeDexCallingConventionVisitorRISCV64 : public InvokeDexCallingConventionVisitor { 135 public: InvokeDexCallingConventionVisitorRISCV64()136 InvokeDexCallingConventionVisitorRISCV64() {} ~InvokeDexCallingConventionVisitorRISCV64()137 virtual ~InvokeDexCallingConventionVisitorRISCV64() {} 138 139 Location GetNextLocation(DataType::Type type) override; 140 Location GetReturnLocation(DataType::Type type) const override; 141 Location GetMethodLocation() const override; 142 143 private: 144 InvokeDexCallingConvention calling_convention; 145 146 DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConventionVisitorRISCV64); 147 }; 148 149 class CriticalNativeCallingConventionVisitorRiscv64 : public InvokeDexCallingConventionVisitor { 150 public: CriticalNativeCallingConventionVisitorRiscv64(bool for_register_allocation)151 explicit CriticalNativeCallingConventionVisitorRiscv64(bool for_register_allocation) 152 : for_register_allocation_(for_register_allocation) {} 153 ~CriticalNativeCallingConventionVisitorRiscv64()154 virtual ~CriticalNativeCallingConventionVisitorRiscv64() {} 155 156 Location GetNextLocation(DataType::Type type) override; 157 Location GetReturnLocation(DataType::Type type) const override; 158 Location GetMethodLocation() const override; 159 GetStackOffset()160 size_t GetStackOffset() const { return stack_offset_; } 161 162 private: 163 // Register allocator does not support adjusting frame size, so we cannot provide final locations 164 // of stack arguments for register allocation. We ask the register allocator for any location and 165 // move these arguments to the right place after adjusting the SP when generating the call. 166 const bool for_register_allocation_; 167 size_t gpr_index_ = 0u; 168 size_t fpr_index_ = 0u; 169 size_t stack_offset_ = 0u; 170 171 DISALLOW_COPY_AND_ASSIGN(CriticalNativeCallingConventionVisitorRiscv64); 172 }; 173 174 class SlowPathCodeRISCV64 : public SlowPathCode { 175 public: SlowPathCodeRISCV64(HInstruction * instruction)176 explicit SlowPathCodeRISCV64(HInstruction* instruction) 177 : SlowPathCode(instruction), entry_label_(), exit_label_() {} 178 GetEntryLabel()179 Riscv64Label* GetEntryLabel() { return &entry_label_; } GetExitLabel()180 Riscv64Label* GetExitLabel() { return &exit_label_; } 181 182 private: 183 Riscv64Label entry_label_; 184 Riscv64Label exit_label_; 185 186 DISALLOW_COPY_AND_ASSIGN(SlowPathCodeRISCV64); 187 }; 188 189 class ParallelMoveResolverRISCV64 : public ParallelMoveResolverWithSwap { 190 public: ParallelMoveResolverRISCV64(ArenaAllocator * allocator,CodeGeneratorRISCV64 * codegen)191 ParallelMoveResolverRISCV64(ArenaAllocator* allocator, CodeGeneratorRISCV64* codegen) 192 : ParallelMoveResolverWithSwap(allocator), codegen_(codegen) {} 193 194 void EmitMove(size_t index) override; 195 void EmitSwap(size_t index) override; 196 void SpillScratch(int reg) override; 197 void RestoreScratch(int reg) override; 198 199 void Exchange(int index1, int index2, bool double_slot); 200 201 Riscv64Assembler* GetAssembler() const; 202 203 private: 204 CodeGeneratorRISCV64* const codegen_; 205 206 DISALLOW_COPY_AND_ASSIGN(ParallelMoveResolverRISCV64); 207 }; 208 209 class FieldAccessCallingConventionRISCV64 : public FieldAccessCallingConvention { 210 public: FieldAccessCallingConventionRISCV64()211 FieldAccessCallingConventionRISCV64() {} 212 GetObjectLocation()213 Location GetObjectLocation() const override { 214 return Location::RegisterLocation(A1); 215 } GetFieldIndexLocation()216 Location GetFieldIndexLocation() const override { 217 return Location::RegisterLocation(A0); 218 } GetReturnLocation(DataType::Type type ATTRIBUTE_UNUSED)219 Location GetReturnLocation(DataType::Type type ATTRIBUTE_UNUSED) const override { 220 return Location::RegisterLocation(A0); 221 } GetSetValueLocation(DataType::Type type ATTRIBUTE_UNUSED,bool is_instance)222 Location GetSetValueLocation(DataType::Type type ATTRIBUTE_UNUSED, 223 bool is_instance) const override { 224 return is_instance 225 ? Location::RegisterLocation(A2) 226 : Location::RegisterLocation(A1); 227 } GetFpuLocation(DataType::Type type ATTRIBUTE_UNUSED)228 Location GetFpuLocation(DataType::Type type ATTRIBUTE_UNUSED) const override { 229 return Location::FpuRegisterLocation(FA0); 230 } 231 232 private: 233 DISALLOW_COPY_AND_ASSIGN(FieldAccessCallingConventionRISCV64); 234 }; 235 236 class LocationsBuilderRISCV64 : public HGraphVisitor { 237 public: LocationsBuilderRISCV64(HGraph * graph,CodeGeneratorRISCV64 * codegen)238 LocationsBuilderRISCV64(HGraph* graph, CodeGeneratorRISCV64* codegen) 239 : HGraphVisitor(graph), codegen_(codegen) {} 240 241 #define DECLARE_VISIT_INSTRUCTION(name, super) void Visit##name(H##name* instr) override; 242 243 FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION) FOR_EACH_CONCRETE_INSTRUCTION_RISCV64(DECLARE_VISIT_INSTRUCTION)244 FOR_EACH_CONCRETE_INSTRUCTION_RISCV64(DECLARE_VISIT_INSTRUCTION) 245 246 #undef DECLARE_VISIT_INSTRUCTION 247 248 void VisitInstruction(HInstruction* instruction) override { 249 LOG(FATAL) << "Unreachable instruction " << instruction->DebugName() << " (id " 250 << instruction->GetId() << ")"; 251 } 252 253 protected: 254 void HandleInvoke(HInvoke* invoke); 255 void HandleBinaryOp(HBinaryOperation* operation); 256 void HandleCondition(HCondition* instruction); 257 void HandleShift(HBinaryOperation* operation); 258 void HandleFieldSet(HInstruction* instruction); 259 void HandleFieldGet(HInstruction* instruction); 260 261 InvokeDexCallingConventionVisitorRISCV64 parameter_visitor_; 262 263 CodeGeneratorRISCV64* const codegen_; 264 265 DISALLOW_COPY_AND_ASSIGN(LocationsBuilderRISCV64); 266 }; 267 268 class InstructionCodeGeneratorRISCV64 : public InstructionCodeGenerator { 269 public: 270 InstructionCodeGeneratorRISCV64(HGraph* graph, CodeGeneratorRISCV64* codegen); 271 272 #define DECLARE_VISIT_INSTRUCTION(name, super) void Visit##name(H##name* instr) override; 273 274 FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION) FOR_EACH_CONCRETE_INSTRUCTION_RISCV64(DECLARE_VISIT_INSTRUCTION)275 FOR_EACH_CONCRETE_INSTRUCTION_RISCV64(DECLARE_VISIT_INSTRUCTION) 276 277 #undef DECLARE_VISIT_INSTRUCTION 278 279 void VisitInstruction(HInstruction* instruction) override { 280 LOG(FATAL) << "Unreachable instruction " << instruction->DebugName() << " (id " 281 << instruction->GetId() << ")"; 282 } 283 GetAssembler()284 Riscv64Assembler* GetAssembler() const { return assembler_; } 285 286 void GenerateMemoryBarrier(MemBarrierKind kind); 287 288 void FAdd(FRegister rd, FRegister rs1, FRegister rs2, DataType::Type type); 289 void FClass(XRegister rd, FRegister rs1, DataType::Type type); 290 291 void Load(Location out, XRegister rs1, int32_t offset, DataType::Type type); 292 void Store(Location value, XRegister rs1, int32_t offset, DataType::Type type); 293 294 // Sequentially consistent store. Used for volatile fields and intrinsics. 295 // The `instruction` argument is for recording an implicit null check stack map with the 296 // store instruction which may not be the last instruction emitted by `StoreSeqCst()`. 297 void StoreSeqCst(Location value, 298 XRegister rs1, 299 int32_t offset, 300 DataType::Type type, 301 HInstruction* instruction = nullptr); 302 303 void ShNAdd(XRegister rd, XRegister rs1, XRegister rs2, DataType::Type type); 304 305 protected: 306 void GenerateClassInitializationCheck(SlowPathCodeRISCV64* slow_path, XRegister class_reg); 307 void GenerateBitstringTypeCheckCompare(HTypeCheckInstruction* check, XRegister temp); 308 void GenerateSuspendCheck(HSuspendCheck* check, HBasicBlock* successor); 309 void HandleBinaryOp(HBinaryOperation* operation); 310 void HandleCondition(HCondition* instruction); 311 void HandleShift(HBinaryOperation* operation); 312 void HandleFieldSet(HInstruction* instruction, 313 const FieldInfo& field_info, 314 bool value_can_be_null, 315 WriteBarrierKind write_barrier_kind); 316 void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info); 317 318 // Generate a heap reference load using one register `out`: 319 // 320 // out <- *(out + offset) 321 // 322 // while honoring heap poisoning and/or read barriers (if any). 323 // 324 // Location `maybe_temp` is used when generating a read barrier and 325 // shall be a register in that case; it may be an invalid location 326 // otherwise. 327 void GenerateReferenceLoadOneRegister(HInstruction* instruction, 328 Location out, 329 uint32_t offset, 330 Location maybe_temp, 331 ReadBarrierOption read_barrier_option); 332 // Generate a heap reference load using two different registers 333 // `out` and `obj`: 334 // 335 // out <- *(obj + offset) 336 // 337 // while honoring heap poisoning and/or read barriers (if any). 338 // 339 // Location `maybe_temp` is used when generating a Baker's (fast 340 // path) read barrier and shall be a register in that case; it may 341 // be an invalid location otherwise. 342 void GenerateReferenceLoadTwoRegisters(HInstruction* instruction, 343 Location out, 344 Location obj, 345 uint32_t offset, 346 Location maybe_temp, 347 ReadBarrierOption read_barrier_option); 348 349 void GenerateTestAndBranch(HInstruction* instruction, 350 size_t condition_input_index, 351 Riscv64Label* true_target, 352 Riscv64Label* false_target); 353 void DivRemOneOrMinusOne(HBinaryOperation* instruction); 354 void DivRemByPowerOfTwo(HBinaryOperation* instruction); 355 void GenerateDivRemWithAnyConstant(HBinaryOperation* instruction); 356 void GenerateDivRemIntegral(HBinaryOperation* instruction); 357 void GenerateIntLongCondition(IfCondition cond, LocationSummary* locations); 358 void GenerateIntLongCondition(IfCondition cond, 359 LocationSummary* locations, 360 XRegister rd, 361 bool to_all_bits); 362 void GenerateIntLongCompareAndBranch(IfCondition cond, 363 LocationSummary* locations, 364 Riscv64Label* label); 365 void GenerateFpCondition(IfCondition cond, 366 bool gt_bias, 367 DataType::Type type, 368 LocationSummary* locations, 369 Riscv64Label* label = nullptr); 370 void GenerateFpCondition(IfCondition cond, 371 bool gt_bias, 372 DataType::Type type, 373 LocationSummary* locations, 374 Riscv64Label* label, 375 XRegister rd, 376 bool to_all_bits); 377 void GenerateMethodEntryExitHook(HInstruction* instruction); 378 void HandleGoto(HInstruction* got, HBasicBlock* successor); 379 void GenPackedSwitchWithCompares(XRegister adjusted, 380 XRegister temp, 381 uint32_t num_entries, 382 HBasicBlock* switch_block); 383 void GenTableBasedPackedSwitch(XRegister adjusted, 384 XRegister temp, 385 uint32_t num_entries, 386 HBasicBlock* switch_block); 387 int32_t VecAddress(LocationSummary* locations, 388 size_t size, 389 /*out*/ XRegister* adjusted_base); 390 391 template <typename Reg, 392 void (Riscv64Assembler::*opS)(Reg, FRegister, FRegister), 393 void (Riscv64Assembler::*opD)(Reg, FRegister, FRegister)> 394 void FpBinOp(Reg rd, FRegister rs1, FRegister rs2, DataType::Type type); 395 void FSub(FRegister rd, FRegister rs1, FRegister rs2, DataType::Type type); 396 void FDiv(FRegister rd, FRegister rs1, FRegister rs2, DataType::Type type); 397 void FMul(FRegister rd, FRegister rs1, FRegister rs2, DataType::Type type); 398 void FMin(FRegister rd, FRegister rs1, FRegister rs2, DataType::Type type); 399 void FMax(FRegister rd, FRegister rs1, FRegister rs2, DataType::Type type); 400 void FEq(XRegister rd, FRegister rs1, FRegister rs2, DataType::Type type); 401 void FLt(XRegister rd, FRegister rs1, FRegister rs2, DataType::Type type); 402 void FLe(XRegister rd, FRegister rs1, FRegister rs2, DataType::Type type); 403 404 template <typename Reg, 405 void (Riscv64Assembler::*opS)(Reg, FRegister), 406 void (Riscv64Assembler::*opD)(Reg, FRegister)> 407 void FpUnOp(Reg rd, FRegister rs1, DataType::Type type); 408 void FAbs(FRegister rd, FRegister rs1, DataType::Type type); 409 void FNeg(FRegister rd, FRegister rs1, DataType::Type type); 410 void FMv(FRegister rd, FRegister rs1, DataType::Type type); 411 void FMvX(XRegister rd, FRegister rs1, DataType::Type type); 412 413 Riscv64Assembler* const assembler_; 414 CodeGeneratorRISCV64* const codegen_; 415 416 DISALLOW_COPY_AND_ASSIGN(InstructionCodeGeneratorRISCV64); 417 }; 418 419 class CodeGeneratorRISCV64 : public CodeGenerator { 420 public: 421 CodeGeneratorRISCV64(HGraph* graph, 422 const CompilerOptions& compiler_options, 423 OptimizingCompilerStats* stats = nullptr); ~CodeGeneratorRISCV64()424 virtual ~CodeGeneratorRISCV64() {} 425 426 void GenerateFrameEntry() override; 427 void GenerateFrameExit() override; 428 429 void Bind(HBasicBlock* block) override; 430 GetWordSize()431 size_t GetWordSize() const override { 432 // The "word" for the compiler is the core register size (64-bit for riscv64) while the 433 // riscv64 assembler uses "word" for 32-bit values and "double word" for 64-bit values. 434 return kRiscv64DoublewordSize; 435 } 436 SupportsPredicatedSIMD()437 bool SupportsPredicatedSIMD() const override { 438 // TODO(riscv64): Check the vector extension. 439 return false; 440 } 441 442 // Get FP register width in bytes for spilling/restoring in the slow paths. 443 // 444 // Note: In SIMD graphs this should return SIMD register width as all FP and SIMD registers 445 // alias and live SIMD registers are forced to be spilled in full size in the slow paths. GetSlowPathFPWidth()446 size_t GetSlowPathFPWidth() const override { 447 // Default implementation. 448 return GetCalleePreservedFPWidth(); 449 } 450 GetCalleePreservedFPWidth()451 size_t GetCalleePreservedFPWidth() const override { 452 return kRiscv64FloatRegSizeInBytes; 453 }; 454 GetSIMDRegisterWidth()455 size_t GetSIMDRegisterWidth() const override { 456 // TODO(riscv64): Implement SIMD with the Vector extension. 457 // Note: HLoopOptimization calls this function even for an ISA without SIMD support. 458 return kRiscv64FloatRegSizeInBytes; 459 }; 460 GetAddressOf(HBasicBlock * block)461 uintptr_t GetAddressOf(HBasicBlock* block) override { 462 return assembler_.GetLabelLocation(GetLabelOf(block)); 463 }; 464 GetLabelOf(HBasicBlock * block)465 Riscv64Label* GetLabelOf(HBasicBlock* block) const { 466 return CommonGetLabelOf<Riscv64Label>(block_labels_, block); 467 } 468 Initialize()469 void Initialize() override { block_labels_ = CommonInitializeLabels<Riscv64Label>(); } 470 471 void MoveConstant(Location destination, int32_t value) override; 472 void MoveLocation(Location destination, Location source, DataType::Type dst_type) override; 473 void AddLocationAsTemp(Location location, LocationSummary* locations) override; 474 GetAssembler()475 Riscv64Assembler* GetAssembler() override { return &assembler_; } GetAssembler()476 const Riscv64Assembler& GetAssembler() const override { return assembler_; } 477 GetLocationBuilder()478 HGraphVisitor* GetLocationBuilder() override { return &location_builder_; } 479 GetInstructionVisitor()480 InstructionCodeGeneratorRISCV64* GetInstructionVisitor() override { 481 return &instruction_visitor_; 482 } 483 484 void MaybeGenerateInlineCacheCheck(HInstruction* instruction, XRegister klass); 485 486 void SetupBlockedRegisters() const override; 487 488 size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) override; 489 size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) override; 490 size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) override; 491 size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) override; 492 493 void DumpCoreRegister(std::ostream& stream, int reg) const override; 494 void DumpFloatingPointRegister(std::ostream& stream, int reg) const override; 495 GetInstructionSet()496 InstructionSet GetInstructionSet() const override { return InstructionSet::kRiscv64; } 497 498 const Riscv64InstructionSetFeatures& GetInstructionSetFeatures() const; 499 GetPreferredSlotsAlignment()500 uint32_t GetPreferredSlotsAlignment() const override { 501 return static_cast<uint32_t>(kRiscv64PointerSize); 502 } 503 504 void Finalize() override; 505 506 // Generate code to invoke a runtime entry point. 507 void InvokeRuntime(QuickEntrypointEnum entrypoint, 508 HInstruction* instruction, 509 uint32_t dex_pc, 510 SlowPathCode* slow_path = nullptr) override; 511 512 // Generate code to invoke a runtime entry point, but do not record 513 // PC-related information in a stack map. 514 void InvokeRuntimeWithoutRecordingPcInfo(int32_t entry_point_offset, 515 HInstruction* instruction, 516 SlowPathCode* slow_path); 517 GetMoveResolver()518 ParallelMoveResolver* GetMoveResolver() override { return &move_resolver_; } 519 NeedsTwoRegisters(DataType::Type type)520 bool NeedsTwoRegisters([[maybe_unused]] DataType::Type type) const override { return false; } 521 522 void IncreaseFrame(size_t adjustment) override; 523 void DecreaseFrame(size_t adjustment) override; 524 525 void GenerateNop() override; 526 527 void GenerateImplicitNullCheck(HNullCheck* instruction) override; 528 void GenerateExplicitNullCheck(HNullCheck* instruction) override; 529 530 // Check if the desired_string_load_kind is supported. If it is, return it, 531 // otherwise return a fall-back kind that should be used instead. 532 HLoadString::LoadKind GetSupportedLoadStringKind( 533 HLoadString::LoadKind desired_string_load_kind) override; 534 535 // Check if the desired_class_load_kind is supported. If it is, return it, 536 // otherwise return a fall-back kind that should be used instead. 537 HLoadClass::LoadKind GetSupportedLoadClassKind( 538 HLoadClass::LoadKind desired_class_load_kind) override; 539 540 // Check if the desired_dispatch_info is supported. If it is, return it, 541 // otherwise return a fall-back info that should be used instead. 542 HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch( 543 const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info, ArtMethod* method) override; 544 545 // The PcRelativePatchInfo is used for PC-relative addressing of methods/strings/types, 546 // whether through .data.img.rel.ro, .bss, or directly in the boot image. 547 // 548 // The 20-bit and 12-bit parts of the 32-bit PC-relative offset are patched separately, 549 // necessitating two patches/infos. There can be more than two patches/infos if the 550 // instruction supplying the high part is shared with e.g. a slow path, while the low 551 // part is supplied by separate instructions, e.g.: 552 // auipc r1, high // patch 553 // lwu r2, low(r1) // patch 554 // beqz r2, slow_path 555 // back: 556 // ... 557 // slow_path: 558 // ... 559 // sw r2, low(r1) // patch 560 // j back 561 struct PcRelativePatchInfo : PatchInfo<Riscv64Label> { PcRelativePatchInfoPcRelativePatchInfo562 PcRelativePatchInfo(const DexFile* dex_file, 563 uint32_t off_or_idx, 564 const PcRelativePatchInfo* info_high) 565 : PatchInfo<Riscv64Label>(dex_file, off_or_idx), 566 pc_insn_label(info_high != nullptr ? &info_high->label : &label) { 567 DCHECK_IMPLIES(info_high != nullptr, info_high->pc_insn_label == &info_high->label); 568 } 569 570 // Pointer to the info for the high part patch or nullptr if this is the high part patch info. 571 const Riscv64Label* pc_insn_label; 572 573 private: 574 PcRelativePatchInfo(PcRelativePatchInfo&& other) = delete; 575 DISALLOW_COPY_AND_ASSIGN(PcRelativePatchInfo); 576 }; 577 578 PcRelativePatchInfo* NewBootImageIntrinsicPatch(uint32_t intrinsic_data, 579 const PcRelativePatchInfo* info_high = nullptr); 580 PcRelativePatchInfo* NewBootImageRelRoPatch(uint32_t boot_image_offset, 581 const PcRelativePatchInfo* info_high = nullptr); 582 PcRelativePatchInfo* NewBootImageMethodPatch(MethodReference target_method, 583 const PcRelativePatchInfo* info_high = nullptr); 584 PcRelativePatchInfo* NewMethodBssEntryPatch(MethodReference target_method, 585 const PcRelativePatchInfo* info_high = nullptr); 586 PcRelativePatchInfo* NewBootImageJniEntrypointPatch( 587 MethodReference target_method, const PcRelativePatchInfo* info_high = nullptr); 588 589 PcRelativePatchInfo* NewBootImageTypePatch(const DexFile& dex_file, 590 dex::TypeIndex type_index, 591 const PcRelativePatchInfo* info_high = nullptr); 592 PcRelativePatchInfo* NewAppImageTypePatch(const DexFile& dex_file, 593 dex::TypeIndex type_index, 594 const PcRelativePatchInfo* info_high = nullptr); 595 PcRelativePatchInfo* NewTypeBssEntryPatch(HLoadClass* load_class, 596 const PcRelativePatchInfo* info_high = nullptr); 597 PcRelativePatchInfo* NewBootImageStringPatch(const DexFile& dex_file, 598 dex::StringIndex string_index, 599 const PcRelativePatchInfo* info_high = nullptr); 600 PcRelativePatchInfo* NewStringBssEntryPatch(const DexFile& dex_file, 601 dex::StringIndex string_index, 602 const PcRelativePatchInfo* info_high = nullptr); 603 604 void EmitPcRelativeAuipcPlaceholder(PcRelativePatchInfo* info_high, XRegister out); 605 void EmitPcRelativeAddiPlaceholder(PcRelativePatchInfo* info_low, XRegister rd, XRegister rs1); 606 void EmitPcRelativeLwuPlaceholder(PcRelativePatchInfo* info_low, XRegister rd, XRegister rs1); 607 void EmitPcRelativeLdPlaceholder(PcRelativePatchInfo* info_low, XRegister rd, XRegister rs1); 608 609 void EmitLinkerPatches(ArenaVector<linker::LinkerPatch>* linker_patches) override; 610 611 Literal* DeduplicateBootImageAddressLiteral(uint64_t address); 612 void PatchJitRootUse(uint8_t* code, 613 const uint8_t* roots_data, 614 const Literal* literal, 615 uint64_t index_in_table) const; 616 Literal* DeduplicateJitStringLiteral(const DexFile& dex_file, 617 dex::StringIndex string_index, 618 Handle<mirror::String> handle); 619 Literal* DeduplicateJitClassLiteral(const DexFile& dex_file, 620 dex::TypeIndex type_index, 621 Handle<mirror::Class> handle); 622 void EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) override; 623 624 void LoadTypeForBootImageIntrinsic(XRegister dest, TypeReference target_type); 625 void LoadBootImageRelRoEntry(XRegister dest, uint32_t boot_image_offset); 626 void LoadBootImageAddress(XRegister dest, uint32_t boot_image_reference); 627 void LoadIntrinsicDeclaringClass(XRegister dest, HInvoke* invoke); 628 void LoadClassRootForIntrinsic(XRegister dest, ClassRoot class_root); 629 630 void LoadMethod(MethodLoadKind load_kind, Location temp, HInvoke* invoke); 631 void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, 632 Location temp, 633 SlowPathCode* slow_path = nullptr) override; 634 void GenerateVirtualCall(HInvokeVirtual* invoke, 635 Location temp, 636 SlowPathCode* slow_path = nullptr) override; 637 void MoveFromReturnRegister(Location trg, DataType::Type type) override; 638 639 void GenerateMemoryBarrier(MemBarrierKind kind); 640 641 void MaybeIncrementHotness(HSuspendCheck* suspend_check, bool is_frame_entry); 642 643 bool CanUseImplicitSuspendCheck() const; 644 645 646 // Create slow path for a Baker read barrier for a GC root load within `instruction`. 647 SlowPathCodeRISCV64* AddGcRootBakerBarrierBarrierSlowPath( 648 HInstruction* instruction, Location root, Location temp); 649 650 // Emit marking check for a Baker read barrier for a GC root load within `instruction`. 651 void EmitBakerReadBarierMarkingCheck( 652 SlowPathCodeRISCV64* slow_path, Location root, Location temp); 653 654 // Generate a GC root reference load: 655 // 656 // root <- *(obj + offset) 657 // 658 // while honoring read barriers (if any). 659 void GenerateGcRootFieldLoad(HInstruction* instruction, 660 Location root, 661 XRegister obj, 662 uint32_t offset, 663 ReadBarrierOption read_barrier_option, 664 Riscv64Label* label_low = nullptr); 665 666 // Fast path implementation of ReadBarrier::Barrier for a heap 667 // reference field load when Baker's read barriers are used. 668 void GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction, 669 Location ref, 670 XRegister obj, 671 uint32_t offset, 672 Location temp, 673 bool needs_null_check); 674 // Fast path implementation of ReadBarrier::Barrier for a heap 675 // reference array load when Baker's read barriers are used. 676 void GenerateArrayLoadWithBakerReadBarrier(HInstruction* instruction, 677 Location ref, 678 XRegister obj, 679 uint32_t data_offset, 680 Location index, 681 Location temp, 682 bool needs_null_check); 683 // Factored implementation, used by GenerateFieldLoadWithBakerReadBarrier, 684 // GenerateArrayLoadWithBakerReadBarrier and intrinsics. 685 void GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction, 686 Location ref, 687 XRegister obj, 688 uint32_t offset, 689 Location index, 690 Location temp, 691 bool needs_null_check); 692 693 // Create slow path for a read barrier for a heap reference within `instruction`. 694 // 695 // This is a helper function for GenerateReadBarrierSlow() that has the same 696 // arguments. The creation and adding of the slow path is exposed for intrinsics 697 // that cannot use GenerateReadBarrierSlow() from their own slow paths. 698 SlowPathCodeRISCV64* AddReadBarrierSlowPath(HInstruction* instruction, 699 Location out, 700 Location ref, 701 Location obj, 702 uint32_t offset, 703 Location index); 704 705 // Generate a read barrier for a heap reference within `instruction` 706 // using a slow path. 707 // 708 // A read barrier for an object reference read from the heap is 709 // implemented as a call to the artReadBarrierSlow runtime entry 710 // point, which is passed the values in locations `ref`, `obj`, and 711 // `offset`: 712 // 713 // mirror::Object* artReadBarrierSlow(mirror::Object* ref, 714 // mirror::Object* obj, 715 // uint32_t offset); 716 // 717 // The `out` location contains the value returned by 718 // artReadBarrierSlow. 719 // 720 // When `index` is provided (i.e. for array accesses), the offset 721 // value passed to artReadBarrierSlow is adjusted to take `index` 722 // into account. 723 void GenerateReadBarrierSlow(HInstruction* instruction, 724 Location out, 725 Location ref, 726 Location obj, 727 uint32_t offset, 728 Location index = Location::NoLocation()); 729 730 // If read barriers are enabled, generate a read barrier for a heap 731 // reference using a slow path. If heap poisoning is enabled, also 732 // unpoison the reference in `out`. 733 void MaybeGenerateReadBarrierSlow(HInstruction* instruction, 734 Location out, 735 Location ref, 736 Location obj, 737 uint32_t offset, 738 Location index = Location::NoLocation()); 739 740 // Generate a read barrier for a GC root within `instruction` using 741 // a slow path. 742 // 743 // A read barrier for an object reference GC root is implemented as 744 // a call to the artReadBarrierForRootSlow runtime entry point, 745 // which is passed the value in location `root`: 746 // 747 // mirror::Object* artReadBarrierForRootSlow(GcRoot<mirror::Object>* root); 748 // 749 // The `out` location contains the value returned by 750 // artReadBarrierForRootSlow. 751 void GenerateReadBarrierForRootSlow(HInstruction* instruction, Location out, Location root); 752 753 // Emit a write barrier if: 754 // A) emit_null_check is false 755 // B) emit_null_check is true, and value is not null. 756 void MaybeMarkGCCard(XRegister object, XRegister value, bool emit_null_check); 757 758 // Emit a write barrier unconditionally. 759 void MarkGCCard(XRegister object); 760 761 // Crash if the card table is not valid. This check is only emitted for the CC GC. We assert 762 // `(!clean || !self->is_gc_marking)`, since the card table should not be set to clean when the CC 763 // GC is marking for eliminated write barriers. 764 void CheckGCCardIsValid(XRegister object); 765 766 // 767 // Heap poisoning. 768 // 769 770 // Poison a heap reference contained in `reg`. 771 void PoisonHeapReference(XRegister reg); 772 773 // Unpoison a heap reference contained in `reg`. 774 void UnpoisonHeapReference(XRegister reg); 775 776 // Poison a heap reference contained in `reg` if heap poisoning is enabled. 777 void MaybePoisonHeapReference(XRegister reg); 778 779 // Unpoison a heap reference contained in `reg` if heap poisoning is enabled. 780 void MaybeUnpoisonHeapReference(XRegister reg); 781 782 void SwapLocations(Location loc1, Location loc2, DataType::Type type); 783 784 private: 785 using Uint32ToLiteralMap = ArenaSafeMap<uint32_t, Literal*>; 786 using Uint64ToLiteralMap = ArenaSafeMap<uint64_t, Literal*>; 787 using StringToLiteralMap = 788 ArenaSafeMap<StringReference, Literal*, StringReferenceValueComparator>; 789 using TypeToLiteralMap = ArenaSafeMap<TypeReference, Literal*, TypeReferenceValueComparator>; 790 791 Literal* DeduplicateUint32Literal(uint32_t value); 792 Literal* DeduplicateUint64Literal(uint64_t value); 793 794 PcRelativePatchInfo* NewPcRelativePatch(const DexFile* dex_file, 795 uint32_t offset_or_index, 796 const PcRelativePatchInfo* info_high, 797 ArenaDeque<PcRelativePatchInfo>* patches); 798 799 template <linker::LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)> 800 void EmitPcRelativeLinkerPatches(const ArenaDeque<PcRelativePatchInfo>& infos, 801 ArenaVector<linker::LinkerPatch>* linker_patches); 802 803 Riscv64Assembler assembler_; 804 LocationsBuilderRISCV64 location_builder_; 805 InstructionCodeGeneratorRISCV64 instruction_visitor_; 806 Riscv64Label frame_entry_label_; 807 808 // Labels for each block that will be compiled. 809 Riscv64Label* block_labels_; // Indexed by block id. 810 811 ParallelMoveResolverRISCV64 move_resolver_; 812 813 // Deduplication map for 32-bit literals, used for non-patchable boot image addresses. 814 Uint32ToLiteralMap uint32_literals_; 815 // Deduplication map for 64-bit literals, used for non-patchable method address or method code 816 // address. 817 Uint64ToLiteralMap uint64_literals_; 818 819 // PC-relative method patch info for kBootImageLinkTimePcRelative. 820 ArenaDeque<PcRelativePatchInfo> boot_image_method_patches_; 821 // PC-relative method patch info for kBssEntry. 822 ArenaDeque<PcRelativePatchInfo> method_bss_entry_patches_; 823 // PC-relative type patch info for kBootImageLinkTimePcRelative. 824 ArenaDeque<PcRelativePatchInfo> boot_image_type_patches_; 825 // PC-relative type patch info for kAppImageRelRo. 826 ArenaDeque<PcRelativePatchInfo> app_image_type_patches_; 827 // PC-relative type patch info for kBssEntry. 828 ArenaDeque<PcRelativePatchInfo> type_bss_entry_patches_; 829 // PC-relative public type patch info for kBssEntryPublic. 830 ArenaDeque<PcRelativePatchInfo> public_type_bss_entry_patches_; 831 // PC-relative package type patch info for kBssEntryPackage. 832 ArenaDeque<PcRelativePatchInfo> package_type_bss_entry_patches_; 833 // PC-relative String patch info for kBootImageLinkTimePcRelative. 834 ArenaDeque<PcRelativePatchInfo> boot_image_string_patches_; 835 // PC-relative String patch info for kBssEntry. 836 ArenaDeque<PcRelativePatchInfo> string_bss_entry_patches_; 837 // PC-relative method patch info for kBootImageLinkTimePcRelative+kCallCriticalNative. 838 ArenaDeque<PcRelativePatchInfo> boot_image_jni_entrypoint_patches_; 839 // PC-relative patch info for IntrinsicObjects for the boot image, 840 // and for method/type/string patches for kBootImageRelRo otherwise. 841 ArenaDeque<PcRelativePatchInfo> boot_image_other_patches_; 842 843 // Patches for string root accesses in JIT compiled code. 844 StringToLiteralMap jit_string_patches_; 845 // Patches for class root accesses in JIT compiled code. 846 TypeToLiteralMap jit_class_patches_; 847 }; 848 849 } // namespace riscv64 850 } // namespace art 851 852 #endif // ART_COMPILER_OPTIMIZING_CODE_GENERATOR_RISCV64_H_ 853