diff options
Diffstat (limited to 'compiler/optimizing')
-rw-r--r-- | compiler/optimizing/code_generator_x86.cc | 73 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86_64.cc | 63 |
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; |