summaryrefslogtreecommitdiff
path: root/compiler/optimizing
diff options
context:
space:
mode:
author Vladimir Marko <vmarko@google.com> 2022-04-12 10:46:28 +0100
committer Vladimir Marko <vmarko@google.com> 2022-04-13 14:46:10 +0000
commitd77cf74d29bf53d807b707e5f4da4f7176c08239 (patch)
tree34b114565c3d3cd73e04cf966dc0db5b7c114cbb /compiler/optimizing
parentd0600629cfab3133eb1cb4d6826799e1c777562e (diff)
x86/x86-64: Fix BoundsCheck slow path clobbering EDX/RDX.
Test: New run-test 731-bounds-check-slow-path. Test: m test-art-host-gtest Test: testrunner.py --host --optimizing --interpreter --jit --jvm Bug: 227613778 Bug: 227365246 Bug: 216608614 Bug: 216629762 Change-Id: Ia5fd372128f4c5d40a482491b7f9a4b8772f579c
Diffstat (limited to 'compiler/optimizing')
-rw-r--r--compiler/optimizing/code_generator_x86.cc73
-rw-r--r--compiler/optimizing/code_generator_x86_64.cc63
2 files changed, 86 insertions, 50 deletions
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 4025684bda..8c6b8027cd 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -150,41 +150,62 @@ class BoundsCheckSlowPathX86 : public SlowPathCode {
LocationSummary* locations = instruction_->GetLocations();
CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
__ Bind(GetEntryLabel());
- // We're moving two locations to locations that could overlap, so we need a parallel
- // move resolver.
if (instruction_->CanThrowIntoCatchBlock()) {
// Live registers will be restored in the catch block if caught.
- SaveLiveRegisters(codegen, instruction_->GetLocations());
+ SaveLiveRegisters(codegen, locations);
}
- // Are we using an array length from memory?
- HInstruction* array_length = instruction_->InputAt(1);
+ Location index_loc = locations->InAt(0);
Location length_loc = locations->InAt(1);
InvokeRuntimeCallingConvention calling_convention;
- if (array_length->IsArrayLength() && array_length->IsEmittedAtUseSite()) {
- // Load the array length into our temporary.
- HArrayLength* length = array_length->AsArrayLength();
- uint32_t len_offset = CodeGenerator::GetArrayLengthOffset(length);
+ Location index_arg = Location::RegisterLocation(calling_convention.GetRegisterAt(0));
+ Location length_arg = Location::RegisterLocation(calling_convention.GetRegisterAt(1));
+
+ // Are we using an array length from memory?
+ if (!length_loc.IsValid()) {
+ DCHECK(instruction_->InputAt(1)->IsArrayLength());
+ HArrayLength* array_length = instruction_->InputAt(1)->AsArrayLength();
+ DCHECK(array_length->IsEmittedAtUseSite());
+ uint32_t len_offset = CodeGenerator::GetArrayLengthOffset(array_length);
Location array_loc = array_length->GetLocations()->InAt(0);
- Address array_len(array_loc.AsRegister<Register>(), len_offset);
- length_loc = Location::RegisterLocation(calling_convention.GetRegisterAt(1));
- // Check for conflicts with index.
- if (length_loc.Equals(locations->InAt(0))) {
- // We know we aren't using parameter 2.
- length_loc = Location::RegisterLocation(calling_convention.GetRegisterAt(2));
- }
- __ movl(length_loc.AsRegister<Register>(), array_len);
- if (mirror::kUseStringCompression && length->IsStringLength()) {
- __ shrl(length_loc.AsRegister<Register>(), Immediate(1));
+ if (!index_loc.Equals(length_arg)) {
+ // The index is not clobbered by loading the length directly to `length_arg`.
+ __ movl(length_arg.AsRegister<Register>(),
+ Address(array_loc.AsRegister<Register>(), len_offset));
+ x86_codegen->Move32(index_arg, index_loc);
+ } else if (!array_loc.Equals(index_arg)) {
+ // The array reference is not clobbered by the index move.
+ x86_codegen->Move32(index_arg, index_loc);
+ __ movl(length_arg.AsRegister<Register>(),
+ Address(array_loc.AsRegister<Register>(), len_offset));
+ } else {
+ // We do not have a temporary we could use, so swap the registers using the
+ // parallel move resolver and replace the array with the length afterwards.
+ codegen->EmitParallelMoves(
+ index_loc,
+ index_arg,
+ DataType::Type::kInt32,
+ array_loc,
+ length_arg,
+ DataType::Type::kReference);
+ __ movl(length_arg.AsRegister<Register>(),
+ Address(length_arg.AsRegister<Register>(), len_offset));
+ }
+ if (mirror::kUseStringCompression && array_length->IsStringLength()) {
+ __ shrl(length_arg.AsRegister<Register>(), Immediate(1));
}
+ } else {
+ // We're moving two locations to locations that could overlap,
+ // so we need a parallel move resolver.
+ codegen->EmitParallelMoves(
+ index_loc,
+ index_arg,
+ DataType::Type::kInt32,
+ length_loc,
+ length_arg,
+ DataType::Type::kInt32);
}
- x86_codegen->EmitParallelMoves(
- locations->InAt(0),
- Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
- DataType::Type::kInt32,
- length_loc,
- Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
- DataType::Type::kInt32);
+
QuickEntrypointEnum entrypoint = instruction_->AsBoundsCheck()->IsStringCharAt()
? kQuickThrowStringBounds
: kQuickThrowArrayBounds;
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 8c1a533fd3..d919fa7c09 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -203,39 +203,54 @@ class BoundsCheckSlowPathX86_64 : public SlowPathCode {
__ Bind(GetEntryLabel());
if (instruction_->CanThrowIntoCatchBlock()) {
// Live registers will be restored in the catch block if caught.
- SaveLiveRegisters(codegen, instruction_->GetLocations());
+ SaveLiveRegisters(codegen, locations);
}
- // Are we using an array length from memory?
- HInstruction* array_length = instruction_->InputAt(1);
+
+ Location index_loc = locations->InAt(0);
Location length_loc = locations->InAt(1);
InvokeRuntimeCallingConvention calling_convention;
- if (array_length->IsArrayLength() && array_length->IsEmittedAtUseSite()) {
- // Load the array length into our temporary.
- HArrayLength* length = array_length->AsArrayLength();
- uint32_t len_offset = CodeGenerator::GetArrayLengthOffset(length);
+ Location index_arg = Location::RegisterLocation(calling_convention.GetRegisterAt(0));
+ Location length_arg = Location::RegisterLocation(calling_convention.GetRegisterAt(1));
+
+ // Are we using an array length from memory?
+ if (!length_loc.IsValid()) {
+ DCHECK(instruction_->InputAt(1)->IsArrayLength());
+ HArrayLength* array_length = instruction_->InputAt(1)->AsArrayLength();
+ DCHECK(array_length->IsEmittedAtUseSite());
+ uint32_t len_offset = CodeGenerator::GetArrayLengthOffset(array_length);
Location array_loc = array_length->GetLocations()->InAt(0);
Address array_len(array_loc.AsRegister<CpuRegister>(), len_offset);
- length_loc = Location::RegisterLocation(calling_convention.GetRegisterAt(1));
- // Check for conflicts with index.
- if (length_loc.Equals(locations->InAt(0))) {
- // We know we aren't using parameter 2.
- length_loc = Location::RegisterLocation(calling_convention.GetRegisterAt(2));
+ if (!index_loc.Equals(length_arg)) {
+ // The index is not clobbered by loading the length directly to `length_arg`.
+ __ movl(length_arg.AsRegister<CpuRegister>(), array_len);
+ x86_64_codegen->Move(index_arg, index_loc);
+ } else if (!array_loc.Equals(index_arg)) {
+ // The array reference is not clobbered by the index move.
+ x86_64_codegen->Move(index_arg, index_loc);
+ __ movl(length_arg.AsRegister<CpuRegister>(), array_len);
+ } else {
+ // Load the array length into `TMP`.
+ DCHECK(codegen->IsBlockedCoreRegister(TMP));
+ __ movl(CpuRegister(TMP), array_len);
+ // Single move to CPU register does not clobber `TMP`.
+ x86_64_codegen->Move(index_arg, index_loc);
+ __ movl(length_arg.AsRegister<CpuRegister>(), CpuRegister(TMP));
}
- __ movl(length_loc.AsRegister<CpuRegister>(), array_len);
- if (mirror::kUseStringCompression && length->IsStringLength()) {
- __ shrl(length_loc.AsRegister<CpuRegister>(), Immediate(1));
+ if (mirror::kUseStringCompression && array_length->IsStringLength()) {
+ __ shrl(length_arg.AsRegister<CpuRegister>(), Immediate(1));
}
+ } else {
+ // We're moving two locations to locations that could overlap,
+ // so we need a parallel move resolver.
+ codegen->EmitParallelMoves(
+ index_loc,
+ index_arg,
+ DataType::Type::kInt32,
+ length_loc,
+ length_arg,
+ DataType::Type::kInt32);
}
- // We're moving two locations to locations that could overlap, so we need a parallel
- // move resolver.
- codegen->EmitParallelMoves(
- locations->InAt(0),
- Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
- DataType::Type::kInt32,
- length_loc,
- Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
- DataType::Type::kInt32);
QuickEntrypointEnum entrypoint = instruction_->AsBoundsCheck()->IsStringCharAt()
? kQuickThrowStringBounds
: kQuickThrowArrayBounds;