diff options
Diffstat (limited to 'compiler/optimizing/code_generator_arm.cc')
-rw-r--r-- | compiler/optimizing/code_generator_arm.cc | 98 |
1 files changed, 65 insertions, 33 deletions
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index caea250ab6..00e215fc7d 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -7039,14 +7039,16 @@ void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) { uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value(); uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value(); uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value(); - Label done, zero; - Label* final_label = codegen_->GetFinalLabel(instruction, &done); + Label done; + Label* const final_label = codegen_->GetFinalLabel(instruction, &done); SlowPathCodeARM* slow_path = nullptr; // Return 0 if `obj` is null. // avoid null check if we know obj is not null. if (instruction->MustDoNullCheck()) { - __ CompareAndBranchIfZero(obj, &zero); + DCHECK_NE(out, obj); + __ LoadImmediate(out, 0); + __ CompareAndBranchIfZero(obj, final_label); } switch (type_check_kind) { @@ -7058,11 +7060,23 @@ void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) { class_offset, maybe_temp_loc, kCompilerReadBarrierOption); - __ cmp(out, ShifterOperand(cls)); // Classes must be equal for the instanceof to succeed. - __ b(&zero, NE); - __ LoadImmediate(out, 1); - __ b(final_label); + __ cmp(out, ShifterOperand(cls)); + // We speculatively set the result to false without changing the condition + // flags, which allows us to avoid some branching later. + __ mov(out, ShifterOperand(0), AL, kCcKeep); + + // Since IT blocks longer than a 16-bit instruction are deprecated by ARMv8, + // we check that the output is in a low register, so that a 16-bit MOV + // encoding can be used. + if (ArmAssembler::IsLowRegister(out)) { + __ it(EQ); + __ mov(out, ShifterOperand(1), EQ); + } else { + __ b(final_label, NE); + __ LoadImmediate(out, 1); + } + break; } @@ -7084,14 +7098,11 @@ void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) { super_offset, maybe_temp_loc, kCompilerReadBarrierOption); - // If `out` is null, we use it for the result, and jump to `done`. + // If `out` is null, we use it for the result, and jump to the final label. __ CompareAndBranchIfZero(out, final_label); __ cmp(out, ShifterOperand(cls)); __ b(&loop, NE); __ LoadImmediate(out, 1); - if (zero.IsLinked()) { - __ b(final_label); - } break; } @@ -7114,14 +7125,32 @@ void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) { super_offset, maybe_temp_loc, kCompilerReadBarrierOption); - __ CompareAndBranchIfNonZero(out, &loop); - // If `out` is null, we use it for the result, and jump to `done`. - __ b(final_label); - __ Bind(&success); - __ LoadImmediate(out, 1); - if (zero.IsLinked()) { + // This is essentially a null check, but it sets the condition flags to the + // proper value for the code that follows the loop, i.e. not `EQ`. + __ cmp(out, ShifterOperand(1)); + __ b(&loop, HS); + + // Since IT blocks longer than a 16-bit instruction are deprecated by ARMv8, + // we check that the output is in a low register, so that a 16-bit MOV + // encoding can be used. + if (ArmAssembler::IsLowRegister(out)) { + // If `out` is null, we use it for the result, and the condition flags + // have already been set to `NE`, so the IT block that comes afterwards + // (and which handles the successful case) turns into a NOP (instead of + // overwriting `out`). + __ Bind(&success); + // There is only one branch to the `success` label (which is bound to this + // IT block), and it has the same condition, `EQ`, so in that case the MOV + // is executed. + __ it(EQ); + __ mov(out, ShifterOperand(1), EQ); + } else { + // If `out` is null, we use it for the result, and jump to the final label. __ b(final_label); + __ Bind(&success); + __ LoadImmediate(out, 1); } + break; } @@ -7144,14 +7173,28 @@ void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) { component_offset, maybe_temp_loc, kCompilerReadBarrierOption); - // If `out` is null, we use it for the result, and jump to `done`. + // If `out` is null, we use it for the result, and jump to the final label. __ CompareAndBranchIfZero(out, final_label); __ LoadFromOffset(kLoadUnsignedHalfword, out, out, primitive_offset); static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot"); - __ CompareAndBranchIfNonZero(out, &zero); - __ Bind(&exact_check); - __ LoadImmediate(out, 1); - __ b(final_label); + __ cmp(out, ShifterOperand(0)); + // We speculatively set the result to false without changing the condition + // flags, which allows us to avoid some branching later. + __ mov(out, ShifterOperand(0), AL, kCcKeep); + + // Since IT blocks longer than a 16-bit instruction are deprecated by ARMv8, + // we check that the output is in a low register, so that a 16-bit MOV + // encoding can be used. + if (ArmAssembler::IsLowRegister(out)) { + __ Bind(&exact_check); + __ it(EQ); + __ mov(out, ShifterOperand(1), EQ); + } else { + __ b(final_label, NE); + __ Bind(&exact_check); + __ LoadImmediate(out, 1); + } + break; } @@ -7171,9 +7214,6 @@ void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) { codegen_->AddSlowPath(slow_path); __ b(slow_path->GetEntryLabel(), NE); __ LoadImmediate(out, 1); - if (zero.IsLinked()) { - __ b(final_label); - } break; } @@ -7202,18 +7242,10 @@ void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) { /* is_fatal */ false); codegen_->AddSlowPath(slow_path); __ b(slow_path->GetEntryLabel()); - if (zero.IsLinked()) { - __ b(final_label); - } break; } } - if (zero.IsLinked()) { - __ Bind(&zero); - __ LoadImmediate(out, 0); - } - if (done.IsLinked()) { __ Bind(&done); } |