diff options
Diffstat (limited to 'compiler/optimizing/intrinsics_arm_vixl.cc')
-rw-r--r-- | compiler/optimizing/intrinsics_arm_vixl.cc | 173 |
1 files changed, 119 insertions, 54 deletions
diff --git a/compiler/optimizing/intrinsics_arm_vixl.cc b/compiler/optimizing/intrinsics_arm_vixl.cc index 1b1711b9de..7f89f56d0c 100644 --- a/compiler/optimizing/intrinsics_arm_vixl.cc +++ b/compiler/optimizing/intrinsics_arm_vixl.cc @@ -16,6 +16,7 @@ #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" @@ -30,12 +31,11 @@ #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,9 +3871,15 @@ static void CreateUnsafeGetAndUpdateLocations(HInvoke* invoke, 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. 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); + } + 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; @@ -3894,10 +3900,18 @@ 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(); - Location out = locations->Out(); // Result. + 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(); 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. @@ -3930,24 +3944,24 @@ static void GenUnsafeGetAndUpdate(HInvoke* invoke, type, tmp_ptr, arg, - /*old_value=*/ out, + /*old_value=*/ out_or_temp, /*store_result=*/ temp, maybe_temp, /*maybe_vreg_temp=*/ Location::NoLocation()); codegen->GenerateMemoryBarrier(MemBarrierKind::kAnyAny); - if (type == DataType::Type::kReference && codegen->EmitReadBarrier()) { + if (!is_void && type == DataType::Type::kReference && codegen->EmitReadBarrier()) { DCHECK(get_and_update_op == GetAndUpdateOp::kSet); if (kUseBakerReadBarrier) { - codegen->GenerateIntrinsicMoveWithBakerReadBarrier(RegisterFrom(out), RegisterFrom(out)); + codegen->GenerateIntrinsicMoveWithBakerReadBarrier(RegisterFrom(out_or_temp), + RegisterFrom(out_or_temp)); } else { - codegen->GenerateReadBarrierSlow( - invoke, - out, - out, - Location::RegisterLocation(base.GetCode()), - /*offset=*/ 0u, - /*index=*/ Location::RegisterLocation(offset.GetCode())); + codegen->GenerateReadBarrierSlow(invoke, + out_or_temp, + out_or_temp, + Location::RegisterLocation(base.GetCode()), + /*offset=*/ 0u, + /*index=*/ Location::RegisterLocation(offset.GetCode())); } } } @@ -4656,6 +4670,7 @@ 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)) { @@ -5163,7 +5178,10 @@ 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. + 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 @@ -5177,7 +5195,6 @@ 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. @@ -5211,6 +5228,23 @@ 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, @@ -5218,13 +5252,38 @@ 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); - 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); + + 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(); + } VarHandleTarget target = GetVarHandleTarget(invoke); VarHandleSlowPathARMVIXL* slow_path = nullptr; @@ -5261,7 +5320,7 @@ static void GenerateVarHandleGetAndUpdate(HInvoke* invoke, : value_type; // Prepare register for old value and temporaries if any. - Location old_value = out; + Location old_value = result; Location maybe_temp = Location::NoLocation(); Location maybe_vreg_temp = Location::NoLocation(); if (get_and_update_op == GetAndUpdateOp::kSet) { @@ -5269,7 +5328,9 @@ 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); - DCHECK_EQ(locations->GetTempCount(), 5u); // `store_result` and the four here. + // `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); old_value = LocationFrom(RegisterFrom(locations->GetTemp(1)), RegisterFrom(locations->GetTemp(2))); arg = LocationFrom(RegisterFrom(locations->GetTemp(3)), RegisterFrom(locations->GetTemp(4))); @@ -5281,7 +5342,9 @@ static void GenerateVarHandleGetAndUpdate(HInvoke* invoke, } } else if (value_type == DataType::Type::kFloat32) { vixl32::SRegister arg_vreg = SRegisterFrom(arg); - DCHECK_EQ(locations->GetTempCount(), 3u); // `store_result` and the two here. + // `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); old_value = locations->GetTemp(1); arg = locations->GetTemp(2); __ Vmov(RegisterFrom(arg), arg_vreg); @@ -5293,7 +5356,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(out); // Use the `out` for the exclusive store result. + store_result = RegisterFrom(result); // Use `result` for the exclusive store result. } else { // The store_result is a separate temporary. DCHECK(!store_result.Is(target.object)); @@ -5305,7 +5368,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(out), LowRegisterFrom(out)); + old_value = LocationFrom(HighRegisterFrom(result), LowRegisterFrom(result)); } GenerateReverseBytes(assembler, value_type, original_arg, arg); } @@ -5315,7 +5378,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(locations->GetTempCount() - 1u); + maybe_vreg_temp = locations->GetTemp(temp_count - 1u - temps_that_mimic_out); DCHECK(maybe_vreg_temp.IsFpuRegisterPair()); } if (byte_swap) { @@ -5324,7 +5387,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(out), LowRegisterFrom(out)); + old_value = LocationFrom(HighRegisterFrom(result), LowRegisterFrom(result)); // Due to lack of registers, reverse bytes in `arg` and undo that later. GenerateReverseBytesInPlaceForEachWord(assembler, arg); arg = LocationFrom(HighRegisterFrom(arg), LowRegisterFrom(arg)); @@ -5353,36 +5416,38 @@ static void GenerateVarHandleGetAndUpdate(HInvoke* invoke, seq_cst_barrier ? MemBarrierKind::kAnyAny : MemBarrierKind::kLoadAny); } - 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); + 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())); } - } 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())); } } |