diff options
author | 2023-11-22 15:27:39 +0000 | |
---|---|---|
committer | 2023-11-24 12:48:55 +0000 | |
commit | c0eceac192ecc628be22df5fd5484bcc50591737 (patch) | |
tree | 2e5364815741769d7fed8ceae58d3be65c716729 /compiler/optimizing | |
parent | aeefe81cc03267d7ba9a6bfaf8daef91fbd33aa0 (diff) |
riscv64: Implement boxing `valueOf()` intrinsics.
Test: testrunner.py --target --64 --ndebug --optimizing --jit
Bug: 283082089
Change-Id: Icd2175edcb835638b7d0667908ea9076580111e1
Diffstat (limited to 'compiler/optimizing')
-rw-r--r-- | compiler/optimizing/code_generator_riscv64.cc | 42 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_riscv64.h | 6 | ||||
-rw-r--r-- | compiler/optimizing/intrinsics_riscv64.cc | 84 | ||||
-rw-r--r-- | compiler/optimizing/intrinsics_riscv64.h | 5 |
4 files changed, 123 insertions, 14 deletions
diff --git a/compiler/optimizing/code_generator_riscv64.cc b/compiler/optimizing/code_generator_riscv64.cc index fb44abce55..7331ad6e4e 100644 --- a/compiler/optimizing/code_generator_riscv64.cc +++ b/compiler/optimizing/code_generator_riscv64.cc @@ -6581,6 +6581,38 @@ void CodeGeneratorRISCV64::LoadBootImageRelRoEntry(XRegister dest, uint32_t boot EmitPcRelativeLwuPlaceholder(info_low, dest, dest); } +void CodeGeneratorRISCV64::LoadBootImageAddress(XRegister dest, uint32_t boot_image_reference) { + if (GetCompilerOptions().IsBootImage()) { + PcRelativePatchInfo* info_high = NewBootImageIntrinsicPatch(boot_image_reference); + EmitPcRelativeAuipcPlaceholder(info_high, dest); + PcRelativePatchInfo* info_low = NewBootImageIntrinsicPatch(boot_image_reference, info_high); + EmitPcRelativeAddiPlaceholder(info_low, dest, dest); + } else if (GetCompilerOptions().GetCompilePic()) { + LoadBootImageRelRoEntry(dest, boot_image_reference); + } else { + DCHECK(GetCompilerOptions().IsJitCompiler()); + gc::Heap* heap = Runtime::Current()->GetHeap(); + DCHECK(!heap->GetBootImageSpaces().empty()); + const uint8_t* address = heap->GetBootImageSpaces()[0]->Begin() + boot_image_reference; + // Note: Boot image is in the low 4GiB (usually the low 2GiB, requiring just LUI+ADDI). + // We may not have an available scratch register for `LoadConst64()` but it never + // emits better code than `Li()` for 32-bit unsigned constants anyway. + __ Li(dest, reinterpret_cast32<uint32_t>(address)); + } +} + +void CodeGeneratorRISCV64::LoadIntrinsicDeclaringClass(XRegister dest, HInvoke* invoke) { + DCHECK_NE(invoke->GetIntrinsic(), Intrinsics::kNone); + if (GetCompilerOptions().IsBootImage()) { + MethodReference target_method = invoke->GetResolvedMethodReference(); + dex::TypeIndex type_idx = target_method.dex_file->GetMethodId(target_method.index).class_idx_; + LoadTypeForBootImageIntrinsic(dest, TypeReference(target_method.dex_file, type_idx)); + } else { + uint32_t boot_image_offset = GetBootImageOffsetOfIntrinsicDeclaringClass(invoke); + LoadBootImageAddress(dest, boot_image_offset); + } +} + void CodeGeneratorRISCV64::LoadClassRootForIntrinsic(XRegister dest, ClassRoot class_root) { if (GetCompilerOptions().IsBootImage()) { ScopedObjectAccess soa(Thread::Current()); @@ -6589,15 +6621,7 @@ void CodeGeneratorRISCV64::LoadClassRootForIntrinsic(XRegister dest, ClassRoot c LoadTypeForBootImageIntrinsic(dest, target_type); } else { uint32_t boot_image_offset = GetBootImageOffset(class_root); - if (GetCompilerOptions().GetCompilePic()) { - LoadBootImageRelRoEntry(dest, boot_image_offset); - } else { - DCHECK(GetCompilerOptions().IsJitCompiler()); - gc::Heap* heap = Runtime::Current()->GetHeap(); - DCHECK(!heap->GetBootImageSpaces().empty()); - const uint8_t* address = heap->GetBootImageSpaces()[0]->Begin() + boot_image_offset; - __ Loadwu(dest, DeduplicateBootImageAddressLiteral(reinterpret_cast<uintptr_t>(address))); - } + LoadBootImageAddress(dest, boot_image_offset); } } diff --git a/compiler/optimizing/code_generator_riscv64.h b/compiler/optimizing/code_generator_riscv64.h index 20c48db12c..522adfd88b 100644 --- a/compiler/optimizing/code_generator_riscv64.h +++ b/compiler/optimizing/code_generator_riscv64.h @@ -160,10 +160,6 @@ static constexpr int32_t kFClassNaNMinValue = 0x100; V(CRC32UpdateByteBuffer) \ V(MethodHandleInvokeExact) \ V(MethodHandleInvoke) \ - V(ByteValueOf) \ - V(ShortValueOf) \ - V(CharacterValueOf) \ - V(IntegerValueOf) \ // Method register on invoke. static const XRegister kArtMethodRegister = A0; @@ -690,6 +686,8 @@ class CodeGeneratorRISCV64 : public CodeGenerator { void LoadTypeForBootImageIntrinsic(XRegister dest, TypeReference target_type); void LoadBootImageRelRoEntry(XRegister dest, uint32_t boot_image_offset); + void LoadBootImageAddress(XRegister dest, uint32_t boot_image_reference); + void LoadIntrinsicDeclaringClass(XRegister dest, HInvoke* invoke); void LoadClassRootForIntrinsic(XRegister dest, ClassRoot class_root); void LoadMethod(MethodLoadKind load_kind, Location temp, HInvoke* invoke); diff --git a/compiler/optimizing/intrinsics_riscv64.cc b/compiler/optimizing/intrinsics_riscv64.cc index fb3f11357a..de153820ca 100644 --- a/compiler/optimizing/intrinsics_riscv64.cc +++ b/compiler/optimizing/intrinsics_riscv64.cc @@ -17,7 +17,9 @@ #include "intrinsics_riscv64.h" #include "code_generator_riscv64.h" +#include "intrinsic_objects.h" #include "intrinsics_utils.h" +#include "well_known_classes.h" namespace art HIDDEN { namespace riscv64 { @@ -473,6 +475,88 @@ void IntrinsicCodeGeneratorRISCV64::VisitLongNumberOfTrailingZeros(HInvoke* invo EmitIntegralUnOp(invoke, [&](XRegister rd, XRegister rs1) { __ Ctz(rd, rs1); }); } +#define VISIT_INTRINSIC(name, low, high, type, start_index) \ + void IntrinsicLocationsBuilderRISCV64::Visit ##name ##ValueOf(HInvoke* invoke) { \ + InvokeRuntimeCallingConvention calling_convention; \ + IntrinsicVisitor::ComputeValueOfLocations( \ + invoke, \ + codegen_, \ + low, \ + high - low + 1, \ + calling_convention.GetReturnLocation(DataType::Type::kReference), \ + Location::RegisterLocation(calling_convention.GetRegisterAt(0))); \ + } \ + void IntrinsicCodeGeneratorRISCV64::Visit ##name ##ValueOf(HInvoke* invoke) { \ + IntrinsicVisitor::ValueOfInfo info = \ + IntrinsicVisitor::ComputeValueOfInfo( \ + invoke, \ + codegen_->GetCompilerOptions(), \ + WellKnownClasses::java_lang_ ##name ##_value, \ + low, \ + high - low + 1, \ + start_index); \ + HandleValueOf(invoke, info, type); \ + } + BOXED_TYPES(VISIT_INTRINSIC) +#undef VISIT_INTRINSIC + +void IntrinsicCodeGeneratorRISCV64::HandleValueOf(HInvoke* invoke, + const IntrinsicVisitor::ValueOfInfo& info, + DataType::Type type) { + Riscv64Assembler* assembler = codegen_->GetAssembler(); + LocationSummary* locations = invoke->GetLocations(); + XRegister out = locations->Out().AsRegister<XRegister>(); + ScratchRegisterScope srs(assembler); + XRegister temp = srs.AllocateXRegister(); + auto allocate_instance = [&]() { + DCHECK_EQ(out, InvokeRuntimeCallingConvention().GetRegisterAt(0)); + codegen_->LoadIntrinsicDeclaringClass(out, invoke); + codegen_->InvokeRuntime(kQuickAllocObjectInitialized, invoke, invoke->GetDexPc()); + CheckEntrypointTypes<kQuickAllocObjectWithChecks, void*, mirror::Class*>(); + }; + if (invoke->InputAt(0)->IsIntConstant()) { + int32_t value = invoke->InputAt(0)->AsIntConstant()->GetValue(); + if (static_cast<uint32_t>(value - info.low) < info.length) { + // Just embed the object in the code. + DCHECK_NE(info.value_boot_image_reference, ValueOfInfo::kInvalidReference); + codegen_->LoadBootImageAddress(out, info.value_boot_image_reference); + } else { + DCHECK(locations->CanCall()); + // Allocate and initialize a new object. + // TODO: If we JIT, we could allocate the object now, and store it in the + // JIT object table. + allocate_instance(); + __ Li(temp, value); + codegen_->GetInstructionVisitor()->Store( + Location::RegisterLocation(temp), out, info.value_offset, type); + // Class pointer and `value` final field stores require a barrier before publication. + codegen_->GenerateMemoryBarrier(MemBarrierKind::kStoreStore); + } + } else { + DCHECK(locations->CanCall()); + XRegister in = locations->InAt(0).AsRegister<XRegister>(); + Riscv64Label allocate, done; + // Check bounds of our cache. + __ AddConst32(out, in, -info.low); + __ Li(temp, info.length); + __ Bgeu(out, temp, &allocate); + // If the value is within the bounds, load the object directly from the array. + codegen_->LoadBootImageAddress(temp, info.array_data_boot_image_reference); + __ Sh2Add(temp, out, temp); + __ Loadwu(out, temp, 0); + codegen_->MaybeUnpoisonHeapReference(out); + __ J(&done); + __ Bind(&allocate); + // Otherwise allocate and initialize a new object. + allocate_instance(); + codegen_->GetInstructionVisitor()->Store( + Location::RegisterLocation(in), out, info.value_offset, type); + // Class pointer and `value` final field stores require a barrier before publication. + codegen_->GenerateMemoryBarrier(MemBarrierKind::kStoreStore); + __ Bind(&done); + } +} + static void GenerateVisitStringIndexOf(HInvoke* invoke, Riscv64Assembler* assembler, CodeGeneratorRISCV64* codegen, diff --git a/compiler/optimizing/intrinsics_riscv64.h b/compiler/optimizing/intrinsics_riscv64.h index 49c057de2b..8160c054ee 100644 --- a/compiler/optimizing/intrinsics_riscv64.h +++ b/compiler/optimizing/intrinsics_riscv64.h @@ -70,9 +70,12 @@ class IntrinsicCodeGeneratorRISCV64 final : public IntrinsicVisitor { private: Riscv64Assembler* GetAssembler(); - ArenaAllocator* GetAllocator(); + void HandleValueOf(HInvoke* invoke, + const IntrinsicVisitor::ValueOfInfo& info, + DataType::Type type); + CodeGeneratorRISCV64* const codegen_; DISALLOW_COPY_AND_ASSIGN(IntrinsicCodeGeneratorRISCV64); |