diff options
author | 2015-07-06 18:11:54 +0100 | |
---|---|---|
committer | 2015-07-08 15:45:22 +0100 | |
commit | 4fa13f65ece3b68fe3d8722d679ebab8656bbf99 (patch) | |
tree | 09939739f6ae87e05e91d370007e978b5e72ca8e /compiler/optimizing | |
parent | c470193cfc522fc818eb2eaab896aef9caf0c75a (diff) |
Fuse long and FP compare & condition on ARM in Optimizing.
Also:
- Stylistic changes in corresponding parts on the x86 and
x86-64 code generators.
- Update and improve the documentation of
art::arm::Condition.
Bug: 21120453
Change-Id: If144772046e7d21362c3c2086246cb7d011d49ce
Diffstat (limited to 'compiler/optimizing')
-rw-r--r-- | compiler/optimizing/builder.cc | 10 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_arm.cc | 295 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_arm.h | 8 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86.cc | 118 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86_64.cc | 90 | ||||
-rw-r--r-- | compiler/optimizing/instruction_simplifier.cc | 6 | ||||
-rw-r--r-- | compiler/optimizing/instruction_simplifier.h | 2 | ||||
-rw-r--r-- | compiler/optimizing/nodes.h | 20 |
8 files changed, 356 insertions, 193 deletions
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index 6b245b3ffe..a7eb36c2f8 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -2303,27 +2303,27 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 } case Instruction::CMP_LONG: { - Binop_23x_cmp(instruction, Primitive::kPrimLong, kNoBias, dex_pc); + Binop_23x_cmp(instruction, Primitive::kPrimLong, ComparisonBias::kNoBias, dex_pc); break; } case Instruction::CMPG_FLOAT: { - Binop_23x_cmp(instruction, Primitive::kPrimFloat, kGtBias, dex_pc); + Binop_23x_cmp(instruction, Primitive::kPrimFloat, ComparisonBias::kGtBias, dex_pc); break; } case Instruction::CMPG_DOUBLE: { - Binop_23x_cmp(instruction, Primitive::kPrimDouble, kGtBias, dex_pc); + Binop_23x_cmp(instruction, Primitive::kPrimDouble, ComparisonBias::kGtBias, dex_pc); break; } case Instruction::CMPL_FLOAT: { - Binop_23x_cmp(instruction, Primitive::kPrimFloat, kLtBias, dex_pc); + Binop_23x_cmp(instruction, Primitive::kPrimFloat, ComparisonBias::kLtBias, dex_pc); break; } case Instruction::CMPL_DOUBLE: { - Binop_23x_cmp(instruction, Primitive::kPrimDouble, kLtBias, dex_pc); + Binop_23x_cmp(instruction, Primitive::kPrimDouble, ComparisonBias::kLtBias, dex_pc); break; } diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index e3683ef0dd..ff1232902f 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -334,7 +334,7 @@ class DeoptimizationSlowPathARM : public SlowPathCodeARM { #undef __ #define __ down_cast<ArmAssembler*>(GetAssembler())-> -inline Condition ARMCondition(IfCondition cond) { +inline Condition ARMSignedOrFPCondition(IfCondition cond) { switch (cond) { case kCondEQ: return EQ; case kCondNE: return NE; @@ -342,24 +342,22 @@ inline Condition ARMCondition(IfCondition cond) { case kCondLE: return LE; case kCondGT: return GT; case kCondGE: return GE; - default: - LOG(FATAL) << "Unknown if condition"; } - return EQ; // Unreachable. + LOG(FATAL) << "Unreachable"; + UNREACHABLE(); } -inline Condition ARMOppositeCondition(IfCondition cond) { +inline Condition ARMUnsignedCondition(IfCondition cond) { switch (cond) { - case kCondEQ: return NE; - case kCondNE: return EQ; - case kCondLT: return GE; - case kCondLE: return GT; - case kCondGT: return LE; - case kCondGE: return LT; - default: - LOG(FATAL) << "Unknown if condition"; + case kCondEQ: return EQ; + case kCondNE: return NE; + case kCondLT: return LO; + case kCondLE: return LS; + case kCondGT: return HI; + case kCondGE: return HS; } - return EQ; // Unreachable. + LOG(FATAL) << "Unreachable"; + UNREACHABLE(); } void CodeGeneratorARM::DumpCoreRegister(std::ostream& stream, int reg) const { @@ -1008,6 +1006,142 @@ void InstructionCodeGeneratorARM::VisitExit(HExit* exit) { UNUSED(exit); } +void InstructionCodeGeneratorARM::GenerateCompareWithImmediate(Register left, int32_t right) { + ShifterOperand operand; + if (GetAssembler()->ShifterOperandCanHold(R0, left, CMP, right, &operand)) { + __ cmp(left, operand); + } else { + Register temp = IP; + __ LoadImmediate(temp, right); + __ cmp(left, ShifterOperand(temp)); + } +} + +void InstructionCodeGeneratorARM::GenerateFPJumps(HCondition* cond, + Label* true_label, + Label* false_label) { + __ vmstat(); // transfer FP status register to ARM APSR. + if (cond->IsFPConditionTrueIfNaN()) { + __ b(true_label, VS); // VS for unordered. + } else if (cond->IsFPConditionFalseIfNaN()) { + __ b(false_label, VS); // VS for unordered. + } + __ b(true_label, ARMSignedOrFPCondition(cond->GetCondition())); +} + +void InstructionCodeGeneratorARM::GenerateLongComparesAndJumps(HCondition* cond, + Label* true_label, + Label* false_label) { + LocationSummary* locations = cond->GetLocations(); + Location left = locations->InAt(0); + Location right = locations->InAt(1); + IfCondition if_cond = cond->GetCondition(); + + Register left_high = left.AsRegisterPairHigh<Register>(); + Register left_low = left.AsRegisterPairLow<Register>(); + IfCondition true_high_cond = if_cond; + IfCondition false_high_cond = cond->GetOppositeCondition(); + Condition final_condition = ARMUnsignedCondition(if_cond); + + // Set the conditions for the test, remembering that == needs to be + // decided using the low words. + switch (if_cond) { + case kCondEQ: + case kCondNE: + // Nothing to do. + break; + case kCondLT: + false_high_cond = kCondGT; + break; + case kCondLE: + true_high_cond = kCondLT; + break; + case kCondGT: + false_high_cond = kCondLT; + break; + case kCondGE: + true_high_cond = kCondGT; + break; + } + if (right.IsConstant()) { + int64_t value = right.GetConstant()->AsLongConstant()->GetValue(); + int32_t val_low = Low32Bits(value); + int32_t val_high = High32Bits(value); + + GenerateCompareWithImmediate(left_high, val_high); + if (if_cond == kCondNE) { + __ b(true_label, ARMSignedOrFPCondition(true_high_cond)); + } else if (if_cond == kCondEQ) { + __ b(false_label, ARMSignedOrFPCondition(false_high_cond)); + } else { + __ b(true_label, ARMSignedOrFPCondition(true_high_cond)); + __ b(false_label, ARMSignedOrFPCondition(false_high_cond)); + } + // Must be equal high, so compare the lows. + GenerateCompareWithImmediate(left_low, val_low); + } else { + Register right_high = right.AsRegisterPairHigh<Register>(); + Register right_low = right.AsRegisterPairLow<Register>(); + + __ cmp(left_high, ShifterOperand(right_high)); + if (if_cond == kCondNE) { + __ b(true_label, ARMSignedOrFPCondition(true_high_cond)); + } else if (if_cond == kCondEQ) { + __ b(false_label, ARMSignedOrFPCondition(false_high_cond)); + } else { + __ b(true_label, ARMSignedOrFPCondition(true_high_cond)); + __ b(false_label, ARMSignedOrFPCondition(false_high_cond)); + } + // Must be equal high, so compare the lows. + __ cmp(left_low, ShifterOperand(right_low)); + } + // The last comparison might be unsigned. + __ b(true_label, final_condition); +} + +void InstructionCodeGeneratorARM::GenerateCompareTestAndBranch(HIf* if_instr, + HCondition* condition, + Label* true_target, + Label* false_target, + Label* always_true_target) { + LocationSummary* locations = condition->GetLocations(); + Location left = locations->InAt(0); + Location right = locations->InAt(1); + + // We don't want true_target as a nullptr. + if (true_target == nullptr) { + true_target = always_true_target; + } + bool falls_through = (false_target == nullptr); + + // FP compares don't like null false_targets. + if (false_target == nullptr) { + false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor()); + } + + Primitive::Type type = condition->InputAt(0)->GetType(); + switch (type) { + case Primitive::kPrimLong: + GenerateLongComparesAndJumps(condition, true_target, false_target); + break; + case Primitive::kPrimFloat: + __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>()); + GenerateFPJumps(condition, true_target, false_target); + break; + case Primitive::kPrimDouble: + __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()), + FromLowSToD(right.AsFpuRegisterPairLow<SRegister>())); + GenerateFPJumps(condition, true_target, false_target); + break; + default: + LOG(FATAL) << "Unexpected compare type " << type; + } + + if (!falls_through) { + __ b(false_target); + } +} + void InstructionCodeGeneratorARM::GenerateTestAndBranch(HInstruction* instruction, Label* true_target, Label* false_target, @@ -1033,25 +1167,27 @@ void InstructionCodeGeneratorARM::GenerateTestAndBranch(HInstruction* instructio } else { // Condition has not been materialized, use its inputs as the // comparison and its condition as the branch condition. + Primitive::Type type = + cond->IsCondition() ? cond->InputAt(0)->GetType() : Primitive::kPrimInt; + // Is this a long or FP comparison that has been folded into the HCondition? + if (type == Primitive::kPrimLong || Primitive::IsFloatingPointType(type)) { + // Generate the comparison directly. + GenerateCompareTestAndBranch(instruction->AsIf(), cond->AsCondition(), + true_target, false_target, always_true_target); + return; + } + LocationSummary* locations = cond->GetLocations(); DCHECK(locations->InAt(0).IsRegister()) << locations->InAt(0); Register left = locations->InAt(0).AsRegister<Register>(); - if (locations->InAt(1).IsRegister()) { - __ cmp(left, ShifterOperand(locations->InAt(1).AsRegister<Register>())); + Location right = locations->InAt(1); + if (right.IsRegister()) { + __ cmp(left, ShifterOperand(right.AsRegister<Register>())); } else { - DCHECK(locations->InAt(1).IsConstant()); - HConstant* constant = locations->InAt(1).GetConstant(); - int32_t value = CodeGenerator::GetInt32ValueOf(constant); - ShifterOperand operand; - if (GetAssembler()->ShifterOperandCanHold(R0, left, CMP, value, &operand)) { - __ cmp(left, operand); - } else { - Register temp = IP; - __ LoadImmediate(temp, value); - __ cmp(left, ShifterOperand(temp)); - } + DCHECK(right.IsConstant()); + GenerateCompareWithImmediate(left, CodeGenerator::GetInt32ValueOf(right.GetConstant())); } - __ b(true_target, ARMCondition(cond->AsCondition()->GetCondition())); + __ b(true_target, ARMSignedOrFPCondition(cond->AsCondition()->GetCondition())); } } if (false_target != nullptr) { @@ -1104,37 +1240,88 @@ void InstructionCodeGeneratorARM::VisitDeoptimize(HDeoptimize* deoptimize) { void LocationsBuilderARM::VisitCondition(HCondition* cond) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall); - locations->SetInAt(0, Location::RequiresRegister()); - locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1))); - if (cond->NeedsMaterialization()) { - locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); + // Handle the long/FP comparisons made in instruction simplification. + switch (cond->InputAt(0)->GetType()) { + case Primitive::kPrimLong: + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1))); + if (cond->NeedsMaterialization()) { + locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap); + } + break; + + case Primitive::kPrimFloat: + case Primitive::kPrimDouble: + locations->SetInAt(0, Location::RequiresFpuRegister()); + locations->SetInAt(1, Location::RequiresFpuRegister()); + if (cond->NeedsMaterialization()) { + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); + } + break; + + default: + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1))); + if (cond->NeedsMaterialization()) { + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); + } } } void InstructionCodeGeneratorARM::VisitCondition(HCondition* cond) { - if (!cond->NeedsMaterialization()) return; + if (!cond->NeedsMaterialization()) { + return; + } + LocationSummary* locations = cond->GetLocations(); - Register left = locations->InAt(0).AsRegister<Register>(); + Location left = locations->InAt(0); + Location right = locations->InAt(1); + Register out = locations->Out().AsRegister<Register>(); + Label true_label, false_label; - if (locations->InAt(1).IsRegister()) { - __ cmp(left, ShifterOperand(locations->InAt(1).AsRegister<Register>())); - } else { - DCHECK(locations->InAt(1).IsConstant()); - int32_t value = CodeGenerator::GetInt32ValueOf(locations->InAt(1).GetConstant()); - ShifterOperand operand; - if (GetAssembler()->ShifterOperandCanHold(R0, left, CMP, value, &operand)) { - __ cmp(left, operand); - } else { - Register temp = IP; - __ LoadImmediate(temp, value); - __ cmp(left, ShifterOperand(temp)); + switch (cond->InputAt(0)->GetType()) { + default: { + // Integer case. + if (right.IsRegister()) { + __ cmp(left.AsRegister<Register>(), ShifterOperand(right.AsRegister<Register>())); + } else { + DCHECK(right.IsConstant()); + GenerateCompareWithImmediate(left.AsRegister<Register>(), + CodeGenerator::GetInt32ValueOf(right.GetConstant())); + } + __ it(ARMSignedOrFPCondition(cond->GetCondition()), kItElse); + __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(1), + ARMSignedOrFPCondition(cond->GetCondition())); + __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(0), + ARMSignedOrFPCondition(cond->GetOppositeCondition())); + return; } + case Primitive::kPrimLong: + GenerateLongComparesAndJumps(cond, &true_label, &false_label); + break; + case Primitive::kPrimFloat: + __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>()); + GenerateFPJumps(cond, &true_label, &false_label); + break; + case Primitive::kPrimDouble: + __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()), + FromLowSToD(right.AsFpuRegisterPairLow<SRegister>())); + GenerateFPJumps(cond, &true_label, &false_label); + break; } - __ it(ARMCondition(cond->GetCondition()), kItElse); - __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(1), - ARMCondition(cond->GetCondition())); - __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(0), - ARMOppositeCondition(cond->GetCondition())); + + // Convert the jumps into the result. + Label done_label; + + // False case: result = 0. + __ Bind(&false_label); + __ LoadImmediate(out, 0); + __ b(&done_label); + + // True case: result = 1. + __ Bind(&true_label); + __ LoadImmediate(out, 1); + __ Bind(&done_label); } void LocationsBuilderARM::VisitEqual(HEqual* comp) { @@ -2913,7 +3100,7 @@ void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) { ShifterOperand(right.AsRegisterPairHigh<Register>())); // Signed compare. __ b(&less, LT); __ b(&greater, GT); - // Do LoadImmediate before any `cmp`, as LoadImmediate might affect the status flags. + // Do LoadImmediate before the last `cmp`, as LoadImmediate might affect the status flags. __ LoadImmediate(out, 0); __ cmp(left.AsRegisterPairLow<Register>(), ShifterOperand(right.AsRegisterPairLow<Register>())); // Unsigned compare. @@ -2936,7 +3123,7 @@ void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) { LOG(FATAL) << "Unexpected compare type " << type; } __ b(&done, EQ); - __ b(&less, CC); // CC is for both: unsigned compare for longs and 'less than' for floats. + __ b(&less, LO); // LO is for both: unsigned compare for longs and 'less than' for floats. __ Bind(&greater); __ LoadImmediate(out, 1); @@ -3710,7 +3897,7 @@ void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) { Register length = locations->InAt(1).AsRegister<Register>(); __ cmp(index, ShifterOperand(length)); - __ b(slow_path->GetEntryLabel(), CS); + __ b(slow_path->GetEntryLabel(), HS); } void CodeGeneratorARM::MarkGCCard(Register temp, diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h index 1d10293b58..53bd766dd4 100644 --- a/compiler/optimizing/code_generator_arm.h +++ b/compiler/optimizing/code_generator_arm.h @@ -207,6 +207,14 @@ class InstructionCodeGeneratorARM : public HGraphVisitor { Label* true_target, Label* false_target, Label* always_true_target); + void GenerateCompareWithImmediate(Register left, int32_t right); + void GenerateCompareTestAndBranch(HIf* if_instr, + HCondition* condition, + Label* true_target, + Label* false_target, + Label* always_true_target); + void GenerateFPJumps(HCondition* cond, Label* true_label, Label* false_label); + void GenerateLongComparesAndJumps(HCondition* cond, Label* true_label, Label* false_label); void DivRemOneOrMinusOne(HBinaryOperation* instruction); void DivRemByPowerOfTwo(HBinaryOperation* instruction); void GenerateDivRemWithAnyConstant(HBinaryOperation* instruction); diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index be71443b15..fd4bd1803a 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -344,7 +344,7 @@ class DeoptimizationSlowPathX86 : public SlowPathCodeX86 { #undef __ #define __ down_cast<X86Assembler*>(GetAssembler())-> -inline Condition X86Condition(IfCondition cond) { +inline Condition X86SignedCondition(IfCondition cond) { switch (cond) { case kCondEQ: return kEqual; case kCondNE: return kNotEqual; @@ -352,10 +352,22 @@ inline Condition X86Condition(IfCondition cond) { case kCondLE: return kLessEqual; case kCondGT: return kGreater; case kCondGE: return kGreaterEqual; - default: - LOG(FATAL) << "Unknown if condition"; } - return kEqual; + LOG(FATAL) << "Unreachable"; + UNREACHABLE(); +} + +inline Condition X86UnsignedOrFPCondition(IfCondition cond) { + switch (cond) { + case kCondEQ: return kEqual; + case kCondNE: return kNotEqual; + case kCondLT: return kBelow; + case kCondLE: return kBelowEqual; + case kCondGT: return kAbove; + case kCondGE: return kAboveEqual; + } + LOG(FATAL) << "Unreachable"; + UNREACHABLE(); } void CodeGeneratorX86::DumpCoreRegister(std::ostream& stream, int reg) const { @@ -892,46 +904,12 @@ void InstructionCodeGeneratorX86::VisitExit(HExit* exit) { void InstructionCodeGeneratorX86::GenerateFPJumps(HCondition* cond, Label* true_label, Label* false_label) { - bool gt_bias = cond->IsGtBias(); - IfCondition if_cond = cond->GetCondition(); - Condition ccode = X86Condition(if_cond); - switch (if_cond) { - case kCondEQ: - if (!gt_bias) { - __ j(kParityEven, false_label); - } - break; - case kCondNE: - if (!gt_bias) { - __ j(kParityEven, true_label); - } - break; - case kCondLT: - if (gt_bias) { - __ j(kParityEven, false_label); - } - ccode = kBelow; - break; - case kCondLE: - if (gt_bias) { - __ j(kParityEven, false_label); - } - ccode = kBelowEqual; - break; - case kCondGT: - if (gt_bias) { - __ j(kParityEven, true_label); - } - ccode = kAbove; - break; - case kCondGE: - if (gt_bias) { - __ j(kParityEven, true_label); - } - ccode = kAboveEqual; - break; + if (cond->IsFPConditionTrueIfNaN()) { + __ j(kUnordered, true_label); + } else if (cond->IsFPConditionFalseIfNaN()) { + __ j(kUnordered, false_label); } - __ j(ccode, true_label); + __ j(X86UnsignedOrFPCondition(cond->GetCondition()), true_label); } void InstructionCodeGeneratorX86::GenerateLongComparesAndJumps(HCondition* cond, @@ -942,43 +920,37 @@ void InstructionCodeGeneratorX86::GenerateLongComparesAndJumps(HCondition* cond, Location right = locations->InAt(1); IfCondition if_cond = cond->GetCondition(); - Register left_low = left.AsRegisterPairLow<Register>(); Register left_high = left.AsRegisterPairHigh<Register>(); + Register left_low = left.AsRegisterPairLow<Register>(); IfCondition true_high_cond = if_cond; IfCondition false_high_cond = cond->GetOppositeCondition(); - Condition final_condition = X86Condition(if_cond); + Condition final_condition = X86UnsignedOrFPCondition(if_cond); // Set the conditions for the test, remembering that == needs to be // decided using the low words. switch (if_cond) { case kCondEQ: - false_high_cond = kCondNE; - break; case kCondNE: - false_high_cond = kCondEQ; + // Nothing to do. break; case kCondLT: false_high_cond = kCondGT; - final_condition = kBelow; break; case kCondLE: true_high_cond = kCondLT; - final_condition = kBelowEqual; break; case kCondGT: false_high_cond = kCondLT; - final_condition = kAbove; break; case kCondGE: true_high_cond = kCondGT; - final_condition = kAboveEqual; break; } if (right.IsConstant()) { int64_t value = right.GetConstant()->AsLongConstant()->GetValue(); - int32_t val_low = Low32Bits(value); int32_t val_high = High32Bits(value); + int32_t val_low = Low32Bits(value); if (val_high == 0) { __ testl(left_high, left_high); @@ -986,12 +958,12 @@ void InstructionCodeGeneratorX86::GenerateLongComparesAndJumps(HCondition* cond, __ cmpl(left_high, Immediate(val_high)); } if (if_cond == kCondNE) { - __ j(X86Condition(true_high_cond), true_label); + __ j(X86SignedCondition(true_high_cond), true_label); } else if (if_cond == kCondEQ) { - __ j(X86Condition(false_high_cond), false_label); + __ j(X86SignedCondition(false_high_cond), false_label); } else { - __ j(X86Condition(true_high_cond), true_label); - __ j(X86Condition(false_high_cond), false_label); + __ j(X86SignedCondition(true_high_cond), true_label); + __ j(X86SignedCondition(false_high_cond), false_label); } // Must be equal high, so compare the lows. if (val_low == 0) { @@ -1000,17 +972,17 @@ void InstructionCodeGeneratorX86::GenerateLongComparesAndJumps(HCondition* cond, __ cmpl(left_low, Immediate(val_low)); } } else { - Register right_low = right.AsRegisterPairLow<Register>(); Register right_high = right.AsRegisterPairHigh<Register>(); + Register right_low = right.AsRegisterPairLow<Register>(); __ cmpl(left_high, right_high); if (if_cond == kCondNE) { - __ j(X86Condition(true_high_cond), true_label); + __ j(X86SignedCondition(true_high_cond), true_label); } else if (if_cond == kCondEQ) { - __ j(X86Condition(false_high_cond), false_label); + __ j(X86SignedCondition(false_high_cond), false_label); } else { - __ j(X86Condition(true_high_cond), true_label); - __ j(X86Condition(false_high_cond), false_label); + __ j(X86SignedCondition(true_high_cond), true_label); + __ j(X86SignedCondition(false_high_cond), false_label); } // Must be equal high, so compare the lows. __ cmpl(left_low, right_low); @@ -1045,12 +1017,10 @@ void InstructionCodeGeneratorX86::GenerateCompareTestAndBranch(HIf* if_instr, GenerateLongComparesAndJumps(condition, true_target, false_target); break; case Primitive::kPrimFloat: - DCHECK(right.IsFpuRegister()); __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>()); GenerateFPJumps(condition, true_target, false_target); break; case Primitive::kPrimDouble: - DCHECK(right.IsFpuRegister()); __ ucomisd(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>()); GenerateFPJumps(condition, true_target, false_target); break; @@ -1080,7 +1050,7 @@ void InstructionCodeGeneratorX86::GenerateTestAndBranch(HInstruction* instructio DCHECK_EQ(cond_value, 0); } } else { - bool materialized = + bool is_materialized = !cond->IsCondition() || cond->AsCondition()->NeedsMaterialization(); // Moves do not affect the eflags register, so if the condition is // evaluated just before the if, we don't need to evaluate it @@ -1089,8 +1059,8 @@ void InstructionCodeGeneratorX86::GenerateTestAndBranch(HInstruction* instructio Primitive::Type type = cond->IsCondition() ? cond->InputAt(0)->GetType() : Primitive::kPrimInt; bool eflags_set = cond->IsCondition() && cond->AsCondition()->IsBeforeWhenDisregardMoves(instruction) - && type == Primitive::kPrimInt; - if (materialized) { + && (type != Primitive::kPrimLong && !Primitive::IsFloatingPointType(type)); + if (is_materialized) { if (!eflags_set) { // Materialized condition, compare against 0. Location lhs = instruction->GetLocations()->InAt(0); @@ -1101,9 +1071,12 @@ void InstructionCodeGeneratorX86::GenerateTestAndBranch(HInstruction* instructio } __ j(kNotEqual, true_target); } else { - __ j(X86Condition(cond->AsCondition()->GetCondition()), true_target); + __ j(X86SignedCondition(cond->AsCondition()->GetCondition()), true_target); } } else { + // Condition has not been materialized, use its inputs as the + // comparison and its condition as the branch condition. + // Is this a long or FP comparison that has been folded into the HCondition? if (type == Primitive::kPrimLong || Primitive::IsFloatingPointType(type)) { // Generate the comparison directly. @@ -1114,6 +1087,7 @@ void InstructionCodeGeneratorX86::GenerateTestAndBranch(HInstruction* instructio always_true_target); return; } + Location lhs = cond->GetLocations()->InAt(0); Location rhs = cond->GetLocations()->InAt(1); // LHS is guaranteed to be in a register (see @@ -1130,7 +1104,7 @@ void InstructionCodeGeneratorX86::GenerateTestAndBranch(HInstruction* instructio } else { __ cmpl(lhs.AsRegister<Register>(), Address(ESP, rhs.GetStackIndex())); } - __ j(X86Condition(cond->AsCondition()->GetCondition()), true_target); + __ j(X86SignedCondition(cond->AsCondition()->GetCondition()), true_target); } } if (false_target != nullptr) { @@ -1288,7 +1262,7 @@ void InstructionCodeGeneratorX86::VisitCondition(HCondition* cond) { } else { __ cmpl(lhs.AsRegister<Register>(), Address(ESP, rhs.GetStackIndex())); } - __ setb(X86Condition(cond->GetCondition()), reg); + __ setb(X86SignedCondition(cond->GetCondition()), reg); return; } case Primitive::kPrimLong: @@ -1307,12 +1281,12 @@ void InstructionCodeGeneratorX86::VisitCondition(HCondition* cond) { // Convert the jumps into the result. Label done_label; - // false case: result = 0; + // False case: result = 0. __ Bind(&false_label); __ xorl(reg, reg); __ jmp(&done_label); - // True case: result = 1 + // True case: result = 1. __ Bind(&true_label); __ movl(reg, Immediate(1)); __ Bind(&done_label); diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index ddaa60db5e..ae7bcc8f0e 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -363,7 +363,7 @@ class DeoptimizationSlowPathX86_64 : public SlowPathCodeX86_64 { #undef __ #define __ down_cast<X86_64Assembler*>(GetAssembler())-> -inline Condition X86_64Condition(IfCondition cond) { +inline Condition X86_64IntegerCondition(IfCondition cond) { switch (cond) { case kCondEQ: return kEqual; case kCondNE: return kNotEqual; @@ -371,10 +371,22 @@ inline Condition X86_64Condition(IfCondition cond) { case kCondLE: return kLessEqual; case kCondGT: return kGreater; case kCondGE: return kGreaterEqual; - default: - LOG(FATAL) << "Unknown if condition"; } - return kEqual; + LOG(FATAL) << "Unreachable"; + UNREACHABLE(); +} + +inline Condition X86_64FPCondition(IfCondition cond) { + switch (cond) { + case kCondEQ: return kEqual; + case kCondNE: return kNotEqual; + case kCondLT: return kBelow; + case kCondLE: return kBelowEqual; + case kCondGT: return kAbove; + case kCondGE: return kAboveEqual; + }; + LOG(FATAL) << "Unreachable"; + UNREACHABLE(); } void CodeGeneratorX86_64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, @@ -836,46 +848,12 @@ void InstructionCodeGeneratorX86_64::VisitExit(HExit* exit) { void InstructionCodeGeneratorX86_64::GenerateFPJumps(HCondition* cond, Label* true_label, Label* false_label) { - bool gt_bias = cond->IsGtBias(); - IfCondition if_cond = cond->GetCondition(); - Condition ccode = X86_64Condition(if_cond); - switch (if_cond) { - case kCondEQ: - if (!gt_bias) { - __ j(kParityEven, false_label); - } - break; - case kCondNE: - if (!gt_bias) { - __ j(kParityEven, true_label); - } - break; - case kCondLT: - if (gt_bias) { - __ j(kParityEven, false_label); - } - ccode = kBelow; - break; - case kCondLE: - if (gt_bias) { - __ j(kParityEven, false_label); - } - ccode = kBelowEqual; - break; - case kCondGT: - if (gt_bias) { - __ j(kParityEven, true_label); - } - ccode = kAbove; - break; - case kCondGE: - if (gt_bias) { - __ j(kParityEven, true_label); - } - ccode = kAboveEqual; - break; + if (cond->IsFPConditionTrueIfNaN()) { + __ j(kUnordered, true_label); + } else if (cond->IsFPConditionFalseIfNaN()) { + __ j(kUnordered, false_label); } - __ j(ccode, true_label); + __ j(X86_64FPCondition(cond->GetCondition()), true_label); } void InstructionCodeGeneratorX86_64::GenerateCompareTestAndBranch(HIf* if_instr, @@ -911,7 +889,7 @@ void InstructionCodeGeneratorX86_64::GenerateCompareTestAndBranch(HIf* if_instr, __ cmpq(left_reg, Immediate(static_cast<int32_t>(value))); } } else { - // Value won't fit in an 32-bit integer. + // Value won't fit in a 32-bit integer. __ cmpq(left_reg, codegen_->LiteralInt64Address(value)); } } else if (right.IsDoubleStackSlot()) { @@ -919,7 +897,7 @@ void InstructionCodeGeneratorX86_64::GenerateCompareTestAndBranch(HIf* if_instr, } else { __ cmpq(left_reg, right.AsRegister<CpuRegister>()); } - __ j(X86_64Condition(condition->GetCondition()), true_target); + __ j(X86_64IntegerCondition(condition->GetCondition()), true_target); break; } case Primitive::kPrimFloat: { @@ -978,7 +956,7 @@ void InstructionCodeGeneratorX86_64::GenerateTestAndBranch(HInstruction* instruc DCHECK_EQ(cond_value, 0); } } else { - bool materialized = + bool is_materialized = !cond->IsCondition() || cond->AsCondition()->NeedsMaterialization(); // Moves do not affect the eflags register, so if the condition is // evaluated just before the if, we don't need to evaluate it @@ -989,7 +967,7 @@ void InstructionCodeGeneratorX86_64::GenerateTestAndBranch(HInstruction* instruc && cond->AsCondition()->IsBeforeWhenDisregardMoves(instruction) && !Primitive::IsFloatingPointType(type); - if (materialized) { + if (is_materialized) { if (!eflags_set) { // Materialized condition, compare against 0. Location lhs = instruction->GetLocations()->InAt(0); @@ -1001,16 +979,20 @@ void InstructionCodeGeneratorX86_64::GenerateTestAndBranch(HInstruction* instruc } __ j(kNotEqual, true_target); } else { - __ j(X86_64Condition(cond->AsCondition()->GetCondition()), true_target); + __ j(X86_64IntegerCondition(cond->AsCondition()->GetCondition()), true_target); } } else { + // Condition has not been materialized, use its inputs as the + // comparison and its condition as the branch condition. + // Is this a long or FP comparison that has been folded into the HCondition? if (type == Primitive::kPrimLong || Primitive::IsFloatingPointType(type)) { - // Generate the comparison directly + // Generate the comparison directly. GenerateCompareTestAndBranch(instruction->AsIf(), cond->AsCondition(), true_target, false_target, always_true_target); return; } + Location lhs = cond->GetLocations()->InAt(0); Location rhs = cond->GetLocations()->InAt(1); if (rhs.IsRegister()) { @@ -1026,7 +1008,7 @@ void InstructionCodeGeneratorX86_64::GenerateTestAndBranch(HInstruction* instruc __ cmpl(lhs.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), rhs.GetStackIndex())); } - __ j(X86_64Condition(cond->AsCondition()->GetCondition()), true_target); + __ j(X86_64IntegerCondition(cond->AsCondition()->GetCondition()), true_target); } } if (false_target != nullptr) { @@ -1175,7 +1157,7 @@ void InstructionCodeGeneratorX86_64::VisitCondition(HCondition* cond) { } else { __ cmpl(lhs.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), rhs.GetStackIndex())); } - __ setcc(X86_64Condition(cond->GetCondition()), reg); + __ setcc(X86_64IntegerCondition(cond->GetCondition()), reg); return; case Primitive::kPrimLong: // Clear output register: setcc only sets the low byte. @@ -1198,7 +1180,7 @@ void InstructionCodeGeneratorX86_64::VisitCondition(HCondition* cond) { } else { __ cmpq(lhs.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), rhs.GetStackIndex())); } - __ setcc(X86_64Condition(cond->GetCondition()), reg); + __ setcc(X86_64IntegerCondition(cond->GetCondition()), reg); return; case Primitive::kPrimFloat: { XmmRegister lhs_reg = lhs.AsFpuRegister<XmmRegister>(); @@ -1231,12 +1213,12 @@ void InstructionCodeGeneratorX86_64::VisitCondition(HCondition* cond) { // Convert the jumps into the result. Label done_label; - // false case: result = 0; + // False case: result = 0. __ Bind(&false_label); __ xorl(reg, reg); __ jmp(&done_label); - // True case: result = 1 + // True case: result = 1. __ Bind(&true_label); __ movl(reg, Immediate(1)); __ Bind(&done_label); diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc index 337cf5b525..017b6781a9 100644 --- a/compiler/optimizing/instruction_simplifier.cc +++ b/compiler/optimizing/instruction_simplifier.cc @@ -517,10 +517,10 @@ void InstructionSimplifierVisitor::VisitLessThanOrEqual(HLessThanOrEqual* condit void InstructionSimplifierVisitor::VisitCondition(HCondition* condition) { // Try to fold an HCompare into this HCondition. - // This simplification is currently only supported on x86 and x86_64. - // TODO: Implement it for ARM, ARM64 and MIPS64. + // This simplification is currently only supported on x86, x86_64 and ARM. + // TODO: Implement it for ARM64 and MIPS64. InstructionSet instruction_set = GetGraph()->GetInstructionSet(); - if (instruction_set != kX86 && instruction_set != kX86_64) { + if (instruction_set != kX86 && instruction_set != kX86_64 && instruction_set != kThumb2) { return; } diff --git a/compiler/optimizing/instruction_simplifier.h b/compiler/optimizing/instruction_simplifier.h index faee2dd91e..cc4b6f6adc 100644 --- a/compiler/optimizing/instruction_simplifier.h +++ b/compiler/optimizing/instruction_simplifier.h @@ -31,7 +31,7 @@ class InstructionSimplifier : public HOptimization { InstructionSimplifier(HGraph* graph, OptimizingCompilerStats* stats = nullptr, const char* name = kInstructionSimplifierPassName) - : HOptimization(graph, name, stats) {} + : HOptimization(graph, name, stats) {} static constexpr const char* kInstructionSimplifierPassName = "instruction_simplifier"; diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 0db1ac32b3..d19170195a 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -2149,7 +2149,7 @@ class HBinaryOperation : public HExpression<2> { // The comparison bias applies for floating point operations and indicates how NaN // comparisons are treated: -enum ComparisonBias { +enum class ComparisonBias { kNoBias, // bias is not applicable (i.e. for long operation) kGtBias, // return 1 for NaN comparisons kLtBias, // return -1 for NaN comparisons @@ -2160,7 +2160,7 @@ class HCondition : public HBinaryOperation { HCondition(HInstruction* first, HInstruction* second) : HBinaryOperation(Primitive::kPrimBoolean, first, second), needs_materialization_(true), - bias_(kNoBias) {} + bias_(ComparisonBias::kNoBias) {} bool NeedsMaterialization() const { return needs_materialization_; } void ClearNeedsMaterialization() { needs_materialization_ = false; } @@ -2175,7 +2175,7 @@ class HCondition : public HBinaryOperation { virtual IfCondition GetOppositeCondition() const = 0; - bool IsGtBias() { return bias_ == kGtBias; } + bool IsGtBias() const { return bias_ == ComparisonBias::kGtBias; } void SetBias(ComparisonBias bias) { bias_ = bias; } @@ -2183,6 +2183,18 @@ class HCondition : public HBinaryOperation { return bias_ == other->AsCondition()->bias_; } + bool IsFPConditionTrueIfNaN() const { + DCHECK(Primitive::IsFloatingPointType(InputAt(0)->GetType())); + IfCondition if_cond = GetCondition(); + return IsGtBias() ? ((if_cond == kCondGT) || (if_cond == kCondGE)) : (if_cond == kCondNE); + } + + bool IsFPConditionFalseIfNaN() const { + DCHECK(Primitive::IsFloatingPointType(InputAt(0)->GetType())); + IfCondition if_cond = GetCondition(); + return IsGtBias() ? ((if_cond == kCondLT) || (if_cond == kCondLE)) : (if_cond == kCondEQ); + } + private: // For register allocation purposes, returns whether this instruction needs to be // materialized (that is, not just be in the processor flags). @@ -2390,7 +2402,7 @@ class HCompare : public HBinaryOperation { ComparisonBias GetBias() const { return bias_; } - bool IsGtBias() { return bias_ == kGtBias; } + bool IsGtBias() { return bias_ == ComparisonBias::kGtBias; } uint32_t GetDexPc() const { return dex_pc_; } |