1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2023 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker *
4*795d594fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker *
8*795d594fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker *
10*795d594fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker */
16*795d594fSAndroid Build Coastguard Worker
17*795d594fSAndroid Build Coastguard Worker #include "intrinsics_riscv64.h"
18*795d594fSAndroid Build Coastguard Worker
19*795d594fSAndroid Build Coastguard Worker #include "code_generator_riscv64.h"
20*795d594fSAndroid Build Coastguard Worker #include "intrinsic_objects.h"
21*795d594fSAndroid Build Coastguard Worker #include "intrinsics_utils.h"
22*795d594fSAndroid Build Coastguard Worker #include "optimizing/locations.h"
23*795d594fSAndroid Build Coastguard Worker #include "well_known_classes.h"
24*795d594fSAndroid Build Coastguard Worker
25*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
26*795d594fSAndroid Build Coastguard Worker namespace riscv64 {
27*795d594fSAndroid Build Coastguard Worker
28*795d594fSAndroid Build Coastguard Worker using IntrinsicSlowPathRISCV64 = IntrinsicSlowPath<InvokeDexCallingConventionVisitorRISCV64,
29*795d594fSAndroid Build Coastguard Worker SlowPathCodeRISCV64,
30*795d594fSAndroid Build Coastguard Worker Riscv64Assembler>;
31*795d594fSAndroid Build Coastguard Worker
32*795d594fSAndroid Build Coastguard Worker #define __ assembler->
33*795d594fSAndroid Build Coastguard Worker
34*795d594fSAndroid Build Coastguard Worker // Slow path implementing the SystemArrayCopy intrinsic copy loop with read barriers.
35*795d594fSAndroid Build Coastguard Worker class ReadBarrierSystemArrayCopySlowPathRISCV64 : public SlowPathCodeRISCV64 {
36*795d594fSAndroid Build Coastguard Worker public:
ReadBarrierSystemArrayCopySlowPathRISCV64(HInstruction * instruction,Location tmp)37*795d594fSAndroid Build Coastguard Worker ReadBarrierSystemArrayCopySlowPathRISCV64(HInstruction* instruction, Location tmp)
38*795d594fSAndroid Build Coastguard Worker : SlowPathCodeRISCV64(instruction), tmp_(tmp) {}
39*795d594fSAndroid Build Coastguard Worker
EmitNativeCode(CodeGenerator * codegen_in)40*795d594fSAndroid Build Coastguard Worker void EmitNativeCode(CodeGenerator* codegen_in) override {
41*795d594fSAndroid Build Coastguard Worker DCHECK(codegen_in->EmitBakerReadBarrier());
42*795d594fSAndroid Build Coastguard Worker CodeGeneratorRISCV64* codegen = down_cast<CodeGeneratorRISCV64*>(codegen_in);
43*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = codegen->GetAssembler();
44*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = instruction_->GetLocations();
45*795d594fSAndroid Build Coastguard Worker DCHECK(locations->CanCall());
46*795d594fSAndroid Build Coastguard Worker DCHECK(instruction_->IsInvokeStaticOrDirect())
47*795d594fSAndroid Build Coastguard Worker << "Unexpected instruction in read barrier arraycopy slow path: "
48*795d594fSAndroid Build Coastguard Worker << instruction_->DebugName();
49*795d594fSAndroid Build Coastguard Worker DCHECK(instruction_->GetLocations()->Intrinsified());
50*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(instruction_->AsInvoke()->GetIntrinsic(), Intrinsics::kSystemArrayCopy);
51*795d594fSAndroid Build Coastguard Worker
52*795d594fSAndroid Build Coastguard Worker const int32_t element_size = DataType::Size(DataType::Type::kReference);
53*795d594fSAndroid Build Coastguard Worker
54*795d594fSAndroid Build Coastguard Worker XRegister src_curr_addr = locations->GetTemp(0).AsRegister<XRegister>();
55*795d594fSAndroid Build Coastguard Worker XRegister dst_curr_addr = locations->GetTemp(1).AsRegister<XRegister>();
56*795d594fSAndroid Build Coastguard Worker XRegister src_stop_addr = locations->GetTemp(2).AsRegister<XRegister>();
57*795d594fSAndroid Build Coastguard Worker XRegister tmp_reg = tmp_.AsRegister<XRegister>();
58*795d594fSAndroid Build Coastguard Worker
59*795d594fSAndroid Build Coastguard Worker __ Bind(GetEntryLabel());
60*795d594fSAndroid Build Coastguard Worker // The source range and destination pointer were initialized before entering the slow-path.
61*795d594fSAndroid Build Coastguard Worker Riscv64Label slow_copy_loop;
62*795d594fSAndroid Build Coastguard Worker __ Bind(&slow_copy_loop);
63*795d594fSAndroid Build Coastguard Worker __ Loadwu(tmp_reg, src_curr_addr, 0);
64*795d594fSAndroid Build Coastguard Worker codegen->MaybeUnpoisonHeapReference(tmp_reg);
65*795d594fSAndroid Build Coastguard Worker // TODO: Inline the mark bit check before calling the runtime?
66*795d594fSAndroid Build Coastguard Worker // tmp_reg = ReadBarrier::Mark(tmp_reg);
67*795d594fSAndroid Build Coastguard Worker // No need to save live registers; it's taken care of by the
68*795d594fSAndroid Build Coastguard Worker // entrypoint. Also, there is no need to update the stack mask,
69*795d594fSAndroid Build Coastguard Worker // as this runtime call will not trigger a garbage collection.
70*795d594fSAndroid Build Coastguard Worker // (See ReadBarrierMarkSlowPathRISCV64::EmitNativeCode for more
71*795d594fSAndroid Build Coastguard Worker // explanations.)
72*795d594fSAndroid Build Coastguard Worker int32_t entry_point_offset = ReadBarrierMarkEntrypointOffset(tmp_);
73*795d594fSAndroid Build Coastguard Worker // This runtime call does not require a stack map.
74*795d594fSAndroid Build Coastguard Worker codegen->InvokeRuntimeWithoutRecordingPcInfo(entry_point_offset, instruction_, this);
75*795d594fSAndroid Build Coastguard Worker codegen->MaybePoisonHeapReference(tmp_reg);
76*795d594fSAndroid Build Coastguard Worker __ Storew(tmp_reg, dst_curr_addr, 0);
77*795d594fSAndroid Build Coastguard Worker __ Addi(src_curr_addr, src_curr_addr, element_size);
78*795d594fSAndroid Build Coastguard Worker __ Addi(dst_curr_addr, dst_curr_addr, element_size);
79*795d594fSAndroid Build Coastguard Worker __ Bne(src_curr_addr, src_stop_addr, &slow_copy_loop);
80*795d594fSAndroid Build Coastguard Worker __ J(GetExitLabel());
81*795d594fSAndroid Build Coastguard Worker }
82*795d594fSAndroid Build Coastguard Worker
GetDescription() const83*795d594fSAndroid Build Coastguard Worker const char* GetDescription() const override {
84*795d594fSAndroid Build Coastguard Worker return "ReadBarrierSystemArrayCopySlowPathRISCV64";
85*795d594fSAndroid Build Coastguard Worker }
86*795d594fSAndroid Build Coastguard Worker
87*795d594fSAndroid Build Coastguard Worker private:
88*795d594fSAndroid Build Coastguard Worker Location tmp_;
89*795d594fSAndroid Build Coastguard Worker
90*795d594fSAndroid Build Coastguard Worker DISALLOW_COPY_AND_ASSIGN(ReadBarrierSystemArrayCopySlowPathRISCV64);
91*795d594fSAndroid Build Coastguard Worker };
92*795d594fSAndroid Build Coastguard Worker
TryDispatch(HInvoke * invoke)93*795d594fSAndroid Build Coastguard Worker bool IntrinsicLocationsBuilderRISCV64::TryDispatch(HInvoke* invoke) {
94*795d594fSAndroid Build Coastguard Worker Dispatch(invoke);
95*795d594fSAndroid Build Coastguard Worker LocationSummary* res = invoke->GetLocations();
96*795d594fSAndroid Build Coastguard Worker if (res == nullptr) {
97*795d594fSAndroid Build Coastguard Worker return false;
98*795d594fSAndroid Build Coastguard Worker }
99*795d594fSAndroid Build Coastguard Worker return res->Intrinsified();
100*795d594fSAndroid Build Coastguard Worker }
101*795d594fSAndroid Build Coastguard Worker
GetAssembler()102*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* IntrinsicCodeGeneratorRISCV64::GetAssembler() {
103*795d594fSAndroid Build Coastguard Worker return codegen_->GetAssembler();
104*795d594fSAndroid Build Coastguard Worker }
105*795d594fSAndroid Build Coastguard Worker
CreateFPToIntLocations(ArenaAllocator * allocator,HInvoke * invoke)106*795d594fSAndroid Build Coastguard Worker static void CreateFPToIntLocations(ArenaAllocator* allocator, HInvoke* invoke) {
107*795d594fSAndroid Build Coastguard Worker LocationSummary* locations =
108*795d594fSAndroid Build Coastguard Worker new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
109*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresFpuRegister());
110*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresRegister());
111*795d594fSAndroid Build Coastguard Worker }
112*795d594fSAndroid Build Coastguard Worker
CreateIntToFPLocations(ArenaAllocator * allocator,HInvoke * invoke)113*795d594fSAndroid Build Coastguard Worker static void CreateIntToFPLocations(ArenaAllocator* allocator, HInvoke* invoke) {
114*795d594fSAndroid Build Coastguard Worker LocationSummary* locations =
115*795d594fSAndroid Build Coastguard Worker new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
116*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresRegister());
117*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresFpuRegister());
118*795d594fSAndroid Build Coastguard Worker }
119*795d594fSAndroid Build Coastguard Worker
CreateFPToFPCallLocations(ArenaAllocator * allocator,HInvoke * invoke)120*795d594fSAndroid Build Coastguard Worker static void CreateFPToFPCallLocations(ArenaAllocator* allocator, HInvoke* invoke) {
121*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(invoke->GetNumberOfArguments(), 1U);
122*795d594fSAndroid Build Coastguard Worker DCHECK(DataType::IsFloatingPointType(invoke->InputAt(0)->GetType()));
123*795d594fSAndroid Build Coastguard Worker DCHECK(DataType::IsFloatingPointType(invoke->GetType()));
124*795d594fSAndroid Build Coastguard Worker
125*795d594fSAndroid Build Coastguard Worker LocationSummary* const locations =
126*795d594fSAndroid Build Coastguard Worker new (allocator) LocationSummary(invoke, LocationSummary::kCallOnMainOnly, kIntrinsified);
127*795d594fSAndroid Build Coastguard Worker InvokeRuntimeCallingConvention calling_convention;
128*795d594fSAndroid Build Coastguard Worker
129*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
130*795d594fSAndroid Build Coastguard Worker locations->SetOut(calling_convention.GetReturnLocation(invoke->GetType()));
131*795d594fSAndroid Build Coastguard Worker }
132*795d594fSAndroid Build Coastguard Worker
CreateFPFPToFPCallLocations(ArenaAllocator * allocator,HInvoke * invoke)133*795d594fSAndroid Build Coastguard Worker static void CreateFPFPToFPCallLocations(ArenaAllocator* allocator, HInvoke* invoke) {
134*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(invoke->GetNumberOfArguments(), 2U);
135*795d594fSAndroid Build Coastguard Worker DCHECK(DataType::IsFloatingPointType(invoke->InputAt(0)->GetType()));
136*795d594fSAndroid Build Coastguard Worker DCHECK(DataType::IsFloatingPointType(invoke->InputAt(1)->GetType()));
137*795d594fSAndroid Build Coastguard Worker DCHECK(DataType::IsFloatingPointType(invoke->GetType()));
138*795d594fSAndroid Build Coastguard Worker
139*795d594fSAndroid Build Coastguard Worker LocationSummary* const locations =
140*795d594fSAndroid Build Coastguard Worker new (allocator) LocationSummary(invoke, LocationSummary::kCallOnMainOnly, kIntrinsified);
141*795d594fSAndroid Build Coastguard Worker InvokeRuntimeCallingConvention calling_convention;
142*795d594fSAndroid Build Coastguard Worker
143*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
144*795d594fSAndroid Build Coastguard Worker locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
145*795d594fSAndroid Build Coastguard Worker locations->SetOut(calling_convention.GetReturnLocation(invoke->GetType()));
146*795d594fSAndroid Build Coastguard Worker }
147*795d594fSAndroid Build Coastguard Worker
CreateFpFpFpToFpNoOverlapLocations(ArenaAllocator * allocator,HInvoke * invoke)148*795d594fSAndroid Build Coastguard Worker static void CreateFpFpFpToFpNoOverlapLocations(ArenaAllocator* allocator, HInvoke* invoke) {
149*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(invoke->GetNumberOfArguments(), 3U);
150*795d594fSAndroid Build Coastguard Worker DCHECK(DataType::IsFloatingPointType(invoke->InputAt(0)->GetType()));
151*795d594fSAndroid Build Coastguard Worker DCHECK(DataType::IsFloatingPointType(invoke->InputAt(1)->GetType()));
152*795d594fSAndroid Build Coastguard Worker DCHECK(DataType::IsFloatingPointType(invoke->InputAt(2)->GetType()));
153*795d594fSAndroid Build Coastguard Worker DCHECK(DataType::IsFloatingPointType(invoke->GetType()));
154*795d594fSAndroid Build Coastguard Worker
155*795d594fSAndroid Build Coastguard Worker LocationSummary* const locations =
156*795d594fSAndroid Build Coastguard Worker new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
157*795d594fSAndroid Build Coastguard Worker
158*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresFpuRegister());
159*795d594fSAndroid Build Coastguard Worker locations->SetInAt(1, Location::RequiresFpuRegister());
160*795d594fSAndroid Build Coastguard Worker locations->SetInAt(2, Location::RequiresFpuRegister());
161*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
162*795d594fSAndroid Build Coastguard Worker }
163*795d594fSAndroid Build Coastguard Worker
CreateFPToFPLocations(ArenaAllocator * allocator,HInvoke * invoke,Location::OutputOverlap overlaps=Location::kOutputOverlap)164*795d594fSAndroid Build Coastguard Worker static void CreateFPToFPLocations(ArenaAllocator* allocator,
165*795d594fSAndroid Build Coastguard Worker HInvoke* invoke,
166*795d594fSAndroid Build Coastguard Worker Location::OutputOverlap overlaps = Location::kOutputOverlap) {
167*795d594fSAndroid Build Coastguard Worker LocationSummary* locations =
168*795d594fSAndroid Build Coastguard Worker new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
169*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresFpuRegister());
170*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresFpuRegister(), overlaps);
171*795d594fSAndroid Build Coastguard Worker }
172*795d594fSAndroid Build Coastguard Worker
VisitDoubleDoubleToRawLongBits(HInvoke * invoke)173*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitDoubleDoubleToRawLongBits(HInvoke* invoke) {
174*795d594fSAndroid Build Coastguard Worker CreateFPToIntLocations(allocator_, invoke);
175*795d594fSAndroid Build Coastguard Worker }
176*795d594fSAndroid Build Coastguard Worker
VisitDoubleDoubleToRawLongBits(HInvoke * invoke)177*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitDoubleDoubleToRawLongBits(HInvoke* invoke) {
178*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = invoke->GetLocations();
179*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = GetAssembler();
180*795d594fSAndroid Build Coastguard Worker __ FMvXD(locations->Out().AsRegister<XRegister>(), locations->InAt(0).AsFpuRegister<FRegister>());
181*795d594fSAndroid Build Coastguard Worker }
182*795d594fSAndroid Build Coastguard Worker
VisitDoubleLongBitsToDouble(HInvoke * invoke)183*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitDoubleLongBitsToDouble(HInvoke* invoke) {
184*795d594fSAndroid Build Coastguard Worker CreateIntToFPLocations(allocator_, invoke);
185*795d594fSAndroid Build Coastguard Worker }
186*795d594fSAndroid Build Coastguard Worker
VisitDoubleLongBitsToDouble(HInvoke * invoke)187*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitDoubleLongBitsToDouble(HInvoke* invoke) {
188*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = invoke->GetLocations();
189*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = GetAssembler();
190*795d594fSAndroid Build Coastguard Worker __ FMvDX(locations->Out().AsFpuRegister<FRegister>(), locations->InAt(0).AsRegister<XRegister>());
191*795d594fSAndroid Build Coastguard Worker }
192*795d594fSAndroid Build Coastguard Worker
VisitFloatFloatToRawIntBits(HInvoke * invoke)193*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitFloatFloatToRawIntBits(HInvoke* invoke) {
194*795d594fSAndroid Build Coastguard Worker CreateFPToIntLocations(allocator_, invoke);
195*795d594fSAndroid Build Coastguard Worker }
196*795d594fSAndroid Build Coastguard Worker
VisitFloatFloatToRawIntBits(HInvoke * invoke)197*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitFloatFloatToRawIntBits(HInvoke* invoke) {
198*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = invoke->GetLocations();
199*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = GetAssembler();
200*795d594fSAndroid Build Coastguard Worker __ FMvXW(locations->Out().AsRegister<XRegister>(), locations->InAt(0).AsFpuRegister<FRegister>());
201*795d594fSAndroid Build Coastguard Worker }
202*795d594fSAndroid Build Coastguard Worker
VisitFloatIntBitsToFloat(HInvoke * invoke)203*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitFloatIntBitsToFloat(HInvoke* invoke) {
204*795d594fSAndroid Build Coastguard Worker CreateIntToFPLocations(allocator_, invoke);
205*795d594fSAndroid Build Coastguard Worker }
206*795d594fSAndroid Build Coastguard Worker
VisitFloatIntBitsToFloat(HInvoke * invoke)207*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitFloatIntBitsToFloat(HInvoke* invoke) {
208*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = invoke->GetLocations();
209*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = GetAssembler();
210*795d594fSAndroid Build Coastguard Worker __ FMvWX(locations->Out().AsFpuRegister<FRegister>(), locations->InAt(0).AsRegister<XRegister>());
211*795d594fSAndroid Build Coastguard Worker }
212*795d594fSAndroid Build Coastguard Worker
VisitDoubleIsInfinite(HInvoke * invoke)213*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitDoubleIsInfinite(HInvoke* invoke) {
214*795d594fSAndroid Build Coastguard Worker CreateFPToIntLocations(allocator_, invoke);
215*795d594fSAndroid Build Coastguard Worker }
216*795d594fSAndroid Build Coastguard Worker
VisitDoubleIsInfinite(HInvoke * invoke)217*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitDoubleIsInfinite(HInvoke* invoke) {
218*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = invoke->GetLocations();
219*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = GetAssembler();
220*795d594fSAndroid Build Coastguard Worker XRegister out = locations->Out().AsRegister<XRegister>();
221*795d594fSAndroid Build Coastguard Worker __ FClassD(out, locations->InAt(0).AsFpuRegister<FRegister>());
222*795d594fSAndroid Build Coastguard Worker __ Andi(out, out, kPositiveInfinity | kNegativeInfinity);
223*795d594fSAndroid Build Coastguard Worker __ Snez(out, out);
224*795d594fSAndroid Build Coastguard Worker }
225*795d594fSAndroid Build Coastguard Worker
VisitFloatIsInfinite(HInvoke * invoke)226*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitFloatIsInfinite(HInvoke* invoke) {
227*795d594fSAndroid Build Coastguard Worker CreateFPToIntLocations(allocator_, invoke);
228*795d594fSAndroid Build Coastguard Worker }
229*795d594fSAndroid Build Coastguard Worker
VisitFloatIsInfinite(HInvoke * invoke)230*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitFloatIsInfinite(HInvoke* invoke) {
231*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = invoke->GetLocations();
232*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = GetAssembler();
233*795d594fSAndroid Build Coastguard Worker XRegister out = locations->Out().AsRegister<XRegister>();
234*795d594fSAndroid Build Coastguard Worker __ FClassS(out, locations->InAt(0).AsFpuRegister<FRegister>());
235*795d594fSAndroid Build Coastguard Worker __ Andi(out, out, kPositiveInfinity | kNegativeInfinity);
236*795d594fSAndroid Build Coastguard Worker __ Snez(out, out);
237*795d594fSAndroid Build Coastguard Worker }
238*795d594fSAndroid Build Coastguard Worker
CreateIntToIntNoOverlapLocations(ArenaAllocator * allocator,HInvoke * invoke)239*795d594fSAndroid Build Coastguard Worker static void CreateIntToIntNoOverlapLocations(ArenaAllocator* allocator, HInvoke* invoke) {
240*795d594fSAndroid Build Coastguard Worker LocationSummary* locations =
241*795d594fSAndroid Build Coastguard Worker new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
242*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresRegister());
243*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
244*795d594fSAndroid Build Coastguard Worker }
245*795d594fSAndroid Build Coastguard Worker
246*795d594fSAndroid Build Coastguard Worker template <typename EmitOp>
EmitMemoryPeek(HInvoke * invoke,EmitOp && emit_op)247*795d594fSAndroid Build Coastguard Worker void EmitMemoryPeek(HInvoke* invoke, EmitOp&& emit_op) {
248*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = invoke->GetLocations();
249*795d594fSAndroid Build Coastguard Worker emit_op(locations->Out().AsRegister<XRegister>(), locations->InAt(0).AsRegister<XRegister>());
250*795d594fSAndroid Build Coastguard Worker }
251*795d594fSAndroid Build Coastguard Worker
VisitMemoryPeekByte(HInvoke * invoke)252*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitMemoryPeekByte(HInvoke* invoke) {
253*795d594fSAndroid Build Coastguard Worker CreateIntToIntNoOverlapLocations(allocator_, invoke);
254*795d594fSAndroid Build Coastguard Worker }
255*795d594fSAndroid Build Coastguard Worker
VisitMemoryPeekByte(HInvoke * invoke)256*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitMemoryPeekByte(HInvoke* invoke) {
257*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = GetAssembler();
258*795d594fSAndroid Build Coastguard Worker EmitMemoryPeek(invoke, [&](XRegister rd, XRegister rs1) { __ Lb(rd, rs1, 0); });
259*795d594fSAndroid Build Coastguard Worker }
260*795d594fSAndroid Build Coastguard Worker
VisitMemoryPeekIntNative(HInvoke * invoke)261*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitMemoryPeekIntNative(HInvoke* invoke) {
262*795d594fSAndroid Build Coastguard Worker CreateIntToIntNoOverlapLocations(allocator_, invoke);
263*795d594fSAndroid Build Coastguard Worker }
264*795d594fSAndroid Build Coastguard Worker
VisitMemoryPeekIntNative(HInvoke * invoke)265*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitMemoryPeekIntNative(HInvoke* invoke) {
266*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = GetAssembler();
267*795d594fSAndroid Build Coastguard Worker EmitMemoryPeek(invoke, [&](XRegister rd, XRegister rs1) { __ Lw(rd, rs1, 0); });
268*795d594fSAndroid Build Coastguard Worker }
269*795d594fSAndroid Build Coastguard Worker
VisitMemoryPeekLongNative(HInvoke * invoke)270*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitMemoryPeekLongNative(HInvoke* invoke) {
271*795d594fSAndroid Build Coastguard Worker CreateIntToIntNoOverlapLocations(allocator_, invoke);
272*795d594fSAndroid Build Coastguard Worker }
273*795d594fSAndroid Build Coastguard Worker
VisitMemoryPeekLongNative(HInvoke * invoke)274*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitMemoryPeekLongNative(HInvoke* invoke) {
275*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = GetAssembler();
276*795d594fSAndroid Build Coastguard Worker EmitMemoryPeek(invoke, [&](XRegister rd, XRegister rs1) { __ Ld(rd, rs1, 0); });
277*795d594fSAndroid Build Coastguard Worker }
278*795d594fSAndroid Build Coastguard Worker
VisitMemoryPeekShortNative(HInvoke * invoke)279*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitMemoryPeekShortNative(HInvoke* invoke) {
280*795d594fSAndroid Build Coastguard Worker CreateIntToIntNoOverlapLocations(allocator_, invoke);
281*795d594fSAndroid Build Coastguard Worker }
282*795d594fSAndroid Build Coastguard Worker
VisitMemoryPeekShortNative(HInvoke * invoke)283*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitMemoryPeekShortNative(HInvoke* invoke) {
284*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = GetAssembler();
285*795d594fSAndroid Build Coastguard Worker EmitMemoryPeek(invoke, [&](XRegister rd, XRegister rs1) { __ Lh(rd, rs1, 0); });
286*795d594fSAndroid Build Coastguard Worker }
287*795d594fSAndroid Build Coastguard Worker
CreateIntIntToVoidLocations(ArenaAllocator * allocator,HInvoke * invoke)288*795d594fSAndroid Build Coastguard Worker static void CreateIntIntToVoidLocations(ArenaAllocator* allocator, HInvoke* invoke) {
289*795d594fSAndroid Build Coastguard Worker LocationSummary* locations =
290*795d594fSAndroid Build Coastguard Worker new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
291*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresRegister());
292*795d594fSAndroid Build Coastguard Worker locations->SetInAt(1, Location::RequiresRegister());
293*795d594fSAndroid Build Coastguard Worker }
294*795d594fSAndroid Build Coastguard Worker
CreateIntIntToIntSlowPathCallLocations(ArenaAllocator * allocator,HInvoke * invoke)295*795d594fSAndroid Build Coastguard Worker static void CreateIntIntToIntSlowPathCallLocations(ArenaAllocator* allocator, HInvoke* invoke) {
296*795d594fSAndroid Build Coastguard Worker LocationSummary* locations =
297*795d594fSAndroid Build Coastguard Worker new (allocator) LocationSummary(invoke, LocationSummary::kCallOnSlowPath, kIntrinsified);
298*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresRegister());
299*795d594fSAndroid Build Coastguard Worker locations->SetInAt(1, Location::RequiresRegister());
300*795d594fSAndroid Build Coastguard Worker // Force kOutputOverlap; see comments in IntrinsicSlowPath::EmitNativeCode.
301*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
302*795d594fSAndroid Build Coastguard Worker }
303*795d594fSAndroid Build Coastguard Worker
304*795d594fSAndroid Build Coastguard Worker template <typename EmitOp>
EmitMemoryPoke(HInvoke * invoke,EmitOp && emit_op)305*795d594fSAndroid Build Coastguard Worker void EmitMemoryPoke(HInvoke* invoke, EmitOp&& emit_op) {
306*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = invoke->GetLocations();
307*795d594fSAndroid Build Coastguard Worker emit_op(locations->InAt(1).AsRegister<XRegister>(), locations->InAt(0).AsRegister<XRegister>());
308*795d594fSAndroid Build Coastguard Worker }
309*795d594fSAndroid Build Coastguard Worker
VisitMemoryPokeByte(HInvoke * invoke)310*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitMemoryPokeByte(HInvoke* invoke) {
311*795d594fSAndroid Build Coastguard Worker CreateIntIntToVoidLocations(allocator_, invoke);
312*795d594fSAndroid Build Coastguard Worker }
313*795d594fSAndroid Build Coastguard Worker
VisitMemoryPokeByte(HInvoke * invoke)314*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitMemoryPokeByte(HInvoke* invoke) {
315*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = GetAssembler();
316*795d594fSAndroid Build Coastguard Worker EmitMemoryPoke(invoke, [&](XRegister rs2, XRegister rs1) { __ Sb(rs2, rs1, 0); });
317*795d594fSAndroid Build Coastguard Worker }
318*795d594fSAndroid Build Coastguard Worker
VisitMemoryPokeIntNative(HInvoke * invoke)319*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitMemoryPokeIntNative(HInvoke* invoke) {
320*795d594fSAndroid Build Coastguard Worker CreateIntIntToVoidLocations(allocator_, invoke);
321*795d594fSAndroid Build Coastguard Worker }
322*795d594fSAndroid Build Coastguard Worker
VisitMemoryPokeIntNative(HInvoke * invoke)323*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitMemoryPokeIntNative(HInvoke* invoke) {
324*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = GetAssembler();
325*795d594fSAndroid Build Coastguard Worker EmitMemoryPoke(invoke, [&](XRegister rs2, XRegister rs1) { __ Sw(rs2, rs1, 0); });
326*795d594fSAndroid Build Coastguard Worker }
327*795d594fSAndroid Build Coastguard Worker
VisitMemoryPokeLongNative(HInvoke * invoke)328*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitMemoryPokeLongNative(HInvoke* invoke) {
329*795d594fSAndroid Build Coastguard Worker CreateIntIntToVoidLocations(allocator_, invoke);
330*795d594fSAndroid Build Coastguard Worker }
331*795d594fSAndroid Build Coastguard Worker
VisitMemoryPokeLongNative(HInvoke * invoke)332*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitMemoryPokeLongNative(HInvoke* invoke) {
333*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = GetAssembler();
334*795d594fSAndroid Build Coastguard Worker EmitMemoryPoke(invoke, [&](XRegister rs2, XRegister rs1) { __ Sd(rs2, rs1, 0); });
335*795d594fSAndroid Build Coastguard Worker }
336*795d594fSAndroid Build Coastguard Worker
VisitMemoryPokeShortNative(HInvoke * invoke)337*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitMemoryPokeShortNative(HInvoke* invoke) {
338*795d594fSAndroid Build Coastguard Worker CreateIntIntToVoidLocations(allocator_, invoke);
339*795d594fSAndroid Build Coastguard Worker }
340*795d594fSAndroid Build Coastguard Worker
VisitMemoryPokeShortNative(HInvoke * invoke)341*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitMemoryPokeShortNative(HInvoke* invoke) {
342*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = GetAssembler();
343*795d594fSAndroid Build Coastguard Worker EmitMemoryPoke(invoke, [&](XRegister rs2, XRegister rs1) { __ Sh(rs2, rs1, 0); });
344*795d594fSAndroid Build Coastguard Worker }
345*795d594fSAndroid Build Coastguard Worker
GenerateReverseBytes(CodeGeneratorRISCV64 * codegen,Location rd,XRegister rs1,DataType::Type type)346*795d594fSAndroid Build Coastguard Worker static void GenerateReverseBytes(CodeGeneratorRISCV64* codegen,
347*795d594fSAndroid Build Coastguard Worker Location rd,
348*795d594fSAndroid Build Coastguard Worker XRegister rs1,
349*795d594fSAndroid Build Coastguard Worker DataType::Type type) {
350*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = codegen->GetAssembler();
351*795d594fSAndroid Build Coastguard Worker switch (type) {
352*795d594fSAndroid Build Coastguard Worker case DataType::Type::kUint16:
353*795d594fSAndroid Build Coastguard Worker // There is no 16-bit reverse bytes instruction.
354*795d594fSAndroid Build Coastguard Worker __ Rev8(rd.AsRegister<XRegister>(), rs1);
355*795d594fSAndroid Build Coastguard Worker __ Srli(rd.AsRegister<XRegister>(), rd.AsRegister<XRegister>(), 48);
356*795d594fSAndroid Build Coastguard Worker break;
357*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt16:
358*795d594fSAndroid Build Coastguard Worker // There is no 16-bit reverse bytes instruction.
359*795d594fSAndroid Build Coastguard Worker __ Rev8(rd.AsRegister<XRegister>(), rs1);
360*795d594fSAndroid Build Coastguard Worker __ Srai(rd.AsRegister<XRegister>(), rd.AsRegister<XRegister>(), 48);
361*795d594fSAndroid Build Coastguard Worker break;
362*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt32:
363*795d594fSAndroid Build Coastguard Worker // There is no 32-bit reverse bytes instruction.
364*795d594fSAndroid Build Coastguard Worker __ Rev8(rd.AsRegister<XRegister>(), rs1);
365*795d594fSAndroid Build Coastguard Worker __ Srai(rd.AsRegister<XRegister>(), rd.AsRegister<XRegister>(), 32);
366*795d594fSAndroid Build Coastguard Worker break;
367*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt64:
368*795d594fSAndroid Build Coastguard Worker __ Rev8(rd.AsRegister<XRegister>(), rs1);
369*795d594fSAndroid Build Coastguard Worker break;
370*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat32:
371*795d594fSAndroid Build Coastguard Worker // There is no 32-bit reverse bytes instruction.
372*795d594fSAndroid Build Coastguard Worker __ Rev8(rs1, rs1); // Note: Clobbers `rs1`.
373*795d594fSAndroid Build Coastguard Worker __ Srai(rs1, rs1, 32);
374*795d594fSAndroid Build Coastguard Worker __ FMvWX(rd.AsFpuRegister<FRegister>(), rs1);
375*795d594fSAndroid Build Coastguard Worker break;
376*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat64:
377*795d594fSAndroid Build Coastguard Worker __ Rev8(rs1, rs1); // Note: Clobbers `rs1`.
378*795d594fSAndroid Build Coastguard Worker __ FMvDX(rd.AsFpuRegister<FRegister>(), rs1);
379*795d594fSAndroid Build Coastguard Worker break;
380*795d594fSAndroid Build Coastguard Worker default:
381*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unexpected type: " << type;
382*795d594fSAndroid Build Coastguard Worker UNREACHABLE();
383*795d594fSAndroid Build Coastguard Worker }
384*795d594fSAndroid Build Coastguard Worker }
385*795d594fSAndroid Build Coastguard Worker
GenerateReverseBytes(CodeGeneratorRISCV64 * codegen,HInvoke * invoke,DataType::Type type)386*795d594fSAndroid Build Coastguard Worker static void GenerateReverseBytes(CodeGeneratorRISCV64* codegen,
387*795d594fSAndroid Build Coastguard Worker HInvoke* invoke,
388*795d594fSAndroid Build Coastguard Worker DataType::Type type) {
389*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(type, invoke->GetType());
390*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = invoke->GetLocations();
391*795d594fSAndroid Build Coastguard Worker GenerateReverseBytes(codegen, locations->Out(), locations->InAt(0).AsRegister<XRegister>(), type);
392*795d594fSAndroid Build Coastguard Worker }
393*795d594fSAndroid Build Coastguard Worker
GenerateReverse(CodeGeneratorRISCV64 * codegen,HInvoke * invoke,DataType::Type type)394*795d594fSAndroid Build Coastguard Worker static void GenerateReverse(CodeGeneratorRISCV64* codegen, HInvoke* invoke, DataType::Type type) {
395*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(type, invoke->GetType());
396*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = codegen->GetAssembler();
397*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = invoke->GetLocations();
398*795d594fSAndroid Build Coastguard Worker XRegister in = locations->InAt(0).AsRegister<XRegister>();
399*795d594fSAndroid Build Coastguard Worker XRegister out = locations->Out().AsRegister<XRegister>();
400*795d594fSAndroid Build Coastguard Worker ScratchRegisterScope srs(assembler);
401*795d594fSAndroid Build Coastguard Worker XRegister temp1 = srs.AllocateXRegister();
402*795d594fSAndroid Build Coastguard Worker XRegister temp2 = srs.AllocateXRegister();
403*795d594fSAndroid Build Coastguard Worker
404*795d594fSAndroid Build Coastguard Worker auto maybe_extend_mask = [type, assembler](XRegister mask, XRegister temp) {
405*795d594fSAndroid Build Coastguard Worker if (type == DataType::Type::kInt64) {
406*795d594fSAndroid Build Coastguard Worker __ Slli(temp, mask, 32);
407*795d594fSAndroid Build Coastguard Worker __ Add(mask, mask, temp);
408*795d594fSAndroid Build Coastguard Worker }
409*795d594fSAndroid Build Coastguard Worker };
410*795d594fSAndroid Build Coastguard Worker
411*795d594fSAndroid Build Coastguard Worker // Swap bits in bit pairs.
412*795d594fSAndroid Build Coastguard Worker __ Li(temp1, 0x55555555);
413*795d594fSAndroid Build Coastguard Worker maybe_extend_mask(temp1, temp2);
414*795d594fSAndroid Build Coastguard Worker __ Srli(temp2, in, 1);
415*795d594fSAndroid Build Coastguard Worker __ And(out, in, temp1);
416*795d594fSAndroid Build Coastguard Worker __ And(temp2, temp2, temp1);
417*795d594fSAndroid Build Coastguard Worker __ Sh1Add(out, out, temp2);
418*795d594fSAndroid Build Coastguard Worker
419*795d594fSAndroid Build Coastguard Worker // Swap bit pairs in 4-bit groups.
420*795d594fSAndroid Build Coastguard Worker __ Li(temp1, 0x33333333);
421*795d594fSAndroid Build Coastguard Worker maybe_extend_mask(temp1, temp2);
422*795d594fSAndroid Build Coastguard Worker __ Srli(temp2, out, 2);
423*795d594fSAndroid Build Coastguard Worker __ And(out, out, temp1);
424*795d594fSAndroid Build Coastguard Worker __ And(temp2, temp2, temp1);
425*795d594fSAndroid Build Coastguard Worker __ Sh2Add(out, out, temp2);
426*795d594fSAndroid Build Coastguard Worker
427*795d594fSAndroid Build Coastguard Worker // Swap 4-bit groups in 8-bit groups.
428*795d594fSAndroid Build Coastguard Worker __ Li(temp1, 0x0f0f0f0f);
429*795d594fSAndroid Build Coastguard Worker maybe_extend_mask(temp1, temp2);
430*795d594fSAndroid Build Coastguard Worker __ Srli(temp2, out, 4);
431*795d594fSAndroid Build Coastguard Worker __ And(out, out, temp1);
432*795d594fSAndroid Build Coastguard Worker __ And(temp2, temp2, temp1);
433*795d594fSAndroid Build Coastguard Worker __ Slli(out, out, 4);
434*795d594fSAndroid Build Coastguard Worker __ Add(out, out, temp2);
435*795d594fSAndroid Build Coastguard Worker
436*795d594fSAndroid Build Coastguard Worker GenerateReverseBytes(codegen, Location::RegisterLocation(out), out, type);
437*795d594fSAndroid Build Coastguard Worker }
438*795d594fSAndroid Build Coastguard Worker
VisitIntegerReverse(HInvoke * invoke)439*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitIntegerReverse(HInvoke* invoke) {
440*795d594fSAndroid Build Coastguard Worker CreateIntToIntNoOverlapLocations(allocator_, invoke);
441*795d594fSAndroid Build Coastguard Worker }
442*795d594fSAndroid Build Coastguard Worker
VisitIntegerReverse(HInvoke * invoke)443*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitIntegerReverse(HInvoke* invoke) {
444*795d594fSAndroid Build Coastguard Worker GenerateReverse(codegen_, invoke, DataType::Type::kInt32);
445*795d594fSAndroid Build Coastguard Worker }
446*795d594fSAndroid Build Coastguard Worker
VisitLongReverse(HInvoke * invoke)447*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitLongReverse(HInvoke* invoke) {
448*795d594fSAndroid Build Coastguard Worker CreateIntToIntNoOverlapLocations(allocator_, invoke);
449*795d594fSAndroid Build Coastguard Worker }
450*795d594fSAndroid Build Coastguard Worker
VisitLongReverse(HInvoke * invoke)451*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitLongReverse(HInvoke* invoke) {
452*795d594fSAndroid Build Coastguard Worker GenerateReverse(codegen_, invoke, DataType::Type::kInt64);
453*795d594fSAndroid Build Coastguard Worker }
454*795d594fSAndroid Build Coastguard Worker
VisitIntegerReverseBytes(HInvoke * invoke)455*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitIntegerReverseBytes(HInvoke* invoke) {
456*795d594fSAndroid Build Coastguard Worker CreateIntToIntNoOverlapLocations(allocator_, invoke);
457*795d594fSAndroid Build Coastguard Worker }
458*795d594fSAndroid Build Coastguard Worker
VisitIntegerReverseBytes(HInvoke * invoke)459*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitIntegerReverseBytes(HInvoke* invoke) {
460*795d594fSAndroid Build Coastguard Worker GenerateReverseBytes(codegen_, invoke, DataType::Type::kInt32);
461*795d594fSAndroid Build Coastguard Worker }
462*795d594fSAndroid Build Coastguard Worker
VisitLongReverseBytes(HInvoke * invoke)463*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitLongReverseBytes(HInvoke* invoke) {
464*795d594fSAndroid Build Coastguard Worker CreateIntToIntNoOverlapLocations(allocator_, invoke);
465*795d594fSAndroid Build Coastguard Worker }
466*795d594fSAndroid Build Coastguard Worker
VisitLongReverseBytes(HInvoke * invoke)467*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitLongReverseBytes(HInvoke* invoke) {
468*795d594fSAndroid Build Coastguard Worker GenerateReverseBytes(codegen_, invoke, DataType::Type::kInt64);
469*795d594fSAndroid Build Coastguard Worker }
470*795d594fSAndroid Build Coastguard Worker
VisitShortReverseBytes(HInvoke * invoke)471*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitShortReverseBytes(HInvoke* invoke) {
472*795d594fSAndroid Build Coastguard Worker CreateIntToIntNoOverlapLocations(allocator_, invoke);
473*795d594fSAndroid Build Coastguard Worker }
474*795d594fSAndroid Build Coastguard Worker
VisitShortReverseBytes(HInvoke * invoke)475*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitShortReverseBytes(HInvoke* invoke) {
476*795d594fSAndroid Build Coastguard Worker GenerateReverseBytes(codegen_, invoke, DataType::Type::kInt16);
477*795d594fSAndroid Build Coastguard Worker }
478*795d594fSAndroid Build Coastguard Worker
479*795d594fSAndroid Build Coastguard Worker template <typename EmitOp>
EmitIntegralUnOp(HInvoke * invoke,EmitOp && emit_op)480*795d594fSAndroid Build Coastguard Worker void EmitIntegralUnOp(HInvoke* invoke, EmitOp&& emit_op) {
481*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = invoke->GetLocations();
482*795d594fSAndroid Build Coastguard Worker emit_op(locations->Out().AsRegister<XRegister>(), locations->InAt(0).AsRegister<XRegister>());
483*795d594fSAndroid Build Coastguard Worker }
484*795d594fSAndroid Build Coastguard Worker
VisitIntegerBitCount(HInvoke * invoke)485*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitIntegerBitCount(HInvoke* invoke) {
486*795d594fSAndroid Build Coastguard Worker CreateIntToIntNoOverlapLocations(allocator_, invoke);
487*795d594fSAndroid Build Coastguard Worker }
488*795d594fSAndroid Build Coastguard Worker
VisitIntegerBitCount(HInvoke * invoke)489*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitIntegerBitCount(HInvoke* invoke) {
490*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = GetAssembler();
491*795d594fSAndroid Build Coastguard Worker EmitIntegralUnOp(invoke, [&](XRegister rd, XRegister rs1) { __ Cpopw(rd, rs1); });
492*795d594fSAndroid Build Coastguard Worker }
493*795d594fSAndroid Build Coastguard Worker
VisitLongBitCount(HInvoke * invoke)494*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitLongBitCount(HInvoke* invoke) {
495*795d594fSAndroid Build Coastguard Worker CreateIntToIntNoOverlapLocations(allocator_, invoke);
496*795d594fSAndroid Build Coastguard Worker }
497*795d594fSAndroid Build Coastguard Worker
VisitLongBitCount(HInvoke * invoke)498*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitLongBitCount(HInvoke* invoke) {
499*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = GetAssembler();
500*795d594fSAndroid Build Coastguard Worker EmitIntegralUnOp(invoke, [&](XRegister rd, XRegister rs1) { __ Cpop(rd, rs1); });
501*795d594fSAndroid Build Coastguard Worker }
502*795d594fSAndroid Build Coastguard Worker
VisitIntegerHighestOneBit(HInvoke * invoke)503*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitIntegerHighestOneBit(HInvoke* invoke) {
504*795d594fSAndroid Build Coastguard Worker CreateIntToIntNoOverlapLocations(allocator_, invoke);
505*795d594fSAndroid Build Coastguard Worker }
506*795d594fSAndroid Build Coastguard Worker
VisitIntegerHighestOneBit(HInvoke * invoke)507*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitIntegerHighestOneBit(HInvoke* invoke) {
508*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = GetAssembler();
509*795d594fSAndroid Build Coastguard Worker EmitIntegralUnOp(invoke, [&](XRegister rd, XRegister rs1) {
510*795d594fSAndroid Build Coastguard Worker ScratchRegisterScope srs(assembler);
511*795d594fSAndroid Build Coastguard Worker XRegister tmp = srs.AllocateXRegister();
512*795d594fSAndroid Build Coastguard Worker XRegister tmp2 = srs.AllocateXRegister();
513*795d594fSAndroid Build Coastguard Worker __ Clzw(tmp, rs1);
514*795d594fSAndroid Build Coastguard Worker __ Li(tmp2, INT64_C(-0x80000000));
515*795d594fSAndroid Build Coastguard Worker __ Srlw(tmp2, tmp2, tmp);
516*795d594fSAndroid Build Coastguard Worker __ And(rd, rs1, tmp2); // Make sure the result is zero if the input is zero.
517*795d594fSAndroid Build Coastguard Worker });
518*795d594fSAndroid Build Coastguard Worker }
519*795d594fSAndroid Build Coastguard Worker
VisitLongHighestOneBit(HInvoke * invoke)520*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitLongHighestOneBit(HInvoke* invoke) {
521*795d594fSAndroid Build Coastguard Worker CreateIntToIntNoOverlapLocations(allocator_, invoke);
522*795d594fSAndroid Build Coastguard Worker }
523*795d594fSAndroid Build Coastguard Worker
VisitLongHighestOneBit(HInvoke * invoke)524*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitLongHighestOneBit(HInvoke* invoke) {
525*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = GetAssembler();
526*795d594fSAndroid Build Coastguard Worker EmitIntegralUnOp(invoke, [&](XRegister rd, XRegister rs1) {
527*795d594fSAndroid Build Coastguard Worker ScratchRegisterScope srs(assembler);
528*795d594fSAndroid Build Coastguard Worker XRegister tmp = srs.AllocateXRegister();
529*795d594fSAndroid Build Coastguard Worker XRegister tmp2 = srs.AllocateXRegister();
530*795d594fSAndroid Build Coastguard Worker __ Clz(tmp, rs1);
531*795d594fSAndroid Build Coastguard Worker __ Li(tmp2, INT64_C(-0x8000000000000000));
532*795d594fSAndroid Build Coastguard Worker __ Srl(tmp2, tmp2, tmp);
533*795d594fSAndroid Build Coastguard Worker __ And(rd, rs1, tmp2); // Make sure the result is zero if the input is zero.
534*795d594fSAndroid Build Coastguard Worker });
535*795d594fSAndroid Build Coastguard Worker }
536*795d594fSAndroid Build Coastguard Worker
VisitIntegerLowestOneBit(HInvoke * invoke)537*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitIntegerLowestOneBit(HInvoke* invoke) {
538*795d594fSAndroid Build Coastguard Worker CreateIntToIntNoOverlapLocations(allocator_, invoke);
539*795d594fSAndroid Build Coastguard Worker }
540*795d594fSAndroid Build Coastguard Worker
VisitIntegerLowestOneBit(HInvoke * invoke)541*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitIntegerLowestOneBit(HInvoke* invoke) {
542*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = GetAssembler();
543*795d594fSAndroid Build Coastguard Worker EmitIntegralUnOp(invoke, [&](XRegister rd, XRegister rs1) {
544*795d594fSAndroid Build Coastguard Worker ScratchRegisterScope srs(assembler);
545*795d594fSAndroid Build Coastguard Worker XRegister tmp = srs.AllocateXRegister();
546*795d594fSAndroid Build Coastguard Worker __ NegW(tmp, rs1);
547*795d594fSAndroid Build Coastguard Worker __ And(rd, rs1, tmp);
548*795d594fSAndroid Build Coastguard Worker });
549*795d594fSAndroid Build Coastguard Worker }
550*795d594fSAndroid Build Coastguard Worker
VisitLongLowestOneBit(HInvoke * invoke)551*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitLongLowestOneBit(HInvoke* invoke) {
552*795d594fSAndroid Build Coastguard Worker CreateIntToIntNoOverlapLocations(allocator_, invoke);
553*795d594fSAndroid Build Coastguard Worker }
554*795d594fSAndroid Build Coastguard Worker
VisitLongLowestOneBit(HInvoke * invoke)555*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitLongLowestOneBit(HInvoke* invoke) {
556*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = GetAssembler();
557*795d594fSAndroid Build Coastguard Worker EmitIntegralUnOp(invoke, [&](XRegister rd, XRegister rs1) {
558*795d594fSAndroid Build Coastguard Worker ScratchRegisterScope srs(assembler);
559*795d594fSAndroid Build Coastguard Worker XRegister tmp = srs.AllocateXRegister();
560*795d594fSAndroid Build Coastguard Worker __ Neg(tmp, rs1);
561*795d594fSAndroid Build Coastguard Worker __ And(rd, rs1, tmp);
562*795d594fSAndroid Build Coastguard Worker });
563*795d594fSAndroid Build Coastguard Worker }
564*795d594fSAndroid Build Coastguard Worker
VisitIntegerNumberOfLeadingZeros(HInvoke * invoke)565*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitIntegerNumberOfLeadingZeros(HInvoke* invoke) {
566*795d594fSAndroid Build Coastguard Worker CreateIntToIntNoOverlapLocations(allocator_, invoke);
567*795d594fSAndroid Build Coastguard Worker }
568*795d594fSAndroid Build Coastguard Worker
VisitIntegerNumberOfLeadingZeros(HInvoke * invoke)569*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitIntegerNumberOfLeadingZeros(HInvoke* invoke) {
570*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = GetAssembler();
571*795d594fSAndroid Build Coastguard Worker EmitIntegralUnOp(invoke, [&](XRegister rd, XRegister rs1) { __ Clzw(rd, rs1); });
572*795d594fSAndroid Build Coastguard Worker }
573*795d594fSAndroid Build Coastguard Worker
VisitLongNumberOfLeadingZeros(HInvoke * invoke)574*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitLongNumberOfLeadingZeros(HInvoke* invoke) {
575*795d594fSAndroid Build Coastguard Worker CreateIntToIntNoOverlapLocations(allocator_, invoke);
576*795d594fSAndroid Build Coastguard Worker }
577*795d594fSAndroid Build Coastguard Worker
VisitLongNumberOfLeadingZeros(HInvoke * invoke)578*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitLongNumberOfLeadingZeros(HInvoke* invoke) {
579*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = GetAssembler();
580*795d594fSAndroid Build Coastguard Worker EmitIntegralUnOp(invoke, [&](XRegister rd, XRegister rs1) { __ Clz(rd, rs1); });
581*795d594fSAndroid Build Coastguard Worker }
582*795d594fSAndroid Build Coastguard Worker
VisitIntegerNumberOfTrailingZeros(HInvoke * invoke)583*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitIntegerNumberOfTrailingZeros(HInvoke* invoke) {
584*795d594fSAndroid Build Coastguard Worker CreateIntToIntNoOverlapLocations(allocator_, invoke);
585*795d594fSAndroid Build Coastguard Worker }
586*795d594fSAndroid Build Coastguard Worker
VisitIntegerNumberOfTrailingZeros(HInvoke * invoke)587*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitIntegerNumberOfTrailingZeros(HInvoke* invoke) {
588*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = GetAssembler();
589*795d594fSAndroid Build Coastguard Worker EmitIntegralUnOp(invoke, [&](XRegister rd, XRegister rs1) { __ Ctzw(rd, rs1); });
590*795d594fSAndroid Build Coastguard Worker }
591*795d594fSAndroid Build Coastguard Worker
VisitLongNumberOfTrailingZeros(HInvoke * invoke)592*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitLongNumberOfTrailingZeros(HInvoke* invoke) {
593*795d594fSAndroid Build Coastguard Worker CreateIntToIntNoOverlapLocations(allocator_, invoke);
594*795d594fSAndroid Build Coastguard Worker }
595*795d594fSAndroid Build Coastguard Worker
VisitLongNumberOfTrailingZeros(HInvoke * invoke)596*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitLongNumberOfTrailingZeros(HInvoke* invoke) {
597*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = GetAssembler();
598*795d594fSAndroid Build Coastguard Worker EmitIntegralUnOp(invoke, [&](XRegister rd, XRegister rs1) { __ Ctz(rd, rs1); });
599*795d594fSAndroid Build Coastguard Worker }
600*795d594fSAndroid Build Coastguard Worker
GenerateDivRemUnsigned(HInvoke * invoke,bool is_div,CodeGeneratorRISCV64 * codegen)601*795d594fSAndroid Build Coastguard Worker static void GenerateDivRemUnsigned(HInvoke* invoke, bool is_div, CodeGeneratorRISCV64* codegen) {
602*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = invoke->GetLocations();
603*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = codegen->GetAssembler();
604*795d594fSAndroid Build Coastguard Worker DataType::Type type = invoke->GetType();
605*795d594fSAndroid Build Coastguard Worker DCHECK(type == DataType::Type::kInt32 || type == DataType::Type::kInt64);
606*795d594fSAndroid Build Coastguard Worker
607*795d594fSAndroid Build Coastguard Worker XRegister dividend = locations->InAt(0).AsRegister<XRegister>();
608*795d594fSAndroid Build Coastguard Worker XRegister divisor = locations->InAt(1).AsRegister<XRegister>();
609*795d594fSAndroid Build Coastguard Worker XRegister out = locations->Out().AsRegister<XRegister>();
610*795d594fSAndroid Build Coastguard Worker
611*795d594fSAndroid Build Coastguard Worker // Check if divisor is zero, bail to managed implementation to handle.
612*795d594fSAndroid Build Coastguard Worker SlowPathCodeRISCV64* slow_path =
613*795d594fSAndroid Build Coastguard Worker new (codegen->GetScopedAllocator()) IntrinsicSlowPathRISCV64(invoke);
614*795d594fSAndroid Build Coastguard Worker codegen->AddSlowPath(slow_path);
615*795d594fSAndroid Build Coastguard Worker __ Beqz(divisor, slow_path->GetEntryLabel());
616*795d594fSAndroid Build Coastguard Worker
617*795d594fSAndroid Build Coastguard Worker if (is_div) {
618*795d594fSAndroid Build Coastguard Worker if (type == DataType::Type::kInt32) {
619*795d594fSAndroid Build Coastguard Worker __ Divuw(out, dividend, divisor);
620*795d594fSAndroid Build Coastguard Worker } else {
621*795d594fSAndroid Build Coastguard Worker __ Divu(out, dividend, divisor);
622*795d594fSAndroid Build Coastguard Worker }
623*795d594fSAndroid Build Coastguard Worker } else {
624*795d594fSAndroid Build Coastguard Worker if (type == DataType::Type::kInt32) {
625*795d594fSAndroid Build Coastguard Worker __ Remuw(out, dividend, divisor);
626*795d594fSAndroid Build Coastguard Worker } else {
627*795d594fSAndroid Build Coastguard Worker __ Remu(out, dividend, divisor);
628*795d594fSAndroid Build Coastguard Worker }
629*795d594fSAndroid Build Coastguard Worker }
630*795d594fSAndroid Build Coastguard Worker
631*795d594fSAndroid Build Coastguard Worker __ Bind(slow_path->GetExitLabel());
632*795d594fSAndroid Build Coastguard Worker }
633*795d594fSAndroid Build Coastguard Worker
VisitIntegerDivideUnsigned(HInvoke * invoke)634*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitIntegerDivideUnsigned(HInvoke* invoke) {
635*795d594fSAndroid Build Coastguard Worker CreateIntIntToIntSlowPathCallLocations(allocator_, invoke);
636*795d594fSAndroid Build Coastguard Worker }
637*795d594fSAndroid Build Coastguard Worker
VisitIntegerDivideUnsigned(HInvoke * invoke)638*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitIntegerDivideUnsigned(HInvoke* invoke) {
639*795d594fSAndroid Build Coastguard Worker GenerateDivRemUnsigned(invoke, /*is_div=*/true, codegen_);
640*795d594fSAndroid Build Coastguard Worker }
641*795d594fSAndroid Build Coastguard Worker
VisitLongDivideUnsigned(HInvoke * invoke)642*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitLongDivideUnsigned(HInvoke* invoke) {
643*795d594fSAndroid Build Coastguard Worker CreateIntIntToIntSlowPathCallLocations(allocator_, invoke);
644*795d594fSAndroid Build Coastguard Worker }
645*795d594fSAndroid Build Coastguard Worker
VisitLongDivideUnsigned(HInvoke * invoke)646*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitLongDivideUnsigned(HInvoke* invoke) {
647*795d594fSAndroid Build Coastguard Worker GenerateDivRemUnsigned(invoke, /*is_div=*/true, codegen_);
648*795d594fSAndroid Build Coastguard Worker }
649*795d594fSAndroid Build Coastguard Worker
VisitIntegerRemainderUnsigned(HInvoke * invoke)650*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitIntegerRemainderUnsigned(HInvoke* invoke) {
651*795d594fSAndroid Build Coastguard Worker CreateIntIntToIntSlowPathCallLocations(allocator_, invoke);
652*795d594fSAndroid Build Coastguard Worker }
653*795d594fSAndroid Build Coastguard Worker
VisitIntegerRemainderUnsigned(HInvoke * invoke)654*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitIntegerRemainderUnsigned(HInvoke* invoke) {
655*795d594fSAndroid Build Coastguard Worker GenerateDivRemUnsigned(invoke, /*is_div=*/false, codegen_);
656*795d594fSAndroid Build Coastguard Worker }
657*795d594fSAndroid Build Coastguard Worker
VisitLongRemainderUnsigned(HInvoke * invoke)658*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitLongRemainderUnsigned(HInvoke* invoke) {
659*795d594fSAndroid Build Coastguard Worker CreateIntIntToIntSlowPathCallLocations(allocator_, invoke);
660*795d594fSAndroid Build Coastguard Worker }
661*795d594fSAndroid Build Coastguard Worker
VisitLongRemainderUnsigned(HInvoke * invoke)662*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitLongRemainderUnsigned(HInvoke* invoke) {
663*795d594fSAndroid Build Coastguard Worker GenerateDivRemUnsigned(invoke, /*is_div=*/false, codegen_);
664*795d594fSAndroid Build Coastguard Worker }
665*795d594fSAndroid Build Coastguard Worker
666*795d594fSAndroid Build Coastguard Worker #define VISIT_INTRINSIC(name, low, high, type, start_index) \
667*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::Visit##name##ValueOf(HInvoke* invoke) { \
668*795d594fSAndroid Build Coastguard Worker InvokeRuntimeCallingConvention calling_convention; \
669*795d594fSAndroid Build Coastguard Worker IntrinsicVisitor::ComputeValueOfLocations( \
670*795d594fSAndroid Build Coastguard Worker invoke, \
671*795d594fSAndroid Build Coastguard Worker codegen_, \
672*795d594fSAndroid Build Coastguard Worker low, \
673*795d594fSAndroid Build Coastguard Worker (high) - (low) + 1, \
674*795d594fSAndroid Build Coastguard Worker calling_convention.GetReturnLocation(DataType::Type::kReference), \
675*795d594fSAndroid Build Coastguard Worker Location::RegisterLocation(calling_convention.GetRegisterAt(0))); \
676*795d594fSAndroid Build Coastguard Worker } \
677*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::Visit##name##ValueOf(HInvoke* invoke) { \
678*795d594fSAndroid Build Coastguard Worker IntrinsicVisitor::ValueOfInfo info = \
679*795d594fSAndroid Build Coastguard Worker IntrinsicVisitor::ComputeValueOfInfo(invoke, \
680*795d594fSAndroid Build Coastguard Worker codegen_->GetCompilerOptions(), \
681*795d594fSAndroid Build Coastguard Worker WellKnownClasses::java_lang_##name##_value, \
682*795d594fSAndroid Build Coastguard Worker low, \
683*795d594fSAndroid Build Coastguard Worker (high) - (low) + 1, \
684*795d594fSAndroid Build Coastguard Worker start_index); \
685*795d594fSAndroid Build Coastguard Worker HandleValueOf(invoke, info, type); \
686*795d594fSAndroid Build Coastguard Worker }
BOXED_TYPES(VISIT_INTRINSIC)687*795d594fSAndroid Build Coastguard Worker BOXED_TYPES(VISIT_INTRINSIC)
688*795d594fSAndroid Build Coastguard Worker #undef VISIT_INTRINSIC
689*795d594fSAndroid Build Coastguard Worker
690*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::HandleValueOf(HInvoke* invoke,
691*795d594fSAndroid Build Coastguard Worker const IntrinsicVisitor::ValueOfInfo& info,
692*795d594fSAndroid Build Coastguard Worker DataType::Type type) {
693*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = codegen_->GetAssembler();
694*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = invoke->GetLocations();
695*795d594fSAndroid Build Coastguard Worker XRegister out = locations->Out().AsRegister<XRegister>();
696*795d594fSAndroid Build Coastguard Worker ScratchRegisterScope srs(assembler);
697*795d594fSAndroid Build Coastguard Worker XRegister temp = srs.AllocateXRegister();
698*795d594fSAndroid Build Coastguard Worker auto allocate_instance = [&]() {
699*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(out, InvokeRuntimeCallingConvention().GetRegisterAt(0));
700*795d594fSAndroid Build Coastguard Worker codegen_->LoadIntrinsicDeclaringClass(out, invoke);
701*795d594fSAndroid Build Coastguard Worker codegen_->InvokeRuntime(kQuickAllocObjectInitialized, invoke, invoke->GetDexPc());
702*795d594fSAndroid Build Coastguard Worker CheckEntrypointTypes<kQuickAllocObjectWithChecks, void*, mirror::Class*>();
703*795d594fSAndroid Build Coastguard Worker };
704*795d594fSAndroid Build Coastguard Worker if (invoke->InputAt(0)->IsIntConstant()) {
705*795d594fSAndroid Build Coastguard Worker int32_t value = invoke->InputAt(0)->AsIntConstant()->GetValue();
706*795d594fSAndroid Build Coastguard Worker if (static_cast<uint32_t>(value - info.low) < info.length) {
707*795d594fSAndroid Build Coastguard Worker // Just embed the object in the code.
708*795d594fSAndroid Build Coastguard Worker DCHECK_NE(info.value_boot_image_reference, ValueOfInfo::kInvalidReference);
709*795d594fSAndroid Build Coastguard Worker codegen_->LoadBootImageAddress(out, info.value_boot_image_reference);
710*795d594fSAndroid Build Coastguard Worker } else {
711*795d594fSAndroid Build Coastguard Worker DCHECK(locations->CanCall());
712*795d594fSAndroid Build Coastguard Worker // Allocate and initialize a new object.
713*795d594fSAndroid Build Coastguard Worker // TODO: If we JIT, we could allocate the object now, and store it in the
714*795d594fSAndroid Build Coastguard Worker // JIT object table.
715*795d594fSAndroid Build Coastguard Worker allocate_instance();
716*795d594fSAndroid Build Coastguard Worker __ Li(temp, value);
717*795d594fSAndroid Build Coastguard Worker codegen_->GetInstructionVisitor()->Store(
718*795d594fSAndroid Build Coastguard Worker Location::RegisterLocation(temp), out, info.value_offset, type);
719*795d594fSAndroid Build Coastguard Worker // Class pointer and `value` final field stores require a barrier before publication.
720*795d594fSAndroid Build Coastguard Worker codegen_->GenerateMemoryBarrier(MemBarrierKind::kStoreStore);
721*795d594fSAndroid Build Coastguard Worker }
722*795d594fSAndroid Build Coastguard Worker } else {
723*795d594fSAndroid Build Coastguard Worker DCHECK(locations->CanCall());
724*795d594fSAndroid Build Coastguard Worker XRegister in = locations->InAt(0).AsRegister<XRegister>();
725*795d594fSAndroid Build Coastguard Worker Riscv64Label allocate, done;
726*795d594fSAndroid Build Coastguard Worker // Check bounds of our cache.
727*795d594fSAndroid Build Coastguard Worker __ AddConst32(out, in, -info.low);
728*795d594fSAndroid Build Coastguard Worker __ Li(temp, info.length);
729*795d594fSAndroid Build Coastguard Worker __ Bgeu(out, temp, &allocate);
730*795d594fSAndroid Build Coastguard Worker // If the value is within the bounds, load the object directly from the array.
731*795d594fSAndroid Build Coastguard Worker codegen_->LoadBootImageAddress(temp, info.array_data_boot_image_reference);
732*795d594fSAndroid Build Coastguard Worker __ Sh2Add(temp, out, temp);
733*795d594fSAndroid Build Coastguard Worker __ Loadwu(out, temp, 0);
734*795d594fSAndroid Build Coastguard Worker codegen_->MaybeUnpoisonHeapReference(out);
735*795d594fSAndroid Build Coastguard Worker __ J(&done);
736*795d594fSAndroid Build Coastguard Worker __ Bind(&allocate);
737*795d594fSAndroid Build Coastguard Worker // Otherwise allocate and initialize a new object.
738*795d594fSAndroid Build Coastguard Worker allocate_instance();
739*795d594fSAndroid Build Coastguard Worker codegen_->GetInstructionVisitor()->Store(
740*795d594fSAndroid Build Coastguard Worker Location::RegisterLocation(in), out, info.value_offset, type);
741*795d594fSAndroid Build Coastguard Worker // Class pointer and `value` final field stores require a barrier before publication.
742*795d594fSAndroid Build Coastguard Worker codegen_->GenerateMemoryBarrier(MemBarrierKind::kStoreStore);
743*795d594fSAndroid Build Coastguard Worker __ Bind(&done);
744*795d594fSAndroid Build Coastguard Worker }
745*795d594fSAndroid Build Coastguard Worker }
746*795d594fSAndroid Build Coastguard Worker
VisitReferenceGetReferent(HInvoke * invoke)747*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitReferenceGetReferent(HInvoke* invoke) {
748*795d594fSAndroid Build Coastguard Worker IntrinsicVisitor::CreateReferenceGetReferentLocations(invoke, codegen_);
749*795d594fSAndroid Build Coastguard Worker
750*795d594fSAndroid Build Coastguard Worker if (codegen_->EmitBakerReadBarrier() && invoke->GetLocations() != nullptr) {
751*795d594fSAndroid Build Coastguard Worker invoke->GetLocations()->AddTemp(Location::RequiresRegister());
752*795d594fSAndroid Build Coastguard Worker }
753*795d594fSAndroid Build Coastguard Worker }
754*795d594fSAndroid Build Coastguard Worker
VisitReferenceGetReferent(HInvoke * invoke)755*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitReferenceGetReferent(HInvoke* invoke) {
756*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = GetAssembler();
757*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = invoke->GetLocations();
758*795d594fSAndroid Build Coastguard Worker Location obj = locations->InAt(0);
759*795d594fSAndroid Build Coastguard Worker Location out = locations->Out();
760*795d594fSAndroid Build Coastguard Worker
761*795d594fSAndroid Build Coastguard Worker SlowPathCodeRISCV64* slow_path =
762*795d594fSAndroid Build Coastguard Worker new (codegen_->GetScopedAllocator()) IntrinsicSlowPathRISCV64(invoke);
763*795d594fSAndroid Build Coastguard Worker codegen_->AddSlowPath(slow_path);
764*795d594fSAndroid Build Coastguard Worker
765*795d594fSAndroid Build Coastguard Worker if (codegen_->EmitReadBarrier()) {
766*795d594fSAndroid Build Coastguard Worker // Check self->GetWeakRefAccessEnabled().
767*795d594fSAndroid Build Coastguard Worker ScratchRegisterScope srs(assembler);
768*795d594fSAndroid Build Coastguard Worker XRegister temp = srs.AllocateXRegister();
769*795d594fSAndroid Build Coastguard Worker __ Loadwu(temp, TR, Thread::WeakRefAccessEnabledOffset<kRiscv64PointerSize>().Int32Value());
770*795d594fSAndroid Build Coastguard Worker static_assert(enum_cast<int32_t>(WeakRefAccessState::kVisiblyEnabled) == 0);
771*795d594fSAndroid Build Coastguard Worker __ Bnez(temp, slow_path->GetEntryLabel());
772*795d594fSAndroid Build Coastguard Worker }
773*795d594fSAndroid Build Coastguard Worker
774*795d594fSAndroid Build Coastguard Worker {
775*795d594fSAndroid Build Coastguard Worker // Load the java.lang.ref.Reference class.
776*795d594fSAndroid Build Coastguard Worker ScratchRegisterScope srs(assembler);
777*795d594fSAndroid Build Coastguard Worker XRegister temp = srs.AllocateXRegister();
778*795d594fSAndroid Build Coastguard Worker codegen_->LoadIntrinsicDeclaringClass(temp, invoke);
779*795d594fSAndroid Build Coastguard Worker
780*795d594fSAndroid Build Coastguard Worker // Check static fields java.lang.ref.Reference.{disableIntrinsic,slowPathEnabled} together.
781*795d594fSAndroid Build Coastguard Worker MemberOffset disable_intrinsic_offset = IntrinsicVisitor::GetReferenceDisableIntrinsicOffset();
782*795d594fSAndroid Build Coastguard Worker DCHECK_ALIGNED(disable_intrinsic_offset.Uint32Value(), 2u);
783*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(disable_intrinsic_offset.Uint32Value() + 1u,
784*795d594fSAndroid Build Coastguard Worker IntrinsicVisitor::GetReferenceSlowPathEnabledOffset().Uint32Value());
785*795d594fSAndroid Build Coastguard Worker __ Loadhu(temp, temp, disable_intrinsic_offset.Int32Value());
786*795d594fSAndroid Build Coastguard Worker __ Bnez(temp, slow_path->GetEntryLabel());
787*795d594fSAndroid Build Coastguard Worker }
788*795d594fSAndroid Build Coastguard Worker
789*795d594fSAndroid Build Coastguard Worker // Load the value from the field.
790*795d594fSAndroid Build Coastguard Worker uint32_t referent_offset = mirror::Reference::ReferentOffset().Uint32Value();
791*795d594fSAndroid Build Coastguard Worker if (codegen_->EmitBakerReadBarrier()) {
792*795d594fSAndroid Build Coastguard Worker codegen_->GenerateFieldLoadWithBakerReadBarrier(invoke,
793*795d594fSAndroid Build Coastguard Worker out,
794*795d594fSAndroid Build Coastguard Worker obj.AsRegister<XRegister>(),
795*795d594fSAndroid Build Coastguard Worker referent_offset,
796*795d594fSAndroid Build Coastguard Worker /*temp=*/locations->GetTemp(0),
797*795d594fSAndroid Build Coastguard Worker /*needs_null_check=*/false);
798*795d594fSAndroid Build Coastguard Worker } else {
799*795d594fSAndroid Build Coastguard Worker codegen_->GetInstructionVisitor()->Load(
800*795d594fSAndroid Build Coastguard Worker out, obj.AsRegister<XRegister>(), referent_offset, DataType::Type::kReference);
801*795d594fSAndroid Build Coastguard Worker codegen_->MaybeGenerateReadBarrierSlow(invoke, out, out, obj, referent_offset);
802*795d594fSAndroid Build Coastguard Worker }
803*795d594fSAndroid Build Coastguard Worker // Emit memory barrier for load-acquire.
804*795d594fSAndroid Build Coastguard Worker codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
805*795d594fSAndroid Build Coastguard Worker __ Bind(slow_path->GetExitLabel());
806*795d594fSAndroid Build Coastguard Worker }
807*795d594fSAndroid Build Coastguard Worker
VisitReferenceRefersTo(HInvoke * invoke)808*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitReferenceRefersTo(HInvoke* invoke) {
809*795d594fSAndroid Build Coastguard Worker IntrinsicVisitor::CreateReferenceRefersToLocations(invoke, codegen_);
810*795d594fSAndroid Build Coastguard Worker }
811*795d594fSAndroid Build Coastguard Worker
VisitReferenceRefersTo(HInvoke * invoke)812*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitReferenceRefersTo(HInvoke* invoke) {
813*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = GetAssembler();
814*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = invoke->GetLocations();
815*795d594fSAndroid Build Coastguard Worker XRegister obj = locations->InAt(0).AsRegister<XRegister>();
816*795d594fSAndroid Build Coastguard Worker XRegister other = locations->InAt(1).AsRegister<XRegister>();
817*795d594fSAndroid Build Coastguard Worker XRegister out = locations->Out().AsRegister<XRegister>();
818*795d594fSAndroid Build Coastguard Worker
819*795d594fSAndroid Build Coastguard Worker uint32_t referent_offset = mirror::Reference::ReferentOffset().Uint32Value();
820*795d594fSAndroid Build Coastguard Worker uint32_t monitor_offset = mirror::Object::MonitorOffset().Int32Value();
821*795d594fSAndroid Build Coastguard Worker
822*795d594fSAndroid Build Coastguard Worker codegen_->GetInstructionVisitor()->Load(
823*795d594fSAndroid Build Coastguard Worker Location::RegisterLocation(out), obj, referent_offset, DataType::Type::kReference);
824*795d594fSAndroid Build Coastguard Worker codegen_->MaybeRecordImplicitNullCheck(invoke);
825*795d594fSAndroid Build Coastguard Worker codegen_->MaybeUnpoisonHeapReference(out);
826*795d594fSAndroid Build Coastguard Worker
827*795d594fSAndroid Build Coastguard Worker // Emit memory barrier for load-acquire.
828*795d594fSAndroid Build Coastguard Worker codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
829*795d594fSAndroid Build Coastguard Worker
830*795d594fSAndroid Build Coastguard Worker if (codegen_->EmitReadBarrier()) {
831*795d594fSAndroid Build Coastguard Worker DCHECK(kUseBakerReadBarrier);
832*795d594fSAndroid Build Coastguard Worker
833*795d594fSAndroid Build Coastguard Worker Riscv64Label calculate_result;
834*795d594fSAndroid Build Coastguard Worker
835*795d594fSAndroid Build Coastguard Worker // If equal to `other`, the loaded reference is final (it cannot be a from-space reference).
836*795d594fSAndroid Build Coastguard Worker __ Beq(out, other, &calculate_result);
837*795d594fSAndroid Build Coastguard Worker
838*795d594fSAndroid Build Coastguard Worker // If the GC is not marking, the loaded reference is final.
839*795d594fSAndroid Build Coastguard Worker ScratchRegisterScope srs(assembler);
840*795d594fSAndroid Build Coastguard Worker XRegister tmp = srs.AllocateXRegister();
841*795d594fSAndroid Build Coastguard Worker __ Loadwu(tmp, TR, Thread::IsGcMarkingOffset<kRiscv64PointerSize>().Int32Value());
842*795d594fSAndroid Build Coastguard Worker __ Beqz(tmp, &calculate_result);
843*795d594fSAndroid Build Coastguard Worker
844*795d594fSAndroid Build Coastguard Worker // Check if the loaded reference is null.
845*795d594fSAndroid Build Coastguard Worker __ Beqz(out, &calculate_result);
846*795d594fSAndroid Build Coastguard Worker
847*795d594fSAndroid Build Coastguard Worker // For correct memory visibility, we need a barrier before loading the lock word to
848*795d594fSAndroid Build Coastguard Worker // synchronize with the publishing of `other` by the CC GC. However, as long as the
849*795d594fSAndroid Build Coastguard Worker // load-acquire above is implemented as a plain load followed by a barrier (rather
850*795d594fSAndroid Build Coastguard Worker // than an atomic load-acquire instruction which synchronizes only with other
851*795d594fSAndroid Build Coastguard Worker // instructions on the same memory location), that barrier is sufficient.
852*795d594fSAndroid Build Coastguard Worker
853*795d594fSAndroid Build Coastguard Worker // Load the lockword and check if it is a forwarding address.
854*795d594fSAndroid Build Coastguard Worker static_assert(LockWord::kStateShift == 30u);
855*795d594fSAndroid Build Coastguard Worker static_assert(LockWord::kStateForwardingAddress == 3u);
856*795d594fSAndroid Build Coastguard Worker // Load the lock word sign-extended. Comparing it to the sign-extended forwarding
857*795d594fSAndroid Build Coastguard Worker // address bits as unsigned is the same as comparing both zero-extended.
858*795d594fSAndroid Build Coastguard Worker __ Loadw(tmp, out, monitor_offset);
859*795d594fSAndroid Build Coastguard Worker // Materialize sign-extended forwarding address bits. This is a single LUI instruction.
860*795d594fSAndroid Build Coastguard Worker XRegister tmp2 = srs.AllocateXRegister();
861*795d594fSAndroid Build Coastguard Worker __ Li(tmp2, INT64_C(-1) & ~static_cast<int64_t>((1 << LockWord::kStateShift) - 1));
862*795d594fSAndroid Build Coastguard Worker // If we do not have a forwarding address, the loaded reference cannot be the same as `other`,
863*795d594fSAndroid Build Coastguard Worker // so we proceed to calculate the result with `out != other`.
864*795d594fSAndroid Build Coastguard Worker __ Bltu(tmp, tmp2, &calculate_result);
865*795d594fSAndroid Build Coastguard Worker
866*795d594fSAndroid Build Coastguard Worker // Extract the forwarding address for comparison with `other`.
867*795d594fSAndroid Build Coastguard Worker // Note that the high 32 bits shall not be used for the result calculation.
868*795d594fSAndroid Build Coastguard Worker __ Slliw(out, tmp, LockWord::kForwardingAddressShift);
869*795d594fSAndroid Build Coastguard Worker
870*795d594fSAndroid Build Coastguard Worker __ Bind(&calculate_result);
871*795d594fSAndroid Build Coastguard Worker }
872*795d594fSAndroid Build Coastguard Worker
873*795d594fSAndroid Build Coastguard Worker // Calculate the result `out == other`.
874*795d594fSAndroid Build Coastguard Worker __ Subw(out, out, other);
875*795d594fSAndroid Build Coastguard Worker __ Seqz(out, out);
876*795d594fSAndroid Build Coastguard Worker }
877*795d594fSAndroid Build Coastguard Worker
GenerateVisitStringIndexOf(HInvoke * invoke,Riscv64Assembler * assembler,CodeGeneratorRISCV64 * codegen,bool start_at_zero)878*795d594fSAndroid Build Coastguard Worker static void GenerateVisitStringIndexOf(HInvoke* invoke,
879*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler,
880*795d594fSAndroid Build Coastguard Worker CodeGeneratorRISCV64* codegen,
881*795d594fSAndroid Build Coastguard Worker bool start_at_zero) {
882*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = invoke->GetLocations();
883*795d594fSAndroid Build Coastguard Worker
884*795d594fSAndroid Build Coastguard Worker // Note that the null check must have been done earlier.
885*795d594fSAndroid Build Coastguard Worker DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0)));
886*795d594fSAndroid Build Coastguard Worker
887*795d594fSAndroid Build Coastguard Worker // Check for code points > 0xFFFF. Either a slow-path check when we don't know statically,
888*795d594fSAndroid Build Coastguard Worker // or directly dispatch for a large constant, or omit slow-path for a small constant or a char.
889*795d594fSAndroid Build Coastguard Worker SlowPathCodeRISCV64* slow_path = nullptr;
890*795d594fSAndroid Build Coastguard Worker HInstruction* code_point = invoke->InputAt(1);
891*795d594fSAndroid Build Coastguard Worker if (code_point->IsIntConstant()) {
892*795d594fSAndroid Build Coastguard Worker if (static_cast<uint32_t>(code_point->AsIntConstant()->GetValue()) > 0xFFFFU) {
893*795d594fSAndroid Build Coastguard Worker // Always needs the slow-path. We could directly dispatch to it, but this case should be
894*795d594fSAndroid Build Coastguard Worker // rare, so for simplicity just put the full slow-path down and branch unconditionally.
895*795d594fSAndroid Build Coastguard Worker slow_path = new (codegen->GetScopedAllocator()) IntrinsicSlowPathRISCV64(invoke);
896*795d594fSAndroid Build Coastguard Worker codegen->AddSlowPath(slow_path);
897*795d594fSAndroid Build Coastguard Worker __ J(slow_path->GetEntryLabel());
898*795d594fSAndroid Build Coastguard Worker __ Bind(slow_path->GetExitLabel());
899*795d594fSAndroid Build Coastguard Worker return;
900*795d594fSAndroid Build Coastguard Worker }
901*795d594fSAndroid Build Coastguard Worker } else if (code_point->GetType() != DataType::Type::kUint16) {
902*795d594fSAndroid Build Coastguard Worker slow_path = new (codegen->GetScopedAllocator()) IntrinsicSlowPathRISCV64(invoke);
903*795d594fSAndroid Build Coastguard Worker codegen->AddSlowPath(slow_path);
904*795d594fSAndroid Build Coastguard Worker ScratchRegisterScope srs(assembler);
905*795d594fSAndroid Build Coastguard Worker XRegister tmp = srs.AllocateXRegister();
906*795d594fSAndroid Build Coastguard Worker __ Srliw(tmp, locations->InAt(1).AsRegister<XRegister>(), 16);
907*795d594fSAndroid Build Coastguard Worker __ Bnez(tmp, slow_path->GetEntryLabel());
908*795d594fSAndroid Build Coastguard Worker }
909*795d594fSAndroid Build Coastguard Worker
910*795d594fSAndroid Build Coastguard Worker if (start_at_zero) {
911*795d594fSAndroid Build Coastguard Worker // Start-index = 0.
912*795d594fSAndroid Build Coastguard Worker XRegister tmp_reg = locations->GetTemp(0).AsRegister<XRegister>();
913*795d594fSAndroid Build Coastguard Worker __ Li(tmp_reg, 0);
914*795d594fSAndroid Build Coastguard Worker }
915*795d594fSAndroid Build Coastguard Worker
916*795d594fSAndroid Build Coastguard Worker codegen->InvokeRuntime(kQuickIndexOf, invoke, invoke->GetDexPc(), slow_path);
917*795d594fSAndroid Build Coastguard Worker CheckEntrypointTypes<kQuickIndexOf, int32_t, void*, uint32_t, uint32_t>();
918*795d594fSAndroid Build Coastguard Worker
919*795d594fSAndroid Build Coastguard Worker if (slow_path != nullptr) {
920*795d594fSAndroid Build Coastguard Worker __ Bind(slow_path->GetExitLabel());
921*795d594fSAndroid Build Coastguard Worker }
922*795d594fSAndroid Build Coastguard Worker }
923*795d594fSAndroid Build Coastguard Worker
VisitStringIndexOf(HInvoke * invoke)924*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitStringIndexOf(HInvoke* invoke) {
925*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = new (allocator_) LocationSummary(
926*795d594fSAndroid Build Coastguard Worker invoke, LocationSummary::kCallOnMainAndSlowPath, kIntrinsified);
927*795d594fSAndroid Build Coastguard Worker // We have a hand-crafted assembly stub that follows the runtime calling convention. So it's
928*795d594fSAndroid Build Coastguard Worker // best to align the inputs accordingly.
929*795d594fSAndroid Build Coastguard Worker InvokeRuntimeCallingConvention calling_convention;
930*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
931*795d594fSAndroid Build Coastguard Worker locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
932*795d594fSAndroid Build Coastguard Worker locations->SetOut(calling_convention.GetReturnLocation(DataType::Type::kInt32));
933*795d594fSAndroid Build Coastguard Worker
934*795d594fSAndroid Build Coastguard Worker // Need to send start_index=0.
935*795d594fSAndroid Build Coastguard Worker locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
936*795d594fSAndroid Build Coastguard Worker }
937*795d594fSAndroid Build Coastguard Worker
VisitStringIndexOf(HInvoke * invoke)938*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitStringIndexOf(HInvoke* invoke) {
939*795d594fSAndroid Build Coastguard Worker GenerateVisitStringIndexOf(invoke, GetAssembler(), codegen_, /* start_at_zero= */ true);
940*795d594fSAndroid Build Coastguard Worker }
941*795d594fSAndroid Build Coastguard Worker
VisitStringIndexOfAfter(HInvoke * invoke)942*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitStringIndexOfAfter(HInvoke* invoke) {
943*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = new (allocator_) LocationSummary(
944*795d594fSAndroid Build Coastguard Worker invoke, LocationSummary::kCallOnMainAndSlowPath, kIntrinsified);
945*795d594fSAndroid Build Coastguard Worker // We have a hand-crafted assembly stub that follows the runtime calling convention. So it's
946*795d594fSAndroid Build Coastguard Worker // best to align the inputs accordingly.
947*795d594fSAndroid Build Coastguard Worker InvokeRuntimeCallingConvention calling_convention;
948*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
949*795d594fSAndroid Build Coastguard Worker locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
950*795d594fSAndroid Build Coastguard Worker locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
951*795d594fSAndroid Build Coastguard Worker locations->SetOut(calling_convention.GetReturnLocation(DataType::Type::kInt32));
952*795d594fSAndroid Build Coastguard Worker }
953*795d594fSAndroid Build Coastguard Worker
VisitStringIndexOfAfter(HInvoke * invoke)954*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitStringIndexOfAfter(HInvoke* invoke) {
955*795d594fSAndroid Build Coastguard Worker GenerateVisitStringIndexOf(invoke, GetAssembler(), codegen_, /* start_at_zero= */ false);
956*795d594fSAndroid Build Coastguard Worker }
957*795d594fSAndroid Build Coastguard Worker
VisitStringNewStringFromBytes(HInvoke * invoke)958*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitStringNewStringFromBytes(HInvoke* invoke) {
959*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = new (allocator_) LocationSummary(
960*795d594fSAndroid Build Coastguard Worker invoke, LocationSummary::kCallOnMainAndSlowPath, kIntrinsified);
961*795d594fSAndroid Build Coastguard Worker InvokeRuntimeCallingConvention calling_convention;
962*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
963*795d594fSAndroid Build Coastguard Worker locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
964*795d594fSAndroid Build Coastguard Worker locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
965*795d594fSAndroid Build Coastguard Worker locations->SetInAt(3, Location::RegisterLocation(calling_convention.GetRegisterAt(3)));
966*795d594fSAndroid Build Coastguard Worker locations->SetOut(calling_convention.GetReturnLocation(DataType::Type::kReference));
967*795d594fSAndroid Build Coastguard Worker }
968*795d594fSAndroid Build Coastguard Worker
VisitStringNewStringFromBytes(HInvoke * invoke)969*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitStringNewStringFromBytes(HInvoke* invoke) {
970*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = GetAssembler();
971*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = invoke->GetLocations();
972*795d594fSAndroid Build Coastguard Worker XRegister byte_array = locations->InAt(0).AsRegister<XRegister>();
973*795d594fSAndroid Build Coastguard Worker
974*795d594fSAndroid Build Coastguard Worker SlowPathCodeRISCV64* slow_path =
975*795d594fSAndroid Build Coastguard Worker new (codegen_->GetScopedAllocator()) IntrinsicSlowPathRISCV64(invoke);
976*795d594fSAndroid Build Coastguard Worker codegen_->AddSlowPath(slow_path);
977*795d594fSAndroid Build Coastguard Worker __ Beqz(byte_array, slow_path->GetEntryLabel());
978*795d594fSAndroid Build Coastguard Worker
979*795d594fSAndroid Build Coastguard Worker codegen_->InvokeRuntime(kQuickAllocStringFromBytes, invoke, invoke->GetDexPc(), slow_path);
980*795d594fSAndroid Build Coastguard Worker CheckEntrypointTypes<kQuickAllocStringFromBytes, void*, void*, int32_t, int32_t, int32_t>();
981*795d594fSAndroid Build Coastguard Worker __ Bind(slow_path->GetExitLabel());
982*795d594fSAndroid Build Coastguard Worker }
983*795d594fSAndroid Build Coastguard Worker
VisitStringNewStringFromChars(HInvoke * invoke)984*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitStringNewStringFromChars(HInvoke* invoke) {
985*795d594fSAndroid Build Coastguard Worker LocationSummary* locations =
986*795d594fSAndroid Build Coastguard Worker new (allocator_) LocationSummary(invoke, LocationSummary::kCallOnMainOnly, kIntrinsified);
987*795d594fSAndroid Build Coastguard Worker InvokeRuntimeCallingConvention calling_convention;
988*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
989*795d594fSAndroid Build Coastguard Worker locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
990*795d594fSAndroid Build Coastguard Worker locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
991*795d594fSAndroid Build Coastguard Worker locations->SetOut(calling_convention.GetReturnLocation(DataType::Type::kReference));
992*795d594fSAndroid Build Coastguard Worker }
993*795d594fSAndroid Build Coastguard Worker
VisitStringNewStringFromChars(HInvoke * invoke)994*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitStringNewStringFromChars(HInvoke* invoke) {
995*795d594fSAndroid Build Coastguard Worker // No need to emit code checking whether `locations->InAt(2)` is a null
996*795d594fSAndroid Build Coastguard Worker // pointer, as callers of the native method
997*795d594fSAndroid Build Coastguard Worker //
998*795d594fSAndroid Build Coastguard Worker // java.lang.StringFactory.newStringFromChars(int offset, int charCount, char[] data)
999*795d594fSAndroid Build Coastguard Worker //
1000*795d594fSAndroid Build Coastguard Worker // all include a null check on `data` before calling that method.
1001*795d594fSAndroid Build Coastguard Worker codegen_->InvokeRuntime(kQuickAllocStringFromChars, invoke, invoke->GetDexPc());
1002*795d594fSAndroid Build Coastguard Worker CheckEntrypointTypes<kQuickAllocStringFromChars, void*, int32_t, int32_t, void*>();
1003*795d594fSAndroid Build Coastguard Worker }
1004*795d594fSAndroid Build Coastguard Worker
VisitStringNewStringFromString(HInvoke * invoke)1005*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitStringNewStringFromString(HInvoke* invoke) {
1006*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = new (allocator_) LocationSummary(
1007*795d594fSAndroid Build Coastguard Worker invoke, LocationSummary::kCallOnMainAndSlowPath, kIntrinsified);
1008*795d594fSAndroid Build Coastguard Worker InvokeRuntimeCallingConvention calling_convention;
1009*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1010*795d594fSAndroid Build Coastguard Worker locations->SetOut(calling_convention.GetReturnLocation(DataType::Type::kReference));
1011*795d594fSAndroid Build Coastguard Worker }
1012*795d594fSAndroid Build Coastguard Worker
VisitStringNewStringFromString(HInvoke * invoke)1013*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitStringNewStringFromString(HInvoke* invoke) {
1014*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = GetAssembler();
1015*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = invoke->GetLocations();
1016*795d594fSAndroid Build Coastguard Worker XRegister string_to_copy = locations->InAt(0).AsRegister<XRegister>();
1017*795d594fSAndroid Build Coastguard Worker
1018*795d594fSAndroid Build Coastguard Worker SlowPathCodeRISCV64* slow_path =
1019*795d594fSAndroid Build Coastguard Worker new (codegen_->GetScopedAllocator()) IntrinsicSlowPathRISCV64(invoke);
1020*795d594fSAndroid Build Coastguard Worker codegen_->AddSlowPath(slow_path);
1021*795d594fSAndroid Build Coastguard Worker __ Beqz(string_to_copy, slow_path->GetEntryLabel());
1022*795d594fSAndroid Build Coastguard Worker
1023*795d594fSAndroid Build Coastguard Worker codegen_->InvokeRuntime(kQuickAllocStringFromString, invoke, invoke->GetDexPc(), slow_path);
1024*795d594fSAndroid Build Coastguard Worker CheckEntrypointTypes<kQuickAllocStringFromString, void*, void*>();
1025*795d594fSAndroid Build Coastguard Worker __ Bind(slow_path->GetExitLabel());
1026*795d594fSAndroid Build Coastguard Worker }
1027*795d594fSAndroid Build Coastguard Worker
GenerateSet(CodeGeneratorRISCV64 * codegen,std::memory_order order,Location value,XRegister rs1,int32_t offset,DataType::Type type)1028*795d594fSAndroid Build Coastguard Worker static void GenerateSet(CodeGeneratorRISCV64* codegen,
1029*795d594fSAndroid Build Coastguard Worker std::memory_order order,
1030*795d594fSAndroid Build Coastguard Worker Location value,
1031*795d594fSAndroid Build Coastguard Worker XRegister rs1,
1032*795d594fSAndroid Build Coastguard Worker int32_t offset,
1033*795d594fSAndroid Build Coastguard Worker DataType::Type type) {
1034*795d594fSAndroid Build Coastguard Worker if (order == std::memory_order_seq_cst) {
1035*795d594fSAndroid Build Coastguard Worker codegen->GetInstructionVisitor()->StoreSeqCst(value, rs1, offset, type);
1036*795d594fSAndroid Build Coastguard Worker } else {
1037*795d594fSAndroid Build Coastguard Worker if (order == std::memory_order_release) {
1038*795d594fSAndroid Build Coastguard Worker codegen->GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
1039*795d594fSAndroid Build Coastguard Worker } else {
1040*795d594fSAndroid Build Coastguard Worker DCHECK(order == std::memory_order_relaxed);
1041*795d594fSAndroid Build Coastguard Worker }
1042*795d594fSAndroid Build Coastguard Worker codegen->GetInstructionVisitor()->Store(value, rs1, offset, type);
1043*795d594fSAndroid Build Coastguard Worker }
1044*795d594fSAndroid Build Coastguard Worker }
1045*795d594fSAndroid Build Coastguard Worker
GetLrScAqRl(std::memory_order order)1046*795d594fSAndroid Build Coastguard Worker std::pair<AqRl, AqRl> GetLrScAqRl(std::memory_order order) {
1047*795d594fSAndroid Build Coastguard Worker AqRl load_aqrl = AqRl::kNone;
1048*795d594fSAndroid Build Coastguard Worker AqRl store_aqrl = AqRl::kNone;
1049*795d594fSAndroid Build Coastguard Worker if (order == std::memory_order_acquire) {
1050*795d594fSAndroid Build Coastguard Worker load_aqrl = AqRl::kAcquire;
1051*795d594fSAndroid Build Coastguard Worker } else if (order == std::memory_order_release) {
1052*795d594fSAndroid Build Coastguard Worker store_aqrl = AqRl::kRelease;
1053*795d594fSAndroid Build Coastguard Worker } else if (order == std::memory_order_seq_cst) {
1054*795d594fSAndroid Build Coastguard Worker load_aqrl = AqRl::kAqRl;
1055*795d594fSAndroid Build Coastguard Worker store_aqrl = AqRl::kRelease;
1056*795d594fSAndroid Build Coastguard Worker } else {
1057*795d594fSAndroid Build Coastguard Worker DCHECK(order == std::memory_order_relaxed);
1058*795d594fSAndroid Build Coastguard Worker }
1059*795d594fSAndroid Build Coastguard Worker return {load_aqrl, store_aqrl};
1060*795d594fSAndroid Build Coastguard Worker }
1061*795d594fSAndroid Build Coastguard Worker
GetAmoAqRl(std::memory_order order)1062*795d594fSAndroid Build Coastguard Worker AqRl GetAmoAqRl(std::memory_order order) {
1063*795d594fSAndroid Build Coastguard Worker AqRl amo_aqrl = AqRl::kNone;
1064*795d594fSAndroid Build Coastguard Worker if (order == std::memory_order_acquire) {
1065*795d594fSAndroid Build Coastguard Worker amo_aqrl = AqRl::kAcquire;
1066*795d594fSAndroid Build Coastguard Worker } else if (order == std::memory_order_release) {
1067*795d594fSAndroid Build Coastguard Worker amo_aqrl = AqRl::kRelease;
1068*795d594fSAndroid Build Coastguard Worker } else {
1069*795d594fSAndroid Build Coastguard Worker DCHECK(order == std::memory_order_seq_cst);
1070*795d594fSAndroid Build Coastguard Worker amo_aqrl = AqRl::kAqRl;
1071*795d594fSAndroid Build Coastguard Worker }
1072*795d594fSAndroid Build Coastguard Worker return amo_aqrl;
1073*795d594fSAndroid Build Coastguard Worker }
1074*795d594fSAndroid Build Coastguard Worker
EmitLoadReserved(Riscv64Assembler * assembler,DataType::Type type,XRegister ptr,XRegister old_value,AqRl aqrl)1075*795d594fSAndroid Build Coastguard Worker static void EmitLoadReserved(Riscv64Assembler* assembler,
1076*795d594fSAndroid Build Coastguard Worker DataType::Type type,
1077*795d594fSAndroid Build Coastguard Worker XRegister ptr,
1078*795d594fSAndroid Build Coastguard Worker XRegister old_value,
1079*795d594fSAndroid Build Coastguard Worker AqRl aqrl) {
1080*795d594fSAndroid Build Coastguard Worker switch (type) {
1081*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt32:
1082*795d594fSAndroid Build Coastguard Worker __ LrW(old_value, ptr, aqrl);
1083*795d594fSAndroid Build Coastguard Worker break;
1084*795d594fSAndroid Build Coastguard Worker case DataType::Type::kReference:
1085*795d594fSAndroid Build Coastguard Worker __ LrW(old_value, ptr, aqrl);
1086*795d594fSAndroid Build Coastguard Worker // TODO(riscv64): The `ZextW()` macro currently emits `SLLI+SRLI` which are from the
1087*795d594fSAndroid Build Coastguard Worker // base "I" instruction set. When the assembler is updated to use a single-instruction
1088*795d594fSAndroid Build Coastguard Worker // `ZextW()` macro, either the ADD.UW, or the C.ZEXT.W (16-bit encoding), we need to
1089*795d594fSAndroid Build Coastguard Worker // rewrite this to avoid these non-"I" instructions. We could, for example, sign-extend
1090*795d594fSAndroid Build Coastguard Worker // the reference and do the CAS as `Int32`.
1091*795d594fSAndroid Build Coastguard Worker __ ZextW(old_value, old_value);
1092*795d594fSAndroid Build Coastguard Worker break;
1093*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt64:
1094*795d594fSAndroid Build Coastguard Worker __ LrD(old_value, ptr, aqrl);
1095*795d594fSAndroid Build Coastguard Worker break;
1096*795d594fSAndroid Build Coastguard Worker default:
1097*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unexpected type: " << type;
1098*795d594fSAndroid Build Coastguard Worker UNREACHABLE();
1099*795d594fSAndroid Build Coastguard Worker }
1100*795d594fSAndroid Build Coastguard Worker }
1101*795d594fSAndroid Build Coastguard Worker
VisitStringEquals(HInvoke * invoke)1102*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitStringEquals(HInvoke* invoke) {
1103*795d594fSAndroid Build Coastguard Worker LocationSummary* locations =
1104*795d594fSAndroid Build Coastguard Worker new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
1105*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresRegister());
1106*795d594fSAndroid Build Coastguard Worker locations->SetInAt(1, Location::RequiresRegister());
1107*795d594fSAndroid Build Coastguard Worker locations->AddTemp(Location::RequiresRegister());
1108*795d594fSAndroid Build Coastguard Worker // TODO: If the String.equals() is used only for an immediately following HIf, we can
1109*795d594fSAndroid Build Coastguard Worker // mark it as emitted-at-use-site and emit branches directly to the appropriate blocks.
1110*795d594fSAndroid Build Coastguard Worker // Then we shall need an extra temporary register instead of the output register.
1111*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
1112*795d594fSAndroid Build Coastguard Worker }
1113*795d594fSAndroid Build Coastguard Worker
VisitStringEquals(HInvoke * invoke)1114*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitStringEquals(HInvoke* invoke) {
1115*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = GetAssembler();
1116*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = invoke->GetLocations();
1117*795d594fSAndroid Build Coastguard Worker
1118*795d594fSAndroid Build Coastguard Worker // Get offsets of count, value, and class fields within a string object.
1119*795d594fSAndroid Build Coastguard Worker const int32_t count_offset = mirror::String::CountOffset().Int32Value();
1120*795d594fSAndroid Build Coastguard Worker const int32_t value_offset = mirror::String::ValueOffset().Int32Value();
1121*795d594fSAndroid Build Coastguard Worker const int32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1122*795d594fSAndroid Build Coastguard Worker
1123*795d594fSAndroid Build Coastguard Worker XRegister str = locations->InAt(0).AsRegister<XRegister>();
1124*795d594fSAndroid Build Coastguard Worker XRegister arg = locations->InAt(1).AsRegister<XRegister>();
1125*795d594fSAndroid Build Coastguard Worker XRegister out = locations->Out().AsRegister<XRegister>();
1126*795d594fSAndroid Build Coastguard Worker
1127*795d594fSAndroid Build Coastguard Worker ScratchRegisterScope srs(assembler);
1128*795d594fSAndroid Build Coastguard Worker XRegister temp = srs.AllocateXRegister();
1129*795d594fSAndroid Build Coastguard Worker XRegister temp1 = locations->GetTemp(0).AsRegister<XRegister>();
1130*795d594fSAndroid Build Coastguard Worker
1131*795d594fSAndroid Build Coastguard Worker Riscv64Label loop;
1132*795d594fSAndroid Build Coastguard Worker Riscv64Label end;
1133*795d594fSAndroid Build Coastguard Worker Riscv64Label return_true;
1134*795d594fSAndroid Build Coastguard Worker Riscv64Label return_false;
1135*795d594fSAndroid Build Coastguard Worker
1136*795d594fSAndroid Build Coastguard Worker DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0)));
1137*795d594fSAndroid Build Coastguard Worker
1138*795d594fSAndroid Build Coastguard Worker StringEqualsOptimizations optimizations(invoke);
1139*795d594fSAndroid Build Coastguard Worker if (!optimizations.GetArgumentNotNull()) {
1140*795d594fSAndroid Build Coastguard Worker // Check if input is null, return false if it is.
1141*795d594fSAndroid Build Coastguard Worker __ Beqz(arg, &return_false);
1142*795d594fSAndroid Build Coastguard Worker }
1143*795d594fSAndroid Build Coastguard Worker
1144*795d594fSAndroid Build Coastguard Worker // Reference equality check, return true if same reference.
1145*795d594fSAndroid Build Coastguard Worker __ Beq(str, arg, &return_true);
1146*795d594fSAndroid Build Coastguard Worker
1147*795d594fSAndroid Build Coastguard Worker if (!optimizations.GetArgumentIsString()) {
1148*795d594fSAndroid Build Coastguard Worker // Instanceof check for the argument by comparing class fields.
1149*795d594fSAndroid Build Coastguard Worker // All string objects must have the same type since String cannot be subclassed.
1150*795d594fSAndroid Build Coastguard Worker // Receiver must be a string object, so its class field is equal to all strings' class fields.
1151*795d594fSAndroid Build Coastguard Worker // If the argument is a string object, its class field must be equal to receiver's class field.
1152*795d594fSAndroid Build Coastguard Worker //
1153*795d594fSAndroid Build Coastguard Worker // As the String class is expected to be non-movable, we can read the class
1154*795d594fSAndroid Build Coastguard Worker // field from String.equals' arguments without read barriers.
1155*795d594fSAndroid Build Coastguard Worker AssertNonMovableStringClass();
1156*795d594fSAndroid Build Coastguard Worker // /* HeapReference<Class> */ temp = str->klass_
1157*795d594fSAndroid Build Coastguard Worker __ Loadwu(temp, str, class_offset);
1158*795d594fSAndroid Build Coastguard Worker // /* HeapReference<Class> */ temp1 = arg->klass_
1159*795d594fSAndroid Build Coastguard Worker __ Loadwu(temp1, arg, class_offset);
1160*795d594fSAndroid Build Coastguard Worker // Also, because we use the previously loaded class references only in the
1161*795d594fSAndroid Build Coastguard Worker // following comparison, we don't need to unpoison them.
1162*795d594fSAndroid Build Coastguard Worker __ Bne(temp, temp1, &return_false);
1163*795d594fSAndroid Build Coastguard Worker }
1164*795d594fSAndroid Build Coastguard Worker
1165*795d594fSAndroid Build Coastguard Worker // Load `count` fields of this and argument strings.
1166*795d594fSAndroid Build Coastguard Worker __ Loadwu(temp, str, count_offset);
1167*795d594fSAndroid Build Coastguard Worker __ Loadwu(temp1, arg, count_offset);
1168*795d594fSAndroid Build Coastguard Worker // Check if `count` fields are equal, return false if they're not.
1169*795d594fSAndroid Build Coastguard Worker // Also compares the compression style, if differs return false.
1170*795d594fSAndroid Build Coastguard Worker __ Bne(temp, temp1, &return_false);
1171*795d594fSAndroid Build Coastguard Worker
1172*795d594fSAndroid Build Coastguard Worker // Assertions that must hold in order to compare strings 8 bytes at a time.
1173*795d594fSAndroid Build Coastguard Worker // Ok to do this because strings are zero-padded to kObjectAlignment.
1174*795d594fSAndroid Build Coastguard Worker DCHECK_ALIGNED(value_offset, 8);
1175*795d594fSAndroid Build Coastguard Worker static_assert(IsAligned<8>(kObjectAlignment), "String of odd length is not zero padded");
1176*795d594fSAndroid Build Coastguard Worker
1177*795d594fSAndroid Build Coastguard Worker // Return true if both strings are empty. Even with string compression `count == 0` means empty.
1178*795d594fSAndroid Build Coastguard Worker static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u,
1179*795d594fSAndroid Build Coastguard Worker "Expecting 0=compressed, 1=uncompressed");
1180*795d594fSAndroid Build Coastguard Worker __ Beqz(temp, &return_true);
1181*795d594fSAndroid Build Coastguard Worker
1182*795d594fSAndroid Build Coastguard Worker if (mirror::kUseStringCompression) {
1183*795d594fSAndroid Build Coastguard Worker // For string compression, calculate the number of bytes to compare (not chars).
1184*795d594fSAndroid Build Coastguard Worker // This could in theory exceed INT32_MAX, so treat temp as unsigned.
1185*795d594fSAndroid Build Coastguard Worker __ Andi(temp1, temp, 1); // Extract compression flag.
1186*795d594fSAndroid Build Coastguard Worker __ Srliw(temp, temp, 1u); // Extract length.
1187*795d594fSAndroid Build Coastguard Worker __ Sllw(temp, temp, temp1); // Calculate number of bytes to compare.
1188*795d594fSAndroid Build Coastguard Worker }
1189*795d594fSAndroid Build Coastguard Worker
1190*795d594fSAndroid Build Coastguard Worker // Store offset of string value in preparation for comparison loop
1191*795d594fSAndroid Build Coastguard Worker __ Li(temp1, value_offset);
1192*795d594fSAndroid Build Coastguard Worker
1193*795d594fSAndroid Build Coastguard Worker XRegister temp2 = srs.AllocateXRegister();
1194*795d594fSAndroid Build Coastguard Worker // Loop to compare strings 8 bytes at a time starting at the front of the string.
1195*795d594fSAndroid Build Coastguard Worker __ Bind(&loop);
1196*795d594fSAndroid Build Coastguard Worker __ Add(out, str, temp1);
1197*795d594fSAndroid Build Coastguard Worker __ Ld(out, out, 0);
1198*795d594fSAndroid Build Coastguard Worker __ Add(temp2, arg, temp1);
1199*795d594fSAndroid Build Coastguard Worker __ Ld(temp2, temp2, 0);
1200*795d594fSAndroid Build Coastguard Worker __ Addi(temp1, temp1, sizeof(uint64_t));
1201*795d594fSAndroid Build Coastguard Worker __ Bne(out, temp2, &return_false);
1202*795d594fSAndroid Build Coastguard Worker // With string compression, we have compared 8 bytes, otherwise 4 chars.
1203*795d594fSAndroid Build Coastguard Worker __ Addi(temp, temp, mirror::kUseStringCompression ? -8 : -4);
1204*795d594fSAndroid Build Coastguard Worker __ Bgt(temp, Zero, &loop);
1205*795d594fSAndroid Build Coastguard Worker
1206*795d594fSAndroid Build Coastguard Worker // Return true and exit the function.
1207*795d594fSAndroid Build Coastguard Worker // If loop does not result in returning false, we return true.
1208*795d594fSAndroid Build Coastguard Worker __ Bind(&return_true);
1209*795d594fSAndroid Build Coastguard Worker __ Li(out, 1);
1210*795d594fSAndroid Build Coastguard Worker __ J(&end);
1211*795d594fSAndroid Build Coastguard Worker
1212*795d594fSAndroid Build Coastguard Worker // Return false and exit the function.
1213*795d594fSAndroid Build Coastguard Worker __ Bind(&return_false);
1214*795d594fSAndroid Build Coastguard Worker __ Li(out, 0);
1215*795d594fSAndroid Build Coastguard Worker __ Bind(&end);
1216*795d594fSAndroid Build Coastguard Worker }
1217*795d594fSAndroid Build Coastguard Worker
EmitStoreConditional(Riscv64Assembler * assembler,DataType::Type type,XRegister ptr,XRegister store_result,XRegister to_store,AqRl aqrl)1218*795d594fSAndroid Build Coastguard Worker static void EmitStoreConditional(Riscv64Assembler* assembler,
1219*795d594fSAndroid Build Coastguard Worker DataType::Type type,
1220*795d594fSAndroid Build Coastguard Worker XRegister ptr,
1221*795d594fSAndroid Build Coastguard Worker XRegister store_result,
1222*795d594fSAndroid Build Coastguard Worker XRegister to_store,
1223*795d594fSAndroid Build Coastguard Worker AqRl aqrl) {
1224*795d594fSAndroid Build Coastguard Worker switch (type) {
1225*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt32:
1226*795d594fSAndroid Build Coastguard Worker case DataType::Type::kReference:
1227*795d594fSAndroid Build Coastguard Worker __ ScW(store_result, to_store, ptr, aqrl);
1228*795d594fSAndroid Build Coastguard Worker break;
1229*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt64:
1230*795d594fSAndroid Build Coastguard Worker __ ScD(store_result, to_store, ptr, aqrl);
1231*795d594fSAndroid Build Coastguard Worker break;
1232*795d594fSAndroid Build Coastguard Worker default:
1233*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unexpected type: " << type;
1234*795d594fSAndroid Build Coastguard Worker UNREACHABLE();
1235*795d594fSAndroid Build Coastguard Worker }
1236*795d594fSAndroid Build Coastguard Worker }
1237*795d594fSAndroid Build Coastguard Worker
GenerateCompareAndSet(Riscv64Assembler * assembler,DataType::Type type,std::memory_order order,bool strong,Riscv64Label * cmp_failure,XRegister ptr,XRegister new_value,XRegister old_value,XRegister mask,XRegister masked,XRegister store_result,XRegister expected,XRegister expected2=kNoXRegister)1238*795d594fSAndroid Build Coastguard Worker static void GenerateCompareAndSet(Riscv64Assembler* assembler,
1239*795d594fSAndroid Build Coastguard Worker DataType::Type type,
1240*795d594fSAndroid Build Coastguard Worker std::memory_order order,
1241*795d594fSAndroid Build Coastguard Worker bool strong,
1242*795d594fSAndroid Build Coastguard Worker Riscv64Label* cmp_failure,
1243*795d594fSAndroid Build Coastguard Worker XRegister ptr,
1244*795d594fSAndroid Build Coastguard Worker XRegister new_value,
1245*795d594fSAndroid Build Coastguard Worker XRegister old_value,
1246*795d594fSAndroid Build Coastguard Worker XRegister mask,
1247*795d594fSAndroid Build Coastguard Worker XRegister masked,
1248*795d594fSAndroid Build Coastguard Worker XRegister store_result,
1249*795d594fSAndroid Build Coastguard Worker XRegister expected,
1250*795d594fSAndroid Build Coastguard Worker XRegister expected2 = kNoXRegister) {
1251*795d594fSAndroid Build Coastguard Worker DCHECK(!DataType::IsFloatingPointType(type));
1252*795d594fSAndroid Build Coastguard Worker DCHECK_GE(DataType::Size(type), 4u);
1253*795d594fSAndroid Build Coastguard Worker
1254*795d594fSAndroid Build Coastguard Worker // The `expected2` is valid only for reference slow path and represents the unmarked old value
1255*795d594fSAndroid Build Coastguard Worker // from the main path attempt to emit CAS when the marked old value matched `expected`.
1256*795d594fSAndroid Build Coastguard Worker DCHECK_IMPLIES(expected2 != kNoXRegister, type == DataType::Type::kReference);
1257*795d594fSAndroid Build Coastguard Worker
1258*795d594fSAndroid Build Coastguard Worker auto [load_aqrl, store_aqrl] = GetLrScAqRl(order);
1259*795d594fSAndroid Build Coastguard Worker
1260*795d594fSAndroid Build Coastguard Worker // repeat: {
1261*795d594fSAndroid Build Coastguard Worker // old_value = [ptr]; // Load exclusive.
1262*795d594fSAndroid Build Coastguard Worker // cmp_value = old_value & mask; // Extract relevant bits if applicable.
1263*795d594fSAndroid Build Coastguard Worker // if (cmp_value != expected && cmp_value != expected2) goto cmp_failure;
1264*795d594fSAndroid Build Coastguard Worker // store_result = failed([ptr] <- new_value); // Store exclusive.
1265*795d594fSAndroid Build Coastguard Worker // }
1266*795d594fSAndroid Build Coastguard Worker // if (strong) {
1267*795d594fSAndroid Build Coastguard Worker // if (store_result) goto repeat; // Repeat until compare fails or store exclusive succeeds.
1268*795d594fSAndroid Build Coastguard Worker // } else {
1269*795d594fSAndroid Build Coastguard Worker // store_result = store_result ^ 1; // Report success as 1, failure as 0.
1270*795d594fSAndroid Build Coastguard Worker // }
1271*795d594fSAndroid Build Coastguard Worker //
1272*795d594fSAndroid Build Coastguard Worker // (If `mask` is not valid, `expected` is compared with `old_value` instead of `cmp_value`.)
1273*795d594fSAndroid Build Coastguard Worker // (If `expected2` is not valid, the `cmp_value == expected2` part is not emitted.)
1274*795d594fSAndroid Build Coastguard Worker
1275*795d594fSAndroid Build Coastguard Worker // Note: We're using "bare" local branches to enforce that they shall not be expanded
1276*795d594fSAndroid Build Coastguard Worker // and the scrach register `TMP` shall not be clobbered if taken. Taking the branch to
1277*795d594fSAndroid Build Coastguard Worker // `cmp_failure` can theoretically clobber `TMP` (if outside the 1 MiB range).
1278*795d594fSAndroid Build Coastguard Worker Riscv64Label loop;
1279*795d594fSAndroid Build Coastguard Worker if (strong) {
1280*795d594fSAndroid Build Coastguard Worker __ Bind(&loop);
1281*795d594fSAndroid Build Coastguard Worker }
1282*795d594fSAndroid Build Coastguard Worker EmitLoadReserved(assembler, type, ptr, old_value, load_aqrl);
1283*795d594fSAndroid Build Coastguard Worker XRegister to_store = new_value;
1284*795d594fSAndroid Build Coastguard Worker {
1285*795d594fSAndroid Build Coastguard Worker ScopedLrScExtensionsRestriction slser(assembler);
1286*795d594fSAndroid Build Coastguard Worker if (mask != kNoXRegister) {
1287*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(expected2, kNoXRegister);
1288*795d594fSAndroid Build Coastguard Worker DCHECK_NE(masked, kNoXRegister);
1289*795d594fSAndroid Build Coastguard Worker __ And(masked, old_value, mask);
1290*795d594fSAndroid Build Coastguard Worker __ Bne(masked, expected, cmp_failure);
1291*795d594fSAndroid Build Coastguard Worker // The `old_value` does not need to be preserved as the caller shall use `masked`
1292*795d594fSAndroid Build Coastguard Worker // to return the old value if needed.
1293*795d594fSAndroid Build Coastguard Worker to_store = old_value;
1294*795d594fSAndroid Build Coastguard Worker // TODO(riscv64): We could XOR the old and new value before the loop and use a single XOR here
1295*795d594fSAndroid Build Coastguard Worker // instead of the XOR+OR. (The `new_value` is either Zero or a temporary we can clobber.)
1296*795d594fSAndroid Build Coastguard Worker __ Xor(to_store, old_value, masked);
1297*795d594fSAndroid Build Coastguard Worker __ Or(to_store, to_store, new_value);
1298*795d594fSAndroid Build Coastguard Worker } else if (expected2 != kNoXRegister) {
1299*795d594fSAndroid Build Coastguard Worker Riscv64Label match2;
1300*795d594fSAndroid Build Coastguard Worker __ Beq(old_value, expected2, &match2, /*is_bare=*/ true);
1301*795d594fSAndroid Build Coastguard Worker __ Bne(old_value, expected, cmp_failure);
1302*795d594fSAndroid Build Coastguard Worker __ Bind(&match2);
1303*795d594fSAndroid Build Coastguard Worker } else {
1304*795d594fSAndroid Build Coastguard Worker __ Bne(old_value, expected, cmp_failure);
1305*795d594fSAndroid Build Coastguard Worker }
1306*795d594fSAndroid Build Coastguard Worker }
1307*795d594fSAndroid Build Coastguard Worker EmitStoreConditional(assembler, type, ptr, store_result, to_store, store_aqrl);
1308*795d594fSAndroid Build Coastguard Worker if (strong) {
1309*795d594fSAndroid Build Coastguard Worker __ Bnez(store_result, &loop, /*is_bare=*/ true);
1310*795d594fSAndroid Build Coastguard Worker } else {
1311*795d594fSAndroid Build Coastguard Worker // Flip the `store_result` register to indicate success by 1 and failure by 0.
1312*795d594fSAndroid Build Coastguard Worker __ Xori(store_result, store_result, 1);
1313*795d594fSAndroid Build Coastguard Worker }
1314*795d594fSAndroid Build Coastguard Worker }
1315*795d594fSAndroid Build Coastguard Worker
1316*795d594fSAndroid Build Coastguard Worker class ReadBarrierCasSlowPathRISCV64 : public SlowPathCodeRISCV64 {
1317*795d594fSAndroid Build Coastguard Worker public:
ReadBarrierCasSlowPathRISCV64(HInvoke * invoke,std::memory_order order,bool strong,XRegister base,XRegister offset,XRegister expected,XRegister new_value,XRegister old_value,XRegister old_value_temp,XRegister store_result,bool update_old_value,CodeGeneratorRISCV64 * riscv64_codegen)1318*795d594fSAndroid Build Coastguard Worker ReadBarrierCasSlowPathRISCV64(HInvoke* invoke,
1319*795d594fSAndroid Build Coastguard Worker std::memory_order order,
1320*795d594fSAndroid Build Coastguard Worker bool strong,
1321*795d594fSAndroid Build Coastguard Worker XRegister base,
1322*795d594fSAndroid Build Coastguard Worker XRegister offset,
1323*795d594fSAndroid Build Coastguard Worker XRegister expected,
1324*795d594fSAndroid Build Coastguard Worker XRegister new_value,
1325*795d594fSAndroid Build Coastguard Worker XRegister old_value,
1326*795d594fSAndroid Build Coastguard Worker XRegister old_value_temp,
1327*795d594fSAndroid Build Coastguard Worker XRegister store_result,
1328*795d594fSAndroid Build Coastguard Worker bool update_old_value,
1329*795d594fSAndroid Build Coastguard Worker CodeGeneratorRISCV64* riscv64_codegen)
1330*795d594fSAndroid Build Coastguard Worker : SlowPathCodeRISCV64(invoke),
1331*795d594fSAndroid Build Coastguard Worker order_(order),
1332*795d594fSAndroid Build Coastguard Worker strong_(strong),
1333*795d594fSAndroid Build Coastguard Worker base_(base),
1334*795d594fSAndroid Build Coastguard Worker offset_(offset),
1335*795d594fSAndroid Build Coastguard Worker expected_(expected),
1336*795d594fSAndroid Build Coastguard Worker new_value_(new_value),
1337*795d594fSAndroid Build Coastguard Worker old_value_(old_value),
1338*795d594fSAndroid Build Coastguard Worker old_value_temp_(old_value_temp),
1339*795d594fSAndroid Build Coastguard Worker store_result_(store_result),
1340*795d594fSAndroid Build Coastguard Worker update_old_value_(update_old_value),
1341*795d594fSAndroid Build Coastguard Worker mark_old_value_slow_path_(nullptr),
1342*795d594fSAndroid Build Coastguard Worker update_old_value_slow_path_(nullptr) {
1343*795d594fSAndroid Build Coastguard Worker // We need to add slow paths now, it is too late when emitting slow path code.
1344*795d594fSAndroid Build Coastguard Worker Location old_value_loc = Location::RegisterLocation(old_value);
1345*795d594fSAndroid Build Coastguard Worker Location old_value_temp_loc = Location::RegisterLocation(old_value_temp);
1346*795d594fSAndroid Build Coastguard Worker if (kUseBakerReadBarrier) {
1347*795d594fSAndroid Build Coastguard Worker mark_old_value_slow_path_ = riscv64_codegen->AddGcRootBakerBarrierBarrierSlowPath(
1348*795d594fSAndroid Build Coastguard Worker invoke, old_value_temp_loc, kBakerReadBarrierTemp);
1349*795d594fSAndroid Build Coastguard Worker if (update_old_value_) {
1350*795d594fSAndroid Build Coastguard Worker update_old_value_slow_path_ = riscv64_codegen->AddGcRootBakerBarrierBarrierSlowPath(
1351*795d594fSAndroid Build Coastguard Worker invoke, old_value_loc, kBakerReadBarrierTemp);
1352*795d594fSAndroid Build Coastguard Worker }
1353*795d594fSAndroid Build Coastguard Worker } else {
1354*795d594fSAndroid Build Coastguard Worker Location base_loc = Location::RegisterLocation(base);
1355*795d594fSAndroid Build Coastguard Worker Location index = Location::RegisterLocation(offset);
1356*795d594fSAndroid Build Coastguard Worker mark_old_value_slow_path_ = riscv64_codegen->AddReadBarrierSlowPath(
1357*795d594fSAndroid Build Coastguard Worker invoke, old_value_temp_loc, old_value_loc, base_loc, /*offset=*/ 0u, index);
1358*795d594fSAndroid Build Coastguard Worker if (update_old_value_) {
1359*795d594fSAndroid Build Coastguard Worker update_old_value_slow_path_ = riscv64_codegen->AddReadBarrierSlowPath(
1360*795d594fSAndroid Build Coastguard Worker invoke, old_value_loc, old_value_temp_loc, base_loc, /*offset=*/ 0u, index);
1361*795d594fSAndroid Build Coastguard Worker }
1362*795d594fSAndroid Build Coastguard Worker }
1363*795d594fSAndroid Build Coastguard Worker }
1364*795d594fSAndroid Build Coastguard Worker
GetDescription() const1365*795d594fSAndroid Build Coastguard Worker const char* GetDescription() const override { return "ReadBarrierCasSlowPathRISCV64"; }
1366*795d594fSAndroid Build Coastguard Worker
1367*795d594fSAndroid Build Coastguard Worker // We return to a different label on success for a strong CAS that does not return old value.
GetSuccessExitLabel()1368*795d594fSAndroid Build Coastguard Worker Riscv64Label* GetSuccessExitLabel() {
1369*795d594fSAndroid Build Coastguard Worker return &success_exit_label_;
1370*795d594fSAndroid Build Coastguard Worker }
1371*795d594fSAndroid Build Coastguard Worker
EmitNativeCode(CodeGenerator * codegen)1372*795d594fSAndroid Build Coastguard Worker void EmitNativeCode(CodeGenerator* codegen) override {
1373*795d594fSAndroid Build Coastguard Worker CodeGeneratorRISCV64* riscv64_codegen = down_cast<CodeGeneratorRISCV64*>(codegen);
1374*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = riscv64_codegen->GetAssembler();
1375*795d594fSAndroid Build Coastguard Worker __ Bind(GetEntryLabel());
1376*795d594fSAndroid Build Coastguard Worker
1377*795d594fSAndroid Build Coastguard Worker // Mark the `old_value_` from the main path and compare with `expected_`.
1378*795d594fSAndroid Build Coastguard Worker DCHECK(mark_old_value_slow_path_ != nullptr);
1379*795d594fSAndroid Build Coastguard Worker if (kUseBakerReadBarrier) {
1380*795d594fSAndroid Build Coastguard Worker __ Mv(old_value_temp_, old_value_);
1381*795d594fSAndroid Build Coastguard Worker riscv64_codegen->EmitBakerReadBarierMarkingCheck(mark_old_value_slow_path_,
1382*795d594fSAndroid Build Coastguard Worker Location::RegisterLocation(old_value_temp_),
1383*795d594fSAndroid Build Coastguard Worker kBakerReadBarrierTemp);
1384*795d594fSAndroid Build Coastguard Worker } else {
1385*795d594fSAndroid Build Coastguard Worker __ J(mark_old_value_slow_path_->GetEntryLabel());
1386*795d594fSAndroid Build Coastguard Worker __ Bind(mark_old_value_slow_path_->GetExitLabel());
1387*795d594fSAndroid Build Coastguard Worker }
1388*795d594fSAndroid Build Coastguard Worker Riscv64Label move_marked_old_value;
1389*795d594fSAndroid Build Coastguard Worker __ Bne(old_value_temp_, expected_, update_old_value_ ? &move_marked_old_value : GetExitLabel());
1390*795d594fSAndroid Build Coastguard Worker
1391*795d594fSAndroid Build Coastguard Worker // The `old_value` we have read did not match `expected` (which is always a to-space
1392*795d594fSAndroid Build Coastguard Worker // reference) but after the read barrier the marked to-space value matched, so the
1393*795d594fSAndroid Build Coastguard Worker // `old_value` must be a from-space reference to the same object. Do the same CAS loop
1394*795d594fSAndroid Build Coastguard Worker // as the main path but check for both `expected` and the unmarked old value
1395*795d594fSAndroid Build Coastguard Worker // representing the to-space and from-space references for the same object.
1396*795d594fSAndroid Build Coastguard Worker
1397*795d594fSAndroid Build Coastguard Worker ScratchRegisterScope srs(assembler);
1398*795d594fSAndroid Build Coastguard Worker XRegister tmp_ptr = srs.AllocateXRegister();
1399*795d594fSAndroid Build Coastguard Worker XRegister store_result =
1400*795d594fSAndroid Build Coastguard Worker store_result_ != kNoXRegister ? store_result_ : srs.AllocateXRegister();
1401*795d594fSAndroid Build Coastguard Worker
1402*795d594fSAndroid Build Coastguard Worker // Recalculate the `tmp_ptr` from main path potentially clobbered by the read barrier above
1403*795d594fSAndroid Build Coastguard Worker // or by an expanded conditional branch (clobbers `TMP` if beyond 1MiB).
1404*795d594fSAndroid Build Coastguard Worker __ Add(tmp_ptr, base_, offset_);
1405*795d594fSAndroid Build Coastguard Worker
1406*795d594fSAndroid Build Coastguard Worker Riscv64Label mark_old_value;
1407*795d594fSAndroid Build Coastguard Worker GenerateCompareAndSet(riscv64_codegen->GetAssembler(),
1408*795d594fSAndroid Build Coastguard Worker DataType::Type::kReference,
1409*795d594fSAndroid Build Coastguard Worker order_,
1410*795d594fSAndroid Build Coastguard Worker strong_,
1411*795d594fSAndroid Build Coastguard Worker /*cmp_failure=*/ update_old_value_ ? &mark_old_value : GetExitLabel(),
1412*795d594fSAndroid Build Coastguard Worker tmp_ptr,
1413*795d594fSAndroid Build Coastguard Worker new_value_,
1414*795d594fSAndroid Build Coastguard Worker /*old_value=*/ old_value_temp_,
1415*795d594fSAndroid Build Coastguard Worker /*mask=*/ kNoXRegister,
1416*795d594fSAndroid Build Coastguard Worker /*masked=*/ kNoXRegister,
1417*795d594fSAndroid Build Coastguard Worker store_result,
1418*795d594fSAndroid Build Coastguard Worker expected_,
1419*795d594fSAndroid Build Coastguard Worker /*expected2=*/ old_value_);
1420*795d594fSAndroid Build Coastguard Worker if (update_old_value_) {
1421*795d594fSAndroid Build Coastguard Worker // To reach this point, the `old_value_temp_` must be either a from-space or a to-space
1422*795d594fSAndroid Build Coastguard Worker // reference of the `expected_` object. Update the `old_value_` to the to-space reference.
1423*795d594fSAndroid Build Coastguard Worker __ Mv(old_value_, expected_);
1424*795d594fSAndroid Build Coastguard Worker }
1425*795d594fSAndroid Build Coastguard Worker if (!update_old_value_ && strong_) {
1426*795d594fSAndroid Build Coastguard Worker // Load success value to the result register.
1427*795d594fSAndroid Build Coastguard Worker // We must jump to the instruction that loads the success value in the main path.
1428*795d594fSAndroid Build Coastguard Worker // Note that a SC failure in the CAS loop sets the `store_result` to 1, so the main
1429*795d594fSAndroid Build Coastguard Worker // path must not use the `store_result` as an indication of success.
1430*795d594fSAndroid Build Coastguard Worker __ J(GetSuccessExitLabel());
1431*795d594fSAndroid Build Coastguard Worker } else {
1432*795d594fSAndroid Build Coastguard Worker __ J(GetExitLabel());
1433*795d594fSAndroid Build Coastguard Worker }
1434*795d594fSAndroid Build Coastguard Worker
1435*795d594fSAndroid Build Coastguard Worker if (update_old_value_) {
1436*795d594fSAndroid Build Coastguard Worker // TODO(riscv64): If we initially saw a from-space reference and then saw
1437*795d594fSAndroid Build Coastguard Worker // a different reference, can the latter be also a from-space reference?
1438*795d594fSAndroid Build Coastguard Worker // (Shouldn't every reference write store a to-space reference?)
1439*795d594fSAndroid Build Coastguard Worker DCHECK(update_old_value_slow_path_ != nullptr);
1440*795d594fSAndroid Build Coastguard Worker __ Bind(&mark_old_value);
1441*795d594fSAndroid Build Coastguard Worker if (kUseBakerReadBarrier) {
1442*795d594fSAndroid Build Coastguard Worker __ Mv(old_value_, old_value_temp_);
1443*795d594fSAndroid Build Coastguard Worker riscv64_codegen->EmitBakerReadBarierMarkingCheck(update_old_value_slow_path_,
1444*795d594fSAndroid Build Coastguard Worker Location::RegisterLocation(old_value_),
1445*795d594fSAndroid Build Coastguard Worker kBakerReadBarrierTemp);
1446*795d594fSAndroid Build Coastguard Worker } else {
1447*795d594fSAndroid Build Coastguard Worker // Note: We could redirect the `failure` above directly to the entry label and bind
1448*795d594fSAndroid Build Coastguard Worker // the exit label in the main path, but the main path would need to access the
1449*795d594fSAndroid Build Coastguard Worker // `update_old_value_slow_path_`. To keep the code simple, keep the extra jumps.
1450*795d594fSAndroid Build Coastguard Worker __ J(update_old_value_slow_path_->GetEntryLabel());
1451*795d594fSAndroid Build Coastguard Worker __ Bind(update_old_value_slow_path_->GetExitLabel());
1452*795d594fSAndroid Build Coastguard Worker }
1453*795d594fSAndroid Build Coastguard Worker __ J(GetExitLabel());
1454*795d594fSAndroid Build Coastguard Worker
1455*795d594fSAndroid Build Coastguard Worker __ Bind(&move_marked_old_value);
1456*795d594fSAndroid Build Coastguard Worker __ Mv(old_value_, old_value_temp_);
1457*795d594fSAndroid Build Coastguard Worker __ J(GetExitLabel());
1458*795d594fSAndroid Build Coastguard Worker }
1459*795d594fSAndroid Build Coastguard Worker }
1460*795d594fSAndroid Build Coastguard Worker
1461*795d594fSAndroid Build Coastguard Worker private:
1462*795d594fSAndroid Build Coastguard Worker // Use RA as temp. It is clobbered in the slow path anyway.
1463*795d594fSAndroid Build Coastguard Worker static constexpr Location kBakerReadBarrierTemp = Location::RegisterLocation(RA);
1464*795d594fSAndroid Build Coastguard Worker
1465*795d594fSAndroid Build Coastguard Worker std::memory_order order_;
1466*795d594fSAndroid Build Coastguard Worker bool strong_;
1467*795d594fSAndroid Build Coastguard Worker XRegister base_;
1468*795d594fSAndroid Build Coastguard Worker XRegister offset_;
1469*795d594fSAndroid Build Coastguard Worker XRegister expected_;
1470*795d594fSAndroid Build Coastguard Worker XRegister new_value_;
1471*795d594fSAndroid Build Coastguard Worker XRegister old_value_;
1472*795d594fSAndroid Build Coastguard Worker XRegister old_value_temp_;
1473*795d594fSAndroid Build Coastguard Worker XRegister store_result_;
1474*795d594fSAndroid Build Coastguard Worker bool update_old_value_;
1475*795d594fSAndroid Build Coastguard Worker SlowPathCodeRISCV64* mark_old_value_slow_path_;
1476*795d594fSAndroid Build Coastguard Worker SlowPathCodeRISCV64* update_old_value_slow_path_;
1477*795d594fSAndroid Build Coastguard Worker Riscv64Label success_exit_label_;
1478*795d594fSAndroid Build Coastguard Worker };
1479*795d594fSAndroid Build Coastguard Worker
EmitBlt32(Riscv64Assembler * assembler,XRegister rs1,Location rs2,Riscv64Label * label,XRegister temp)1480*795d594fSAndroid Build Coastguard Worker static void EmitBlt32(Riscv64Assembler* assembler,
1481*795d594fSAndroid Build Coastguard Worker XRegister rs1,
1482*795d594fSAndroid Build Coastguard Worker Location rs2,
1483*795d594fSAndroid Build Coastguard Worker Riscv64Label* label,
1484*795d594fSAndroid Build Coastguard Worker XRegister temp) {
1485*795d594fSAndroid Build Coastguard Worker if (rs2.IsConstant()) {
1486*795d594fSAndroid Build Coastguard Worker __ Li(temp, rs2.GetConstant()->AsIntConstant()->GetValue());
1487*795d594fSAndroid Build Coastguard Worker __ Blt(rs1, temp, label);
1488*795d594fSAndroid Build Coastguard Worker } else {
1489*795d594fSAndroid Build Coastguard Worker __ Blt(rs1, rs2.AsRegister<XRegister>(), label);
1490*795d594fSAndroid Build Coastguard Worker }
1491*795d594fSAndroid Build Coastguard Worker }
1492*795d594fSAndroid Build Coastguard Worker
CheckSystemArrayCopyPosition(Riscv64Assembler * assembler,XRegister array,Location pos,Location length,SlowPathCodeRISCV64 * slow_path,XRegister temp1,XRegister temp2,bool length_is_array_length,bool position_sign_checked)1493*795d594fSAndroid Build Coastguard Worker static void CheckSystemArrayCopyPosition(Riscv64Assembler* assembler,
1494*795d594fSAndroid Build Coastguard Worker XRegister array,
1495*795d594fSAndroid Build Coastguard Worker Location pos,
1496*795d594fSAndroid Build Coastguard Worker Location length,
1497*795d594fSAndroid Build Coastguard Worker SlowPathCodeRISCV64* slow_path,
1498*795d594fSAndroid Build Coastguard Worker XRegister temp1,
1499*795d594fSAndroid Build Coastguard Worker XRegister temp2,
1500*795d594fSAndroid Build Coastguard Worker bool length_is_array_length,
1501*795d594fSAndroid Build Coastguard Worker bool position_sign_checked) {
1502*795d594fSAndroid Build Coastguard Worker const int32_t length_offset = mirror::Array::LengthOffset().Int32Value();
1503*795d594fSAndroid Build Coastguard Worker if (pos.IsConstant()) {
1504*795d594fSAndroid Build Coastguard Worker int32_t pos_const = pos.GetConstant()->AsIntConstant()->GetValue();
1505*795d594fSAndroid Build Coastguard Worker DCHECK_GE(pos_const, 0); // Checked in location builder.
1506*795d594fSAndroid Build Coastguard Worker if (pos_const == 0) {
1507*795d594fSAndroid Build Coastguard Worker if (!length_is_array_length) {
1508*795d594fSAndroid Build Coastguard Worker // Check that length(array) >= length.
1509*795d594fSAndroid Build Coastguard Worker __ Loadw(temp1, array, length_offset);
1510*795d594fSAndroid Build Coastguard Worker EmitBlt32(assembler, temp1, length, slow_path->GetEntryLabel(), temp2);
1511*795d594fSAndroid Build Coastguard Worker }
1512*795d594fSAndroid Build Coastguard Worker } else {
1513*795d594fSAndroid Build Coastguard Worker // Calculate length(array) - pos.
1514*795d594fSAndroid Build Coastguard Worker // Both operands are known to be non-negative `int32_t`, so the difference cannot underflow
1515*795d594fSAndroid Build Coastguard Worker // as `int32_t`. If the result is negative, the BLT below shall go to the slow path.
1516*795d594fSAndroid Build Coastguard Worker __ Loadw(temp1, array, length_offset);
1517*795d594fSAndroid Build Coastguard Worker __ AddConst32(temp1, temp1, -pos_const);
1518*795d594fSAndroid Build Coastguard Worker
1519*795d594fSAndroid Build Coastguard Worker // Check that (length(array) - pos) >= length.
1520*795d594fSAndroid Build Coastguard Worker EmitBlt32(assembler, temp1, length, slow_path->GetEntryLabel(), temp2);
1521*795d594fSAndroid Build Coastguard Worker }
1522*795d594fSAndroid Build Coastguard Worker } else if (length_is_array_length) {
1523*795d594fSAndroid Build Coastguard Worker // The only way the copy can succeed is if pos is zero.
1524*795d594fSAndroid Build Coastguard Worker __ Bnez(pos.AsRegister<XRegister>(), slow_path->GetEntryLabel());
1525*795d594fSAndroid Build Coastguard Worker } else {
1526*795d594fSAndroid Build Coastguard Worker // Check that pos >= 0.
1527*795d594fSAndroid Build Coastguard Worker XRegister pos_reg = pos.AsRegister<XRegister>();
1528*795d594fSAndroid Build Coastguard Worker if (!position_sign_checked) {
1529*795d594fSAndroid Build Coastguard Worker __ Bltz(pos_reg, slow_path->GetEntryLabel());
1530*795d594fSAndroid Build Coastguard Worker }
1531*795d594fSAndroid Build Coastguard Worker
1532*795d594fSAndroid Build Coastguard Worker // Calculate length(array) - pos.
1533*795d594fSAndroid Build Coastguard Worker // Both operands are known to be non-negative `int32_t`, so the difference cannot underflow
1534*795d594fSAndroid Build Coastguard Worker // as `int32_t`. If the result is negative, the BLT below shall go to the slow path.
1535*795d594fSAndroid Build Coastguard Worker __ Loadw(temp1, array, length_offset);
1536*795d594fSAndroid Build Coastguard Worker __ Sub(temp1, temp1, pos_reg);
1537*795d594fSAndroid Build Coastguard Worker
1538*795d594fSAndroid Build Coastguard Worker // Check that (length(array) - pos) >= length.
1539*795d594fSAndroid Build Coastguard Worker EmitBlt32(assembler, temp1, length, slow_path->GetEntryLabel(), temp2);
1540*795d594fSAndroid Build Coastguard Worker }
1541*795d594fSAndroid Build Coastguard Worker }
1542*795d594fSAndroid Build Coastguard Worker
GenArrayAddress(CodeGeneratorRISCV64 * codegen,XRegister dest,XRegister base,Location pos,DataType::Type type,int32_t data_offset)1543*795d594fSAndroid Build Coastguard Worker static void GenArrayAddress(CodeGeneratorRISCV64* codegen,
1544*795d594fSAndroid Build Coastguard Worker XRegister dest,
1545*795d594fSAndroid Build Coastguard Worker XRegister base,
1546*795d594fSAndroid Build Coastguard Worker Location pos,
1547*795d594fSAndroid Build Coastguard Worker DataType::Type type,
1548*795d594fSAndroid Build Coastguard Worker int32_t data_offset) {
1549*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = codegen->GetAssembler();
1550*795d594fSAndroid Build Coastguard Worker if (pos.IsConstant()) {
1551*795d594fSAndroid Build Coastguard Worker int32_t constant = pos.GetConstant()->AsIntConstant()->GetValue();
1552*795d594fSAndroid Build Coastguard Worker __ AddConst64(dest, base, DataType::Size(type) * constant + data_offset);
1553*795d594fSAndroid Build Coastguard Worker } else {
1554*795d594fSAndroid Build Coastguard Worker codegen->GetInstructionVisitor()->ShNAdd(dest, pos.AsRegister<XRegister>(), base, type);
1555*795d594fSAndroid Build Coastguard Worker if (data_offset != 0) {
1556*795d594fSAndroid Build Coastguard Worker __ AddConst64(dest, dest, data_offset);
1557*795d594fSAndroid Build Coastguard Worker }
1558*795d594fSAndroid Build Coastguard Worker }
1559*795d594fSAndroid Build Coastguard Worker }
1560*795d594fSAndroid Build Coastguard Worker
1561*795d594fSAndroid Build Coastguard Worker // Compute base source address, base destination address, and end
1562*795d594fSAndroid Build Coastguard Worker // source address for System.arraycopy* intrinsics in `src_base`,
1563*795d594fSAndroid Build Coastguard Worker // `dst_base` and `src_end` respectively.
GenSystemArrayCopyAddresses(CodeGeneratorRISCV64 * codegen,DataType::Type type,XRegister src,Location src_pos,XRegister dst,Location dst_pos,Location copy_length,XRegister src_base,XRegister dst_base,XRegister src_end)1564*795d594fSAndroid Build Coastguard Worker static void GenSystemArrayCopyAddresses(CodeGeneratorRISCV64* codegen,
1565*795d594fSAndroid Build Coastguard Worker DataType::Type type,
1566*795d594fSAndroid Build Coastguard Worker XRegister src,
1567*795d594fSAndroid Build Coastguard Worker Location src_pos,
1568*795d594fSAndroid Build Coastguard Worker XRegister dst,
1569*795d594fSAndroid Build Coastguard Worker Location dst_pos,
1570*795d594fSAndroid Build Coastguard Worker Location copy_length,
1571*795d594fSAndroid Build Coastguard Worker XRegister src_base,
1572*795d594fSAndroid Build Coastguard Worker XRegister dst_base,
1573*795d594fSAndroid Build Coastguard Worker XRegister src_end) {
1574*795d594fSAndroid Build Coastguard Worker // This routine is used by the SystemArrayCopyX intrinsics.
1575*795d594fSAndroid Build Coastguard Worker DCHECK(type == DataType::Type::kReference || type == DataType::Type::kInt8 ||
1576*795d594fSAndroid Build Coastguard Worker type == DataType::Type::kUint16 || type == DataType::Type::kInt32)
1577*795d594fSAndroid Build Coastguard Worker << "Unexpected element type: " << type;
1578*795d594fSAndroid Build Coastguard Worker const int32_t element_size = DataType::Size(type);
1579*795d594fSAndroid Build Coastguard Worker const uint32_t data_offset = mirror::Array::DataOffset(element_size).Uint32Value();
1580*795d594fSAndroid Build Coastguard Worker
1581*795d594fSAndroid Build Coastguard Worker GenArrayAddress(codegen, src_base, src, src_pos, type, data_offset);
1582*795d594fSAndroid Build Coastguard Worker GenArrayAddress(codegen, dst_base, dst, dst_pos, type, data_offset);
1583*795d594fSAndroid Build Coastguard Worker GenArrayAddress(codegen, src_end, src_base, copy_length, type, /*data_offset=*/ 0);
1584*795d594fSAndroid Build Coastguard Worker }
1585*795d594fSAndroid Build Coastguard Worker
LocationForSystemArrayCopyInput(HInstruction * input)1586*795d594fSAndroid Build Coastguard Worker static Location LocationForSystemArrayCopyInput(HInstruction* input) {
1587*795d594fSAndroid Build Coastguard Worker HIntConstant* const_input = input->AsIntConstantOrNull();
1588*795d594fSAndroid Build Coastguard Worker if (const_input != nullptr && IsInt<12>(const_input->GetValue())) {
1589*795d594fSAndroid Build Coastguard Worker return Location::ConstantLocation(const_input);
1590*795d594fSAndroid Build Coastguard Worker } else {
1591*795d594fSAndroid Build Coastguard Worker return Location::RequiresRegister();
1592*795d594fSAndroid Build Coastguard Worker }
1593*795d594fSAndroid Build Coastguard Worker }
1594*795d594fSAndroid Build Coastguard Worker
1595*795d594fSAndroid Build Coastguard Worker // We can choose to use the native implementation there for longer copy lengths.
1596*795d594fSAndroid Build Coastguard Worker static constexpr int32_t kSystemArrayCopyThreshold = 128;
1597*795d594fSAndroid Build Coastguard Worker
VisitSystemArrayCopy(HInvoke * invoke)1598*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitSystemArrayCopy(HInvoke* invoke) {
1599*795d594fSAndroid Build Coastguard Worker // The only read barrier implementation supporting the
1600*795d594fSAndroid Build Coastguard Worker // SystemArrayCopy intrinsic is the Baker-style read barriers.
1601*795d594fSAndroid Build Coastguard Worker if (codegen_->EmitNonBakerReadBarrier()) {
1602*795d594fSAndroid Build Coastguard Worker return;
1603*795d594fSAndroid Build Coastguard Worker }
1604*795d594fSAndroid Build Coastguard Worker
1605*795d594fSAndroid Build Coastguard Worker size_t num_temps = codegen_->EmitBakerReadBarrier() ? 4u : 2u;
1606*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = CodeGenerator::CreateSystemArrayCopyLocationSummary(
1607*795d594fSAndroid Build Coastguard Worker invoke, kSystemArrayCopyThreshold, num_temps);
1608*795d594fSAndroid Build Coastguard Worker if (locations != nullptr) {
1609*795d594fSAndroid Build Coastguard Worker // We request position and length as constants only for small integral values.
1610*795d594fSAndroid Build Coastguard Worker locations->SetInAt(1, LocationForSystemArrayCopyInput(invoke->InputAt(1)));
1611*795d594fSAndroid Build Coastguard Worker locations->SetInAt(3, LocationForSystemArrayCopyInput(invoke->InputAt(3)));
1612*795d594fSAndroid Build Coastguard Worker locations->SetInAt(4, LocationForSystemArrayCopyInput(invoke->InputAt(4)));
1613*795d594fSAndroid Build Coastguard Worker }
1614*795d594fSAndroid Build Coastguard Worker }
1615*795d594fSAndroid Build Coastguard Worker
VisitSystemArrayCopy(HInvoke * invoke)1616*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitSystemArrayCopy(HInvoke* invoke) {
1617*795d594fSAndroid Build Coastguard Worker // The only read barrier implementation supporting the
1618*795d594fSAndroid Build Coastguard Worker // SystemArrayCopy intrinsic is the Baker-style read barriers.
1619*795d594fSAndroid Build Coastguard Worker DCHECK_IMPLIES(codegen_->EmitReadBarrier(), kUseBakerReadBarrier);
1620*795d594fSAndroid Build Coastguard Worker
1621*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = GetAssembler();
1622*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = invoke->GetLocations();
1623*795d594fSAndroid Build Coastguard Worker
1624*795d594fSAndroid Build Coastguard Worker uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1625*795d594fSAndroid Build Coastguard Worker uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
1626*795d594fSAndroid Build Coastguard Worker uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
1627*795d594fSAndroid Build Coastguard Worker uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
1628*795d594fSAndroid Build Coastguard Worker uint32_t monitor_offset = mirror::Object::MonitorOffset().Int32Value();
1629*795d594fSAndroid Build Coastguard Worker
1630*795d594fSAndroid Build Coastguard Worker XRegister src = locations->InAt(0).AsRegister<XRegister>();
1631*795d594fSAndroid Build Coastguard Worker Location src_pos = locations->InAt(1);
1632*795d594fSAndroid Build Coastguard Worker XRegister dest = locations->InAt(2).AsRegister<XRegister>();
1633*795d594fSAndroid Build Coastguard Worker Location dest_pos = locations->InAt(3);
1634*795d594fSAndroid Build Coastguard Worker Location length = locations->InAt(4);
1635*795d594fSAndroid Build Coastguard Worker XRegister temp1 = locations->GetTemp(0).AsRegister<XRegister>();
1636*795d594fSAndroid Build Coastguard Worker XRegister temp2 = locations->GetTemp(1).AsRegister<XRegister>();
1637*795d594fSAndroid Build Coastguard Worker
1638*795d594fSAndroid Build Coastguard Worker SlowPathCodeRISCV64* intrinsic_slow_path =
1639*795d594fSAndroid Build Coastguard Worker new (codegen_->GetScopedAllocator()) IntrinsicSlowPathRISCV64(invoke);
1640*795d594fSAndroid Build Coastguard Worker codegen_->AddSlowPath(intrinsic_slow_path);
1641*795d594fSAndroid Build Coastguard Worker
1642*795d594fSAndroid Build Coastguard Worker Riscv64Label conditions_on_positions_validated;
1643*795d594fSAndroid Build Coastguard Worker SystemArrayCopyOptimizations optimizations(invoke);
1644*795d594fSAndroid Build Coastguard Worker
1645*795d594fSAndroid Build Coastguard Worker // If source and destination are the same, we go to slow path if we need to do forward copying.
1646*795d594fSAndroid Build Coastguard Worker // We do not need to do this check if the source and destination positions are the same.
1647*795d594fSAndroid Build Coastguard Worker if (!optimizations.GetSourcePositionIsDestinationPosition()) {
1648*795d594fSAndroid Build Coastguard Worker if (src_pos.IsConstant()) {
1649*795d594fSAndroid Build Coastguard Worker int32_t src_pos_constant = src_pos.GetConstant()->AsIntConstant()->GetValue();
1650*795d594fSAndroid Build Coastguard Worker if (dest_pos.IsConstant()) {
1651*795d594fSAndroid Build Coastguard Worker int32_t dest_pos_constant = dest_pos.GetConstant()->AsIntConstant()->GetValue();
1652*795d594fSAndroid Build Coastguard Worker if (optimizations.GetDestinationIsSource()) {
1653*795d594fSAndroid Build Coastguard Worker // Checked when building locations.
1654*795d594fSAndroid Build Coastguard Worker DCHECK_GE(src_pos_constant, dest_pos_constant);
1655*795d594fSAndroid Build Coastguard Worker } else if (src_pos_constant < dest_pos_constant) {
1656*795d594fSAndroid Build Coastguard Worker __ Beq(src, dest, intrinsic_slow_path->GetEntryLabel());
1657*795d594fSAndroid Build Coastguard Worker }
1658*795d594fSAndroid Build Coastguard Worker } else {
1659*795d594fSAndroid Build Coastguard Worker if (!optimizations.GetDestinationIsSource()) {
1660*795d594fSAndroid Build Coastguard Worker __ Bne(src, dest, &conditions_on_positions_validated);
1661*795d594fSAndroid Build Coastguard Worker }
1662*795d594fSAndroid Build Coastguard Worker __ Li(temp1, src_pos_constant);
1663*795d594fSAndroid Build Coastguard Worker __ Bgt(dest_pos.AsRegister<XRegister>(), temp1, intrinsic_slow_path->GetEntryLabel());
1664*795d594fSAndroid Build Coastguard Worker }
1665*795d594fSAndroid Build Coastguard Worker } else {
1666*795d594fSAndroid Build Coastguard Worker if (!optimizations.GetDestinationIsSource()) {
1667*795d594fSAndroid Build Coastguard Worker __ Bne(src, dest, &conditions_on_positions_validated);
1668*795d594fSAndroid Build Coastguard Worker }
1669*795d594fSAndroid Build Coastguard Worker XRegister src_pos_reg = src_pos.AsRegister<XRegister>();
1670*795d594fSAndroid Build Coastguard Worker EmitBlt32(assembler, src_pos_reg, dest_pos, intrinsic_slow_path->GetEntryLabel(), temp2);
1671*795d594fSAndroid Build Coastguard Worker }
1672*795d594fSAndroid Build Coastguard Worker }
1673*795d594fSAndroid Build Coastguard Worker
1674*795d594fSAndroid Build Coastguard Worker __ Bind(&conditions_on_positions_validated);
1675*795d594fSAndroid Build Coastguard Worker
1676*795d594fSAndroid Build Coastguard Worker if (!optimizations.GetSourceIsNotNull()) {
1677*795d594fSAndroid Build Coastguard Worker // Bail out if the source is null.
1678*795d594fSAndroid Build Coastguard Worker __ Beqz(src, intrinsic_slow_path->GetEntryLabel());
1679*795d594fSAndroid Build Coastguard Worker }
1680*795d594fSAndroid Build Coastguard Worker
1681*795d594fSAndroid Build Coastguard Worker if (!optimizations.GetDestinationIsNotNull() && !optimizations.GetDestinationIsSource()) {
1682*795d594fSAndroid Build Coastguard Worker // Bail out if the destination is null.
1683*795d594fSAndroid Build Coastguard Worker __ Beqz(dest, intrinsic_slow_path->GetEntryLabel());
1684*795d594fSAndroid Build Coastguard Worker }
1685*795d594fSAndroid Build Coastguard Worker
1686*795d594fSAndroid Build Coastguard Worker // We have already checked in the LocationsBuilder for the constant case.
1687*795d594fSAndroid Build Coastguard Worker if (!length.IsConstant()) {
1688*795d594fSAndroid Build Coastguard Worker // Merge the following two comparisons into one:
1689*795d594fSAndroid Build Coastguard Worker // If the length is negative, bail out (delegate to libcore's native implementation).
1690*795d594fSAndroid Build Coastguard Worker // If the length >= 128 then (currently) prefer native implementation.
1691*795d594fSAndroid Build Coastguard Worker __ Li(temp1, kSystemArrayCopyThreshold);
1692*795d594fSAndroid Build Coastguard Worker __ Bgeu(length.AsRegister<XRegister>(), temp1, intrinsic_slow_path->GetEntryLabel());
1693*795d594fSAndroid Build Coastguard Worker }
1694*795d594fSAndroid Build Coastguard Worker // Validity checks: source.
1695*795d594fSAndroid Build Coastguard Worker CheckSystemArrayCopyPosition(assembler,
1696*795d594fSAndroid Build Coastguard Worker src,
1697*795d594fSAndroid Build Coastguard Worker src_pos,
1698*795d594fSAndroid Build Coastguard Worker length,
1699*795d594fSAndroid Build Coastguard Worker intrinsic_slow_path,
1700*795d594fSAndroid Build Coastguard Worker temp1,
1701*795d594fSAndroid Build Coastguard Worker temp2,
1702*795d594fSAndroid Build Coastguard Worker optimizations.GetCountIsSourceLength(),
1703*795d594fSAndroid Build Coastguard Worker /*position_sign_checked=*/ false);
1704*795d594fSAndroid Build Coastguard Worker
1705*795d594fSAndroid Build Coastguard Worker // Validity checks: dest.
1706*795d594fSAndroid Build Coastguard Worker bool dest_position_sign_checked = optimizations.GetSourcePositionIsDestinationPosition();
1707*795d594fSAndroid Build Coastguard Worker CheckSystemArrayCopyPosition(assembler,
1708*795d594fSAndroid Build Coastguard Worker dest,
1709*795d594fSAndroid Build Coastguard Worker dest_pos,
1710*795d594fSAndroid Build Coastguard Worker length,
1711*795d594fSAndroid Build Coastguard Worker intrinsic_slow_path,
1712*795d594fSAndroid Build Coastguard Worker temp1,
1713*795d594fSAndroid Build Coastguard Worker temp2,
1714*795d594fSAndroid Build Coastguard Worker optimizations.GetCountIsDestinationLength(),
1715*795d594fSAndroid Build Coastguard Worker dest_position_sign_checked);
1716*795d594fSAndroid Build Coastguard Worker
1717*795d594fSAndroid Build Coastguard Worker auto check_non_primitive_array_class = [&](XRegister klass, XRegister temp) {
1718*795d594fSAndroid Build Coastguard Worker // No read barrier is needed for reading a chain of constant references for comparing
1719*795d594fSAndroid Build Coastguard Worker // with null, or for reading a constant primitive value, see `ReadBarrierOption`.
1720*795d594fSAndroid Build Coastguard Worker // /* HeapReference<Class> */ temp = klass->component_type_
1721*795d594fSAndroid Build Coastguard Worker __ Loadwu(temp, klass, component_offset);
1722*795d594fSAndroid Build Coastguard Worker codegen_->MaybeUnpoisonHeapReference(temp);
1723*795d594fSAndroid Build Coastguard Worker // Check that the component type is not null.
1724*795d594fSAndroid Build Coastguard Worker __ Beqz(temp, intrinsic_slow_path->GetEntryLabel());
1725*795d594fSAndroid Build Coastguard Worker // Check that the component type is not a primitive.
1726*795d594fSAndroid Build Coastguard Worker // /* uint16_t */ temp = static_cast<uint16>(klass->primitive_type_);
1727*795d594fSAndroid Build Coastguard Worker __ Loadhu(temp, temp, primitive_offset);
1728*795d594fSAndroid Build Coastguard Worker static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
1729*795d594fSAndroid Build Coastguard Worker __ Bnez(temp, intrinsic_slow_path->GetEntryLabel());
1730*795d594fSAndroid Build Coastguard Worker };
1731*795d594fSAndroid Build Coastguard Worker
1732*795d594fSAndroid Build Coastguard Worker if (!optimizations.GetDoesNotNeedTypeCheck()) {
1733*795d594fSAndroid Build Coastguard Worker // Check whether all elements of the source array are assignable to the component
1734*795d594fSAndroid Build Coastguard Worker // type of the destination array. We do two checks: the classes are the same,
1735*795d594fSAndroid Build Coastguard Worker // or the destination is Object[]. If none of these checks succeed, we go to the
1736*795d594fSAndroid Build Coastguard Worker // slow path.
1737*795d594fSAndroid Build Coastguard Worker
1738*795d594fSAndroid Build Coastguard Worker if (codegen_->EmitBakerReadBarrier()) {
1739*795d594fSAndroid Build Coastguard Worker XRegister temp3 = locations->GetTemp(2).AsRegister<XRegister>();
1740*795d594fSAndroid Build Coastguard Worker // /* HeapReference<Class> */ temp1 = dest->klass_
1741*795d594fSAndroid Build Coastguard Worker codegen_->GenerateFieldLoadWithBakerReadBarrier(invoke,
1742*795d594fSAndroid Build Coastguard Worker Location::RegisterLocation(temp1),
1743*795d594fSAndroid Build Coastguard Worker dest,
1744*795d594fSAndroid Build Coastguard Worker class_offset,
1745*795d594fSAndroid Build Coastguard Worker Location::RegisterLocation(temp3),
1746*795d594fSAndroid Build Coastguard Worker /* needs_null_check= */ false);
1747*795d594fSAndroid Build Coastguard Worker // /* HeapReference<Class> */ temp2 = src->klass_
1748*795d594fSAndroid Build Coastguard Worker codegen_->GenerateFieldLoadWithBakerReadBarrier(invoke,
1749*795d594fSAndroid Build Coastguard Worker Location::RegisterLocation(temp2),
1750*795d594fSAndroid Build Coastguard Worker src,
1751*795d594fSAndroid Build Coastguard Worker class_offset,
1752*795d594fSAndroid Build Coastguard Worker Location::RegisterLocation(temp3),
1753*795d594fSAndroid Build Coastguard Worker /* needs_null_check= */ false);
1754*795d594fSAndroid Build Coastguard Worker } else {
1755*795d594fSAndroid Build Coastguard Worker // /* HeapReference<Class> */ temp1 = dest->klass_
1756*795d594fSAndroid Build Coastguard Worker __ Loadwu(temp1, dest, class_offset);
1757*795d594fSAndroid Build Coastguard Worker codegen_->MaybeUnpoisonHeapReference(temp1);
1758*795d594fSAndroid Build Coastguard Worker // /* HeapReference<Class> */ temp2 = src->klass_
1759*795d594fSAndroid Build Coastguard Worker __ Loadwu(temp2, src, class_offset);
1760*795d594fSAndroid Build Coastguard Worker codegen_->MaybeUnpoisonHeapReference(temp2);
1761*795d594fSAndroid Build Coastguard Worker }
1762*795d594fSAndroid Build Coastguard Worker
1763*795d594fSAndroid Build Coastguard Worker if (optimizations.GetDestinationIsTypedObjectArray()) {
1764*795d594fSAndroid Build Coastguard Worker DCHECK(optimizations.GetDestinationIsNonPrimitiveArray());
1765*795d594fSAndroid Build Coastguard Worker Riscv64Label do_copy;
1766*795d594fSAndroid Build Coastguard Worker // For class match, we can skip the source type check regardless of the optimization flag.
1767*795d594fSAndroid Build Coastguard Worker __ Beq(temp1, temp2, &do_copy);
1768*795d594fSAndroid Build Coastguard Worker // No read barrier is needed for reading a chain of constant references
1769*795d594fSAndroid Build Coastguard Worker // for comparing with null, see `ReadBarrierOption`.
1770*795d594fSAndroid Build Coastguard Worker // /* HeapReference<Class> */ temp1 = temp1->component_type_
1771*795d594fSAndroid Build Coastguard Worker __ Loadwu(temp1, temp1, component_offset);
1772*795d594fSAndroid Build Coastguard Worker codegen_->MaybeUnpoisonHeapReference(temp1);
1773*795d594fSAndroid Build Coastguard Worker // /* HeapReference<Class> */ temp1 = temp1->super_class_
1774*795d594fSAndroid Build Coastguard Worker __ Loadwu(temp1, temp1, super_offset);
1775*795d594fSAndroid Build Coastguard Worker // No need to unpoison the result, we're comparing against null.
1776*795d594fSAndroid Build Coastguard Worker __ Bnez(temp1, intrinsic_slow_path->GetEntryLabel());
1777*795d594fSAndroid Build Coastguard Worker // Bail out if the source is not a non primitive array.
1778*795d594fSAndroid Build Coastguard Worker if (!optimizations.GetSourceIsNonPrimitiveArray()) {
1779*795d594fSAndroid Build Coastguard Worker check_non_primitive_array_class(temp2, temp2);
1780*795d594fSAndroid Build Coastguard Worker }
1781*795d594fSAndroid Build Coastguard Worker __ Bind(&do_copy);
1782*795d594fSAndroid Build Coastguard Worker } else {
1783*795d594fSAndroid Build Coastguard Worker DCHECK(!optimizations.GetDestinationIsTypedObjectArray());
1784*795d594fSAndroid Build Coastguard Worker // For class match, we can skip the array type check completely if at least one of source
1785*795d594fSAndroid Build Coastguard Worker // and destination is known to be a non primitive array, otherwise one check is enough.
1786*795d594fSAndroid Build Coastguard Worker __ Bne(temp1, temp2, intrinsic_slow_path->GetEntryLabel());
1787*795d594fSAndroid Build Coastguard Worker if (!optimizations.GetDestinationIsNonPrimitiveArray() &&
1788*795d594fSAndroid Build Coastguard Worker !optimizations.GetSourceIsNonPrimitiveArray()) {
1789*795d594fSAndroid Build Coastguard Worker check_non_primitive_array_class(temp2, temp2);
1790*795d594fSAndroid Build Coastguard Worker }
1791*795d594fSAndroid Build Coastguard Worker }
1792*795d594fSAndroid Build Coastguard Worker } else if (!optimizations.GetSourceIsNonPrimitiveArray()) {
1793*795d594fSAndroid Build Coastguard Worker DCHECK(optimizations.GetDestinationIsNonPrimitiveArray());
1794*795d594fSAndroid Build Coastguard Worker // Bail out if the source is not a non primitive array.
1795*795d594fSAndroid Build Coastguard Worker // No read barrier is needed for reading a chain of constant references for comparing
1796*795d594fSAndroid Build Coastguard Worker // with null, or for reading a constant primitive value, see `ReadBarrierOption`.
1797*795d594fSAndroid Build Coastguard Worker // /* HeapReference<Class> */ temp2 = src->klass_
1798*795d594fSAndroid Build Coastguard Worker __ Loadwu(temp2, src, class_offset);
1799*795d594fSAndroid Build Coastguard Worker codegen_->MaybeUnpoisonHeapReference(temp2);
1800*795d594fSAndroid Build Coastguard Worker check_non_primitive_array_class(temp2, temp2);
1801*795d594fSAndroid Build Coastguard Worker }
1802*795d594fSAndroid Build Coastguard Worker
1803*795d594fSAndroid Build Coastguard Worker if (length.IsConstant() && length.GetConstant()->AsIntConstant()->GetValue() == 0) {
1804*795d594fSAndroid Build Coastguard Worker // Null constant length: not need to emit the loop code at all.
1805*795d594fSAndroid Build Coastguard Worker } else {
1806*795d594fSAndroid Build Coastguard Worker Riscv64Label skip_copy_and_write_barrier;
1807*795d594fSAndroid Build Coastguard Worker if (length.IsRegister()) {
1808*795d594fSAndroid Build Coastguard Worker // Don't enter the copy loop if the length is null.
1809*795d594fSAndroid Build Coastguard Worker __ Beqz(length.AsRegister<XRegister>(), &skip_copy_and_write_barrier);
1810*795d594fSAndroid Build Coastguard Worker }
1811*795d594fSAndroid Build Coastguard Worker
1812*795d594fSAndroid Build Coastguard Worker {
1813*795d594fSAndroid Build Coastguard Worker // We use a block to end the scratch scope before the write barrier, thus
1814*795d594fSAndroid Build Coastguard Worker // freeing the scratch registers so they can be used in `MarkGCCard`.
1815*795d594fSAndroid Build Coastguard Worker ScratchRegisterScope srs(assembler);
1816*795d594fSAndroid Build Coastguard Worker bool emit_rb = codegen_->EmitBakerReadBarrier();
1817*795d594fSAndroid Build Coastguard Worker XRegister temp3 =
1818*795d594fSAndroid Build Coastguard Worker emit_rb ? locations->GetTemp(2).AsRegister<XRegister>() : srs.AllocateXRegister();
1819*795d594fSAndroid Build Coastguard Worker
1820*795d594fSAndroid Build Coastguard Worker XRegister src_curr_addr = temp1;
1821*795d594fSAndroid Build Coastguard Worker XRegister dst_curr_addr = temp2;
1822*795d594fSAndroid Build Coastguard Worker XRegister src_stop_addr = temp3;
1823*795d594fSAndroid Build Coastguard Worker const DataType::Type type = DataType::Type::kReference;
1824*795d594fSAndroid Build Coastguard Worker const int32_t element_size = DataType::Size(type);
1825*795d594fSAndroid Build Coastguard Worker
1826*795d594fSAndroid Build Coastguard Worker XRegister tmp = kNoXRegister;
1827*795d594fSAndroid Build Coastguard Worker SlowPathCodeRISCV64* read_barrier_slow_path = nullptr;
1828*795d594fSAndroid Build Coastguard Worker if (emit_rb) {
1829*795d594fSAndroid Build Coastguard Worker // TODO: Also convert this intrinsic to the IsGcMarking strategy?
1830*795d594fSAndroid Build Coastguard Worker
1831*795d594fSAndroid Build Coastguard Worker // SystemArrayCopy implementation for Baker read barriers (see
1832*795d594fSAndroid Build Coastguard Worker // also CodeGeneratorRISCV64::GenerateReferenceLoadWithBakerReadBarrier):
1833*795d594fSAndroid Build Coastguard Worker //
1834*795d594fSAndroid Build Coastguard Worker // uint32_t rb_state = Lockword(src->monitor_).ReadBarrierState();
1835*795d594fSAndroid Build Coastguard Worker // lfence; // Load fence or artificial data dependency to prevent load-load reordering
1836*795d594fSAndroid Build Coastguard Worker // bool is_gray = (rb_state == ReadBarrier::GrayState());
1837*795d594fSAndroid Build Coastguard Worker // if (is_gray) {
1838*795d594fSAndroid Build Coastguard Worker // // Slow-path copy.
1839*795d594fSAndroid Build Coastguard Worker // do {
1840*795d594fSAndroid Build Coastguard Worker // *dest_ptr++ = MaybePoison(ReadBarrier::Mark(MaybeUnpoison(*src_ptr++)));
1841*795d594fSAndroid Build Coastguard Worker // } while (src_ptr != end_ptr)
1842*795d594fSAndroid Build Coastguard Worker // } else {
1843*795d594fSAndroid Build Coastguard Worker // // Fast-path copy.
1844*795d594fSAndroid Build Coastguard Worker // do {
1845*795d594fSAndroid Build Coastguard Worker // *dest_ptr++ = *src_ptr++;
1846*795d594fSAndroid Build Coastguard Worker // } while (src_ptr != end_ptr)
1847*795d594fSAndroid Build Coastguard Worker // }
1848*795d594fSAndroid Build Coastguard Worker
1849*795d594fSAndroid Build Coastguard Worker // /* uint32_t */ monitor = src->monitor_
1850*795d594fSAndroid Build Coastguard Worker tmp = locations->GetTemp(3).AsRegister<XRegister>();
1851*795d594fSAndroid Build Coastguard Worker __ Loadwu(tmp, src, monitor_offset);
1852*795d594fSAndroid Build Coastguard Worker // /* LockWord */ lock_word = LockWord(monitor)
1853*795d594fSAndroid Build Coastguard Worker static_assert(sizeof(LockWord) == sizeof(int32_t),
1854*795d594fSAndroid Build Coastguard Worker "art::LockWord and int32_t have different sizes.");
1855*795d594fSAndroid Build Coastguard Worker
1856*795d594fSAndroid Build Coastguard Worker // Shift the RB state bit to the sign bit while also clearing the low 32 bits
1857*795d594fSAndroid Build Coastguard Worker // for the fake dependency below.
1858*795d594fSAndroid Build Coastguard Worker static_assert(LockWord::kReadBarrierStateShift < 31);
1859*795d594fSAndroid Build Coastguard Worker __ Slli(tmp, tmp, 63 - LockWord::kReadBarrierStateShift);
1860*795d594fSAndroid Build Coastguard Worker
1861*795d594fSAndroid Build Coastguard Worker // Introduce a dependency on the lock_word including rb_state, to prevent load-load
1862*795d594fSAndroid Build Coastguard Worker // reordering, and without using a memory barrier (which would be more expensive).
1863*795d594fSAndroid Build Coastguard Worker // `src` is unchanged by this operation (since Adduw adds low 32 bits
1864*795d594fSAndroid Build Coastguard Worker // which are zero after left shift), but its value now depends on `tmp`.
1865*795d594fSAndroid Build Coastguard Worker __ AddUw(src, tmp, src);
1866*795d594fSAndroid Build Coastguard Worker
1867*795d594fSAndroid Build Coastguard Worker // Slow path used to copy array when `src` is gray.
1868*795d594fSAndroid Build Coastguard Worker read_barrier_slow_path = new (codegen_->GetScopedAllocator())
1869*795d594fSAndroid Build Coastguard Worker ReadBarrierSystemArrayCopySlowPathRISCV64(invoke, Location::RegisterLocation(tmp));
1870*795d594fSAndroid Build Coastguard Worker codegen_->AddSlowPath(read_barrier_slow_path);
1871*795d594fSAndroid Build Coastguard Worker }
1872*795d594fSAndroid Build Coastguard Worker
1873*795d594fSAndroid Build Coastguard Worker // Compute base source address, base destination address, and end source address for
1874*795d594fSAndroid Build Coastguard Worker // System.arraycopy* intrinsics in `src_base`, `dst_base` and `src_end` respectively.
1875*795d594fSAndroid Build Coastguard Worker // Note that `src_curr_addr` is computed from from `src` (and `src_pos`) here, and
1876*795d594fSAndroid Build Coastguard Worker // thus honors the artificial dependency of `src` on `tmp` for read barriers.
1877*795d594fSAndroid Build Coastguard Worker GenSystemArrayCopyAddresses(codegen_,
1878*795d594fSAndroid Build Coastguard Worker type,
1879*795d594fSAndroid Build Coastguard Worker src,
1880*795d594fSAndroid Build Coastguard Worker src_pos,
1881*795d594fSAndroid Build Coastguard Worker dest,
1882*795d594fSAndroid Build Coastguard Worker dest_pos,
1883*795d594fSAndroid Build Coastguard Worker length,
1884*795d594fSAndroid Build Coastguard Worker src_curr_addr,
1885*795d594fSAndroid Build Coastguard Worker dst_curr_addr,
1886*795d594fSAndroid Build Coastguard Worker src_stop_addr);
1887*795d594fSAndroid Build Coastguard Worker
1888*795d594fSAndroid Build Coastguard Worker if (emit_rb) {
1889*795d594fSAndroid Build Coastguard Worker // Given the numeric representation, it's enough to check the low bit of the RB state.
1890*795d594fSAndroid Build Coastguard Worker static_assert(ReadBarrier::NonGrayState() == 0, "Expecting non-gray to have value 0");
1891*795d594fSAndroid Build Coastguard Worker static_assert(ReadBarrier::GrayState() == 1, "Expecting gray to have value 1");
1892*795d594fSAndroid Build Coastguard Worker DCHECK_NE(tmp, kNoXRegister);
1893*795d594fSAndroid Build Coastguard Worker __ Bltz(tmp, read_barrier_slow_path->GetEntryLabel());
1894*795d594fSAndroid Build Coastguard Worker } else {
1895*795d594fSAndroid Build Coastguard Worker // After allocating the last scrach register, we cannot use macro load/store instructions
1896*795d594fSAndroid Build Coastguard Worker // such as `Loadwu()` and need to use raw instructions. However, all offsets below are 0.
1897*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(tmp, kNoXRegister);
1898*795d594fSAndroid Build Coastguard Worker tmp = srs.AllocateXRegister();
1899*795d594fSAndroid Build Coastguard Worker }
1900*795d594fSAndroid Build Coastguard Worker
1901*795d594fSAndroid Build Coastguard Worker // Iterate over the arrays and do a raw copy of the objects. We don't need to
1902*795d594fSAndroid Build Coastguard Worker // poison/unpoison.
1903*795d594fSAndroid Build Coastguard Worker Riscv64Label loop;
1904*795d594fSAndroid Build Coastguard Worker __ Bind(&loop);
1905*795d594fSAndroid Build Coastguard Worker __ Lwu(tmp, src_curr_addr, 0);
1906*795d594fSAndroid Build Coastguard Worker __ Sw(tmp, dst_curr_addr, 0);
1907*795d594fSAndroid Build Coastguard Worker __ Addi(src_curr_addr, src_curr_addr, element_size);
1908*795d594fSAndroid Build Coastguard Worker __ Addi(dst_curr_addr, dst_curr_addr, element_size);
1909*795d594fSAndroid Build Coastguard Worker // Bare: `TMP` shall not be clobbered.
1910*795d594fSAndroid Build Coastguard Worker __ Bne(src_curr_addr, src_stop_addr, &loop, /*is_bare=*/ true);
1911*795d594fSAndroid Build Coastguard Worker
1912*795d594fSAndroid Build Coastguard Worker if (emit_rb) {
1913*795d594fSAndroid Build Coastguard Worker DCHECK(read_barrier_slow_path != nullptr);
1914*795d594fSAndroid Build Coastguard Worker __ Bind(read_barrier_slow_path->GetExitLabel());
1915*795d594fSAndroid Build Coastguard Worker }
1916*795d594fSAndroid Build Coastguard Worker }
1917*795d594fSAndroid Build Coastguard Worker
1918*795d594fSAndroid Build Coastguard Worker // We only need one card marking on the destination array.
1919*795d594fSAndroid Build Coastguard Worker codegen_->MarkGCCard(dest);
1920*795d594fSAndroid Build Coastguard Worker
1921*795d594fSAndroid Build Coastguard Worker __ Bind(&skip_copy_and_write_barrier);
1922*795d594fSAndroid Build Coastguard Worker }
1923*795d594fSAndroid Build Coastguard Worker
1924*795d594fSAndroid Build Coastguard Worker __ Bind(intrinsic_slow_path->GetExitLabel());
1925*795d594fSAndroid Build Coastguard Worker }
1926*795d594fSAndroid Build Coastguard Worker
1927*795d594fSAndroid Build Coastguard Worker // This value is in bytes and greater than ARRAYCOPY_SHORT_XXX_ARRAY_THRESHOLD
1928*795d594fSAndroid Build Coastguard Worker // in libcore, so if we choose to jump to the slow path we will end up
1929*795d594fSAndroid Build Coastguard Worker // in the native implementation.
1930*795d594fSAndroid Build Coastguard Worker static constexpr int32_t kSystemArrayCopyPrimThreshold = 384;
1931*795d594fSAndroid Build Coastguard Worker
CreateSystemArrayCopyLocations(HInvoke * invoke,DataType::Type type)1932*795d594fSAndroid Build Coastguard Worker static void CreateSystemArrayCopyLocations(HInvoke* invoke, DataType::Type type) {
1933*795d594fSAndroid Build Coastguard Worker int32_t copy_threshold = kSystemArrayCopyPrimThreshold / DataType::Size(type);
1934*795d594fSAndroid Build Coastguard Worker
1935*795d594fSAndroid Build Coastguard Worker // Check to see if we have known failures that will cause us to have to bail out
1936*795d594fSAndroid Build Coastguard Worker // to the runtime, and just generate the runtime call directly.
1937*795d594fSAndroid Build Coastguard Worker HIntConstant* src_pos = invoke->InputAt(1)->AsIntConstantOrNull();
1938*795d594fSAndroid Build Coastguard Worker HIntConstant* dst_pos = invoke->InputAt(3)->AsIntConstantOrNull();
1939*795d594fSAndroid Build Coastguard Worker
1940*795d594fSAndroid Build Coastguard Worker // The positions must be non-negative.
1941*795d594fSAndroid Build Coastguard Worker if ((src_pos != nullptr && src_pos->GetValue() < 0) ||
1942*795d594fSAndroid Build Coastguard Worker (dst_pos != nullptr && dst_pos->GetValue() < 0)) {
1943*795d594fSAndroid Build Coastguard Worker // We will have to fail anyways.
1944*795d594fSAndroid Build Coastguard Worker return;
1945*795d594fSAndroid Build Coastguard Worker }
1946*795d594fSAndroid Build Coastguard Worker
1947*795d594fSAndroid Build Coastguard Worker // The length must be >= 0 and not so long that we would (currently) prefer libcore's
1948*795d594fSAndroid Build Coastguard Worker // native implementation.
1949*795d594fSAndroid Build Coastguard Worker HIntConstant* length = invoke->InputAt(4)->AsIntConstantOrNull();
1950*795d594fSAndroid Build Coastguard Worker if (length != nullptr) {
1951*795d594fSAndroid Build Coastguard Worker int32_t len = length->GetValue();
1952*795d594fSAndroid Build Coastguard Worker if (len < 0 || len > copy_threshold) {
1953*795d594fSAndroid Build Coastguard Worker // Just call as normal.
1954*795d594fSAndroid Build Coastguard Worker return;
1955*795d594fSAndroid Build Coastguard Worker }
1956*795d594fSAndroid Build Coastguard Worker }
1957*795d594fSAndroid Build Coastguard Worker
1958*795d594fSAndroid Build Coastguard Worker ArenaAllocator* allocator = invoke->GetBlock()->GetGraph()->GetAllocator();
1959*795d594fSAndroid Build Coastguard Worker LocationSummary* locations =
1960*795d594fSAndroid Build Coastguard Worker new (allocator) LocationSummary(invoke, LocationSummary::kCallOnSlowPath, kIntrinsified);
1961*795d594fSAndroid Build Coastguard Worker // arraycopy(char[] src, int src_pos, char[] dst, int dst_pos, int length).
1962*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresRegister());
1963*795d594fSAndroid Build Coastguard Worker locations->SetInAt(1, LocationForSystemArrayCopyInput(invoke->InputAt(1)));
1964*795d594fSAndroid Build Coastguard Worker locations->SetInAt(2, Location::RequiresRegister());
1965*795d594fSAndroid Build Coastguard Worker locations->SetInAt(3, LocationForSystemArrayCopyInput(invoke->InputAt(3)));
1966*795d594fSAndroid Build Coastguard Worker locations->SetInAt(4, LocationForSystemArrayCopyInput(invoke->InputAt(4)));
1967*795d594fSAndroid Build Coastguard Worker
1968*795d594fSAndroid Build Coastguard Worker locations->AddRegisterTemps(3);
1969*795d594fSAndroid Build Coastguard Worker }
1970*795d594fSAndroid Build Coastguard Worker
VisitSystemArrayCopyByte(HInvoke * invoke)1971*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitSystemArrayCopyByte(HInvoke* invoke) {
1972*795d594fSAndroid Build Coastguard Worker CreateSystemArrayCopyLocations(invoke, DataType::Type::kInt8);
1973*795d594fSAndroid Build Coastguard Worker }
1974*795d594fSAndroid Build Coastguard Worker
VisitSystemArrayCopyChar(HInvoke * invoke)1975*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitSystemArrayCopyChar(HInvoke* invoke) {
1976*795d594fSAndroid Build Coastguard Worker CreateSystemArrayCopyLocations(invoke, DataType::Type::kUint16);
1977*795d594fSAndroid Build Coastguard Worker }
1978*795d594fSAndroid Build Coastguard Worker
VisitSystemArrayCopyInt(HInvoke * invoke)1979*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitSystemArrayCopyInt(HInvoke* invoke) {
1980*795d594fSAndroid Build Coastguard Worker CreateSystemArrayCopyLocations(invoke, DataType::Type::kInt32);
1981*795d594fSAndroid Build Coastguard Worker }
1982*795d594fSAndroid Build Coastguard Worker
GenerateUnsignedLoad(Riscv64Assembler * assembler,XRegister rd,XRegister rs1,int32_t offset,size_t type_size)1983*795d594fSAndroid Build Coastguard Worker static void GenerateUnsignedLoad(
1984*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler, XRegister rd, XRegister rs1, int32_t offset, size_t type_size) {
1985*795d594fSAndroid Build Coastguard Worker switch (type_size) {
1986*795d594fSAndroid Build Coastguard Worker case 1:
1987*795d594fSAndroid Build Coastguard Worker __ Lbu(rd, rs1, offset);
1988*795d594fSAndroid Build Coastguard Worker break;
1989*795d594fSAndroid Build Coastguard Worker case 2:
1990*795d594fSAndroid Build Coastguard Worker __ Lhu(rd, rs1, offset);
1991*795d594fSAndroid Build Coastguard Worker break;
1992*795d594fSAndroid Build Coastguard Worker case 4:
1993*795d594fSAndroid Build Coastguard Worker __ Lwu(rd, rs1, offset);
1994*795d594fSAndroid Build Coastguard Worker break;
1995*795d594fSAndroid Build Coastguard Worker case 8:
1996*795d594fSAndroid Build Coastguard Worker __ Ld(rd, rs1, offset);
1997*795d594fSAndroid Build Coastguard Worker break;
1998*795d594fSAndroid Build Coastguard Worker default:
1999*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unexpected data type";
2000*795d594fSAndroid Build Coastguard Worker }
2001*795d594fSAndroid Build Coastguard Worker }
2002*795d594fSAndroid Build Coastguard Worker
GenerateStore(Riscv64Assembler * assembler,XRegister rs2,XRegister rs1,int32_t offset,size_t type_size)2003*795d594fSAndroid Build Coastguard Worker static void GenerateStore(
2004*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler, XRegister rs2, XRegister rs1, int32_t offset, size_t type_size) {
2005*795d594fSAndroid Build Coastguard Worker switch (type_size) {
2006*795d594fSAndroid Build Coastguard Worker case 1:
2007*795d594fSAndroid Build Coastguard Worker __ Sb(rs2, rs1, offset);
2008*795d594fSAndroid Build Coastguard Worker break;
2009*795d594fSAndroid Build Coastguard Worker case 2:
2010*795d594fSAndroid Build Coastguard Worker __ Sh(rs2, rs1, offset);
2011*795d594fSAndroid Build Coastguard Worker break;
2012*795d594fSAndroid Build Coastguard Worker case 4:
2013*795d594fSAndroid Build Coastguard Worker __ Sw(rs2, rs1, offset);
2014*795d594fSAndroid Build Coastguard Worker break;
2015*795d594fSAndroid Build Coastguard Worker case 8:
2016*795d594fSAndroid Build Coastguard Worker __ Sd(rs2, rs1, offset);
2017*795d594fSAndroid Build Coastguard Worker break;
2018*795d594fSAndroid Build Coastguard Worker default:
2019*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unexpected data type";
2020*795d594fSAndroid Build Coastguard Worker }
2021*795d594fSAndroid Build Coastguard Worker }
2022*795d594fSAndroid Build Coastguard Worker
SystemArrayCopyPrimitive(HInvoke * invoke,CodeGeneratorRISCV64 * codegen,DataType::Type type)2023*795d594fSAndroid Build Coastguard Worker static void SystemArrayCopyPrimitive(HInvoke* invoke,
2024*795d594fSAndroid Build Coastguard Worker CodeGeneratorRISCV64* codegen,
2025*795d594fSAndroid Build Coastguard Worker DataType::Type type) {
2026*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = codegen->GetAssembler();
2027*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = invoke->GetLocations();
2028*795d594fSAndroid Build Coastguard Worker XRegister src = locations->InAt(0).AsRegister<XRegister>();
2029*795d594fSAndroid Build Coastguard Worker Location src_pos = locations->InAt(1);
2030*795d594fSAndroid Build Coastguard Worker XRegister dst = locations->InAt(2).AsRegister<XRegister>();
2031*795d594fSAndroid Build Coastguard Worker Location dst_pos = locations->InAt(3);
2032*795d594fSAndroid Build Coastguard Worker Location length = locations->InAt(4);
2033*795d594fSAndroid Build Coastguard Worker
2034*795d594fSAndroid Build Coastguard Worker SlowPathCodeRISCV64* slow_path =
2035*795d594fSAndroid Build Coastguard Worker new (codegen->GetScopedAllocator()) IntrinsicSlowPathRISCV64(invoke);
2036*795d594fSAndroid Build Coastguard Worker codegen->AddSlowPath(slow_path);
2037*795d594fSAndroid Build Coastguard Worker
2038*795d594fSAndroid Build Coastguard Worker SystemArrayCopyOptimizations optimizations(invoke);
2039*795d594fSAndroid Build Coastguard Worker
2040*795d594fSAndroid Build Coastguard Worker // If source and destination are the same, take the slow path. Overlapping copy regions must be
2041*795d594fSAndroid Build Coastguard Worker // copied in reverse and we can't know in all cases if it's needed.
2042*795d594fSAndroid Build Coastguard Worker __ Beq(src, dst, slow_path->GetEntryLabel());
2043*795d594fSAndroid Build Coastguard Worker
2044*795d594fSAndroid Build Coastguard Worker if (!optimizations.GetSourceIsNotNull()) {
2045*795d594fSAndroid Build Coastguard Worker // Bail out if the source is null.
2046*795d594fSAndroid Build Coastguard Worker __ Beqz(src, slow_path->GetEntryLabel());
2047*795d594fSAndroid Build Coastguard Worker }
2048*795d594fSAndroid Build Coastguard Worker
2049*795d594fSAndroid Build Coastguard Worker if (!optimizations.GetDestinationIsNotNull() && !optimizations.GetDestinationIsSource()) {
2050*795d594fSAndroid Build Coastguard Worker // Bail out if the destination is null.
2051*795d594fSAndroid Build Coastguard Worker __ Beqz(dst, slow_path->GetEntryLabel());
2052*795d594fSAndroid Build Coastguard Worker }
2053*795d594fSAndroid Build Coastguard Worker
2054*795d594fSAndroid Build Coastguard Worker int32_t copy_threshold = kSystemArrayCopyPrimThreshold / DataType::Size(type);
2055*795d594fSAndroid Build Coastguard Worker XRegister tmp = locations->GetTemp(0).AsRegister<XRegister>();
2056*795d594fSAndroid Build Coastguard Worker if (!length.IsConstant()) {
2057*795d594fSAndroid Build Coastguard Worker // Merge the following two comparisons into one:
2058*795d594fSAndroid Build Coastguard Worker // If the length is negative, bail out (delegate to libcore's native implementation).
2059*795d594fSAndroid Build Coastguard Worker // If the length >= kSystemArrayCopyPrimThreshold then (currently) prefer libcore's
2060*795d594fSAndroid Build Coastguard Worker // native implementation.
2061*795d594fSAndroid Build Coastguard Worker __ Li(tmp, copy_threshold);
2062*795d594fSAndroid Build Coastguard Worker __ Bgeu(length.AsRegister<XRegister>(), tmp, slow_path->GetEntryLabel());
2063*795d594fSAndroid Build Coastguard Worker } else {
2064*795d594fSAndroid Build Coastguard Worker // We have already checked in the LocationsBuilder for the constant case.
2065*795d594fSAndroid Build Coastguard Worker DCHECK_GE(length.GetConstant()->AsIntConstant()->GetValue(), 0);
2066*795d594fSAndroid Build Coastguard Worker DCHECK_LE(length.GetConstant()->AsIntConstant()->GetValue(), copy_threshold);
2067*795d594fSAndroid Build Coastguard Worker }
2068*795d594fSAndroid Build Coastguard Worker
2069*795d594fSAndroid Build Coastguard Worker XRegister src_curr_addr = locations->GetTemp(1).AsRegister<XRegister>();
2070*795d594fSAndroid Build Coastguard Worker XRegister dst_curr_addr = locations->GetTemp(2).AsRegister<XRegister>();
2071*795d594fSAndroid Build Coastguard Worker
2072*795d594fSAndroid Build Coastguard Worker CheckSystemArrayCopyPosition(assembler,
2073*795d594fSAndroid Build Coastguard Worker src,
2074*795d594fSAndroid Build Coastguard Worker src_pos,
2075*795d594fSAndroid Build Coastguard Worker length,
2076*795d594fSAndroid Build Coastguard Worker slow_path,
2077*795d594fSAndroid Build Coastguard Worker src_curr_addr,
2078*795d594fSAndroid Build Coastguard Worker dst_curr_addr,
2079*795d594fSAndroid Build Coastguard Worker /*length_is_array_length=*/ false,
2080*795d594fSAndroid Build Coastguard Worker /*position_sign_checked=*/ false);
2081*795d594fSAndroid Build Coastguard Worker
2082*795d594fSAndroid Build Coastguard Worker CheckSystemArrayCopyPosition(assembler,
2083*795d594fSAndroid Build Coastguard Worker dst,
2084*795d594fSAndroid Build Coastguard Worker dst_pos,
2085*795d594fSAndroid Build Coastguard Worker length,
2086*795d594fSAndroid Build Coastguard Worker slow_path,
2087*795d594fSAndroid Build Coastguard Worker src_curr_addr,
2088*795d594fSAndroid Build Coastguard Worker dst_curr_addr,
2089*795d594fSAndroid Build Coastguard Worker /*length_is_array_length=*/ false,
2090*795d594fSAndroid Build Coastguard Worker /*position_sign_checked=*/ false);
2091*795d594fSAndroid Build Coastguard Worker
2092*795d594fSAndroid Build Coastguard Worker const int32_t element_size = DataType::Size(type);
2093*795d594fSAndroid Build Coastguard Worker const uint32_t data_offset = mirror::Array::DataOffset(element_size).Uint32Value();
2094*795d594fSAndroid Build Coastguard Worker
2095*795d594fSAndroid Build Coastguard Worker GenArrayAddress(codegen, src_curr_addr, src, src_pos, type, data_offset);
2096*795d594fSAndroid Build Coastguard Worker GenArrayAddress(codegen, dst_curr_addr, dst, dst_pos, type, data_offset);
2097*795d594fSAndroid Build Coastguard Worker
2098*795d594fSAndroid Build Coastguard Worker // We split processing of the array in two parts: head and tail.
2099*795d594fSAndroid Build Coastguard Worker // A first loop handles the head by copying a block of elements per
2100*795d594fSAndroid Build Coastguard Worker // iteration (see: elements_per_block).
2101*795d594fSAndroid Build Coastguard Worker // A second loop handles the tail by copying the remaining elements.
2102*795d594fSAndroid Build Coastguard Worker // If the copy length is not constant, we copy them one-by-one.
2103*795d594fSAndroid Build Coastguard Worker //
2104*795d594fSAndroid Build Coastguard Worker // Both loops are inverted for better performance, meaning they are
2105*795d594fSAndroid Build Coastguard Worker // implemented as conditional do-while loops.
2106*795d594fSAndroid Build Coastguard Worker // Here, the loop condition is first checked to determine if there are
2107*795d594fSAndroid Build Coastguard Worker // sufficient elements to run an iteration, then we enter the do-while: an
2108*795d594fSAndroid Build Coastguard Worker // iteration is performed followed by a conditional branch only if another
2109*795d594fSAndroid Build Coastguard Worker // iteration is necessary. As opposed to a standard while-loop, this inversion
2110*795d594fSAndroid Build Coastguard Worker // can save some branching (e.g. we don't branch back to the initial condition
2111*795d594fSAndroid Build Coastguard Worker // at the end of every iteration only to potentially immediately branch
2112*795d594fSAndroid Build Coastguard Worker // again).
2113*795d594fSAndroid Build Coastguard Worker //
2114*795d594fSAndroid Build Coastguard Worker // A full block of elements is subtracted and added before and after the head
2115*795d594fSAndroid Build Coastguard Worker // loop, respectively. This ensures that any remaining length after each
2116*795d594fSAndroid Build Coastguard Worker // head loop iteration means there is a full block remaining, reducing the
2117*795d594fSAndroid Build Coastguard Worker // number of conditional checks required on every iteration.
2118*795d594fSAndroid Build Coastguard Worker ScratchRegisterScope temps(assembler);
2119*795d594fSAndroid Build Coastguard Worker constexpr int32_t bytes_copied_per_iteration = 16;
2120*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(bytes_copied_per_iteration % element_size, 0);
2121*795d594fSAndroid Build Coastguard Worker int32_t elements_per_block = bytes_copied_per_iteration / element_size;
2122*795d594fSAndroid Build Coastguard Worker Riscv64Label done;
2123*795d594fSAndroid Build Coastguard Worker
2124*795d594fSAndroid Build Coastguard Worker XRegister length_tmp = temps.AllocateXRegister();
2125*795d594fSAndroid Build Coastguard Worker
2126*795d594fSAndroid Build Coastguard Worker auto emit_head_loop = [&]() {
2127*795d594fSAndroid Build Coastguard Worker ScratchRegisterScope local_temps(assembler);
2128*795d594fSAndroid Build Coastguard Worker XRegister tmp2 = local_temps.AllocateXRegister();
2129*795d594fSAndroid Build Coastguard Worker
2130*795d594fSAndroid Build Coastguard Worker Riscv64Label loop;
2131*795d594fSAndroid Build Coastguard Worker __ Bind(&loop);
2132*795d594fSAndroid Build Coastguard Worker __ Ld(tmp, src_curr_addr, 0);
2133*795d594fSAndroid Build Coastguard Worker __ Ld(tmp2, src_curr_addr, 8);
2134*795d594fSAndroid Build Coastguard Worker __ Sd(tmp, dst_curr_addr, 0);
2135*795d594fSAndroid Build Coastguard Worker __ Sd(tmp2, dst_curr_addr, 8);
2136*795d594fSAndroid Build Coastguard Worker __ Addi(length_tmp, length_tmp, -elements_per_block);
2137*795d594fSAndroid Build Coastguard Worker __ Addi(src_curr_addr, src_curr_addr, bytes_copied_per_iteration);
2138*795d594fSAndroid Build Coastguard Worker __ Addi(dst_curr_addr, dst_curr_addr, bytes_copied_per_iteration);
2139*795d594fSAndroid Build Coastguard Worker __ Bgez(length_tmp, &loop);
2140*795d594fSAndroid Build Coastguard Worker };
2141*795d594fSAndroid Build Coastguard Worker
2142*795d594fSAndroid Build Coastguard Worker auto emit_tail_loop = [&]() {
2143*795d594fSAndroid Build Coastguard Worker Riscv64Label loop;
2144*795d594fSAndroid Build Coastguard Worker __ Bind(&loop);
2145*795d594fSAndroid Build Coastguard Worker GenerateUnsignedLoad(assembler, tmp, src_curr_addr, 0, element_size);
2146*795d594fSAndroid Build Coastguard Worker GenerateStore(assembler, tmp, dst_curr_addr, 0, element_size);
2147*795d594fSAndroid Build Coastguard Worker __ Addi(length_tmp, length_tmp, -1);
2148*795d594fSAndroid Build Coastguard Worker __ Addi(src_curr_addr, src_curr_addr, element_size);
2149*795d594fSAndroid Build Coastguard Worker __ Addi(dst_curr_addr, dst_curr_addr, element_size);
2150*795d594fSAndroid Build Coastguard Worker __ Bgtz(length_tmp, &loop);
2151*795d594fSAndroid Build Coastguard Worker };
2152*795d594fSAndroid Build Coastguard Worker
2153*795d594fSAndroid Build Coastguard Worker auto emit_unrolled_tail_loop = [&](int32_t tail_length) {
2154*795d594fSAndroid Build Coastguard Worker DCHECK_LT(tail_length, elements_per_block);
2155*795d594fSAndroid Build Coastguard Worker
2156*795d594fSAndroid Build Coastguard Worker int32_t length_in_bytes = tail_length * element_size;
2157*795d594fSAndroid Build Coastguard Worker size_t offset = 0;
2158*795d594fSAndroid Build Coastguard Worker for (size_t operation_size = 8; operation_size > 0; operation_size >>= 1) {
2159*795d594fSAndroid Build Coastguard Worker if ((length_in_bytes & operation_size) != 0) {
2160*795d594fSAndroid Build Coastguard Worker GenerateUnsignedLoad(assembler, tmp, src_curr_addr, offset, operation_size);
2161*795d594fSAndroid Build Coastguard Worker GenerateStore(assembler, tmp, dst_curr_addr, offset, operation_size);
2162*795d594fSAndroid Build Coastguard Worker offset += operation_size;
2163*795d594fSAndroid Build Coastguard Worker }
2164*795d594fSAndroid Build Coastguard Worker }
2165*795d594fSAndroid Build Coastguard Worker };
2166*795d594fSAndroid Build Coastguard Worker
2167*795d594fSAndroid Build Coastguard Worker if (length.IsConstant()) {
2168*795d594fSAndroid Build Coastguard Worker const int32_t constant_length = length.GetConstant()->AsIntConstant()->GetValue();
2169*795d594fSAndroid Build Coastguard Worker if (constant_length >= elements_per_block) {
2170*795d594fSAndroid Build Coastguard Worker __ Li(length_tmp, constant_length - elements_per_block);
2171*795d594fSAndroid Build Coastguard Worker emit_head_loop();
2172*795d594fSAndroid Build Coastguard Worker }
2173*795d594fSAndroid Build Coastguard Worker emit_unrolled_tail_loop(constant_length % elements_per_block);
2174*795d594fSAndroid Build Coastguard Worker } else {
2175*795d594fSAndroid Build Coastguard Worker Riscv64Label tail_loop;
2176*795d594fSAndroid Build Coastguard Worker XRegister length_reg = length.AsRegister<XRegister>();
2177*795d594fSAndroid Build Coastguard Worker __ Addi(length_tmp, length_reg, -elements_per_block);
2178*795d594fSAndroid Build Coastguard Worker __ Bltz(length_tmp, &tail_loop);
2179*795d594fSAndroid Build Coastguard Worker
2180*795d594fSAndroid Build Coastguard Worker emit_head_loop();
2181*795d594fSAndroid Build Coastguard Worker
2182*795d594fSAndroid Build Coastguard Worker __ Bind(&tail_loop);
2183*795d594fSAndroid Build Coastguard Worker __ Addi(length_tmp, length_tmp, elements_per_block);
2184*795d594fSAndroid Build Coastguard Worker __ Beqz(length_tmp, &done);
2185*795d594fSAndroid Build Coastguard Worker
2186*795d594fSAndroid Build Coastguard Worker emit_tail_loop();
2187*795d594fSAndroid Build Coastguard Worker }
2188*795d594fSAndroid Build Coastguard Worker
2189*795d594fSAndroid Build Coastguard Worker __ Bind(&done);
2190*795d594fSAndroid Build Coastguard Worker __ Bind(slow_path->GetExitLabel());
2191*795d594fSAndroid Build Coastguard Worker }
2192*795d594fSAndroid Build Coastguard Worker
VisitSystemArrayCopyByte(HInvoke * invoke)2193*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitSystemArrayCopyByte(HInvoke* invoke) {
2194*795d594fSAndroid Build Coastguard Worker SystemArrayCopyPrimitive(invoke, codegen_, DataType::Type::kInt8);
2195*795d594fSAndroid Build Coastguard Worker }
2196*795d594fSAndroid Build Coastguard Worker
VisitSystemArrayCopyChar(HInvoke * invoke)2197*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitSystemArrayCopyChar(HInvoke* invoke) {
2198*795d594fSAndroid Build Coastguard Worker SystemArrayCopyPrimitive(invoke, codegen_, DataType::Type::kUint16);
2199*795d594fSAndroid Build Coastguard Worker }
2200*795d594fSAndroid Build Coastguard Worker
VisitSystemArrayCopyInt(HInvoke * invoke)2201*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitSystemArrayCopyInt(HInvoke* invoke) {
2202*795d594fSAndroid Build Coastguard Worker SystemArrayCopyPrimitive(invoke, codegen_, DataType::Type::kInt32);
2203*795d594fSAndroid Build Coastguard Worker }
2204*795d594fSAndroid Build Coastguard Worker
2205*795d594fSAndroid Build Coastguard Worker enum class GetAndUpdateOp {
2206*795d594fSAndroid Build Coastguard Worker kSet,
2207*795d594fSAndroid Build Coastguard Worker kAdd,
2208*795d594fSAndroid Build Coastguard Worker kAnd,
2209*795d594fSAndroid Build Coastguard Worker kOr,
2210*795d594fSAndroid Build Coastguard Worker kXor
2211*795d594fSAndroid Build Coastguard Worker };
2212*795d594fSAndroid Build Coastguard Worker
2213*795d594fSAndroid Build Coastguard Worker // Generate a GetAndUpdate operation.
2214*795d594fSAndroid Build Coastguard Worker //
2215*795d594fSAndroid Build Coastguard Worker // Only 32-bit and 64-bit atomics are currently supported, therefore smaller types need
2216*795d594fSAndroid Build Coastguard Worker // special handling. The caller emits code to prepare aligned `ptr` and adjusted `arg`
2217*795d594fSAndroid Build Coastguard Worker // and extract the needed bits from `old_value`. For bitwise operations, no extra
2218*795d594fSAndroid Build Coastguard Worker // handling is needed here. For `GetAndUpdateOp::kSet` and `GetAndUpdateOp::kAdd` we
2219*795d594fSAndroid Build Coastguard Worker // also use a special LR/SC sequence that uses a `mask` to update only the desired bits.
2220*795d594fSAndroid Build Coastguard Worker // Note: The `mask` must contain the bits to keep for `GetAndUpdateOp::kSet` and
2221*795d594fSAndroid Build Coastguard Worker // the bits to replace for `GetAndUpdateOp::kAdd`.
GenerateGetAndUpdate(CodeGeneratorRISCV64 * codegen,GetAndUpdateOp get_and_update_op,DataType::Type type,std::memory_order order,XRegister ptr,XRegister arg,XRegister old_value,XRegister mask,XRegister temp)2222*795d594fSAndroid Build Coastguard Worker static void GenerateGetAndUpdate(CodeGeneratorRISCV64* codegen,
2223*795d594fSAndroid Build Coastguard Worker GetAndUpdateOp get_and_update_op,
2224*795d594fSAndroid Build Coastguard Worker DataType::Type type,
2225*795d594fSAndroid Build Coastguard Worker std::memory_order order,
2226*795d594fSAndroid Build Coastguard Worker XRegister ptr,
2227*795d594fSAndroid Build Coastguard Worker XRegister arg,
2228*795d594fSAndroid Build Coastguard Worker XRegister old_value,
2229*795d594fSAndroid Build Coastguard Worker XRegister mask,
2230*795d594fSAndroid Build Coastguard Worker XRegister temp) {
2231*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(mask != kNoXRegister, temp != kNoXRegister);
2232*795d594fSAndroid Build Coastguard Worker DCHECK_IMPLIES(mask != kNoXRegister, type == DataType::Type::kInt32);
2233*795d594fSAndroid Build Coastguard Worker DCHECK_IMPLIES(
2234*795d594fSAndroid Build Coastguard Worker mask != kNoXRegister,
2235*795d594fSAndroid Build Coastguard Worker (get_and_update_op == GetAndUpdateOp::kSet) || (get_and_update_op == GetAndUpdateOp::kAdd));
2236*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = codegen->GetAssembler();
2237*795d594fSAndroid Build Coastguard Worker AqRl amo_aqrl = GetAmoAqRl(order);
2238*795d594fSAndroid Build Coastguard Worker switch (get_and_update_op) {
2239*795d594fSAndroid Build Coastguard Worker case GetAndUpdateOp::kSet:
2240*795d594fSAndroid Build Coastguard Worker if (type == DataType::Type::kInt64) {
2241*795d594fSAndroid Build Coastguard Worker __ AmoSwapD(old_value, arg, ptr, amo_aqrl);
2242*795d594fSAndroid Build Coastguard Worker } else if (mask == kNoXRegister) {
2243*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(type, DataType::Type::kInt32);
2244*795d594fSAndroid Build Coastguard Worker __ AmoSwapW(old_value, arg, ptr, amo_aqrl);
2245*795d594fSAndroid Build Coastguard Worker } else {
2246*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(type, DataType::Type::kInt32);
2247*795d594fSAndroid Build Coastguard Worker DCHECK_NE(temp, kNoXRegister);
2248*795d594fSAndroid Build Coastguard Worker auto [load_aqrl, store_aqrl] = GetLrScAqRl(order);
2249*795d594fSAndroid Build Coastguard Worker Riscv64Label retry;
2250*795d594fSAndroid Build Coastguard Worker __ Bind(&retry);
2251*795d594fSAndroid Build Coastguard Worker __ LrW(old_value, ptr, load_aqrl);
2252*795d594fSAndroid Build Coastguard Worker {
2253*795d594fSAndroid Build Coastguard Worker ScopedLrScExtensionsRestriction slser(assembler);
2254*795d594fSAndroid Build Coastguard Worker __ And(temp, old_value, mask);
2255*795d594fSAndroid Build Coastguard Worker __ Or(temp, temp, arg);
2256*795d594fSAndroid Build Coastguard Worker }
2257*795d594fSAndroid Build Coastguard Worker __ ScW(temp, temp, ptr, store_aqrl);
2258*795d594fSAndroid Build Coastguard Worker __ Bnez(temp, &retry, /*is_bare=*/ true); // Bare: `TMP` shall not be clobbered.
2259*795d594fSAndroid Build Coastguard Worker }
2260*795d594fSAndroid Build Coastguard Worker break;
2261*795d594fSAndroid Build Coastguard Worker case GetAndUpdateOp::kAdd:
2262*795d594fSAndroid Build Coastguard Worker if (type == DataType::Type::kInt64) {
2263*795d594fSAndroid Build Coastguard Worker __ AmoAddD(old_value, arg, ptr, amo_aqrl);
2264*795d594fSAndroid Build Coastguard Worker } else if (mask == kNoXRegister) {
2265*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(type, DataType::Type::kInt32);
2266*795d594fSAndroid Build Coastguard Worker __ AmoAddW(old_value, arg, ptr, amo_aqrl);
2267*795d594fSAndroid Build Coastguard Worker } else {
2268*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(type, DataType::Type::kInt32);
2269*795d594fSAndroid Build Coastguard Worker DCHECK_NE(temp, kNoXRegister);
2270*795d594fSAndroid Build Coastguard Worker auto [load_aqrl, store_aqrl] = GetLrScAqRl(order);
2271*795d594fSAndroid Build Coastguard Worker Riscv64Label retry;
2272*795d594fSAndroid Build Coastguard Worker __ Bind(&retry);
2273*795d594fSAndroid Build Coastguard Worker __ LrW(old_value, ptr, load_aqrl);
2274*795d594fSAndroid Build Coastguard Worker {
2275*795d594fSAndroid Build Coastguard Worker ScopedLrScExtensionsRestriction slser(assembler);
2276*795d594fSAndroid Build Coastguard Worker __ Add(temp, old_value, arg);
2277*795d594fSAndroid Build Coastguard Worker // We use `(A ^ B) ^ A == B` and with the masking `((A ^ B) & mask) ^ A`, the result
2278*795d594fSAndroid Build Coastguard Worker // contains bits from `B` for bits specified in `mask` and bits from `A` elsewhere.
2279*795d594fSAndroid Build Coastguard Worker // Note: These instructions directly depend on each other, so it's not necessarily the
2280*795d594fSAndroid Build Coastguard Worker // fastest approach but for `(A ^ ~mask) | (B & mask)` we would need an extra register
2281*795d594fSAndroid Build Coastguard Worker // for `~mask` because ANDN is not in the "I" instruction set as required for a LR/SC
2282*795d594fSAndroid Build Coastguard Worker // sequence.
2283*795d594fSAndroid Build Coastguard Worker __ Xor(temp, temp, old_value);
2284*795d594fSAndroid Build Coastguard Worker __ And(temp, temp, mask);
2285*795d594fSAndroid Build Coastguard Worker __ Xor(temp, temp, old_value);
2286*795d594fSAndroid Build Coastguard Worker }
2287*795d594fSAndroid Build Coastguard Worker __ ScW(temp, temp, ptr, store_aqrl);
2288*795d594fSAndroid Build Coastguard Worker __ Bnez(temp, &retry, /*is_bare=*/ true); // Bare: `TMP` shall not be clobbered.
2289*795d594fSAndroid Build Coastguard Worker }
2290*795d594fSAndroid Build Coastguard Worker break;
2291*795d594fSAndroid Build Coastguard Worker case GetAndUpdateOp::kAnd:
2292*795d594fSAndroid Build Coastguard Worker if (type == DataType::Type::kInt64) {
2293*795d594fSAndroid Build Coastguard Worker __ AmoAndD(old_value, arg, ptr, amo_aqrl);
2294*795d594fSAndroid Build Coastguard Worker } else {
2295*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(type, DataType::Type::kInt32);
2296*795d594fSAndroid Build Coastguard Worker __ AmoAndW(old_value, arg, ptr, amo_aqrl);
2297*795d594fSAndroid Build Coastguard Worker }
2298*795d594fSAndroid Build Coastguard Worker break;
2299*795d594fSAndroid Build Coastguard Worker case GetAndUpdateOp::kOr:
2300*795d594fSAndroid Build Coastguard Worker if (type == DataType::Type::kInt64) {
2301*795d594fSAndroid Build Coastguard Worker __ AmoOrD(old_value, arg, ptr, amo_aqrl);
2302*795d594fSAndroid Build Coastguard Worker } else {
2303*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(type, DataType::Type::kInt32);
2304*795d594fSAndroid Build Coastguard Worker __ AmoOrW(old_value, arg, ptr, amo_aqrl);
2305*795d594fSAndroid Build Coastguard Worker }
2306*795d594fSAndroid Build Coastguard Worker break;
2307*795d594fSAndroid Build Coastguard Worker case GetAndUpdateOp::kXor:
2308*795d594fSAndroid Build Coastguard Worker if (type == DataType::Type::kInt64) {
2309*795d594fSAndroid Build Coastguard Worker __ AmoXorD(old_value, arg, ptr, amo_aqrl);
2310*795d594fSAndroid Build Coastguard Worker } else {
2311*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(type, DataType::Type::kInt32);
2312*795d594fSAndroid Build Coastguard Worker __ AmoXorW(old_value, arg, ptr, amo_aqrl);
2313*795d594fSAndroid Build Coastguard Worker }
2314*795d594fSAndroid Build Coastguard Worker break;
2315*795d594fSAndroid Build Coastguard Worker }
2316*795d594fSAndroid Build Coastguard Worker }
2317*795d594fSAndroid Build Coastguard Worker
CreateUnsafeGetLocations(ArenaAllocator * allocator,HInvoke * invoke,CodeGeneratorRISCV64 * codegen)2318*795d594fSAndroid Build Coastguard Worker static void CreateUnsafeGetLocations(ArenaAllocator* allocator,
2319*795d594fSAndroid Build Coastguard Worker HInvoke* invoke,
2320*795d594fSAndroid Build Coastguard Worker CodeGeneratorRISCV64* codegen) {
2321*795d594fSAndroid Build Coastguard Worker bool can_call = codegen->EmitReadBarrier() && IsUnsafeGetReference(invoke);
2322*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = new (allocator) LocationSummary(
2323*795d594fSAndroid Build Coastguard Worker invoke,
2324*795d594fSAndroid Build Coastguard Worker can_call ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall,
2325*795d594fSAndroid Build Coastguard Worker kIntrinsified);
2326*795d594fSAndroid Build Coastguard Worker if (can_call && kUseBakerReadBarrier) {
2327*795d594fSAndroid Build Coastguard Worker locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
2328*795d594fSAndroid Build Coastguard Worker }
2329*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::NoLocation()); // Unused receiver.
2330*795d594fSAndroid Build Coastguard Worker locations->SetInAt(1, Location::RequiresRegister());
2331*795d594fSAndroid Build Coastguard Worker locations->SetInAt(2, Location::RequiresRegister());
2332*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresRegister(),
2333*795d594fSAndroid Build Coastguard Worker (can_call ? Location::kOutputOverlap : Location::kNoOutputOverlap));
2334*795d594fSAndroid Build Coastguard Worker }
2335*795d594fSAndroid Build Coastguard Worker
CreateUnsafeGetAbsoluteLocations(ArenaAllocator * allocator,HInvoke * invoke)2336*795d594fSAndroid Build Coastguard Worker static void CreateUnsafeGetAbsoluteLocations(ArenaAllocator* allocator,
2337*795d594fSAndroid Build Coastguard Worker HInvoke* invoke) {
2338*795d594fSAndroid Build Coastguard Worker LocationSummary* locations =
2339*795d594fSAndroid Build Coastguard Worker new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
2340*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::NoLocation()); // Unused receiver.
2341*795d594fSAndroid Build Coastguard Worker locations->SetInAt(1, Location::RequiresRegister());
2342*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2343*795d594fSAndroid Build Coastguard Worker }
2344*795d594fSAndroid Build Coastguard Worker
GenUnsafeGet(HInvoke * invoke,CodeGeneratorRISCV64 * codegen,std::memory_order order,DataType::Type type)2345*795d594fSAndroid Build Coastguard Worker static void GenUnsafeGet(HInvoke* invoke,
2346*795d594fSAndroid Build Coastguard Worker CodeGeneratorRISCV64* codegen,
2347*795d594fSAndroid Build Coastguard Worker std::memory_order order,
2348*795d594fSAndroid Build Coastguard Worker DataType::Type type) {
2349*795d594fSAndroid Build Coastguard Worker DCHECK((type == DataType::Type::kInt8) ||
2350*795d594fSAndroid Build Coastguard Worker (type == DataType::Type::kInt32) ||
2351*795d594fSAndroid Build Coastguard Worker (type == DataType::Type::kInt64) ||
2352*795d594fSAndroid Build Coastguard Worker (type == DataType::Type::kReference));
2353*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = invoke->GetLocations();
2354*795d594fSAndroid Build Coastguard Worker Location object_loc = locations->InAt(1);
2355*795d594fSAndroid Build Coastguard Worker XRegister object = object_loc.AsRegister<XRegister>(); // Object pointer.
2356*795d594fSAndroid Build Coastguard Worker Location offset_loc = locations->InAt(2);
2357*795d594fSAndroid Build Coastguard Worker XRegister offset = offset_loc.AsRegister<XRegister>(); // Long offset.
2358*795d594fSAndroid Build Coastguard Worker Location out_loc = locations->Out();
2359*795d594fSAndroid Build Coastguard Worker XRegister out = out_loc.AsRegister<XRegister>();
2360*795d594fSAndroid Build Coastguard Worker
2361*795d594fSAndroid Build Coastguard Worker bool seq_cst_barrier = (order == std::memory_order_seq_cst);
2362*795d594fSAndroid Build Coastguard Worker bool acquire_barrier = seq_cst_barrier || (order == std::memory_order_acquire);
2363*795d594fSAndroid Build Coastguard Worker DCHECK(acquire_barrier || order == std::memory_order_relaxed);
2364*795d594fSAndroid Build Coastguard Worker
2365*795d594fSAndroid Build Coastguard Worker if (seq_cst_barrier) {
2366*795d594fSAndroid Build Coastguard Worker codegen->GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
2367*795d594fSAndroid Build Coastguard Worker }
2368*795d594fSAndroid Build Coastguard Worker
2369*795d594fSAndroid Build Coastguard Worker if (type == DataType::Type::kReference && codegen->EmitBakerReadBarrier()) {
2370*795d594fSAndroid Build Coastguard Worker // JdkUnsafeGetReference/JdkUnsafeGetReferenceVolatile with Baker's read barrier case.
2371*795d594fSAndroid Build Coastguard Worker // TODO(riscv64): Revisit when we add checking if the holder is black.
2372*795d594fSAndroid Build Coastguard Worker Location temp = Location::NoLocation();
2373*795d594fSAndroid Build Coastguard Worker codegen->GenerateReferenceLoadWithBakerReadBarrier(invoke,
2374*795d594fSAndroid Build Coastguard Worker out_loc,
2375*795d594fSAndroid Build Coastguard Worker object,
2376*795d594fSAndroid Build Coastguard Worker /*offset=*/ 0,
2377*795d594fSAndroid Build Coastguard Worker /*index=*/ offset_loc,
2378*795d594fSAndroid Build Coastguard Worker temp,
2379*795d594fSAndroid Build Coastguard Worker /*needs_null_check=*/ false);
2380*795d594fSAndroid Build Coastguard Worker } else {
2381*795d594fSAndroid Build Coastguard Worker // Other cases.
2382*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = codegen->GetAssembler();
2383*795d594fSAndroid Build Coastguard Worker __ Add(out, object, offset);
2384*795d594fSAndroid Build Coastguard Worker codegen->GetInstructionVisitor()->Load(out_loc, out, /*offset=*/ 0, type);
2385*795d594fSAndroid Build Coastguard Worker
2386*795d594fSAndroid Build Coastguard Worker if (type == DataType::Type::kReference) {
2387*795d594fSAndroid Build Coastguard Worker codegen->MaybeGenerateReadBarrierSlow(
2388*795d594fSAndroid Build Coastguard Worker invoke, out_loc, out_loc, object_loc, /*offset=*/ 0u, /*index=*/ offset_loc);
2389*795d594fSAndroid Build Coastguard Worker }
2390*795d594fSAndroid Build Coastguard Worker }
2391*795d594fSAndroid Build Coastguard Worker
2392*795d594fSAndroid Build Coastguard Worker if (acquire_barrier) {
2393*795d594fSAndroid Build Coastguard Worker codegen->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
2394*795d594fSAndroid Build Coastguard Worker }
2395*795d594fSAndroid Build Coastguard Worker }
2396*795d594fSAndroid Build Coastguard Worker
GenUnsafeGetAbsolute(HInvoke * invoke,CodeGeneratorRISCV64 * codegen,std::memory_order order,DataType::Type type)2397*795d594fSAndroid Build Coastguard Worker static void GenUnsafeGetAbsolute(HInvoke* invoke,
2398*795d594fSAndroid Build Coastguard Worker CodeGeneratorRISCV64* codegen,
2399*795d594fSAndroid Build Coastguard Worker std::memory_order order,
2400*795d594fSAndroid Build Coastguard Worker DataType::Type type) {
2401*795d594fSAndroid Build Coastguard Worker DCHECK((type == DataType::Type::kInt8) ||
2402*795d594fSAndroid Build Coastguard Worker (type == DataType::Type::kInt32) ||
2403*795d594fSAndroid Build Coastguard Worker (type == DataType::Type::kInt64));
2404*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = invoke->GetLocations();
2405*795d594fSAndroid Build Coastguard Worker Location address_loc = locations->InAt(1);
2406*795d594fSAndroid Build Coastguard Worker XRegister address = address_loc.AsRegister<XRegister>();
2407*795d594fSAndroid Build Coastguard Worker Location out_loc = locations->Out();
2408*795d594fSAndroid Build Coastguard Worker
2409*795d594fSAndroid Build Coastguard Worker bool seq_cst_barrier = order == std::memory_order_seq_cst;
2410*795d594fSAndroid Build Coastguard Worker bool acquire_barrier = seq_cst_barrier || order == std::memory_order_acquire;
2411*795d594fSAndroid Build Coastguard Worker DCHECK(acquire_barrier || order == std::memory_order_relaxed);
2412*795d594fSAndroid Build Coastguard Worker
2413*795d594fSAndroid Build Coastguard Worker if (seq_cst_barrier) {
2414*795d594fSAndroid Build Coastguard Worker codegen->GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
2415*795d594fSAndroid Build Coastguard Worker }
2416*795d594fSAndroid Build Coastguard Worker
2417*795d594fSAndroid Build Coastguard Worker codegen->GetInstructionVisitor()->Load(out_loc, address, /*offset=*/ 0, type);
2418*795d594fSAndroid Build Coastguard Worker
2419*795d594fSAndroid Build Coastguard Worker if (acquire_barrier) {
2420*795d594fSAndroid Build Coastguard Worker codegen->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
2421*795d594fSAndroid Build Coastguard Worker }
2422*795d594fSAndroid Build Coastguard Worker }
2423*795d594fSAndroid Build Coastguard Worker
VisitUnsafeGet(HInvoke * invoke)2424*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitUnsafeGet(HInvoke* invoke) {
2425*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafeGet(invoke);
2426*795d594fSAndroid Build Coastguard Worker }
2427*795d594fSAndroid Build Coastguard Worker
VisitUnsafeGetAbsolute(HInvoke * invoke)2428*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitUnsafeGetAbsolute(HInvoke* invoke) {
2429*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafeGetAbsolute(invoke);
2430*795d594fSAndroid Build Coastguard Worker }
2431*795d594fSAndroid Build Coastguard Worker
VisitUnsafeGet(HInvoke * invoke)2432*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitUnsafeGet(HInvoke* invoke) {
2433*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafeGet(invoke);
2434*795d594fSAndroid Build Coastguard Worker }
2435*795d594fSAndroid Build Coastguard Worker
VisitUnsafeGetAbsolute(HInvoke * invoke)2436*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitUnsafeGetAbsolute(HInvoke* invoke) {
2437*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafeGetAbsolute(invoke);
2438*795d594fSAndroid Build Coastguard Worker }
2439*795d594fSAndroid Build Coastguard Worker
VisitUnsafeGetVolatile(HInvoke * invoke)2440*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitUnsafeGetVolatile(HInvoke* invoke) {
2441*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafeGetVolatile(invoke);
2442*795d594fSAndroid Build Coastguard Worker }
2443*795d594fSAndroid Build Coastguard Worker
VisitUnsafeGetVolatile(HInvoke * invoke)2444*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitUnsafeGetVolatile(HInvoke* invoke) {
2445*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafeGetVolatile(invoke);
2446*795d594fSAndroid Build Coastguard Worker }
2447*795d594fSAndroid Build Coastguard Worker
VisitUnsafeGetObject(HInvoke * invoke)2448*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitUnsafeGetObject(HInvoke* invoke) {
2449*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafeGetReference(invoke);
2450*795d594fSAndroid Build Coastguard Worker }
2451*795d594fSAndroid Build Coastguard Worker
VisitUnsafeGetObject(HInvoke * invoke)2452*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitUnsafeGetObject(HInvoke* invoke) {
2453*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafeGetReference(invoke);
2454*795d594fSAndroid Build Coastguard Worker }
2455*795d594fSAndroid Build Coastguard Worker
VisitUnsafeGetObjectVolatile(HInvoke * invoke)2456*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitUnsafeGetObjectVolatile(HInvoke* invoke) {
2457*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafeGetReferenceVolatile(invoke);
2458*795d594fSAndroid Build Coastguard Worker }
2459*795d594fSAndroid Build Coastguard Worker
VisitUnsafeGetObjectVolatile(HInvoke * invoke)2460*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitUnsafeGetObjectVolatile(HInvoke* invoke) {
2461*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafeGetReferenceVolatile(invoke);
2462*795d594fSAndroid Build Coastguard Worker }
2463*795d594fSAndroid Build Coastguard Worker
VisitUnsafeGetLong(HInvoke * invoke)2464*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitUnsafeGetLong(HInvoke* invoke) {
2465*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafeGetLong(invoke);
2466*795d594fSAndroid Build Coastguard Worker }
2467*795d594fSAndroid Build Coastguard Worker
VisitUnsafeGetLong(HInvoke * invoke)2468*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitUnsafeGetLong(HInvoke* invoke) {
2469*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafeGetLong(invoke);
2470*795d594fSAndroid Build Coastguard Worker }
2471*795d594fSAndroid Build Coastguard Worker
VisitUnsafeGetLongVolatile(HInvoke * invoke)2472*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitUnsafeGetLongVolatile(HInvoke* invoke) {
2473*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafeGetLongVolatile(invoke);
2474*795d594fSAndroid Build Coastguard Worker }
2475*795d594fSAndroid Build Coastguard Worker
VisitUnsafeGetLongVolatile(HInvoke * invoke)2476*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitUnsafeGetLongVolatile(HInvoke* invoke) {
2477*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafeGetLongVolatile(invoke);
2478*795d594fSAndroid Build Coastguard Worker }
2479*795d594fSAndroid Build Coastguard Worker
VisitUnsafeGetByte(HInvoke * invoke)2480*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitUnsafeGetByte(HInvoke* invoke) {
2481*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafeGetByte(invoke);
2482*795d594fSAndroid Build Coastguard Worker }
2483*795d594fSAndroid Build Coastguard Worker
VisitUnsafeGetByte(HInvoke * invoke)2484*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitUnsafeGetByte(HInvoke* invoke) {
2485*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafeGetByte(invoke);
2486*795d594fSAndroid Build Coastguard Worker }
2487*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafeGet(HInvoke * invoke)2488*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitJdkUnsafeGet(HInvoke* invoke) {
2489*795d594fSAndroid Build Coastguard Worker CreateUnsafeGetLocations(allocator_, invoke, codegen_);
2490*795d594fSAndroid Build Coastguard Worker }
2491*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafeGetAbsolute(HInvoke * invoke)2492*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitJdkUnsafeGetAbsolute(HInvoke* invoke) {
2493*795d594fSAndroid Build Coastguard Worker CreateUnsafeGetAbsoluteLocations(allocator_, invoke);
2494*795d594fSAndroid Build Coastguard Worker }
2495*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafeGet(HInvoke * invoke)2496*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitJdkUnsafeGet(HInvoke* invoke) {
2497*795d594fSAndroid Build Coastguard Worker GenUnsafeGet(invoke, codegen_, std::memory_order_relaxed, DataType::Type::kInt32);
2498*795d594fSAndroid Build Coastguard Worker }
2499*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafeGetAbsolute(HInvoke * invoke)2500*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitJdkUnsafeGetAbsolute(HInvoke* invoke) {
2501*795d594fSAndroid Build Coastguard Worker GenUnsafeGetAbsolute(invoke, codegen_, std::memory_order_relaxed, DataType::Type::kInt32);
2502*795d594fSAndroid Build Coastguard Worker }
2503*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafeGetAcquire(HInvoke * invoke)2504*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitJdkUnsafeGetAcquire(HInvoke* invoke) {
2505*795d594fSAndroid Build Coastguard Worker CreateUnsafeGetLocations(allocator_, invoke, codegen_);
2506*795d594fSAndroid Build Coastguard Worker }
2507*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafeGetAcquire(HInvoke * invoke)2508*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitJdkUnsafeGetAcquire(HInvoke* invoke) {
2509*795d594fSAndroid Build Coastguard Worker GenUnsafeGet(invoke, codegen_, std::memory_order_acquire, DataType::Type::kInt32);
2510*795d594fSAndroid Build Coastguard Worker }
2511*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafeGetVolatile(HInvoke * invoke)2512*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitJdkUnsafeGetVolatile(HInvoke* invoke) {
2513*795d594fSAndroid Build Coastguard Worker CreateUnsafeGetLocations(allocator_, invoke, codegen_);
2514*795d594fSAndroid Build Coastguard Worker }
2515*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafeGetVolatile(HInvoke * invoke)2516*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitJdkUnsafeGetVolatile(HInvoke* invoke) {
2517*795d594fSAndroid Build Coastguard Worker GenUnsafeGet(invoke, codegen_, std::memory_order_seq_cst, DataType::Type::kInt32);
2518*795d594fSAndroid Build Coastguard Worker }
2519*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafeGetReference(HInvoke * invoke)2520*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitJdkUnsafeGetReference(HInvoke* invoke) {
2521*795d594fSAndroid Build Coastguard Worker CreateUnsafeGetLocations(allocator_, invoke, codegen_);
2522*795d594fSAndroid Build Coastguard Worker }
2523*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafeGetReference(HInvoke * invoke)2524*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitJdkUnsafeGetReference(HInvoke* invoke) {
2525*795d594fSAndroid Build Coastguard Worker GenUnsafeGet(invoke, codegen_, std::memory_order_relaxed, DataType::Type::kReference);
2526*795d594fSAndroid Build Coastguard Worker }
2527*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafeGetReferenceAcquire(HInvoke * invoke)2528*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitJdkUnsafeGetReferenceAcquire(HInvoke* invoke) {
2529*795d594fSAndroid Build Coastguard Worker CreateUnsafeGetLocations(allocator_, invoke, codegen_);
2530*795d594fSAndroid Build Coastguard Worker }
2531*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafeGetReferenceAcquire(HInvoke * invoke)2532*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitJdkUnsafeGetReferenceAcquire(HInvoke* invoke) {
2533*795d594fSAndroid Build Coastguard Worker GenUnsafeGet(invoke, codegen_, std::memory_order_acquire, DataType::Type::kReference);
2534*795d594fSAndroid Build Coastguard Worker }
2535*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafeGetReferenceVolatile(HInvoke * invoke)2536*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitJdkUnsafeGetReferenceVolatile(HInvoke* invoke) {
2537*795d594fSAndroid Build Coastguard Worker CreateUnsafeGetLocations(allocator_, invoke, codegen_);
2538*795d594fSAndroid Build Coastguard Worker }
2539*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafeGetReferenceVolatile(HInvoke * invoke)2540*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitJdkUnsafeGetReferenceVolatile(HInvoke* invoke) {
2541*795d594fSAndroid Build Coastguard Worker GenUnsafeGet(invoke, codegen_, std::memory_order_seq_cst, DataType::Type::kReference);
2542*795d594fSAndroid Build Coastguard Worker }
2543*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafeGetLong(HInvoke * invoke)2544*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitJdkUnsafeGetLong(HInvoke* invoke) {
2545*795d594fSAndroid Build Coastguard Worker CreateUnsafeGetLocations(allocator_, invoke, codegen_);
2546*795d594fSAndroid Build Coastguard Worker }
2547*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafeGetLong(HInvoke * invoke)2548*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitJdkUnsafeGetLong(HInvoke* invoke) {
2549*795d594fSAndroid Build Coastguard Worker GenUnsafeGet(invoke, codegen_, std::memory_order_relaxed, DataType::Type::kInt64);
2550*795d594fSAndroid Build Coastguard Worker }
2551*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafeGetLongAcquire(HInvoke * invoke)2552*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitJdkUnsafeGetLongAcquire(HInvoke* invoke) {
2553*795d594fSAndroid Build Coastguard Worker CreateUnsafeGetLocations(allocator_, invoke, codegen_);
2554*795d594fSAndroid Build Coastguard Worker }
2555*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafeGetLongAcquire(HInvoke * invoke)2556*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitJdkUnsafeGetLongAcquire(HInvoke* invoke) {
2557*795d594fSAndroid Build Coastguard Worker GenUnsafeGet(invoke, codegen_, std::memory_order_acquire, DataType::Type::kInt64);
2558*795d594fSAndroid Build Coastguard Worker }
2559*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafeGetLongVolatile(HInvoke * invoke)2560*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitJdkUnsafeGetLongVolatile(HInvoke* invoke) {
2561*795d594fSAndroid Build Coastguard Worker CreateUnsafeGetLocations(allocator_, invoke, codegen_);
2562*795d594fSAndroid Build Coastguard Worker }
2563*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafeGetLongVolatile(HInvoke * invoke)2564*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitJdkUnsafeGetLongVolatile(HInvoke* invoke) {
2565*795d594fSAndroid Build Coastguard Worker GenUnsafeGet(invoke, codegen_, std::memory_order_seq_cst, DataType::Type::kInt64);
2566*795d594fSAndroid Build Coastguard Worker }
2567*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafeGetByte(HInvoke * invoke)2568*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitJdkUnsafeGetByte(HInvoke* invoke) {
2569*795d594fSAndroid Build Coastguard Worker CreateUnsafeGetLocations(allocator_, invoke, codegen_);
2570*795d594fSAndroid Build Coastguard Worker }
2571*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafeGetByte(HInvoke * invoke)2572*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitJdkUnsafeGetByte(HInvoke* invoke) {
2573*795d594fSAndroid Build Coastguard Worker GenUnsafeGet(invoke, codegen_, std::memory_order_relaxed, DataType::Type::kInt8);
2574*795d594fSAndroid Build Coastguard Worker }
2575*795d594fSAndroid Build Coastguard Worker
CreateUnsafePutLocations(ArenaAllocator * allocator,HInvoke * invoke)2576*795d594fSAndroid Build Coastguard Worker static void CreateUnsafePutLocations(ArenaAllocator* allocator, HInvoke* invoke) {
2577*795d594fSAndroid Build Coastguard Worker LocationSummary* locations =
2578*795d594fSAndroid Build Coastguard Worker new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
2579*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::NoLocation()); // Unused receiver.
2580*795d594fSAndroid Build Coastguard Worker locations->SetInAt(1, Location::RequiresRegister());
2581*795d594fSAndroid Build Coastguard Worker locations->SetInAt(2, Location::RequiresRegister());
2582*795d594fSAndroid Build Coastguard Worker locations->SetInAt(3, Location::RequiresRegister());
2583*795d594fSAndroid Build Coastguard Worker if (kPoisonHeapReferences && invoke->InputAt(3)->GetType() == DataType::Type::kReference) {
2584*795d594fSAndroid Build Coastguard Worker locations->AddTemp(Location::RequiresRegister());
2585*795d594fSAndroid Build Coastguard Worker }
2586*795d594fSAndroid Build Coastguard Worker }
2587*795d594fSAndroid Build Coastguard Worker
CreateUnsafePutAbsoluteLocations(ArenaAllocator * allocator,HInvoke * invoke)2588*795d594fSAndroid Build Coastguard Worker static void CreateUnsafePutAbsoluteLocations(ArenaAllocator* allocator, HInvoke* invoke) {
2589*795d594fSAndroid Build Coastguard Worker LocationSummary* locations =
2590*795d594fSAndroid Build Coastguard Worker new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
2591*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::NoLocation()); // Unused receiver.
2592*795d594fSAndroid Build Coastguard Worker locations->SetInAt(1, Location::RequiresRegister());
2593*795d594fSAndroid Build Coastguard Worker locations->SetInAt(2, Location::RequiresRegister());
2594*795d594fSAndroid Build Coastguard Worker }
2595*795d594fSAndroid Build Coastguard Worker
GenUnsafePut(HInvoke * invoke,CodeGeneratorRISCV64 * codegen,std::memory_order order,DataType::Type type)2596*795d594fSAndroid Build Coastguard Worker static void GenUnsafePut(HInvoke* invoke,
2597*795d594fSAndroid Build Coastguard Worker CodeGeneratorRISCV64* codegen,
2598*795d594fSAndroid Build Coastguard Worker std::memory_order order,
2599*795d594fSAndroid Build Coastguard Worker DataType::Type type) {
2600*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = codegen->GetAssembler();
2601*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = invoke->GetLocations();
2602*795d594fSAndroid Build Coastguard Worker XRegister base = locations->InAt(1).AsRegister<XRegister>(); // Object pointer.
2603*795d594fSAndroid Build Coastguard Worker XRegister offset = locations->InAt(2).AsRegister<XRegister>(); // Long offset.
2604*795d594fSAndroid Build Coastguard Worker Location value = locations->InAt(3);
2605*795d594fSAndroid Build Coastguard Worker
2606*795d594fSAndroid Build Coastguard Worker {
2607*795d594fSAndroid Build Coastguard Worker // We use a block to end the scratch scope before the write barrier, thus
2608*795d594fSAndroid Build Coastguard Worker // freeing the temporary registers so they can be used in `MarkGCCard()`.
2609*795d594fSAndroid Build Coastguard Worker ScratchRegisterScope srs(assembler);
2610*795d594fSAndroid Build Coastguard Worker // Heap poisoning needs two scratch registers in `Store()`.
2611*795d594fSAndroid Build Coastguard Worker XRegister address = (kPoisonHeapReferences && type == DataType::Type::kReference)
2612*795d594fSAndroid Build Coastguard Worker ? locations->GetTemp(0).AsRegister<XRegister>()
2613*795d594fSAndroid Build Coastguard Worker : srs.AllocateXRegister();
2614*795d594fSAndroid Build Coastguard Worker __ Add(address, base, offset);
2615*795d594fSAndroid Build Coastguard Worker GenerateSet(codegen, order, value, address, /*offset=*/ 0, type);
2616*795d594fSAndroid Build Coastguard Worker }
2617*795d594fSAndroid Build Coastguard Worker
2618*795d594fSAndroid Build Coastguard Worker if (type == DataType::Type::kReference) {
2619*795d594fSAndroid Build Coastguard Worker bool value_can_be_null = true; // TODO: Worth finding out this information?
2620*795d594fSAndroid Build Coastguard Worker codegen->MaybeMarkGCCard(base, value.AsRegister<XRegister>(), value_can_be_null);
2621*795d594fSAndroid Build Coastguard Worker }
2622*795d594fSAndroid Build Coastguard Worker }
2623*795d594fSAndroid Build Coastguard Worker
GenUnsafePutAbsolute(HInvoke * invoke,CodeGeneratorRISCV64 * codegen,std::memory_order order,DataType::Type type)2624*795d594fSAndroid Build Coastguard Worker static void GenUnsafePutAbsolute(HInvoke* invoke,
2625*795d594fSAndroid Build Coastguard Worker CodeGeneratorRISCV64* codegen,
2626*795d594fSAndroid Build Coastguard Worker std::memory_order order,
2627*795d594fSAndroid Build Coastguard Worker DataType::Type type) {
2628*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = invoke->GetLocations();
2629*795d594fSAndroid Build Coastguard Worker XRegister address = locations->InAt(1).AsRegister<XRegister>();
2630*795d594fSAndroid Build Coastguard Worker Location value = locations->InAt(2);
2631*795d594fSAndroid Build Coastguard Worker
2632*795d594fSAndroid Build Coastguard Worker GenerateSet(codegen, order, value, address, /*offset=*/ 0, type);
2633*795d594fSAndroid Build Coastguard Worker }
2634*795d594fSAndroid Build Coastguard Worker
VisitUnsafePut(HInvoke * invoke)2635*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitUnsafePut(HInvoke* invoke) {
2636*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafePut(invoke);
2637*795d594fSAndroid Build Coastguard Worker }
2638*795d594fSAndroid Build Coastguard Worker
VisitUnsafePutAbsolute(HInvoke * invoke)2639*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitUnsafePutAbsolute(HInvoke* invoke) {
2640*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafePutAbsolute(invoke);
2641*795d594fSAndroid Build Coastguard Worker }
2642*795d594fSAndroid Build Coastguard Worker
VisitUnsafePut(HInvoke * invoke)2643*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitUnsafePut(HInvoke* invoke) {
2644*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafePut(invoke);
2645*795d594fSAndroid Build Coastguard Worker }
2646*795d594fSAndroid Build Coastguard Worker
VisitUnsafePutAbsolute(HInvoke * invoke)2647*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitUnsafePutAbsolute(HInvoke* invoke) {
2648*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafePutAbsolute(invoke);
2649*795d594fSAndroid Build Coastguard Worker }
2650*795d594fSAndroid Build Coastguard Worker
VisitUnsafePutOrdered(HInvoke * invoke)2651*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitUnsafePutOrdered(HInvoke* invoke) {
2652*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafePutOrdered(invoke);
2653*795d594fSAndroid Build Coastguard Worker }
2654*795d594fSAndroid Build Coastguard Worker
VisitUnsafePutOrdered(HInvoke * invoke)2655*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitUnsafePutOrdered(HInvoke* invoke) {
2656*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafePutOrdered(invoke);
2657*795d594fSAndroid Build Coastguard Worker }
2658*795d594fSAndroid Build Coastguard Worker
VisitUnsafePutVolatile(HInvoke * invoke)2659*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitUnsafePutVolatile(HInvoke* invoke) {
2660*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafePutVolatile(invoke);
2661*795d594fSAndroid Build Coastguard Worker }
2662*795d594fSAndroid Build Coastguard Worker
VisitUnsafePutVolatile(HInvoke * invoke)2663*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitUnsafePutVolatile(HInvoke* invoke) {
2664*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafePutVolatile(invoke);
2665*795d594fSAndroid Build Coastguard Worker }
2666*795d594fSAndroid Build Coastguard Worker
VisitUnsafePutObject(HInvoke * invoke)2667*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitUnsafePutObject(HInvoke* invoke) {
2668*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafePutReference(invoke);
2669*795d594fSAndroid Build Coastguard Worker }
2670*795d594fSAndroid Build Coastguard Worker
VisitUnsafePutObject(HInvoke * invoke)2671*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitUnsafePutObject(HInvoke* invoke) {
2672*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafePutReference(invoke);
2673*795d594fSAndroid Build Coastguard Worker }
2674*795d594fSAndroid Build Coastguard Worker
VisitUnsafePutObjectOrdered(HInvoke * invoke)2675*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitUnsafePutObjectOrdered(HInvoke* invoke) {
2676*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafePutObjectOrdered(invoke);
2677*795d594fSAndroid Build Coastguard Worker }
2678*795d594fSAndroid Build Coastguard Worker
VisitUnsafePutObjectOrdered(HInvoke * invoke)2679*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitUnsafePutObjectOrdered(HInvoke* invoke) {
2680*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafePutObjectOrdered(invoke);
2681*795d594fSAndroid Build Coastguard Worker }
2682*795d594fSAndroid Build Coastguard Worker
VisitUnsafePutObjectVolatile(HInvoke * invoke)2683*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitUnsafePutObjectVolatile(HInvoke* invoke) {
2684*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafePutReferenceVolatile(invoke);
2685*795d594fSAndroid Build Coastguard Worker }
2686*795d594fSAndroid Build Coastguard Worker
VisitUnsafePutObjectVolatile(HInvoke * invoke)2687*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitUnsafePutObjectVolatile(HInvoke* invoke) {
2688*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafePutReferenceVolatile(invoke);
2689*795d594fSAndroid Build Coastguard Worker }
2690*795d594fSAndroid Build Coastguard Worker
VisitUnsafePutLong(HInvoke * invoke)2691*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitUnsafePutLong(HInvoke* invoke) {
2692*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafePutLong(invoke);
2693*795d594fSAndroid Build Coastguard Worker }
2694*795d594fSAndroid Build Coastguard Worker
VisitUnsafePutLong(HInvoke * invoke)2695*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitUnsafePutLong(HInvoke* invoke) {
2696*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafePutLong(invoke);
2697*795d594fSAndroid Build Coastguard Worker }
2698*795d594fSAndroid Build Coastguard Worker
VisitUnsafePutLongOrdered(HInvoke * invoke)2699*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitUnsafePutLongOrdered(HInvoke* invoke) {
2700*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafePutLongOrdered(invoke);
2701*795d594fSAndroid Build Coastguard Worker }
2702*795d594fSAndroid Build Coastguard Worker
VisitUnsafePutLongOrdered(HInvoke * invoke)2703*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitUnsafePutLongOrdered(HInvoke* invoke) {
2704*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafePutLongOrdered(invoke);
2705*795d594fSAndroid Build Coastguard Worker }
2706*795d594fSAndroid Build Coastguard Worker
VisitUnsafePutLongVolatile(HInvoke * invoke)2707*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitUnsafePutLongVolatile(HInvoke* invoke) {
2708*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafePutLongVolatile(invoke);
2709*795d594fSAndroid Build Coastguard Worker }
2710*795d594fSAndroid Build Coastguard Worker
VisitUnsafePutLongVolatile(HInvoke * invoke)2711*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitUnsafePutLongVolatile(HInvoke* invoke) {
2712*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafePutLongVolatile(invoke);
2713*795d594fSAndroid Build Coastguard Worker }
2714*795d594fSAndroid Build Coastguard Worker
VisitUnsafePutByte(HInvoke * invoke)2715*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitUnsafePutByte(HInvoke* invoke) {
2716*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafePutByte(invoke);
2717*795d594fSAndroid Build Coastguard Worker }
2718*795d594fSAndroid Build Coastguard Worker
VisitUnsafePutByte(HInvoke * invoke)2719*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitUnsafePutByte(HInvoke* invoke) {
2720*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafePutByte(invoke);
2721*795d594fSAndroid Build Coastguard Worker }
2722*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafePut(HInvoke * invoke)2723*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitJdkUnsafePut(HInvoke* invoke) {
2724*795d594fSAndroid Build Coastguard Worker CreateUnsafePutLocations(allocator_, invoke);
2725*795d594fSAndroid Build Coastguard Worker }
2726*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafePutAbsolute(HInvoke * invoke)2727*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitJdkUnsafePutAbsolute(HInvoke* invoke) {
2728*795d594fSAndroid Build Coastguard Worker CreateUnsafePutAbsoluteLocations(allocator_, invoke);
2729*795d594fSAndroid Build Coastguard Worker }
2730*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafePut(HInvoke * invoke)2731*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitJdkUnsafePut(HInvoke* invoke) {
2732*795d594fSAndroid Build Coastguard Worker GenUnsafePut(invoke, codegen_, std::memory_order_relaxed, DataType::Type::kInt32);
2733*795d594fSAndroid Build Coastguard Worker }
2734*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafePutAbsolute(HInvoke * invoke)2735*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitJdkUnsafePutAbsolute(HInvoke* invoke) {
2736*795d594fSAndroid Build Coastguard Worker GenUnsafePutAbsolute(invoke, codegen_, std::memory_order_relaxed, DataType::Type::kInt32);
2737*795d594fSAndroid Build Coastguard Worker }
2738*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafePutOrdered(HInvoke * invoke)2739*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitJdkUnsafePutOrdered(HInvoke* invoke) {
2740*795d594fSAndroid Build Coastguard Worker CreateUnsafePutLocations(allocator_, invoke);
2741*795d594fSAndroid Build Coastguard Worker }
2742*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafePutOrdered(HInvoke * invoke)2743*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitJdkUnsafePutOrdered(HInvoke* invoke) {
2744*795d594fSAndroid Build Coastguard Worker GenUnsafePut(invoke, codegen_, std::memory_order_release, DataType::Type::kInt32);
2745*795d594fSAndroid Build Coastguard Worker }
2746*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafePutRelease(HInvoke * invoke)2747*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitJdkUnsafePutRelease(HInvoke* invoke) {
2748*795d594fSAndroid Build Coastguard Worker CreateUnsafePutLocations(allocator_, invoke);
2749*795d594fSAndroid Build Coastguard Worker }
2750*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafePutRelease(HInvoke * invoke)2751*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitJdkUnsafePutRelease(HInvoke* invoke) {
2752*795d594fSAndroid Build Coastguard Worker GenUnsafePut(invoke, codegen_, std::memory_order_release, DataType::Type::kInt32);
2753*795d594fSAndroid Build Coastguard Worker }
2754*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafePutVolatile(HInvoke * invoke)2755*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitJdkUnsafePutVolatile(HInvoke* invoke) {
2756*795d594fSAndroid Build Coastguard Worker CreateUnsafePutLocations(allocator_, invoke);
2757*795d594fSAndroid Build Coastguard Worker }
2758*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafePutVolatile(HInvoke * invoke)2759*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitJdkUnsafePutVolatile(HInvoke* invoke) {
2760*795d594fSAndroid Build Coastguard Worker GenUnsafePut(invoke, codegen_, std::memory_order_seq_cst, DataType::Type::kInt32);
2761*795d594fSAndroid Build Coastguard Worker }
2762*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafePutReference(HInvoke * invoke)2763*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitJdkUnsafePutReference(HInvoke* invoke) {
2764*795d594fSAndroid Build Coastguard Worker CreateUnsafePutLocations(allocator_, invoke);
2765*795d594fSAndroid Build Coastguard Worker }
2766*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafePutReference(HInvoke * invoke)2767*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitJdkUnsafePutReference(HInvoke* invoke) {
2768*795d594fSAndroid Build Coastguard Worker GenUnsafePut(invoke, codegen_, std::memory_order_relaxed, DataType::Type::kReference);
2769*795d594fSAndroid Build Coastguard Worker }
2770*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafePutObjectOrdered(HInvoke * invoke)2771*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitJdkUnsafePutObjectOrdered(HInvoke* invoke) {
2772*795d594fSAndroid Build Coastguard Worker CreateUnsafePutLocations(allocator_, invoke);
2773*795d594fSAndroid Build Coastguard Worker }
2774*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafePutObjectOrdered(HInvoke * invoke)2775*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitJdkUnsafePutObjectOrdered(HInvoke* invoke) {
2776*795d594fSAndroid Build Coastguard Worker GenUnsafePut(invoke, codegen_, std::memory_order_release, DataType::Type::kReference);
2777*795d594fSAndroid Build Coastguard Worker }
2778*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafePutReferenceRelease(HInvoke * invoke)2779*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitJdkUnsafePutReferenceRelease(HInvoke* invoke) {
2780*795d594fSAndroid Build Coastguard Worker CreateUnsafePutLocations(allocator_, invoke);
2781*795d594fSAndroid Build Coastguard Worker }
2782*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafePutReferenceRelease(HInvoke * invoke)2783*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitJdkUnsafePutReferenceRelease(HInvoke* invoke) {
2784*795d594fSAndroid Build Coastguard Worker GenUnsafePut(invoke, codegen_, std::memory_order_release, DataType::Type::kReference);
2785*795d594fSAndroid Build Coastguard Worker }
2786*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafePutReferenceVolatile(HInvoke * invoke)2787*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitJdkUnsafePutReferenceVolatile(HInvoke* invoke) {
2788*795d594fSAndroid Build Coastguard Worker CreateUnsafePutLocations(allocator_, invoke);
2789*795d594fSAndroid Build Coastguard Worker }
2790*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafePutReferenceVolatile(HInvoke * invoke)2791*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitJdkUnsafePutReferenceVolatile(HInvoke* invoke) {
2792*795d594fSAndroid Build Coastguard Worker GenUnsafePut(invoke, codegen_, std::memory_order_seq_cst, DataType::Type::kReference);
2793*795d594fSAndroid Build Coastguard Worker }
2794*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafePutLong(HInvoke * invoke)2795*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitJdkUnsafePutLong(HInvoke* invoke) {
2796*795d594fSAndroid Build Coastguard Worker CreateUnsafePutLocations(allocator_, invoke);
2797*795d594fSAndroid Build Coastguard Worker }
2798*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafePutLong(HInvoke * invoke)2799*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitJdkUnsafePutLong(HInvoke* invoke) {
2800*795d594fSAndroid Build Coastguard Worker GenUnsafePut(invoke, codegen_, std::memory_order_relaxed, DataType::Type::kInt64);
2801*795d594fSAndroid Build Coastguard Worker }
2802*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafePutLongOrdered(HInvoke * invoke)2803*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitJdkUnsafePutLongOrdered(HInvoke* invoke) {
2804*795d594fSAndroid Build Coastguard Worker CreateUnsafePutLocations(allocator_, invoke);
2805*795d594fSAndroid Build Coastguard Worker }
2806*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafePutLongOrdered(HInvoke * invoke)2807*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitJdkUnsafePutLongOrdered(HInvoke* invoke) {
2808*795d594fSAndroid Build Coastguard Worker GenUnsafePut(invoke, codegen_, std::memory_order_release, DataType::Type::kInt64);
2809*795d594fSAndroid Build Coastguard Worker }
2810*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafePutLongRelease(HInvoke * invoke)2811*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitJdkUnsafePutLongRelease(HInvoke* invoke) {
2812*795d594fSAndroid Build Coastguard Worker CreateUnsafePutLocations(allocator_, invoke);
2813*795d594fSAndroid Build Coastguard Worker }
2814*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafePutLongRelease(HInvoke * invoke)2815*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitJdkUnsafePutLongRelease(HInvoke* invoke) {
2816*795d594fSAndroid Build Coastguard Worker GenUnsafePut(invoke, codegen_, std::memory_order_release, DataType::Type::kInt64);
2817*795d594fSAndroid Build Coastguard Worker }
2818*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafePutLongVolatile(HInvoke * invoke)2819*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitJdkUnsafePutLongVolatile(HInvoke* invoke) {
2820*795d594fSAndroid Build Coastguard Worker CreateUnsafePutLocations(allocator_, invoke);
2821*795d594fSAndroid Build Coastguard Worker }
2822*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafePutLongVolatile(HInvoke * invoke)2823*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitJdkUnsafePutLongVolatile(HInvoke* invoke) {
2824*795d594fSAndroid Build Coastguard Worker GenUnsafePut(invoke, codegen_, std::memory_order_seq_cst, DataType::Type::kInt64);
2825*795d594fSAndroid Build Coastguard Worker }
2826*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafePutByte(HInvoke * invoke)2827*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitJdkUnsafePutByte(HInvoke* invoke) {
2828*795d594fSAndroid Build Coastguard Worker CreateUnsafePutLocations(allocator_, invoke);
2829*795d594fSAndroid Build Coastguard Worker }
2830*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafePutByte(HInvoke * invoke)2831*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitJdkUnsafePutByte(HInvoke* invoke) {
2832*795d594fSAndroid Build Coastguard Worker GenUnsafePut(invoke, codegen_, std::memory_order_relaxed, DataType::Type::kInt8);
2833*795d594fSAndroid Build Coastguard Worker }
2834*795d594fSAndroid Build Coastguard Worker
CreateUnsafeCASLocations(ArenaAllocator * allocator,HInvoke * invoke,CodeGeneratorRISCV64 * codegen)2835*795d594fSAndroid Build Coastguard Worker static void CreateUnsafeCASLocations(ArenaAllocator* allocator,
2836*795d594fSAndroid Build Coastguard Worker HInvoke* invoke,
2837*795d594fSAndroid Build Coastguard Worker CodeGeneratorRISCV64* codegen) {
2838*795d594fSAndroid Build Coastguard Worker const bool can_call = codegen->EmitReadBarrier() && IsUnsafeCASReference(invoke);
2839*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = new (allocator) LocationSummary(
2840*795d594fSAndroid Build Coastguard Worker invoke,
2841*795d594fSAndroid Build Coastguard Worker can_call ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall,
2842*795d594fSAndroid Build Coastguard Worker kIntrinsified);
2843*795d594fSAndroid Build Coastguard Worker if (can_call && kUseBakerReadBarrier) {
2844*795d594fSAndroid Build Coastguard Worker locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
2845*795d594fSAndroid Build Coastguard Worker }
2846*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::NoLocation()); // Unused receiver.
2847*795d594fSAndroid Build Coastguard Worker locations->SetInAt(1, Location::RequiresRegister());
2848*795d594fSAndroid Build Coastguard Worker locations->SetInAt(2, Location::RequiresRegister());
2849*795d594fSAndroid Build Coastguard Worker locations->SetInAt(3, Location::RequiresRegister());
2850*795d594fSAndroid Build Coastguard Worker locations->SetInAt(4, Location::RequiresRegister());
2851*795d594fSAndroid Build Coastguard Worker
2852*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresRegister());
2853*795d594fSAndroid Build Coastguard Worker }
2854*795d594fSAndroid Build Coastguard Worker
GenUnsafeCas(HInvoke * invoke,CodeGeneratorRISCV64 * codegen,DataType::Type type)2855*795d594fSAndroid Build Coastguard Worker static void GenUnsafeCas(HInvoke* invoke, CodeGeneratorRISCV64* codegen, DataType::Type type) {
2856*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = codegen->GetAssembler();
2857*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = invoke->GetLocations();
2858*795d594fSAndroid Build Coastguard Worker XRegister out = locations->Out().AsRegister<XRegister>(); // Boolean result.
2859*795d594fSAndroid Build Coastguard Worker XRegister object = locations->InAt(1).AsRegister<XRegister>(); // Object pointer.
2860*795d594fSAndroid Build Coastguard Worker XRegister offset = locations->InAt(2).AsRegister<XRegister>(); // Long offset.
2861*795d594fSAndroid Build Coastguard Worker XRegister expected = locations->InAt(3).AsRegister<XRegister>(); // Expected.
2862*795d594fSAndroid Build Coastguard Worker XRegister new_value = locations->InAt(4).AsRegister<XRegister>(); // New value.
2863*795d594fSAndroid Build Coastguard Worker
2864*795d594fSAndroid Build Coastguard Worker // This needs to be before the temp registers, as MarkGCCard also uses scratch registers.
2865*795d594fSAndroid Build Coastguard Worker if (type == DataType::Type::kReference) {
2866*795d594fSAndroid Build Coastguard Worker // Mark card for object assuming new value is stored.
2867*795d594fSAndroid Build Coastguard Worker bool new_value_can_be_null = true; // TODO: Worth finding out this information?
2868*795d594fSAndroid Build Coastguard Worker codegen->MaybeMarkGCCard(object, new_value, new_value_can_be_null);
2869*795d594fSAndroid Build Coastguard Worker }
2870*795d594fSAndroid Build Coastguard Worker
2871*795d594fSAndroid Build Coastguard Worker ScratchRegisterScope srs(assembler);
2872*795d594fSAndroid Build Coastguard Worker XRegister tmp_ptr = srs.AllocateXRegister(); // Pointer to actual memory.
2873*795d594fSAndroid Build Coastguard Worker XRegister old_value; // Value in memory.
2874*795d594fSAndroid Build Coastguard Worker
2875*795d594fSAndroid Build Coastguard Worker Riscv64Label exit_loop_label;
2876*795d594fSAndroid Build Coastguard Worker Riscv64Label* exit_loop = &exit_loop_label;
2877*795d594fSAndroid Build Coastguard Worker Riscv64Label* cmp_failure = &exit_loop_label;
2878*795d594fSAndroid Build Coastguard Worker
2879*795d594fSAndroid Build Coastguard Worker ReadBarrierCasSlowPathRISCV64* slow_path = nullptr;
2880*795d594fSAndroid Build Coastguard Worker if (type == DataType::Type::kReference && codegen->EmitReadBarrier()) {
2881*795d594fSAndroid Build Coastguard Worker // We need to store the `old_value` in a non-scratch register to make sure
2882*795d594fSAndroid Build Coastguard Worker // the read barrier in the slow path does not clobber it.
2883*795d594fSAndroid Build Coastguard Worker old_value = locations->GetTemp(0).AsRegister<XRegister>(); // The old value from main path.
2884*795d594fSAndroid Build Coastguard Worker // The `old_value_temp` is used first for marking the `old_value` and then for the unmarked
2885*795d594fSAndroid Build Coastguard Worker // reloaded old value for subsequent CAS in the slow path. We make this a scratch register
2886*795d594fSAndroid Build Coastguard Worker // as we do have marking entrypoints on riscv64 even for scratch registers.
2887*795d594fSAndroid Build Coastguard Worker XRegister old_value_temp = srs.AllocateXRegister();
2888*795d594fSAndroid Build Coastguard Worker slow_path = new (codegen->GetScopedAllocator()) ReadBarrierCasSlowPathRISCV64(
2889*795d594fSAndroid Build Coastguard Worker invoke,
2890*795d594fSAndroid Build Coastguard Worker std::memory_order_seq_cst,
2891*795d594fSAndroid Build Coastguard Worker /*strong=*/ true,
2892*795d594fSAndroid Build Coastguard Worker object,
2893*795d594fSAndroid Build Coastguard Worker offset,
2894*795d594fSAndroid Build Coastguard Worker expected,
2895*795d594fSAndroid Build Coastguard Worker new_value,
2896*795d594fSAndroid Build Coastguard Worker old_value,
2897*795d594fSAndroid Build Coastguard Worker old_value_temp,
2898*795d594fSAndroid Build Coastguard Worker /*store_result=*/ old_value_temp, // Let the SC result clobber the reloaded old_value.
2899*795d594fSAndroid Build Coastguard Worker /*update_old_value=*/ false,
2900*795d594fSAndroid Build Coastguard Worker codegen);
2901*795d594fSAndroid Build Coastguard Worker codegen->AddSlowPath(slow_path);
2902*795d594fSAndroid Build Coastguard Worker exit_loop = slow_path->GetExitLabel();
2903*795d594fSAndroid Build Coastguard Worker cmp_failure = slow_path->GetEntryLabel();
2904*795d594fSAndroid Build Coastguard Worker } else {
2905*795d594fSAndroid Build Coastguard Worker old_value = srs.AllocateXRegister();
2906*795d594fSAndroid Build Coastguard Worker }
2907*795d594fSAndroid Build Coastguard Worker
2908*795d594fSAndroid Build Coastguard Worker __ Add(tmp_ptr, object, offset);
2909*795d594fSAndroid Build Coastguard Worker
2910*795d594fSAndroid Build Coastguard Worker // Pre-populate the result register with failure.
2911*795d594fSAndroid Build Coastguard Worker __ Li(out, 0);
2912*795d594fSAndroid Build Coastguard Worker
2913*795d594fSAndroid Build Coastguard Worker GenerateCompareAndSet(assembler,
2914*795d594fSAndroid Build Coastguard Worker type,
2915*795d594fSAndroid Build Coastguard Worker std::memory_order_seq_cst,
2916*795d594fSAndroid Build Coastguard Worker /*strong=*/ true,
2917*795d594fSAndroid Build Coastguard Worker cmp_failure,
2918*795d594fSAndroid Build Coastguard Worker tmp_ptr,
2919*795d594fSAndroid Build Coastguard Worker new_value,
2920*795d594fSAndroid Build Coastguard Worker old_value,
2921*795d594fSAndroid Build Coastguard Worker /*mask=*/ kNoXRegister,
2922*795d594fSAndroid Build Coastguard Worker /*masked=*/ kNoXRegister,
2923*795d594fSAndroid Build Coastguard Worker /*store_result=*/ old_value, // Let the SC result clobber the `old_value`.
2924*795d594fSAndroid Build Coastguard Worker expected);
2925*795d594fSAndroid Build Coastguard Worker
2926*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(slow_path != nullptr, type == DataType::Type::kReference && codegen->EmitReadBarrier());
2927*795d594fSAndroid Build Coastguard Worker if (slow_path != nullptr) {
2928*795d594fSAndroid Build Coastguard Worker __ Bind(slow_path->GetSuccessExitLabel());
2929*795d594fSAndroid Build Coastguard Worker }
2930*795d594fSAndroid Build Coastguard Worker
2931*795d594fSAndroid Build Coastguard Worker // Indicate success if we successfully execute the SC.
2932*795d594fSAndroid Build Coastguard Worker __ Li(out, 1);
2933*795d594fSAndroid Build Coastguard Worker
2934*795d594fSAndroid Build Coastguard Worker __ Bind(exit_loop);
2935*795d594fSAndroid Build Coastguard Worker }
2936*795d594fSAndroid Build Coastguard Worker
VisitUnsafeCASInt(HInvoke * invoke)2937*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitUnsafeCASInt(HInvoke* invoke) {
2938*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafeCASInt(invoke);
2939*795d594fSAndroid Build Coastguard Worker }
2940*795d594fSAndroid Build Coastguard Worker
VisitUnsafeCASInt(HInvoke * invoke)2941*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitUnsafeCASInt(HInvoke* invoke) {
2942*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafeCASInt(invoke);
2943*795d594fSAndroid Build Coastguard Worker }
2944*795d594fSAndroid Build Coastguard Worker
VisitUnsafeCASLong(HInvoke * invoke)2945*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitUnsafeCASLong(HInvoke* invoke) {
2946*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafeCASLong(invoke);
2947*795d594fSAndroid Build Coastguard Worker }
2948*795d594fSAndroid Build Coastguard Worker
VisitUnsafeCASLong(HInvoke * invoke)2949*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitUnsafeCASLong(HInvoke* invoke) {
2950*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafeCASLong(invoke);
2951*795d594fSAndroid Build Coastguard Worker }
2952*795d594fSAndroid Build Coastguard Worker
VisitUnsafeCASObject(HInvoke * invoke)2953*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitUnsafeCASObject(HInvoke* invoke) {
2954*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafeCASObject(invoke);
2955*795d594fSAndroid Build Coastguard Worker }
2956*795d594fSAndroid Build Coastguard Worker
VisitUnsafeCASObject(HInvoke * invoke)2957*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitUnsafeCASObject(HInvoke* invoke) {
2958*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafeCASObject(invoke);
2959*795d594fSAndroid Build Coastguard Worker }
2960*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafeCASInt(HInvoke * invoke)2961*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitJdkUnsafeCASInt(HInvoke* invoke) {
2962*795d594fSAndroid Build Coastguard Worker // `jdk.internal.misc.Unsafe.compareAndSwapInt` has compare-and-set semantics (see javadoc).
2963*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafeCompareAndSetInt(invoke);
2964*795d594fSAndroid Build Coastguard Worker }
2965*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafeCASInt(HInvoke * invoke)2966*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitJdkUnsafeCASInt(HInvoke* invoke) {
2967*795d594fSAndroid Build Coastguard Worker // `jdk.internal.misc.Unsafe.compareAndSwapInt` has compare-and-set semantics (see javadoc).
2968*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafeCompareAndSetInt(invoke);
2969*795d594fSAndroid Build Coastguard Worker }
2970*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafeCASLong(HInvoke * invoke)2971*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitJdkUnsafeCASLong(HInvoke* invoke) {
2972*795d594fSAndroid Build Coastguard Worker // `jdk.internal.misc.Unsafe.compareAndSwapLong` has compare-and-set semantics (see javadoc).
2973*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafeCompareAndSetLong(invoke);
2974*795d594fSAndroid Build Coastguard Worker }
2975*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafeCASLong(HInvoke * invoke)2976*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitJdkUnsafeCASLong(HInvoke* invoke) {
2977*795d594fSAndroid Build Coastguard Worker // `jdk.internal.misc.Unsafe.compareAndSwapLong` has compare-and-set semantics (see javadoc).
2978*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafeCompareAndSetLong(invoke);
2979*795d594fSAndroid Build Coastguard Worker }
2980*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafeCASObject(HInvoke * invoke)2981*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitJdkUnsafeCASObject(HInvoke* invoke) {
2982*795d594fSAndroid Build Coastguard Worker // `jdk.internal.misc.Unsafe.compareAndSwapObject` has compare-and-set semantics (see javadoc).
2983*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafeCompareAndSetReference(invoke);
2984*795d594fSAndroid Build Coastguard Worker }
2985*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafeCASObject(HInvoke * invoke)2986*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitJdkUnsafeCASObject(HInvoke* invoke) {
2987*795d594fSAndroid Build Coastguard Worker // `jdk.internal.misc.Unsafe.compareAndSwapObject` has compare-and-set semantics (see javadoc).
2988*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafeCompareAndSetReference(invoke);
2989*795d594fSAndroid Build Coastguard Worker }
2990*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafeCompareAndSetInt(HInvoke * invoke)2991*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitJdkUnsafeCompareAndSetInt(HInvoke* invoke) {
2992*795d594fSAndroid Build Coastguard Worker CreateUnsafeCASLocations(allocator_, invoke, codegen_);
2993*795d594fSAndroid Build Coastguard Worker }
2994*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafeCompareAndSetInt(HInvoke * invoke)2995*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitJdkUnsafeCompareAndSetInt(HInvoke* invoke) {
2996*795d594fSAndroid Build Coastguard Worker GenUnsafeCas(invoke, codegen_, DataType::Type::kInt32);
2997*795d594fSAndroid Build Coastguard Worker }
2998*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafeCompareAndSetLong(HInvoke * invoke)2999*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitJdkUnsafeCompareAndSetLong(HInvoke* invoke) {
3000*795d594fSAndroid Build Coastguard Worker CreateUnsafeCASLocations(allocator_, invoke, codegen_);
3001*795d594fSAndroid Build Coastguard Worker }
3002*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafeCompareAndSetLong(HInvoke * invoke)3003*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitJdkUnsafeCompareAndSetLong(HInvoke* invoke) {
3004*795d594fSAndroid Build Coastguard Worker GenUnsafeCas(invoke, codegen_, DataType::Type::kInt64);
3005*795d594fSAndroid Build Coastguard Worker }
3006*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafeCompareAndSetReference(HInvoke * invoke)3007*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitJdkUnsafeCompareAndSetReference(HInvoke* invoke) {
3008*795d594fSAndroid Build Coastguard Worker // The only supported read barrier implementation is the Baker-style read barriers.
3009*795d594fSAndroid Build Coastguard Worker if (codegen_->EmitNonBakerReadBarrier()) {
3010*795d594fSAndroid Build Coastguard Worker return;
3011*795d594fSAndroid Build Coastguard Worker }
3012*795d594fSAndroid Build Coastguard Worker
3013*795d594fSAndroid Build Coastguard Worker // TODO(riscv64): Fix this intrinsic for heap poisoning configuration.
3014*795d594fSAndroid Build Coastguard Worker if (kPoisonHeapReferences) {
3015*795d594fSAndroid Build Coastguard Worker return;
3016*795d594fSAndroid Build Coastguard Worker }
3017*795d594fSAndroid Build Coastguard Worker
3018*795d594fSAndroid Build Coastguard Worker CreateUnsafeCASLocations(allocator_, invoke, codegen_);
3019*795d594fSAndroid Build Coastguard Worker if (codegen_->EmitReadBarrier()) {
3020*795d594fSAndroid Build Coastguard Worker DCHECK(kUseBakerReadBarrier);
3021*795d594fSAndroid Build Coastguard Worker // We need one non-scratch temporary register for read barrier.
3022*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = invoke->GetLocations();
3023*795d594fSAndroid Build Coastguard Worker locations->AddTemp(Location::RequiresRegister());
3024*795d594fSAndroid Build Coastguard Worker }
3025*795d594fSAndroid Build Coastguard Worker }
3026*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafeCompareAndSetReference(HInvoke * invoke)3027*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitJdkUnsafeCompareAndSetReference(HInvoke* invoke) {
3028*795d594fSAndroid Build Coastguard Worker GenUnsafeCas(invoke, codegen_, DataType::Type::kReference);
3029*795d594fSAndroid Build Coastguard Worker }
3030*795d594fSAndroid Build Coastguard Worker
CreateUnsafeGetAndUpdateLocations(ArenaAllocator * allocator,HInvoke * invoke,CodeGeneratorRISCV64 * codegen)3031*795d594fSAndroid Build Coastguard Worker static void CreateUnsafeGetAndUpdateLocations(ArenaAllocator* allocator,
3032*795d594fSAndroid Build Coastguard Worker HInvoke* invoke,
3033*795d594fSAndroid Build Coastguard Worker CodeGeneratorRISCV64* codegen) {
3034*795d594fSAndroid Build Coastguard Worker const bool can_call = codegen->EmitReadBarrier() && IsUnsafeGetAndSetReference(invoke);
3035*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = new (allocator) LocationSummary(
3036*795d594fSAndroid Build Coastguard Worker invoke,
3037*795d594fSAndroid Build Coastguard Worker can_call ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall,
3038*795d594fSAndroid Build Coastguard Worker kIntrinsified);
3039*795d594fSAndroid Build Coastguard Worker if (can_call && kUseBakerReadBarrier) {
3040*795d594fSAndroid Build Coastguard Worker locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
3041*795d594fSAndroid Build Coastguard Worker }
3042*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::NoLocation()); // Unused receiver.
3043*795d594fSAndroid Build Coastguard Worker locations->SetInAt(1, Location::RequiresRegister());
3044*795d594fSAndroid Build Coastguard Worker locations->SetInAt(2, Location::RequiresRegister());
3045*795d594fSAndroid Build Coastguard Worker locations->SetInAt(3, Location::RequiresRegister());
3046*795d594fSAndroid Build Coastguard Worker
3047*795d594fSAndroid Build Coastguard Worker // Request another temporary register for methods that don't return a value.
3048*795d594fSAndroid Build Coastguard Worker DataType::Type return_type = invoke->GetType();
3049*795d594fSAndroid Build Coastguard Worker const bool is_void = return_type == DataType::Type::kVoid;
3050*795d594fSAndroid Build Coastguard Worker if (is_void) {
3051*795d594fSAndroid Build Coastguard Worker locations->AddTemp(Location::RequiresRegister());
3052*795d594fSAndroid Build Coastguard Worker } else {
3053*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3054*795d594fSAndroid Build Coastguard Worker }
3055*795d594fSAndroid Build Coastguard Worker }
3056*795d594fSAndroid Build Coastguard Worker
GenUnsafeGetAndUpdate(HInvoke * invoke,DataType::Type type,CodeGeneratorRISCV64 * codegen,GetAndUpdateOp get_and_update_op)3057*795d594fSAndroid Build Coastguard Worker static void GenUnsafeGetAndUpdate(HInvoke* invoke,
3058*795d594fSAndroid Build Coastguard Worker DataType::Type type,
3059*795d594fSAndroid Build Coastguard Worker CodeGeneratorRISCV64* codegen,
3060*795d594fSAndroid Build Coastguard Worker GetAndUpdateOp get_and_update_op) {
3061*795d594fSAndroid Build Coastguard Worker // Currently only used for these GetAndUpdateOp. Might be fine for other ops but double check
3062*795d594fSAndroid Build Coastguard Worker // before using.
3063*795d594fSAndroid Build Coastguard Worker DCHECK(get_and_update_op == GetAndUpdateOp::kAdd || get_and_update_op == GetAndUpdateOp::kSet);
3064*795d594fSAndroid Build Coastguard Worker
3065*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = codegen->GetAssembler();
3066*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = invoke->GetLocations();
3067*795d594fSAndroid Build Coastguard Worker DataType::Type return_type = invoke->GetType();
3068*795d594fSAndroid Build Coastguard Worker const bool is_void = return_type == DataType::Type::kVoid;
3069*795d594fSAndroid Build Coastguard Worker // We use a temporary for void methods, as we don't return the value.
3070*795d594fSAndroid Build Coastguard Worker Location out_or_temp_loc =
3071*795d594fSAndroid Build Coastguard Worker is_void ? locations->GetTemp(locations->GetTempCount() - 1u) : locations->Out();
3072*795d594fSAndroid Build Coastguard Worker XRegister out_or_temp = out_or_temp_loc.AsRegister<XRegister>(); // Result.
3073*795d594fSAndroid Build Coastguard Worker XRegister base = locations->InAt(1).AsRegister<XRegister>(); // Object pointer.
3074*795d594fSAndroid Build Coastguard Worker XRegister offset = locations->InAt(2).AsRegister<XRegister>(); // Long offset.
3075*795d594fSAndroid Build Coastguard Worker XRegister arg = locations->InAt(3).AsRegister<XRegister>(); // New value or addend.
3076*795d594fSAndroid Build Coastguard Worker
3077*795d594fSAndroid Build Coastguard Worker // This needs to be before the temp registers, as MarkGCCard also uses scratch registers.
3078*795d594fSAndroid Build Coastguard Worker if (type == DataType::Type::kReference) {
3079*795d594fSAndroid Build Coastguard Worker DCHECK(get_and_update_op == GetAndUpdateOp::kSet);
3080*795d594fSAndroid Build Coastguard Worker // Mark card for object as a new value shall be stored.
3081*795d594fSAndroid Build Coastguard Worker bool new_value_can_be_null = true; // TODO: Worth finding out this information?
3082*795d594fSAndroid Build Coastguard Worker codegen->MaybeMarkGCCard(base, /*value=*/arg, new_value_can_be_null);
3083*795d594fSAndroid Build Coastguard Worker }
3084*795d594fSAndroid Build Coastguard Worker
3085*795d594fSAndroid Build Coastguard Worker ScratchRegisterScope srs(assembler);
3086*795d594fSAndroid Build Coastguard Worker XRegister tmp_ptr = srs.AllocateXRegister(); // Pointer to actual memory.
3087*795d594fSAndroid Build Coastguard Worker __ Add(tmp_ptr, base, offset);
3088*795d594fSAndroid Build Coastguard Worker GenerateGetAndUpdate(codegen,
3089*795d594fSAndroid Build Coastguard Worker get_and_update_op,
3090*795d594fSAndroid Build Coastguard Worker (type == DataType::Type::kReference) ? DataType::Type::kInt32 : type,
3091*795d594fSAndroid Build Coastguard Worker std::memory_order_seq_cst,
3092*795d594fSAndroid Build Coastguard Worker tmp_ptr,
3093*795d594fSAndroid Build Coastguard Worker arg,
3094*795d594fSAndroid Build Coastguard Worker /*old_value=*/ out_or_temp,
3095*795d594fSAndroid Build Coastguard Worker /*mask=*/ kNoXRegister,
3096*795d594fSAndroid Build Coastguard Worker /*temp=*/ kNoXRegister);
3097*795d594fSAndroid Build Coastguard Worker
3098*795d594fSAndroid Build Coastguard Worker if (!is_void && type == DataType::Type::kReference) {
3099*795d594fSAndroid Build Coastguard Worker __ ZextW(out_or_temp, out_or_temp);
3100*795d594fSAndroid Build Coastguard Worker if (codegen->EmitReadBarrier()) {
3101*795d594fSAndroid Build Coastguard Worker DCHECK(get_and_update_op == GetAndUpdateOp::kSet);
3102*795d594fSAndroid Build Coastguard Worker if (kUseBakerReadBarrier) {
3103*795d594fSAndroid Build Coastguard Worker // Use RA as temp. It is clobbered in the slow path anyway.
3104*795d594fSAndroid Build Coastguard Worker static constexpr Location kBakerReadBarrierTemp = Location::RegisterLocation(RA);
3105*795d594fSAndroid Build Coastguard Worker SlowPathCodeRISCV64* rb_slow_path = codegen->AddGcRootBakerBarrierBarrierSlowPath(
3106*795d594fSAndroid Build Coastguard Worker invoke, out_or_temp_loc, kBakerReadBarrierTemp);
3107*795d594fSAndroid Build Coastguard Worker codegen->EmitBakerReadBarierMarkingCheck(
3108*795d594fSAndroid Build Coastguard Worker rb_slow_path, out_or_temp_loc, kBakerReadBarrierTemp);
3109*795d594fSAndroid Build Coastguard Worker } else {
3110*795d594fSAndroid Build Coastguard Worker codegen->GenerateReadBarrierSlow(invoke,
3111*795d594fSAndroid Build Coastguard Worker out_or_temp_loc,
3112*795d594fSAndroid Build Coastguard Worker out_or_temp_loc,
3113*795d594fSAndroid Build Coastguard Worker Location::RegisterLocation(base),
3114*795d594fSAndroid Build Coastguard Worker /*offset=*/ 0u,
3115*795d594fSAndroid Build Coastguard Worker /*index=*/ Location::RegisterLocation(offset));
3116*795d594fSAndroid Build Coastguard Worker }
3117*795d594fSAndroid Build Coastguard Worker }
3118*795d594fSAndroid Build Coastguard Worker }
3119*795d594fSAndroid Build Coastguard Worker }
3120*795d594fSAndroid Build Coastguard Worker
VisitUnsafeGetAndAddInt(HInvoke * invoke)3121*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitUnsafeGetAndAddInt(HInvoke* invoke) {
3122*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafeGetAndAddInt(invoke);
3123*795d594fSAndroid Build Coastguard Worker }
3124*795d594fSAndroid Build Coastguard Worker
VisitUnsafeGetAndAddInt(HInvoke * invoke)3125*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitUnsafeGetAndAddInt(HInvoke* invoke) {
3126*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafeGetAndAddInt(invoke);
3127*795d594fSAndroid Build Coastguard Worker }
3128*795d594fSAndroid Build Coastguard Worker
VisitUnsafeGetAndAddLong(HInvoke * invoke)3129*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitUnsafeGetAndAddLong(HInvoke* invoke) {
3130*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafeGetAndAddLong(invoke);
3131*795d594fSAndroid Build Coastguard Worker }
3132*795d594fSAndroid Build Coastguard Worker
VisitUnsafeGetAndAddLong(HInvoke * invoke)3133*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitUnsafeGetAndAddLong(HInvoke* invoke) {
3134*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafeGetAndAddLong(invoke);
3135*795d594fSAndroid Build Coastguard Worker }
3136*795d594fSAndroid Build Coastguard Worker
VisitUnsafeGetAndSetInt(HInvoke * invoke)3137*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitUnsafeGetAndSetInt(HInvoke* invoke) {
3138*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafeGetAndSetInt(invoke);
3139*795d594fSAndroid Build Coastguard Worker }
3140*795d594fSAndroid Build Coastguard Worker
VisitUnsafeGetAndSetInt(HInvoke * invoke)3141*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitUnsafeGetAndSetInt(HInvoke* invoke) {
3142*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafeGetAndSetInt(invoke);
3143*795d594fSAndroid Build Coastguard Worker }
3144*795d594fSAndroid Build Coastguard Worker
VisitUnsafeGetAndSetLong(HInvoke * invoke)3145*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitUnsafeGetAndSetLong(HInvoke* invoke) {
3146*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafeGetAndSetLong(invoke);
3147*795d594fSAndroid Build Coastguard Worker }
3148*795d594fSAndroid Build Coastguard Worker
VisitUnsafeGetAndSetLong(HInvoke * invoke)3149*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitUnsafeGetAndSetLong(HInvoke* invoke) {
3150*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafeGetAndSetLong(invoke);
3151*795d594fSAndroid Build Coastguard Worker }
3152*795d594fSAndroid Build Coastguard Worker
VisitUnsafeGetAndSetObject(HInvoke * invoke)3153*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitUnsafeGetAndSetObject(HInvoke* invoke) {
3154*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafeGetAndSetReference(invoke);
3155*795d594fSAndroid Build Coastguard Worker }
3156*795d594fSAndroid Build Coastguard Worker
VisitUnsafeGetAndSetObject(HInvoke * invoke)3157*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitUnsafeGetAndSetObject(HInvoke* invoke) {
3158*795d594fSAndroid Build Coastguard Worker VisitJdkUnsafeGetAndSetReference(invoke);
3159*795d594fSAndroid Build Coastguard Worker }
3160*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafeGetAndAddInt(HInvoke * invoke)3161*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitJdkUnsafeGetAndAddInt(HInvoke* invoke) {
3162*795d594fSAndroid Build Coastguard Worker CreateUnsafeGetAndUpdateLocations(allocator_, invoke, codegen_);
3163*795d594fSAndroid Build Coastguard Worker }
3164*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafeGetAndAddInt(HInvoke * invoke)3165*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitJdkUnsafeGetAndAddInt(HInvoke* invoke) {
3166*795d594fSAndroid Build Coastguard Worker GenUnsafeGetAndUpdate(invoke, DataType::Type::kInt32, codegen_, GetAndUpdateOp::kAdd);
3167*795d594fSAndroid Build Coastguard Worker }
3168*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafeGetAndAddLong(HInvoke * invoke)3169*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitJdkUnsafeGetAndAddLong(HInvoke* invoke) {
3170*795d594fSAndroid Build Coastguard Worker CreateUnsafeGetAndUpdateLocations(allocator_, invoke, codegen_);
3171*795d594fSAndroid Build Coastguard Worker }
3172*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafeGetAndAddLong(HInvoke * invoke)3173*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitJdkUnsafeGetAndAddLong(HInvoke* invoke) {
3174*795d594fSAndroid Build Coastguard Worker GenUnsafeGetAndUpdate(invoke, DataType::Type::kInt64, codegen_, GetAndUpdateOp::kAdd);
3175*795d594fSAndroid Build Coastguard Worker }
3176*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafeGetAndSetInt(HInvoke * invoke)3177*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitJdkUnsafeGetAndSetInt(HInvoke* invoke) {
3178*795d594fSAndroid Build Coastguard Worker CreateUnsafeGetAndUpdateLocations(allocator_, invoke, codegen_);
3179*795d594fSAndroid Build Coastguard Worker }
3180*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafeGetAndSetInt(HInvoke * invoke)3181*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitJdkUnsafeGetAndSetInt(HInvoke* invoke) {
3182*795d594fSAndroid Build Coastguard Worker GenUnsafeGetAndUpdate(invoke, DataType::Type::kInt32, codegen_, GetAndUpdateOp::kSet);
3183*795d594fSAndroid Build Coastguard Worker }
3184*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafeGetAndSetLong(HInvoke * invoke)3185*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitJdkUnsafeGetAndSetLong(HInvoke* invoke) {
3186*795d594fSAndroid Build Coastguard Worker CreateUnsafeGetAndUpdateLocations(allocator_, invoke, codegen_);
3187*795d594fSAndroid Build Coastguard Worker }
3188*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafeGetAndSetLong(HInvoke * invoke)3189*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitJdkUnsafeGetAndSetLong(HInvoke* invoke) {
3190*795d594fSAndroid Build Coastguard Worker GenUnsafeGetAndUpdate(invoke, DataType::Type::kInt64, codegen_, GetAndUpdateOp::kSet);
3191*795d594fSAndroid Build Coastguard Worker }
3192*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafeGetAndSetReference(HInvoke * invoke)3193*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitJdkUnsafeGetAndSetReference(HInvoke* invoke) {
3194*795d594fSAndroid Build Coastguard Worker // TODO(riscv64): Fix this intrinsic for heap poisoning configuration.
3195*795d594fSAndroid Build Coastguard Worker if (kPoisonHeapReferences) {
3196*795d594fSAndroid Build Coastguard Worker return;
3197*795d594fSAndroid Build Coastguard Worker }
3198*795d594fSAndroid Build Coastguard Worker
3199*795d594fSAndroid Build Coastguard Worker CreateUnsafeGetAndUpdateLocations(allocator_, invoke, codegen_);
3200*795d594fSAndroid Build Coastguard Worker }
3201*795d594fSAndroid Build Coastguard Worker
VisitJdkUnsafeGetAndSetReference(HInvoke * invoke)3202*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitJdkUnsafeGetAndSetReference(HInvoke* invoke) {
3203*795d594fSAndroid Build Coastguard Worker GenUnsafeGetAndUpdate(invoke, DataType::Type::kReference, codegen_, GetAndUpdateOp::kSet);
3204*795d594fSAndroid Build Coastguard Worker }
3205*795d594fSAndroid Build Coastguard Worker
VisitStringCompareTo(HInvoke * invoke)3206*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitStringCompareTo(HInvoke* invoke) {
3207*795d594fSAndroid Build Coastguard Worker LocationSummary* locations =
3208*795d594fSAndroid Build Coastguard Worker new (allocator_) LocationSummary(invoke,
3209*795d594fSAndroid Build Coastguard Worker invoke->InputAt(1)->CanBeNull()
3210*795d594fSAndroid Build Coastguard Worker ? LocationSummary::kCallOnSlowPath
3211*795d594fSAndroid Build Coastguard Worker : LocationSummary::kNoCall,
3212*795d594fSAndroid Build Coastguard Worker kIntrinsified);
3213*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresRegister());
3214*795d594fSAndroid Build Coastguard Worker locations->SetInAt(1, Location::RequiresRegister());
3215*795d594fSAndroid Build Coastguard Worker locations->AddRegisterTemps(3);
3216*795d594fSAndroid Build Coastguard Worker // Need temporary registers for String compression's feature.
3217*795d594fSAndroid Build Coastguard Worker if (mirror::kUseStringCompression) {
3218*795d594fSAndroid Build Coastguard Worker locations->AddTemp(Location::RequiresRegister());
3219*795d594fSAndroid Build Coastguard Worker }
3220*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3221*795d594fSAndroid Build Coastguard Worker }
3222*795d594fSAndroid Build Coastguard Worker
VisitStringCompareTo(HInvoke * invoke)3223*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitStringCompareTo(HInvoke* invoke) {
3224*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = GetAssembler();
3225*795d594fSAndroid Build Coastguard Worker DCHECK(assembler->IsExtensionEnabled(Riscv64Extension::kZbb));
3226*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = invoke->GetLocations();
3227*795d594fSAndroid Build Coastguard Worker
3228*795d594fSAndroid Build Coastguard Worker XRegister str = locations->InAt(0).AsRegister<XRegister>();
3229*795d594fSAndroid Build Coastguard Worker XRegister arg = locations->InAt(1).AsRegister<XRegister>();
3230*795d594fSAndroid Build Coastguard Worker XRegister out = locations->Out().AsRegister<XRegister>();
3231*795d594fSAndroid Build Coastguard Worker
3232*795d594fSAndroid Build Coastguard Worker XRegister temp0 = locations->GetTemp(0).AsRegister<XRegister>();
3233*795d594fSAndroid Build Coastguard Worker XRegister temp1 = locations->GetTemp(1).AsRegister<XRegister>();
3234*795d594fSAndroid Build Coastguard Worker XRegister temp2 = locations->GetTemp(2).AsRegister<XRegister>();
3235*795d594fSAndroid Build Coastguard Worker XRegister temp3 = kNoXRegister;
3236*795d594fSAndroid Build Coastguard Worker if (mirror::kUseStringCompression) {
3237*795d594fSAndroid Build Coastguard Worker temp3 = locations->GetTemp(3).AsRegister<XRegister>();
3238*795d594fSAndroid Build Coastguard Worker }
3239*795d594fSAndroid Build Coastguard Worker
3240*795d594fSAndroid Build Coastguard Worker Riscv64Label loop;
3241*795d594fSAndroid Build Coastguard Worker Riscv64Label find_char_diff;
3242*795d594fSAndroid Build Coastguard Worker Riscv64Label end;
3243*795d594fSAndroid Build Coastguard Worker Riscv64Label different_compression;
3244*795d594fSAndroid Build Coastguard Worker
3245*795d594fSAndroid Build Coastguard Worker // Get offsets of count and value fields within a string object.
3246*795d594fSAndroid Build Coastguard Worker const int32_t count_offset = mirror::String::CountOffset().Int32Value();
3247*795d594fSAndroid Build Coastguard Worker const int32_t value_offset = mirror::String::ValueOffset().Int32Value();
3248*795d594fSAndroid Build Coastguard Worker
3249*795d594fSAndroid Build Coastguard Worker // Note that the null check must have been done earlier.
3250*795d594fSAndroid Build Coastguard Worker DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0)));
3251*795d594fSAndroid Build Coastguard Worker
3252*795d594fSAndroid Build Coastguard Worker // Take slow path and throw if input can be and is null.
3253*795d594fSAndroid Build Coastguard Worker SlowPathCodeRISCV64* slow_path = nullptr;
3254*795d594fSAndroid Build Coastguard Worker const bool can_slow_path = invoke->InputAt(1)->CanBeNull();
3255*795d594fSAndroid Build Coastguard Worker if (can_slow_path) {
3256*795d594fSAndroid Build Coastguard Worker slow_path = new (codegen_->GetScopedAllocator()) IntrinsicSlowPathRISCV64(invoke);
3257*795d594fSAndroid Build Coastguard Worker codegen_->AddSlowPath(slow_path);
3258*795d594fSAndroid Build Coastguard Worker __ Beqz(arg, slow_path->GetEntryLabel());
3259*795d594fSAndroid Build Coastguard Worker }
3260*795d594fSAndroid Build Coastguard Worker
3261*795d594fSAndroid Build Coastguard Worker // Reference equality check, return 0 if same reference.
3262*795d594fSAndroid Build Coastguard Worker __ Sub(out, str, arg);
3263*795d594fSAndroid Build Coastguard Worker __ Beqz(out, &end);
3264*795d594fSAndroid Build Coastguard Worker
3265*795d594fSAndroid Build Coastguard Worker if (mirror::kUseStringCompression) {
3266*795d594fSAndroid Build Coastguard Worker // Load `count` fields of this and argument strings.
3267*795d594fSAndroid Build Coastguard Worker __ Loadwu(temp3, str, count_offset);
3268*795d594fSAndroid Build Coastguard Worker __ Loadwu(temp2, arg, count_offset);
3269*795d594fSAndroid Build Coastguard Worker // Clean out compression flag from lengths.
3270*795d594fSAndroid Build Coastguard Worker __ Srliw(temp0, temp3, 1u);
3271*795d594fSAndroid Build Coastguard Worker __ Srliw(temp1, temp2, 1u);
3272*795d594fSAndroid Build Coastguard Worker } else {
3273*795d594fSAndroid Build Coastguard Worker // Load lengths of this and argument strings.
3274*795d594fSAndroid Build Coastguard Worker __ Loadwu(temp0, str, count_offset);
3275*795d594fSAndroid Build Coastguard Worker __ Loadwu(temp1, arg, count_offset);
3276*795d594fSAndroid Build Coastguard Worker }
3277*795d594fSAndroid Build Coastguard Worker // out = length diff.
3278*795d594fSAndroid Build Coastguard Worker __ Subw(out, temp0, temp1);
3279*795d594fSAndroid Build Coastguard Worker
3280*795d594fSAndroid Build Coastguard Worker // Find the length of the shorter string
3281*795d594fSAndroid Build Coastguard Worker __ Minu(temp0, temp0, temp1);
3282*795d594fSAndroid Build Coastguard Worker // Shorter string is empty?
3283*795d594fSAndroid Build Coastguard Worker __ Beqz(temp0, &end);
3284*795d594fSAndroid Build Coastguard Worker
3285*795d594fSAndroid Build Coastguard Worker if (mirror::kUseStringCompression) {
3286*795d594fSAndroid Build Coastguard Worker // Extract both compression flags
3287*795d594fSAndroid Build Coastguard Worker __ Andi(temp3, temp3, 1);
3288*795d594fSAndroid Build Coastguard Worker __ Andi(temp2, temp2, 1);
3289*795d594fSAndroid Build Coastguard Worker __ Bne(temp2, temp3, &different_compression);
3290*795d594fSAndroid Build Coastguard Worker }
3291*795d594fSAndroid Build Coastguard Worker // Store offset of string value in preparation for comparison loop.
3292*795d594fSAndroid Build Coastguard Worker __ Li(temp1, value_offset);
3293*795d594fSAndroid Build Coastguard Worker if (mirror::kUseStringCompression) {
3294*795d594fSAndroid Build Coastguard Worker // For string compression, calculate the number of bytes to compare (not chars).
3295*795d594fSAndroid Build Coastguard Worker __ Sll(temp0, temp0, temp3);
3296*795d594fSAndroid Build Coastguard Worker }
3297*795d594fSAndroid Build Coastguard Worker
3298*795d594fSAndroid Build Coastguard Worker // Assertions that must hold in order to compare strings 8 bytes at a time.
3299*795d594fSAndroid Build Coastguard Worker DCHECK_ALIGNED(value_offset, 8);
3300*795d594fSAndroid Build Coastguard Worker static_assert(IsAligned<8>(kObjectAlignment), "String of odd length is not zero padded");
3301*795d594fSAndroid Build Coastguard Worker
3302*795d594fSAndroid Build Coastguard Worker constexpr size_t char_size = DataType::Size(DataType::Type::kUint16);
3303*795d594fSAndroid Build Coastguard Worker static_assert(char_size == 2u, "Char expected to be 2 bytes wide");
3304*795d594fSAndroid Build Coastguard Worker
3305*795d594fSAndroid Build Coastguard Worker ScratchRegisterScope scratch_scope(assembler);
3306*795d594fSAndroid Build Coastguard Worker XRegister temp4 = scratch_scope.AllocateXRegister();
3307*795d594fSAndroid Build Coastguard Worker
3308*795d594fSAndroid Build Coastguard Worker // Loop to compare 4x16-bit characters at a time (ok because of string data alignment).
3309*795d594fSAndroid Build Coastguard Worker __ Bind(&loop);
3310*795d594fSAndroid Build Coastguard Worker __ Add(temp4, str, temp1);
3311*795d594fSAndroid Build Coastguard Worker __ Ld(temp4, temp4, 0);
3312*795d594fSAndroid Build Coastguard Worker __ Add(temp2, arg, temp1);
3313*795d594fSAndroid Build Coastguard Worker __ Ld(temp2, temp2, 0);
3314*795d594fSAndroid Build Coastguard Worker __ Bne(temp4, temp2, &find_char_diff);
3315*795d594fSAndroid Build Coastguard Worker __ Addi(temp1, temp1, char_size * 4);
3316*795d594fSAndroid Build Coastguard Worker // With string compression, we have compared 8 bytes, otherwise 4 chars.
3317*795d594fSAndroid Build Coastguard Worker __ Addi(temp0, temp0, (mirror::kUseStringCompression) ? -8 : -4);
3318*795d594fSAndroid Build Coastguard Worker __ Bgtz(temp0, &loop);
3319*795d594fSAndroid Build Coastguard Worker __ J(&end);
3320*795d594fSAndroid Build Coastguard Worker
3321*795d594fSAndroid Build Coastguard Worker // Find the single character difference.
3322*795d594fSAndroid Build Coastguard Worker __ Bind(&find_char_diff);
3323*795d594fSAndroid Build Coastguard Worker // Get the bit position of the first character that differs.
3324*795d594fSAndroid Build Coastguard Worker __ Xor(temp1, temp2, temp4);
3325*795d594fSAndroid Build Coastguard Worker __ Ctz(temp1, temp1);
3326*795d594fSAndroid Build Coastguard Worker
3327*795d594fSAndroid Build Coastguard Worker // If the number of chars remaining <= the index where the difference occurs (0-3), then
3328*795d594fSAndroid Build Coastguard Worker // the difference occurs outside the remaining string data, so just return length diff (out).
3329*795d594fSAndroid Build Coastguard Worker __ Srliw(temp1, temp1, (mirror::kUseStringCompression) ? 3 : 4);
3330*795d594fSAndroid Build Coastguard Worker __ Ble(temp0, temp1, &end);
3331*795d594fSAndroid Build Coastguard Worker
3332*795d594fSAndroid Build Coastguard Worker // Extract the characters and calculate the difference.
3333*795d594fSAndroid Build Coastguard Worker __ Slliw(temp1, temp1, (mirror::kUseStringCompression) ? 3 : 4);
3334*795d594fSAndroid Build Coastguard Worker if (mirror:: kUseStringCompression) {
3335*795d594fSAndroid Build Coastguard Worker __ Slliw(temp3, temp3, 3u);
3336*795d594fSAndroid Build Coastguard Worker __ Andn(temp1, temp1, temp3);
3337*795d594fSAndroid Build Coastguard Worker }
3338*795d594fSAndroid Build Coastguard Worker __ Srl(temp2, temp2, temp1);
3339*795d594fSAndroid Build Coastguard Worker __ Srl(temp4, temp4, temp1);
3340*795d594fSAndroid Build Coastguard Worker if (mirror::kUseStringCompression) {
3341*795d594fSAndroid Build Coastguard Worker __ Li(temp0, -256); // ~0xff
3342*795d594fSAndroid Build Coastguard Worker __ Sllw(temp0, temp0, temp3); // temp3 = 0 or 8, temp0 := ~0xff or ~0xffff
3343*795d594fSAndroid Build Coastguard Worker __ Andn(temp4, temp4, temp0); // Extract 8 or 16 bits.
3344*795d594fSAndroid Build Coastguard Worker __ Andn(temp2, temp2, temp0); // Extract 8 or 16 bits.
3345*795d594fSAndroid Build Coastguard Worker } else {
3346*795d594fSAndroid Build Coastguard Worker __ ZextH(temp4, temp4);
3347*795d594fSAndroid Build Coastguard Worker __ ZextH(temp2, temp2);
3348*795d594fSAndroid Build Coastguard Worker }
3349*795d594fSAndroid Build Coastguard Worker
3350*795d594fSAndroid Build Coastguard Worker __ Subw(out, temp4, temp2);
3351*795d594fSAndroid Build Coastguard Worker
3352*795d594fSAndroid Build Coastguard Worker if (mirror::kUseStringCompression) {
3353*795d594fSAndroid Build Coastguard Worker __ J(&end);
3354*795d594fSAndroid Build Coastguard Worker __ Bind(&different_compression);
3355*795d594fSAndroid Build Coastguard Worker
3356*795d594fSAndroid Build Coastguard Worker // Comparison for different compression style.
3357*795d594fSAndroid Build Coastguard Worker constexpr size_t c_char_size = DataType::Size(DataType::Type::kInt8);
3358*795d594fSAndroid Build Coastguard Worker static_assert(c_char_size == 1u, "Compressed char expected to be 1 byte wide");
3359*795d594fSAndroid Build Coastguard Worker
3360*795d594fSAndroid Build Coastguard Worker // `temp1` will hold the compressed data pointer, `temp2` the uncompressed data pointer.
3361*795d594fSAndroid Build Coastguard Worker __ Xor(temp4, str, arg);
3362*795d594fSAndroid Build Coastguard Worker __ Addi(temp3, temp3, -1); // -1 if str is compressed, 0 otherwise
3363*795d594fSAndroid Build Coastguard Worker __ And(temp2, temp4, temp3); // str^arg if str is compressed, 0 otherwise
3364*795d594fSAndroid Build Coastguard Worker __ Xor(temp1, temp2, arg); // str if str is compressed, arg otherwise
3365*795d594fSAndroid Build Coastguard Worker __ Xor(temp2, temp2, str); // arg if str is compressed, str otherwise
3366*795d594fSAndroid Build Coastguard Worker
3367*795d594fSAndroid Build Coastguard Worker // We want to free up the temp3, currently holding `str` compression flag, for comparison.
3368*795d594fSAndroid Build Coastguard Worker // So, we move it to the bottom bit of the iteration count `temp0` which we then need to treat
3369*795d594fSAndroid Build Coastguard Worker // as unsigned. This will allow `addi temp0, temp0, -2; bgtz different_compression_loop`
3370*795d594fSAndroid Build Coastguard Worker // to serve as the loop condition.
3371*795d594fSAndroid Build Coastguard Worker __ Sh1Add(temp0, temp0, temp3);
3372*795d594fSAndroid Build Coastguard Worker
3373*795d594fSAndroid Build Coastguard Worker // Adjust temp1 and temp2 from string pointers to data pointers.
3374*795d594fSAndroid Build Coastguard Worker __ Addi(temp1, temp1, value_offset);
3375*795d594fSAndroid Build Coastguard Worker __ Addi(temp2, temp2, value_offset);
3376*795d594fSAndroid Build Coastguard Worker
3377*795d594fSAndroid Build Coastguard Worker Riscv64Label different_compression_loop;
3378*795d594fSAndroid Build Coastguard Worker Riscv64Label different_compression_diff;
3379*795d594fSAndroid Build Coastguard Worker
3380*795d594fSAndroid Build Coastguard Worker __ Bind(&different_compression_loop);
3381*795d594fSAndroid Build Coastguard Worker __ Lbu(temp4, temp1, 0);
3382*795d594fSAndroid Build Coastguard Worker __ Addiw(temp1, temp1, c_char_size);
3383*795d594fSAndroid Build Coastguard Worker __ Lhu(temp3, temp2, 0);
3384*795d594fSAndroid Build Coastguard Worker __ Addi(temp2, temp2, char_size);
3385*795d594fSAndroid Build Coastguard Worker __ Sub(temp4, temp4, temp3);
3386*795d594fSAndroid Build Coastguard Worker __ Bnez(temp4, &different_compression_diff);
3387*795d594fSAndroid Build Coastguard Worker __ Addi(temp0, temp0, -2);
3388*795d594fSAndroid Build Coastguard Worker __ Bgtz(temp0, &different_compression_loop);
3389*795d594fSAndroid Build Coastguard Worker __ J(&end);
3390*795d594fSAndroid Build Coastguard Worker
3391*795d594fSAndroid Build Coastguard Worker // Calculate the difference.
3392*795d594fSAndroid Build Coastguard Worker __ Bind(&different_compression_diff);
3393*795d594fSAndroid Build Coastguard Worker static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u,
3394*795d594fSAndroid Build Coastguard Worker "Expecting 0=compressed, 1=uncompressed");
3395*795d594fSAndroid Build Coastguard Worker __ Andi(temp0, temp0, 1);
3396*795d594fSAndroid Build Coastguard Worker __ Addi(temp0, temp0, -1);
3397*795d594fSAndroid Build Coastguard Worker __ Xor(out, temp4, temp0);
3398*795d594fSAndroid Build Coastguard Worker __ Sub(out, out, temp0);
3399*795d594fSAndroid Build Coastguard Worker }
3400*795d594fSAndroid Build Coastguard Worker
3401*795d594fSAndroid Build Coastguard Worker __ Bind(&end);
3402*795d594fSAndroid Build Coastguard Worker
3403*795d594fSAndroid Build Coastguard Worker if (can_slow_path) {
3404*795d594fSAndroid Build Coastguard Worker __ Bind(slow_path->GetExitLabel());
3405*795d594fSAndroid Build Coastguard Worker }
3406*795d594fSAndroid Build Coastguard Worker }
3407*795d594fSAndroid Build Coastguard Worker
3408*795d594fSAndroid Build Coastguard Worker class VarHandleSlowPathRISCV64 : public IntrinsicSlowPathRISCV64 {
3409*795d594fSAndroid Build Coastguard Worker public:
VarHandleSlowPathRISCV64(HInvoke * invoke,std::memory_order order)3410*795d594fSAndroid Build Coastguard Worker VarHandleSlowPathRISCV64(HInvoke* invoke, std::memory_order order)
3411*795d594fSAndroid Build Coastguard Worker : IntrinsicSlowPathRISCV64(invoke),
3412*795d594fSAndroid Build Coastguard Worker order_(order),
3413*795d594fSAndroid Build Coastguard Worker return_success_(false),
3414*795d594fSAndroid Build Coastguard Worker strong_(false),
3415*795d594fSAndroid Build Coastguard Worker get_and_update_op_(GetAndUpdateOp::kAdd) {
3416*795d594fSAndroid Build Coastguard Worker }
3417*795d594fSAndroid Build Coastguard Worker
GetByteArrayViewCheckLabel()3418*795d594fSAndroid Build Coastguard Worker Riscv64Label* GetByteArrayViewCheckLabel() {
3419*795d594fSAndroid Build Coastguard Worker return &byte_array_view_check_label_;
3420*795d594fSAndroid Build Coastguard Worker }
3421*795d594fSAndroid Build Coastguard Worker
GetNativeByteOrderLabel()3422*795d594fSAndroid Build Coastguard Worker Riscv64Label* GetNativeByteOrderLabel() {
3423*795d594fSAndroid Build Coastguard Worker return &native_byte_order_label_;
3424*795d594fSAndroid Build Coastguard Worker }
3425*795d594fSAndroid Build Coastguard Worker
SetCompareAndSetOrExchangeArgs(bool return_success,bool strong)3426*795d594fSAndroid Build Coastguard Worker void SetCompareAndSetOrExchangeArgs(bool return_success, bool strong) {
3427*795d594fSAndroid Build Coastguard Worker if (return_success) {
3428*795d594fSAndroid Build Coastguard Worker DCHECK(GetAccessModeTemplate() == mirror::VarHandle::AccessModeTemplate::kCompareAndSet);
3429*795d594fSAndroid Build Coastguard Worker } else {
3430*795d594fSAndroid Build Coastguard Worker DCHECK(GetAccessModeTemplate() == mirror::VarHandle::AccessModeTemplate::kCompareAndExchange);
3431*795d594fSAndroid Build Coastguard Worker }
3432*795d594fSAndroid Build Coastguard Worker return_success_ = return_success;
3433*795d594fSAndroid Build Coastguard Worker strong_ = strong;
3434*795d594fSAndroid Build Coastguard Worker }
3435*795d594fSAndroid Build Coastguard Worker
SetGetAndUpdateOp(GetAndUpdateOp get_and_update_op)3436*795d594fSAndroid Build Coastguard Worker void SetGetAndUpdateOp(GetAndUpdateOp get_and_update_op) {
3437*795d594fSAndroid Build Coastguard Worker DCHECK(GetAccessModeTemplate() == mirror::VarHandle::AccessModeTemplate::kGetAndUpdate);
3438*795d594fSAndroid Build Coastguard Worker get_and_update_op_ = get_and_update_op;
3439*795d594fSAndroid Build Coastguard Worker }
3440*795d594fSAndroid Build Coastguard Worker
EmitNativeCode(CodeGenerator * codegen_in)3441*795d594fSAndroid Build Coastguard Worker void EmitNativeCode(CodeGenerator* codegen_in) override {
3442*795d594fSAndroid Build Coastguard Worker if (GetByteArrayViewCheckLabel()->IsLinked()) {
3443*795d594fSAndroid Build Coastguard Worker EmitByteArrayViewCode(codegen_in);
3444*795d594fSAndroid Build Coastguard Worker }
3445*795d594fSAndroid Build Coastguard Worker IntrinsicSlowPathRISCV64::EmitNativeCode(codegen_in);
3446*795d594fSAndroid Build Coastguard Worker }
3447*795d594fSAndroid Build Coastguard Worker
3448*795d594fSAndroid Build Coastguard Worker private:
GetInvoke() const3449*795d594fSAndroid Build Coastguard Worker HInvoke* GetInvoke() const {
3450*795d594fSAndroid Build Coastguard Worker return GetInstruction()->AsInvoke();
3451*795d594fSAndroid Build Coastguard Worker }
3452*795d594fSAndroid Build Coastguard Worker
GetAccessModeTemplate() const3453*795d594fSAndroid Build Coastguard Worker mirror::VarHandle::AccessModeTemplate GetAccessModeTemplate() const {
3454*795d594fSAndroid Build Coastguard Worker return mirror::VarHandle::GetAccessModeTemplateByIntrinsic(GetInvoke()->GetIntrinsic());
3455*795d594fSAndroid Build Coastguard Worker }
3456*795d594fSAndroid Build Coastguard Worker
3457*795d594fSAndroid Build Coastguard Worker void EmitByteArrayViewCode(CodeGenerator* codegen_in);
3458*795d594fSAndroid Build Coastguard Worker
3459*795d594fSAndroid Build Coastguard Worker Riscv64Label byte_array_view_check_label_;
3460*795d594fSAndroid Build Coastguard Worker Riscv64Label native_byte_order_label_;
3461*795d594fSAndroid Build Coastguard Worker // Shared parameter for all VarHandle intrinsics.
3462*795d594fSAndroid Build Coastguard Worker std::memory_order order_;
3463*795d594fSAndroid Build Coastguard Worker // Extra arguments for GenerateVarHandleCompareAndSetOrExchange().
3464*795d594fSAndroid Build Coastguard Worker bool return_success_;
3465*795d594fSAndroid Build Coastguard Worker bool strong_;
3466*795d594fSAndroid Build Coastguard Worker // Extra argument for GenerateVarHandleGetAndUpdate().
3467*795d594fSAndroid Build Coastguard Worker GetAndUpdateOp get_and_update_op_;
3468*795d594fSAndroid Build Coastguard Worker };
3469*795d594fSAndroid Build Coastguard Worker
3470*795d594fSAndroid Build Coastguard Worker // Generate subtype check without read barriers.
GenerateSubTypeObjectCheckNoReadBarrier(CodeGeneratorRISCV64 * codegen,SlowPathCodeRISCV64 * slow_path,XRegister object,XRegister type,bool object_can_be_null=true)3471*795d594fSAndroid Build Coastguard Worker static void GenerateSubTypeObjectCheckNoReadBarrier(CodeGeneratorRISCV64* codegen,
3472*795d594fSAndroid Build Coastguard Worker SlowPathCodeRISCV64* slow_path,
3473*795d594fSAndroid Build Coastguard Worker XRegister object,
3474*795d594fSAndroid Build Coastguard Worker XRegister type,
3475*795d594fSAndroid Build Coastguard Worker bool object_can_be_null = true) {
3476*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = codegen->GetAssembler();
3477*795d594fSAndroid Build Coastguard Worker
3478*795d594fSAndroid Build Coastguard Worker const MemberOffset class_offset = mirror::Object::ClassOffset();
3479*795d594fSAndroid Build Coastguard Worker const MemberOffset super_class_offset = mirror::Class::SuperClassOffset();
3480*795d594fSAndroid Build Coastguard Worker
3481*795d594fSAndroid Build Coastguard Worker Riscv64Label success;
3482*795d594fSAndroid Build Coastguard Worker if (object_can_be_null) {
3483*795d594fSAndroid Build Coastguard Worker __ Beqz(object, &success);
3484*795d594fSAndroid Build Coastguard Worker }
3485*795d594fSAndroid Build Coastguard Worker
3486*795d594fSAndroid Build Coastguard Worker ScratchRegisterScope srs(assembler);
3487*795d594fSAndroid Build Coastguard Worker XRegister temp = srs.AllocateXRegister();
3488*795d594fSAndroid Build Coastguard Worker
3489*795d594fSAndroid Build Coastguard Worker // Note: The `type` can be `TMP`. We're using "bare" local branches to enforce that they shall
3490*795d594fSAndroid Build Coastguard Worker // not be expanded and the scrach register `TMP` shall not be clobbered if taken. Taking the
3491*795d594fSAndroid Build Coastguard Worker // branch to the slow path can theoretically clobber `TMP` (if outside the 1 MiB range).
3492*795d594fSAndroid Build Coastguard Worker __ Loadwu(temp, object, class_offset.Int32Value());
3493*795d594fSAndroid Build Coastguard Worker codegen->MaybeUnpoisonHeapReference(temp);
3494*795d594fSAndroid Build Coastguard Worker Riscv64Label loop;
3495*795d594fSAndroid Build Coastguard Worker __ Bind(&loop);
3496*795d594fSAndroid Build Coastguard Worker __ Beq(type, temp, &success, /*is_bare=*/ true);
3497*795d594fSAndroid Build Coastguard Worker // We may not have another scratch register for `Loadwu()`. Use `Lwu()` directly.
3498*795d594fSAndroid Build Coastguard Worker DCHECK(IsInt<12>(super_class_offset.Int32Value()));
3499*795d594fSAndroid Build Coastguard Worker __ Lwu(temp, temp, super_class_offset.Int32Value());
3500*795d594fSAndroid Build Coastguard Worker codegen->MaybeUnpoisonHeapReference(temp);
3501*795d594fSAndroid Build Coastguard Worker __ Beqz(temp, slow_path->GetEntryLabel());
3502*795d594fSAndroid Build Coastguard Worker __ J(&loop, /*is_bare=*/ true);
3503*795d594fSAndroid Build Coastguard Worker __ Bind(&success);
3504*795d594fSAndroid Build Coastguard Worker }
3505*795d594fSAndroid Build Coastguard Worker
3506*795d594fSAndroid Build Coastguard Worker // Check access mode and the primitive type from VarHandle.varType.
3507*795d594fSAndroid Build Coastguard Worker // Check reference arguments against the VarHandle.varType; for references this is a subclass
3508*795d594fSAndroid Build Coastguard Worker // check without read barrier, so it can have false negatives which we handle in the slow path.
GenerateVarHandleAccessModeAndVarTypeChecks(HInvoke * invoke,CodeGeneratorRISCV64 * codegen,SlowPathCodeRISCV64 * slow_path,DataType::Type type)3509*795d594fSAndroid Build Coastguard Worker static void GenerateVarHandleAccessModeAndVarTypeChecks(HInvoke* invoke,
3510*795d594fSAndroid Build Coastguard Worker CodeGeneratorRISCV64* codegen,
3511*795d594fSAndroid Build Coastguard Worker SlowPathCodeRISCV64* slow_path,
3512*795d594fSAndroid Build Coastguard Worker DataType::Type type) {
3513*795d594fSAndroid Build Coastguard Worker mirror::VarHandle::AccessMode access_mode =
3514*795d594fSAndroid Build Coastguard Worker mirror::VarHandle::GetAccessModeByIntrinsic(invoke->GetIntrinsic());
3515*795d594fSAndroid Build Coastguard Worker Primitive::Type primitive_type = DataTypeToPrimitive(type);
3516*795d594fSAndroid Build Coastguard Worker
3517*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = codegen->GetAssembler();
3518*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = invoke->GetLocations();
3519*795d594fSAndroid Build Coastguard Worker XRegister varhandle = locations->InAt(0).AsRegister<XRegister>();
3520*795d594fSAndroid Build Coastguard Worker
3521*795d594fSAndroid Build Coastguard Worker const MemberOffset var_type_offset = mirror::VarHandle::VarTypeOffset();
3522*795d594fSAndroid Build Coastguard Worker const MemberOffset access_mode_bit_mask_offset = mirror::VarHandle::AccessModesBitMaskOffset();
3523*795d594fSAndroid Build Coastguard Worker const MemberOffset primitive_type_offset = mirror::Class::PrimitiveTypeOffset();
3524*795d594fSAndroid Build Coastguard Worker
3525*795d594fSAndroid Build Coastguard Worker ScratchRegisterScope srs(assembler);
3526*795d594fSAndroid Build Coastguard Worker XRegister temp = srs.AllocateXRegister();
3527*795d594fSAndroid Build Coastguard Worker XRegister temp2 = srs.AllocateXRegister();
3528*795d594fSAndroid Build Coastguard Worker
3529*795d594fSAndroid Build Coastguard Worker // Check that the operation is permitted.
3530*795d594fSAndroid Build Coastguard Worker __ Loadw(temp, varhandle, access_mode_bit_mask_offset.Int32Value());
3531*795d594fSAndroid Build Coastguard Worker DCHECK_LT(enum_cast<uint32_t>(access_mode), 31u); // We cannot avoid the shift below.
3532*795d594fSAndroid Build Coastguard Worker __ Slliw(temp, temp, 31 - enum_cast<uint32_t>(access_mode)); // Shift tested bit to sign bit.
3533*795d594fSAndroid Build Coastguard Worker __ Bgez(temp, slow_path->GetEntryLabel()); // If not permitted, go to slow path.
3534*795d594fSAndroid Build Coastguard Worker
3535*795d594fSAndroid Build Coastguard Worker // For primitive types, we do not need a read barrier when loading a reference only for loading
3536*795d594fSAndroid Build Coastguard Worker // constant field through the reference. For reference types, we deliberately avoid the read
3537*795d594fSAndroid Build Coastguard Worker // barrier, letting the slow path handle the false negatives.
3538*795d594fSAndroid Build Coastguard Worker __ Loadwu(temp, varhandle, var_type_offset.Int32Value());
3539*795d594fSAndroid Build Coastguard Worker codegen->MaybeUnpoisonHeapReference(temp);
3540*795d594fSAndroid Build Coastguard Worker
3541*795d594fSAndroid Build Coastguard Worker // Check the varType.primitiveType field against the type we're trying to use.
3542*795d594fSAndroid Build Coastguard Worker __ Loadhu(temp2, temp, primitive_type_offset.Int32Value());
3543*795d594fSAndroid Build Coastguard Worker if (primitive_type == Primitive::kPrimNot) {
3544*795d594fSAndroid Build Coastguard Worker static_assert(Primitive::kPrimNot == 0);
3545*795d594fSAndroid Build Coastguard Worker __ Bnez(temp2, slow_path->GetEntryLabel());
3546*795d594fSAndroid Build Coastguard Worker } else {
3547*795d594fSAndroid Build Coastguard Worker __ Li(temp, enum_cast<int32_t>(primitive_type)); // `temp` can be clobbered.
3548*795d594fSAndroid Build Coastguard Worker __ Bne(temp2, temp, slow_path->GetEntryLabel());
3549*795d594fSAndroid Build Coastguard Worker }
3550*795d594fSAndroid Build Coastguard Worker
3551*795d594fSAndroid Build Coastguard Worker srs.FreeXRegister(temp2);
3552*795d594fSAndroid Build Coastguard Worker
3553*795d594fSAndroid Build Coastguard Worker if (type == DataType::Type::kReference) {
3554*795d594fSAndroid Build Coastguard Worker // Check reference arguments against the varType.
3555*795d594fSAndroid Build Coastguard Worker // False negatives due to varType being an interface or array type
3556*795d594fSAndroid Build Coastguard Worker // or due to the missing read barrier are handled by the slow path.
3557*795d594fSAndroid Build Coastguard Worker size_t expected_coordinates_count = GetExpectedVarHandleCoordinatesCount(invoke);
3558*795d594fSAndroid Build Coastguard Worker uint32_t arguments_start = /* VarHandle object */ 1u + expected_coordinates_count;
3559*795d594fSAndroid Build Coastguard Worker uint32_t number_of_arguments = invoke->GetNumberOfArguments();
3560*795d594fSAndroid Build Coastguard Worker for (size_t arg_index = arguments_start; arg_index != number_of_arguments; ++arg_index) {
3561*795d594fSAndroid Build Coastguard Worker HInstruction* arg = invoke->InputAt(arg_index);
3562*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(arg->GetType(), DataType::Type::kReference);
3563*795d594fSAndroid Build Coastguard Worker if (!arg->IsNullConstant()) {
3564*795d594fSAndroid Build Coastguard Worker XRegister arg_reg = locations->InAt(arg_index).AsRegister<XRegister>();
3565*795d594fSAndroid Build Coastguard Worker GenerateSubTypeObjectCheckNoReadBarrier(codegen, slow_path, arg_reg, temp);
3566*795d594fSAndroid Build Coastguard Worker }
3567*795d594fSAndroid Build Coastguard Worker }
3568*795d594fSAndroid Build Coastguard Worker }
3569*795d594fSAndroid Build Coastguard Worker }
3570*795d594fSAndroid Build Coastguard Worker
GenerateVarHandleStaticFieldCheck(HInvoke * invoke,CodeGeneratorRISCV64 * codegen,SlowPathCodeRISCV64 * slow_path)3571*795d594fSAndroid Build Coastguard Worker static void GenerateVarHandleStaticFieldCheck(HInvoke* invoke,
3572*795d594fSAndroid Build Coastguard Worker CodeGeneratorRISCV64* codegen,
3573*795d594fSAndroid Build Coastguard Worker SlowPathCodeRISCV64* slow_path) {
3574*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = codegen->GetAssembler();
3575*795d594fSAndroid Build Coastguard Worker XRegister varhandle = invoke->GetLocations()->InAt(0).AsRegister<XRegister>();
3576*795d594fSAndroid Build Coastguard Worker
3577*795d594fSAndroid Build Coastguard Worker const MemberOffset coordinate_type0_offset = mirror::VarHandle::CoordinateType0Offset();
3578*795d594fSAndroid Build Coastguard Worker
3579*795d594fSAndroid Build Coastguard Worker ScratchRegisterScope srs(assembler);
3580*795d594fSAndroid Build Coastguard Worker XRegister temp = srs.AllocateXRegister();
3581*795d594fSAndroid Build Coastguard Worker
3582*795d594fSAndroid Build Coastguard Worker // Check that the VarHandle references a static field by checking that coordinateType0 == null.
3583*795d594fSAndroid Build Coastguard Worker // Do not emit read barrier (or unpoison the reference) for comparing to null.
3584*795d594fSAndroid Build Coastguard Worker __ Loadwu(temp, varhandle, coordinate_type0_offset.Int32Value());
3585*795d594fSAndroid Build Coastguard Worker __ Bnez(temp, slow_path->GetEntryLabel());
3586*795d594fSAndroid Build Coastguard Worker }
3587*795d594fSAndroid Build Coastguard Worker
GenerateVarHandleInstanceFieldChecks(HInvoke * invoke,CodeGeneratorRISCV64 * codegen,SlowPathCodeRISCV64 * slow_path)3588*795d594fSAndroid Build Coastguard Worker static void GenerateVarHandleInstanceFieldChecks(HInvoke* invoke,
3589*795d594fSAndroid Build Coastguard Worker CodeGeneratorRISCV64* codegen,
3590*795d594fSAndroid Build Coastguard Worker SlowPathCodeRISCV64* slow_path) {
3591*795d594fSAndroid Build Coastguard Worker VarHandleOptimizations optimizations(invoke);
3592*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = codegen->GetAssembler();
3593*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = invoke->GetLocations();
3594*795d594fSAndroid Build Coastguard Worker XRegister varhandle = locations->InAt(0).AsRegister<XRegister>();
3595*795d594fSAndroid Build Coastguard Worker XRegister object = locations->InAt(1).AsRegister<XRegister>();
3596*795d594fSAndroid Build Coastguard Worker
3597*795d594fSAndroid Build Coastguard Worker const MemberOffset coordinate_type0_offset = mirror::VarHandle::CoordinateType0Offset();
3598*795d594fSAndroid Build Coastguard Worker const MemberOffset coordinate_type1_offset = mirror::VarHandle::CoordinateType1Offset();
3599*795d594fSAndroid Build Coastguard Worker
3600*795d594fSAndroid Build Coastguard Worker // Null-check the object.
3601*795d594fSAndroid Build Coastguard Worker if (!optimizations.GetSkipObjectNullCheck()) {
3602*795d594fSAndroid Build Coastguard Worker __ Beqz(object, slow_path->GetEntryLabel());
3603*795d594fSAndroid Build Coastguard Worker }
3604*795d594fSAndroid Build Coastguard Worker
3605*795d594fSAndroid Build Coastguard Worker if (!optimizations.GetUseKnownImageVarHandle()) {
3606*795d594fSAndroid Build Coastguard Worker ScratchRegisterScope srs(assembler);
3607*795d594fSAndroid Build Coastguard Worker XRegister temp = srs.AllocateXRegister();
3608*795d594fSAndroid Build Coastguard Worker
3609*795d594fSAndroid Build Coastguard Worker // Check that the VarHandle references an instance field by checking that
3610*795d594fSAndroid Build Coastguard Worker // coordinateType1 == null. coordinateType0 should not be null, but this is handled by the
3611*795d594fSAndroid Build Coastguard Worker // type compatibility check with the source object's type, which will fail for null.
3612*795d594fSAndroid Build Coastguard Worker __ Loadwu(temp, varhandle, coordinate_type1_offset.Int32Value());
3613*795d594fSAndroid Build Coastguard Worker // No need for read barrier or unpoisoning of coordinateType1 for comparison with null.
3614*795d594fSAndroid Build Coastguard Worker __ Bnez(temp, slow_path->GetEntryLabel());
3615*795d594fSAndroid Build Coastguard Worker
3616*795d594fSAndroid Build Coastguard Worker // Check that the object has the correct type.
3617*795d594fSAndroid Build Coastguard Worker // We deliberately avoid the read barrier, letting the slow path handle the false negatives.
3618*795d594fSAndroid Build Coastguard Worker __ Loadwu(temp, varhandle, coordinate_type0_offset.Int32Value());
3619*795d594fSAndroid Build Coastguard Worker codegen->MaybeUnpoisonHeapReference(temp);
3620*795d594fSAndroid Build Coastguard Worker GenerateSubTypeObjectCheckNoReadBarrier(
3621*795d594fSAndroid Build Coastguard Worker codegen, slow_path, object, temp, /*object_can_be_null=*/ false);
3622*795d594fSAndroid Build Coastguard Worker }
3623*795d594fSAndroid Build Coastguard Worker }
3624*795d594fSAndroid Build Coastguard Worker
GenerateVarHandleArrayChecks(HInvoke * invoke,CodeGeneratorRISCV64 * codegen,VarHandleSlowPathRISCV64 * slow_path)3625*795d594fSAndroid Build Coastguard Worker static void GenerateVarHandleArrayChecks(HInvoke* invoke,
3626*795d594fSAndroid Build Coastguard Worker CodeGeneratorRISCV64* codegen,
3627*795d594fSAndroid Build Coastguard Worker VarHandleSlowPathRISCV64* slow_path) {
3628*795d594fSAndroid Build Coastguard Worker VarHandleOptimizations optimizations(invoke);
3629*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = codegen->GetAssembler();
3630*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = invoke->GetLocations();
3631*795d594fSAndroid Build Coastguard Worker XRegister varhandle = locations->InAt(0).AsRegister<XRegister>();
3632*795d594fSAndroid Build Coastguard Worker XRegister object = locations->InAt(1).AsRegister<XRegister>();
3633*795d594fSAndroid Build Coastguard Worker XRegister index = locations->InAt(2).AsRegister<XRegister>();
3634*795d594fSAndroid Build Coastguard Worker DataType::Type value_type =
3635*795d594fSAndroid Build Coastguard Worker GetVarHandleExpectedValueType(invoke, /*expected_coordinates_count=*/ 2u);
3636*795d594fSAndroid Build Coastguard Worker Primitive::Type primitive_type = DataTypeToPrimitive(value_type);
3637*795d594fSAndroid Build Coastguard Worker
3638*795d594fSAndroid Build Coastguard Worker const MemberOffset coordinate_type0_offset = mirror::VarHandle::CoordinateType0Offset();
3639*795d594fSAndroid Build Coastguard Worker const MemberOffset coordinate_type1_offset = mirror::VarHandle::CoordinateType1Offset();
3640*795d594fSAndroid Build Coastguard Worker const MemberOffset component_type_offset = mirror::Class::ComponentTypeOffset();
3641*795d594fSAndroid Build Coastguard Worker const MemberOffset primitive_type_offset = mirror::Class::PrimitiveTypeOffset();
3642*795d594fSAndroid Build Coastguard Worker const MemberOffset class_offset = mirror::Object::ClassOffset();
3643*795d594fSAndroid Build Coastguard Worker const MemberOffset array_length_offset = mirror::Array::LengthOffset();
3644*795d594fSAndroid Build Coastguard Worker
3645*795d594fSAndroid Build Coastguard Worker // Null-check the object.
3646*795d594fSAndroid Build Coastguard Worker if (!optimizations.GetSkipObjectNullCheck()) {
3647*795d594fSAndroid Build Coastguard Worker __ Beqz(object, slow_path->GetEntryLabel());
3648*795d594fSAndroid Build Coastguard Worker }
3649*795d594fSAndroid Build Coastguard Worker
3650*795d594fSAndroid Build Coastguard Worker ScratchRegisterScope srs(assembler);
3651*795d594fSAndroid Build Coastguard Worker XRegister temp = srs.AllocateXRegister();
3652*795d594fSAndroid Build Coastguard Worker XRegister temp2 = srs.AllocateXRegister();
3653*795d594fSAndroid Build Coastguard Worker
3654*795d594fSAndroid Build Coastguard Worker // Check that the VarHandle references an array, byte array view or ByteBuffer by checking
3655*795d594fSAndroid Build Coastguard Worker // that coordinateType1 != null. If that's true, coordinateType1 shall be int.class and
3656*795d594fSAndroid Build Coastguard Worker // coordinateType0 shall not be null but we do not explicitly verify that.
3657*795d594fSAndroid Build Coastguard Worker __ Loadwu(temp, varhandle, coordinate_type1_offset.Int32Value());
3658*795d594fSAndroid Build Coastguard Worker // No need for read barrier or unpoisoning of coordinateType1 for comparison with null.
3659*795d594fSAndroid Build Coastguard Worker __ Beqz(temp, slow_path->GetEntryLabel());
3660*795d594fSAndroid Build Coastguard Worker
3661*795d594fSAndroid Build Coastguard Worker // Check object class against componentType0.
3662*795d594fSAndroid Build Coastguard Worker //
3663*795d594fSAndroid Build Coastguard Worker // This is an exact check and we defer other cases to the runtime. This includes
3664*795d594fSAndroid Build Coastguard Worker // conversion to array of superclass references, which is valid but subsequently
3665*795d594fSAndroid Build Coastguard Worker // requires all update operations to check that the value can indeed be stored.
3666*795d594fSAndroid Build Coastguard Worker // We do not want to perform such extra checks in the intrinsified code.
3667*795d594fSAndroid Build Coastguard Worker //
3668*795d594fSAndroid Build Coastguard Worker // We do this check without read barrier, so there can be false negatives which we
3669*795d594fSAndroid Build Coastguard Worker // defer to the slow path. There shall be no false negatives for array classes in the
3670*795d594fSAndroid Build Coastguard Worker // boot image (including Object[] and primitive arrays) because they are non-movable.
3671*795d594fSAndroid Build Coastguard Worker __ Loadwu(temp, varhandle, coordinate_type0_offset.Int32Value());
3672*795d594fSAndroid Build Coastguard Worker __ Loadwu(temp2, object, class_offset.Int32Value());
3673*795d594fSAndroid Build Coastguard Worker __ Bne(temp, temp2, slow_path->GetEntryLabel());
3674*795d594fSAndroid Build Coastguard Worker
3675*795d594fSAndroid Build Coastguard Worker // Check that the coordinateType0 is an array type. We do not need a read barrier
3676*795d594fSAndroid Build Coastguard Worker // for loading constant reference fields (or chains of them) for comparison with null,
3677*795d594fSAndroid Build Coastguard Worker // nor for finally loading a constant primitive field (primitive type) below.
3678*795d594fSAndroid Build Coastguard Worker codegen->MaybeUnpoisonHeapReference(temp);
3679*795d594fSAndroid Build Coastguard Worker __ Loadwu(temp2, temp, component_type_offset.Int32Value());
3680*795d594fSAndroid Build Coastguard Worker codegen->MaybeUnpoisonHeapReference(temp2);
3681*795d594fSAndroid Build Coastguard Worker __ Beqz(temp2, slow_path->GetEntryLabel());
3682*795d594fSAndroid Build Coastguard Worker
3683*795d594fSAndroid Build Coastguard Worker // Check that the array component type matches the primitive type.
3684*795d594fSAndroid Build Coastguard Worker __ Loadhu(temp, temp2, primitive_type_offset.Int32Value());
3685*795d594fSAndroid Build Coastguard Worker if (primitive_type == Primitive::kPrimNot) {
3686*795d594fSAndroid Build Coastguard Worker static_assert(Primitive::kPrimNot == 0);
3687*795d594fSAndroid Build Coastguard Worker __ Bnez(temp, slow_path->GetEntryLabel());
3688*795d594fSAndroid Build Coastguard Worker } else {
3689*795d594fSAndroid Build Coastguard Worker // With the exception of `kPrimNot` (handled above), `kPrimByte` and `kPrimBoolean`,
3690*795d594fSAndroid Build Coastguard Worker // we shall check for a byte array view in the slow path.
3691*795d594fSAndroid Build Coastguard Worker // The check requires the ByteArrayViewVarHandle.class to be in the boot image,
3692*795d594fSAndroid Build Coastguard Worker // so we cannot emit that if we're JITting without boot image.
3693*795d594fSAndroid Build Coastguard Worker bool boot_image_available =
3694*795d594fSAndroid Build Coastguard Worker codegen->GetCompilerOptions().IsBootImage() ||
3695*795d594fSAndroid Build Coastguard Worker !Runtime::Current()->GetHeap()->GetBootImageSpaces().empty();
3696*795d594fSAndroid Build Coastguard Worker bool can_be_view = (DataType::Size(value_type) != 1u) && boot_image_available;
3697*795d594fSAndroid Build Coastguard Worker Riscv64Label* slow_path_label =
3698*795d594fSAndroid Build Coastguard Worker can_be_view ? slow_path->GetByteArrayViewCheckLabel() : slow_path->GetEntryLabel();
3699*795d594fSAndroid Build Coastguard Worker __ Li(temp2, enum_cast<int32_t>(primitive_type));
3700*795d594fSAndroid Build Coastguard Worker __ Bne(temp, temp2, slow_path_label);
3701*795d594fSAndroid Build Coastguard Worker }
3702*795d594fSAndroid Build Coastguard Worker
3703*795d594fSAndroid Build Coastguard Worker // Check for array index out of bounds.
3704*795d594fSAndroid Build Coastguard Worker __ Loadw(temp, object, array_length_offset.Int32Value());
3705*795d594fSAndroid Build Coastguard Worker __ Bgeu(index, temp, slow_path->GetEntryLabel());
3706*795d594fSAndroid Build Coastguard Worker }
3707*795d594fSAndroid Build Coastguard Worker
GenerateVarHandleCoordinateChecks(HInvoke * invoke,CodeGeneratorRISCV64 * codegen,VarHandleSlowPathRISCV64 * slow_path)3708*795d594fSAndroid Build Coastguard Worker static void GenerateVarHandleCoordinateChecks(HInvoke* invoke,
3709*795d594fSAndroid Build Coastguard Worker CodeGeneratorRISCV64* codegen,
3710*795d594fSAndroid Build Coastguard Worker VarHandleSlowPathRISCV64* slow_path) {
3711*795d594fSAndroid Build Coastguard Worker size_t expected_coordinates_count = GetExpectedVarHandleCoordinatesCount(invoke);
3712*795d594fSAndroid Build Coastguard Worker if (expected_coordinates_count == 0u) {
3713*795d594fSAndroid Build Coastguard Worker GenerateVarHandleStaticFieldCheck(invoke, codegen, slow_path);
3714*795d594fSAndroid Build Coastguard Worker } else if (expected_coordinates_count == 1u) {
3715*795d594fSAndroid Build Coastguard Worker GenerateVarHandleInstanceFieldChecks(invoke, codegen, slow_path);
3716*795d594fSAndroid Build Coastguard Worker } else {
3717*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(expected_coordinates_count, 2u);
3718*795d594fSAndroid Build Coastguard Worker GenerateVarHandleArrayChecks(invoke, codegen, slow_path);
3719*795d594fSAndroid Build Coastguard Worker }
3720*795d594fSAndroid Build Coastguard Worker }
3721*795d594fSAndroid Build Coastguard Worker
GenerateVarHandleChecks(HInvoke * invoke,CodeGeneratorRISCV64 * codegen,std::memory_order order,DataType::Type type)3722*795d594fSAndroid Build Coastguard Worker static VarHandleSlowPathRISCV64* GenerateVarHandleChecks(HInvoke* invoke,
3723*795d594fSAndroid Build Coastguard Worker CodeGeneratorRISCV64* codegen,
3724*795d594fSAndroid Build Coastguard Worker std::memory_order order,
3725*795d594fSAndroid Build Coastguard Worker DataType::Type type) {
3726*795d594fSAndroid Build Coastguard Worker size_t expected_coordinates_count = GetExpectedVarHandleCoordinatesCount(invoke);
3727*795d594fSAndroid Build Coastguard Worker VarHandleOptimizations optimizations(invoke);
3728*795d594fSAndroid Build Coastguard Worker if (optimizations.GetUseKnownImageVarHandle()) {
3729*795d594fSAndroid Build Coastguard Worker DCHECK_NE(expected_coordinates_count, 2u);
3730*795d594fSAndroid Build Coastguard Worker if (expected_coordinates_count == 0u || optimizations.GetSkipObjectNullCheck()) {
3731*795d594fSAndroid Build Coastguard Worker return nullptr;
3732*795d594fSAndroid Build Coastguard Worker }
3733*795d594fSAndroid Build Coastguard Worker }
3734*795d594fSAndroid Build Coastguard Worker
3735*795d594fSAndroid Build Coastguard Worker VarHandleSlowPathRISCV64* slow_path =
3736*795d594fSAndroid Build Coastguard Worker new (codegen->GetScopedAllocator()) VarHandleSlowPathRISCV64(invoke, order);
3737*795d594fSAndroid Build Coastguard Worker codegen->AddSlowPath(slow_path);
3738*795d594fSAndroid Build Coastguard Worker
3739*795d594fSAndroid Build Coastguard Worker if (!optimizations.GetUseKnownImageVarHandle()) {
3740*795d594fSAndroid Build Coastguard Worker GenerateVarHandleAccessModeAndVarTypeChecks(invoke, codegen, slow_path, type);
3741*795d594fSAndroid Build Coastguard Worker }
3742*795d594fSAndroid Build Coastguard Worker GenerateVarHandleCoordinateChecks(invoke, codegen, slow_path);
3743*795d594fSAndroid Build Coastguard Worker
3744*795d594fSAndroid Build Coastguard Worker return slow_path;
3745*795d594fSAndroid Build Coastguard Worker }
3746*795d594fSAndroid Build Coastguard Worker
3747*795d594fSAndroid Build Coastguard Worker struct VarHandleTarget {
3748*795d594fSAndroid Build Coastguard Worker XRegister object; // The object holding the value to operate on.
3749*795d594fSAndroid Build Coastguard Worker XRegister offset; // The offset of the value to operate on.
3750*795d594fSAndroid Build Coastguard Worker };
3751*795d594fSAndroid Build Coastguard Worker
GetVarHandleTarget(HInvoke * invoke)3752*795d594fSAndroid Build Coastguard Worker static VarHandleTarget GetVarHandleTarget(HInvoke* invoke) {
3753*795d594fSAndroid Build Coastguard Worker size_t expected_coordinates_count = GetExpectedVarHandleCoordinatesCount(invoke);
3754*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = invoke->GetLocations();
3755*795d594fSAndroid Build Coastguard Worker
3756*795d594fSAndroid Build Coastguard Worker VarHandleTarget target;
3757*795d594fSAndroid Build Coastguard Worker // The temporary allocated for loading the offset.
3758*795d594fSAndroid Build Coastguard Worker target.offset = locations->GetTemp(0u).AsRegister<XRegister>();
3759*795d594fSAndroid Build Coastguard Worker // The reference to the object that holds the value to operate on.
3760*795d594fSAndroid Build Coastguard Worker target.object = (expected_coordinates_count == 0u)
3761*795d594fSAndroid Build Coastguard Worker ? locations->GetTemp(1u).AsRegister<XRegister>()
3762*795d594fSAndroid Build Coastguard Worker : locations->InAt(1).AsRegister<XRegister>();
3763*795d594fSAndroid Build Coastguard Worker return target;
3764*795d594fSAndroid Build Coastguard Worker }
3765*795d594fSAndroid Build Coastguard Worker
GenerateVarHandleTarget(HInvoke * invoke,const VarHandleTarget & target,CodeGeneratorRISCV64 * codegen)3766*795d594fSAndroid Build Coastguard Worker static void GenerateVarHandleTarget(HInvoke* invoke,
3767*795d594fSAndroid Build Coastguard Worker const VarHandleTarget& target,
3768*795d594fSAndroid Build Coastguard Worker CodeGeneratorRISCV64* codegen) {
3769*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = codegen->GetAssembler();
3770*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = invoke->GetLocations();
3771*795d594fSAndroid Build Coastguard Worker XRegister varhandle = locations->InAt(0).AsRegister<XRegister>();
3772*795d594fSAndroid Build Coastguard Worker size_t expected_coordinates_count = GetExpectedVarHandleCoordinatesCount(invoke);
3773*795d594fSAndroid Build Coastguard Worker
3774*795d594fSAndroid Build Coastguard Worker if (expected_coordinates_count <= 1u) {
3775*795d594fSAndroid Build Coastguard Worker if (VarHandleOptimizations(invoke).GetUseKnownImageVarHandle()) {
3776*795d594fSAndroid Build Coastguard Worker ScopedObjectAccess soa(Thread::Current());
3777*795d594fSAndroid Build Coastguard Worker ArtField* target_field = GetBootImageVarHandleField(invoke);
3778*795d594fSAndroid Build Coastguard Worker if (expected_coordinates_count == 0u) {
3779*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::Class> declaring_class = target_field->GetDeclaringClass();
3780*795d594fSAndroid Build Coastguard Worker if (Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(declaring_class)) {
3781*795d594fSAndroid Build Coastguard Worker uint32_t boot_image_offset = CodeGenerator::GetBootImageOffset(declaring_class);
3782*795d594fSAndroid Build Coastguard Worker codegen->LoadBootImageRelRoEntry(target.object, boot_image_offset);
3783*795d594fSAndroid Build Coastguard Worker } else {
3784*795d594fSAndroid Build Coastguard Worker codegen->LoadTypeForBootImageIntrinsic(
3785*795d594fSAndroid Build Coastguard Worker target.object,
3786*795d594fSAndroid Build Coastguard Worker TypeReference(&declaring_class->GetDexFile(), declaring_class->GetDexTypeIndex()));
3787*795d594fSAndroid Build Coastguard Worker }
3788*795d594fSAndroid Build Coastguard Worker }
3789*795d594fSAndroid Build Coastguard Worker __ Li(target.offset, target_field->GetOffset().Uint32Value());
3790*795d594fSAndroid Build Coastguard Worker } else {
3791*795d594fSAndroid Build Coastguard Worker // For static fields, we need to fill the `target.object` with the declaring class,
3792*795d594fSAndroid Build Coastguard Worker // so we can use `target.object` as temporary for the `ArtField*`. For instance fields,
3793*795d594fSAndroid Build Coastguard Worker // we do not need the declaring class, so we can forget the `ArtField*` when
3794*795d594fSAndroid Build Coastguard Worker // we load the `target.offset`, so use the `target.offset` to hold the `ArtField*`.
3795*795d594fSAndroid Build Coastguard Worker XRegister field = (expected_coordinates_count == 0) ? target.object : target.offset;
3796*795d594fSAndroid Build Coastguard Worker
3797*795d594fSAndroid Build Coastguard Worker const MemberOffset art_field_offset = mirror::FieldVarHandle::ArtFieldOffset();
3798*795d594fSAndroid Build Coastguard Worker const MemberOffset offset_offset = ArtField::OffsetOffset();
3799*795d594fSAndroid Build Coastguard Worker
3800*795d594fSAndroid Build Coastguard Worker // Load the ArtField*, the offset and, if needed, declaring class.
3801*795d594fSAndroid Build Coastguard Worker __ Loadd(field, varhandle, art_field_offset.Int32Value());
3802*795d594fSAndroid Build Coastguard Worker __ Loadwu(target.offset, field, offset_offset.Int32Value());
3803*795d594fSAndroid Build Coastguard Worker if (expected_coordinates_count == 0u) {
3804*795d594fSAndroid Build Coastguard Worker codegen->GenerateGcRootFieldLoad(
3805*795d594fSAndroid Build Coastguard Worker invoke,
3806*795d594fSAndroid Build Coastguard Worker Location::RegisterLocation(target.object),
3807*795d594fSAndroid Build Coastguard Worker field,
3808*795d594fSAndroid Build Coastguard Worker ArtField::DeclaringClassOffset().Int32Value(),
3809*795d594fSAndroid Build Coastguard Worker codegen->GetCompilerReadBarrierOption());
3810*795d594fSAndroid Build Coastguard Worker }
3811*795d594fSAndroid Build Coastguard Worker }
3812*795d594fSAndroid Build Coastguard Worker } else {
3813*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(expected_coordinates_count, 2u);
3814*795d594fSAndroid Build Coastguard Worker DataType::Type value_type =
3815*795d594fSAndroid Build Coastguard Worker GetVarHandleExpectedValueType(invoke, /*expected_coordinates_count=*/ 2u);
3816*795d594fSAndroid Build Coastguard Worker MemberOffset data_offset = mirror::Array::DataOffset(DataType::Size(value_type));
3817*795d594fSAndroid Build Coastguard Worker
3818*795d594fSAndroid Build Coastguard Worker XRegister index = locations->InAt(2).AsRegister<XRegister>();
3819*795d594fSAndroid Build Coastguard Worker __ Li(target.offset, data_offset.Int32Value());
3820*795d594fSAndroid Build Coastguard Worker codegen->GetInstructionVisitor()->ShNAdd(target.offset, index, target.offset, value_type);
3821*795d594fSAndroid Build Coastguard Worker }
3822*795d594fSAndroid Build Coastguard Worker }
3823*795d594fSAndroid Build Coastguard Worker
CreateVarHandleCommonLocations(HInvoke * invoke,CodeGeneratorRISCV64 * codegen)3824*795d594fSAndroid Build Coastguard Worker static LocationSummary* CreateVarHandleCommonLocations(HInvoke* invoke,
3825*795d594fSAndroid Build Coastguard Worker CodeGeneratorRISCV64* codegen) {
3826*795d594fSAndroid Build Coastguard Worker size_t expected_coordinates_count = GetExpectedVarHandleCoordinatesCount(invoke);
3827*795d594fSAndroid Build Coastguard Worker DataType::Type return_type = invoke->GetType();
3828*795d594fSAndroid Build Coastguard Worker
3829*795d594fSAndroid Build Coastguard Worker ArenaAllocator* allocator = invoke->GetBlock()->GetGraph()->GetAllocator();
3830*795d594fSAndroid Build Coastguard Worker LocationSummary* locations =
3831*795d594fSAndroid Build Coastguard Worker new (allocator) LocationSummary(invoke, LocationSummary::kCallOnSlowPath, kIntrinsified);
3832*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresRegister());
3833*795d594fSAndroid Build Coastguard Worker // Require coordinates in registers. These are the object holding the value
3834*795d594fSAndroid Build Coastguard Worker // to operate on (except for static fields) and index (for arrays and views).
3835*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i != expected_coordinates_count; ++i) {
3836*795d594fSAndroid Build Coastguard Worker locations->SetInAt(/* VarHandle object */ 1u + i, Location::RequiresRegister());
3837*795d594fSAndroid Build Coastguard Worker }
3838*795d594fSAndroid Build Coastguard Worker if (return_type != DataType::Type::kVoid) {
3839*795d594fSAndroid Build Coastguard Worker if (DataType::IsFloatingPointType(return_type)) {
3840*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresFpuRegister());
3841*795d594fSAndroid Build Coastguard Worker } else {
3842*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresRegister());
3843*795d594fSAndroid Build Coastguard Worker }
3844*795d594fSAndroid Build Coastguard Worker }
3845*795d594fSAndroid Build Coastguard Worker uint32_t arguments_start = /* VarHandle object */ 1u + expected_coordinates_count;
3846*795d594fSAndroid Build Coastguard Worker uint32_t number_of_arguments = invoke->GetNumberOfArguments();
3847*795d594fSAndroid Build Coastguard Worker for (size_t arg_index = arguments_start; arg_index != number_of_arguments; ++arg_index) {
3848*795d594fSAndroid Build Coastguard Worker HInstruction* arg = invoke->InputAt(arg_index);
3849*795d594fSAndroid Build Coastguard Worker if (IsZeroBitPattern(arg)) {
3850*795d594fSAndroid Build Coastguard Worker locations->SetInAt(arg_index, Location::ConstantLocation(arg));
3851*795d594fSAndroid Build Coastguard Worker } else if (DataType::IsFloatingPointType(arg->GetType())) {
3852*795d594fSAndroid Build Coastguard Worker locations->SetInAt(arg_index, Location::RequiresFpuRegister());
3853*795d594fSAndroid Build Coastguard Worker } else {
3854*795d594fSAndroid Build Coastguard Worker locations->SetInAt(arg_index, Location::RequiresRegister());
3855*795d594fSAndroid Build Coastguard Worker }
3856*795d594fSAndroid Build Coastguard Worker }
3857*795d594fSAndroid Build Coastguard Worker
3858*795d594fSAndroid Build Coastguard Worker // Add a temporary for offset.
3859*795d594fSAndroid Build Coastguard Worker if (codegen->EmitNonBakerReadBarrier() &&
3860*795d594fSAndroid Build Coastguard Worker GetExpectedVarHandleCoordinatesCount(invoke) == 0u) { // For static fields.
3861*795d594fSAndroid Build Coastguard Worker // To preserve the offset value across the non-Baker read barrier slow path
3862*795d594fSAndroid Build Coastguard Worker // for loading the declaring class, use a fixed callee-save register.
3863*795d594fSAndroid Build Coastguard Worker constexpr int first_callee_save = CTZ(kRiscv64CalleeSaveRefSpills);
3864*795d594fSAndroid Build Coastguard Worker locations->AddTemp(Location::RegisterLocation(first_callee_save));
3865*795d594fSAndroid Build Coastguard Worker } else {
3866*795d594fSAndroid Build Coastguard Worker locations->AddTemp(Location::RequiresRegister());
3867*795d594fSAndroid Build Coastguard Worker }
3868*795d594fSAndroid Build Coastguard Worker if (expected_coordinates_count == 0u) {
3869*795d594fSAndroid Build Coastguard Worker // Add a temporary to hold the declaring class.
3870*795d594fSAndroid Build Coastguard Worker locations->AddTemp(Location::RequiresRegister());
3871*795d594fSAndroid Build Coastguard Worker }
3872*795d594fSAndroid Build Coastguard Worker
3873*795d594fSAndroid Build Coastguard Worker return locations;
3874*795d594fSAndroid Build Coastguard Worker }
3875*795d594fSAndroid Build Coastguard Worker
CreateVarHandleGetLocations(HInvoke * invoke,CodeGeneratorRISCV64 * codegen)3876*795d594fSAndroid Build Coastguard Worker static void CreateVarHandleGetLocations(HInvoke* invoke, CodeGeneratorRISCV64* codegen) {
3877*795d594fSAndroid Build Coastguard Worker VarHandleOptimizations optimizations(invoke);
3878*795d594fSAndroid Build Coastguard Worker if (optimizations.GetDoNotIntrinsify()) {
3879*795d594fSAndroid Build Coastguard Worker return;
3880*795d594fSAndroid Build Coastguard Worker }
3881*795d594fSAndroid Build Coastguard Worker
3882*795d594fSAndroid Build Coastguard Worker if (codegen->EmitNonBakerReadBarrier() &&
3883*795d594fSAndroid Build Coastguard Worker invoke->GetType() == DataType::Type::kReference &&
3884*795d594fSAndroid Build Coastguard Worker invoke->GetIntrinsic() != Intrinsics::kVarHandleGet &&
3885*795d594fSAndroid Build Coastguard Worker invoke->GetIntrinsic() != Intrinsics::kVarHandleGetOpaque) {
3886*795d594fSAndroid Build Coastguard Worker // Unsupported for non-Baker read barrier because the artReadBarrierSlow() ignores
3887*795d594fSAndroid Build Coastguard Worker // the passed reference and reloads it from the field. This gets the memory visibility
3888*795d594fSAndroid Build Coastguard Worker // wrong for Acquire/Volatile operations. b/173104084
3889*795d594fSAndroid Build Coastguard Worker return;
3890*795d594fSAndroid Build Coastguard Worker }
3891*795d594fSAndroid Build Coastguard Worker
3892*795d594fSAndroid Build Coastguard Worker CreateVarHandleCommonLocations(invoke, codegen);
3893*795d594fSAndroid Build Coastguard Worker }
3894*795d594fSAndroid Build Coastguard Worker
IntTypeForFloatingPointType(DataType::Type fp_type)3895*795d594fSAndroid Build Coastguard Worker DataType::Type IntTypeForFloatingPointType(DataType::Type fp_type) {
3896*795d594fSAndroid Build Coastguard Worker DCHECK(DataType::IsFloatingPointType(fp_type));
3897*795d594fSAndroid Build Coastguard Worker return (fp_type == DataType::Type::kFloat32) ? DataType::Type::kInt32 : DataType::Type::kInt64;
3898*795d594fSAndroid Build Coastguard Worker }
3899*795d594fSAndroid Build Coastguard Worker
GenerateVarHandleGet(HInvoke * invoke,CodeGeneratorRISCV64 * codegen,std::memory_order order,bool byte_swap=false)3900*795d594fSAndroid Build Coastguard Worker static void GenerateVarHandleGet(HInvoke* invoke,
3901*795d594fSAndroid Build Coastguard Worker CodeGeneratorRISCV64* codegen,
3902*795d594fSAndroid Build Coastguard Worker std::memory_order order,
3903*795d594fSAndroid Build Coastguard Worker bool byte_swap = false) {
3904*795d594fSAndroid Build Coastguard Worker DataType::Type type = invoke->GetType();
3905*795d594fSAndroid Build Coastguard Worker DCHECK_NE(type, DataType::Type::kVoid);
3906*795d594fSAndroid Build Coastguard Worker
3907*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = invoke->GetLocations();
3908*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = codegen->GetAssembler();
3909*795d594fSAndroid Build Coastguard Worker Location out = locations->Out();
3910*795d594fSAndroid Build Coastguard Worker
3911*795d594fSAndroid Build Coastguard Worker VarHandleTarget target = GetVarHandleTarget(invoke);
3912*795d594fSAndroid Build Coastguard Worker VarHandleSlowPathRISCV64* slow_path = nullptr;
3913*795d594fSAndroid Build Coastguard Worker if (!byte_swap) {
3914*795d594fSAndroid Build Coastguard Worker slow_path = GenerateVarHandleChecks(invoke, codegen, order, type);
3915*795d594fSAndroid Build Coastguard Worker GenerateVarHandleTarget(invoke, target, codegen);
3916*795d594fSAndroid Build Coastguard Worker if (slow_path != nullptr) {
3917*795d594fSAndroid Build Coastguard Worker __ Bind(slow_path->GetNativeByteOrderLabel());
3918*795d594fSAndroid Build Coastguard Worker }
3919*795d594fSAndroid Build Coastguard Worker }
3920*795d594fSAndroid Build Coastguard Worker
3921*795d594fSAndroid Build Coastguard Worker bool seq_cst_barrier = (order == std::memory_order_seq_cst);
3922*795d594fSAndroid Build Coastguard Worker bool acquire_barrier = seq_cst_barrier || (order == std::memory_order_acquire);
3923*795d594fSAndroid Build Coastguard Worker DCHECK(acquire_barrier || order == std::memory_order_relaxed);
3924*795d594fSAndroid Build Coastguard Worker
3925*795d594fSAndroid Build Coastguard Worker if (seq_cst_barrier) {
3926*795d594fSAndroid Build Coastguard Worker codegen->GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
3927*795d594fSAndroid Build Coastguard Worker }
3928*795d594fSAndroid Build Coastguard Worker
3929*795d594fSAndroid Build Coastguard Worker // Load the value from the target location.
3930*795d594fSAndroid Build Coastguard Worker if (type == DataType::Type::kReference && codegen->EmitBakerReadBarrier()) {
3931*795d594fSAndroid Build Coastguard Worker Location index = Location::RegisterLocation(target.offset);
3932*795d594fSAndroid Build Coastguard Worker // TODO(riscv64): Revisit when we add checking if the holder is black.
3933*795d594fSAndroid Build Coastguard Worker Location temp = Location::NoLocation();
3934*795d594fSAndroid Build Coastguard Worker codegen->GenerateReferenceLoadWithBakerReadBarrier(invoke,
3935*795d594fSAndroid Build Coastguard Worker out,
3936*795d594fSAndroid Build Coastguard Worker target.object,
3937*795d594fSAndroid Build Coastguard Worker /*offset=*/ 0,
3938*795d594fSAndroid Build Coastguard Worker index,
3939*795d594fSAndroid Build Coastguard Worker temp,
3940*795d594fSAndroid Build Coastguard Worker /*needs_null_check=*/ false);
3941*795d594fSAndroid Build Coastguard Worker DCHECK(!byte_swap);
3942*795d594fSAndroid Build Coastguard Worker } else {
3943*795d594fSAndroid Build Coastguard Worker ScratchRegisterScope srs(assembler);
3944*795d594fSAndroid Build Coastguard Worker XRegister address = srs.AllocateXRegister();
3945*795d594fSAndroid Build Coastguard Worker __ Add(address, target.object, target.offset);
3946*795d594fSAndroid Build Coastguard Worker Location load_loc = out;
3947*795d594fSAndroid Build Coastguard Worker DataType::Type load_type = type;
3948*795d594fSAndroid Build Coastguard Worker if (byte_swap && DataType::IsFloatingPointType(type)) {
3949*795d594fSAndroid Build Coastguard Worker load_loc = Location::RegisterLocation(target.offset); // Load to the offset temporary.
3950*795d594fSAndroid Build Coastguard Worker load_type = IntTypeForFloatingPointType(type);
3951*795d594fSAndroid Build Coastguard Worker }
3952*795d594fSAndroid Build Coastguard Worker codegen->GetInstructionVisitor()->Load(load_loc, address, /*offset=*/ 0, load_type);
3953*795d594fSAndroid Build Coastguard Worker if (type == DataType::Type::kReference) {
3954*795d594fSAndroid Build Coastguard Worker DCHECK(!byte_swap);
3955*795d594fSAndroid Build Coastguard Worker Location object_loc = Location::RegisterLocation(target.object);
3956*795d594fSAndroid Build Coastguard Worker Location offset_loc = Location::RegisterLocation(target.offset);
3957*795d594fSAndroid Build Coastguard Worker codegen->MaybeGenerateReadBarrierSlow(
3958*795d594fSAndroid Build Coastguard Worker invoke, out, out, object_loc, /*offset=*/ 0u, /*index=*/ offset_loc);
3959*795d594fSAndroid Build Coastguard Worker } else if (byte_swap) {
3960*795d594fSAndroid Build Coastguard Worker GenerateReverseBytes(codegen, out, load_loc.AsRegister<XRegister>(), type);
3961*795d594fSAndroid Build Coastguard Worker }
3962*795d594fSAndroid Build Coastguard Worker }
3963*795d594fSAndroid Build Coastguard Worker
3964*795d594fSAndroid Build Coastguard Worker if (acquire_barrier) {
3965*795d594fSAndroid Build Coastguard Worker codegen->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
3966*795d594fSAndroid Build Coastguard Worker }
3967*795d594fSAndroid Build Coastguard Worker
3968*795d594fSAndroid Build Coastguard Worker if (slow_path != nullptr) {
3969*795d594fSAndroid Build Coastguard Worker DCHECK(!byte_swap);
3970*795d594fSAndroid Build Coastguard Worker __ Bind(slow_path->GetExitLabel());
3971*795d594fSAndroid Build Coastguard Worker }
3972*795d594fSAndroid Build Coastguard Worker }
3973*795d594fSAndroid Build Coastguard Worker
VisitVarHandleGet(HInvoke * invoke)3974*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitVarHandleGet(HInvoke* invoke) {
3975*795d594fSAndroid Build Coastguard Worker CreateVarHandleGetLocations(invoke, codegen_);
3976*795d594fSAndroid Build Coastguard Worker }
3977*795d594fSAndroid Build Coastguard Worker
VisitVarHandleGet(HInvoke * invoke)3978*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitVarHandleGet(HInvoke* invoke) {
3979*795d594fSAndroid Build Coastguard Worker GenerateVarHandleGet(invoke, codegen_, std::memory_order_relaxed);
3980*795d594fSAndroid Build Coastguard Worker }
3981*795d594fSAndroid Build Coastguard Worker
VisitVarHandleGetOpaque(HInvoke * invoke)3982*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitVarHandleGetOpaque(HInvoke* invoke) {
3983*795d594fSAndroid Build Coastguard Worker CreateVarHandleGetLocations(invoke, codegen_);
3984*795d594fSAndroid Build Coastguard Worker }
3985*795d594fSAndroid Build Coastguard Worker
VisitVarHandleGetOpaque(HInvoke * invoke)3986*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitVarHandleGetOpaque(HInvoke* invoke) {
3987*795d594fSAndroid Build Coastguard Worker GenerateVarHandleGet(invoke, codegen_, std::memory_order_relaxed);
3988*795d594fSAndroid Build Coastguard Worker }
3989*795d594fSAndroid Build Coastguard Worker
VisitVarHandleGetAcquire(HInvoke * invoke)3990*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitVarHandleGetAcquire(HInvoke* invoke) {
3991*795d594fSAndroid Build Coastguard Worker CreateVarHandleGetLocations(invoke, codegen_);
3992*795d594fSAndroid Build Coastguard Worker }
3993*795d594fSAndroid Build Coastguard Worker
VisitVarHandleGetAcquire(HInvoke * invoke)3994*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitVarHandleGetAcquire(HInvoke* invoke) {
3995*795d594fSAndroid Build Coastguard Worker GenerateVarHandleGet(invoke, codegen_, std::memory_order_acquire);
3996*795d594fSAndroid Build Coastguard Worker }
3997*795d594fSAndroid Build Coastguard Worker
VisitVarHandleGetVolatile(HInvoke * invoke)3998*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitVarHandleGetVolatile(HInvoke* invoke) {
3999*795d594fSAndroid Build Coastguard Worker CreateVarHandleGetLocations(invoke, codegen_);
4000*795d594fSAndroid Build Coastguard Worker }
4001*795d594fSAndroid Build Coastguard Worker
VisitVarHandleGetVolatile(HInvoke * invoke)4002*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitVarHandleGetVolatile(HInvoke* invoke) {
4003*795d594fSAndroid Build Coastguard Worker GenerateVarHandleGet(invoke, codegen_, std::memory_order_seq_cst);
4004*795d594fSAndroid Build Coastguard Worker }
4005*795d594fSAndroid Build Coastguard Worker
CreateVarHandleSetLocations(HInvoke * invoke,CodeGeneratorRISCV64 * codegen)4006*795d594fSAndroid Build Coastguard Worker static void CreateVarHandleSetLocations(HInvoke* invoke, CodeGeneratorRISCV64* codegen) {
4007*795d594fSAndroid Build Coastguard Worker VarHandleOptimizations optimizations(invoke);
4008*795d594fSAndroid Build Coastguard Worker if (optimizations.GetDoNotIntrinsify()) {
4009*795d594fSAndroid Build Coastguard Worker return;
4010*795d594fSAndroid Build Coastguard Worker }
4011*795d594fSAndroid Build Coastguard Worker
4012*795d594fSAndroid Build Coastguard Worker CreateVarHandleCommonLocations(invoke, codegen);
4013*795d594fSAndroid Build Coastguard Worker if (kPoisonHeapReferences && invoke->GetLocations() != nullptr) {
4014*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = invoke->GetLocations();
4015*795d594fSAndroid Build Coastguard Worker uint32_t value_index = invoke->GetNumberOfArguments() - 1;
4016*795d594fSAndroid Build Coastguard Worker DataType::Type value_type = GetDataTypeFromShorty(invoke, value_index);
4017*795d594fSAndroid Build Coastguard Worker if (value_type == DataType::Type::kReference && !locations->InAt(value_index).IsConstant()) {
4018*795d594fSAndroid Build Coastguard Worker locations->AddTemp(Location::RequiresRegister());
4019*795d594fSAndroid Build Coastguard Worker }
4020*795d594fSAndroid Build Coastguard Worker }
4021*795d594fSAndroid Build Coastguard Worker }
4022*795d594fSAndroid Build Coastguard Worker
GenerateVarHandleSet(HInvoke * invoke,CodeGeneratorRISCV64 * codegen,std::memory_order order,bool byte_swap=false)4023*795d594fSAndroid Build Coastguard Worker static void GenerateVarHandleSet(HInvoke* invoke,
4024*795d594fSAndroid Build Coastguard Worker CodeGeneratorRISCV64* codegen,
4025*795d594fSAndroid Build Coastguard Worker std::memory_order order,
4026*795d594fSAndroid Build Coastguard Worker bool byte_swap = false) {
4027*795d594fSAndroid Build Coastguard Worker uint32_t value_index = invoke->GetNumberOfArguments() - 1;
4028*795d594fSAndroid Build Coastguard Worker DataType::Type value_type = GetDataTypeFromShorty(invoke, value_index);
4029*795d594fSAndroid Build Coastguard Worker
4030*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = codegen->GetAssembler();
4031*795d594fSAndroid Build Coastguard Worker Location value = invoke->GetLocations()->InAt(value_index);
4032*795d594fSAndroid Build Coastguard Worker
4033*795d594fSAndroid Build Coastguard Worker VarHandleTarget target = GetVarHandleTarget(invoke);
4034*795d594fSAndroid Build Coastguard Worker VarHandleSlowPathRISCV64* slow_path = nullptr;
4035*795d594fSAndroid Build Coastguard Worker if (!byte_swap) {
4036*795d594fSAndroid Build Coastguard Worker slow_path = GenerateVarHandleChecks(invoke, codegen, order, value_type);
4037*795d594fSAndroid Build Coastguard Worker GenerateVarHandleTarget(invoke, target, codegen);
4038*795d594fSAndroid Build Coastguard Worker if (slow_path != nullptr) {
4039*795d594fSAndroid Build Coastguard Worker __ Bind(slow_path->GetNativeByteOrderLabel());
4040*795d594fSAndroid Build Coastguard Worker }
4041*795d594fSAndroid Build Coastguard Worker }
4042*795d594fSAndroid Build Coastguard Worker
4043*795d594fSAndroid Build Coastguard Worker {
4044*795d594fSAndroid Build Coastguard Worker ScratchRegisterScope srs(assembler);
4045*795d594fSAndroid Build Coastguard Worker // Heap poisoning needs two scratch registers in `Store()`, except for null constants.
4046*795d594fSAndroid Build Coastguard Worker XRegister address =
4047*795d594fSAndroid Build Coastguard Worker (kPoisonHeapReferences && value_type == DataType::Type::kReference && !value.IsConstant())
4048*795d594fSAndroid Build Coastguard Worker ? invoke->GetLocations()->GetTemp(0).AsRegister<XRegister>()
4049*795d594fSAndroid Build Coastguard Worker : srs.AllocateXRegister();
4050*795d594fSAndroid Build Coastguard Worker __ Add(address, target.object, target.offset);
4051*795d594fSAndroid Build Coastguard Worker
4052*795d594fSAndroid Build Coastguard Worker if (byte_swap) {
4053*795d594fSAndroid Build Coastguard Worker DCHECK(!value.IsConstant()); // Zero uses the main path as it does not need a byte swap.
4054*795d594fSAndroid Build Coastguard Worker // The offset is no longer needed, so reuse the offset temporary for the byte-swapped value.
4055*795d594fSAndroid Build Coastguard Worker Location new_value = Location::RegisterLocation(target.offset);
4056*795d594fSAndroid Build Coastguard Worker if (DataType::IsFloatingPointType(value_type)) {
4057*795d594fSAndroid Build Coastguard Worker value_type = IntTypeForFloatingPointType(value_type);
4058*795d594fSAndroid Build Coastguard Worker codegen->MoveLocation(new_value, value, value_type);
4059*795d594fSAndroid Build Coastguard Worker value = new_value;
4060*795d594fSAndroid Build Coastguard Worker }
4061*795d594fSAndroid Build Coastguard Worker GenerateReverseBytes(codegen, new_value, value.AsRegister<XRegister>(), value_type);
4062*795d594fSAndroid Build Coastguard Worker value = new_value;
4063*795d594fSAndroid Build Coastguard Worker }
4064*795d594fSAndroid Build Coastguard Worker
4065*795d594fSAndroid Build Coastguard Worker GenerateSet(codegen, order, value, address, /*offset=*/ 0, value_type);
4066*795d594fSAndroid Build Coastguard Worker }
4067*795d594fSAndroid Build Coastguard Worker
4068*795d594fSAndroid Build Coastguard Worker if (CodeGenerator::StoreNeedsWriteBarrier(value_type, invoke->InputAt(value_index))) {
4069*795d594fSAndroid Build Coastguard Worker codegen->MaybeMarkGCCard(
4070*795d594fSAndroid Build Coastguard Worker target.object, value.AsRegister<XRegister>(), /* emit_null_check= */ true);
4071*795d594fSAndroid Build Coastguard Worker }
4072*795d594fSAndroid Build Coastguard Worker
4073*795d594fSAndroid Build Coastguard Worker if (slow_path != nullptr) {
4074*795d594fSAndroid Build Coastguard Worker DCHECK(!byte_swap);
4075*795d594fSAndroid Build Coastguard Worker __ Bind(slow_path->GetExitLabel());
4076*795d594fSAndroid Build Coastguard Worker }
4077*795d594fSAndroid Build Coastguard Worker }
4078*795d594fSAndroid Build Coastguard Worker
VisitVarHandleSet(HInvoke * invoke)4079*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitVarHandleSet(HInvoke* invoke) {
4080*795d594fSAndroid Build Coastguard Worker CreateVarHandleSetLocations(invoke, codegen_);
4081*795d594fSAndroid Build Coastguard Worker }
4082*795d594fSAndroid Build Coastguard Worker
VisitVarHandleSet(HInvoke * invoke)4083*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitVarHandleSet(HInvoke* invoke) {
4084*795d594fSAndroid Build Coastguard Worker GenerateVarHandleSet(invoke, codegen_, std::memory_order_relaxed);
4085*795d594fSAndroid Build Coastguard Worker }
4086*795d594fSAndroid Build Coastguard Worker
VisitVarHandleSetOpaque(HInvoke * invoke)4087*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitVarHandleSetOpaque(HInvoke* invoke) {
4088*795d594fSAndroid Build Coastguard Worker CreateVarHandleSetLocations(invoke, codegen_);
4089*795d594fSAndroid Build Coastguard Worker }
4090*795d594fSAndroid Build Coastguard Worker
VisitVarHandleSetOpaque(HInvoke * invoke)4091*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitVarHandleSetOpaque(HInvoke* invoke) {
4092*795d594fSAndroid Build Coastguard Worker GenerateVarHandleSet(invoke, codegen_, std::memory_order_relaxed);
4093*795d594fSAndroid Build Coastguard Worker }
4094*795d594fSAndroid Build Coastguard Worker
VisitVarHandleSetRelease(HInvoke * invoke)4095*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitVarHandleSetRelease(HInvoke* invoke) {
4096*795d594fSAndroid Build Coastguard Worker CreateVarHandleSetLocations(invoke, codegen_);
4097*795d594fSAndroid Build Coastguard Worker }
4098*795d594fSAndroid Build Coastguard Worker
VisitVarHandleSetRelease(HInvoke * invoke)4099*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitVarHandleSetRelease(HInvoke* invoke) {
4100*795d594fSAndroid Build Coastguard Worker GenerateVarHandleSet(invoke, codegen_, std::memory_order_release);
4101*795d594fSAndroid Build Coastguard Worker }
4102*795d594fSAndroid Build Coastguard Worker
VisitVarHandleSetVolatile(HInvoke * invoke)4103*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitVarHandleSetVolatile(HInvoke* invoke) {
4104*795d594fSAndroid Build Coastguard Worker CreateVarHandleSetLocations(invoke, codegen_);
4105*795d594fSAndroid Build Coastguard Worker }
4106*795d594fSAndroid Build Coastguard Worker
VisitVarHandleSetVolatile(HInvoke * invoke)4107*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitVarHandleSetVolatile(HInvoke* invoke) {
4108*795d594fSAndroid Build Coastguard Worker GenerateVarHandleSet(invoke, codegen_, std::memory_order_seq_cst);
4109*795d594fSAndroid Build Coastguard Worker }
4110*795d594fSAndroid Build Coastguard Worker
ScratchXRegisterNeeded(Location loc,DataType::Type type,bool byte_swap)4111*795d594fSAndroid Build Coastguard Worker static bool ScratchXRegisterNeeded(Location loc, DataType::Type type, bool byte_swap) {
4112*795d594fSAndroid Build Coastguard Worker if (loc.IsConstant()) {
4113*795d594fSAndroid Build Coastguard Worker DCHECK(loc.GetConstant()->IsZeroBitPattern());
4114*795d594fSAndroid Build Coastguard Worker return false;
4115*795d594fSAndroid Build Coastguard Worker }
4116*795d594fSAndroid Build Coastguard Worker return DataType::IsFloatingPointType(type) || DataType::Size(type) < 4u || byte_swap;
4117*795d594fSAndroid Build Coastguard Worker }
4118*795d594fSAndroid Build Coastguard Worker
CreateVarHandleCompareAndSetOrExchangeLocations(HInvoke * invoke,CodeGeneratorRISCV64 * codegen,bool return_success)4119*795d594fSAndroid Build Coastguard Worker static void CreateVarHandleCompareAndSetOrExchangeLocations(HInvoke* invoke,
4120*795d594fSAndroid Build Coastguard Worker CodeGeneratorRISCV64* codegen,
4121*795d594fSAndroid Build Coastguard Worker bool return_success) {
4122*795d594fSAndroid Build Coastguard Worker VarHandleOptimizations optimizations(invoke);
4123*795d594fSAndroid Build Coastguard Worker if (optimizations.GetDoNotIntrinsify()) {
4124*795d594fSAndroid Build Coastguard Worker return;
4125*795d594fSAndroid Build Coastguard Worker }
4126*795d594fSAndroid Build Coastguard Worker
4127*795d594fSAndroid Build Coastguard Worker uint32_t expected_index = invoke->GetNumberOfArguments() - 2;
4128*795d594fSAndroid Build Coastguard Worker uint32_t new_value_index = invoke->GetNumberOfArguments() - 1;
4129*795d594fSAndroid Build Coastguard Worker DataType::Type value_type = GetDataTypeFromShorty(invoke, new_value_index);
4130*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(value_type, GetDataTypeFromShorty(invoke, expected_index));
4131*795d594fSAndroid Build Coastguard Worker
4132*795d594fSAndroid Build Coastguard Worker bool is_reference = (value_type == DataType::Type::kReference);
4133*795d594fSAndroid Build Coastguard Worker if (is_reference && codegen->EmitNonBakerReadBarrier()) {
4134*795d594fSAndroid Build Coastguard Worker // Unsupported for non-Baker read barrier because the artReadBarrierSlow() ignores
4135*795d594fSAndroid Build Coastguard Worker // the passed reference and reloads it from the field. This breaks the read barriers
4136*795d594fSAndroid Build Coastguard Worker // in slow path in different ways. The marked old value may not actually be a to-space
4137*795d594fSAndroid Build Coastguard Worker // reference to the same object as `old_value`, breaking slow path assumptions. And
4138*795d594fSAndroid Build Coastguard Worker // for CompareAndExchange, marking the old value after comparison failure may actually
4139*795d594fSAndroid Build Coastguard Worker // return the reference to `expected`, erroneously indicating success even though we
4140*795d594fSAndroid Build Coastguard Worker // did not set the new value. (And it also gets the memory visibility wrong.) b/173104084
4141*795d594fSAndroid Build Coastguard Worker return;
4142*795d594fSAndroid Build Coastguard Worker }
4143*795d594fSAndroid Build Coastguard Worker
4144*795d594fSAndroid Build Coastguard Worker // TODO(riscv64): Fix this intrinsic for heap poisoning configuration.
4145*795d594fSAndroid Build Coastguard Worker if (kPoisonHeapReferences && value_type == DataType::Type::kReference) {
4146*795d594fSAndroid Build Coastguard Worker return;
4147*795d594fSAndroid Build Coastguard Worker }
4148*795d594fSAndroid Build Coastguard Worker
4149*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = CreateVarHandleCommonLocations(invoke, codegen);
4150*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(expected_index, 1u + GetExpectedVarHandleCoordinatesCount(invoke));
4151*795d594fSAndroid Build Coastguard Worker
4152*795d594fSAndroid Build Coastguard Worker if (codegen->EmitNonBakerReadBarrier()) {
4153*795d594fSAndroid Build Coastguard Worker // We need callee-save registers for both the class object and offset instead of
4154*795d594fSAndroid Build Coastguard Worker // the temporaries reserved in CreateVarHandleCommonLocations().
4155*795d594fSAndroid Build Coastguard Worker static_assert(POPCOUNT(kRiscv64CalleeSaveRefSpills) >= 2u);
4156*795d594fSAndroid Build Coastguard Worker uint32_t first_callee_save = CTZ(kRiscv64CalleeSaveRefSpills);
4157*795d594fSAndroid Build Coastguard Worker uint32_t second_callee_save = CTZ(kRiscv64CalleeSaveRefSpills ^ (1u << first_callee_save));
4158*795d594fSAndroid Build Coastguard Worker if (expected_index == 1u) { // For static fields.
4159*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(locations->GetTempCount(), 2u);
4160*795d594fSAndroid Build Coastguard Worker DCHECK(locations->GetTemp(0u).Equals(Location::RequiresRegister()));
4161*795d594fSAndroid Build Coastguard Worker DCHECK(locations->GetTemp(1u).Equals(Location::RegisterLocation(first_callee_save)));
4162*795d594fSAndroid Build Coastguard Worker locations->SetTempAt(0u, Location::RegisterLocation(second_callee_save));
4163*795d594fSAndroid Build Coastguard Worker } else {
4164*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(locations->GetTempCount(), 1u);
4165*795d594fSAndroid Build Coastguard Worker DCHECK(locations->GetTemp(0u).Equals(Location::RequiresRegister()));
4166*795d594fSAndroid Build Coastguard Worker locations->SetTempAt(0u, Location::RegisterLocation(first_callee_save));
4167*795d594fSAndroid Build Coastguard Worker }
4168*795d594fSAndroid Build Coastguard Worker }
4169*795d594fSAndroid Build Coastguard Worker
4170*795d594fSAndroid Build Coastguard Worker size_t old_temp_count = locations->GetTempCount();
4171*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(old_temp_count, (expected_index == 1u) ? 2u : 1u);
4172*795d594fSAndroid Build Coastguard Worker Location expected = locations->InAt(expected_index);
4173*795d594fSAndroid Build Coastguard Worker Location new_value = locations->InAt(new_value_index);
4174*795d594fSAndroid Build Coastguard Worker size_t data_size = DataType::Size(value_type);
4175*795d594fSAndroid Build Coastguard Worker bool is_small = (data_size < 4u);
4176*795d594fSAndroid Build Coastguard Worker bool can_byte_swap =
4177*795d594fSAndroid Build Coastguard Worker (expected_index == 3u) && (value_type != DataType::Type::kReference && data_size != 1u);
4178*795d594fSAndroid Build Coastguard Worker bool is_fp = DataType::IsFloatingPointType(value_type);
4179*795d594fSAndroid Build Coastguard Worker size_t temps_needed =
4180*795d594fSAndroid Build Coastguard Worker // The offset temp is used for the `tmp_ptr`, except for the read barrier case. For read
4181*795d594fSAndroid Build Coastguard Worker // barrier we must preserve the offset and class pointer (if any) for the slow path and
4182*795d594fSAndroid Build Coastguard Worker // use a separate temp for `tmp_ptr` and we also need another temp for `old_value_temp`.
4183*795d594fSAndroid Build Coastguard Worker ((is_reference && codegen->EmitReadBarrier()) ? old_temp_count + 2u : 1u) +
4184*795d594fSAndroid Build Coastguard Worker // For small values, we need a temp for the `mask`, `masked` and maybe also for the `shift`.
4185*795d594fSAndroid Build Coastguard Worker (is_small ? (return_success ? 2u : 3u) : 0u) +
4186*795d594fSAndroid Build Coastguard Worker // Some cases need modified copies of `new_value` and `expected`.
4187*795d594fSAndroid Build Coastguard Worker (ScratchXRegisterNeeded(expected, value_type, can_byte_swap) ? 1u : 0u) +
4188*795d594fSAndroid Build Coastguard Worker (ScratchXRegisterNeeded(new_value, value_type, can_byte_swap) ? 1u : 0u) +
4189*795d594fSAndroid Build Coastguard Worker // We need a scratch register either for the old value or for the result of SC.
4190*795d594fSAndroid Build Coastguard Worker // If we need to return a floating point old value, we need a temp for each.
4191*795d594fSAndroid Build Coastguard Worker ((!return_success && is_fp) ? 2u : 1u);
4192*795d594fSAndroid Build Coastguard Worker size_t scratch_registers_available = 2u;
4193*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(scratch_registers_available,
4194*795d594fSAndroid Build Coastguard Worker ScratchRegisterScope(codegen->GetAssembler()).AvailableXRegisters());
4195*795d594fSAndroid Build Coastguard Worker if (temps_needed > old_temp_count + scratch_registers_available) {
4196*795d594fSAndroid Build Coastguard Worker locations->AddRegisterTemps(temps_needed - (old_temp_count + scratch_registers_available));
4197*795d594fSAndroid Build Coastguard Worker }
4198*795d594fSAndroid Build Coastguard Worker }
4199*795d594fSAndroid Build Coastguard Worker
PrepareXRegister(CodeGeneratorRISCV64 * codegen,Location loc,DataType::Type type,XRegister shift,XRegister mask,bool byte_swap,ScratchRegisterScope * srs)4200*795d594fSAndroid Build Coastguard Worker static XRegister PrepareXRegister(CodeGeneratorRISCV64* codegen,
4201*795d594fSAndroid Build Coastguard Worker Location loc,
4202*795d594fSAndroid Build Coastguard Worker DataType::Type type,
4203*795d594fSAndroid Build Coastguard Worker XRegister shift,
4204*795d594fSAndroid Build Coastguard Worker XRegister mask,
4205*795d594fSAndroid Build Coastguard Worker bool byte_swap,
4206*795d594fSAndroid Build Coastguard Worker ScratchRegisterScope* srs) {
4207*795d594fSAndroid Build Coastguard Worker DCHECK_IMPLIES(mask != kNoXRegister, shift != kNoXRegister);
4208*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(shift == kNoXRegister, DataType::Size(type) >= 4u);
4209*795d594fSAndroid Build Coastguard Worker if (loc.IsConstant()) {
4210*795d594fSAndroid Build Coastguard Worker // The `shift`/`mask` and `byte_swap` are irrelevant for zero input.
4211*795d594fSAndroid Build Coastguard Worker DCHECK(loc.GetConstant()->IsZeroBitPattern());
4212*795d594fSAndroid Build Coastguard Worker return Zero;
4213*795d594fSAndroid Build Coastguard Worker }
4214*795d594fSAndroid Build Coastguard Worker
4215*795d594fSAndroid Build Coastguard Worker Location result = loc;
4216*795d594fSAndroid Build Coastguard Worker if (DataType::IsFloatingPointType(type)) {
4217*795d594fSAndroid Build Coastguard Worker type = IntTypeForFloatingPointType(type);
4218*795d594fSAndroid Build Coastguard Worker result = Location::RegisterLocation(srs->AllocateXRegister());
4219*795d594fSAndroid Build Coastguard Worker codegen->MoveLocation(result, loc, type);
4220*795d594fSAndroid Build Coastguard Worker loc = result;
4221*795d594fSAndroid Build Coastguard Worker } else if (byte_swap || shift != kNoXRegister) {
4222*795d594fSAndroid Build Coastguard Worker result = Location::RegisterLocation(srs->AllocateXRegister());
4223*795d594fSAndroid Build Coastguard Worker }
4224*795d594fSAndroid Build Coastguard Worker if (byte_swap) {
4225*795d594fSAndroid Build Coastguard Worker if (type == DataType::Type::kInt16) {
4226*795d594fSAndroid Build Coastguard Worker type = DataType::Type::kUint16; // Do the masking as part of the byte swap.
4227*795d594fSAndroid Build Coastguard Worker }
4228*795d594fSAndroid Build Coastguard Worker GenerateReverseBytes(codegen, result, loc.AsRegister<XRegister>(), type);
4229*795d594fSAndroid Build Coastguard Worker loc = result;
4230*795d594fSAndroid Build Coastguard Worker }
4231*795d594fSAndroid Build Coastguard Worker if (shift != kNoXRegister) {
4232*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = codegen->GetAssembler();
4233*795d594fSAndroid Build Coastguard Worker __ Sllw(result.AsRegister<XRegister>(), loc.AsRegister<XRegister>(), shift);
4234*795d594fSAndroid Build Coastguard Worker DCHECK_NE(type, DataType::Type::kUint8);
4235*795d594fSAndroid Build Coastguard Worker if (mask != kNoXRegister && type != DataType::Type::kUint16 && type != DataType::Type::kBool) {
4236*795d594fSAndroid Build Coastguard Worker __ And(result.AsRegister<XRegister>(), result.AsRegister<XRegister>(), mask);
4237*795d594fSAndroid Build Coastguard Worker }
4238*795d594fSAndroid Build Coastguard Worker }
4239*795d594fSAndroid Build Coastguard Worker return result.AsRegister<XRegister>();
4240*795d594fSAndroid Build Coastguard Worker }
4241*795d594fSAndroid Build Coastguard Worker
GenerateByteSwapAndExtract(CodeGeneratorRISCV64 * codegen,Location rd,XRegister rs1,XRegister shift,DataType::Type type)4242*795d594fSAndroid Build Coastguard Worker static void GenerateByteSwapAndExtract(CodeGeneratorRISCV64* codegen,
4243*795d594fSAndroid Build Coastguard Worker Location rd,
4244*795d594fSAndroid Build Coastguard Worker XRegister rs1,
4245*795d594fSAndroid Build Coastguard Worker XRegister shift,
4246*795d594fSAndroid Build Coastguard Worker DataType::Type type) {
4247*795d594fSAndroid Build Coastguard Worker // Apply shift before `GenerateReverseBytes()` for small types.
4248*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(shift != kNoXRegister, DataType::Size(type) < 4u);
4249*795d594fSAndroid Build Coastguard Worker if (shift != kNoXRegister) {
4250*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = codegen->GetAssembler();
4251*795d594fSAndroid Build Coastguard Worker __ Srlw(rd.AsRegister<XRegister>(), rs1, shift);
4252*795d594fSAndroid Build Coastguard Worker rs1 = rd.AsRegister<XRegister>();
4253*795d594fSAndroid Build Coastguard Worker }
4254*795d594fSAndroid Build Coastguard Worker // Also handles moving to FP registers.
4255*795d594fSAndroid Build Coastguard Worker GenerateReverseBytes(codegen, rd, rs1, type);
4256*795d594fSAndroid Build Coastguard Worker }
4257*795d594fSAndroid Build Coastguard Worker
GenerateVarHandleCompareAndSetOrExchange(HInvoke * invoke,CodeGeneratorRISCV64 * codegen,std::memory_order order,bool return_success,bool strong,bool byte_swap=false)4258*795d594fSAndroid Build Coastguard Worker static void GenerateVarHandleCompareAndSetOrExchange(HInvoke* invoke,
4259*795d594fSAndroid Build Coastguard Worker CodeGeneratorRISCV64* codegen,
4260*795d594fSAndroid Build Coastguard Worker std::memory_order order,
4261*795d594fSAndroid Build Coastguard Worker bool return_success,
4262*795d594fSAndroid Build Coastguard Worker bool strong,
4263*795d594fSAndroid Build Coastguard Worker bool byte_swap = false) {
4264*795d594fSAndroid Build Coastguard Worker DCHECK(return_success || strong);
4265*795d594fSAndroid Build Coastguard Worker
4266*795d594fSAndroid Build Coastguard Worker uint32_t expected_index = invoke->GetNumberOfArguments() - 2;
4267*795d594fSAndroid Build Coastguard Worker uint32_t new_value_index = invoke->GetNumberOfArguments() - 1;
4268*795d594fSAndroid Build Coastguard Worker DataType::Type value_type = GetDataTypeFromShorty(invoke, new_value_index);
4269*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(value_type, GetDataTypeFromShorty(invoke, expected_index));
4270*795d594fSAndroid Build Coastguard Worker
4271*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = codegen->GetAssembler();
4272*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = invoke->GetLocations();
4273*795d594fSAndroid Build Coastguard Worker Location expected = locations->InAt(expected_index);
4274*795d594fSAndroid Build Coastguard Worker Location new_value = locations->InAt(new_value_index);
4275*795d594fSAndroid Build Coastguard Worker Location out = locations->Out();
4276*795d594fSAndroid Build Coastguard Worker
4277*795d594fSAndroid Build Coastguard Worker VarHandleTarget target = GetVarHandleTarget(invoke);
4278*795d594fSAndroid Build Coastguard Worker VarHandleSlowPathRISCV64* slow_path = nullptr;
4279*795d594fSAndroid Build Coastguard Worker if (!byte_swap) {
4280*795d594fSAndroid Build Coastguard Worker slow_path = GenerateVarHandleChecks(invoke, codegen, order, value_type);
4281*795d594fSAndroid Build Coastguard Worker GenerateVarHandleTarget(invoke, target, codegen);
4282*795d594fSAndroid Build Coastguard Worker if (slow_path != nullptr) {
4283*795d594fSAndroid Build Coastguard Worker slow_path->SetCompareAndSetOrExchangeArgs(return_success, strong);
4284*795d594fSAndroid Build Coastguard Worker __ Bind(slow_path->GetNativeByteOrderLabel());
4285*795d594fSAndroid Build Coastguard Worker }
4286*795d594fSAndroid Build Coastguard Worker }
4287*795d594fSAndroid Build Coastguard Worker
4288*795d594fSAndroid Build Coastguard Worker // This needs to be before we allocate the scratch registers, as MarkGCCard also uses them.
4289*795d594fSAndroid Build Coastguard Worker if (CodeGenerator::StoreNeedsWriteBarrier(value_type, invoke->InputAt(new_value_index))) {
4290*795d594fSAndroid Build Coastguard Worker // Mark card for object assuming new value is stored.
4291*795d594fSAndroid Build Coastguard Worker bool new_value_can_be_null = true; // TODO: Worth finding out this information?
4292*795d594fSAndroid Build Coastguard Worker codegen->MaybeMarkGCCard(
4293*795d594fSAndroid Build Coastguard Worker target.object, new_value.AsRegister<XRegister>(), new_value_can_be_null);
4294*795d594fSAndroid Build Coastguard Worker }
4295*795d594fSAndroid Build Coastguard Worker
4296*795d594fSAndroid Build Coastguard Worker // Scratch registers may be needed for `new_value` and `expected`.
4297*795d594fSAndroid Build Coastguard Worker ScratchRegisterScope srs(assembler);
4298*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(srs.AvailableXRegisters(), 2u);
4299*795d594fSAndroid Build Coastguard Worker size_t available_scratch_registers =
4300*795d594fSAndroid Build Coastguard Worker (ScratchXRegisterNeeded(expected, value_type, byte_swap) ? 0u : 1u) +
4301*795d594fSAndroid Build Coastguard Worker (ScratchXRegisterNeeded(new_value, value_type, byte_swap) ? 0u : 1u);
4302*795d594fSAndroid Build Coastguard Worker
4303*795d594fSAndroid Build Coastguard Worker // Reuse the `offset` temporary for the pointer to the target location,
4304*795d594fSAndroid Build Coastguard Worker // except for references that need the offset for the read barrier.
4305*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(target.offset, locations->GetTemp(0u).AsRegister<XRegister>());
4306*795d594fSAndroid Build Coastguard Worker size_t next_temp = 1u;
4307*795d594fSAndroid Build Coastguard Worker XRegister tmp_ptr = target.offset;
4308*795d594fSAndroid Build Coastguard Worker bool is_reference = (value_type == DataType::Type::kReference);
4309*795d594fSAndroid Build Coastguard Worker if (is_reference && codegen->EmitReadBarrier()) {
4310*795d594fSAndroid Build Coastguard Worker // Reserve scratch registers for `tmp_ptr` and `old_value_temp`.
4311*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(available_scratch_registers, 2u);
4312*795d594fSAndroid Build Coastguard Worker available_scratch_registers = 0u;
4313*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(expected_index, 1u + GetExpectedVarHandleCoordinatesCount(invoke));
4314*795d594fSAndroid Build Coastguard Worker next_temp = expected_index == 1u ? 2u : 1u; // Preserve the class register for static field.
4315*795d594fSAndroid Build Coastguard Worker tmp_ptr = srs.AllocateXRegister();
4316*795d594fSAndroid Build Coastguard Worker }
4317*795d594fSAndroid Build Coastguard Worker __ Add(tmp_ptr, target.object, target.offset);
4318*795d594fSAndroid Build Coastguard Worker
4319*795d594fSAndroid Build Coastguard Worker auto get_temp = [&]() {
4320*795d594fSAndroid Build Coastguard Worker if (available_scratch_registers != 0u) {
4321*795d594fSAndroid Build Coastguard Worker available_scratch_registers -= 1u;
4322*795d594fSAndroid Build Coastguard Worker return srs.AllocateXRegister();
4323*795d594fSAndroid Build Coastguard Worker } else {
4324*795d594fSAndroid Build Coastguard Worker XRegister temp = locations->GetTemp(next_temp).AsRegister<XRegister>();
4325*795d594fSAndroid Build Coastguard Worker next_temp += 1u;
4326*795d594fSAndroid Build Coastguard Worker return temp;
4327*795d594fSAndroid Build Coastguard Worker }
4328*795d594fSAndroid Build Coastguard Worker };
4329*795d594fSAndroid Build Coastguard Worker
4330*795d594fSAndroid Build Coastguard Worker XRegister shift = kNoXRegister;
4331*795d594fSAndroid Build Coastguard Worker XRegister mask = kNoXRegister;
4332*795d594fSAndroid Build Coastguard Worker XRegister masked = kNoXRegister;
4333*795d594fSAndroid Build Coastguard Worker size_t data_size = DataType::Size(value_type);
4334*795d594fSAndroid Build Coastguard Worker bool is_small = (data_size < 4u);
4335*795d594fSAndroid Build Coastguard Worker if (is_small) {
4336*795d594fSAndroid Build Coastguard Worker // When returning "success" and not the old value, we shall not need the `shift` after
4337*795d594fSAndroid Build Coastguard Worker // the raw CAS operation, so use the output register as a temporary here.
4338*795d594fSAndroid Build Coastguard Worker shift = return_success ? locations->Out().AsRegister<XRegister>() : get_temp();
4339*795d594fSAndroid Build Coastguard Worker mask = get_temp();
4340*795d594fSAndroid Build Coastguard Worker masked = get_temp();
4341*795d594fSAndroid Build Coastguard Worker // Upper bits of the shift are not used, so we do not need to clear them.
4342*795d594fSAndroid Build Coastguard Worker __ Slli(shift, tmp_ptr, WhichPowerOf2(kBitsPerByte));
4343*795d594fSAndroid Build Coastguard Worker __ Andi(tmp_ptr, tmp_ptr, -4);
4344*795d594fSAndroid Build Coastguard Worker __ Li(mask, (1 << (data_size * kBitsPerByte)) - 1);
4345*795d594fSAndroid Build Coastguard Worker __ Sllw(mask, mask, shift);
4346*795d594fSAndroid Build Coastguard Worker }
4347*795d594fSAndroid Build Coastguard Worker
4348*795d594fSAndroid Build Coastguard Worker // Move floating point values to scratch registers and apply shift, mask and byte swap if needed.
4349*795d594fSAndroid Build Coastguard Worker // Note that float/double CAS uses bitwise comparison, rather than the operator==.
4350*795d594fSAndroid Build Coastguard Worker XRegister expected_reg =
4351*795d594fSAndroid Build Coastguard Worker PrepareXRegister(codegen, expected, value_type, shift, mask, byte_swap, &srs);
4352*795d594fSAndroid Build Coastguard Worker XRegister new_value_reg =
4353*795d594fSAndroid Build Coastguard Worker PrepareXRegister(codegen, new_value, value_type, shift, mask, byte_swap, &srs);
4354*795d594fSAndroid Build Coastguard Worker bool is_fp = DataType::IsFloatingPointType(value_type);
4355*795d594fSAndroid Build Coastguard Worker DataType::Type cas_type = is_fp
4356*795d594fSAndroid Build Coastguard Worker ? IntTypeForFloatingPointType(value_type)
4357*795d594fSAndroid Build Coastguard Worker : (is_small ? DataType::Type::kInt32 : value_type);
4358*795d594fSAndroid Build Coastguard Worker
4359*795d594fSAndroid Build Coastguard Worker // Prepare registers for old value and the result of the store conditional.
4360*795d594fSAndroid Build Coastguard Worker XRegister old_value;
4361*795d594fSAndroid Build Coastguard Worker XRegister store_result;
4362*795d594fSAndroid Build Coastguard Worker if (return_success) {
4363*795d594fSAndroid Build Coastguard Worker // Use a temp for the old value.
4364*795d594fSAndroid Build Coastguard Worker old_value = get_temp();
4365*795d594fSAndroid Build Coastguard Worker // For strong CAS, use the `old_value` temp also for the SC result.
4366*795d594fSAndroid Build Coastguard Worker // For weak CAS, put the SC result directly to `out`.
4367*795d594fSAndroid Build Coastguard Worker store_result = strong ? old_value : out.AsRegister<XRegister>();
4368*795d594fSAndroid Build Coastguard Worker } else if (is_fp) {
4369*795d594fSAndroid Build Coastguard Worker // We need two temporary registers.
4370*795d594fSAndroid Build Coastguard Worker old_value = get_temp();
4371*795d594fSAndroid Build Coastguard Worker store_result = get_temp();
4372*795d594fSAndroid Build Coastguard Worker } else {
4373*795d594fSAndroid Build Coastguard Worker // Use the output register for the old value and a temp for the store conditional result.
4374*795d594fSAndroid Build Coastguard Worker old_value = out.AsRegister<XRegister>();
4375*795d594fSAndroid Build Coastguard Worker store_result = get_temp();
4376*795d594fSAndroid Build Coastguard Worker }
4377*795d594fSAndroid Build Coastguard Worker
4378*795d594fSAndroid Build Coastguard Worker Riscv64Label exit_loop_label;
4379*795d594fSAndroid Build Coastguard Worker Riscv64Label* exit_loop = &exit_loop_label;
4380*795d594fSAndroid Build Coastguard Worker Riscv64Label* cmp_failure = &exit_loop_label;
4381*795d594fSAndroid Build Coastguard Worker
4382*795d594fSAndroid Build Coastguard Worker ReadBarrierCasSlowPathRISCV64* rb_slow_path = nullptr;
4383*795d594fSAndroid Build Coastguard Worker if (is_reference && codegen->EmitReadBarrier()) {
4384*795d594fSAndroid Build Coastguard Worker // The `old_value_temp` is used first for marking the `old_value` and then for the unmarked
4385*795d594fSAndroid Build Coastguard Worker // reloaded old value for subsequent CAS in the slow path. We make this a scratch register
4386*795d594fSAndroid Build Coastguard Worker // as we do have marking entrypoints on riscv64 even for scratch registers.
4387*795d594fSAndroid Build Coastguard Worker XRegister old_value_temp = srs.AllocateXRegister();
4388*795d594fSAndroid Build Coastguard Worker // For strong CAS, use the `old_value_temp` also for the SC result as the reloaded old value
4389*795d594fSAndroid Build Coastguard Worker // is no longer needed after the comparison. For weak CAS, store the SC result in the same
4390*795d594fSAndroid Build Coastguard Worker // result register as the main path.
4391*795d594fSAndroid Build Coastguard Worker // Note that for a strong CAS, a SC failure in the slow path can set the register to 1, so
4392*795d594fSAndroid Build Coastguard Worker // we cannot use that register to indicate success without resetting it to 0 at the start of
4393*795d594fSAndroid Build Coastguard Worker // the retry loop. Instead, we return to the success indicating instruction in the main path.
4394*795d594fSAndroid Build Coastguard Worker XRegister slow_path_store_result = strong ? old_value_temp : store_result;
4395*795d594fSAndroid Build Coastguard Worker rb_slow_path = new (codegen->GetScopedAllocator()) ReadBarrierCasSlowPathRISCV64(
4396*795d594fSAndroid Build Coastguard Worker invoke,
4397*795d594fSAndroid Build Coastguard Worker order,
4398*795d594fSAndroid Build Coastguard Worker strong,
4399*795d594fSAndroid Build Coastguard Worker target.object,
4400*795d594fSAndroid Build Coastguard Worker target.offset,
4401*795d594fSAndroid Build Coastguard Worker expected_reg,
4402*795d594fSAndroid Build Coastguard Worker new_value_reg,
4403*795d594fSAndroid Build Coastguard Worker old_value,
4404*795d594fSAndroid Build Coastguard Worker old_value_temp,
4405*795d594fSAndroid Build Coastguard Worker slow_path_store_result,
4406*795d594fSAndroid Build Coastguard Worker /*update_old_value=*/ !return_success,
4407*795d594fSAndroid Build Coastguard Worker codegen);
4408*795d594fSAndroid Build Coastguard Worker codegen->AddSlowPath(rb_slow_path);
4409*795d594fSAndroid Build Coastguard Worker exit_loop = rb_slow_path->GetExitLabel();
4410*795d594fSAndroid Build Coastguard Worker cmp_failure = rb_slow_path->GetEntryLabel();
4411*795d594fSAndroid Build Coastguard Worker }
4412*795d594fSAndroid Build Coastguard Worker
4413*795d594fSAndroid Build Coastguard Worker if (return_success) {
4414*795d594fSAndroid Build Coastguard Worker // Pre-populate the output register with failure for the case when the old value
4415*795d594fSAndroid Build Coastguard Worker // differs and we do not execute the store conditional.
4416*795d594fSAndroid Build Coastguard Worker __ Li(out.AsRegister<XRegister>(), 0);
4417*795d594fSAndroid Build Coastguard Worker }
4418*795d594fSAndroid Build Coastguard Worker GenerateCompareAndSet(codegen->GetAssembler(),
4419*795d594fSAndroid Build Coastguard Worker cas_type,
4420*795d594fSAndroid Build Coastguard Worker order,
4421*795d594fSAndroid Build Coastguard Worker strong,
4422*795d594fSAndroid Build Coastguard Worker cmp_failure,
4423*795d594fSAndroid Build Coastguard Worker tmp_ptr,
4424*795d594fSAndroid Build Coastguard Worker new_value_reg,
4425*795d594fSAndroid Build Coastguard Worker old_value,
4426*795d594fSAndroid Build Coastguard Worker mask,
4427*795d594fSAndroid Build Coastguard Worker masked,
4428*795d594fSAndroid Build Coastguard Worker store_result,
4429*795d594fSAndroid Build Coastguard Worker expected_reg);
4430*795d594fSAndroid Build Coastguard Worker if (return_success && strong) {
4431*795d594fSAndroid Build Coastguard Worker if (rb_slow_path != nullptr) {
4432*795d594fSAndroid Build Coastguard Worker // Slow path returns here on success.
4433*795d594fSAndroid Build Coastguard Worker __ Bind(rb_slow_path->GetSuccessExitLabel());
4434*795d594fSAndroid Build Coastguard Worker }
4435*795d594fSAndroid Build Coastguard Worker // Load success value to the output register.
4436*795d594fSAndroid Build Coastguard Worker // `GenerateCompareAndSet()` does not emit code to indicate success for a strong CAS.
4437*795d594fSAndroid Build Coastguard Worker __ Li(out.AsRegister<XRegister>(), 1);
4438*795d594fSAndroid Build Coastguard Worker } else if (rb_slow_path != nullptr) {
4439*795d594fSAndroid Build Coastguard Worker DCHECK(!rb_slow_path->GetSuccessExitLabel()->IsLinked());
4440*795d594fSAndroid Build Coastguard Worker }
4441*795d594fSAndroid Build Coastguard Worker __ Bind(exit_loop);
4442*795d594fSAndroid Build Coastguard Worker
4443*795d594fSAndroid Build Coastguard Worker if (return_success) {
4444*795d594fSAndroid Build Coastguard Worker // Nothing to do, the result register already contains 1 on success and 0 on failure.
4445*795d594fSAndroid Build Coastguard Worker } else if (byte_swap) {
4446*795d594fSAndroid Build Coastguard Worker DCHECK_IMPLIES(is_small, out.AsRegister<XRegister>() == old_value)
4447*795d594fSAndroid Build Coastguard Worker << " " << value_type << " " << out.AsRegister<XRegister>() << "!=" << old_value;
4448*795d594fSAndroid Build Coastguard Worker GenerateByteSwapAndExtract(codegen, out, old_value, shift, value_type);
4449*795d594fSAndroid Build Coastguard Worker } else if (is_fp) {
4450*795d594fSAndroid Build Coastguard Worker codegen->MoveLocation(out, Location::RegisterLocation(old_value), value_type);
4451*795d594fSAndroid Build Coastguard Worker } else if (is_small) {
4452*795d594fSAndroid Build Coastguard Worker __ Srlw(old_value, masked, shift);
4453*795d594fSAndroid Build Coastguard Worker if (value_type == DataType::Type::kInt8) {
4454*795d594fSAndroid Build Coastguard Worker __ SextB(old_value, old_value);
4455*795d594fSAndroid Build Coastguard Worker } else if (value_type == DataType::Type::kInt16) {
4456*795d594fSAndroid Build Coastguard Worker __ SextH(old_value, old_value);
4457*795d594fSAndroid Build Coastguard Worker }
4458*795d594fSAndroid Build Coastguard Worker }
4459*795d594fSAndroid Build Coastguard Worker
4460*795d594fSAndroid Build Coastguard Worker if (slow_path != nullptr) {
4461*795d594fSAndroid Build Coastguard Worker DCHECK(!byte_swap);
4462*795d594fSAndroid Build Coastguard Worker __ Bind(slow_path->GetExitLabel());
4463*795d594fSAndroid Build Coastguard Worker }
4464*795d594fSAndroid Build Coastguard Worker
4465*795d594fSAndroid Build Coastguard Worker // Check that we have allocated the right number of temps. We may need more registers
4466*795d594fSAndroid Build Coastguard Worker // for byte swapped CAS in the slow path, so skip this check for the main path in that case.
4467*795d594fSAndroid Build Coastguard Worker bool has_byte_swap = (expected_index == 3u) && (!is_reference && data_size != 1u);
4468*795d594fSAndroid Build Coastguard Worker if ((!has_byte_swap || byte_swap) && next_temp != locations->GetTempCount()) {
4469*795d594fSAndroid Build Coastguard Worker // We allocate a temporary register for the class object for a static field `VarHandle` but
4470*795d594fSAndroid Build Coastguard Worker // we do not update the `next_temp` if it's otherwise unused after the address calculation.
4471*795d594fSAndroid Build Coastguard Worker CHECK_EQ(expected_index, 1u);
4472*795d594fSAndroid Build Coastguard Worker CHECK_EQ(next_temp, 1u);
4473*795d594fSAndroid Build Coastguard Worker CHECK_EQ(locations->GetTempCount(), 2u);
4474*795d594fSAndroid Build Coastguard Worker }
4475*795d594fSAndroid Build Coastguard Worker }
4476*795d594fSAndroid Build Coastguard Worker
VisitVarHandleCompareAndExchange(HInvoke * invoke)4477*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitVarHandleCompareAndExchange(HInvoke* invoke) {
4478*795d594fSAndroid Build Coastguard Worker CreateVarHandleCompareAndSetOrExchangeLocations(invoke, codegen_, /*return_success=*/ false);
4479*795d594fSAndroid Build Coastguard Worker }
4480*795d594fSAndroid Build Coastguard Worker
VisitVarHandleCompareAndExchange(HInvoke * invoke)4481*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitVarHandleCompareAndExchange(HInvoke* invoke) {
4482*795d594fSAndroid Build Coastguard Worker GenerateVarHandleCompareAndSetOrExchange(
4483*795d594fSAndroid Build Coastguard Worker invoke, codegen_, std::memory_order_seq_cst, /*return_success=*/ false, /*strong=*/ true);
4484*795d594fSAndroid Build Coastguard Worker }
4485*795d594fSAndroid Build Coastguard Worker
VisitVarHandleCompareAndExchangeAcquire(HInvoke * invoke)4486*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitVarHandleCompareAndExchangeAcquire(HInvoke* invoke) {
4487*795d594fSAndroid Build Coastguard Worker CreateVarHandleCompareAndSetOrExchangeLocations(invoke, codegen_, /*return_success=*/ false);
4488*795d594fSAndroid Build Coastguard Worker }
4489*795d594fSAndroid Build Coastguard Worker
VisitVarHandleCompareAndExchangeAcquire(HInvoke * invoke)4490*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitVarHandleCompareAndExchangeAcquire(HInvoke* invoke) {
4491*795d594fSAndroid Build Coastguard Worker GenerateVarHandleCompareAndSetOrExchange(
4492*795d594fSAndroid Build Coastguard Worker invoke, codegen_, std::memory_order_acquire, /*return_success=*/ false, /*strong=*/ true);
4493*795d594fSAndroid Build Coastguard Worker }
4494*795d594fSAndroid Build Coastguard Worker
VisitVarHandleCompareAndExchangeRelease(HInvoke * invoke)4495*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitVarHandleCompareAndExchangeRelease(HInvoke* invoke) {
4496*795d594fSAndroid Build Coastguard Worker CreateVarHandleCompareAndSetOrExchangeLocations(invoke, codegen_, /*return_success=*/ false);
4497*795d594fSAndroid Build Coastguard Worker }
4498*795d594fSAndroid Build Coastguard Worker
VisitVarHandleCompareAndExchangeRelease(HInvoke * invoke)4499*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitVarHandleCompareAndExchangeRelease(HInvoke* invoke) {
4500*795d594fSAndroid Build Coastguard Worker GenerateVarHandleCompareAndSetOrExchange(
4501*795d594fSAndroid Build Coastguard Worker invoke, codegen_, std::memory_order_release, /*return_success=*/ false, /*strong=*/ true);
4502*795d594fSAndroid Build Coastguard Worker }
4503*795d594fSAndroid Build Coastguard Worker
VisitVarHandleCompareAndSet(HInvoke * invoke)4504*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitVarHandleCompareAndSet(HInvoke* invoke) {
4505*795d594fSAndroid Build Coastguard Worker CreateVarHandleCompareAndSetOrExchangeLocations(invoke, codegen_, /*return_success=*/ true);
4506*795d594fSAndroid Build Coastguard Worker }
4507*795d594fSAndroid Build Coastguard Worker
VisitVarHandleCompareAndSet(HInvoke * invoke)4508*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitVarHandleCompareAndSet(HInvoke* invoke) {
4509*795d594fSAndroid Build Coastguard Worker GenerateVarHandleCompareAndSetOrExchange(
4510*795d594fSAndroid Build Coastguard Worker invoke, codegen_, std::memory_order_seq_cst, /*return_success=*/ true, /*strong=*/ true);
4511*795d594fSAndroid Build Coastguard Worker }
4512*795d594fSAndroid Build Coastguard Worker
VisitVarHandleWeakCompareAndSet(HInvoke * invoke)4513*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitVarHandleWeakCompareAndSet(HInvoke* invoke) {
4514*795d594fSAndroid Build Coastguard Worker CreateVarHandleCompareAndSetOrExchangeLocations(invoke, codegen_, /*return_success=*/ true);
4515*795d594fSAndroid Build Coastguard Worker }
4516*795d594fSAndroid Build Coastguard Worker
VisitVarHandleWeakCompareAndSet(HInvoke * invoke)4517*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitVarHandleWeakCompareAndSet(HInvoke* invoke) {
4518*795d594fSAndroid Build Coastguard Worker GenerateVarHandleCompareAndSetOrExchange(
4519*795d594fSAndroid Build Coastguard Worker invoke, codegen_, std::memory_order_seq_cst, /*return_success=*/ true, /*strong=*/ false);
4520*795d594fSAndroid Build Coastguard Worker }
4521*795d594fSAndroid Build Coastguard Worker
VisitVarHandleWeakCompareAndSetAcquire(HInvoke * invoke)4522*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitVarHandleWeakCompareAndSetAcquire(HInvoke* invoke) {
4523*795d594fSAndroid Build Coastguard Worker CreateVarHandleCompareAndSetOrExchangeLocations(invoke, codegen_, /*return_success=*/ true);
4524*795d594fSAndroid Build Coastguard Worker }
4525*795d594fSAndroid Build Coastguard Worker
VisitVarHandleWeakCompareAndSetAcquire(HInvoke * invoke)4526*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitVarHandleWeakCompareAndSetAcquire(HInvoke* invoke) {
4527*795d594fSAndroid Build Coastguard Worker GenerateVarHandleCompareAndSetOrExchange(
4528*795d594fSAndroid Build Coastguard Worker invoke, codegen_, std::memory_order_acquire, /*return_success=*/ true, /*strong=*/ false);
4529*795d594fSAndroid Build Coastguard Worker }
4530*795d594fSAndroid Build Coastguard Worker
VisitVarHandleWeakCompareAndSetPlain(HInvoke * invoke)4531*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitVarHandleWeakCompareAndSetPlain(HInvoke* invoke) {
4532*795d594fSAndroid Build Coastguard Worker CreateVarHandleCompareAndSetOrExchangeLocations(invoke, codegen_, /*return_success=*/ true);
4533*795d594fSAndroid Build Coastguard Worker }
4534*795d594fSAndroid Build Coastguard Worker
VisitVarHandleWeakCompareAndSetPlain(HInvoke * invoke)4535*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitVarHandleWeakCompareAndSetPlain(HInvoke* invoke) {
4536*795d594fSAndroid Build Coastguard Worker GenerateVarHandleCompareAndSetOrExchange(
4537*795d594fSAndroid Build Coastguard Worker invoke, codegen_, std::memory_order_relaxed, /*return_success=*/ true, /*strong=*/ false);
4538*795d594fSAndroid Build Coastguard Worker }
4539*795d594fSAndroid Build Coastguard Worker
VisitVarHandleWeakCompareAndSetRelease(HInvoke * invoke)4540*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitVarHandleWeakCompareAndSetRelease(HInvoke* invoke) {
4541*795d594fSAndroid Build Coastguard Worker CreateVarHandleCompareAndSetOrExchangeLocations(invoke, codegen_, /*return_success=*/ true);
4542*795d594fSAndroid Build Coastguard Worker }
4543*795d594fSAndroid Build Coastguard Worker
VisitVarHandleWeakCompareAndSetRelease(HInvoke * invoke)4544*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitVarHandleWeakCompareAndSetRelease(HInvoke* invoke) {
4545*795d594fSAndroid Build Coastguard Worker GenerateVarHandleCompareAndSetOrExchange(
4546*795d594fSAndroid Build Coastguard Worker invoke, codegen_, std::memory_order_release, /*return_success=*/ true, /*strong=*/ false);
4547*795d594fSAndroid Build Coastguard Worker }
4548*795d594fSAndroid Build Coastguard Worker
CreateVarHandleGetAndUpdateLocations(HInvoke * invoke,CodeGeneratorRISCV64 * codegen,GetAndUpdateOp get_and_update_op)4549*795d594fSAndroid Build Coastguard Worker static void CreateVarHandleGetAndUpdateLocations(HInvoke* invoke,
4550*795d594fSAndroid Build Coastguard Worker CodeGeneratorRISCV64* codegen,
4551*795d594fSAndroid Build Coastguard Worker GetAndUpdateOp get_and_update_op) {
4552*795d594fSAndroid Build Coastguard Worker VarHandleOptimizations optimizations(invoke);
4553*795d594fSAndroid Build Coastguard Worker if (optimizations.GetDoNotIntrinsify()) {
4554*795d594fSAndroid Build Coastguard Worker return;
4555*795d594fSAndroid Build Coastguard Worker }
4556*795d594fSAndroid Build Coastguard Worker
4557*795d594fSAndroid Build Coastguard Worker // Get the type from the shorty as the invokes may not return a value.
4558*795d594fSAndroid Build Coastguard Worker uint32_t arg_index = invoke->GetNumberOfArguments() - 1;
4559*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(arg_index, 1u + GetExpectedVarHandleCoordinatesCount(invoke));
4560*795d594fSAndroid Build Coastguard Worker DataType::Type value_type = GetDataTypeFromShorty(invoke, arg_index);
4561*795d594fSAndroid Build Coastguard Worker if (value_type == DataType::Type::kReference && codegen->EmitNonBakerReadBarrier()) {
4562*795d594fSAndroid Build Coastguard Worker // Unsupported for non-Baker read barrier because the artReadBarrierSlow() ignores
4563*795d594fSAndroid Build Coastguard Worker // the passed reference and reloads it from the field, thus seeing the new value
4564*795d594fSAndroid Build Coastguard Worker // that we have just stored. (And it also gets the memory visibility wrong.) b/173104084
4565*795d594fSAndroid Build Coastguard Worker return;
4566*795d594fSAndroid Build Coastguard Worker }
4567*795d594fSAndroid Build Coastguard Worker
4568*795d594fSAndroid Build Coastguard Worker // TODO(riscv64): Fix this intrinsic for heap poisoning configuration.
4569*795d594fSAndroid Build Coastguard Worker if (kPoisonHeapReferences && value_type == DataType::Type::kReference) {
4570*795d594fSAndroid Build Coastguard Worker return;
4571*795d594fSAndroid Build Coastguard Worker }
4572*795d594fSAndroid Build Coastguard Worker
4573*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = CreateVarHandleCommonLocations(invoke, codegen);
4574*795d594fSAndroid Build Coastguard Worker Location arg = locations->InAt(arg_index);
4575*795d594fSAndroid Build Coastguard Worker
4576*795d594fSAndroid Build Coastguard Worker bool is_fp = DataType::IsFloatingPointType(value_type);
4577*795d594fSAndroid Build Coastguard Worker if (is_fp) {
4578*795d594fSAndroid Build Coastguard Worker if (get_and_update_op == GetAndUpdateOp::kAdd) {
4579*795d594fSAndroid Build Coastguard Worker // For ADD, do not use ZR for zero bit pattern (+0.0f or +0.0).
4580*795d594fSAndroid Build Coastguard Worker locations->SetInAt(arg_index, Location::RequiresFpuRegister());
4581*795d594fSAndroid Build Coastguard Worker } else {
4582*795d594fSAndroid Build Coastguard Worker DCHECK(get_and_update_op == GetAndUpdateOp::kSet);
4583*795d594fSAndroid Build Coastguard Worker }
4584*795d594fSAndroid Build Coastguard Worker }
4585*795d594fSAndroid Build Coastguard Worker
4586*795d594fSAndroid Build Coastguard Worker size_t data_size = DataType::Size(value_type);
4587*795d594fSAndroid Build Coastguard Worker bool can_byte_swap =
4588*795d594fSAndroid Build Coastguard Worker (arg_index == 3u) && (value_type != DataType::Type::kReference && data_size != 1u);
4589*795d594fSAndroid Build Coastguard Worker bool can_use_cas = (get_and_update_op == GetAndUpdateOp::kAdd) && (can_byte_swap || is_fp);
4590*795d594fSAndroid Build Coastguard Worker bool is_small = (data_size < 4u);
4591*795d594fSAndroid Build Coastguard Worker bool is_small_and = is_small && (get_and_update_op == GetAndUpdateOp::kAnd);
4592*795d594fSAndroid Build Coastguard Worker bool is_bitwise =
4593*795d594fSAndroid Build Coastguard Worker (get_and_update_op != GetAndUpdateOp::kSet && get_and_update_op != GetAndUpdateOp::kAdd);
4594*795d594fSAndroid Build Coastguard Worker
4595*795d594fSAndroid Build Coastguard Worker size_t temps_needed =
4596*795d594fSAndroid Build Coastguard Worker // The offset temp is used for the `tmp_ptr`.
4597*795d594fSAndroid Build Coastguard Worker 1u +
4598*795d594fSAndroid Build Coastguard Worker // For small values, we need temps for `shift` and maybe also `mask` and `temp`.
4599*795d594fSAndroid Build Coastguard Worker (is_small ? (is_bitwise ? 1u : 3u) : 0u) +
4600*795d594fSAndroid Build Coastguard Worker // Some cases need modified copies of `arg`.
4601*795d594fSAndroid Build Coastguard Worker (is_small_and || ScratchXRegisterNeeded(arg, value_type, can_byte_swap) ? 1u : 0u) +
4602*795d594fSAndroid Build Coastguard Worker // For FP types, we need a temp for `old_value` which cannot be loaded directly to `out`.
4603*795d594fSAndroid Build Coastguard Worker (is_fp ? 1u : 0u);
4604*795d594fSAndroid Build Coastguard Worker if (can_use_cas) {
4605*795d594fSAndroid Build Coastguard Worker size_t cas_temps_needed =
4606*795d594fSAndroid Build Coastguard Worker // The offset temp is used for the `tmp_ptr`.
4607*795d594fSAndroid Build Coastguard Worker 1u +
4608*795d594fSAndroid Build Coastguard Worker // For small values, we need a temp for `shift`.
4609*795d594fSAndroid Build Coastguard Worker (is_small ? 1u : 0u) +
4610*795d594fSAndroid Build Coastguard Worker // And we always need temps for `old_value`, `new_value` and `reloaded_old_value`.
4611*795d594fSAndroid Build Coastguard Worker 3u;
4612*795d594fSAndroid Build Coastguard Worker DCHECK_GE(cas_temps_needed, temps_needed);
4613*795d594fSAndroid Build Coastguard Worker temps_needed = cas_temps_needed;
4614*795d594fSAndroid Build Coastguard Worker }
4615*795d594fSAndroid Build Coastguard Worker
4616*795d594fSAndroid Build Coastguard Worker size_t scratch_registers_available = 2u;
4617*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(scratch_registers_available,
4618*795d594fSAndroid Build Coastguard Worker ScratchRegisterScope(codegen->GetAssembler()).AvailableXRegisters());
4619*795d594fSAndroid Build Coastguard Worker size_t old_temp_count = locations->GetTempCount();
4620*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(old_temp_count, (arg_index == 1u) ? 2u : 1u);
4621*795d594fSAndroid Build Coastguard Worker if (temps_needed > old_temp_count + scratch_registers_available) {
4622*795d594fSAndroid Build Coastguard Worker locations->AddRegisterTemps(temps_needed - (old_temp_count + scratch_registers_available));
4623*795d594fSAndroid Build Coastguard Worker }
4624*795d594fSAndroid Build Coastguard Worker
4625*795d594fSAndroid Build Coastguard Worker // Request another temporary register for methods that don't return a value.
4626*795d594fSAndroid Build Coastguard Worker // For the non-void case, we already set `out` in `CreateVarHandleCommonLocations`.
4627*795d594fSAndroid Build Coastguard Worker DataType::Type return_type = invoke->GetType();
4628*795d594fSAndroid Build Coastguard Worker const bool is_void = return_type == DataType::Type::kVoid;
4629*795d594fSAndroid Build Coastguard Worker DCHECK_IMPLIES(!is_void, return_type == value_type);
4630*795d594fSAndroid Build Coastguard Worker if (is_void) {
4631*795d594fSAndroid Build Coastguard Worker if (DataType::IsFloatingPointType(value_type)) {
4632*795d594fSAndroid Build Coastguard Worker locations->AddTemp(Location::RequiresFpuRegister());
4633*795d594fSAndroid Build Coastguard Worker } else {
4634*795d594fSAndroid Build Coastguard Worker locations->AddTemp(Location::RequiresRegister());
4635*795d594fSAndroid Build Coastguard Worker }
4636*795d594fSAndroid Build Coastguard Worker }
4637*795d594fSAndroid Build Coastguard Worker }
4638*795d594fSAndroid Build Coastguard Worker
GenerateVarHandleGetAndUpdate(HInvoke * invoke,CodeGeneratorRISCV64 * codegen,GetAndUpdateOp get_and_update_op,std::memory_order order,bool byte_swap=false)4639*795d594fSAndroid Build Coastguard Worker static void GenerateVarHandleGetAndUpdate(HInvoke* invoke,
4640*795d594fSAndroid Build Coastguard Worker CodeGeneratorRISCV64* codegen,
4641*795d594fSAndroid Build Coastguard Worker GetAndUpdateOp get_and_update_op,
4642*795d594fSAndroid Build Coastguard Worker std::memory_order order,
4643*795d594fSAndroid Build Coastguard Worker bool byte_swap = false) {
4644*795d594fSAndroid Build Coastguard Worker // Get the type from the shorty as the invokes may not return a value.
4645*795d594fSAndroid Build Coastguard Worker uint32_t arg_index = invoke->GetNumberOfArguments() - 1;
4646*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(arg_index, 1u + GetExpectedVarHandleCoordinatesCount(invoke));
4647*795d594fSAndroid Build Coastguard Worker DataType::Type value_type = GetDataTypeFromShorty(invoke, arg_index);
4648*795d594fSAndroid Build Coastguard Worker
4649*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = codegen->GetAssembler();
4650*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = invoke->GetLocations();
4651*795d594fSAndroid Build Coastguard Worker Location arg = locations->InAt(arg_index);
4652*795d594fSAndroid Build Coastguard Worker DCHECK_IMPLIES(arg.IsConstant(), arg.GetConstant()->IsZeroBitPattern());
4653*795d594fSAndroid Build Coastguard Worker DataType::Type return_type = invoke->GetType();
4654*795d594fSAndroid Build Coastguard Worker const bool is_void = return_type == DataType::Type::kVoid;
4655*795d594fSAndroid Build Coastguard Worker DCHECK_IMPLIES(!is_void, return_type == value_type);
4656*795d594fSAndroid Build Coastguard Worker // We use a temporary for void methods, as we don't return the value.
4657*795d594fSAndroid Build Coastguard Worker Location out_or_temp =
4658*795d594fSAndroid Build Coastguard Worker is_void ? locations->GetTemp(locations->GetTempCount() - 1u) : locations->Out();
4659*795d594fSAndroid Build Coastguard Worker
4660*795d594fSAndroid Build Coastguard Worker VarHandleTarget target = GetVarHandleTarget(invoke);
4661*795d594fSAndroid Build Coastguard Worker VarHandleSlowPathRISCV64* slow_path = nullptr;
4662*795d594fSAndroid Build Coastguard Worker if (!byte_swap) {
4663*795d594fSAndroid Build Coastguard Worker slow_path = GenerateVarHandleChecks(invoke, codegen, order, value_type);
4664*795d594fSAndroid Build Coastguard Worker GenerateVarHandleTarget(invoke, target, codegen);
4665*795d594fSAndroid Build Coastguard Worker if (slow_path != nullptr) {
4666*795d594fSAndroid Build Coastguard Worker slow_path->SetGetAndUpdateOp(get_and_update_op);
4667*795d594fSAndroid Build Coastguard Worker __ Bind(slow_path->GetNativeByteOrderLabel());
4668*795d594fSAndroid Build Coastguard Worker }
4669*795d594fSAndroid Build Coastguard Worker }
4670*795d594fSAndroid Build Coastguard Worker
4671*795d594fSAndroid Build Coastguard Worker // This needs to be before the temp registers, as MarkGCCard also uses scratch registers.
4672*795d594fSAndroid Build Coastguard Worker if (CodeGenerator::StoreNeedsWriteBarrier(value_type, invoke->InputAt(arg_index))) {
4673*795d594fSAndroid Build Coastguard Worker DCHECK(get_and_update_op == GetAndUpdateOp::kSet);
4674*795d594fSAndroid Build Coastguard Worker // Mark card for object, the new value shall be stored.
4675*795d594fSAndroid Build Coastguard Worker bool new_value_can_be_null = true; // TODO: Worth finding out this information?
4676*795d594fSAndroid Build Coastguard Worker codegen->MaybeMarkGCCard(target.object, arg.AsRegister<XRegister>(), new_value_can_be_null);
4677*795d594fSAndroid Build Coastguard Worker }
4678*795d594fSAndroid Build Coastguard Worker
4679*795d594fSAndroid Build Coastguard Worker size_t data_size = DataType::Size(value_type);
4680*795d594fSAndroid Build Coastguard Worker bool is_fp = DataType::IsFloatingPointType(value_type);
4681*795d594fSAndroid Build Coastguard Worker bool use_cas = (get_and_update_op == GetAndUpdateOp::kAdd) && (byte_swap || is_fp);
4682*795d594fSAndroid Build Coastguard Worker bool is_small = (data_size < 4u);
4683*795d594fSAndroid Build Coastguard Worker bool is_small_and = is_small && (get_and_update_op == GetAndUpdateOp::kAnd);
4684*795d594fSAndroid Build Coastguard Worker bool is_reference = (value_type == DataType::Type::kReference);
4685*795d594fSAndroid Build Coastguard Worker DataType::Type op_type = is_fp
4686*795d594fSAndroid Build Coastguard Worker ? IntTypeForFloatingPointType(value_type)
4687*795d594fSAndroid Build Coastguard Worker : (is_small || is_reference ? DataType::Type::kInt32 : value_type);
4688*795d594fSAndroid Build Coastguard Worker
4689*795d594fSAndroid Build Coastguard Worker ScratchRegisterScope srs(assembler);
4690*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(srs.AvailableXRegisters(), 2u);
4691*795d594fSAndroid Build Coastguard Worker size_t available_scratch_registers = use_cas
4692*795d594fSAndroid Build Coastguard Worker // We use scratch registers differently for the CAS path.
4693*795d594fSAndroid Build Coastguard Worker ? 0u
4694*795d594fSAndroid Build Coastguard Worker // Reserve one scratch register for `PrepareXRegister()` or similar `arg_reg` allocation.
4695*795d594fSAndroid Build Coastguard Worker : (is_small_and || ScratchXRegisterNeeded(arg, value_type, byte_swap) ? 1u : 2u);
4696*795d594fSAndroid Build Coastguard Worker
4697*795d594fSAndroid Build Coastguard Worker // Reuse the `target.offset` temporary for the pointer to the target location,
4698*795d594fSAndroid Build Coastguard Worker // except for references that need the offset for the non-Baker read barrier.
4699*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(target.offset, locations->GetTemp(0u).AsRegister<XRegister>());
4700*795d594fSAndroid Build Coastguard Worker size_t next_temp = 1u;
4701*795d594fSAndroid Build Coastguard Worker XRegister tmp_ptr = target.offset;
4702*795d594fSAndroid Build Coastguard Worker if (is_reference && codegen->EmitNonBakerReadBarrier()) {
4703*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(available_scratch_registers, 2u);
4704*795d594fSAndroid Build Coastguard Worker available_scratch_registers -= 1u;
4705*795d594fSAndroid Build Coastguard Worker tmp_ptr = srs.AllocateXRegister();
4706*795d594fSAndroid Build Coastguard Worker }
4707*795d594fSAndroid Build Coastguard Worker __ Add(tmp_ptr, target.object, target.offset);
4708*795d594fSAndroid Build Coastguard Worker
4709*795d594fSAndroid Build Coastguard Worker auto get_temp = [&]() {
4710*795d594fSAndroid Build Coastguard Worker if (available_scratch_registers != 0u) {
4711*795d594fSAndroid Build Coastguard Worker available_scratch_registers -= 1u;
4712*795d594fSAndroid Build Coastguard Worker return srs.AllocateXRegister();
4713*795d594fSAndroid Build Coastguard Worker } else {
4714*795d594fSAndroid Build Coastguard Worker DCHECK_IMPLIES(is_void, next_temp != locations->GetTempCount() - 1u)
4715*795d594fSAndroid Build Coastguard Worker << "The last temp is special for the void case, as it represents the out register.";
4716*795d594fSAndroid Build Coastguard Worker XRegister temp = locations->GetTemp(next_temp).AsRegister<XRegister>();
4717*795d594fSAndroid Build Coastguard Worker next_temp += 1u;
4718*795d594fSAndroid Build Coastguard Worker return temp;
4719*795d594fSAndroid Build Coastguard Worker }
4720*795d594fSAndroid Build Coastguard Worker };
4721*795d594fSAndroid Build Coastguard Worker
4722*795d594fSAndroid Build Coastguard Worker XRegister shift = kNoXRegister;
4723*795d594fSAndroid Build Coastguard Worker XRegister mask = kNoXRegister;
4724*795d594fSAndroid Build Coastguard Worker XRegister prepare_mask = kNoXRegister;
4725*795d594fSAndroid Build Coastguard Worker XRegister temp = kNoXRegister;
4726*795d594fSAndroid Build Coastguard Worker XRegister arg_reg = kNoXRegister;
4727*795d594fSAndroid Build Coastguard Worker if (is_small) {
4728*795d594fSAndroid Build Coastguard Worker shift = get_temp();
4729*795d594fSAndroid Build Coastguard Worker // Upper bits of the shift are not used, so we do not need to clear them.
4730*795d594fSAndroid Build Coastguard Worker __ Slli(shift, tmp_ptr, WhichPowerOf2(kBitsPerByte));
4731*795d594fSAndroid Build Coastguard Worker __ Andi(tmp_ptr, tmp_ptr, -4);
4732*795d594fSAndroid Build Coastguard Worker switch (get_and_update_op) {
4733*795d594fSAndroid Build Coastguard Worker case GetAndUpdateOp::kAdd:
4734*795d594fSAndroid Build Coastguard Worker if (byte_swap) {
4735*795d594fSAndroid Build Coastguard Worker // The mask is not needed in the CAS path.
4736*795d594fSAndroid Build Coastguard Worker DCHECK(use_cas);
4737*795d594fSAndroid Build Coastguard Worker break;
4738*795d594fSAndroid Build Coastguard Worker }
4739*795d594fSAndroid Build Coastguard Worker FALLTHROUGH_INTENDED;
4740*795d594fSAndroid Build Coastguard Worker case GetAndUpdateOp::kSet:
4741*795d594fSAndroid Build Coastguard Worker mask = get_temp();
4742*795d594fSAndroid Build Coastguard Worker temp = get_temp();
4743*795d594fSAndroid Build Coastguard Worker __ Li(mask, (1 << (data_size * kBitsPerByte)) - 1);
4744*795d594fSAndroid Build Coastguard Worker __ Sllw(mask, mask, shift);
4745*795d594fSAndroid Build Coastguard Worker // The argument does not need to be masked for `GetAndUpdateOp::kAdd`,
4746*795d594fSAndroid Build Coastguard Worker // the mask shall be applied after the ADD instruction.
4747*795d594fSAndroid Build Coastguard Worker prepare_mask = (get_and_update_op == GetAndUpdateOp::kSet) ? mask : kNoXRegister;
4748*795d594fSAndroid Build Coastguard Worker break;
4749*795d594fSAndroid Build Coastguard Worker case GetAndUpdateOp::kAnd:
4750*795d594fSAndroid Build Coastguard Worker // We need to set all other bits, so we always need a temp.
4751*795d594fSAndroid Build Coastguard Worker arg_reg = srs.AllocateXRegister();
4752*795d594fSAndroid Build Coastguard Worker if (data_size == 1u) {
4753*795d594fSAndroid Build Coastguard Worker __ Ori(arg_reg, InputXRegisterOrZero(arg), ~0xff);
4754*795d594fSAndroid Build Coastguard Worker DCHECK(!byte_swap);
4755*795d594fSAndroid Build Coastguard Worker } else {
4756*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(data_size, 2u);
4757*795d594fSAndroid Build Coastguard Worker __ Li(arg_reg, ~0xffff);
4758*795d594fSAndroid Build Coastguard Worker __ Or(arg_reg, InputXRegisterOrZero(arg), arg_reg);
4759*795d594fSAndroid Build Coastguard Worker if (byte_swap) {
4760*795d594fSAndroid Build Coastguard Worker __ Rev8(arg_reg, arg_reg);
4761*795d594fSAndroid Build Coastguard Worker __ Rori(arg_reg, arg_reg, 48);
4762*795d594fSAndroid Build Coastguard Worker }
4763*795d594fSAndroid Build Coastguard Worker }
4764*795d594fSAndroid Build Coastguard Worker __ Rolw(arg_reg, arg_reg, shift);
4765*795d594fSAndroid Build Coastguard Worker break;
4766*795d594fSAndroid Build Coastguard Worker case GetAndUpdateOp::kOr:
4767*795d594fSAndroid Build Coastguard Worker case GetAndUpdateOp::kXor:
4768*795d594fSAndroid Build Coastguard Worker // Signed values need to be truncated but we're keeping `prepare_mask == kNoXRegister`.
4769*795d594fSAndroid Build Coastguard Worker if (value_type == DataType::Type::kInt8 && !arg.IsConstant()) {
4770*795d594fSAndroid Build Coastguard Worker DCHECK(!byte_swap);
4771*795d594fSAndroid Build Coastguard Worker arg_reg = srs.AllocateXRegister();
4772*795d594fSAndroid Build Coastguard Worker __ ZextB(arg_reg, arg.AsRegister<XRegister>());
4773*795d594fSAndroid Build Coastguard Worker __ Sllw(arg_reg, arg_reg, shift);
4774*795d594fSAndroid Build Coastguard Worker } else if (value_type == DataType::Type::kInt16 && !arg.IsConstant() && !byte_swap) {
4775*795d594fSAndroid Build Coastguard Worker arg_reg = srs.AllocateXRegister();
4776*795d594fSAndroid Build Coastguard Worker __ ZextH(arg_reg, arg.AsRegister<XRegister>());
4777*795d594fSAndroid Build Coastguard Worker __ Sllw(arg_reg, arg_reg, shift);
4778*795d594fSAndroid Build Coastguard Worker } // else handled by `PrepareXRegister()` below.
4779*795d594fSAndroid Build Coastguard Worker break;
4780*795d594fSAndroid Build Coastguard Worker }
4781*795d594fSAndroid Build Coastguard Worker }
4782*795d594fSAndroid Build Coastguard Worker if (arg_reg == kNoXRegister && !use_cas) {
4783*795d594fSAndroid Build Coastguard Worker arg_reg = PrepareXRegister(codegen, arg, value_type, shift, prepare_mask, byte_swap, &srs);
4784*795d594fSAndroid Build Coastguard Worker }
4785*795d594fSAndroid Build Coastguard Worker if (mask != kNoXRegister && get_and_update_op == GetAndUpdateOp::kSet) {
4786*795d594fSAndroid Build Coastguard Worker __ Not(mask, mask); // We need to flip the mask for `kSet`, see `GenerateGetAndUpdate()`.
4787*795d594fSAndroid Build Coastguard Worker }
4788*795d594fSAndroid Build Coastguard Worker
4789*795d594fSAndroid Build Coastguard Worker if (use_cas) {
4790*795d594fSAndroid Build Coastguard Worker // Allocate scratch registers for temps that can theoretically be clobbered on retry.
4791*795d594fSAndroid Build Coastguard Worker // (Even though the `retry` label shall never be far enough for `TMP` to be clobbered.)
4792*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(available_scratch_registers, 0u); // Reserved for the two uses below.
4793*795d594fSAndroid Build Coastguard Worker XRegister old_value = srs.AllocateXRegister();
4794*795d594fSAndroid Build Coastguard Worker XRegister new_value = srs.AllocateXRegister();
4795*795d594fSAndroid Build Coastguard Worker // Allocate other needed temporaries.
4796*795d594fSAndroid Build Coastguard Worker XRegister reloaded_old_value = get_temp();
4797*795d594fSAndroid Build Coastguard Worker XRegister store_result = reloaded_old_value; // Clobber reloaded old value by store result.
4798*795d594fSAndroid Build Coastguard Worker FRegister ftmp = is_fp ? srs.AllocateFRegister() : kNoFRegister;
4799*795d594fSAndroid Build Coastguard Worker
4800*795d594fSAndroid Build Coastguard Worker Riscv64Label retry;
4801*795d594fSAndroid Build Coastguard Worker __ Bind(&retry);
4802*795d594fSAndroid Build Coastguard Worker codegen->GetInstructionVisitor()->Load(
4803*795d594fSAndroid Build Coastguard Worker Location::RegisterLocation(old_value), tmp_ptr, /*offset=*/ 0, op_type);
4804*795d594fSAndroid Build Coastguard Worker if (byte_swap) {
4805*795d594fSAndroid Build Coastguard Worker GenerateByteSwapAndExtract(codegen, out_or_temp, old_value, shift, value_type);
4806*795d594fSAndroid Build Coastguard Worker } else {
4807*795d594fSAndroid Build Coastguard Worker DCHECK(is_fp);
4808*795d594fSAndroid Build Coastguard Worker codegen->MoveLocation(out_or_temp, Location::RegisterLocation(old_value), value_type);
4809*795d594fSAndroid Build Coastguard Worker }
4810*795d594fSAndroid Build Coastguard Worker if (is_fp) {
4811*795d594fSAndroid Build Coastguard Worker codegen->GetInstructionVisitor()->FAdd(
4812*795d594fSAndroid Build Coastguard Worker ftmp, out_or_temp.AsFpuRegister<FRegister>(), arg.AsFpuRegister<FRegister>(), value_type);
4813*795d594fSAndroid Build Coastguard Worker codegen->MoveLocation(
4814*795d594fSAndroid Build Coastguard Worker Location::RegisterLocation(new_value), Location::FpuRegisterLocation(ftmp), op_type);
4815*795d594fSAndroid Build Coastguard Worker } else if (arg.IsConstant()) {
4816*795d594fSAndroid Build Coastguard Worker DCHECK(arg.GetConstant()->IsZeroBitPattern());
4817*795d594fSAndroid Build Coastguard Worker __ Mv(new_value, out_or_temp.AsRegister<XRegister>());
4818*795d594fSAndroid Build Coastguard Worker } else if (value_type == DataType::Type::kInt64) {
4819*795d594fSAndroid Build Coastguard Worker __ Add(new_value, out_or_temp.AsRegister<XRegister>(), arg.AsRegister<XRegister>());
4820*795d594fSAndroid Build Coastguard Worker } else {
4821*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(op_type, DataType::Type::kInt32);
4822*795d594fSAndroid Build Coastguard Worker __ Addw(new_value, out_or_temp.AsRegister<XRegister>(), arg.AsRegister<XRegister>());
4823*795d594fSAndroid Build Coastguard Worker }
4824*795d594fSAndroid Build Coastguard Worker if (byte_swap) {
4825*795d594fSAndroid Build Coastguard Worker DataType::Type swap_type = op_type;
4826*795d594fSAndroid Build Coastguard Worker if (is_small) {
4827*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(data_size, 2u);
4828*795d594fSAndroid Build Coastguard Worker // We want to update only 16 bits of the 32-bit location. The 16 bits we want to replace
4829*795d594fSAndroid Build Coastguard Worker // are present in both `old_value` and `out` but in different bits and byte order.
4830*795d594fSAndroid Build Coastguard Worker // To update the 16 bits, we can XOR the new value with the `out`, byte swap as Uint16
4831*795d594fSAndroid Build Coastguard Worker // (extracting only the bits we want to update), shift and XOR with the old value.
4832*795d594fSAndroid Build Coastguard Worker swap_type = DataType::Type::kUint16;
4833*795d594fSAndroid Build Coastguard Worker __ Xor(new_value, new_value, out_or_temp.AsRegister<XRegister>());
4834*795d594fSAndroid Build Coastguard Worker }
4835*795d594fSAndroid Build Coastguard Worker GenerateReverseBytes(codegen, Location::RegisterLocation(new_value), new_value, swap_type);
4836*795d594fSAndroid Build Coastguard Worker if (is_small) {
4837*795d594fSAndroid Build Coastguard Worker __ Sllw(new_value, new_value, shift);
4838*795d594fSAndroid Build Coastguard Worker __ Xor(new_value, new_value, old_value);
4839*795d594fSAndroid Build Coastguard Worker }
4840*795d594fSAndroid Build Coastguard Worker }
4841*795d594fSAndroid Build Coastguard Worker GenerateCompareAndSet(assembler,
4842*795d594fSAndroid Build Coastguard Worker op_type,
4843*795d594fSAndroid Build Coastguard Worker order,
4844*795d594fSAndroid Build Coastguard Worker /*strong=*/ true,
4845*795d594fSAndroid Build Coastguard Worker /*cmp_failure=*/ &retry,
4846*795d594fSAndroid Build Coastguard Worker tmp_ptr,
4847*795d594fSAndroid Build Coastguard Worker new_value,
4848*795d594fSAndroid Build Coastguard Worker /*old_value=*/ reloaded_old_value,
4849*795d594fSAndroid Build Coastguard Worker /*mask=*/ kNoXRegister,
4850*795d594fSAndroid Build Coastguard Worker /*masked=*/ kNoXRegister,
4851*795d594fSAndroid Build Coastguard Worker store_result,
4852*795d594fSAndroid Build Coastguard Worker /*expected=*/ old_value);
4853*795d594fSAndroid Build Coastguard Worker } else {
4854*795d594fSAndroid Build Coastguard Worker XRegister old_value = is_fp ? get_temp() : out_or_temp.AsRegister<XRegister>();
4855*795d594fSAndroid Build Coastguard Worker GenerateGetAndUpdate(
4856*795d594fSAndroid Build Coastguard Worker codegen, get_and_update_op, op_type, order, tmp_ptr, arg_reg, old_value, mask, temp);
4857*795d594fSAndroid Build Coastguard Worker if (byte_swap) {
4858*795d594fSAndroid Build Coastguard Worker DCHECK_IMPLIES(is_small, out_or_temp.AsRegister<XRegister>() == old_value)
4859*795d594fSAndroid Build Coastguard Worker << " " << value_type << " " << out_or_temp.AsRegister<XRegister>() << "!=" << old_value;
4860*795d594fSAndroid Build Coastguard Worker GenerateByteSwapAndExtract(codegen, out_or_temp, old_value, shift, value_type);
4861*795d594fSAndroid Build Coastguard Worker } else if (is_fp) {
4862*795d594fSAndroid Build Coastguard Worker codegen->MoveLocation(out_or_temp, Location::RegisterLocation(old_value), value_type);
4863*795d594fSAndroid Build Coastguard Worker } else if (is_small) {
4864*795d594fSAndroid Build Coastguard Worker __ Srlw(old_value, old_value, shift);
4865*795d594fSAndroid Build Coastguard Worker DCHECK_NE(value_type, DataType::Type::kUint8);
4866*795d594fSAndroid Build Coastguard Worker if (value_type == DataType::Type::kInt8) {
4867*795d594fSAndroid Build Coastguard Worker __ SextB(old_value, old_value);
4868*795d594fSAndroid Build Coastguard Worker } else if (value_type == DataType::Type::kBool) {
4869*795d594fSAndroid Build Coastguard Worker __ ZextB(old_value, old_value);
4870*795d594fSAndroid Build Coastguard Worker } else if (value_type == DataType::Type::kInt16) {
4871*795d594fSAndroid Build Coastguard Worker __ SextH(old_value, old_value);
4872*795d594fSAndroid Build Coastguard Worker } else {
4873*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(value_type, DataType::Type::kUint16);
4874*795d594fSAndroid Build Coastguard Worker __ ZextH(old_value, old_value);
4875*795d594fSAndroid Build Coastguard Worker }
4876*795d594fSAndroid Build Coastguard Worker } else if (is_reference) {
4877*795d594fSAndroid Build Coastguard Worker __ ZextW(old_value, old_value);
4878*795d594fSAndroid Build Coastguard Worker if (codegen->EmitBakerReadBarrier()) {
4879*795d594fSAndroid Build Coastguard Worker // Use RA as temp. It is clobbered in the slow path anyway.
4880*795d594fSAndroid Build Coastguard Worker static constexpr Location kBakerReadBarrierTemp = Location::RegisterLocation(RA);
4881*795d594fSAndroid Build Coastguard Worker SlowPathCodeRISCV64* rb_slow_path = codegen->AddGcRootBakerBarrierBarrierSlowPath(
4882*795d594fSAndroid Build Coastguard Worker invoke, out_or_temp, kBakerReadBarrierTemp);
4883*795d594fSAndroid Build Coastguard Worker codegen->EmitBakerReadBarierMarkingCheck(rb_slow_path, out_or_temp, kBakerReadBarrierTemp);
4884*795d594fSAndroid Build Coastguard Worker } else if (codegen->EmitNonBakerReadBarrier()) {
4885*795d594fSAndroid Build Coastguard Worker Location base_loc = Location::RegisterLocation(target.object);
4886*795d594fSAndroid Build Coastguard Worker Location index = Location::RegisterLocation(target.offset);
4887*795d594fSAndroid Build Coastguard Worker SlowPathCodeRISCV64* rb_slow_path = codegen->AddReadBarrierSlowPath(
4888*795d594fSAndroid Build Coastguard Worker invoke, out_or_temp, out_or_temp, base_loc, /*offset=*/ 0u, index);
4889*795d594fSAndroid Build Coastguard Worker __ J(rb_slow_path->GetEntryLabel());
4890*795d594fSAndroid Build Coastguard Worker __ Bind(rb_slow_path->GetExitLabel());
4891*795d594fSAndroid Build Coastguard Worker }
4892*795d594fSAndroid Build Coastguard Worker }
4893*795d594fSAndroid Build Coastguard Worker }
4894*795d594fSAndroid Build Coastguard Worker
4895*795d594fSAndroid Build Coastguard Worker if (slow_path != nullptr) {
4896*795d594fSAndroid Build Coastguard Worker DCHECK(!byte_swap);
4897*795d594fSAndroid Build Coastguard Worker __ Bind(slow_path->GetExitLabel());
4898*795d594fSAndroid Build Coastguard Worker }
4899*795d594fSAndroid Build Coastguard Worker
4900*795d594fSAndroid Build Coastguard Worker // Check that we have allocated the right number of temps. We may need more registers
4901*795d594fSAndroid Build Coastguard Worker // for byte swapped CAS in the slow path, so skip this check for the main path in that case.
4902*795d594fSAndroid Build Coastguard Worker // In the void case, we requested an extra register to mimic the `out` register.
4903*795d594fSAndroid Build Coastguard Worker const size_t extra_temp_registers = is_void ? 1u : 0u;
4904*795d594fSAndroid Build Coastguard Worker bool has_byte_swap = (arg_index == 3u) && (!is_reference && data_size != 1u);
4905*795d594fSAndroid Build Coastguard Worker if ((!has_byte_swap || byte_swap) &&
4906*795d594fSAndroid Build Coastguard Worker next_temp != locations->GetTempCount() - extra_temp_registers) {
4907*795d594fSAndroid Build Coastguard Worker // We allocate a temporary register for the class object for a static field `VarHandle` but
4908*795d594fSAndroid Build Coastguard Worker // we do not update the `next_temp` if it's otherwise unused after the address calculation.
4909*795d594fSAndroid Build Coastguard Worker CHECK_EQ(arg_index, 1u);
4910*795d594fSAndroid Build Coastguard Worker CHECK_EQ(next_temp, 1u);
4911*795d594fSAndroid Build Coastguard Worker CHECK_EQ(locations->GetTempCount(), 2u + extra_temp_registers);
4912*795d594fSAndroid Build Coastguard Worker }
4913*795d594fSAndroid Build Coastguard Worker }
4914*795d594fSAndroid Build Coastguard Worker
VisitVarHandleGetAndSet(HInvoke * invoke)4915*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitVarHandleGetAndSet(HInvoke* invoke) {
4916*795d594fSAndroid Build Coastguard Worker CreateVarHandleGetAndUpdateLocations(invoke, codegen_, GetAndUpdateOp::kSet);
4917*795d594fSAndroid Build Coastguard Worker }
4918*795d594fSAndroid Build Coastguard Worker
VisitVarHandleGetAndSet(HInvoke * invoke)4919*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitVarHandleGetAndSet(HInvoke* invoke) {
4920*795d594fSAndroid Build Coastguard Worker GenerateVarHandleGetAndUpdate(invoke, codegen_, GetAndUpdateOp::kSet, std::memory_order_seq_cst);
4921*795d594fSAndroid Build Coastguard Worker }
4922*795d594fSAndroid Build Coastguard Worker
VisitVarHandleGetAndSetAcquire(HInvoke * invoke)4923*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitVarHandleGetAndSetAcquire(HInvoke* invoke) {
4924*795d594fSAndroid Build Coastguard Worker CreateVarHandleGetAndUpdateLocations(invoke, codegen_, GetAndUpdateOp::kSet);
4925*795d594fSAndroid Build Coastguard Worker }
4926*795d594fSAndroid Build Coastguard Worker
VisitVarHandleGetAndSetAcquire(HInvoke * invoke)4927*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitVarHandleGetAndSetAcquire(HInvoke* invoke) {
4928*795d594fSAndroid Build Coastguard Worker GenerateVarHandleGetAndUpdate(invoke, codegen_, GetAndUpdateOp::kSet, std::memory_order_acquire);
4929*795d594fSAndroid Build Coastguard Worker }
4930*795d594fSAndroid Build Coastguard Worker
VisitVarHandleGetAndSetRelease(HInvoke * invoke)4931*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitVarHandleGetAndSetRelease(HInvoke* invoke) {
4932*795d594fSAndroid Build Coastguard Worker CreateVarHandleGetAndUpdateLocations(invoke, codegen_, GetAndUpdateOp::kSet);
4933*795d594fSAndroid Build Coastguard Worker }
4934*795d594fSAndroid Build Coastguard Worker
VisitVarHandleGetAndSetRelease(HInvoke * invoke)4935*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitVarHandleGetAndSetRelease(HInvoke* invoke) {
4936*795d594fSAndroid Build Coastguard Worker GenerateVarHandleGetAndUpdate(invoke, codegen_, GetAndUpdateOp::kSet, std::memory_order_release);
4937*795d594fSAndroid Build Coastguard Worker }
4938*795d594fSAndroid Build Coastguard Worker
VisitVarHandleGetAndAdd(HInvoke * invoke)4939*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitVarHandleGetAndAdd(HInvoke* invoke) {
4940*795d594fSAndroid Build Coastguard Worker CreateVarHandleGetAndUpdateLocations(invoke, codegen_, GetAndUpdateOp::kAdd);
4941*795d594fSAndroid Build Coastguard Worker }
4942*795d594fSAndroid Build Coastguard Worker
VisitVarHandleGetAndAdd(HInvoke * invoke)4943*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitVarHandleGetAndAdd(HInvoke* invoke) {
4944*795d594fSAndroid Build Coastguard Worker GenerateVarHandleGetAndUpdate(invoke, codegen_, GetAndUpdateOp::kAdd, std::memory_order_seq_cst);
4945*795d594fSAndroid Build Coastguard Worker }
4946*795d594fSAndroid Build Coastguard Worker
VisitVarHandleGetAndAddAcquire(HInvoke * invoke)4947*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitVarHandleGetAndAddAcquire(HInvoke* invoke) {
4948*795d594fSAndroid Build Coastguard Worker CreateVarHandleGetAndUpdateLocations(invoke, codegen_, GetAndUpdateOp::kAdd);
4949*795d594fSAndroid Build Coastguard Worker }
4950*795d594fSAndroid Build Coastguard Worker
VisitVarHandleGetAndAddAcquire(HInvoke * invoke)4951*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitVarHandleGetAndAddAcquire(HInvoke* invoke) {
4952*795d594fSAndroid Build Coastguard Worker GenerateVarHandleGetAndUpdate(invoke, codegen_, GetAndUpdateOp::kAdd, std::memory_order_acquire);
4953*795d594fSAndroid Build Coastguard Worker }
4954*795d594fSAndroid Build Coastguard Worker
VisitVarHandleGetAndAddRelease(HInvoke * invoke)4955*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitVarHandleGetAndAddRelease(HInvoke* invoke) {
4956*795d594fSAndroid Build Coastguard Worker CreateVarHandleGetAndUpdateLocations(invoke, codegen_, GetAndUpdateOp::kAdd);
4957*795d594fSAndroid Build Coastguard Worker }
4958*795d594fSAndroid Build Coastguard Worker
VisitVarHandleGetAndAddRelease(HInvoke * invoke)4959*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitVarHandleGetAndAddRelease(HInvoke* invoke) {
4960*795d594fSAndroid Build Coastguard Worker GenerateVarHandleGetAndUpdate(invoke, codegen_, GetAndUpdateOp::kAdd, std::memory_order_release);
4961*795d594fSAndroid Build Coastguard Worker }
4962*795d594fSAndroid Build Coastguard Worker
VisitVarHandleGetAndBitwiseAnd(HInvoke * invoke)4963*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitVarHandleGetAndBitwiseAnd(HInvoke* invoke) {
4964*795d594fSAndroid Build Coastguard Worker CreateVarHandleGetAndUpdateLocations(invoke, codegen_, GetAndUpdateOp::kAnd);
4965*795d594fSAndroid Build Coastguard Worker }
4966*795d594fSAndroid Build Coastguard Worker
VisitVarHandleGetAndBitwiseAnd(HInvoke * invoke)4967*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitVarHandleGetAndBitwiseAnd(HInvoke* invoke) {
4968*795d594fSAndroid Build Coastguard Worker GenerateVarHandleGetAndUpdate(invoke, codegen_, GetAndUpdateOp::kAnd, std::memory_order_seq_cst);
4969*795d594fSAndroid Build Coastguard Worker }
4970*795d594fSAndroid Build Coastguard Worker
VisitVarHandleGetAndBitwiseAndAcquire(HInvoke * invoke)4971*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitVarHandleGetAndBitwiseAndAcquire(HInvoke* invoke) {
4972*795d594fSAndroid Build Coastguard Worker CreateVarHandleGetAndUpdateLocations(invoke, codegen_, GetAndUpdateOp::kAnd);
4973*795d594fSAndroid Build Coastguard Worker }
4974*795d594fSAndroid Build Coastguard Worker
VisitVarHandleGetAndBitwiseAndAcquire(HInvoke * invoke)4975*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitVarHandleGetAndBitwiseAndAcquire(HInvoke* invoke) {
4976*795d594fSAndroid Build Coastguard Worker GenerateVarHandleGetAndUpdate(invoke, codegen_, GetAndUpdateOp::kAnd, std::memory_order_acquire);
4977*795d594fSAndroid Build Coastguard Worker }
4978*795d594fSAndroid Build Coastguard Worker
VisitVarHandleGetAndBitwiseAndRelease(HInvoke * invoke)4979*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitVarHandleGetAndBitwiseAndRelease(HInvoke* invoke) {
4980*795d594fSAndroid Build Coastguard Worker CreateVarHandleGetAndUpdateLocations(invoke, codegen_, GetAndUpdateOp::kAnd);
4981*795d594fSAndroid Build Coastguard Worker }
4982*795d594fSAndroid Build Coastguard Worker
VisitVarHandleGetAndBitwiseAndRelease(HInvoke * invoke)4983*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitVarHandleGetAndBitwiseAndRelease(HInvoke* invoke) {
4984*795d594fSAndroid Build Coastguard Worker GenerateVarHandleGetAndUpdate(invoke, codegen_, GetAndUpdateOp::kAnd, std::memory_order_release);
4985*795d594fSAndroid Build Coastguard Worker }
4986*795d594fSAndroid Build Coastguard Worker
VisitVarHandleGetAndBitwiseOr(HInvoke * invoke)4987*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitVarHandleGetAndBitwiseOr(HInvoke* invoke) {
4988*795d594fSAndroid Build Coastguard Worker CreateVarHandleGetAndUpdateLocations(invoke, codegen_, GetAndUpdateOp::kOr);
4989*795d594fSAndroid Build Coastguard Worker }
4990*795d594fSAndroid Build Coastguard Worker
VisitVarHandleGetAndBitwiseOr(HInvoke * invoke)4991*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitVarHandleGetAndBitwiseOr(HInvoke* invoke) {
4992*795d594fSAndroid Build Coastguard Worker GenerateVarHandleGetAndUpdate(invoke, codegen_, GetAndUpdateOp::kOr, std::memory_order_seq_cst);
4993*795d594fSAndroid Build Coastguard Worker }
4994*795d594fSAndroid Build Coastguard Worker
VisitVarHandleGetAndBitwiseOrAcquire(HInvoke * invoke)4995*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitVarHandleGetAndBitwiseOrAcquire(HInvoke* invoke) {
4996*795d594fSAndroid Build Coastguard Worker CreateVarHandleGetAndUpdateLocations(invoke, codegen_, GetAndUpdateOp::kOr);
4997*795d594fSAndroid Build Coastguard Worker }
4998*795d594fSAndroid Build Coastguard Worker
VisitVarHandleGetAndBitwiseOrAcquire(HInvoke * invoke)4999*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitVarHandleGetAndBitwiseOrAcquire(HInvoke* invoke) {
5000*795d594fSAndroid Build Coastguard Worker GenerateVarHandleGetAndUpdate(invoke, codegen_, GetAndUpdateOp::kOr, std::memory_order_acquire);
5001*795d594fSAndroid Build Coastguard Worker }
5002*795d594fSAndroid Build Coastguard Worker
VisitVarHandleGetAndBitwiseOrRelease(HInvoke * invoke)5003*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitVarHandleGetAndBitwiseOrRelease(HInvoke* invoke) {
5004*795d594fSAndroid Build Coastguard Worker CreateVarHandleGetAndUpdateLocations(invoke, codegen_, GetAndUpdateOp::kOr);
5005*795d594fSAndroid Build Coastguard Worker }
5006*795d594fSAndroid Build Coastguard Worker
VisitVarHandleGetAndBitwiseOrRelease(HInvoke * invoke)5007*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitVarHandleGetAndBitwiseOrRelease(HInvoke* invoke) {
5008*795d594fSAndroid Build Coastguard Worker GenerateVarHandleGetAndUpdate(invoke, codegen_, GetAndUpdateOp::kOr, std::memory_order_release);
5009*795d594fSAndroid Build Coastguard Worker }
5010*795d594fSAndroid Build Coastguard Worker
VisitVarHandleGetAndBitwiseXor(HInvoke * invoke)5011*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitVarHandleGetAndBitwiseXor(HInvoke* invoke) {
5012*795d594fSAndroid Build Coastguard Worker CreateVarHandleGetAndUpdateLocations(invoke, codegen_, GetAndUpdateOp::kXor);
5013*795d594fSAndroid Build Coastguard Worker }
5014*795d594fSAndroid Build Coastguard Worker
VisitVarHandleGetAndBitwiseXor(HInvoke * invoke)5015*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitVarHandleGetAndBitwiseXor(HInvoke* invoke) {
5016*795d594fSAndroid Build Coastguard Worker GenerateVarHandleGetAndUpdate(invoke, codegen_, GetAndUpdateOp::kXor, std::memory_order_seq_cst);
5017*795d594fSAndroid Build Coastguard Worker }
5018*795d594fSAndroid Build Coastguard Worker
VisitVarHandleGetAndBitwiseXorAcquire(HInvoke * invoke)5019*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitVarHandleGetAndBitwiseXorAcquire(HInvoke* invoke) {
5020*795d594fSAndroid Build Coastguard Worker CreateVarHandleGetAndUpdateLocations(invoke, codegen_, GetAndUpdateOp::kXor);
5021*795d594fSAndroid Build Coastguard Worker }
5022*795d594fSAndroid Build Coastguard Worker
VisitVarHandleGetAndBitwiseXorAcquire(HInvoke * invoke)5023*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitVarHandleGetAndBitwiseXorAcquire(HInvoke* invoke) {
5024*795d594fSAndroid Build Coastguard Worker GenerateVarHandleGetAndUpdate(invoke, codegen_, GetAndUpdateOp::kXor, std::memory_order_acquire);
5025*795d594fSAndroid Build Coastguard Worker }
5026*795d594fSAndroid Build Coastguard Worker
VisitVarHandleGetAndBitwiseXorRelease(HInvoke * invoke)5027*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitVarHandleGetAndBitwiseXorRelease(HInvoke* invoke) {
5028*795d594fSAndroid Build Coastguard Worker CreateVarHandleGetAndUpdateLocations(invoke, codegen_, GetAndUpdateOp::kXor);
5029*795d594fSAndroid Build Coastguard Worker }
5030*795d594fSAndroid Build Coastguard Worker
VisitVarHandleGetAndBitwiseXorRelease(HInvoke * invoke)5031*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitVarHandleGetAndBitwiseXorRelease(HInvoke* invoke) {
5032*795d594fSAndroid Build Coastguard Worker GenerateVarHandleGetAndUpdate(invoke, codegen_, GetAndUpdateOp::kXor, std::memory_order_release);
5033*795d594fSAndroid Build Coastguard Worker }
5034*795d594fSAndroid Build Coastguard Worker
EmitByteArrayViewCode(CodeGenerator * codegen_in)5035*795d594fSAndroid Build Coastguard Worker void VarHandleSlowPathRISCV64::EmitByteArrayViewCode(CodeGenerator* codegen_in) {
5036*795d594fSAndroid Build Coastguard Worker DCHECK(GetByteArrayViewCheckLabel()->IsLinked());
5037*795d594fSAndroid Build Coastguard Worker CodeGeneratorRISCV64* codegen = down_cast<CodeGeneratorRISCV64*>(codegen_in);
5038*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = codegen->GetAssembler();
5039*795d594fSAndroid Build Coastguard Worker HInvoke* invoke = GetInvoke();
5040*795d594fSAndroid Build Coastguard Worker mirror::VarHandle::AccessModeTemplate access_mode_template = GetAccessModeTemplate();
5041*795d594fSAndroid Build Coastguard Worker DataType::Type value_type =
5042*795d594fSAndroid Build Coastguard Worker GetVarHandleExpectedValueType(invoke, /*expected_coordinates_count=*/ 2u);
5043*795d594fSAndroid Build Coastguard Worker DCHECK_NE(value_type, DataType::Type::kReference);
5044*795d594fSAndroid Build Coastguard Worker size_t size = DataType::Size(value_type);
5045*795d594fSAndroid Build Coastguard Worker DCHECK_GT(size, 1u);
5046*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = invoke->GetLocations();
5047*795d594fSAndroid Build Coastguard Worker XRegister varhandle = locations->InAt(0).AsRegister<XRegister>();
5048*795d594fSAndroid Build Coastguard Worker XRegister object = locations->InAt(1).AsRegister<XRegister>();
5049*795d594fSAndroid Build Coastguard Worker XRegister index = locations->InAt(2).AsRegister<XRegister>();
5050*795d594fSAndroid Build Coastguard Worker
5051*795d594fSAndroid Build Coastguard Worker MemberOffset class_offset = mirror::Object::ClassOffset();
5052*795d594fSAndroid Build Coastguard Worker MemberOffset array_length_offset = mirror::Array::LengthOffset();
5053*795d594fSAndroid Build Coastguard Worker MemberOffset data_offset = mirror::Array::DataOffset(Primitive::kPrimByte);
5054*795d594fSAndroid Build Coastguard Worker MemberOffset native_byte_order_offset = mirror::ByteArrayViewVarHandle::NativeByteOrderOffset();
5055*795d594fSAndroid Build Coastguard Worker
5056*795d594fSAndroid Build Coastguard Worker __ Bind(GetByteArrayViewCheckLabel());
5057*795d594fSAndroid Build Coastguard Worker
5058*795d594fSAndroid Build Coastguard Worker VarHandleTarget target = GetVarHandleTarget(invoke);
5059*795d594fSAndroid Build Coastguard Worker {
5060*795d594fSAndroid Build Coastguard Worker ScratchRegisterScope srs(assembler);
5061*795d594fSAndroid Build Coastguard Worker XRegister temp = srs.AllocateXRegister();
5062*795d594fSAndroid Build Coastguard Worker XRegister temp2 = srs.AllocateXRegister();
5063*795d594fSAndroid Build Coastguard Worker
5064*795d594fSAndroid Build Coastguard Worker // The main path checked that the coordinateType0 is an array class that matches
5065*795d594fSAndroid Build Coastguard Worker // the class of the actual coordinate argument but it does not match the value type.
5066*795d594fSAndroid Build Coastguard Worker // Check if the `varhandle` references a ByteArrayViewVarHandle instance.
5067*795d594fSAndroid Build Coastguard Worker __ Loadwu(temp, varhandle, class_offset.Int32Value());
5068*795d594fSAndroid Build Coastguard Worker codegen->MaybeUnpoisonHeapReference(temp);
5069*795d594fSAndroid Build Coastguard Worker codegen->LoadClassRootForIntrinsic(temp2, ClassRoot::kJavaLangInvokeByteArrayViewVarHandle);
5070*795d594fSAndroid Build Coastguard Worker __ Bne(temp, temp2, GetEntryLabel());
5071*795d594fSAndroid Build Coastguard Worker
5072*795d594fSAndroid Build Coastguard Worker // Check for array index out of bounds.
5073*795d594fSAndroid Build Coastguard Worker __ Loadw(temp, object, array_length_offset.Int32Value());
5074*795d594fSAndroid Build Coastguard Worker __ Bgeu(index, temp, GetEntryLabel());
5075*795d594fSAndroid Build Coastguard Worker __ Addi(temp2, index, size - 1u);
5076*795d594fSAndroid Build Coastguard Worker __ Bgeu(temp2, temp, GetEntryLabel());
5077*795d594fSAndroid Build Coastguard Worker
5078*795d594fSAndroid Build Coastguard Worker // Construct the target.
5079*795d594fSAndroid Build Coastguard Worker __ Addi(target.offset, index, data_offset.Int32Value());
5080*795d594fSAndroid Build Coastguard Worker
5081*795d594fSAndroid Build Coastguard Worker // Alignment check. For unaligned access, go to the runtime.
5082*795d594fSAndroid Build Coastguard Worker DCHECK(IsPowerOfTwo(size));
5083*795d594fSAndroid Build Coastguard Worker __ Andi(temp, target.offset, size - 1u);
5084*795d594fSAndroid Build Coastguard Worker __ Bnez(temp, GetEntryLabel());
5085*795d594fSAndroid Build Coastguard Worker
5086*795d594fSAndroid Build Coastguard Worker // Byte order check. For native byte order return to the main path.
5087*795d594fSAndroid Build Coastguard Worker if (access_mode_template == mirror::VarHandle::AccessModeTemplate::kSet &&
5088*795d594fSAndroid Build Coastguard Worker IsZeroBitPattern(invoke->InputAt(invoke->GetNumberOfArguments() - 1u))) {
5089*795d594fSAndroid Build Coastguard Worker // There is no reason to differentiate between native byte order and byte-swap
5090*795d594fSAndroid Build Coastguard Worker // for setting a zero bit pattern. Just return to the main path.
5091*795d594fSAndroid Build Coastguard Worker __ J(GetNativeByteOrderLabel());
5092*795d594fSAndroid Build Coastguard Worker return;
5093*795d594fSAndroid Build Coastguard Worker }
5094*795d594fSAndroid Build Coastguard Worker __ Loadbu(temp, varhandle, native_byte_order_offset.Int32Value());
5095*795d594fSAndroid Build Coastguard Worker __ Bnez(temp, GetNativeByteOrderLabel());
5096*795d594fSAndroid Build Coastguard Worker }
5097*795d594fSAndroid Build Coastguard Worker
5098*795d594fSAndroid Build Coastguard Worker switch (access_mode_template) {
5099*795d594fSAndroid Build Coastguard Worker case mirror::VarHandle::AccessModeTemplate::kGet:
5100*795d594fSAndroid Build Coastguard Worker GenerateVarHandleGet(invoke, codegen, order_, /*byte_swap=*/ true);
5101*795d594fSAndroid Build Coastguard Worker break;
5102*795d594fSAndroid Build Coastguard Worker case mirror::VarHandle::AccessModeTemplate::kSet:
5103*795d594fSAndroid Build Coastguard Worker GenerateVarHandleSet(invoke, codegen, order_, /*byte_swap=*/ true);
5104*795d594fSAndroid Build Coastguard Worker break;
5105*795d594fSAndroid Build Coastguard Worker case mirror::VarHandle::AccessModeTemplate::kCompareAndSet:
5106*795d594fSAndroid Build Coastguard Worker case mirror::VarHandle::AccessModeTemplate::kCompareAndExchange:
5107*795d594fSAndroid Build Coastguard Worker GenerateVarHandleCompareAndSetOrExchange(
5108*795d594fSAndroid Build Coastguard Worker invoke, codegen, order_, return_success_, strong_, /*byte_swap=*/ true);
5109*795d594fSAndroid Build Coastguard Worker break;
5110*795d594fSAndroid Build Coastguard Worker case mirror::VarHandle::AccessModeTemplate::kGetAndUpdate:
5111*795d594fSAndroid Build Coastguard Worker GenerateVarHandleGetAndUpdate(
5112*795d594fSAndroid Build Coastguard Worker invoke, codegen, get_and_update_op_, order_, /*byte_swap=*/ true);
5113*795d594fSAndroid Build Coastguard Worker break;
5114*795d594fSAndroid Build Coastguard Worker }
5115*795d594fSAndroid Build Coastguard Worker __ J(GetExitLabel());
5116*795d594fSAndroid Build Coastguard Worker }
5117*795d594fSAndroid Build Coastguard Worker
VisitThreadCurrentThread(HInvoke * invoke)5118*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitThreadCurrentThread(HInvoke* invoke) {
5119*795d594fSAndroid Build Coastguard Worker LocationSummary* locations =
5120*795d594fSAndroid Build Coastguard Worker new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
5121*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresRegister());
5122*795d594fSAndroid Build Coastguard Worker }
5123*795d594fSAndroid Build Coastguard Worker
VisitThreadCurrentThread(HInvoke * invoke)5124*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitThreadCurrentThread(HInvoke* invoke) {
5125*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = GetAssembler();
5126*795d594fSAndroid Build Coastguard Worker XRegister out = invoke->GetLocations()->Out().AsRegister<XRegister>();
5127*795d594fSAndroid Build Coastguard Worker __ Loadwu(out, TR, Thread::PeerOffset<kRiscv64PointerSize>().Int32Value());
5128*795d594fSAndroid Build Coastguard Worker }
5129*795d594fSAndroid Build Coastguard Worker
VisitThreadInterrupted(HInvoke * invoke)5130*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitThreadInterrupted(HInvoke* invoke) {
5131*795d594fSAndroid Build Coastguard Worker LocationSummary* locations =
5132*795d594fSAndroid Build Coastguard Worker new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
5133*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresRegister());
5134*795d594fSAndroid Build Coastguard Worker }
5135*795d594fSAndroid Build Coastguard Worker
VisitThreadInterrupted(HInvoke * invoke)5136*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitThreadInterrupted(HInvoke* invoke) {
5137*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = invoke->GetLocations();
5138*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = GetAssembler();
5139*795d594fSAndroid Build Coastguard Worker XRegister out = locations->Out().AsRegister<XRegister>();
5140*795d594fSAndroid Build Coastguard Worker Riscv64Label done;
5141*795d594fSAndroid Build Coastguard Worker
5142*795d594fSAndroid Build Coastguard Worker codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
5143*795d594fSAndroid Build Coastguard Worker __ Loadw(out, TR, Thread::InterruptedOffset<kRiscv64PointerSize>().Int32Value());
5144*795d594fSAndroid Build Coastguard Worker __ Beqz(out, &done);
5145*795d594fSAndroid Build Coastguard Worker __ Storew(Zero, TR, Thread::InterruptedOffset<kRiscv64PointerSize>().Int32Value());
5146*795d594fSAndroid Build Coastguard Worker codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
5147*795d594fSAndroid Build Coastguard Worker __ Bind(&done);
5148*795d594fSAndroid Build Coastguard Worker }
5149*795d594fSAndroid Build Coastguard Worker
VisitReachabilityFence(HInvoke * invoke)5150*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitReachabilityFence(HInvoke* invoke) {
5151*795d594fSAndroid Build Coastguard Worker LocationSummary* locations =
5152*795d594fSAndroid Build Coastguard Worker new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
5153*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::Any());
5154*795d594fSAndroid Build Coastguard Worker }
5155*795d594fSAndroid Build Coastguard Worker
VisitReachabilityFence(HInvoke * invoke)5156*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitReachabilityFence([[maybe_unused]] HInvoke* invoke) {}
5157*795d594fSAndroid Build Coastguard Worker
VisitMathFmaDouble(HInvoke * invoke)5158*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitMathFmaDouble(HInvoke* invoke) {
5159*795d594fSAndroid Build Coastguard Worker CreateFpFpFpToFpNoOverlapLocations(allocator_, invoke);
5160*795d594fSAndroid Build Coastguard Worker }
5161*795d594fSAndroid Build Coastguard Worker
VisitMathFmaDouble(HInvoke * invoke)5162*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitMathFmaDouble(HInvoke* invoke) {
5163*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = invoke->GetLocations();
5164*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = GetAssembler();
5165*795d594fSAndroid Build Coastguard Worker FRegister n = locations->InAt(0).AsFpuRegister<FRegister>();
5166*795d594fSAndroid Build Coastguard Worker FRegister m = locations->InAt(1).AsFpuRegister<FRegister>();
5167*795d594fSAndroid Build Coastguard Worker FRegister a = locations->InAt(2).AsFpuRegister<FRegister>();
5168*795d594fSAndroid Build Coastguard Worker FRegister out = locations->Out().AsFpuRegister<FRegister>();
5169*795d594fSAndroid Build Coastguard Worker
5170*795d594fSAndroid Build Coastguard Worker __ FMAddD(out, n, m, a);
5171*795d594fSAndroid Build Coastguard Worker }
5172*795d594fSAndroid Build Coastguard Worker
VisitMathFmaFloat(HInvoke * invoke)5173*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitMathFmaFloat(HInvoke* invoke) {
5174*795d594fSAndroid Build Coastguard Worker CreateFpFpFpToFpNoOverlapLocations(allocator_, invoke);
5175*795d594fSAndroid Build Coastguard Worker }
5176*795d594fSAndroid Build Coastguard Worker
VisitMathFmaFloat(HInvoke * invoke)5177*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitMathFmaFloat(HInvoke* invoke) {
5178*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = invoke->GetLocations();
5179*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = GetAssembler();
5180*795d594fSAndroid Build Coastguard Worker FRegister n = locations->InAt(0).AsFpuRegister<FRegister>();
5181*795d594fSAndroid Build Coastguard Worker FRegister m = locations->InAt(1).AsFpuRegister<FRegister>();
5182*795d594fSAndroid Build Coastguard Worker FRegister a = locations->InAt(2).AsFpuRegister<FRegister>();
5183*795d594fSAndroid Build Coastguard Worker FRegister out = locations->Out().AsFpuRegister<FRegister>();
5184*795d594fSAndroid Build Coastguard Worker
5185*795d594fSAndroid Build Coastguard Worker __ FMAddS(out, n, m, a);
5186*795d594fSAndroid Build Coastguard Worker }
5187*795d594fSAndroid Build Coastguard Worker
5188*795d594fSAndroid Build Coastguard Worker
VisitMathCos(HInvoke * invoke)5189*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitMathCos(HInvoke* invoke) {
5190*795d594fSAndroid Build Coastguard Worker CreateFPToFPCallLocations(allocator_, invoke);
5191*795d594fSAndroid Build Coastguard Worker }
5192*795d594fSAndroid Build Coastguard Worker
VisitMathCos(HInvoke * invoke)5193*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitMathCos(HInvoke* invoke) {
5194*795d594fSAndroid Build Coastguard Worker codegen_->InvokeRuntime(kQuickCos, invoke, invoke->GetDexPc());
5195*795d594fSAndroid Build Coastguard Worker }
5196*795d594fSAndroid Build Coastguard Worker
VisitMathSin(HInvoke * invoke)5197*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitMathSin(HInvoke* invoke) {
5198*795d594fSAndroid Build Coastguard Worker CreateFPToFPCallLocations(allocator_, invoke);
5199*795d594fSAndroid Build Coastguard Worker }
5200*795d594fSAndroid Build Coastguard Worker
VisitMathSin(HInvoke * invoke)5201*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitMathSin(HInvoke* invoke) {
5202*795d594fSAndroid Build Coastguard Worker codegen_->InvokeRuntime(kQuickSin, invoke, invoke->GetDexPc());
5203*795d594fSAndroid Build Coastguard Worker }
5204*795d594fSAndroid Build Coastguard Worker
VisitMathAcos(HInvoke * invoke)5205*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitMathAcos(HInvoke* invoke) {
5206*795d594fSAndroid Build Coastguard Worker CreateFPToFPCallLocations(allocator_, invoke);
5207*795d594fSAndroid Build Coastguard Worker }
5208*795d594fSAndroid Build Coastguard Worker
VisitMathAcos(HInvoke * invoke)5209*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitMathAcos(HInvoke* invoke) {
5210*795d594fSAndroid Build Coastguard Worker codegen_->InvokeRuntime(kQuickAcos, invoke, invoke->GetDexPc());
5211*795d594fSAndroid Build Coastguard Worker }
5212*795d594fSAndroid Build Coastguard Worker
VisitMathAsin(HInvoke * invoke)5213*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitMathAsin(HInvoke* invoke) {
5214*795d594fSAndroid Build Coastguard Worker CreateFPToFPCallLocations(allocator_, invoke);
5215*795d594fSAndroid Build Coastguard Worker }
5216*795d594fSAndroid Build Coastguard Worker
VisitMathAsin(HInvoke * invoke)5217*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitMathAsin(HInvoke* invoke) {
5218*795d594fSAndroid Build Coastguard Worker codegen_->InvokeRuntime(kQuickAsin, invoke, invoke->GetDexPc());
5219*795d594fSAndroid Build Coastguard Worker }
5220*795d594fSAndroid Build Coastguard Worker
VisitMathAtan(HInvoke * invoke)5221*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitMathAtan(HInvoke* invoke) {
5222*795d594fSAndroid Build Coastguard Worker CreateFPToFPCallLocations(allocator_, invoke);
5223*795d594fSAndroid Build Coastguard Worker }
5224*795d594fSAndroid Build Coastguard Worker
VisitMathAtan(HInvoke * invoke)5225*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitMathAtan(HInvoke* invoke) {
5226*795d594fSAndroid Build Coastguard Worker codegen_->InvokeRuntime(kQuickAtan, invoke, invoke->GetDexPc());
5227*795d594fSAndroid Build Coastguard Worker }
5228*795d594fSAndroid Build Coastguard Worker
VisitMathAtan2(HInvoke * invoke)5229*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitMathAtan2(HInvoke* invoke) {
5230*795d594fSAndroid Build Coastguard Worker CreateFPFPToFPCallLocations(allocator_, invoke);
5231*795d594fSAndroid Build Coastguard Worker }
5232*795d594fSAndroid Build Coastguard Worker
VisitMathAtan2(HInvoke * invoke)5233*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitMathAtan2(HInvoke* invoke) {
5234*795d594fSAndroid Build Coastguard Worker codegen_->InvokeRuntime(kQuickAtan2, invoke, invoke->GetDexPc());
5235*795d594fSAndroid Build Coastguard Worker }
5236*795d594fSAndroid Build Coastguard Worker
VisitMathPow(HInvoke * invoke)5237*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitMathPow(HInvoke* invoke) {
5238*795d594fSAndroid Build Coastguard Worker CreateFPFPToFPCallLocations(allocator_, invoke);
5239*795d594fSAndroid Build Coastguard Worker }
5240*795d594fSAndroid Build Coastguard Worker
VisitMathPow(HInvoke * invoke)5241*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitMathPow(HInvoke* invoke) {
5242*795d594fSAndroid Build Coastguard Worker codegen_->InvokeRuntime(kQuickPow, invoke, invoke->GetDexPc());
5243*795d594fSAndroid Build Coastguard Worker }
5244*795d594fSAndroid Build Coastguard Worker
VisitMathCbrt(HInvoke * invoke)5245*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitMathCbrt(HInvoke* invoke) {
5246*795d594fSAndroid Build Coastguard Worker CreateFPToFPCallLocations(allocator_, invoke);
5247*795d594fSAndroid Build Coastguard Worker }
5248*795d594fSAndroid Build Coastguard Worker
VisitMathCbrt(HInvoke * invoke)5249*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitMathCbrt(HInvoke* invoke) {
5250*795d594fSAndroid Build Coastguard Worker codegen_->InvokeRuntime(kQuickCbrt, invoke, invoke->GetDexPc());
5251*795d594fSAndroid Build Coastguard Worker }
5252*795d594fSAndroid Build Coastguard Worker
VisitMathCosh(HInvoke * invoke)5253*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitMathCosh(HInvoke* invoke) {
5254*795d594fSAndroid Build Coastguard Worker CreateFPToFPCallLocations(allocator_, invoke);
5255*795d594fSAndroid Build Coastguard Worker }
5256*795d594fSAndroid Build Coastguard Worker
VisitMathCosh(HInvoke * invoke)5257*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitMathCosh(HInvoke* invoke) {
5258*795d594fSAndroid Build Coastguard Worker codegen_->InvokeRuntime(kQuickCosh, invoke, invoke->GetDexPc());
5259*795d594fSAndroid Build Coastguard Worker }
5260*795d594fSAndroid Build Coastguard Worker
VisitMathExp(HInvoke * invoke)5261*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitMathExp(HInvoke* invoke) {
5262*795d594fSAndroid Build Coastguard Worker CreateFPToFPCallLocations(allocator_, invoke);
5263*795d594fSAndroid Build Coastguard Worker }
5264*795d594fSAndroid Build Coastguard Worker
VisitMathExp(HInvoke * invoke)5265*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitMathExp(HInvoke* invoke) {
5266*795d594fSAndroid Build Coastguard Worker codegen_->InvokeRuntime(kQuickExp, invoke, invoke->GetDexPc());
5267*795d594fSAndroid Build Coastguard Worker }
5268*795d594fSAndroid Build Coastguard Worker
VisitMathExpm1(HInvoke * invoke)5269*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitMathExpm1(HInvoke* invoke) {
5270*795d594fSAndroid Build Coastguard Worker CreateFPToFPCallLocations(allocator_, invoke);
5271*795d594fSAndroid Build Coastguard Worker }
5272*795d594fSAndroid Build Coastguard Worker
VisitMathExpm1(HInvoke * invoke)5273*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitMathExpm1(HInvoke* invoke) {
5274*795d594fSAndroid Build Coastguard Worker codegen_->InvokeRuntime(kQuickExpm1, invoke, invoke->GetDexPc());
5275*795d594fSAndroid Build Coastguard Worker }
5276*795d594fSAndroid Build Coastguard Worker
VisitMathHypot(HInvoke * invoke)5277*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitMathHypot(HInvoke* invoke) {
5278*795d594fSAndroid Build Coastguard Worker CreateFPFPToFPCallLocations(allocator_, invoke);
5279*795d594fSAndroid Build Coastguard Worker }
5280*795d594fSAndroid Build Coastguard Worker
VisitMathHypot(HInvoke * invoke)5281*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitMathHypot(HInvoke* invoke) {
5282*795d594fSAndroid Build Coastguard Worker codegen_->InvokeRuntime(kQuickHypot, invoke, invoke->GetDexPc());
5283*795d594fSAndroid Build Coastguard Worker }
5284*795d594fSAndroid Build Coastguard Worker
VisitMathLog(HInvoke * invoke)5285*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitMathLog(HInvoke* invoke) {
5286*795d594fSAndroid Build Coastguard Worker CreateFPToFPCallLocations(allocator_, invoke);
5287*795d594fSAndroid Build Coastguard Worker }
5288*795d594fSAndroid Build Coastguard Worker
VisitMathLog(HInvoke * invoke)5289*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitMathLog(HInvoke* invoke) {
5290*795d594fSAndroid Build Coastguard Worker codegen_->InvokeRuntime(kQuickLog, invoke, invoke->GetDexPc());
5291*795d594fSAndroid Build Coastguard Worker }
5292*795d594fSAndroid Build Coastguard Worker
VisitMathLog10(HInvoke * invoke)5293*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitMathLog10(HInvoke* invoke) {
5294*795d594fSAndroid Build Coastguard Worker CreateFPToFPCallLocations(allocator_, invoke);
5295*795d594fSAndroid Build Coastguard Worker }
5296*795d594fSAndroid Build Coastguard Worker
VisitMathLog10(HInvoke * invoke)5297*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitMathLog10(HInvoke* invoke) {
5298*795d594fSAndroid Build Coastguard Worker codegen_->InvokeRuntime(kQuickLog10, invoke, invoke->GetDexPc());
5299*795d594fSAndroid Build Coastguard Worker }
5300*795d594fSAndroid Build Coastguard Worker
VisitMathNextAfter(HInvoke * invoke)5301*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitMathNextAfter(HInvoke* invoke) {
5302*795d594fSAndroid Build Coastguard Worker CreateFPFPToFPCallLocations(allocator_, invoke);
5303*795d594fSAndroid Build Coastguard Worker }
5304*795d594fSAndroid Build Coastguard Worker
VisitMathNextAfter(HInvoke * invoke)5305*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitMathNextAfter(HInvoke* invoke) {
5306*795d594fSAndroid Build Coastguard Worker codegen_->InvokeRuntime(kQuickNextAfter, invoke, invoke->GetDexPc());
5307*795d594fSAndroid Build Coastguard Worker }
5308*795d594fSAndroid Build Coastguard Worker
VisitMathSinh(HInvoke * invoke)5309*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitMathSinh(HInvoke* invoke) {
5310*795d594fSAndroid Build Coastguard Worker CreateFPToFPCallLocations(allocator_, invoke);
5311*795d594fSAndroid Build Coastguard Worker }
5312*795d594fSAndroid Build Coastguard Worker
VisitMathSinh(HInvoke * invoke)5313*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitMathSinh(HInvoke* invoke) {
5314*795d594fSAndroid Build Coastguard Worker codegen_->InvokeRuntime(kQuickSinh, invoke, invoke->GetDexPc());
5315*795d594fSAndroid Build Coastguard Worker }
5316*795d594fSAndroid Build Coastguard Worker
VisitMathTan(HInvoke * invoke)5317*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitMathTan(HInvoke* invoke) {
5318*795d594fSAndroid Build Coastguard Worker CreateFPToFPCallLocations(allocator_, invoke);
5319*795d594fSAndroid Build Coastguard Worker }
5320*795d594fSAndroid Build Coastguard Worker
VisitMathTan(HInvoke * invoke)5321*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitMathTan(HInvoke* invoke) {
5322*795d594fSAndroid Build Coastguard Worker codegen_->InvokeRuntime(kQuickTan, invoke, invoke->GetDexPc());
5323*795d594fSAndroid Build Coastguard Worker }
5324*795d594fSAndroid Build Coastguard Worker
VisitMathTanh(HInvoke * invoke)5325*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitMathTanh(HInvoke* invoke) {
5326*795d594fSAndroid Build Coastguard Worker CreateFPToFPCallLocations(allocator_, invoke);
5327*795d594fSAndroid Build Coastguard Worker }
5328*795d594fSAndroid Build Coastguard Worker
VisitMathTanh(HInvoke * invoke)5329*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitMathTanh(HInvoke* invoke) {
5330*795d594fSAndroid Build Coastguard Worker codegen_->InvokeRuntime(kQuickTanh, invoke, invoke->GetDexPc());
5331*795d594fSAndroid Build Coastguard Worker }
5332*795d594fSAndroid Build Coastguard Worker
VisitMathSqrt(HInvoke * invoke)5333*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitMathSqrt(HInvoke* invoke) {
5334*795d594fSAndroid Build Coastguard Worker CreateFPToFPLocations(allocator_, invoke, Location::kNoOutputOverlap);
5335*795d594fSAndroid Build Coastguard Worker }
5336*795d594fSAndroid Build Coastguard Worker
VisitMathSqrt(HInvoke * invoke)5337*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitMathSqrt(HInvoke* invoke) {
5338*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(invoke->InputAt(0)->GetType(), DataType::Type::kFloat64);
5339*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(invoke->GetType(), DataType::Type::kFloat64);
5340*795d594fSAndroid Build Coastguard Worker
5341*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = invoke->GetLocations();
5342*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = GetAssembler();
5343*795d594fSAndroid Build Coastguard Worker FRegister in = locations->InAt(0).AsFpuRegister<FRegister>();
5344*795d594fSAndroid Build Coastguard Worker FRegister out = locations->Out().AsFpuRegister<FRegister>();
5345*795d594fSAndroid Build Coastguard Worker
5346*795d594fSAndroid Build Coastguard Worker __ FSqrtD(out, in);
5347*795d594fSAndroid Build Coastguard Worker }
5348*795d594fSAndroid Build Coastguard Worker
GenDoubleRound(Riscv64Assembler * assembler,HInvoke * invoke,FPRoundingMode mode)5349*795d594fSAndroid Build Coastguard Worker static void GenDoubleRound(Riscv64Assembler* assembler, HInvoke* invoke, FPRoundingMode mode) {
5350*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = invoke->GetLocations();
5351*795d594fSAndroid Build Coastguard Worker FRegister in = locations->InAt(0).AsFpuRegister<FRegister>();
5352*795d594fSAndroid Build Coastguard Worker FRegister out = locations->Out().AsFpuRegister<FRegister>();
5353*795d594fSAndroid Build Coastguard Worker ScratchRegisterScope srs(assembler);
5354*795d594fSAndroid Build Coastguard Worker XRegister tmp = srs.AllocateXRegister();
5355*795d594fSAndroid Build Coastguard Worker FRegister ftmp = srs.AllocateFRegister();
5356*795d594fSAndroid Build Coastguard Worker Riscv64Label done;
5357*795d594fSAndroid Build Coastguard Worker
5358*795d594fSAndroid Build Coastguard Worker // Load 2^52
5359*795d594fSAndroid Build Coastguard Worker __ LoadConst64(tmp, 0x4330000000000000L);
5360*795d594fSAndroid Build Coastguard Worker __ FMvDX(ftmp, tmp);
5361*795d594fSAndroid Build Coastguard Worker __ FAbsD(out, in);
5362*795d594fSAndroid Build Coastguard Worker __ FLtD(tmp, out, ftmp);
5363*795d594fSAndroid Build Coastguard Worker
5364*795d594fSAndroid Build Coastguard Worker // Set output as the input if input greater than the max
5365*795d594fSAndroid Build Coastguard Worker __ FMvD(out, in);
5366*795d594fSAndroid Build Coastguard Worker __ Beqz(tmp, &done);
5367*795d594fSAndroid Build Coastguard Worker
5368*795d594fSAndroid Build Coastguard Worker // Convert with rounding mode
5369*795d594fSAndroid Build Coastguard Worker __ FCvtLD(tmp, in, mode);
5370*795d594fSAndroid Build Coastguard Worker __ FCvtDL(ftmp, tmp, mode);
5371*795d594fSAndroid Build Coastguard Worker
5372*795d594fSAndroid Build Coastguard Worker // Set the signed bit
5373*795d594fSAndroid Build Coastguard Worker __ FSgnjD(out, ftmp, in);
5374*795d594fSAndroid Build Coastguard Worker __ Bind(&done);
5375*795d594fSAndroid Build Coastguard Worker }
5376*795d594fSAndroid Build Coastguard Worker
VisitMathFloor(HInvoke * invoke)5377*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitMathFloor(HInvoke* invoke) {
5378*795d594fSAndroid Build Coastguard Worker CreateFPToFPLocations(allocator_, invoke);
5379*795d594fSAndroid Build Coastguard Worker }
5380*795d594fSAndroid Build Coastguard Worker
VisitMathFloor(HInvoke * invoke)5381*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitMathFloor(HInvoke* invoke) {
5382*795d594fSAndroid Build Coastguard Worker GenDoubleRound(GetAssembler(), invoke, FPRoundingMode::kRDN);
5383*795d594fSAndroid Build Coastguard Worker }
5384*795d594fSAndroid Build Coastguard Worker
VisitMathCeil(HInvoke * invoke)5385*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitMathCeil(HInvoke* invoke) {
5386*795d594fSAndroid Build Coastguard Worker CreateFPToFPLocations(allocator_, invoke);
5387*795d594fSAndroid Build Coastguard Worker }
5388*795d594fSAndroid Build Coastguard Worker
VisitMathCeil(HInvoke * invoke)5389*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitMathCeil(HInvoke* invoke) {
5390*795d594fSAndroid Build Coastguard Worker GenDoubleRound(GetAssembler(), invoke, FPRoundingMode::kRUP);
5391*795d594fSAndroid Build Coastguard Worker }
5392*795d594fSAndroid Build Coastguard Worker
VisitMathRint(HInvoke * invoke)5393*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitMathRint(HInvoke* invoke) {
5394*795d594fSAndroid Build Coastguard Worker CreateFPToFPLocations(allocator_, invoke);
5395*795d594fSAndroid Build Coastguard Worker }
5396*795d594fSAndroid Build Coastguard Worker
VisitMathRint(HInvoke * invoke)5397*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitMathRint(HInvoke* invoke) {
5398*795d594fSAndroid Build Coastguard Worker GenDoubleRound(GetAssembler(), invoke, FPRoundingMode::kRNE);
5399*795d594fSAndroid Build Coastguard Worker }
5400*795d594fSAndroid Build Coastguard Worker
GenMathRound(CodeGeneratorRISCV64 * codegen,HInvoke * invoke,DataType::Type type)5401*795d594fSAndroid Build Coastguard Worker void GenMathRound(CodeGeneratorRISCV64* codegen, HInvoke* invoke, DataType::Type type) {
5402*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = codegen->GetAssembler();
5403*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = invoke->GetLocations();
5404*795d594fSAndroid Build Coastguard Worker FRegister in = locations->InAt(0).AsFpuRegister<FRegister>();
5405*795d594fSAndroid Build Coastguard Worker XRegister out = locations->Out().AsRegister<XRegister>();
5406*795d594fSAndroid Build Coastguard Worker ScratchRegisterScope srs(assembler);
5407*795d594fSAndroid Build Coastguard Worker FRegister ftmp = srs.AllocateFRegister();
5408*795d594fSAndroid Build Coastguard Worker Riscv64Label done;
5409*795d594fSAndroid Build Coastguard Worker
5410*795d594fSAndroid Build Coastguard Worker // Check NaN
5411*795d594fSAndroid Build Coastguard Worker codegen->GetInstructionVisitor()->FClass(out, in, type);
5412*795d594fSAndroid Build Coastguard Worker __ Slti(out, out, kFClassNaNMinValue);
5413*795d594fSAndroid Build Coastguard Worker __ Beqz(out, &done);
5414*795d594fSAndroid Build Coastguard Worker
5415*795d594fSAndroid Build Coastguard Worker if (type == DataType::Type::kFloat64) {
5416*795d594fSAndroid Build Coastguard Worker // Add 0.5 (0x3fe0000000000000), rounding down (towards negative infinity).
5417*795d594fSAndroid Build Coastguard Worker __ LoadConst64(out, 0x3fe0000000000000L);
5418*795d594fSAndroid Build Coastguard Worker __ FMvDX(ftmp, out);
5419*795d594fSAndroid Build Coastguard Worker __ FAddD(ftmp, ftmp, in, FPRoundingMode::kRDN);
5420*795d594fSAndroid Build Coastguard Worker
5421*795d594fSAndroid Build Coastguard Worker // Convert to managed `long`, rounding down (towards negative infinity).
5422*795d594fSAndroid Build Coastguard Worker __ FCvtLD(out, ftmp, FPRoundingMode::kRDN);
5423*795d594fSAndroid Build Coastguard Worker } else {
5424*795d594fSAndroid Build Coastguard Worker // Add 0.5 (0x3f000000), rounding down (towards negative infinity).
5425*795d594fSAndroid Build Coastguard Worker __ LoadConst32(out, 0x3f000000);
5426*795d594fSAndroid Build Coastguard Worker __ FMvWX(ftmp, out);
5427*795d594fSAndroid Build Coastguard Worker __ FAddS(ftmp, ftmp, in, FPRoundingMode::kRDN);
5428*795d594fSAndroid Build Coastguard Worker
5429*795d594fSAndroid Build Coastguard Worker // Convert to managed `int`, rounding down (towards negative infinity).
5430*795d594fSAndroid Build Coastguard Worker __ FCvtWS(out, ftmp, FPRoundingMode::kRDN);
5431*795d594fSAndroid Build Coastguard Worker }
5432*795d594fSAndroid Build Coastguard Worker
5433*795d594fSAndroid Build Coastguard Worker __ Bind(&done);
5434*795d594fSAndroid Build Coastguard Worker }
5435*795d594fSAndroid Build Coastguard Worker
VisitMathRoundDouble(HInvoke * invoke)5436*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitMathRoundDouble(HInvoke* invoke) {
5437*795d594fSAndroid Build Coastguard Worker CreateFPToIntLocations(allocator_, invoke);
5438*795d594fSAndroid Build Coastguard Worker }
5439*795d594fSAndroid Build Coastguard Worker
VisitMathRoundDouble(HInvoke * invoke)5440*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitMathRoundDouble(HInvoke* invoke) {
5441*795d594fSAndroid Build Coastguard Worker GenMathRound(codegen_, invoke, DataType::Type::kFloat64);
5442*795d594fSAndroid Build Coastguard Worker }
5443*795d594fSAndroid Build Coastguard Worker
VisitMathRoundFloat(HInvoke * invoke)5444*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitMathRoundFloat(HInvoke* invoke) {
5445*795d594fSAndroid Build Coastguard Worker CreateFPToIntLocations(allocator_, invoke);
5446*795d594fSAndroid Build Coastguard Worker }
5447*795d594fSAndroid Build Coastguard Worker
VisitMathRoundFloat(HInvoke * invoke)5448*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitMathRoundFloat(HInvoke* invoke) {
5449*795d594fSAndroid Build Coastguard Worker GenMathRound(codegen_, invoke, DataType::Type::kFloat32);
5450*795d594fSAndroid Build Coastguard Worker }
5451*795d594fSAndroid Build Coastguard Worker
VisitMathMultiplyHigh(HInvoke * invoke)5452*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitMathMultiplyHigh(HInvoke* invoke) {
5453*795d594fSAndroid Build Coastguard Worker LocationSummary* locations =
5454*795d594fSAndroid Build Coastguard Worker new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
5455*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresRegister());
5456*795d594fSAndroid Build Coastguard Worker locations->SetInAt(1, Location::RequiresRegister());
5457*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
5458*795d594fSAndroid Build Coastguard Worker }
5459*795d594fSAndroid Build Coastguard Worker
VisitMathMultiplyHigh(HInvoke * invoke)5460*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitMathMultiplyHigh(HInvoke* invoke) {
5461*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = invoke->GetLocations();
5462*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = GetAssembler();
5463*795d594fSAndroid Build Coastguard Worker DCHECK(invoke->GetType() == DataType::Type::kInt64);
5464*795d594fSAndroid Build Coastguard Worker
5465*795d594fSAndroid Build Coastguard Worker XRegister x = locations->InAt(0).AsRegister<XRegister>();
5466*795d594fSAndroid Build Coastguard Worker XRegister y = locations->InAt(1).AsRegister<XRegister>();
5467*795d594fSAndroid Build Coastguard Worker XRegister out = locations->Out().AsRegister<XRegister>();
5468*795d594fSAndroid Build Coastguard Worker
5469*795d594fSAndroid Build Coastguard Worker // Get high 64 of the multiply
5470*795d594fSAndroid Build Coastguard Worker __ Mulh(out, x, y);
5471*795d594fSAndroid Build Coastguard Worker }
5472*795d594fSAndroid Build Coastguard Worker
VisitStringGetCharsNoCheck(HInvoke * invoke)5473*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitStringGetCharsNoCheck(HInvoke* invoke) {
5474*795d594fSAndroid Build Coastguard Worker LocationSummary* locations =
5475*795d594fSAndroid Build Coastguard Worker new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
5476*795d594fSAndroid Build Coastguard Worker
5477*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresRegister());
5478*795d594fSAndroid Build Coastguard Worker locations->SetInAt(1, Location::RequiresRegister());
5479*795d594fSAndroid Build Coastguard Worker locations->SetInAt(2, Location::RequiresRegister());
5480*795d594fSAndroid Build Coastguard Worker locations->SetInAt(3, Location::RequiresRegister());
5481*795d594fSAndroid Build Coastguard Worker locations->SetInAt(4, Location::RequiresRegister());
5482*795d594fSAndroid Build Coastguard Worker
5483*795d594fSAndroid Build Coastguard Worker locations->AddRegisterTemps(3);
5484*795d594fSAndroid Build Coastguard Worker }
5485*795d594fSAndroid Build Coastguard Worker
VisitStringGetCharsNoCheck(HInvoke * invoke)5486*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitStringGetCharsNoCheck(HInvoke* invoke) {
5487*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = GetAssembler();
5488*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = invoke->GetLocations();
5489*795d594fSAndroid Build Coastguard Worker
5490*795d594fSAndroid Build Coastguard Worker // In Java sizeof(Char) is 2.
5491*795d594fSAndroid Build Coastguard Worker constexpr size_t char_size = DataType::Size(DataType::Type::kUint16);
5492*795d594fSAndroid Build Coastguard Worker static_assert(char_size == 2u);
5493*795d594fSAndroid Build Coastguard Worker
5494*795d594fSAndroid Build Coastguard Worker // Location of data in the destination char array buffer.
5495*795d594fSAndroid Build Coastguard Worker const uint32_t array_data_offset = mirror::Array::DataOffset(char_size).Uint32Value();
5496*795d594fSAndroid Build Coastguard Worker
5497*795d594fSAndroid Build Coastguard Worker // Location of char array data in the source string.
5498*795d594fSAndroid Build Coastguard Worker const uint32_t string_value_offset = mirror::String::ValueOffset().Uint32Value();
5499*795d594fSAndroid Build Coastguard Worker
5500*795d594fSAndroid Build Coastguard Worker // void getCharsNoCheck(int srcBegin, int srcEnd, char[] dst, int dstBegin);
5501*795d594fSAndroid Build Coastguard Worker
5502*795d594fSAndroid Build Coastguard Worker // The source string.
5503*795d594fSAndroid Build Coastguard Worker XRegister source_string_object = locations->InAt(0).AsRegister<XRegister>();
5504*795d594fSAndroid Build Coastguard Worker // Index of the first character.
5505*795d594fSAndroid Build Coastguard Worker XRegister source_begin_index = locations->InAt(1).AsRegister<XRegister>();
5506*795d594fSAndroid Build Coastguard Worker // Index that immediately follows the last character.
5507*795d594fSAndroid Build Coastguard Worker XRegister source_end_index = locations->InAt(2).AsRegister<XRegister>();
5508*795d594fSAndroid Build Coastguard Worker // The destination array.
5509*795d594fSAndroid Build Coastguard Worker XRegister destination_array_object = locations->InAt(3).AsRegister<XRegister>();
5510*795d594fSAndroid Build Coastguard Worker // The start offset in the destination array.
5511*795d594fSAndroid Build Coastguard Worker XRegister destination_begin_offset = locations->InAt(4).AsRegister<XRegister>();
5512*795d594fSAndroid Build Coastguard Worker
5513*795d594fSAndroid Build Coastguard Worker XRegister source_ptr = locations->GetTemp(0).AsRegister<XRegister>();
5514*795d594fSAndroid Build Coastguard Worker XRegister destination_ptr = locations->GetTemp(1).AsRegister<XRegister>();
5515*795d594fSAndroid Build Coastguard Worker XRegister number_of_chars = locations->GetTemp(2).AsRegister<XRegister>();
5516*795d594fSAndroid Build Coastguard Worker
5517*795d594fSAndroid Build Coastguard Worker ScratchRegisterScope temps(assembler);
5518*795d594fSAndroid Build Coastguard Worker XRegister tmp = temps.AllocateXRegister();
5519*795d594fSAndroid Build Coastguard Worker
5520*795d594fSAndroid Build Coastguard Worker Riscv64Label done;
5521*795d594fSAndroid Build Coastguard Worker
5522*795d594fSAndroid Build Coastguard Worker // Calculate the length(number_of_chars) of the string.
5523*795d594fSAndroid Build Coastguard Worker __ Subw(number_of_chars, source_end_index, source_begin_index);
5524*795d594fSAndroid Build Coastguard Worker
5525*795d594fSAndroid Build Coastguard Worker // If the string has zero length then exit.
5526*795d594fSAndroid Build Coastguard Worker __ Beqz(number_of_chars, &done);
5527*795d594fSAndroid Build Coastguard Worker
5528*795d594fSAndroid Build Coastguard Worker // Prepare a register with the destination address
5529*795d594fSAndroid Build Coastguard Worker // to start copying to the address:
5530*795d594fSAndroid Build Coastguard Worker // 1. set the address from which the data in the
5531*795d594fSAndroid Build Coastguard Worker // destination array begins (destination_array_object + array_data_offset);
5532*795d594fSAndroid Build Coastguard Worker __ Addi(destination_ptr, destination_array_object, array_data_offset);
5533*795d594fSAndroid Build Coastguard Worker // 2. it is necessary to add the start offset relative to the beginning
5534*795d594fSAndroid Build Coastguard Worker // of the data in the destination array,
5535*795d594fSAndroid Build Coastguard Worker // yet, due to sizeof(Char) being 2, formerly scaling must be performed
5536*795d594fSAndroid Build Coastguard Worker // (destination_begin_offset * 2 that equals to destination_begin_offset << 1);
5537*795d594fSAndroid Build Coastguard Worker __ Sh1Add(destination_ptr, destination_begin_offset, destination_ptr);
5538*795d594fSAndroid Build Coastguard Worker
5539*795d594fSAndroid Build Coastguard Worker // Prepare a register with the source address
5540*795d594fSAndroid Build Coastguard Worker // to start copying from the address:
5541*795d594fSAndroid Build Coastguard Worker // 1. set the address from which the data in the
5542*795d594fSAndroid Build Coastguard Worker // source string begins (source_string_object + string_value_offset).
5543*795d594fSAndroid Build Coastguard Worker // Other manipulations will be performed later,
5544*795d594fSAndroid Build Coastguard Worker // since they depend on whether the string is compressed or not.
5545*795d594fSAndroid Build Coastguard Worker __ Addi(source_ptr, source_string_object, string_value_offset);
5546*795d594fSAndroid Build Coastguard Worker
5547*795d594fSAndroid Build Coastguard Worker // The string can be compressed. It is a way to store strings more compactly.
5548*795d594fSAndroid Build Coastguard Worker // In this instance, every character is located in one byte (instead of two).
5549*795d594fSAndroid Build Coastguard Worker Riscv64Label compressed_string_preloop;
5550*795d594fSAndroid Build Coastguard Worker
5551*795d594fSAndroid Build Coastguard Worker // Information about whether the string is compressed or not is located
5552*795d594fSAndroid Build Coastguard Worker // in the area intended for storing the length of the string.
5553*795d594fSAndroid Build Coastguard Worker // The least significant bit of the string's length is used
5554*795d594fSAndroid Build Coastguard Worker // as the compression flag if STRING_COMPRESSION_ENABLED.
5555*795d594fSAndroid Build Coastguard Worker if (mirror::kUseStringCompression) {
5556*795d594fSAndroid Build Coastguard Worker // Location of count in string.
5557*795d594fSAndroid Build Coastguard Worker const uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
5558*795d594fSAndroid Build Coastguard Worker // String's length.
5559*795d594fSAndroid Build Coastguard Worker __ Loadwu(tmp, source_string_object, count_offset);
5560*795d594fSAndroid Build Coastguard Worker
5561*795d594fSAndroid Build Coastguard Worker // Checking the string for compression.
5562*795d594fSAndroid Build Coastguard Worker // If so, move to the "compressed_string_preloop".
5563*795d594fSAndroid Build Coastguard Worker __ Andi(tmp, tmp, 0x1);
5564*795d594fSAndroid Build Coastguard Worker __ Beqz(tmp, &compressed_string_preloop);
5565*795d594fSAndroid Build Coastguard Worker }
5566*795d594fSAndroid Build Coastguard Worker
5567*795d594fSAndroid Build Coastguard Worker // Continue preparing the source register:
5568*795d594fSAndroid Build Coastguard Worker // proceed similarly to what was done for the destination register.
5569*795d594fSAndroid Build Coastguard Worker __ Sh1Add(source_ptr, source_begin_index, source_ptr);
5570*795d594fSAndroid Build Coastguard Worker
5571*795d594fSAndroid Build Coastguard Worker // If the string is not compressed, then perform ordinary copying.
5572*795d594fSAndroid Build Coastguard Worker // Copying will occur 4 characters (8 bytes) at a time, immediately after there are
5573*795d594fSAndroid Build Coastguard Worker // less than 4 characters left, move to the "remainder_loop" and copy the remaining
5574*795d594fSAndroid Build Coastguard Worker // characters one character (2 bytes) at a time.
5575*795d594fSAndroid Build Coastguard Worker // Note: Unaligned addresses are acceptable here and it is not required to embed
5576*795d594fSAndroid Build Coastguard Worker // additional code to correct them.
5577*795d594fSAndroid Build Coastguard Worker Riscv64Label main_loop;
5578*795d594fSAndroid Build Coastguard Worker Riscv64Label remainder_loop;
5579*795d594fSAndroid Build Coastguard Worker
5580*795d594fSAndroid Build Coastguard Worker // If initially there are less than 4 characters,
5581*795d594fSAndroid Build Coastguard Worker // then we directly calculate the remainder.
5582*795d594fSAndroid Build Coastguard Worker __ Addi(tmp, number_of_chars, -4);
5583*795d594fSAndroid Build Coastguard Worker __ Bltz(tmp, &remainder_loop);
5584*795d594fSAndroid Build Coastguard Worker
5585*795d594fSAndroid Build Coastguard Worker // Otherwise, save the value to the counter and continue.
5586*795d594fSAndroid Build Coastguard Worker __ Mv(number_of_chars, tmp);
5587*795d594fSAndroid Build Coastguard Worker
5588*795d594fSAndroid Build Coastguard Worker // Main loop. Loads and stores 4 16-bit Java characters at a time.
5589*795d594fSAndroid Build Coastguard Worker __ Bind(&main_loop);
5590*795d594fSAndroid Build Coastguard Worker
5591*795d594fSAndroid Build Coastguard Worker __ Loadd(tmp, source_ptr, 0);
5592*795d594fSAndroid Build Coastguard Worker __ Addi(source_ptr, source_ptr, char_size * 4);
5593*795d594fSAndroid Build Coastguard Worker __ Stored(tmp, destination_ptr, 0);
5594*795d594fSAndroid Build Coastguard Worker __ Addi(destination_ptr, destination_ptr, char_size * 4);
5595*795d594fSAndroid Build Coastguard Worker
5596*795d594fSAndroid Build Coastguard Worker __ Addi(number_of_chars, number_of_chars, -4);
5597*795d594fSAndroid Build Coastguard Worker
5598*795d594fSAndroid Build Coastguard Worker __ Bgez(number_of_chars, &main_loop);
5599*795d594fSAndroid Build Coastguard Worker
5600*795d594fSAndroid Build Coastguard Worker // Restore the previous counter value.
5601*795d594fSAndroid Build Coastguard Worker __ Addi(number_of_chars, number_of_chars, 4);
5602*795d594fSAndroid Build Coastguard Worker __ Beqz(number_of_chars, &done);
5603*795d594fSAndroid Build Coastguard Worker
5604*795d594fSAndroid Build Coastguard Worker // Remainder loop for < 4 characters case and remainder handling.
5605*795d594fSAndroid Build Coastguard Worker // Loads and stores one 16-bit Java character at a time.
5606*795d594fSAndroid Build Coastguard Worker __ Bind(&remainder_loop);
5607*795d594fSAndroid Build Coastguard Worker
5608*795d594fSAndroid Build Coastguard Worker __ Loadhu(tmp, source_ptr, 0);
5609*795d594fSAndroid Build Coastguard Worker __ Addi(source_ptr, source_ptr, char_size);
5610*795d594fSAndroid Build Coastguard Worker
5611*795d594fSAndroid Build Coastguard Worker __ Storeh(tmp, destination_ptr, 0);
5612*795d594fSAndroid Build Coastguard Worker __ Addi(destination_ptr, destination_ptr, char_size);
5613*795d594fSAndroid Build Coastguard Worker
5614*795d594fSAndroid Build Coastguard Worker __ Addi(number_of_chars, number_of_chars, -1);
5615*795d594fSAndroid Build Coastguard Worker __ Bgtz(number_of_chars, &remainder_loop);
5616*795d594fSAndroid Build Coastguard Worker
5617*795d594fSAndroid Build Coastguard Worker Riscv64Label compressed_string_loop;
5618*795d594fSAndroid Build Coastguard Worker if (mirror::kUseStringCompression) {
5619*795d594fSAndroid Build Coastguard Worker __ J(&done);
5620*795d594fSAndroid Build Coastguard Worker
5621*795d594fSAndroid Build Coastguard Worker // Below is the copying under the string compression circumstance mentioned above.
5622*795d594fSAndroid Build Coastguard Worker // Every character in the source string occupies only one byte (instead of two).
5623*795d594fSAndroid Build Coastguard Worker constexpr size_t compressed_char_size = DataType::Size(DataType::Type::kInt8);
5624*795d594fSAndroid Build Coastguard Worker static_assert(compressed_char_size == 1u);
5625*795d594fSAndroid Build Coastguard Worker
5626*795d594fSAndroid Build Coastguard Worker __ Bind(&compressed_string_preloop);
5627*795d594fSAndroid Build Coastguard Worker
5628*795d594fSAndroid Build Coastguard Worker // Continue preparing the source register:
5629*795d594fSAndroid Build Coastguard Worker // proceed identically to what was done for the destination register,
5630*795d594fSAndroid Build Coastguard Worker // yet take into account that only one byte yields for every source character,
5631*795d594fSAndroid Build Coastguard Worker // hence we need to extend it to two ones when copying it to the destination address.
5632*795d594fSAndroid Build Coastguard Worker // Against this background scaling for source_begin_index is not needed.
5633*795d594fSAndroid Build Coastguard Worker __ Add(source_ptr, source_ptr, source_begin_index);
5634*795d594fSAndroid Build Coastguard Worker
5635*795d594fSAndroid Build Coastguard Worker // Copy loop for compressed strings. Copying one 8-bit character to 16-bit one at a time.
5636*795d594fSAndroid Build Coastguard Worker __ Bind(&compressed_string_loop);
5637*795d594fSAndroid Build Coastguard Worker
5638*795d594fSAndroid Build Coastguard Worker __ Loadbu(tmp, source_ptr, 0);
5639*795d594fSAndroid Build Coastguard Worker __ Addi(source_ptr, source_ptr, compressed_char_size);
5640*795d594fSAndroid Build Coastguard Worker __ Storeh(tmp, destination_ptr, 0);
5641*795d594fSAndroid Build Coastguard Worker __ Addi(destination_ptr, destination_ptr, char_size);
5642*795d594fSAndroid Build Coastguard Worker
5643*795d594fSAndroid Build Coastguard Worker __ Addi(number_of_chars, number_of_chars, -1);
5644*795d594fSAndroid Build Coastguard Worker __ Bgtz(number_of_chars, &compressed_string_loop);
5645*795d594fSAndroid Build Coastguard Worker }
5646*795d594fSAndroid Build Coastguard Worker
5647*795d594fSAndroid Build Coastguard Worker __ Bind(&done);
5648*795d594fSAndroid Build Coastguard Worker }
5649*795d594fSAndroid Build Coastguard Worker
GenMathSignum(CodeGeneratorRISCV64 * codegen,HInvoke * invoke,DataType::Type type)5650*795d594fSAndroid Build Coastguard Worker void GenMathSignum(CodeGeneratorRISCV64* codegen, HInvoke* invoke, DataType::Type type) {
5651*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = invoke->GetLocations();
5652*795d594fSAndroid Build Coastguard Worker DCHECK(locations->InAt(0).Equals(locations->Out()));
5653*795d594fSAndroid Build Coastguard Worker FRegister in = locations->InAt(0).AsFpuRegister<FRegister>();
5654*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = codegen->GetAssembler();
5655*795d594fSAndroid Build Coastguard Worker ScratchRegisterScope srs(assembler);
5656*795d594fSAndroid Build Coastguard Worker XRegister tmp = srs.AllocateXRegister();
5657*795d594fSAndroid Build Coastguard Worker FRegister ftmp = srs.AllocateFRegister();
5658*795d594fSAndroid Build Coastguard Worker Riscv64Label done;
5659*795d594fSAndroid Build Coastguard Worker
5660*795d594fSAndroid Build Coastguard Worker if (type == DataType::Type::kFloat64) {
5661*795d594fSAndroid Build Coastguard Worker // 0x3FF0000000000000L = 1.0
5662*795d594fSAndroid Build Coastguard Worker __ Li(tmp, 0x3FF0000000000000L);
5663*795d594fSAndroid Build Coastguard Worker __ FMvDX(ftmp, tmp);
5664*795d594fSAndroid Build Coastguard Worker __ FClassD(tmp, in);
5665*795d594fSAndroid Build Coastguard Worker } else {
5666*795d594fSAndroid Build Coastguard Worker // 0x3f800000 = 1.0f
5667*795d594fSAndroid Build Coastguard Worker __ Li(tmp, 0x3F800000);
5668*795d594fSAndroid Build Coastguard Worker __ FMvWX(ftmp, tmp);
5669*795d594fSAndroid Build Coastguard Worker __ FClassS(tmp, in);
5670*795d594fSAndroid Build Coastguard Worker }
5671*795d594fSAndroid Build Coastguard Worker
5672*795d594fSAndroid Build Coastguard Worker __ Andi(tmp, tmp, kPositiveZero | kNegativeZero | kSignalingNaN | kQuietNaN);
5673*795d594fSAndroid Build Coastguard Worker __ Bnez(tmp, &done);
5674*795d594fSAndroid Build Coastguard Worker
5675*795d594fSAndroid Build Coastguard Worker if (type == DataType::Type::kFloat64) {
5676*795d594fSAndroid Build Coastguard Worker __ FSgnjD(in, ftmp, in);
5677*795d594fSAndroid Build Coastguard Worker } else {
5678*795d594fSAndroid Build Coastguard Worker __ FSgnjS(in, ftmp, in);
5679*795d594fSAndroid Build Coastguard Worker }
5680*795d594fSAndroid Build Coastguard Worker
5681*795d594fSAndroid Build Coastguard Worker __ Bind(&done);
5682*795d594fSAndroid Build Coastguard Worker }
5683*795d594fSAndroid Build Coastguard Worker
VisitMathSignumDouble(HInvoke * invoke)5684*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitMathSignumDouble(HInvoke* invoke) {
5685*795d594fSAndroid Build Coastguard Worker LocationSummary* locations =
5686*795d594fSAndroid Build Coastguard Worker new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
5687*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresFpuRegister());
5688*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::SameAsFirstInput());
5689*795d594fSAndroid Build Coastguard Worker }
5690*795d594fSAndroid Build Coastguard Worker
VisitMathSignumDouble(HInvoke * invoke)5691*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitMathSignumDouble(HInvoke* invoke) {
5692*795d594fSAndroid Build Coastguard Worker GenMathSignum(codegen_, invoke, DataType::Type::kFloat64);
5693*795d594fSAndroid Build Coastguard Worker }
5694*795d594fSAndroid Build Coastguard Worker
VisitMathSignumFloat(HInvoke * invoke)5695*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitMathSignumFloat(HInvoke* invoke) {
5696*795d594fSAndroid Build Coastguard Worker LocationSummary* locations =
5697*795d594fSAndroid Build Coastguard Worker new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
5698*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresFpuRegister());
5699*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::SameAsFirstInput());
5700*795d594fSAndroid Build Coastguard Worker }
5701*795d594fSAndroid Build Coastguard Worker
VisitMathSignumFloat(HInvoke * invoke)5702*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitMathSignumFloat(HInvoke* invoke) {
5703*795d594fSAndroid Build Coastguard Worker GenMathSignum(codegen_, invoke, DataType::Type::kFloat32);
5704*795d594fSAndroid Build Coastguard Worker }
5705*795d594fSAndroid Build Coastguard Worker
GenMathCopySign(CodeGeneratorRISCV64 * codegen,HInvoke * invoke,DataType::Type type)5706*795d594fSAndroid Build Coastguard Worker void GenMathCopySign(CodeGeneratorRISCV64* codegen, HInvoke* invoke, DataType::Type type) {
5707*795d594fSAndroid Build Coastguard Worker Riscv64Assembler* assembler = codegen->GetAssembler();
5708*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = invoke->GetLocations();
5709*795d594fSAndroid Build Coastguard Worker FRegister in0 = locations->InAt(0).AsFpuRegister<FRegister>();
5710*795d594fSAndroid Build Coastguard Worker FRegister in1 = locations->InAt(1).AsFpuRegister<FRegister>();
5711*795d594fSAndroid Build Coastguard Worker FRegister out = locations->Out().AsFpuRegister<FRegister>();
5712*795d594fSAndroid Build Coastguard Worker
5713*795d594fSAndroid Build Coastguard Worker if (type == DataType::Type::kFloat64) {
5714*795d594fSAndroid Build Coastguard Worker __ FSgnjD(out, in0, in1);
5715*795d594fSAndroid Build Coastguard Worker } else {
5716*795d594fSAndroid Build Coastguard Worker __ FSgnjS(out, in0, in1);
5717*795d594fSAndroid Build Coastguard Worker }
5718*795d594fSAndroid Build Coastguard Worker }
5719*795d594fSAndroid Build Coastguard Worker
VisitMathCopySignDouble(HInvoke * invoke)5720*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitMathCopySignDouble(HInvoke* invoke) {
5721*795d594fSAndroid Build Coastguard Worker CreateFPFPToFPCallLocations(allocator_, invoke);
5722*795d594fSAndroid Build Coastguard Worker }
5723*795d594fSAndroid Build Coastguard Worker
VisitMathCopySignDouble(HInvoke * invoke)5724*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitMathCopySignDouble(HInvoke* invoke) {
5725*795d594fSAndroid Build Coastguard Worker GenMathCopySign(codegen_, invoke, DataType::Type::kFloat64);
5726*795d594fSAndroid Build Coastguard Worker }
5727*795d594fSAndroid Build Coastguard Worker
VisitMathCopySignFloat(HInvoke * invoke)5728*795d594fSAndroid Build Coastguard Worker void IntrinsicLocationsBuilderRISCV64::VisitMathCopySignFloat(HInvoke* invoke) {
5729*795d594fSAndroid Build Coastguard Worker CreateFPFPToFPCallLocations(allocator_, invoke);
5730*795d594fSAndroid Build Coastguard Worker }
5731*795d594fSAndroid Build Coastguard Worker
VisitMathCopySignFloat(HInvoke * invoke)5732*795d594fSAndroid Build Coastguard Worker void IntrinsicCodeGeneratorRISCV64::VisitMathCopySignFloat(HInvoke* invoke) {
5733*795d594fSAndroid Build Coastguard Worker GenMathCopySign(codegen_, invoke, DataType::Type::kFloat32);
5734*795d594fSAndroid Build Coastguard Worker }
5735*795d594fSAndroid Build Coastguard Worker
5736*795d594fSAndroid Build Coastguard Worker #define MARK_UNIMPLEMENTED(Name) UNIMPLEMENTED_INTRINSIC(RISCV64, Name)
5737*795d594fSAndroid Build Coastguard Worker UNIMPLEMENTED_INTRINSIC_LIST_RISCV64(MARK_UNIMPLEMENTED);
5738*795d594fSAndroid Build Coastguard Worker #undef MARK_UNIMPLEMENTED
5739*795d594fSAndroid Build Coastguard Worker
5740*795d594fSAndroid Build Coastguard Worker UNREACHABLE_INTRINSICS(RISCV64)
5741*795d594fSAndroid Build Coastguard Worker
5742*795d594fSAndroid Build Coastguard Worker } // namespace riscv64
5743*795d594fSAndroid Build Coastguard Worker } // namespace art
5744