summaryrefslogtreecommitdiff
path: root/compiler/optimizing/intrinsics_riscv64.cc
diff options
context:
space:
mode:
author Santiago Aboy Solanes <solanes@google.com> 2024-09-25 11:32:36 +0000
committer Santiago Aboy Solanes <solanes@google.com> 2024-09-25 13:41:34 +0100
commitbb2fb09b7d4618e4e4319835e1a8e3c1eb1506ae (patch)
tree91e81a7b395847baa0c578568343c09837d41d40 /compiler/optimizing/intrinsics_riscv64.cc
parent8567fcdf972ade85785b689a15e3593a7d3bff9d (diff)
Revert^2 "Add VarHandle implementations for void getAndUpdate methods"
This reverts commit 8567fcdf972ade85785b689a15e3593a7d3bff9d. Reason for revert: RISC-V fix Test: LUCI run for RISC-V Change-Id: I6392bfa045e7737b5c45d78da4f7ecb8fbd3b89a
Diffstat (limited to 'compiler/optimizing/intrinsics_riscv64.cc')
-rw-r--r--compiler/optimizing/intrinsics_riscv64.cc131
1 files changed, 84 insertions, 47 deletions
diff --git a/compiler/optimizing/intrinsics_riscv64.cc b/compiler/optimizing/intrinsics_riscv64.cc
index 2bc8cad71a..4e5dbe4d23 100644
--- a/compiler/optimizing/intrinsics_riscv64.cc
+++ b/compiler/optimizing/intrinsics_riscv64.cc
@@ -2955,20 +2955,35 @@ static void CreateUnsafeGetAndUpdateLocations(ArenaAllocator* allocator,
locations->SetInAt(2, Location::RequiresRegister());
locations->SetInAt(3, Location::RequiresRegister());
- locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
+ // Request another temporary register for methods that don't return a value.
+ DataType::Type return_type = invoke->GetType();
+ const bool is_void = return_type == DataType::Type::kVoid;
+ if (is_void) {
+ locations->AddTemp(Location::RequiresRegister());
+ } else {
+ locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
+ }
}
static void GenUnsafeGetAndUpdate(HInvoke* invoke,
DataType::Type type,
CodeGeneratorRISCV64* codegen,
GetAndUpdateOp get_and_update_op) {
+ // Currently only used for these GetAndUpdateOp. Might be fine for other ops but double check
+ // before using.
+ DCHECK(get_and_update_op == GetAndUpdateOp::kAdd || get_and_update_op == GetAndUpdateOp::kSet);
+
Riscv64Assembler* assembler = codegen->GetAssembler();
LocationSummary* locations = invoke->GetLocations();
- Location out_loc = locations->Out();
- XRegister out = out_loc.AsRegister<XRegister>(); // Result.
- XRegister base = locations->InAt(1).AsRegister<XRegister>(); // Object pointer.
- XRegister offset = locations->InAt(2).AsRegister<XRegister>(); // Long offset.
- XRegister arg = locations->InAt(3).AsRegister<XRegister>(); // New value or addend.
+ DataType::Type return_type = invoke->GetType();
+ const bool is_void = return_type == DataType::Type::kVoid;
+ // We use a temporary for void methods, as we don't return the value.
+ Location out_or_temp_loc =
+ is_void ? locations->GetTemp(locations->GetTempCount() - 1u) : locations->Out();
+ XRegister out_or_temp = out_or_temp_loc.AsRegister<XRegister>(); // Result.
+ XRegister base = locations->InAt(1).AsRegister<XRegister>(); // Object pointer.
+ XRegister offset = locations->InAt(2).AsRegister<XRegister>(); // Long offset.
+ XRegister arg = locations->InAt(3).AsRegister<XRegister>(); // New value or addend.
// This needs to be before the temp registers, as MarkGCCard also uses scratch registers.
if (type == DataType::Type::kReference) {
@@ -2987,28 +3002,28 @@ static void GenUnsafeGetAndUpdate(HInvoke* invoke,
std::memory_order_seq_cst,
tmp_ptr,
arg,
- /*old_value=*/ out,
+ /*old_value=*/ out_or_temp,
/*mask=*/ kNoXRegister,
/*temp=*/ kNoXRegister);
- if (type == DataType::Type::kReference) {
- __ ZextW(out, out);
+ if (!is_void && type == DataType::Type::kReference) {
+ __ ZextW(out_or_temp, out_or_temp);
if (codegen->EmitReadBarrier()) {
DCHECK(get_and_update_op == GetAndUpdateOp::kSet);
if (kUseBakerReadBarrier) {
// Use RA as temp. It is clobbered in the slow path anyway.
static constexpr Location kBakerReadBarrierTemp = Location::RegisterLocation(RA);
- SlowPathCodeRISCV64* rb_slow_path =
- codegen->AddGcRootBakerBarrierBarrierSlowPath(invoke, out_loc, kBakerReadBarrierTemp);
- codegen->EmitBakerReadBarierMarkingCheck(rb_slow_path, out_loc, kBakerReadBarrierTemp);
+ SlowPathCodeRISCV64* rb_slow_path = codegen->AddGcRootBakerBarrierBarrierSlowPath(
+ invoke, out_or_temp_loc, kBakerReadBarrierTemp);
+ codegen->EmitBakerReadBarierMarkingCheck(
+ rb_slow_path, out_or_temp_loc, kBakerReadBarrierTemp);
} else {
- codegen->GenerateReadBarrierSlow(
- invoke,
- out_loc,
- out_loc,
- Location::RegisterLocation(base),
- /*offset=*/ 0u,
- /*index=*/ Location::RegisterLocation(offset));
+ codegen->GenerateReadBarrierSlow(invoke,
+ out_or_temp_loc,
+ out_or_temp_loc,
+ Location::RegisterLocation(base),
+ /*offset=*/ 0u,
+ /*index=*/ Location::RegisterLocation(offset));
}
}
}
@@ -4450,7 +4465,11 @@ static void CreateVarHandleGetAndUpdateLocations(HInvoke* invoke,
return;
}
- if (invoke->GetType() == DataType::Type::kReference && codegen->EmitNonBakerReadBarrier()) {
+ // Get the type from the shorty as the invokes may not return a value.
+ LocationSummary* locations = CreateVarHandleCommonLocations(invoke, codegen);
+ uint32_t arg_index = invoke->GetNumberOfArguments() - 1;
+ DataType::Type value_type = GetDataTypeFromShorty(invoke, arg_index);
+ if (value_type == DataType::Type::kReference && codegen->EmitNonBakerReadBarrier()) {
// Unsupported for non-Baker read barrier because the artReadBarrierSlow() ignores
// the passed reference and reloads it from the field, thus seeing the new value
// that we have just stored. (And it also gets the memory visibility wrong.) b/173104084
@@ -4458,15 +4477,10 @@ static void CreateVarHandleGetAndUpdateLocations(HInvoke* invoke,
}
// TODO(riscv64): Fix this intrinsic for heap poisoning configuration.
- if (kPoisonHeapReferences && invoke->GetType() == DataType::Type::kReference) {
+ if (kPoisonHeapReferences && value_type == DataType::Type::kReference) {
return;
}
- LocationSummary* locations = CreateVarHandleCommonLocations(invoke, codegen);
- uint32_t arg_index = invoke->GetNumberOfArguments() - 1u;
- DCHECK_EQ(arg_index, 1u + GetExpectedVarHandleCoordinatesCount(invoke));
- DataType::Type value_type = invoke->GetType();
- DCHECK_EQ(value_type, GetDataTypeFromShorty(invoke, arg_index));
Location arg = locations->InAt(arg_index);
bool is_fp = DataType::IsFloatingPointType(value_type);
@@ -4517,6 +4531,19 @@ static void CreateVarHandleGetAndUpdateLocations(HInvoke* invoke,
if (temps_needed > old_temp_count + scratch_registers_available) {
locations->AddRegisterTemps(temps_needed - (old_temp_count + scratch_registers_available));
}
+
+ // Request another temporary register for methods that don't return a value.
+ // For the non-void case, we already set `out` in `CreateVarHandleCommonLocations`.
+ DataType::Type return_type = invoke->GetType();
+ const bool is_void = return_type == DataType::Type::kVoid;
+ DCHECK_IMPLIES(!is_void, return_type == value_type);
+ if (is_void) {
+ if (DataType::IsFloatingPointType(value_type)) {
+ locations->AddTemp(Location::RequiresFpuRegister());
+ } else {
+ locations->AddTemp(Location::RequiresRegister());
+ }
+ }
}
static void GenerateVarHandleGetAndUpdate(HInvoke* invoke,
@@ -4524,16 +4551,21 @@ static void GenerateVarHandleGetAndUpdate(HInvoke* invoke,
GetAndUpdateOp get_and_update_op,
std::memory_order order,
bool byte_swap = false) {
+ // Get the type from the shorty as the invokes may not return a value.
uint32_t arg_index = invoke->GetNumberOfArguments() - 1;
DCHECK_EQ(arg_index, 1u + GetExpectedVarHandleCoordinatesCount(invoke));
- DataType::Type value_type = invoke->GetType();
- DCHECK_EQ(value_type, GetDataTypeFromShorty(invoke, arg_index));
+ DataType::Type value_type = GetDataTypeFromShorty(invoke, arg_index);
Riscv64Assembler* assembler = codegen->GetAssembler();
LocationSummary* locations = invoke->GetLocations();
Location arg = locations->InAt(arg_index);
DCHECK_IMPLIES(arg.IsConstant(), arg.GetConstant()->IsZeroBitPattern());
- Location out = locations->Out();
+ DataType::Type return_type = invoke->GetType();
+ const bool is_void = return_type == DataType::Type::kVoid;
+ DCHECK_IMPLIES(!is_void, return_type == value_type);
+ // We use a temporary for void methods, as we don't return the value.
+ Location out_or_temp =
+ is_void ? locations->GetTemp(locations->GetTempCount() - 1u) : locations->Out();
VarHandleTarget target = GetVarHandleTarget(invoke);
VarHandleSlowPathRISCV64* slow_path = nullptr;
@@ -4589,6 +4621,8 @@ static void GenerateVarHandleGetAndUpdate(HInvoke* invoke,
available_scratch_registers -= 1u;
return srs.AllocateXRegister();
} else {
+ DCHECK_IMPLIES(is_void, next_temp != locations->GetTempCount() - 1u)
+ << "The last temp is special for the void case, as it represents the out register.";
XRegister temp = locations->GetTemp(next_temp).AsRegister<XRegister>();
next_temp += 1u;
return temp;
@@ -4678,24 +4712,24 @@ static void GenerateVarHandleGetAndUpdate(HInvoke* invoke,
codegen->GetInstructionVisitor()->Load(
Location::RegisterLocation(old_value), tmp_ptr, /*offset=*/ 0, op_type);
if (byte_swap) {
- GenerateByteSwapAndExtract(codegen, out, old_value, shift, value_type);
+ GenerateByteSwapAndExtract(codegen, out_or_temp, old_value, shift, value_type);
} else {
DCHECK(is_fp);
- codegen->MoveLocation(out, Location::RegisterLocation(old_value), value_type);
+ codegen->MoveLocation(out_or_temp, Location::RegisterLocation(old_value), value_type);
}
if (is_fp) {
codegen->GetInstructionVisitor()->FAdd(
- ftmp, out.AsFpuRegister<FRegister>(), arg.AsFpuRegister<FRegister>(), value_type);
+ ftmp, out_or_temp.AsFpuRegister<FRegister>(), arg.AsFpuRegister<FRegister>(), value_type);
codegen->MoveLocation(
Location::RegisterLocation(new_value), Location::FpuRegisterLocation(ftmp), op_type);
} else if (arg.IsConstant()) {
DCHECK(arg.GetConstant()->IsZeroBitPattern());
- __ Mv(new_value, out.AsRegister<XRegister>());
+ __ Mv(new_value, out_or_temp.AsRegister<XRegister>());
} else if (value_type == DataType::Type::kInt64) {
- __ Add(new_value, out.AsRegister<XRegister>(), arg.AsRegister<XRegister>());
+ __ Add(new_value, out_or_temp.AsRegister<XRegister>(), arg.AsRegister<XRegister>());
} else {
DCHECK_EQ(op_type, DataType::Type::kInt32);
- __ Addw(new_value, out.AsRegister<XRegister>(), arg.AsRegister<XRegister>());
+ __ Addw(new_value, out_or_temp.AsRegister<XRegister>(), arg.AsRegister<XRegister>());
}
if (byte_swap) {
DataType::Type swap_type = op_type;
@@ -4706,7 +4740,7 @@ static void GenerateVarHandleGetAndUpdate(HInvoke* invoke,
// To update the 16 bits, we can XOR the new value with the `out`, byte swap as Uint16
// (extracting only the bits we want to update), shift and XOR with the old value.
swap_type = DataType::Type::kUint16;
- __ Xor(new_value, new_value, out.AsRegister<XRegister>());
+ __ Xor(new_value, new_value, out_or_temp.AsRegister<XRegister>());
}
GenerateReverseBytes(codegen, Location::RegisterLocation(new_value), new_value, swap_type);
if (is_small) {
@@ -4727,15 +4761,15 @@ static void GenerateVarHandleGetAndUpdate(HInvoke* invoke,
store_result,
/*expected=*/ old_value);
} else {
- XRegister old_value = is_fp ? get_temp() : out.AsRegister<XRegister>();
+ XRegister old_value = is_fp ? get_temp() : out_or_temp.AsRegister<XRegister>();
GenerateGetAndUpdate(
codegen, get_and_update_op, op_type, order, tmp_ptr, arg_reg, old_value, mask, temp);
if (byte_swap) {
- DCHECK_IMPLIES(is_small, out.AsRegister<XRegister>() == old_value)
- << " " << value_type << " " << out.AsRegister<XRegister>() << "!=" << old_value;
- GenerateByteSwapAndExtract(codegen, out, old_value, shift, value_type);
+ DCHECK_IMPLIES(is_small, out_or_temp.AsRegister<XRegister>() == old_value)
+ << " " << value_type << " " << out_or_temp.AsRegister<XRegister>() << "!=" << old_value;
+ GenerateByteSwapAndExtract(codegen, out_or_temp, old_value, shift, value_type);
} else if (is_fp) {
- codegen->MoveLocation(out, Location::RegisterLocation(old_value), value_type);
+ codegen->MoveLocation(out_or_temp, Location::RegisterLocation(old_value), value_type);
} else if (is_small) {
__ Srlw(old_value, old_value, shift);
DCHECK_NE(value_type, DataType::Type::kUint8);
@@ -4754,14 +4788,14 @@ static void GenerateVarHandleGetAndUpdate(HInvoke* invoke,
if (codegen->EmitBakerReadBarrier()) {
// Use RA as temp. It is clobbered in the slow path anyway.
static constexpr Location kBakerReadBarrierTemp = Location::RegisterLocation(RA);
- SlowPathCodeRISCV64* rb_slow_path =
- codegen->AddGcRootBakerBarrierBarrierSlowPath(invoke, out, kBakerReadBarrierTemp);
- codegen->EmitBakerReadBarierMarkingCheck(rb_slow_path, out, kBakerReadBarrierTemp);
+ SlowPathCodeRISCV64* rb_slow_path = codegen->AddGcRootBakerBarrierBarrierSlowPath(
+ invoke, out_or_temp, kBakerReadBarrierTemp);
+ codegen->EmitBakerReadBarierMarkingCheck(rb_slow_path, out_or_temp, kBakerReadBarrierTemp);
} else if (codegen->EmitNonBakerReadBarrier()) {
Location base_loc = Location::RegisterLocation(target.object);
Location index = Location::RegisterLocation(target.offset);
SlowPathCodeRISCV64* rb_slow_path = codegen->AddReadBarrierSlowPath(
- invoke, out, out, base_loc, /*offset=*/ 0u, index);
+ invoke, out_or_temp, out_or_temp, base_loc, /*offset=*/ 0u, index);
__ J(rb_slow_path->GetEntryLabel());
__ Bind(rb_slow_path->GetExitLabel());
}
@@ -4775,13 +4809,16 @@ static void GenerateVarHandleGetAndUpdate(HInvoke* invoke,
// Check that we have allocated the right number of temps. We may need more registers
// for byte swapped CAS in the slow path, so skip this check for the main path in that case.
+ // In the void case, we requested an extra register to mimic the `out` register.
+ const size_t extra_temp_registers = is_void ? 1u : 0u;
bool has_byte_swap = (arg_index == 3u) && (!is_reference && data_size != 1u);
- if ((!has_byte_swap || byte_swap) && next_temp != locations->GetTempCount()) {
+ if ((!has_byte_swap || byte_swap) &&
+ next_temp != locations->GetTempCount() - extra_temp_registers) {
// We allocate a temporary register for the class object for a static field `VarHandle` but
// we do not update the `next_temp` if it's otherwise unused after the address calculation.
CHECK_EQ(arg_index, 1u);
CHECK_EQ(next_temp, 1u);
- CHECK_EQ(locations->GetTempCount(), 2u);
+ CHECK_EQ(locations->GetTempCount(), 2u + extra_temp_registers);
}
}