summaryrefslogtreecommitdiff
path: root/compiler
diff options
context:
space:
mode:
author Ulya Trofimovich <skvadrik@google.com> 2024-09-25 07:13:59 +0000
committer Santiago Aboy Solanes <solanes@google.com> 2024-09-25 11:32:19 +0000
commit8567fcdf972ade85785b689a15e3593a7d3bff9d (patch)
tree305b43a087f1616de1d64dcf2f5d5aa66bdbde0b /compiler
parent3c4f9761bca89108b75b4d132bcb243c9a7e7f43 (diff)
Revert "Add VarHandle implementations for void getAndUpdate methods"
This reverts commit 9ff2b617341bfe574e2d8706553f0cd65a1a2fc8. Reason for revert: failed ART test 712-varhandle-invocations on riscv64 `F dex2oat64: intrinsics_riscv64.cc:4821 Check failed: locations->GetTempCount() == 2u (locations->GetTempCount()=3, 2u=2)` Change-Id: I68a3830ccd730afa66e9cff277fe2a06829ddabe
Diffstat (limited to 'compiler')
-rw-r--r--compiler/optimizing/instruction_builder.cc5
-rw-r--r--compiler/optimizing/intrinsics_arm64.cc142
-rw-r--r--compiler/optimizing/intrinsics_arm_vixl.cc173
-rw-r--r--compiler/optimizing/intrinsics_riscv64.cc129
-rw-r--r--compiler/optimizing/intrinsics_utils.h2
-rw-r--r--compiler/optimizing/intrinsics_x86.cc162
-rw-r--r--compiler/optimizing/intrinsics_x86_64.cc193
7 files changed, 251 insertions, 555 deletions
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index 09d7c23fed..a679f88a58 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -26,8 +26,8 @@
#include "data_type-inl.h"
#include "dex/bytecode_utils.h"
#include "dex/dex_instruction-inl.h"
-#include "driver/compiler_options.h"
#include "driver/dex_compilation_unit.h"
+#include "driver/compiler_options.h"
#include "entrypoints/entrypoint_utils-inl.h"
#include "imtable-inl.h"
#include "intrinsics.h"
@@ -36,7 +36,6 @@
#include "jit/profiling_info.h"
#include "mirror/dex_cache.h"
#include "oat/oat_file.h"
-#include "optimizing/data_type.h"
#include "optimizing_compiler_stats.h"
#include "reflective_handle_scope-inl.h"
#include "scoped_thread_state_change-inl.h"
@@ -1358,7 +1357,7 @@ static void DecideVarHandleIntrinsic(HInvoke* invoke) {
optimizations.SetDoNotIntrinsify();
return;
}
- if (value_type != return_type && return_type != DataType::Type::kVoid) {
+ if (value_type != return_type) {
optimizations.SetDoNotIntrinsify();
return;
}
diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc
index 4af63fa906..71ef84e1aa 100644
--- a/compiler/optimizing/intrinsics_arm64.cc
+++ b/compiler/optimizing/intrinsics_arm64.cc
@@ -34,7 +34,6 @@
#include "mirror/reference.h"
#include "mirror/string-inl.h"
#include "mirror/var_handle.h"
-#include "optimizing/data_type.h"
#include "scoped_thread_state_change-inl.h"
#include "thread-current-inl.h"
#include "utils/arm64/assembler_arm64.h"
@@ -1763,33 +1762,17 @@ static void CreateUnsafeGetAndUpdateLocations(ArenaAllocator* allocator,
locations->SetInAt(3, Location::RequiresRegister());
locations->AddTemp(Location::RequiresRegister());
- // 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);
- }
+ locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
}
static void GenUnsafeGetAndUpdate(HInvoke* invoke,
DataType::Type type,
CodeGeneratorARM64* 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);
-
MacroAssembler* masm = codegen->GetVIXLAssembler();
LocationSummary* locations = invoke->GetLocations();
- 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();
- Register out_or_temp = RegisterFrom(out_or_temp_loc, type); // Result.
+ Register out = RegisterFrom(locations->Out(), type); // Result.
Register base = WRegisterFrom(locations->InAt(1)); // Object pointer.
Register offset = XRegisterFrom(locations->InAt(2)); // Long offset.
Register arg = RegisterFrom(locations->InAt(3), type); // New value or addend.
@@ -1810,19 +1793,20 @@ static void GenUnsafeGetAndUpdate(HInvoke* invoke,
std::memory_order_seq_cst,
tmp_ptr,
arg,
- /*old_value=*/ out_or_temp);
+ /*old_value=*/ out);
- if (!is_void && type == DataType::Type::kReference && codegen->EmitReadBarrier()) {
+ if (type == DataType::Type::kReference && codegen->EmitReadBarrier()) {
DCHECK(get_and_update_op == GetAndUpdateOp::kSet);
if (kUseBakerReadBarrier) {
- codegen->GenerateIntrinsicMoveWithBakerReadBarrier(out_or_temp.W(), out_or_temp.W());
+ codegen->GenerateIntrinsicMoveWithBakerReadBarrier(out.W(), out.W());
} else {
- codegen->GenerateReadBarrierSlow(invoke,
- Location::RegisterLocation(out_or_temp.GetCode()),
- Location::RegisterLocation(out_or_temp.GetCode()),
- Location::RegisterLocation(base.GetCode()),
- /*offset=*/ 0u,
- /*index=*/ Location::RegisterLocation(offset.GetCode()));
+ codegen->GenerateReadBarrierSlow(
+ invoke,
+ Location::RegisterLocation(out.GetCode()),
+ Location::RegisterLocation(out.GetCode()),
+ Location::RegisterLocation(base.GetCode()),
+ /*offset=*/ 0u,
+ /*index=*/ Location::RegisterLocation(offset.GetCode()));
}
}
}
@@ -5436,20 +5420,18 @@ static void CreateVarHandleGetAndUpdateLocations(HInvoke* invoke,
return;
}
- // 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);
- size_t old_temp_count = locations->GetTempCount();
- if (value_type == DataType::Type::kReference && codegen->EmitNonBakerReadBarrier()) {
+ if (invoke->GetType() == 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
return;
}
+ LocationSummary* locations = CreateVarHandleCommonLocations(invoke, codegen);
+
+ size_t old_temp_count = locations->GetTempCount();
DCHECK_EQ(old_temp_count, (GetExpectedVarHandleCoordinatesCount(invoke) == 0) ? 2u : 1u);
- if (DataType::IsFloatingPointType(value_type)) {
+ if (DataType::IsFloatingPointType(invoke->GetType())) {
if (get_and_update_op == GetAndUpdateOp::kAdd) {
// For ADD, do not use ZR for zero bit pattern (+0.0f or +0.0).
locations->SetInAt(invoke->GetNumberOfArguments() - 1u, Location::RequiresFpuRegister());
@@ -5469,23 +5451,12 @@ static void CreateVarHandleGetAndUpdateLocations(HInvoke* invoke,
(get_and_update_op != GetAndUpdateOp::kSet && get_and_update_op != GetAndUpdateOp::kAdd) &&
GetExpectedVarHandleCoordinatesCount(invoke) == 2u &&
!IsZeroBitPattern(invoke->InputAt(invoke->GetNumberOfArguments() - 1u))) {
+ DataType::Type value_type =
+ GetVarHandleExpectedValueType(invoke, /*expected_coordinates_count=*/ 2u);
if (value_type != DataType::Type::kReference && DataType::Size(value_type) != 1u) {
locations->AddTemp(Location::RequiresRegister());
}
}
-
- // 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,
@@ -5493,7 +5464,6 @@ 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;
DataType::Type value_type = GetDataTypeFromShorty(invoke, arg_index);
bool is_fp = DataType::IsFloatingPointType(value_type);
@@ -5503,13 +5473,7 @@ static void GenerateVarHandleGetAndUpdate(HInvoke* invoke,
CPURegister arg = (is_fp && get_and_update_op == GetAndUpdateOp::kAdd)
? InputCPURegisterAt(invoke, arg_index)
: InputCPURegisterOrZeroRegAt(invoke, arg_index);
- 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.
- CPURegister out_or_temp =
- is_void ? CPURegisterFrom(locations->GetTemp(locations->GetTempCount() - 1u), value_type) :
- helpers::OutputCPURegister(invoke);
+ CPURegister out = helpers::OutputCPURegister(invoke);
VarHandleTarget target = GetVarHandleTarget(invoke);
VarHandleSlowPathARM64* slow_path = nullptr;
@@ -5552,7 +5516,7 @@ static void GenerateVarHandleGetAndUpdate(HInvoke* invoke,
}
// Prepare register for old value.
- CPURegister old_value = out_or_temp;
+ CPURegister old_value = out;
if (get_and_update_op == GetAndUpdateOp::kSet) {
// For floating point GetAndSet, do the GenerateGetAndUpdate() with core registers,
// rather than moving between core and FP registers in the loop.
@@ -5590,40 +5554,36 @@ static void GenerateVarHandleGetAndUpdate(HInvoke* invoke,
GenerateGetAndUpdate(codegen, get_and_update_op, load_store_type, order, tmp_ptr, arg, old_value);
- if (!is_void) {
- if (get_and_update_op == GetAndUpdateOp::kAddWithByteSwap) {
- // The only adjustment needed is sign-extension for `kInt16`.
- // Everything else has been done by the `GenerateGetAndUpdate()`.
- DCHECK(byte_swap);
- if (value_type == DataType::Type::kInt16) {
- DCHECK_EQ(load_store_type, DataType::Type::kUint16);
- __ Sxth(out_or_temp.W(), old_value.W());
- }
- } else if (byte_swap) {
- // Also handles moving to FP registers.
- GenerateReverseBytes(masm, value_type, old_value, out_or_temp);
- } else if (get_and_update_op == GetAndUpdateOp::kSet &&
- value_type == DataType::Type::kFloat64) {
- __ Fmov(out_or_temp.D(), old_value.X());
- } else if (get_and_update_op == GetAndUpdateOp::kSet &&
- value_type == DataType::Type::kFloat32) {
- __ Fmov(out_or_temp.S(), old_value.W());
- } else if (value_type == DataType::Type::kInt8) {
- __ Sxtb(out_or_temp.W(), old_value.W());
- } else if (value_type == DataType::Type::kInt16) {
- __ Sxth(out_or_temp.W(), old_value.W());
- } else if (value_type == DataType::Type::kReference && codegen->EmitReadBarrier()) {
- if (kUseBakerReadBarrier) {
- codegen->GenerateIntrinsicMoveWithBakerReadBarrier(out_or_temp.W(), old_value.W());
- } else {
- codegen->GenerateReadBarrierSlow(
- invoke,
- Location::RegisterLocation(out_or_temp.GetCode()),
- Location::RegisterLocation(old_value.GetCode()),
- Location::RegisterLocation(target.object.GetCode()),
- /*offset=*/0u,
- /*index=*/Location::RegisterLocation(target.offset.GetCode()));
- }
+ if (get_and_update_op == GetAndUpdateOp::kAddWithByteSwap) {
+ // The only adjustment needed is sign-extension for `kInt16`.
+ // Everything else has been done by the `GenerateGetAndUpdate()`.
+ DCHECK(byte_swap);
+ if (value_type == DataType::Type::kInt16) {
+ DCHECK_EQ(load_store_type, DataType::Type::kUint16);
+ __ Sxth(out.W(), old_value.W());
+ }
+ } else if (byte_swap) {
+ // Also handles moving to FP registers.
+ GenerateReverseBytes(masm, value_type, old_value, out);
+ } else if (get_and_update_op == GetAndUpdateOp::kSet && value_type == DataType::Type::kFloat64) {
+ __ Fmov(out.D(), old_value.X());
+ } else if (get_and_update_op == GetAndUpdateOp::kSet && value_type == DataType::Type::kFloat32) {
+ __ Fmov(out.S(), old_value.W());
+ } else if (value_type == DataType::Type::kInt8) {
+ __ Sxtb(out.W(), old_value.W());
+ } else if (value_type == DataType::Type::kInt16) {
+ __ Sxth(out.W(), old_value.W());
+ } else if (value_type == DataType::Type::kReference && codegen->EmitReadBarrier()) {
+ if (kUseBakerReadBarrier) {
+ codegen->GenerateIntrinsicMoveWithBakerReadBarrier(out.W(), old_value.W());
+ } else {
+ codegen->GenerateReadBarrierSlow(
+ invoke,
+ Location::RegisterLocation(out.GetCode()),
+ Location::RegisterLocation(old_value.GetCode()),
+ Location::RegisterLocation(target.object.GetCode()),
+ /*offset=*/ 0u,
+ /*index=*/ Location::RegisterLocation(target.offset.GetCode()));
}
}
diff --git a/compiler/optimizing/intrinsics_arm_vixl.cc b/compiler/optimizing/intrinsics_arm_vixl.cc
index 7f89f56d0c..1b1711b9de 100644
--- a/compiler/optimizing/intrinsics_arm_vixl.cc
+++ b/compiler/optimizing/intrinsics_arm_vixl.cc
@@ -16,7 +16,6 @@
#include "intrinsics_arm_vixl.h"
-#include "aarch32/constants-aarch32.h"
#include "arch/arm/callee_save_frame_arm.h"
#include "arch/arm/instruction_set_features_arm.h"
#include "art_method.h"
@@ -31,11 +30,12 @@
#include "mirror/object_array-inl.h"
#include "mirror/reference.h"
#include "mirror/string-inl.h"
-#include "optimizing/data_type.h"
#include "scoped_thread_state_change-inl.h"
#include "thread-current-inl.h"
#include "well_known_classes.h"
+#include "aarch32/constants-aarch32.h"
+
namespace art HIDDEN {
namespace arm {
@@ -3871,15 +3871,9 @@ static void CreateUnsafeGetAndUpdateLocations(HInvoke* invoke,
locations->SetInAt(2, Location::RequiresRegister());
locations->SetInAt(3, Location::RequiresRegister());
- // Request another temporary register for methods that don't return a value.
- size_t num_temps = 1u; // We always need `tmp_ptr`.
- const bool is_void = invoke->GetType() == DataType::Type::kVoid;
- if (is_void) {
- num_temps++;
- } else {
- locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
- }
+ locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
+ size_t num_temps = 1u; // We always need `tmp_ptr`.
if (get_and_update_op == GetAndUpdateOp::kAdd) {
// Add `maybe_temp` used for the new value in `GenerateGetAndUpdate()`.
num_temps += (type == DataType::Type::kInt64) ? 2u : 1u;
@@ -3900,18 +3894,10 @@ static void GenUnsafeGetAndUpdate(HInvoke* invoke,
CodeGeneratorARMVIXL* codegen,
DataType::Type type,
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);
-
ArmVIXLAssembler* assembler = codegen->GetAssembler();
LocationSummary* locations = invoke->GetLocations();
- const bool is_void = invoke->GetType() == DataType::Type::kVoid;
-
- // 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();
+ Location out = locations->Out(); // Result.
vixl32::Register base = InputRegisterAt(invoke, 1); // Object pointer.
vixl32::Register offset = LowRegisterFrom(locations->InAt(2)); // Offset (discard high 4B).
Location arg = locations->InAt(3); // New value or addend.
@@ -3944,24 +3930,24 @@ static void GenUnsafeGetAndUpdate(HInvoke* invoke,
type,
tmp_ptr,
arg,
- /*old_value=*/ out_or_temp,
+ /*old_value=*/ out,
/*store_result=*/ temp,
maybe_temp,
/*maybe_vreg_temp=*/ Location::NoLocation());
codegen->GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
- if (!is_void && type == DataType::Type::kReference && codegen->EmitReadBarrier()) {
+ if (type == DataType::Type::kReference && codegen->EmitReadBarrier()) {
DCHECK(get_and_update_op == GetAndUpdateOp::kSet);
if (kUseBakerReadBarrier) {
- codegen->GenerateIntrinsicMoveWithBakerReadBarrier(RegisterFrom(out_or_temp),
- RegisterFrom(out_or_temp));
+ codegen->GenerateIntrinsicMoveWithBakerReadBarrier(RegisterFrom(out), RegisterFrom(out));
} else {
- codegen->GenerateReadBarrierSlow(invoke,
- out_or_temp,
- out_or_temp,
- Location::RegisterLocation(base.GetCode()),
- /*offset=*/ 0u,
- /*index=*/ Location::RegisterLocation(offset.GetCode()));
+ codegen->GenerateReadBarrierSlow(
+ invoke,
+ out,
+ out,
+ Location::RegisterLocation(base.GetCode()),
+ /*offset=*/ 0u,
+ /*index=*/ Location::RegisterLocation(offset.GetCode()));
}
}
}
@@ -4670,7 +4656,6 @@ static void CreateVarHandleSetLocations(HInvoke* invoke,
LocationSummary* locations = CreateVarHandleCommonLocations(invoke, codegen);
- // Get the type from the shorty as the invokes may not return a value.
uint32_t number_of_arguments = invoke->GetNumberOfArguments();
DataType::Type value_type = GetDataTypeFromShorty(invoke, number_of_arguments - 1u);
if (DataType::Is64BitType(value_type)) {
@@ -5178,10 +5163,7 @@ static void CreateVarHandleGetAndUpdateLocations(HInvoke* invoke,
return;
}
- // Get the type from the shorty as the invokes may not return a value.
- uint32_t arg_index = invoke->GetNumberOfArguments() - 1;
- DataType::Type value_type = GetDataTypeFromShorty(invoke, arg_index);
- if (value_type == DataType::Type::kReference && codegen->EmitNonBakerReadBarrier()) {
+ if (invoke->GetType() == 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
@@ -5195,6 +5177,7 @@ static void CreateVarHandleGetAndUpdateLocations(HInvoke* invoke,
DCHECK_EQ(locations->GetTempCount(),
(GetExpectedVarHandleCoordinatesCount(invoke) == 0) ? 2u : 1u);
+ DataType::Type value_type = invoke->GetType();
if (get_and_update_op == GetAndUpdateOp::kSet) {
if (DataType::IsFloatingPointType(value_type)) {
// Add temps needed to do the GenerateGetAndUpdate() with core registers.
@@ -5228,23 +5211,6 @@ static void CreateVarHandleGetAndUpdateLocations(HInvoke* invoke,
locations->AddTemp(Location::RequiresFpuRegister());
}
}
-
- // 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)) {
- // Note: This shall allocate a D register. There is no way to request an S register.
- locations->AddTemp(Location::RequiresFpuRegister());
- } else if (DataType::Is64BitType(value_type)) {
- // We need two for non-fpu 64 bit types.
- locations->AddTemp(Location::RequiresRegister());
- locations->AddTemp(Location::RequiresRegister());
- } else {
- locations->AddTemp(Location::RequiresRegister());
- }
- }
}
static void GenerateVarHandleGetAndUpdate(HInvoke* invoke,
@@ -5252,38 +5218,13 @@ 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;
DataType::Type value_type = GetDataTypeFromShorty(invoke, arg_index);
ArmVIXLAssembler* assembler = codegen->GetAssembler();
LocationSummary* locations = invoke->GetLocations();
Location arg = locations->InAt(arg_index);
- DataType::Type return_type = invoke->GetType();
- const bool is_void = return_type == DataType::Type::kVoid;
- DCHECK_IMPLIES(!is_void, return_type == value_type);
-
- size_t temps_that_mimic_out;
- Location result;
- const size_t temp_count = locations->GetTempCount();
- if (is_void) {
- if (value_type == DataType::Type::kFloat32) {
- // Note: Since we allocated a D register, use the low part.
- DCHECK(locations->GetTemp(temp_count - 1u).IsFpuRegisterPair());
- temps_that_mimic_out = 1u;
- result = locations->GetTemp(temp_count - 1u).ToLow();
- } else if (!DataType::IsFloatingPointType(value_type) && DataType::Is64BitType(value_type)) {
- temps_that_mimic_out = 2u;
- result = LocationFrom(RegisterFrom(locations->GetTemp(temp_count - 2u)),
- RegisterFrom(locations->GetTemp(temp_count - 1u)));
- } else {
- temps_that_mimic_out = 1u;
- result = locations->GetTemp(temp_count - 1u);
- }
- } else {
- temps_that_mimic_out = 0u;
- result = locations->Out();
- }
+ Location out = locations->Out();
VarHandleTarget target = GetVarHandleTarget(invoke);
VarHandleSlowPathARMVIXL* slow_path = nullptr;
@@ -5320,7 +5261,7 @@ static void GenerateVarHandleGetAndUpdate(HInvoke* invoke,
: value_type;
// Prepare register for old value and temporaries if any.
- Location old_value = result;
+ Location old_value = out;
Location maybe_temp = Location::NoLocation();
Location maybe_vreg_temp = Location::NoLocation();
if (get_and_update_op == GetAndUpdateOp::kSet) {
@@ -5328,9 +5269,7 @@ static void GenerateVarHandleGetAndUpdate(HInvoke* invoke,
// rather than moving between core and FP registers in the loop.
if (value_type == DataType::Type::kFloat64) {
vixl32::DRegister arg_vreg = DRegisterFrom(arg);
- // `store_result` and the four here, plus maybe an extra one for the temp that mimics the
- // "out" register.
- DCHECK_EQ(temp_count, 5u + temps_that_mimic_out);
+ DCHECK_EQ(locations->GetTempCount(), 5u); // `store_result` and the four here.
old_value =
LocationFrom(RegisterFrom(locations->GetTemp(1)), RegisterFrom(locations->GetTemp(2)));
arg = LocationFrom(RegisterFrom(locations->GetTemp(3)), RegisterFrom(locations->GetTemp(4)));
@@ -5342,9 +5281,7 @@ static void GenerateVarHandleGetAndUpdate(HInvoke* invoke,
}
} else if (value_type == DataType::Type::kFloat32) {
vixl32::SRegister arg_vreg = SRegisterFrom(arg);
- // `store_result` and the two here, plus maybe an extra one for the temp that mimics the
- // "out" register.
- DCHECK_EQ(temp_count, 3u + temps_that_mimic_out);
+ DCHECK_EQ(locations->GetTempCount(), 3u); // `store_result` and the two here.
old_value = locations->GetTemp(1);
arg = locations->GetTemp(2);
__ Vmov(RegisterFrom(arg), arg_vreg);
@@ -5356,7 +5293,7 @@ static void GenerateVarHandleGetAndUpdate(HInvoke* invoke,
// Load the old value initially to a temporary register.
// We shall move it to `out` later with a read barrier.
old_value = LocationFrom(store_result);
- store_result = RegisterFrom(result); // Use `result` for the exclusive store result.
+ store_result = RegisterFrom(out); // Use the `out` for the exclusive store result.
} else {
// The store_result is a separate temporary.
DCHECK(!store_result.Is(target.object));
@@ -5368,7 +5305,7 @@ static void GenerateVarHandleGetAndUpdate(HInvoke* invoke,
if (value_type == DataType::Type::kInt64) {
arg = LocationFrom(RegisterFrom(arg), RegisterFrom(locations->GetTemp(2)));
// Swap the high/low regs and reverse the bytes in each after the load.
- old_value = LocationFrom(HighRegisterFrom(result), LowRegisterFrom(result));
+ old_value = LocationFrom(HighRegisterFrom(out), LowRegisterFrom(out));
}
GenerateReverseBytes(assembler, value_type, original_arg, arg);
}
@@ -5378,7 +5315,7 @@ static void GenerateVarHandleGetAndUpdate(HInvoke* invoke,
: locations->GetTemp(1);
DCHECK(!maybe_temp.Contains(LocationFrom(store_result)));
if (DataType::IsFloatingPointType(value_type)) {
- maybe_vreg_temp = locations->GetTemp(temp_count - 1u - temps_that_mimic_out);
+ maybe_vreg_temp = locations->GetTemp(locations->GetTempCount() - 1u);
DCHECK(maybe_vreg_temp.IsFpuRegisterPair());
}
if (byte_swap) {
@@ -5387,7 +5324,7 @@ static void GenerateVarHandleGetAndUpdate(HInvoke* invoke,
get_and_update_op = GetAndUpdateOp::kAddWithByteSwap;
} else if (value_type == DataType::Type::kInt64) {
// Swap the high/low regs and reverse the bytes in each after the load.
- old_value = LocationFrom(HighRegisterFrom(result), LowRegisterFrom(result));
+ old_value = LocationFrom(HighRegisterFrom(out), LowRegisterFrom(out));
// Due to lack of registers, reverse bytes in `arg` and undo that later.
GenerateReverseBytesInPlaceForEachWord(assembler, arg);
arg = LocationFrom(HighRegisterFrom(arg), LowRegisterFrom(arg));
@@ -5416,38 +5353,36 @@ static void GenerateVarHandleGetAndUpdate(HInvoke* invoke,
seq_cst_barrier ? MemBarrierKind::kAnyAny : MemBarrierKind::kLoadAny);
}
- if (!is_void) {
- if (byte_swap && get_and_update_op != GetAndUpdateOp::kAddWithByteSwap) {
- if (value_type == DataType::Type::kInt64) {
- GenerateReverseBytesInPlaceForEachWord(assembler, old_value);
- if (get_and_update_op != GetAndUpdateOp::kSet) {
- // Undo byte swapping in `arg`. We do not have the information
- // whether the value in these registers shall be needed later.
- GenerateReverseBytesInPlaceForEachWord(assembler, arg);
- }
- } else {
- GenerateReverseBytes(assembler, value_type, old_value, result);
- }
- } else if (get_and_update_op == GetAndUpdateOp::kSet &&
- DataType::IsFloatingPointType(value_type)) {
- if (value_type == DataType::Type::kFloat64) {
- __ Vmov(DRegisterFrom(result), LowRegisterFrom(old_value), HighRegisterFrom(old_value));
- } else {
- __ Vmov(SRegisterFrom(result), RegisterFrom(old_value));
- }
- } else if (value_type == DataType::Type::kReference && codegen->EmitReadBarrier()) {
- if (kUseBakerReadBarrier) {
- codegen->GenerateIntrinsicMoveWithBakerReadBarrier(RegisterFrom(result),
- RegisterFrom(old_value));
- } else {
- codegen->GenerateReadBarrierSlow(
- invoke,
- Location::RegisterLocation(RegisterFrom(result).GetCode()),
- Location::RegisterLocation(RegisterFrom(old_value).GetCode()),
- Location::RegisterLocation(target.object.GetCode()),
- /*offset=*/ 0u,
- /*index=*/ Location::RegisterLocation(target.offset.GetCode()));
+ if (byte_swap && get_and_update_op != GetAndUpdateOp::kAddWithByteSwap) {
+ if (value_type == DataType::Type::kInt64) {
+ GenerateReverseBytesInPlaceForEachWord(assembler, old_value);
+ if (get_and_update_op != GetAndUpdateOp::kSet) {
+ // Undo byte swapping in `arg`. We do not have the information
+ // whether the value in these registers shall be needed later.
+ GenerateReverseBytesInPlaceForEachWord(assembler, arg);
}
+ } else {
+ GenerateReverseBytes(assembler, value_type, old_value, out);
+ }
+ } else if (get_and_update_op == GetAndUpdateOp::kSet &&
+ DataType::IsFloatingPointType(value_type)) {
+ if (value_type == DataType::Type::kFloat64) {
+ __ Vmov(DRegisterFrom(out), LowRegisterFrom(old_value), HighRegisterFrom(old_value));
+ } else {
+ __ Vmov(SRegisterFrom(out), RegisterFrom(old_value));
+ }
+ } else if (value_type == DataType::Type::kReference && codegen->EmitReadBarrier()) {
+ if (kUseBakerReadBarrier) {
+ codegen->GenerateIntrinsicMoveWithBakerReadBarrier(RegisterFrom(out),
+ RegisterFrom(old_value));
+ } else {
+ codegen->GenerateReadBarrierSlow(
+ invoke,
+ Location::RegisterLocation(RegisterFrom(out).GetCode()),
+ Location::RegisterLocation(RegisterFrom(old_value).GetCode()),
+ Location::RegisterLocation(target.object.GetCode()),
+ /*offset=*/ 0u,
+ /*index=*/ Location::RegisterLocation(target.offset.GetCode()));
}
}
diff --git a/compiler/optimizing/intrinsics_riscv64.cc b/compiler/optimizing/intrinsics_riscv64.cc
index f078beb1a4..2bc8cad71a 100644
--- a/compiler/optimizing/intrinsics_riscv64.cc
+++ b/compiler/optimizing/intrinsics_riscv64.cc
@@ -2955,35 +2955,20 @@ static void CreateUnsafeGetAndUpdateLocations(ArenaAllocator* allocator,
locations->SetInAt(2, Location::RequiresRegister());
locations->SetInAt(3, Location::RequiresRegister());
- // 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);
- }
+ 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();
- 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.
+ 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.
// This needs to be before the temp registers, as MarkGCCard also uses scratch registers.
if (type == DataType::Type::kReference) {
@@ -3002,28 +2987,28 @@ static void GenUnsafeGetAndUpdate(HInvoke* invoke,
std::memory_order_seq_cst,
tmp_ptr,
arg,
- /*old_value=*/ out_or_temp,
+ /*old_value=*/ out,
/*mask=*/ kNoXRegister,
/*temp=*/ kNoXRegister);
- if (!is_void && type == DataType::Type::kReference) {
- __ ZextW(out_or_temp, out_or_temp);
+ if (type == DataType::Type::kReference) {
+ __ ZextW(out, out);
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_or_temp_loc, kBakerReadBarrierTemp);
- codegen->EmitBakerReadBarierMarkingCheck(
- rb_slow_path, out_or_temp_loc, kBakerReadBarrierTemp);
+ SlowPathCodeRISCV64* rb_slow_path =
+ codegen->AddGcRootBakerBarrierBarrierSlowPath(invoke, out_loc, kBakerReadBarrierTemp);
+ codegen->EmitBakerReadBarierMarkingCheck(rb_slow_path, out_loc, kBakerReadBarrierTemp);
} else {
- codegen->GenerateReadBarrierSlow(invoke,
- out_or_temp_loc,
- out_or_temp_loc,
- Location::RegisterLocation(base),
- /*offset=*/ 0u,
- /*index=*/ Location::RegisterLocation(offset));
+ codegen->GenerateReadBarrierSlow(
+ invoke,
+ out_loc,
+ out_loc,
+ Location::RegisterLocation(base),
+ /*offset=*/ 0u,
+ /*index=*/ Location::RegisterLocation(offset));
}
}
}
@@ -4465,11 +4450,7 @@ static void CreateVarHandleGetAndUpdateLocations(HInvoke* invoke,
return;
}
- // 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()) {
+ if (invoke->GetType() == 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
@@ -4477,10 +4458,15 @@ static void CreateVarHandleGetAndUpdateLocations(HInvoke* invoke,
}
// TODO(riscv64): Fix this intrinsic for heap poisoning configuration.
- if (kPoisonHeapReferences && value_type == DataType::Type::kReference) {
+ if (kPoisonHeapReferences && invoke->GetType() == 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);
@@ -4531,19 +4517,6 @@ 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,
@@ -4551,21 +4524,16 @@ 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 = GetDataTypeFromShorty(invoke, arg_index);
+ DataType::Type value_type = invoke->GetType();
+ DCHECK_EQ(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());
- 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();
+ Location out = locations->Out();
VarHandleTarget target = GetVarHandleTarget(invoke);
VarHandleSlowPathRISCV64* slow_path = nullptr;
@@ -4621,8 +4589,6 @@ 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;
@@ -4712,24 +4678,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_or_temp, old_value, shift, value_type);
+ GenerateByteSwapAndExtract(codegen, out, old_value, shift, value_type);
} else {
DCHECK(is_fp);
- codegen->MoveLocation(out_or_temp, Location::RegisterLocation(old_value), value_type);
+ codegen->MoveLocation(out, Location::RegisterLocation(old_value), value_type);
}
if (is_fp) {
codegen->GetInstructionVisitor()->FAdd(
- ftmp, out_or_temp.AsFpuRegister<FRegister>(), arg.AsFpuRegister<FRegister>(), value_type);
+ ftmp, out.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_or_temp.AsRegister<XRegister>());
+ __ Mv(new_value, out.AsRegister<XRegister>());
} else if (value_type == DataType::Type::kInt64) {
- __ Add(new_value, out_or_temp.AsRegister<XRegister>(), arg.AsRegister<XRegister>());
+ __ Add(new_value, out.AsRegister<XRegister>(), arg.AsRegister<XRegister>());
} else {
DCHECK_EQ(op_type, DataType::Type::kInt32);
- __ Addw(new_value, out_or_temp.AsRegister<XRegister>(), arg.AsRegister<XRegister>());
+ __ Addw(new_value, out.AsRegister<XRegister>(), arg.AsRegister<XRegister>());
}
if (byte_swap) {
DataType::Type swap_type = op_type;
@@ -4740,7 +4706,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_or_temp.AsRegister<XRegister>());
+ __ Xor(new_value, new_value, out.AsRegister<XRegister>());
}
GenerateReverseBytes(codegen, Location::RegisterLocation(new_value), new_value, swap_type);
if (is_small) {
@@ -4761,15 +4727,15 @@ static void GenerateVarHandleGetAndUpdate(HInvoke* invoke,
store_result,
/*expected=*/ old_value);
} else {
- XRegister old_value = is_fp ? get_temp() : out_or_temp.AsRegister<XRegister>();
+ XRegister old_value = is_fp ? get_temp() : out.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_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);
+ DCHECK_IMPLIES(is_small, out.AsRegister<XRegister>() == old_value)
+ << " " << value_type << " " << out.AsRegister<XRegister>() << "!=" << old_value;
+ GenerateByteSwapAndExtract(codegen, out, old_value, shift, value_type);
} else if (is_fp) {
- codegen->MoveLocation(out_or_temp, Location::RegisterLocation(old_value), value_type);
+ codegen->MoveLocation(out, Location::RegisterLocation(old_value), value_type);
} else if (is_small) {
__ Srlw(old_value, old_value, shift);
DCHECK_NE(value_type, DataType::Type::kUint8);
@@ -4788,14 +4754,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_or_temp, kBakerReadBarrierTemp);
- codegen->EmitBakerReadBarierMarkingCheck(rb_slow_path, out_or_temp, kBakerReadBarrierTemp);
+ SlowPathCodeRISCV64* rb_slow_path =
+ codegen->AddGcRootBakerBarrierBarrierSlowPath(invoke, out, kBakerReadBarrierTemp);
+ codegen->EmitBakerReadBarierMarkingCheck(rb_slow_path, out, 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_or_temp, out_or_temp, base_loc, /*offset=*/ 0u, index);
+ invoke, out, out, base_loc, /*offset=*/ 0u, index);
__ J(rb_slow_path->GetEntryLabel());
__ Bind(rb_slow_path->GetExitLabel());
}
@@ -4809,11 +4775,8 @@ 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() - extra_temp_registers) {
+ if ((!has_byte_swap || byte_swap) && next_temp != locations->GetTempCount()) {
// 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);
diff --git a/compiler/optimizing/intrinsics_utils.h b/compiler/optimizing/intrinsics_utils.h
index 6c08cea3f8..13d9bc4b68 100644
--- a/compiler/optimizing/intrinsics_utils.h
+++ b/compiler/optimizing/intrinsics_utils.h
@@ -111,7 +111,7 @@ static inline size_t GetExpectedVarHandleCoordinatesCount(HInvoke *invoke) {
}
static inline DataType::Type GetDataTypeFromShorty(HInvoke* invoke, uint32_t index) {
- DCHECK(invoke->IsInvokePolymorphic()) << *invoke;
+ DCHECK(invoke->IsInvokePolymorphic());
const DexFile* dex_file = invoke->GetMethodReference().dex_file;
const char* shorty = dex_file->GetShorty(invoke->AsInvokePolymorphic()->GetProtoIndex());
DCHECK_LT(index, strlen(shorty));
diff --git a/compiler/optimizing/intrinsics_x86.cc b/compiler/optimizing/intrinsics_x86.cc
index dc88de474c..2b83ba8349 100644
--- a/compiler/optimizing/intrinsics_x86.cc
+++ b/compiler/optimizing/intrinsics_x86.cc
@@ -34,7 +34,6 @@
#include "mirror/reference.h"
#include "mirror/string.h"
#include "mirror/var_handle.h"
-#include "optimizing/data_type.h"
#include "scoped_thread_state_change-inl.h"
#include "thread-current-inl.h"
#include "utils/x86/assembler_x86.h"
@@ -2490,7 +2489,6 @@ void CreateUnsafeGetAndUpdateLocations(ArenaAllocator* allocator,
locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
}
locations->SetInAt(0, Location::NoLocation()); // Unused receiver.
- const bool is_void = invoke->GetType() == DataType::Type::kVoid;
if (type == DataType::Type::kInt64) {
// Explicitly allocate all registers.
locations->SetInAt(1, Location::RegisterLocation(EBP));
@@ -2504,23 +2502,14 @@ void CreateUnsafeGetAndUpdateLocations(ArenaAllocator* allocator,
locations->SetInAt(2, Location::RegisterPairLocation(ESI, EDI));
locations->SetInAt(3, Location::RegisterPairLocation(EBX, ECX));
}
- if (is_void) {
- locations->AddTemp(Location::RegisterLocation(EAX));
- locations->AddTemp(Location::RegisterLocation(EDX));
- } else {
- locations->SetOut(Location::RegisterPairLocation(EAX, EDX), Location::kOutputOverlap);
- }
+ locations->SetOut(Location::RegisterPairLocation(EAX, EDX), Location::kOutputOverlap);
} else {
locations->SetInAt(1, Location::RequiresRegister());
locations->SetInAt(2, Location::RequiresRegister());
// Use the same register for both the output and the new value or addend
// to take advantage of XCHG or XADD. Arbitrarily pick EAX.
locations->SetInAt(3, Location::RegisterLocation(EAX));
- // Only set the `out` register if it's needed. In the void case we can still use EAX in the
- // same manner as it is used an as `in` register.
- if (!is_void) {
- locations->SetOut(Location::RegisterLocation(EAX));
- }
+ locations->SetOut(Location::RegisterLocation(EAX));
}
}
@@ -2584,20 +2573,14 @@ static void GenUnsafeGetAndUpdate(HInvoke* invoke,
X86Assembler* assembler = down_cast<X86Assembler*>(codegen->GetAssembler());
LocationSummary* locations = invoke->GetLocations();
- const bool is_void = invoke->GetType() == DataType::Type::kVoid;
- // We use requested specific registers to use as temps for void methods, as we don't return the
- // value.
- Location out_or_temp =
- is_void ? (type == DataType::Type::kInt64 ? Location::RegisterPairLocation(EAX, EDX) :
- Location::RegisterLocation(EAX)) :
- locations->Out();
+ Location out = locations->Out(); // Result.
Register base = locations->InAt(1).AsRegister<Register>(); // Object pointer.
Location offset = locations->InAt(2); // Long offset.
Location arg = locations->InAt(3); // New value or addend.
if (type == DataType::Type::kInt32) {
- DCHECK(out_or_temp.Equals(arg));
- Register out_reg = out_or_temp.AsRegister<Register>();
+ DCHECK(out.Equals(arg));
+ Register out_reg = out.AsRegister<Register>();
Address field_address(base, offset.AsRegisterPairLow<Register>(), TIMES_1, 0);
if (get_and_update_op == GetAndUpdateOp::kAdd) {
__ LockXaddl(field_address, out_reg);
@@ -2638,7 +2621,7 @@ static void GenUnsafeGetAndUpdate(HInvoke* invoke,
} else {
DCHECK_EQ(type, DataType::Type::kReference);
DCHECK(get_and_update_op == GetAndUpdateOp::kSet);
- Register out_reg = out_or_temp.AsRegister<Register>();
+ Register out_reg = out.AsRegister<Register>();
Address field_address(base, offset.AsRegisterPairLow<Register>(), TIMES_1, 0);
Register temp1 = locations->GetTemp(0).AsRegister<Register>();
Register temp2 = locations->GetTemp(1).AsRegister<Register>();
@@ -2667,10 +2650,8 @@ static void GenUnsafeGetAndUpdate(HInvoke* invoke,
__ movl(temp1, out_reg);
__ PoisonHeapReference(temp1);
__ xchgl(temp1, field_address);
- if (!is_void) {
- __ UnpoisonHeapReference(temp1);
- __ movl(out_reg, temp1);
- }
+ __ UnpoisonHeapReference(temp1);
+ __ movl(out_reg, temp1);
} else {
__ xchgl(out_reg, field_address);
}
@@ -4256,13 +4237,9 @@ static void CreateVarHandleGetAndSetLocations(HInvoke* invoke, CodeGeneratorX86*
return;
}
- // Get the type from the shorty as the invokes may not return a value.
uint32_t number_of_arguments = invoke->GetNumberOfArguments();
uint32_t value_index = number_of_arguments - 1;
DataType::Type value_type = GetDataTypeFromShorty(invoke, value_index);
- DataType::Type return_type = invoke->GetType();
- const bool is_void = return_type == DataType::Type::kVoid;
- DCHECK_IMPLIES(!is_void, return_type == value_type);
if (DataType::Is64BitType(value_type)) {
// We avoid the case of an Int64/Float64 value because we would need to place it in a register
@@ -4289,17 +4266,10 @@ static void CreateVarHandleGetAndSetLocations(HInvoke* invoke, CodeGeneratorX86*
if (value_type == DataType::Type::kFloat32) {
locations->AddTemp(Location::RegisterLocation(EAX));
locations->SetInAt(value_index, Location::FpuRegisterOrConstant(invoke->InputAt(value_index)));
- // Only set the `out` register if it's needed. In the void case, we will not use `out`.
- if (!is_void) {
- locations->SetOut(Location::RequiresFpuRegister());
- }
+ locations->SetOut(Location::RequiresFpuRegister());
} else {
locations->SetInAt(value_index, Location::RegisterLocation(EAX));
- // Only set the `out` register if it's needed. In the void case we can still use EAX in the
- // same manner as it is used an as `in` register.
- if (!is_void) {
- locations->SetOut(Location::RegisterLocation(EAX));
- }
+ locations->SetOut(Location::RegisterLocation(EAX));
}
}
@@ -4313,7 +4283,6 @@ static void GenerateVarHandleGetAndSet(HInvoke* invoke, CodeGeneratorX86* codege
// The value we want to set is the last argument
uint32_t value_index = invoke->GetNumberOfArguments() - 1;
Location value = locations->InAt(value_index);
- // Get the type from the shorty as the invokes may not return a value.
DataType::Type value_type = GetDataTypeFromShorty(invoke, value_index);
Register temp = locations->GetTemp(1).AsRegister<Register>();
Register temp2 = locations->GetTemp(2).AsRegister<Register>();
@@ -4338,36 +4307,24 @@ static void GenerateVarHandleGetAndSet(HInvoke* invoke, CodeGeneratorX86* codege
// fields the object is in a separate register, it is safe to use the first temporary register.
temp = expected_coordinates_count == 1u ? temp : locations->GetTemp(3).AsRegister<Register>();
// No need for a lock prefix. `xchg` has an implicit lock when it is used with an address.
-
- DataType::Type return_type = invoke->GetType();
- const bool is_void = return_type == DataType::Type::kVoid;
- DCHECK_IMPLIES(!is_void, return_type == value_type);
switch (value_type) {
case DataType::Type::kBool:
__ xchgb(value.AsRegister<ByteRegister>(), field_addr);
- if (!is_void) {
- __ movzxb(locations->Out().AsRegister<Register>(),
- locations->Out().AsRegister<ByteRegister>());
- }
+ __ movzxb(locations->Out().AsRegister<Register>(),
+ locations->Out().AsRegister<ByteRegister>());
break;
case DataType::Type::kInt8:
__ xchgb(value.AsRegister<ByteRegister>(), field_addr);
- if (!is_void) {
- __ movsxb(locations->Out().AsRegister<Register>(),
- locations->Out().AsRegister<ByteRegister>());
- }
+ __ movsxb(locations->Out().AsRegister<Register>(),
+ locations->Out().AsRegister<ByteRegister>());
break;
case DataType::Type::kUint16:
__ xchgw(value.AsRegister<Register>(), field_addr);
- if (!is_void) {
- __ movzxw(locations->Out().AsRegister<Register>(), locations->Out().AsRegister<Register>());
- }
+ __ movzxw(locations->Out().AsRegister<Register>(), locations->Out().AsRegister<Register>());
break;
case DataType::Type::kInt16:
__ xchgw(value.AsRegister<Register>(), field_addr);
- if (!is_void) {
- __ movsxw(locations->Out().AsRegister<Register>(), locations->Out().AsRegister<Register>());
- }
+ __ movsxw(locations->Out().AsRegister<Register>(), locations->Out().AsRegister<Register>());
break;
case DataType::Type::kInt32:
__ xchgl(value.AsRegister<Register>(), field_addr);
@@ -4375,9 +4332,7 @@ static void GenerateVarHandleGetAndSet(HInvoke* invoke, CodeGeneratorX86* codege
case DataType::Type::kFloat32:
codegen->Move32(Location::RegisterLocation(EAX), value);
__ xchgl(EAX, field_addr);
- if (!is_void) {
- __ movd(locations->Out().AsFpuRegister<XmmRegister>(), EAX);
- }
+ __ movd(locations->Out().AsFpuRegister<XmmRegister>(), EAX);
break;
case DataType::Type::kReference: {
if (codegen->EmitBakerReadBarrier()) {
@@ -4398,13 +4353,10 @@ static void GenerateVarHandleGetAndSet(HInvoke* invoke, CodeGeneratorX86* codege
__ movl(temp, value.AsRegister<Register>());
__ PoisonHeapReference(temp);
__ xchgl(temp, field_addr);
- if (!is_void) {
- __ UnpoisonHeapReference(temp);
- __ movl(locations->Out().AsRegister<Register>(), temp);
- }
+ __ UnpoisonHeapReference(temp);
+ __ movl(locations->Out().AsRegister<Register>(), temp);
} else {
- DCHECK_IMPLIES(!is_void, locations->Out().Equals(Location::RegisterLocation(EAX)));
- __ xchgl(Location::RegisterLocation(EAX).AsRegister<Register>(), field_addr);
+ __ xchgl(locations->Out().AsRegister<Register>(), field_addr);
}
break;
}
@@ -4638,7 +4590,6 @@ static void CreateVarHandleGetAndAddLocations(HInvoke* invoke, CodeGeneratorX86*
return;
}
- // Get the type from the shorty as the invokes may not return a value.
// The last argument should be the value we intend to set.
uint32_t value_index = invoke->GetNumberOfArguments() - 1;
DataType::Type value_type = GetDataTypeFromShorty(invoke, value_index);
@@ -4664,26 +4615,15 @@ static void CreateVarHandleGetAndAddLocations(HInvoke* invoke, CodeGeneratorX86*
locations->AddTemp(Location::RequiresRegister());
}
- DataType::Type return_type = invoke->GetType();
- const bool is_void = return_type == DataType::Type::kVoid;
- DCHECK_IMPLIES(!is_void, return_type == value_type);
-
if (DataType::IsFloatingPointType(value_type)) {
locations->AddTemp(Location::RequiresFpuRegister());
locations->AddTemp(Location::RegisterLocation(EAX));
locations->SetInAt(value_index, Location::RequiresFpuRegister());
- // Only set the `out` register if it's needed. In the void case, we do not use `out`.
- if (!is_void) {
- locations->SetOut(Location::RequiresFpuRegister());
- }
+ locations->SetOut(Location::RequiresFpuRegister());
} else {
// xadd updates the register argument with the old value. ByteRegister required for xaddb.
locations->SetInAt(value_index, Location::RegisterLocation(EAX));
- // Only set the `out` register if it's needed. In the void case we can still use EAX in the
- // same manner as it is used an as `in` register.
- if (!is_void) {
- locations->SetOut(Location::RegisterLocation(EAX));
- }
+ locations->SetOut(Location::RegisterLocation(EAX));
}
}
@@ -4696,11 +4636,8 @@ static void GenerateVarHandleGetAndAdd(HInvoke* invoke, CodeGeneratorX86* codege
LocationSummary* locations = invoke->GetLocations();
uint32_t number_of_arguments = invoke->GetNumberOfArguments();
uint32_t value_index = number_of_arguments - 1;
- // Get the type from the shorty as the invokes may not return a value.
DataType::Type type = GetDataTypeFromShorty(invoke, value_index);
- DataType::Type return_type = invoke->GetType();
- const bool is_void = return_type == DataType::Type::kVoid;
- DCHECK_IMPLIES(!is_void, return_type == type);
+ DCHECK_EQ(type, invoke->GetType());
Location value_loc = locations->InAt(value_index);
Register temp = locations->GetTemp(0).AsRegister<Register>();
SlowPathCode* slow_path = new (codegen->GetScopedAllocator()) IntrinsicSlowPathX86(invoke);
@@ -4722,22 +4659,16 @@ static void GenerateVarHandleGetAndAdd(HInvoke* invoke, CodeGeneratorX86* codege
switch (type) {
case DataType::Type::kInt8:
__ LockXaddb(field_addr, value_loc.AsRegister<ByteRegister>());
- if (!is_void) {
- __ movsxb(locations->Out().AsRegister<Register>(),
- locations->Out().AsRegister<ByteRegister>());
- }
+ __ movsxb(locations->Out().AsRegister<Register>(),
+ locations->Out().AsRegister<ByteRegister>());
break;
case DataType::Type::kInt16:
__ LockXaddw(field_addr, value_loc.AsRegister<Register>());
- if (!is_void) {
- __ movsxw(locations->Out().AsRegister<Register>(), locations->Out().AsRegister<Register>());
- }
+ __ movsxw(locations->Out().AsRegister<Register>(), locations->Out().AsRegister<Register>());
break;
case DataType::Type::kUint16:
__ LockXaddw(field_addr, value_loc.AsRegister<Register>());
- if (!is_void) {
- __ movzxw(locations->Out().AsRegister<Register>(), locations->Out().AsRegister<Register>());
- }
+ __ movzxw(locations->Out().AsRegister<Register>(), locations->Out().AsRegister<Register>());
break;
case DataType::Type::kInt32:
__ LockXaddl(field_addr, value_loc.AsRegister<Register>());
@@ -4762,10 +4693,8 @@ static void GenerateVarHandleGetAndAdd(HInvoke* invoke, CodeGeneratorX86* codege
temp);
__ j(kNotZero, &try_again);
- if (!is_void) {
- // The old value is present in EAX.
- codegen->Move32(locations->Out(), eax);
- }
+ // The old value is present in EAX.
+ codegen->Move32(locations->Out(), eax);
break;
}
default:
@@ -4811,11 +4740,9 @@ static void CreateVarHandleGetAndBitwiseOpLocations(HInvoke* invoke, CodeGenerat
return;
}
- // Get the type from the shorty as the invokes may not return a value.
// The last argument should be the value we intend to set.
uint32_t value_index = invoke->GetNumberOfArguments() - 1;
- DataType::Type value_type = GetDataTypeFromShorty(invoke, value_index);
- if (DataType::Is64BitType(value_type)) {
+ if (DataType::Is64BitType(GetDataTypeFromShorty(invoke, value_index))) {
// We avoid the case of an Int64 value because we would need to place it in a register pair.
// If the slow path is taken, the ParallelMove might fail to move the pair according to the
// X86DexCallingConvention in case of an overlap (e.g., move the 64 bit value from
@@ -4840,18 +4767,7 @@ static void CreateVarHandleGetAndBitwiseOpLocations(HInvoke* invoke, CodeGenerat
}
locations->SetInAt(value_index, Location::RegisterOrConstant(invoke->InputAt(value_index)));
-
- 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) {
- // Used as a temporary, even when we are not outputting it so reserve it. This has to be
- // requested before the other temporary since there's variable number of temp registers and the
- // other temp register is expected to be the last one.
- locations->AddTemp(Location::RegisterLocation(EAX));
- } else {
- locations->SetOut(Location::RegisterLocation(EAX));
- }
+ locations->SetOut(Location::RegisterLocation(EAX));
}
static void GenerateBitwiseOp(HInvoke* invoke,
@@ -4889,12 +4805,9 @@ static void GenerateVarHandleGetAndBitwiseOp(HInvoke* invoke, CodeGeneratorX86*
X86Assembler* assembler = codegen->GetAssembler();
LocationSummary* locations = invoke->GetLocations();
- // Get the type from the shorty as the invokes may not return a value.
uint32_t value_index = invoke->GetNumberOfArguments() - 1;
DataType::Type type = GetDataTypeFromShorty(invoke, value_index);
- DataType::Type return_type = invoke->GetType();
- const bool is_void = return_type == DataType::Type::kVoid;
- DCHECK_IMPLIES(!is_void, return_type == type);
+ DCHECK_EQ(type, invoke->GetType());
Register temp = locations->GetTemp(0).AsRegister<Register>();
SlowPathCode* slow_path = new (codegen->GetScopedAllocator()) IntrinsicSlowPathX86(invoke);
codegen->AddSlowPath(slow_path);
@@ -4913,9 +4826,8 @@ static void GenerateVarHandleGetAndBitwiseOp(HInvoke* invoke, CodeGeneratorX86*
DCHECK_NE(temp, reference);
Address field_addr(reference, offset, TIMES_1, 0);
- Location eax_loc = Location::RegisterLocation(EAX);
- Register eax = eax_loc.AsRegister<Register>();
- DCHECK_IMPLIES(!is_void, locations->Out().Equals(eax_loc));
+ Register out = locations->Out().AsRegister<Register>();
+ DCHECK_EQ(out, EAX);
if (invoke->GetIntrinsic() == Intrinsics::kVarHandleGetAndBitwiseOrRelease ||
invoke->GetIntrinsic() == Intrinsics::kVarHandleGetAndBitwiseXorRelease ||
@@ -4926,12 +4838,12 @@ static void GenerateVarHandleGetAndBitwiseOp(HInvoke* invoke, CodeGeneratorX86*
NearLabel try_again;
__ Bind(&try_again);
// Place the expected value in EAX for cmpxchg
- codegen->LoadFromMemoryNoBarrier(type, eax_loc, field_addr);
+ codegen->LoadFromMemoryNoBarrier(type, locations->Out(), field_addr);
codegen->Move32(locations->GetTemp(0), locations->InAt(value_index));
- GenerateBitwiseOp(invoke, codegen, temp, eax);
+ GenerateBitwiseOp(invoke, codegen, temp, out);
GenPrimitiveLockedCmpxchg(type,
codegen,
- /* expected_value= */ eax_loc,
+ /* expected_value= */ locations->Out(),
/* new_value= */ locations->GetTemp(0),
reference,
offset);
diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc
index ba254ee705..6424201c4b 100644
--- a/compiler/optimizing/intrinsics_x86_64.cc
+++ b/compiler/optimizing/intrinsics_x86_64.cc
@@ -27,8 +27,8 @@
#include "entrypoints/quick/quick_entrypoints.h"
#include "entrypoints/quick/quick_entrypoints_enum.h"
#include "heap_poisoning.h"
-#include "intrinsic_objects.h"
#include "intrinsics.h"
+#include "intrinsic_objects.h"
#include "intrinsics_utils.h"
#include "lock_word.h"
#include "mirror/array-inl.h"
@@ -36,7 +36,6 @@
#include "mirror/reference.h"
#include "mirror/string.h"
#include "optimizing/code_generator.h"
-#include "optimizing/data_type.h"
#include "scoped_thread_state_change-inl.h"
#include "thread-current-inl.h"
#include "utils/x86_64/assembler_x86_64.h"
@@ -2634,11 +2633,7 @@ static void CreateUnsafeGetAndUpdateLocations(ArenaAllocator* allocator,
// Use the same register for both the output and the new value or addend
// to take advantage of XCHG or XADD. Arbitrarily pick RAX.
locations->SetInAt(3, Location::RegisterLocation(RAX));
- // Only set the `out` register if it's needed. In the void case we can still use RAX in the
- // same manner as it is used an as `in` register.
- if (invoke->GetType() != DataType::Type::kVoid) {
- locations->SetOut(Location::RegisterLocation(RAX));
- }
+ locations->SetOut(Location::RegisterLocation(RAX));
}
void IntrinsicLocationsBuilderX86_64::VisitUnsafeGetAndAddInt(HInvoke* invoke) {
@@ -2702,29 +2697,25 @@ static void GenUnsafeGetAndUpdate(HInvoke* invoke,
X86_64Assembler* assembler = down_cast<X86_64Assembler*>(codegen->GetAssembler());
LocationSummary* locations = invoke->GetLocations();
- const bool is_void = invoke->GetType() == DataType::Type::kVoid;
- Location rax_loc = Location::RegisterLocation(RAX);
- // We requested RAX to use as a temporary for void methods, as we don't return the value.
- DCHECK_IMPLIES(!is_void, locations->Out().Equals(rax_loc));
- CpuRegister out_or_temp = rax_loc.AsRegister<CpuRegister>(); // Result.
- CpuRegister base = locations->InAt(1).AsRegister<CpuRegister>(); // Object pointer.
- CpuRegister offset = locations->InAt(2).AsRegister<CpuRegister>(); // Long offset.
- DCHECK_EQ(out_or_temp, locations->InAt(3).AsRegister<CpuRegister>()); // New value or addend.
+ CpuRegister out = locations->Out().AsRegister<CpuRegister>(); // Result.
+ CpuRegister base = locations->InAt(1).AsRegister<CpuRegister>(); // Object pointer.
+ CpuRegister offset = locations->InAt(2).AsRegister<CpuRegister>(); // Long offset.
+ DCHECK_EQ(out, locations->InAt(3).AsRegister<CpuRegister>()); // New value or addend.
Address field_address(base, offset, TIMES_1, 0);
if (type == DataType::Type::kInt32) {
if (get_and_update_op == GetAndUpdateOp::kAdd) {
- __ LockXaddl(field_address, out_or_temp);
+ __ LockXaddl(field_address, out);
} else {
DCHECK(get_and_update_op == GetAndUpdateOp::kSet);
- __ xchgl(out_or_temp, field_address);
+ __ xchgl(out, field_address);
}
} else if (type == DataType::Type::kInt64) {
if (get_and_update_op == GetAndUpdateOp::kAdd) {
- __ LockXaddq(field_address, out_or_temp);
+ __ LockXaddq(field_address, out);
} else {
DCHECK(get_and_update_op == GetAndUpdateOp::kSet);
- __ xchgq(out_or_temp, field_address);
+ __ xchgq(out, field_address);
}
} else {
DCHECK_EQ(type, DataType::Type::kReference);
@@ -2749,20 +2740,18 @@ static void GenUnsafeGetAndUpdate(HInvoke* invoke,
// Mark card for object as a new value shall be stored.
bool new_value_can_be_null = true; // TODO: Worth finding out this information?
- codegen->MaybeMarkGCCard(temp1, temp2, base, /*value=*/out_or_temp, new_value_can_be_null);
+ codegen->MaybeMarkGCCard(temp1, temp2, base, /*value=*/out, new_value_can_be_null);
if (kPoisonHeapReferences) {
// Use a temp to avoid poisoning base of the field address, which might happen if `out`
// is the same as `base` (for code like `unsafe.getAndSet(obj, offset, obj)`).
- __ movl(temp1, out_or_temp);
+ __ movl(temp1, out);
__ PoisonHeapReference(temp1);
__ xchgl(temp1, field_address);
- if (!is_void) {
- __ UnpoisonHeapReference(temp1);
- __ movl(out_or_temp, temp1);
- }
+ __ UnpoisonHeapReference(temp1);
+ __ movl(out, temp1);
} else {
- __ xchgl(out_or_temp, field_address);
+ __ xchgl(out, field_address);
}
}
}
@@ -4498,33 +4487,23 @@ static void CreateVarHandleGetAndSetLocations(HInvoke* invoke, CodeGeneratorX86_
return;
}
- // Get the type from the shorty as the invokes may not return a value.
uint32_t number_of_arguments = invoke->GetNumberOfArguments();
uint32_t new_value_index = number_of_arguments - 1;
- DataType::Type value_type = GetDataTypeFromShorty(invoke, new_value_index);
- DataType::Type return_type = invoke->GetType();
- const bool is_void = return_type == DataType::Type::kVoid;
- DCHECK_IMPLIES(!is_void, return_type == value_type);
+ DataType::Type type = invoke->GetType();
+ DCHECK_EQ(type, GetDataTypeFromShorty(invoke, new_value_index));
LocationSummary* locations = CreateVarHandleCommonLocations(invoke);
- if (DataType::IsFloatingPointType(value_type)) {
- // Only set the `out` register if it's needed. In the void case we don't use `out`.
- if (!is_void) {
- locations->SetOut(Location::RequiresFpuRegister());
- }
+ if (DataType::IsFloatingPointType(type)) {
+ locations->SetOut(Location::RequiresFpuRegister());
// A temporary is needed to load the new floating-point value into a register for XCHG.
locations->AddTemp(Location::RequiresRegister());
} else {
- // Only set the `out` register if it's needed. In the void case we can still use RAX in the
- // same manner as it is used an as `in` register.
- if (!is_void) {
- // Use the same register for both the new value and output to take advantage of XCHG.
- // It doesn't have to be RAX, but we need to choose some to make sure it's the same.
- locations->SetOut(Location::RegisterLocation(RAX));
- }
+ // Use the same register for both the new value and output to take advantage of XCHG.
+ // It doesn't have to be RAX, but we need to choose some to make sure it's the same.
+ locations->SetOut(Location::RegisterLocation(RAX));
locations->SetInAt(new_value_index, Location::RegisterLocation(RAX));
- if (value_type == DataType::Type::kReference) {
+ if (type == DataType::Type::kReference) {
// Need two temporaries for MarkGCCard.
locations->AddRegisterTemps(2);
if (codegen->EmitReadBarrier()) {
@@ -4547,9 +4526,6 @@ static void GenerateVarHandleGetAndSet(HInvoke* invoke,
LocationSummary* locations = invoke->GetLocations();
Location out = locations->Out();
uint32_t temp_count = locations->GetTempCount();
- DataType::Type return_type = invoke->GetType();
- const bool is_void = return_type == DataType::Type::kVoid;
- DCHECK_IMPLIES(!is_void, return_type == type);
if (DataType::IsFloatingPointType(type)) {
// `getAndSet` for floating-point types: move the new FP value into a register, atomically
@@ -4569,9 +4545,7 @@ static void GenerateVarHandleGetAndSet(HInvoke* invoke,
if (byte_swap) {
codegen->GetInstructionCodegen()->Bswap(temp, bswap_type);
}
- if (!is_void) {
- __ movd(out.AsFpuRegister<XmmRegister>(), temp.AsRegister<CpuRegister>(), is64bit);
- }
+ __ movd(out.AsFpuRegister<XmmRegister>(), temp.AsRegister<CpuRegister>(), is64bit);
} else if (type == DataType::Type::kReference) {
// `getAndSet` for references: load reference and atomically exchange it with the field.
// Output register is the same as the one holding new value, so no need to move the result.
@@ -4594,17 +4568,15 @@ static void GenerateVarHandleGetAndSet(HInvoke* invoke,
}
codegen->MarkGCCard(temp1, temp2, ref);
- DCHECK_IMPLIES(!is_void, valreg == out.AsRegister<CpuRegister>());
+ DCHECK_EQ(valreg, out.AsRegister<CpuRegister>());
if (kPoisonHeapReferences) {
// Use a temp to avoid poisoning base of the field address, which might happen if `valreg` is
// the same as `target.object` (for code like `vh.getAndSet(obj, obj)`).
__ movl(temp1, valreg);
__ PoisonHeapReference(temp1);
__ xchgl(temp1, field_addr);
- if (!is_void) {
- __ UnpoisonHeapReference(temp1);
- __ movl(valreg, temp1);
- }
+ __ UnpoisonHeapReference(temp1);
+ __ movl(valreg, temp1);
} else {
__ xchgl(valreg, field_addr);
}
@@ -4615,32 +4587,24 @@ static void GenerateVarHandleGetAndSet(HInvoke* invoke,
codegen->GetInstructionCodegen()->Bswap(value, type);
}
CpuRegister valreg = value.AsRegister<CpuRegister>();
- DCHECK_IMPLIES(!is_void, valreg == out.AsRegister<CpuRegister>());
+ DCHECK_EQ(valreg, out.AsRegister<CpuRegister>());
switch (type) {
case DataType::Type::kBool:
case DataType::Type::kUint8:
__ xchgb(valreg, field_addr);
- if (!is_void) {
- __ movzxb(valreg, valreg);
- }
+ __ movzxb(valreg, valreg);
break;
case DataType::Type::kInt8:
__ xchgb(valreg, field_addr);
- if (!is_void) {
- __ movsxb(valreg, valreg);
- }
+ __ movsxb(valreg, valreg);
break;
case DataType::Type::kUint16:
__ xchgw(valreg, field_addr);
- if (!is_void) {
- __ movzxw(valreg, valreg);
- }
+ __ movzxw(valreg, valreg);
break;
case DataType::Type::kInt16:
__ xchgw(valreg, field_addr);
- if (!is_void) {
- __ movsxw(valreg, valreg);
- }
+ __ movsxw(valreg, valreg);
break;
case DataType::Type::kInt32:
case DataType::Type::kUint32:
@@ -4665,36 +4629,25 @@ static void CreateVarHandleGetAndBitwiseOpLocations(HInvoke* invoke, CodeGenerat
return;
}
- // Get the type from the shorty as the invokes may not return a value.
uint32_t number_of_arguments = invoke->GetNumberOfArguments();
uint32_t new_value_index = number_of_arguments - 1;
- DataType::Type value_type = GetDataTypeFromShorty(invoke, new_value_index);
- DataType::Type return_type = invoke->GetType();
- const bool is_void = return_type == DataType::Type::kVoid;
- DCHECK_IMPLIES(!is_void, return_type == value_type);
+ DataType::Type type = invoke->GetType();
+ DCHECK_EQ(type, GetDataTypeFromShorty(invoke, new_value_index));
LocationSummary* locations = CreateVarHandleCommonLocations(invoke);
- DCHECK_NE(DataType::Type::kReference, value_type);
- DCHECK(!DataType::IsFloatingPointType(value_type));
+ DCHECK_NE(DataType::Type::kReference, type);
+ DCHECK(!DataType::IsFloatingPointType(type));
- if (!is_void) {
- // Output is in RAX to accommodate CMPXCHG. It is also used as a temporary.
- locations->SetOut(Location::RegisterLocation(RAX));
- } else {
- // Used as a temporary, even when we are not outputting it so reserve it. This has to be
- // requested before the other temporary since there's variable number of temp registers and the
- // other temp register is expected to be the last one.
- locations->AddTemp(Location::RegisterLocation(RAX));
- }
// A temporary to compute the bitwise operation on the old and the new values.
locations->AddTemp(Location::RequiresRegister());
// We need value to be either in a register, or a 32-bit constant (as there are no arithmetic
// instructions that accept 64-bit immediate on x86_64).
- locations->SetInAt(new_value_index,
- DataType::Is64BitType(value_type) ?
- Location::RequiresRegister() :
- Location::RegisterOrConstant(invoke->InputAt(new_value_index)));
+ locations->SetInAt(new_value_index, DataType::Is64BitType(type)
+ ? Location::RequiresRegister()
+ : Location::RegisterOrConstant(invoke->InputAt(new_value_index)));
+ // Output is in RAX to accommodate CMPXCHG. It is also used as a temporary.
+ locations->SetOut(Location::RegisterLocation(RAX));
}
static void GenerateVarHandleGetAndOp(HInvoke* invoke,
@@ -4706,9 +4659,8 @@ static void GenerateVarHandleGetAndOp(HInvoke* invoke,
bool byte_swap) {
X86_64Assembler* assembler = codegen->GetAssembler();
LocationSummary* locations = invoke->GetLocations();
- Location temp_loc = locations->GetTemp(locations->GetTempCount() - 1u);
- Location rax_loc = Location::RegisterLocation(RAX);
- DCHECK_IMPLIES(invoke->GetType() != DataType::Type::kVoid, locations->Out().Equals(rax_loc));
+ Location temp_loc = locations->GetTemp(locations->GetTempCount() - 1);
+ Location rax_loc = locations->Out();
CpuRegister temp = temp_loc.AsRegister<CpuRegister>();
CpuRegister rax = rax_loc.AsRegister<CpuRegister>();
DCHECK_EQ(rax.AsRegister(), RAX);
@@ -4816,21 +4768,15 @@ static void CreateVarHandleGetAndAddLocations(HInvoke* invoke, CodeGeneratorX86_
return;
}
- // Get the type from the shorty as the invokes may not return a value.
uint32_t number_of_arguments = invoke->GetNumberOfArguments();
uint32_t new_value_index = number_of_arguments - 1;
- DataType::Type value_type = GetDataTypeFromShorty(invoke, new_value_index);
- DataType::Type return_type = invoke->GetType();
- const bool is_void = return_type == DataType::Type::kVoid;
- DCHECK_IMPLIES(!is_void, return_type == value_type);
+ DataType::Type type = invoke->GetType();
+ DCHECK_EQ(type, GetDataTypeFromShorty(invoke, new_value_index));
LocationSummary* locations = CreateVarHandleCommonLocations(invoke);
- if (DataType::IsFloatingPointType(value_type)) {
- // Only set the `out` register if it's needed. In the void case we don't use `out`
- if (!is_void) {
- locations->SetOut(Location::RequiresFpuRegister());
- }
+ if (DataType::IsFloatingPointType(type)) {
+ locations->SetOut(Location::RequiresFpuRegister());
// Require that the new FP value is in a register (and not a constant) for ADDSS/ADDSD.
locations->SetInAt(new_value_index, Location::RequiresFpuRegister());
// CMPXCHG clobbers RAX.
@@ -4840,15 +4786,11 @@ static void CreateVarHandleGetAndAddLocations(HInvoke* invoke, CodeGeneratorX86_
// A temporary to hold the new value for CMPXCHG.
locations->AddTemp(Location::RequiresRegister());
} else {
- DCHECK_NE(value_type, DataType::Type::kReference);
- // Only set the `out` register if it's needed. In the void case we can still use RAX in the
- // same manner as it is used an as `in` register.
- if (!is_void) {
- // Use the same register for both the new value and output to take advantage of XADD.
- // It should be RAX, because the byte-swapping path of GenerateVarHandleGetAndAdd falls
- // back to GenerateVarHandleGetAndOp that expects out in RAX.
- locations->SetOut(Location::RegisterLocation(RAX));
- }
+ DCHECK_NE(type, DataType::Type::kReference);
+ // Use the same register for both the new value and output to take advantage of XADD.
+ // It should be RAX, because the byte-swapping path of GenerateVarHandleGetAndAdd falls
+ // back to GenerateVarHandleGetAndOp that expects out in RAX.
+ locations->SetOut(Location::RegisterLocation(RAX));
locations->SetInAt(new_value_index, Location::RegisterLocation(RAX));
if (GetExpectedVarHandleCoordinatesCount(invoke) == 2) {
// For byte array views with non-native endianness we need extra BSWAP operations, so we
@@ -4872,10 +4814,6 @@ static void GenerateVarHandleGetAndAdd(HInvoke* invoke,
Location out = locations->Out();
uint32_t temp_count = locations->GetTempCount();
- DataType::Type return_type = invoke->GetType();
- const bool is_void = return_type == DataType::Type::kVoid;
- DCHECK_IMPLIES(!is_void, return_type == type);
-
if (DataType::IsFloatingPointType(type)) {
if (byte_swap) {
// This code should never be executed: it is the case of a byte array view (since it requires
@@ -4938,9 +4876,7 @@ static void GenerateVarHandleGetAndAdd(HInvoke* invoke,
if (byte_swap) {
codegen->GetInstructionCodegen()->Bswap(rax_loc, bswap_type);
}
- if (!is_void) {
- __ movd(out.AsFpuRegister<XmmRegister>(), CpuRegister(RAX), is64bit);
- }
+ __ movd(out.AsFpuRegister<XmmRegister>(), CpuRegister(RAX), is64bit);
} else {
if (byte_swap) {
// We cannot use XADD since we need to byte-swap the old value when reading it from memory,
@@ -4957,32 +4893,24 @@ static void GenerateVarHandleGetAndAdd(HInvoke* invoke,
// the old value to the field. Output register is the same as the one holding new value. Do
// sign extend / zero extend as needed.
CpuRegister valreg = value.AsRegister<CpuRegister>();
- DCHECK_IMPLIES(!is_void, valreg == out.AsRegister<CpuRegister>());
+ DCHECK_EQ(valreg, out.AsRegister<CpuRegister>());
switch (type) {
case DataType::Type::kBool:
case DataType::Type::kUint8:
__ LockXaddb(field_addr, valreg);
- if (!is_void) {
- __ movzxb(valreg, valreg);
- }
+ __ movzxb(valreg, valreg);
break;
case DataType::Type::kInt8:
__ LockXaddb(field_addr, valreg);
- if (!is_void) {
- __ movsxb(valreg, valreg);
- }
+ __ movsxb(valreg, valreg);
break;
case DataType::Type::kUint16:
__ LockXaddw(field_addr, valreg);
- if (!is_void) {
- __ movzxw(valreg, valreg);
- }
+ __ movzxw(valreg, valreg);
break;
case DataType::Type::kInt16:
__ LockXaddw(field_addr, valreg);
- if (!is_void) {
- __ movsxw(valreg, valreg);
- }
+ __ movsxw(valreg, valreg);
break;
case DataType::Type::kInt32:
case DataType::Type::kUint32:
@@ -5011,10 +4939,9 @@ static void GenerateVarHandleGetAndUpdate(HInvoke* invoke,
X86_64Assembler* assembler = codegen->GetAssembler();
LocationSummary* locations = invoke->GetLocations();
- // Get the type from the shorty as the invokes may not return a value.
uint32_t number_of_arguments = invoke->GetNumberOfArguments();
Location value = locations->InAt(number_of_arguments - 1);
- DataType::Type type = GetDataTypeFromShorty(invoke, number_of_arguments - 1);
+ DataType::Type type = invoke->GetType();
VarHandleSlowPathX86_64* slow_path = nullptr;
VarHandleTarget target = GetVarHandleTarget(invoke);
@@ -5272,7 +5199,7 @@ void VarHandleSlowPathX86_64::EmitByteArrayViewCode(CodeGeneratorX86_64* codegen
CpuRegister varhandle = locations->InAt(0).AsRegister<CpuRegister>();
CpuRegister object = locations->InAt(1).AsRegister<CpuRegister>();
CpuRegister index = locations->InAt(2).AsRegister<CpuRegister>();
- CpuRegister temp = locations->GetTemp(locations->GetTempCount() - 1u).AsRegister<CpuRegister>();
+ CpuRegister temp = locations->GetTemp(locations->GetTempCount() - 1).AsRegister<CpuRegister>();
MemberOffset class_offset = mirror::Object::ClassOffset();
MemberOffset array_length_offset = mirror::Array::LengthOffset();