diff options
author | 2017-05-10 11:59:26 +0000 | |
---|---|---|
committer | 2017-05-10 11:59:26 +0000 | |
commit | 3082661d260449e1d773f077e914160c7ad58de5 (patch) | |
tree | 4407aec4c23d0fa52b9a3334529042797da2d24f | |
parent | b404f349d69f940ef2974915fe97c16070364efd (diff) |
Revert "ARM: Improve the code generated for HCondition with a constant input"
Reverting to see if that change is responsible for a crash. Will share with ARM if it is.
This reverts commit b404f349d69f940ef2974915fe97c16070364efd.
Change-Id: Idd04f9109447319445ff49f3fd7dc5b069b4883f
-rw-r--r-- | compiler/optimizing/code_generator_arm.cc | 615 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_arm.h | 9 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_arm_vixl.cc | 640 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_arm_vixl.h | 11 | ||||
-rw-r--r-- | compiler/optimizing/intrinsics_arm.cc | 12 | ||||
-rw-r--r-- | compiler/optimizing/intrinsics_arm_vixl.cc | 12 | ||||
-rw-r--r-- | test/409-materialized-condition/src/Main.java | 71 | ||||
-rw-r--r-- | test/570-checker-select/src/Main.java | 71 |
8 files changed, 270 insertions, 1171 deletions
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index 030b91c115..d7cc577580 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -1602,34 +1602,6 @@ static void GenerateVcmp(HInstruction* instruction, CodeGeneratorARM* codegen) { } } -static int64_t AdjustConstantForCondition(int64_t value, - IfCondition* condition, - IfCondition* opposite) { - if (value == 1) { - if (*condition == kCondB) { - value = 0; - *condition = kCondEQ; - *opposite = kCondNE; - } else if (*condition == kCondAE) { - value = 0; - *condition = kCondNE; - *opposite = kCondEQ; - } - } else if (value == -1) { - if (*condition == kCondGT) { - value = 0; - *condition = kCondGE; - *opposite = kCondLT; - } else if (*condition == kCondLE) { - value = 0; - *condition = kCondLT; - *opposite = kCondGE; - } - } - - return value; -} - static std::pair<Condition, Condition> GenerateLongTestConstant(HCondition* condition, bool invert, CodeGeneratorARM* codegen) { @@ -1643,7 +1615,7 @@ static std::pair<Condition, Condition> GenerateLongTestConstant(HCondition* cond std::swap(cond, opposite); } - std::pair<Condition, Condition> ret(EQ, NE); + std::pair<Condition, Condition> ret; const Location left = locations->InAt(0); const Location right = locations->InAt(1); @@ -1651,38 +1623,7 @@ static std::pair<Condition, Condition> GenerateLongTestConstant(HCondition* cond const Register left_high = left.AsRegisterPairHigh<Register>(); const Register left_low = left.AsRegisterPairLow<Register>(); - int64_t value = AdjustConstantForCondition(right.GetConstant()->AsLongConstant()->GetValue(), - &cond, - &opposite); - - // Comparisons against 0 are common enough to deserve special attention. - if (value == 0) { - switch (cond) { - case kCondNE: - // x > 0 iff x != 0 when the comparison is unsigned. - case kCondA: - ret = std::make_pair(NE, EQ); - FALLTHROUGH_INTENDED; - case kCondEQ: - // x <= 0 iff x == 0 when the comparison is unsigned. - case kCondBE: - __ orrs(IP, left_low, ShifterOperand(left_high)); - return ret; - case kCondLT: - case kCondGE: - __ cmp(left_high, ShifterOperand(0)); - return std::make_pair(ARMCondition(cond), ARMCondition(opposite)); - // Trivially true or false. - case kCondB: - ret = std::make_pair(NE, EQ); - FALLTHROUGH_INTENDED; - case kCondAE: - __ cmp(left_low, ShifterOperand(left_low)); - return ret; - default: - break; - } - } + int64_t value = right.GetConstant()->AsLongConstant()->GetValue(); switch (cond) { case kCondEQ: @@ -1842,14 +1783,10 @@ static std::pair<Condition, Condition> GenerateTest(HCondition* condition, static bool CanGenerateTest(HCondition* condition, ArmAssembler* assembler) { if (condition->GetLeft()->GetType() == Primitive::kPrimLong) { const LocationSummary* const locations = condition->GetLocations(); + const IfCondition c = condition->GetCondition(); if (locations->InAt(1).IsConstant()) { - IfCondition c = condition->GetCondition(); - IfCondition opposite = condition->GetOppositeCondition(); - const int64_t value = AdjustConstantForCondition( - Int64FromConstant(locations->InAt(1).GetConstant()), - &c, - &opposite); + const int64_t value = locations->InAt(1).GetConstant()->AsLongConstant()->GetValue(); ShifterOperand so; if (c < kCondLT || c > kCondGE) { @@ -1857,11 +1794,9 @@ static bool CanGenerateTest(HCondition* condition, ArmAssembler* assembler) { // we check that the least significant half of the first input to be compared // is in a low register (the other half is read outside an IT block), and // the constant fits in an 8-bit unsigned integer, so that a 16-bit CMP - // encoding can be used; 0 is always handled, no matter what registers are - // used by the first input. - if (value != 0 && - (!ArmAssembler::IsLowRegister(locations->InAt(0).AsRegisterPairLow<Register>()) || - !IsUint<8>(Low32Bits(value)))) { + // encoding can be used. + if (!ArmAssembler::IsLowRegister(locations->InAt(0).AsRegisterPairLow<Register>()) || + !IsUint<8>(Low32Bits(value))) { return false; } } else if (c == kCondLE || c == kCondGT) { @@ -1888,329 +1823,6 @@ static bool CanGenerateTest(HCondition* condition, ArmAssembler* assembler) { return true; } -static void GenerateConditionGeneric(HCondition* cond, CodeGeneratorARM* codegen) { - DCHECK(CanGenerateTest(cond, codegen->GetAssembler())); - - const Register out = cond->GetLocations()->Out().AsRegister<Register>(); - const auto condition = GenerateTest(cond, false, codegen); - - __ mov(out, ShifterOperand(0), AL, kCcKeep); - - if (ArmAssembler::IsLowRegister(out)) { - __ it(condition.first); - __ mov(out, ShifterOperand(1), condition.first); - } else { - Label done_label; - Label* const final_label = codegen->GetFinalLabel(cond, &done_label); - - __ b(final_label, condition.second); - __ LoadImmediate(out, 1); - - if (done_label.IsLinked()) { - __ Bind(&done_label); - } - } -} - -static void GenerateEqualLong(HCondition* cond, CodeGeneratorARM* codegen) { - DCHECK_EQ(cond->GetLeft()->GetType(), Primitive::kPrimLong); - - const LocationSummary* const locations = cond->GetLocations(); - IfCondition condition = cond->GetCondition(); - const Register out = locations->Out().AsRegister<Register>(); - const Location left = locations->InAt(0); - const Location right = locations->InAt(1); - Register left_high = left.AsRegisterPairHigh<Register>(); - Register left_low = left.AsRegisterPairLow<Register>(); - - if (right.IsConstant()) { - IfCondition opposite = cond->GetOppositeCondition(); - const int64_t value = AdjustConstantForCondition(Int64FromConstant(right.GetConstant()), - &condition, - &opposite); - int32_t value_high = -High32Bits(value); - int32_t value_low = -Low32Bits(value); - - // The output uses Location::kNoOutputOverlap. - if (out == left_high) { - std::swap(left_low, left_high); - std::swap(value_low, value_high); - } - - __ AddConstant(out, left_low, value_low); - __ AddConstant(IP, left_high, value_high); - } else { - DCHECK(right.IsRegisterPair()); - __ sub(IP, left_high, ShifterOperand(right.AsRegisterPairHigh<Register>())); - __ sub(out, left_low, ShifterOperand(right.AsRegisterPairLow<Register>())); - } - - // Need to check after calling AdjustConstantForCondition(). - DCHECK(condition == kCondEQ || condition == kCondNE) << condition; - - if (condition == kCondNE && ArmAssembler::IsLowRegister(out)) { - __ orrs(out, out, ShifterOperand(IP)); - __ it(NE); - __ mov(out, ShifterOperand(1), NE); - } else { - __ orr(out, out, ShifterOperand(IP)); - codegen->GenerateConditionWithZero(condition, out, out, IP); - } -} - -static void GenerateLongComparesAndJumps(HCondition* cond, - Label* true_label, - Label* false_label, - CodeGeneratorARM* codegen) { - 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); // unsigned on lower part - - // 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; - case kCondB: - false_high_cond = kCondA; - break; - case kCondBE: - true_high_cond = kCondB; - break; - case kCondA: - false_high_cond = kCondB; - break; - case kCondAE: - true_high_cond = kCondA; - break; - } - if (right.IsConstant()) { - int64_t value = right.GetConstant()->AsLongConstant()->GetValue(); - int32_t val_low = Low32Bits(value); - int32_t val_high = High32Bits(value); - - __ CmpConstant(left_high, val_high); - if (if_cond == kCondNE) { - __ b(true_label, ARMCondition(true_high_cond)); - } else if (if_cond == kCondEQ) { - __ b(false_label, ARMCondition(false_high_cond)); - } else { - __ b(true_label, ARMCondition(true_high_cond)); - __ b(false_label, ARMCondition(false_high_cond)); - } - // Must be equal high, so compare the lows. - __ CmpConstant(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, ARMCondition(true_high_cond)); - } else if (if_cond == kCondEQ) { - __ b(false_label, ARMCondition(false_high_cond)); - } else { - __ b(true_label, ARMCondition(true_high_cond)); - __ b(false_label, ARMCondition(false_high_cond)); - } - // Must be equal high, so compare the lows. - __ cmp(left_low, ShifterOperand(right_low)); - } - // The last comparison might be unsigned. - // TODO: optimize cases where this is always true/false - __ b(true_label, final_condition); -} - -static void GenerateConditionLong(HCondition* cond, CodeGeneratorARM* codegen) { - DCHECK_EQ(cond->GetLeft()->GetType(), Primitive::kPrimLong); - - const LocationSummary* const locations = cond->GetLocations(); - IfCondition condition = cond->GetCondition(); - const Register out = locations->Out().AsRegister<Register>(); - const Location left = locations->InAt(0); - const Location right = locations->InAt(1); - - if (right.IsConstant()) { - IfCondition opposite = cond->GetOppositeCondition(); - - // Comparisons against 0 are common enough to deserve special attention. - if (AdjustConstantForCondition(Int64FromConstant(right.GetConstant()), - &condition, - &opposite) == 0) { - switch (condition) { - case kCondNE: - case kCondA: - if (ArmAssembler::IsLowRegister(out)) { - // We only care if both input registers are 0 or not. - __ orrs(out, - left.AsRegisterPairLow<Register>(), - ShifterOperand(left.AsRegisterPairHigh<Register>())); - __ it(NE); - __ mov(out, ShifterOperand(1), NE); - return; - } - - FALLTHROUGH_INTENDED; - case kCondEQ: - case kCondBE: - // We only care if both input registers are 0 or not. - __ orr(out, - left.AsRegisterPairLow<Register>(), - ShifterOperand(left.AsRegisterPairHigh<Register>())); - codegen->GenerateConditionWithZero(condition, out, out); - return; - case kCondLT: - case kCondGE: - // We only care about the sign bit. - FALLTHROUGH_INTENDED; - case kCondAE: - case kCondB: - codegen->GenerateConditionWithZero(condition, out, left.AsRegisterPairHigh<Register>()); - return; - case kCondLE: - case kCondGT: - default: - break; - } - } - } - - if ((condition == kCondEQ || condition == kCondNE) && - // If `out` is a low register, then the GenerateConditionGeneric() - // function generates a shorter code sequence that is still branchless. - (!ArmAssembler::IsLowRegister(out) || !CanGenerateTest(cond, codegen->GetAssembler()))) { - GenerateEqualLong(cond, codegen); - return; - } - - if (CanGenerateTest(cond, codegen->GetAssembler())) { - GenerateConditionGeneric(cond, codegen); - return; - } - - // Convert the jumps into the result. - Label done_label; - Label* const final_label = codegen->GetFinalLabel(cond, &done_label); - Label true_label, false_label; - - GenerateLongComparesAndJumps(cond, &true_label, &false_label, codegen); - - // False case: result = 0. - __ Bind(&false_label); - __ mov(out, ShifterOperand(0)); - __ b(final_label); - - // True case: result = 1. - __ Bind(&true_label); - __ mov(out, ShifterOperand(1)); - - if (done_label.IsLinked()) { - __ Bind(&done_label); - } -} - -static void GenerateConditionIntegralOrNonPrimitive(HCondition* cond, CodeGeneratorARM* codegen) { - const Primitive::Type type = cond->GetLeft()->GetType(); - - DCHECK(Primitive::IsIntegralType(type) || type == Primitive::kPrimNot) << type; - - if (type == Primitive::kPrimLong) { - GenerateConditionLong(cond, codegen); - return; - } - - const LocationSummary* const locations = cond->GetLocations(); - IfCondition condition = cond->GetCondition(); - Register in = locations->InAt(0).AsRegister<Register>(); - const Register out = locations->Out().AsRegister<Register>(); - const Location right = cond->GetLocations()->InAt(1); - int64_t value; - - if (right.IsConstant()) { - IfCondition opposite = cond->GetOppositeCondition(); - - value = AdjustConstantForCondition(Int64FromConstant(right.GetConstant()), - &condition, - &opposite); - - // Comparisons against 0 are common enough to deserve special attention. - if (value == 0) { - switch (condition) { - case kCondNE: - case kCondA: - if (ArmAssembler::IsLowRegister(out) && out == in) { - __ cmp(out, ShifterOperand(0)); - __ it(NE); - __ mov(out, ShifterOperand(1), NE); - return; - } - - FALLTHROUGH_INTENDED; - case kCondEQ: - case kCondBE: - case kCondLT: - case kCondGE: - case kCondAE: - case kCondB: - codegen->GenerateConditionWithZero(condition, out, in); - return; - case kCondLE: - case kCondGT: - default: - break; - } - } - } - - if (condition == kCondEQ || condition == kCondNE) { - ShifterOperand operand; - - if (right.IsConstant()) { - operand = ShifterOperand(value); - } else if (out == right.AsRegister<Register>()) { - // Avoid 32-bit instructions if possible. - operand = ShifterOperand(in); - in = right.AsRegister<Register>(); - } else { - operand = ShifterOperand(right.AsRegister<Register>()); - } - - if (condition == kCondNE && ArmAssembler::IsLowRegister(out)) { - __ subs(out, in, operand); - __ it(NE); - __ mov(out, ShifterOperand(1), NE); - } else { - __ sub(out, in, operand); - codegen->GenerateConditionWithZero(condition, out, out); - } - - return; - } - - GenerateConditionGeneric(cond, codegen); -} - static bool CanEncodeConstantAs8BitImmediate(HConstant* constant) { const Primitive::Type type = constant->GetType(); bool ret = false; @@ -2816,6 +2428,89 @@ void LocationsBuilderARM::VisitExit(HExit* exit) { void InstructionCodeGeneratorARM::VisitExit(HExit* exit ATTRIBUTE_UNUSED) { } +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); // unsigned on lower part + + // 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; + case kCondB: + false_high_cond = kCondA; + break; + case kCondBE: + true_high_cond = kCondB; + break; + case kCondA: + false_high_cond = kCondB; + break; + case kCondAE: + true_high_cond = kCondA; + break; + } + if (right.IsConstant()) { + int64_t value = right.GetConstant()->AsLongConstant()->GetValue(); + int32_t val_low = Low32Bits(value); + int32_t val_high = High32Bits(value); + + __ CmpConstant(left_high, val_high); + if (if_cond == kCondNE) { + __ b(true_label, ARMCondition(true_high_cond)); + } else if (if_cond == kCondEQ) { + __ b(false_label, ARMCondition(false_high_cond)); + } else { + __ b(true_label, ARMCondition(true_high_cond)); + __ b(false_label, ARMCondition(false_high_cond)); + } + // Must be equal high, so compare the lows. + __ CmpConstant(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, ARMCondition(true_high_cond)); + } else if (if_cond == kCondEQ) { + __ b(false_label, ARMCondition(false_high_cond)); + } else { + __ b(true_label, ARMCondition(true_high_cond)); + __ b(false_label, ARMCondition(false_high_cond)); + } + // Must be equal high, so compare the lows. + __ cmp(left_low, ShifterOperand(right_low)); + } + // The last comparison might be unsigned. + // TODO: optimize cases where this is always true/false + __ b(true_label, final_condition); +} + void InstructionCodeGeneratorARM::GenerateCompareTestAndBranch(HCondition* condition, Label* true_target_in, Label* false_target_in) { @@ -2850,7 +2545,7 @@ void InstructionCodeGeneratorARM::GenerateCompareTestAndBranch(HCondition* condi Label* false_target = false_target_in == nullptr ? &fallthrough_target : false_target_in; DCHECK_EQ(condition->InputAt(0)->GetType(), Primitive::kPrimLong); - GenerateLongComparesAndJumps(condition, true_target, false_target, codegen_); + GenerateLongComparesAndJumps(condition, true_target, false_target); if (false_target != &fallthrough_target) { __ b(false_target); @@ -3162,80 +2857,6 @@ void CodeGeneratorARM::GenerateNop() { __ nop(); } -// `temp` is an extra temporary register that is used for some conditions; -// callers may not specify it, in which case the method will use a scratch -// register instead. -void CodeGeneratorARM::GenerateConditionWithZero(IfCondition condition, - Register out, - Register in, - Register temp) { - switch (condition) { - case kCondEQ: - // x <= 0 iff x == 0 when the comparison is unsigned. - case kCondBE: - if (temp == kNoRegister || (ArmAssembler::IsLowRegister(out) && out != in)) { - temp = out; - } - - // Avoid 32-bit instructions if possible; note that `in` and `temp` must be - // different as well. - if (ArmAssembler::IsLowRegister(in) && ArmAssembler::IsLowRegister(temp) && in != temp) { - // temp = - in; only 0 sets the carry flag. - __ rsbs(temp, in, ShifterOperand(0)); - - if (out == in) { - std::swap(in, temp); - } - - // out = - in + in + carry = carry - __ adc(out, temp, ShifterOperand(in)); - } else { - // If `in` is 0, then it has 32 leading zeros, and less than that otherwise. - __ clz(out, in); - // Any number less than 32 logically shifted right by 5 bits results in 0; - // the same operation on 32 yields 1. - __ Lsr(out, out, 5); - } - - break; - case kCondNE: - // x > 0 iff x != 0 when the comparison is unsigned. - case kCondA: - if (out == in) { - if (temp == kNoRegister || in == temp) { - temp = IP; - } - } else if (temp == kNoRegister || !ArmAssembler::IsLowRegister(temp)) { - temp = out; - } - - // temp = in - 1; only 0 does not set the carry flag. - __ subs(temp, in, ShifterOperand(1)); - // out = in + ~temp + carry = in + (-(in - 1) - 1) + carry = in - in + 1 - 1 + carry = carry - __ sbc(out, in, ShifterOperand(temp)); - break; - case kCondGE: - __ mvn(out, ShifterOperand(in)); - in = out; - FALLTHROUGH_INTENDED; - case kCondLT: - // We only care about the sign bit. - __ Lsr(out, in, 31); - break; - case kCondAE: - // Trivially true. - __ mov(out, ShifterOperand(1)); - break; - case kCondB: - // Trivially false. - __ mov(out, ShifterOperand(0)); - break; - default: - LOG(FATAL) << "Unexpected condition " << condition; - UNREACHABLE(); - } -} - void LocationsBuilderARM::HandleCondition(HCondition* cond) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall); @@ -3272,42 +2893,48 @@ void InstructionCodeGeneratorARM::HandleCondition(HCondition* cond) { return; } - const Primitive::Type type = cond->GetLeft()->GetType(); + const Register out = cond->GetLocations()->Out().AsRegister<Register>(); - if (Primitive::IsFloatingPointType(type)) { - GenerateConditionGeneric(cond, codegen_); + if (ArmAssembler::IsLowRegister(out) && CanGenerateTest(cond, codegen_->GetAssembler())) { + const auto condition = GenerateTest(cond, false, codegen_); + + __ it(condition.first); + __ mov(out, ShifterOperand(1), condition.first); + __ it(condition.second); + __ mov(out, ShifterOperand(0), condition.second); return; } - DCHECK(Primitive::IsIntegralType(type) || type == Primitive::kPrimNot) << type; - - if (type == Primitive::kPrimBoolean) { - const LocationSummary* const locations = cond->GetLocations(); - const IfCondition c = cond->GetCondition(); - Register left = locations->InAt(0).AsRegister<Register>(); - const Register out = locations->Out().AsRegister<Register>(); - const Location right_loc = locations->InAt(1); + // Convert the jumps into the result. + Label done_label; + Label* const final_label = codegen_->GetFinalLabel(cond, &done_label); - // All other cases are handled by the instruction simplifier. - DCHECK((c == kCondEQ || c == kCondNE) && !right_loc.IsConstant()); + if (cond->InputAt(0)->GetType() == Primitive::kPrimLong) { + Label true_label, false_label; - Register right = right_loc.AsRegister<Register>(); + GenerateLongComparesAndJumps(cond, &true_label, &false_label); - // Avoid 32-bit instructions if possible. - if (out == right) { - std::swap(left, right); - } + // False case: result = 0. + __ Bind(&false_label); + __ LoadImmediate(out, 0); + __ b(final_label); - __ eor(out, left, ShifterOperand(right)); + // True case: result = 1. + __ Bind(&true_label); + __ LoadImmediate(out, 1); + } else { + DCHECK(CanGenerateTest(cond, codegen_->GetAssembler())); - if (c == kCondEQ) { - __ eor(out, out, ShifterOperand(1)); - } + const auto condition = GenerateTest(cond, false, codegen_); - return; + __ mov(out, ShifterOperand(0), AL, kCcKeep); + __ b(final_label, condition.second); + __ LoadImmediate(out, 1); } - GenerateConditionIntegralOrNonPrimitive(cond, codegen_); + if (done_label.IsLinked()) { + __ Bind(&done_label); + } } void LocationsBuilderARM::VisitEqual(HEqual* comp) { diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h index dedb63921a..86f2f21df7 100644 --- a/compiler/optimizing/code_generator_arm.h +++ b/compiler/optimizing/code_generator_arm.h @@ -299,6 +299,7 @@ class InstructionCodeGeneratorARM : public InstructionCodeGenerator { void GenerateCompareTestAndBranch(HCondition* condition, Label* true_target, Label* false_target); + void GenerateLongComparesAndJumps(HCondition* cond, Label* true_label, Label* false_label); void DivRemOneOrMinusOne(HBinaryOperation* instruction); void DivRemByPowerOfTwo(HBinaryOperation* instruction); void GenerateDivRemWithAnyConstant(HBinaryOperation* instruction); @@ -603,14 +604,6 @@ class CodeGeneratorARM : public CodeGenerator { void GenerateImplicitNullCheck(HNullCheck* instruction) OVERRIDE; void GenerateExplicitNullCheck(HNullCheck* instruction) OVERRIDE; - // `temp` is an extra temporary register that is used for some conditions; - // callers may not specify it, in which case the method will use a scratch - // register instead. - void GenerateConditionWithZero(IfCondition condition, - Register out, - Register in, - Register temp = kNoRegister); - private: Register GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOrDirect* invoke, Register temp); diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc index bbd4d9fde7..b6678b03ef 100644 --- a/compiler/optimizing/code_generator_arm_vixl.cc +++ b/compiler/optimizing/code_generator_arm_vixl.cc @@ -1687,34 +1687,6 @@ static void GenerateVcmp(HInstruction* instruction, CodeGeneratorARMVIXL* codege } } -static int64_t AdjustConstantForCondition(int64_t value, - IfCondition* condition, - IfCondition* opposite) { - if (value == 1) { - if (*condition == kCondB) { - value = 0; - *condition = kCondEQ; - *opposite = kCondNE; - } else if (*condition == kCondAE) { - value = 0; - *condition = kCondNE; - *opposite = kCondEQ; - } - } else if (value == -1) { - if (*condition == kCondGT) { - value = 0; - *condition = kCondGE; - *opposite = kCondLT; - } else if (*condition == kCondLE) { - value = 0; - *condition = kCondLT; - *opposite = kCondGE; - } - } - - return value; -} - static std::pair<vixl32::Condition, vixl32::Condition> GenerateLongTestConstant( HCondition* condition, bool invert, @@ -1737,37 +1709,7 @@ static std::pair<vixl32::Condition, vixl32::Condition> GenerateLongTestConstant( const vixl32::Register left_high = HighRegisterFrom(left); const vixl32::Register left_low = LowRegisterFrom(left); - int64_t value = AdjustConstantForCondition(Int64ConstantFrom(right), &cond, &opposite); - UseScratchRegisterScope temps(codegen->GetVIXLAssembler()); - - // Comparisons against 0 are common enough to deserve special attention. - if (value == 0) { - switch (cond) { - case kCondNE: - // x > 0 iff x != 0 when the comparison is unsigned. - case kCondA: - ret = std::make_pair(ne, eq); - FALLTHROUGH_INTENDED; - case kCondEQ: - // x <= 0 iff x == 0 when the comparison is unsigned. - case kCondBE: - __ Orrs(temps.Acquire(), left_low, left_high); - return ret; - case kCondLT: - case kCondGE: - __ Cmp(left_high, 0); - return std::make_pair(ARMCondition(cond), ARMCondition(opposite)); - // Trivially true or false. - case kCondB: - ret = std::make_pair(ne, eq); - FALLTHROUGH_INTENDED; - case kCondAE: - __ Cmp(left_low, left_low); - return ret; - default: - break; - } - } + int64_t value = Int64ConstantFrom(right); switch (cond) { case kCondEQ: @@ -1812,6 +1754,8 @@ static std::pair<vixl32::Condition, vixl32::Condition> GenerateLongTestConstant( FALLTHROUGH_INTENDED; case kCondGE: case kCondLT: { + UseScratchRegisterScope temps(codegen->GetVIXLAssembler()); + __ Cmp(left_low, Low32Bits(value)); __ Sbcs(temps.Acquire(), left_high, High32Bits(value)); ret = std::make_pair(ARMCondition(cond), ARMCondition(opposite)); @@ -1929,22 +1873,18 @@ static std::pair<vixl32::Condition, vixl32::Condition> GenerateTest(HCondition* static bool CanGenerateTest(HCondition* condition, ArmVIXLAssembler* assembler) { if (condition->GetLeft()->GetType() == Primitive::kPrimLong) { const LocationSummary* const locations = condition->GetLocations(); + const IfCondition c = condition->GetCondition(); if (locations->InAt(1).IsConstant()) { - IfCondition c = condition->GetCondition(); - IfCondition opposite = condition->GetOppositeCondition(); - const int64_t value = - AdjustConstantForCondition(Int64ConstantFrom(locations->InAt(1)), &c, &opposite); + const int64_t value = Int64ConstantFrom(locations->InAt(1)); if (c < kCondLT || c > kCondGE) { // Since IT blocks longer than a 16-bit instruction are deprecated by ARMv8, // we check that the least significant half of the first input to be compared // is in a low register (the other half is read outside an IT block), and // the constant fits in an 8-bit unsigned integer, so that a 16-bit CMP - // encoding can be used; 0 is always handled, no matter what registers are - // used by the first input. - if (value != 0 && - (!LowRegisterFrom(locations->InAt(0)).IsLow() || !IsUint<8>(Low32Bits(value)))) { + // encoding can be used. + if (!LowRegisterFrom(locations->InAt(0)).IsLow() || !IsUint<8>(Low32Bits(value))) { return false; } // TODO(VIXL): The rest of the checks are there to keep the backend in sync with @@ -1963,353 +1903,6 @@ static bool CanGenerateTest(HCondition* condition, ArmVIXLAssembler* assembler) return true; } -static void GenerateConditionGeneric(HCondition* cond, CodeGeneratorARMVIXL* codegen) { - DCHECK(CanGenerateTest(cond, codegen->GetAssembler())); - - const vixl32::Register out = OutputRegister(cond); - const auto condition = GenerateTest(cond, false, codegen); - - __ Mov(LeaveFlags, out, 0); - - if (out.IsLow()) { - // We use the scope because of the IT block that follows. - ExactAssemblyScope guard(codegen->GetVIXLAssembler(), - 2 * vixl32::k16BitT32InstructionSizeInBytes, - CodeBufferCheckScope::kExactSize); - - __ it(condition.first); - __ mov(condition.first, out, 1); - } else { - vixl32::Label done_label; - vixl32::Label* const final_label = codegen->GetFinalLabel(cond, &done_label); - - __ B(condition.second, final_label, /* far_target */ false); - __ Mov(out, 1); - - if (done_label.IsReferenced()) { - __ Bind(&done_label); - } - } -} - -static void GenerateEqualLong(HCondition* cond, CodeGeneratorARMVIXL* codegen) { - DCHECK_EQ(cond->GetLeft()->GetType(), Primitive::kPrimLong); - - const LocationSummary* const locations = cond->GetLocations(); - IfCondition condition = cond->GetCondition(); - const vixl32::Register out = OutputRegister(cond); - const Location left = locations->InAt(0); - const Location right = locations->InAt(1); - vixl32::Register left_high = HighRegisterFrom(left); - vixl32::Register left_low = LowRegisterFrom(left); - vixl32::Register temp; - UseScratchRegisterScope temps(codegen->GetVIXLAssembler()); - - if (right.IsConstant()) { - IfCondition opposite = cond->GetOppositeCondition(); - const int64_t value = AdjustConstantForCondition(Int64ConstantFrom(right), - &condition, - &opposite); - Operand right_high = High32Bits(value); - Operand right_low = Low32Bits(value); - - // The output uses Location::kNoOutputOverlap. - if (out.Is(left_high)) { - std::swap(left_low, left_high); - std::swap(right_low, right_high); - } - - __ Sub(out, left_low, right_low); - temp = temps.Acquire(); - __ Sub(temp, left_high, right_high); - } else { - DCHECK(right.IsRegisterPair()); - temp = temps.Acquire(); - __ Sub(temp, left_high, HighRegisterFrom(right)); - __ Sub(out, left_low, LowRegisterFrom(right)); - } - - // Need to check after calling AdjustConstantForCondition(). - DCHECK(condition == kCondEQ || condition == kCondNE) << condition; - - if (condition == kCondNE && out.IsLow()) { - __ Orrs(out, out, temp); - - // We use the scope because of the IT block that follows. - ExactAssemblyScope guard(codegen->GetVIXLAssembler(), - 2 * vixl32::k16BitT32InstructionSizeInBytes, - CodeBufferCheckScope::kExactSize); - - __ it(ne); - __ mov(ne, out, 1); - } else { - __ Orr(out, out, temp); - codegen->GenerateConditionWithZero(condition, out, out, temp); - } -} - -static void GenerateLongComparesAndJumps(HCondition* cond, - vixl32::Label* true_label, - vixl32::Label* false_label, - CodeGeneratorARMVIXL* codegen) { - LocationSummary* locations = cond->GetLocations(); - Location left = locations->InAt(0); - Location right = locations->InAt(1); - IfCondition if_cond = cond->GetCondition(); - - vixl32::Register left_high = HighRegisterFrom(left); - vixl32::Register left_low = LowRegisterFrom(left); - IfCondition true_high_cond = if_cond; - IfCondition false_high_cond = cond->GetOppositeCondition(); - vixl32::Condition final_condition = ARMUnsignedCondition(if_cond); // unsigned on lower part - - // 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; - case kCondB: - false_high_cond = kCondA; - break; - case kCondBE: - true_high_cond = kCondB; - break; - case kCondA: - false_high_cond = kCondB; - break; - case kCondAE: - true_high_cond = kCondA; - break; - } - if (right.IsConstant()) { - int64_t value = Int64ConstantFrom(right); - int32_t val_low = Low32Bits(value); - int32_t val_high = High32Bits(value); - - __ Cmp(left_high, val_high); - if (if_cond == kCondNE) { - __ B(ARMCondition(true_high_cond), true_label); - } else if (if_cond == kCondEQ) { - __ B(ARMCondition(false_high_cond), false_label); - } else { - __ B(ARMCondition(true_high_cond), true_label); - __ B(ARMCondition(false_high_cond), false_label); - } - // Must be equal high, so compare the lows. - __ Cmp(left_low, val_low); - } else { - vixl32::Register right_high = HighRegisterFrom(right); - vixl32::Register right_low = LowRegisterFrom(right); - - __ Cmp(left_high, right_high); - if (if_cond == kCondNE) { - __ B(ARMCondition(true_high_cond), true_label); - } else if (if_cond == kCondEQ) { - __ B(ARMCondition(false_high_cond), false_label); - } else { - __ B(ARMCondition(true_high_cond), true_label); - __ B(ARMCondition(false_high_cond), false_label); - } - // Must be equal high, so compare the lows. - __ Cmp(left_low, right_low); - } - // The last comparison might be unsigned. - // TODO: optimize cases where this is always true/false - __ B(final_condition, true_label); -} - -static void GenerateConditionLong(HCondition* cond, CodeGeneratorARMVIXL* codegen) { - DCHECK_EQ(cond->GetLeft()->GetType(), Primitive::kPrimLong); - - const LocationSummary* const locations = cond->GetLocations(); - IfCondition condition = cond->GetCondition(); - const vixl32::Register out = OutputRegister(cond); - const Location left = locations->InAt(0); - const Location right = locations->InAt(1); - - if (right.IsConstant()) { - IfCondition opposite = cond->GetOppositeCondition(); - - // Comparisons against 0 are common enough to deserve special attention. - if (AdjustConstantForCondition(Int64ConstantFrom(right), &condition, &opposite) == 0) { - switch (condition) { - case kCondNE: - case kCondA: - if (out.IsLow()) { - // We only care if both input registers are 0 or not. - __ Orrs(out, LowRegisterFrom(left), HighRegisterFrom(left)); - - // We use the scope because of the IT block that follows. - ExactAssemblyScope guard(codegen->GetVIXLAssembler(), - 2 * vixl32::k16BitT32InstructionSizeInBytes, - CodeBufferCheckScope::kExactSize); - - __ it(ne); - __ mov(ne, out, 1); - return; - } - - FALLTHROUGH_INTENDED; - case kCondEQ: - case kCondBE: - // We only care if both input registers are 0 or not. - __ Orr(out, LowRegisterFrom(left), HighRegisterFrom(left)); - codegen->GenerateConditionWithZero(condition, out, out); - return; - case kCondLT: - case kCondGE: - // We only care about the sign bit. - FALLTHROUGH_INTENDED; - case kCondAE: - case kCondB: - codegen->GenerateConditionWithZero(condition, out, HighRegisterFrom(left)); - return; - case kCondLE: - case kCondGT: - default: - break; - } - } - } - - if ((condition == kCondEQ || condition == kCondNE) && - // If `out` is a low register, then the GenerateConditionGeneric() - // function generates a shorter code sequence that is still branchless. - (!out.IsLow() || !CanGenerateTest(cond, codegen->GetAssembler()))) { - GenerateEqualLong(cond, codegen); - return; - } - - if (CanGenerateTest(cond, codegen->GetAssembler())) { - GenerateConditionGeneric(cond, codegen); - return; - } - - // Convert the jumps into the result. - vixl32::Label done_label; - vixl32::Label* const final_label = codegen->GetFinalLabel(cond, &done_label); - vixl32::Label true_label, false_label; - - GenerateLongComparesAndJumps(cond, &true_label, &false_label, codegen); - - // False case: result = 0. - __ Bind(&false_label); - __ Mov(out, 0); - __ B(final_label); - - // True case: result = 1. - __ Bind(&true_label); - __ Mov(out, 1); - - if (done_label.IsReferenced()) { - __ Bind(&done_label); - } -} - -static void GenerateConditionIntegralOrNonPrimitive(HCondition* cond, CodeGeneratorARMVIXL* codegen) { - const Primitive::Type type = cond->GetLeft()->GetType(); - - DCHECK(Primitive::IsIntegralType(type) || type == Primitive::kPrimNot) << type; - - if (type == Primitive::kPrimLong) { - GenerateConditionLong(cond, codegen); - return; - } - - IfCondition condition = cond->GetCondition(); - vixl32::Register in = InputRegisterAt(cond, 0); - const vixl32::Register out = OutputRegister(cond); - const Location right = cond->GetLocations()->InAt(1); - int64_t value; - - if (right.IsConstant()) { - IfCondition opposite = cond->GetOppositeCondition(); - - value = AdjustConstantForCondition(Int64ConstantFrom(right), &condition, &opposite); - - // Comparisons against 0 are common enough to deserve special attention. - if (value == 0) { - switch (condition) { - case kCondNE: - case kCondA: - if (out.IsLow() && out.Is(in)) { - __ Cmp(out, 0); - - // We use the scope because of the IT block that follows. - ExactAssemblyScope guard(codegen->GetVIXLAssembler(), - 2 * vixl32::k16BitT32InstructionSizeInBytes, - CodeBufferCheckScope::kExactSize); - - __ it(ne); - __ mov(ne, out, 1); - return; - } - - FALLTHROUGH_INTENDED; - case kCondEQ: - case kCondBE: - case kCondLT: - case kCondGE: - case kCondAE: - case kCondB: - codegen->GenerateConditionWithZero(condition, out, in); - return; - case kCondLE: - case kCondGT: - default: - break; - } - } - } - - if (condition == kCondEQ || condition == kCondNE) { - Operand operand(0); - - if (right.IsConstant()) { - operand = Operand::From(value); - } else if (out.Is(RegisterFrom(right))) { - // Avoid 32-bit instructions if possible. - operand = InputOperandAt(cond, 0); - in = RegisterFrom(right); - } else { - operand = InputOperandAt(cond, 1); - } - - if (condition == kCondNE && out.IsLow()) { - __ Subs(out, in, operand); - - // We use the scope because of the IT block that follows. - ExactAssemblyScope guard(codegen->GetVIXLAssembler(), - 2 * vixl32::k16BitT32InstructionSizeInBytes, - CodeBufferCheckScope::kExactSize); - - __ it(ne); - __ mov(ne, out, 1); - } else { - __ Sub(out, in, operand); - codegen->GenerateConditionWithZero(condition, out, out); - } - - return; - } - - GenerateConditionGeneric(cond, codegen); -} - static bool CanEncodeConstantAs8BitImmediate(HConstant* constant) { const Primitive::Type type = constant->GetType(); bool ret = false; @@ -2869,6 +2462,89 @@ void LocationsBuilderARMVIXL::VisitExit(HExit* exit) { void InstructionCodeGeneratorARMVIXL::VisitExit(HExit* exit ATTRIBUTE_UNUSED) { } +void InstructionCodeGeneratorARMVIXL::GenerateLongComparesAndJumps(HCondition* cond, + vixl32::Label* true_label, + vixl32::Label* false_label) { + LocationSummary* locations = cond->GetLocations(); + Location left = locations->InAt(0); + Location right = locations->InAt(1); + IfCondition if_cond = cond->GetCondition(); + + vixl32::Register left_high = HighRegisterFrom(left); + vixl32::Register left_low = LowRegisterFrom(left); + IfCondition true_high_cond = if_cond; + IfCondition false_high_cond = cond->GetOppositeCondition(); + vixl32::Condition final_condition = ARMUnsignedCondition(if_cond); // unsigned on lower part + + // 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; + case kCondB: + false_high_cond = kCondA; + break; + case kCondBE: + true_high_cond = kCondB; + break; + case kCondA: + false_high_cond = kCondB; + break; + case kCondAE: + true_high_cond = kCondA; + break; + } + if (right.IsConstant()) { + int64_t value = Int64ConstantFrom(right); + int32_t val_low = Low32Bits(value); + int32_t val_high = High32Bits(value); + + __ Cmp(left_high, val_high); + if (if_cond == kCondNE) { + __ B(ARMCondition(true_high_cond), true_label); + } else if (if_cond == kCondEQ) { + __ B(ARMCondition(false_high_cond), false_label); + } else { + __ B(ARMCondition(true_high_cond), true_label); + __ B(ARMCondition(false_high_cond), false_label); + } + // Must be equal high, so compare the lows. + __ Cmp(left_low, val_low); + } else { + vixl32::Register right_high = HighRegisterFrom(right); + vixl32::Register right_low = LowRegisterFrom(right); + + __ Cmp(left_high, right_high); + if (if_cond == kCondNE) { + __ B(ARMCondition(true_high_cond), true_label); + } else if (if_cond == kCondEQ) { + __ B(ARMCondition(false_high_cond), false_label); + } else { + __ B(ARMCondition(true_high_cond), true_label); + __ B(ARMCondition(false_high_cond), false_label); + } + // Must be equal high, so compare the lows. + __ Cmp(left_low, right_low); + } + // The last comparison might be unsigned. + // TODO: optimize cases where this is always true/false + __ B(final_condition, true_label); +} + void InstructionCodeGeneratorARMVIXL::GenerateCompareTestAndBranch(HCondition* condition, vixl32::Label* true_target_in, vixl32::Label* false_target_in) { @@ -2903,7 +2579,7 @@ void InstructionCodeGeneratorARMVIXL::GenerateCompareTestAndBranch(HCondition* c vixl32::Label* false_target = (false_target_in == nullptr) ? &fallthrough : false_target_in; DCHECK_EQ(condition->InputAt(0)->GetType(), Primitive::kPrimLong); - GenerateLongComparesAndJumps(condition, true_target, false_target, codegen_); + GenerateLongComparesAndJumps(condition, true_target, false_target); if (false_target != &fallthrough) { __ B(false_target); @@ -3211,83 +2887,6 @@ void CodeGeneratorARMVIXL::GenerateNop() { __ Nop(); } -// `temp` is an extra temporary register that is used for some conditions; -// callers may not specify it, in which case the method will use a scratch -// register instead. -void CodeGeneratorARMVIXL::GenerateConditionWithZero(IfCondition condition, - vixl32::Register out, - vixl32::Register in, - vixl32::Register temp) { - switch (condition) { - case kCondEQ: - // x <= 0 iff x == 0 when the comparison is unsigned. - case kCondBE: - if (!temp.IsValid() || (out.IsLow() && !out.Is(in))) { - temp = out; - } - - // Avoid 32-bit instructions if possible; note that `in` and `temp` must be - // different as well. - if (in.IsLow() && temp.IsLow() && !in.Is(temp)) { - // temp = - in; only 0 sets the carry flag. - __ Rsbs(temp, in, 0); - - if (out.Is(in)) { - std::swap(in, temp); - } - - // out = - in + in + carry = carry - __ Adc(out, temp, in); - } else { - // If `in` is 0, then it has 32 leading zeros, and less than that otherwise. - __ Clz(out, in); - // Any number less than 32 logically shifted right by 5 bits results in 0; - // the same operation on 32 yields 1. - __ Lsr(out, out, 5); - } - - break; - case kCondNE: - // x > 0 iff x != 0 when the comparison is unsigned. - case kCondA: { - UseScratchRegisterScope temps(GetVIXLAssembler()); - - if (out.Is(in)) { - if (!temp.IsValid() || in.Is(temp)) { - temp = temps.Acquire(); - } - } else if (!temp.IsValid() || !temp.IsLow()) { - temp = out; - } - - // temp = in - 1; only 0 does not set the carry flag. - __ Subs(temp, in, 1); - // out = in + ~temp + carry = in + (-(in - 1) - 1) + carry = in - in + 1 - 1 + carry = carry - __ Sbc(out, in, temp); - break; - } - case kCondGE: - __ Mvn(out, in); - in = out; - FALLTHROUGH_INTENDED; - case kCondLT: - // We only care about the sign bit. - __ Lsr(out, in, 31); - break; - case kCondAE: - // Trivially true. - __ Mov(out, 1); - break; - case kCondB: - // Trivially false. - __ Mov(out, 0); - break; - default: - LOG(FATAL) << "Unexpected condition " << condition; - UNREACHABLE(); - } -} - void LocationsBuilderARMVIXL::HandleCondition(HCondition* cond) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall); @@ -3324,41 +2923,52 @@ void InstructionCodeGeneratorARMVIXL::HandleCondition(HCondition* cond) { return; } - const Primitive::Type type = cond->GetLeft()->GetType(); + const vixl32::Register out = OutputRegister(cond); + + if (out.IsLow() && CanGenerateTest(cond, codegen_->GetAssembler())) { + const auto condition = GenerateTest(cond, false, codegen_); + // We use the scope because of the IT block that follows. + ExactAssemblyScope guard(GetVIXLAssembler(), + 4 * vixl32::k16BitT32InstructionSizeInBytes, + CodeBufferCheckScope::kExactSize); - if (Primitive::IsFloatingPointType(type)) { - GenerateConditionGeneric(cond, codegen_); + __ it(condition.first); + __ mov(condition.first, out, 1); + __ it(condition.second); + __ mov(condition.second, out, 0); return; } - DCHECK(Primitive::IsIntegralType(type) || type == Primitive::kPrimNot) << type; - - if (type == Primitive::kPrimBoolean) { - const IfCondition c = cond->GetCondition(); - vixl32::Register left = InputRegisterAt(cond, 0); - const vixl32::Register out = OutputRegister(cond); - const Location right_loc = cond->GetLocations()->InAt(1); + // Convert the jumps into the result. + vixl32::Label done_label; + vixl32::Label* const final_label = codegen_->GetFinalLabel(cond, &done_label); - // All other cases are handled by the instruction simplifier. - DCHECK((c == kCondEQ || c == kCondNE) && !right_loc.IsConstant()); + if (cond->InputAt(0)->GetType() == Primitive::kPrimLong) { + vixl32::Label true_label, false_label; - vixl32::Register right = RegisterFrom(right_loc); + GenerateLongComparesAndJumps(cond, &true_label, &false_label); - // Avoid 32-bit instructions if possible. - if (out.Is(right)) { - std::swap(left, right); - } + // False case: result = 0. + __ Bind(&false_label); + __ Mov(out, 0); + __ B(final_label); - __ Eor(out, left, right); + // True case: result = 1. + __ Bind(&true_label); + __ Mov(out, 1); + } else { + DCHECK(CanGenerateTest(cond, codegen_->GetAssembler())); - if (c == kCondEQ) { - __ Eor(out, out, 1); - } + const auto condition = GenerateTest(cond, false, codegen_); - return; + __ Mov(LeaveFlags, out, 0); + __ B(condition.second, final_label, /* far_target */ false); + __ Mov(out, 1); } - GenerateConditionIntegralOrNonPrimitive(cond, codegen_); + if (done_label.IsReferenced()) { + __ Bind(&done_label); + } } void LocationsBuilderARMVIXL::VisitEqual(HEqual* comp) { diff --git a/compiler/optimizing/code_generator_arm_vixl.h b/compiler/optimizing/code_generator_arm_vixl.h index 26416c8057..1e9669dc38 100644 --- a/compiler/optimizing/code_generator_arm_vixl.h +++ b/compiler/optimizing/code_generator_arm_vixl.h @@ -401,6 +401,9 @@ class InstructionCodeGeneratorARMVIXL : public InstructionCodeGenerator { void GenerateCompareTestAndBranch(HCondition* condition, vixl::aarch32::Label* true_target, vixl::aarch32::Label* false_target); + void GenerateLongComparesAndJumps(HCondition* cond, + vixl::aarch32::Label* true_label, + vixl::aarch32::Label* false_label); void DivRemOneOrMinusOne(HBinaryOperation* instruction); void DivRemByPowerOfTwo(HBinaryOperation* instruction); void GenerateDivRemWithAnyConstant(HBinaryOperation* instruction); @@ -696,14 +699,6 @@ class CodeGeneratorARMVIXL : public CodeGenerator { void EmitMovwMovtPlaceholder(CodeGeneratorARMVIXL::PcRelativePatchInfo* labels, vixl::aarch32::Register out); - // `temp` is an extra temporary register that is used for some conditions; - // callers may not specify it, in which case the method will use a scratch - // register instead. - void GenerateConditionWithZero(IfCondition condition, - vixl::aarch32::Register out, - vixl::aarch32::Register in, - vixl::aarch32::Register temp = vixl32::Register()); - private: vixl::aarch32::Register GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOrDirect* invoke, vixl::aarch32::Register temp); diff --git a/compiler/optimizing/intrinsics_arm.cc b/compiler/optimizing/intrinsics_arm.cc index 7769b147a3..750f9cc213 100644 --- a/compiler/optimizing/intrinsics_arm.cc +++ b/compiler/optimizing/intrinsics_arm.cc @@ -2599,7 +2599,11 @@ void IntrinsicCodeGeneratorARM::VisitFloatIsInfinite(HInvoke* invoke) { // We don't care about the sign bit, so shift left. __ Lsl(out, out, 1); __ eor(out, out, ShifterOperand(infinity)); - codegen_->GenerateConditionWithZero(kCondEQ, out, out); + // If the result is 0, then it has 32 leading zeros, and less than that otherwise. + __ clz(out, out); + // Any number less than 32 logically shifted right by 5 bits results in 0; + // the same operation on 32 yields 1. + __ Lsr(out, out, 5); } void IntrinsicLocationsBuilderARM::VisitDoubleIsInfinite(HInvoke* invoke) { @@ -2622,7 +2626,11 @@ void IntrinsicCodeGeneratorARM::VisitDoubleIsInfinite(HInvoke* invoke) { __ eor(out, out, ShifterOperand(infinity_high2)); // We don't care about the sign bit, so shift left. __ orr(out, IP, ShifterOperand(out, LSL, 1)); - codegen_->GenerateConditionWithZero(kCondEQ, out, out); + // If the result is 0, then it has 32 leading zeros, and less than that otherwise. + __ clz(out, out); + // Any number less than 32 logically shifted right by 5 bits results in 0; + // the same operation on 32 yields 1. + __ Lsr(out, out, 5); } void IntrinsicLocationsBuilderARM::VisitReferenceGetReferent(HInvoke* invoke) { diff --git a/compiler/optimizing/intrinsics_arm_vixl.cc b/compiler/optimizing/intrinsics_arm_vixl.cc index b62c1b55fd..fd8a37ae05 100644 --- a/compiler/optimizing/intrinsics_arm_vixl.cc +++ b/compiler/optimizing/intrinsics_arm_vixl.cc @@ -2972,7 +2972,11 @@ void IntrinsicCodeGeneratorARMVIXL::VisitFloatIsInfinite(HInvoke* invoke) { // We don't care about the sign bit, so shift left. __ Lsl(out, out, 1); __ Eor(out, out, infinity); - codegen_->GenerateConditionWithZero(kCondEQ, out, out); + // If the result is 0, then it has 32 leading zeros, and less than that otherwise. + __ Clz(out, out); + // Any number less than 32 logically shifted right by 5 bits results in 0; + // the same operation on 32 yields 1. + __ Lsr(out, out, 5); } void IntrinsicLocationsBuilderARMVIXL::VisitDoubleIsInfinite(HInvoke* invoke) { @@ -2998,7 +3002,11 @@ void IntrinsicCodeGeneratorARMVIXL::VisitDoubleIsInfinite(HInvoke* invoke) { __ Eor(out, out, infinity_high2); // We don't care about the sign bit, so shift left. __ Orr(out, temp, Operand(out, vixl32::LSL, 1)); - codegen_->GenerateConditionWithZero(kCondEQ, out, out); + // If the result is 0, then it has 32 leading zeros, and less than that otherwise. + __ Clz(out, out); + // Any number less than 32 logically shifted right by 5 bits results in 0; + // the same operation on 32 yields 1. + __ Lsr(out, out, 5); } void IntrinsicLocationsBuilderARMVIXL::VisitReferenceGetReferent(HInvoke* invoke) { diff --git a/test/409-materialized-condition/src/Main.java b/test/409-materialized-condition/src/Main.java index 8a814a2da1..0c179a99de 100644 --- a/test/409-materialized-condition/src/Main.java +++ b/test/409-materialized-condition/src/Main.java @@ -50,36 +50,6 @@ public class Main { return b; } - public static boolean $noinline$intEq0(int x) { - return x == 0; - } - - public static boolean $noinline$intNe0(int x) { - return x != 0; - } - - public static boolean $noinline$longEq0(long x) { - return x == 0; - } - - public static boolean $noinline$longNe0(long x) { - return x != 0; - } - - public static boolean $noinline$longEqCst(long x) { - return x == 0x0123456789ABCDEFL; - } - - public static boolean $noinline$longNeCst(long x) { - return x != 0x0123456789ABCDEFL; - } - - public static void assertEqual(boolean expected, boolean actual) { - if (expected != actual) { - throw new Error("Assertion failed: " + expected + " != " + actual); - } - } - public static void main(String[] args) { System.out.println("foo1"); int res = foo1(); @@ -92,46 +62,5 @@ public class Main { if (res != 42) { throw new Error("Unexpected return value for foo2: " + res + ", expected 42."); } - - int[] int_inputs = {0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE, 42, -9000}; - long[] long_inputs = { - 0L, 1L, -1L, Long.MIN_VALUE, Long.MAX_VALUE, 0x100000000L, - 0x100000001L, -9000L, 0x0123456789ABCDEFL}; - - boolean[] int_eq_0_expected = {true, false, false, false, false, false, false}; - - for (int i = 0; i < int_inputs.length; i++) { - assertEqual(int_eq_0_expected[i], $noinline$intEq0(int_inputs[i])); - } - - boolean[] int_ne_0_expected = {false, true, true, true, true, true, true}; - - for (int i = 0; i < int_inputs.length; i++) { - assertEqual(int_ne_0_expected[i], $noinline$intNe0(int_inputs[i])); - } - - boolean[] long_eq_0_expected = {true, false, false, false, false, false, false, false, false}; - - for (int i = 0; i < long_inputs.length; i++) { - assertEqual(long_eq_0_expected[i], $noinline$longEq0(long_inputs[i])); - } - - boolean[] long_ne_0_expected = {false, true, true, true, true, true, true, true, true}; - - for (int i = 0; i < long_inputs.length; i++) { - assertEqual(long_ne_0_expected[i], $noinline$longNe0(long_inputs[i])); - } - - boolean[] long_eq_cst_expected = {false, false, false, false, false, false, false, false, true}; - - for (int i = 0; i < long_inputs.length; i++) { - assertEqual(long_eq_cst_expected[i], $noinline$longEqCst(long_inputs[i])); - } - - boolean[] long_ne_cst_expected = {true, true, true, true, true, true, true, true, false}; - - for (int i = 0; i < long_inputs.length; i++) { - assertEqual(long_ne_cst_expected[i], $noinline$longNeCst(long_inputs[i])); - } } } diff --git a/test/570-checker-select/src/Main.java b/test/570-checker-select/src/Main.java index 2dad14ce31..3ac6f89c5f 100644 --- a/test/570-checker-select/src/Main.java +++ b/test/570-checker-select/src/Main.java @@ -414,46 +414,6 @@ public class Main { return a > 0x7FFFFFFFFFFFFFFFL ? x : y; } - /// CHECK-START-ARM: long Main.$noinline$LongNonmatCondCst_LongVarVar4(long, long, long) disassembly (after) - /// CHECK: Select - /// CHECK-NEXT: orrs ip, {{r\d+}}, {{r\d+}} - /// CHECK-NOT: cmp - /// CHECK-NOT: sbcs - - public static long $noinline$LongNonmatCondCst_LongVarVar4(long a, long x, long y) { - return a == 0 ? x : y; - } - - /// CHECK-START-ARM: long Main.$noinline$LongNonmatCondCst_LongVarVar5(long, long, long) disassembly (after) - /// CHECK: Select - /// CHECK-NEXT: orrs ip, {{r\d+}}, {{r\d+}} - /// CHECK-NOT: cmp - /// CHECK-NOT: sbcs - - public static long $noinline$LongNonmatCondCst_LongVarVar5(long a, long x, long y) { - return a != 0 ? x : y; - } - - /// CHECK-START-ARM: long Main.$noinline$LongNonmatCondCst_LongVarVar6(long, long, long) disassembly (after) - /// CHECK: Select - /// CHECK-NEXT: cmp {{r\d+}}, #0 - /// CHECK-NOT: cmp - /// CHECK-NOT: sbcs - - public static long $noinline$LongNonmatCondCst_LongVarVar6(long a, long x, long y) { - return a >= 0 ? x : y; - } - - /// CHECK-START-ARM: long Main.$noinline$LongNonmatCondCst_LongVarVar7(long, long, long) disassembly (after) - /// CHECK: Select - /// CHECK-NEXT: cmp {{r\d+}}, #0 - /// CHECK-NOT: cmp - /// CHECK-NOT: sbcs - - public static long $noinline$LongNonmatCondCst_LongVarVar7(long a, long x, long y) { - return a < 0 ? x : y; - } - /// CHECK-START: long Main.LongMatCond_LongVarVar(long, long, long, long) register (after) /// CHECK: <<Cond:z\d+>> LessThanOrEqual [{{j\d+}},{{j\d+}}] /// CHECK: <<Sel1:j\d+>> Select [{{j\d+}},{{j\d+}},<<Cond>>] @@ -728,37 +688,6 @@ public class Main { assertEqual(7L, $noinline$LongNonmatCondCst_LongVarVar3(2L, 5L, 7L)); - long[] long_inputs = { - 0L, 1L, -1L, Long.MIN_VALUE, Long.MAX_VALUE, 2L, 0x100000000L, 0xFFFFFFFF00000000L, -9000L}; - - long[] expected_1 = {5L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L}; - - for (int i = 0; i < long_inputs.length; i++) { - assertEqual(expected_1[i], $noinline$LongNonmatCondCst_LongVarVar4(long_inputs[i], 5L, 7L)); - } - - long[] expected_2 = {7L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L}; - - for (int i = 0; i < long_inputs.length; i++) { - assertEqual(expected_2[i], $noinline$LongNonmatCondCst_LongVarVar5(long_inputs[i], 5L, 7L)); - } - - long[] expected_3 = {5L, 5L, 7L, 7L, 5L, 5L, 5L, 7L, 7L}; - - for (int i = 0; i < long_inputs.length; i++) { - assertEqual(expected_3[i], $noinline$LongNonmatCondCst_LongVarVar6(long_inputs[i], 5L, 7L)); - } - - long[] expected_4 = {7L, 7L, 5L, 5L, 7L, 7L, 7L, 5L, 5L}; - - for (int i = 0; i < long_inputs.length; i++) { - assertEqual(expected_4[i], $noinline$LongNonmatCondCst_LongVarVar7(long_inputs[i], 5L, 7L)); - } - - assertEqual(7L, $noinline$LongNonmatCondCst_LongVarVar7(0L, 5L, 7L)); - assertEqual(7L, $noinline$LongNonmatCondCst_LongVarVar7(2L, 5L, 7L)); - assertEqual(5L, $noinline$LongNonmatCondCst_LongVarVar7(-9000L, 5L, 7L)); - assertEqual(5, FloatLtNonmatCond_IntVarVar(3, 2, 5, 7)); assertEqual(7, FloatLtNonmatCond_IntVarVar(2, 3, 5, 7)); assertEqual(7, FloatLtNonmatCond_IntVarVar(Float.NaN, 2, 5, 7)); |