summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/optimizing/code_generator_arm_vixl.cc240
1 files changed, 43 insertions, 197 deletions
diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc
index 3d45dd3446..d78756e964 100644
--- a/compiler/optimizing/code_generator_arm_vixl.cc
+++ b/compiler/optimizing/code_generator_arm_vixl.cc
@@ -1875,15 +1875,26 @@ static std::pair<vixl32::Condition, vixl32::Condition> GenerateLongTestConstant(
case kCondBE:
case kCondA:
case kCondAE: {
+ const uint32_t value_low = Low32Bits(value);
+ Operand operand_low(value_low);
+
__ Cmp(left_high, High32Bits(value));
+ // Since IT blocks longer than a 16-bit instruction are deprecated by ARMv8,
+ // we must ensure that the operands corresponding to the least significant
+ // halves of the inputs fit into a 16-bit CMP encoding.
+ if (!left_low.IsLow() || !IsUint<8>(value_low)) {
+ operand_low = Operand(temps.Acquire());
+ __ Mov(LeaveFlags, operand_low.GetBaseRegister(), value_low);
+ }
+
// We use the scope because of the IT block that follows.
ExactAssemblyScope guard(codegen->GetVIXLAssembler(),
2 * vixl32::k16BitT32InstructionSizeInBytes,
CodeBufferCheckScope::kExactSize);
__ it(eq);
- __ cmp(eq, left_low, Low32Bits(value));
+ __ cmp(eq, left_low, operand_low);
ret = std::make_pair(ARMUnsignedCondition(cond), ARMUnsignedCondition(opposite));
break;
}
@@ -2025,46 +2036,7 @@ static std::pair<vixl32::Condition, vixl32::Condition> GenerateTest(HCondition*
return ret;
}
-static bool CanGenerateTest(HCondition* condition, ArmVIXLAssembler* assembler) {
- if (condition->GetLeft()->GetType() == Primitive::kPrimLong) {
- const LocationSummary* const locations = condition->GetLocations();
-
- if (locations->InAt(1).IsConstant()) {
- IfCondition c = condition->GetCondition();
- IfCondition opposite = condition->GetOppositeCondition();
- const int64_t value =
- AdjustConstantForCondition(Int64ConstantFrom(locations->InAt(1)), &c, &opposite);
-
- 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)))) {
- return false;
- }
- // TODO(VIXL): The rest of the checks are there to keep the backend in sync with
- // the previous one, but are not strictly necessary.
- } else if (c == kCondLE || c == kCondGT) {
- if (value < std::numeric_limits<int64_t>::max() &&
- !assembler->ShifterOperandCanHold(SBC, High32Bits(value + 1), kCcSet)) {
- return false;
- }
- } else if (!assembler->ShifterOperandCanHold(SBC, High32Bits(value), kCcSet)) {
- return false;
- }
- }
- }
-
- 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);
@@ -2147,91 +2119,6 @@ static void GenerateEqualLong(HCondition* cond, CodeGeneratorARMVIXL* codegen) {
}
}
-static void GenerateLongComparesAndJumps(HCondition* cond,
- vixl32::Label* true_label,
- vixl32::Label* false_label,
- CodeGeneratorARMVIXL* codegen,
- bool is_far_target = true) {
- 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, is_far_target);
- } else if (if_cond == kCondEQ) {
- __ B(ARMCondition(false_high_cond), false_label, is_far_target);
- } else {
- __ B(ARMCondition(true_high_cond), true_label, is_far_target);
- __ B(ARMCondition(false_high_cond), false_label, is_far_target);
- }
- // 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, is_far_target);
- } else if (if_cond == kCondEQ) {
- __ B(ARMCondition(false_high_cond), false_label, is_far_target);
- } else {
- __ B(ARMCondition(true_high_cond), true_label, is_far_target);
- __ B(ARMCondition(false_high_cond), false_label, is_far_target);
- }
- // 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, is_far_target);
-}
-
static void GenerateConditionLong(HCondition* cond, CodeGeneratorARMVIXL* codegen) {
DCHECK_EQ(cond->GetLeft()->GetType(), Primitive::kPrimLong);
@@ -2286,38 +2173,14 @@ static void GenerateConditionLong(HCondition* cond, CodeGeneratorARMVIXL* codege
}
}
- 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()))) {
+ // If `out` is a low register, then the GenerateConditionGeneric()
+ // function generates a shorter code sequence that is still branchless.
+ if ((condition == kCondEQ || condition == kCondNE) && !out.IsLow()) {
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, /* is_far_target */ false);
-
- // 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);
- }
+ GenerateConditionGeneric(cond, codegen);
}
static void GenerateConditionIntegralOrNonPrimitive(HCondition* cond,
@@ -2977,56 +2840,41 @@ void InstructionCodeGeneratorARMVIXL::VisitExit(HExit* exit ATTRIBUTE_UNUSED) {
}
void InstructionCodeGeneratorARMVIXL::GenerateCompareTestAndBranch(HCondition* condition,
- vixl32::Label* true_target_in,
- vixl32::Label* false_target_in,
+ vixl32::Label* true_target,
+ vixl32::Label* false_target,
bool is_far_target) {
- if (CanGenerateTest(condition, codegen_->GetAssembler())) {
- vixl32::Label* non_fallthrough_target;
- bool invert;
- bool emit_both_branches;
-
- if (true_target_in == nullptr) {
- // The true target is fallthrough.
- DCHECK(false_target_in != nullptr);
- non_fallthrough_target = false_target_in;
- invert = true;
- emit_both_branches = false;
- } else {
- non_fallthrough_target = true_target_in;
- invert = false;
- // Either the false target is fallthrough, or there is no fallthrough
- // and both branches must be emitted.
- emit_both_branches = (false_target_in != nullptr);
- }
-
- const auto cond = GenerateTest(condition, invert, codegen_);
-
- __ B(cond.first, non_fallthrough_target, is_far_target);
+ if (true_target == false_target) {
+ DCHECK(true_target != nullptr);
+ __ B(true_target);
+ return;
+ }
- if (emit_both_branches) {
- // No target falls through, we need to branch.
- __ B(false_target_in);
- }
+ vixl32::Label* non_fallthrough_target;
+ bool invert;
+ bool emit_both_branches;
- return;
+ if (true_target == nullptr) {
+ // The true target is fallthrough.
+ DCHECK(false_target != nullptr);
+ non_fallthrough_target = false_target;
+ invert = true;
+ emit_both_branches = false;
+ } else {
+ non_fallthrough_target = true_target;
+ invert = false;
+ // Either the false target is fallthrough, or there is no fallthrough
+ // and both branches must be emitted.
+ emit_both_branches = (false_target != nullptr);
}
- // Generated branching requires both targets to be explicit. If either of the
- // targets is nullptr (fallthrough) use and bind `fallthrough` instead.
- vixl32::Label fallthrough;
- vixl32::Label* true_target = (true_target_in == nullptr) ? &fallthrough : true_target_in;
- vixl32::Label* false_target = (false_target_in == nullptr) ? &fallthrough : false_target_in;
+ const auto cond = GenerateTest(condition, invert, codegen_);
- DCHECK_EQ(condition->InputAt(0)->GetType(), Primitive::kPrimLong);
- GenerateLongComparesAndJumps(condition, true_target, false_target, codegen_, is_far_target);
+ __ B(cond.first, non_fallthrough_target, is_far_target);
- if (false_target != &fallthrough) {
+ if (emit_both_branches) {
+ // No target falls through, we need to branch.
__ B(false_target);
}
-
- if (fallthrough.IsReferenced()) {
- __ Bind(&fallthrough);
- }
}
void InstructionCodeGeneratorARMVIXL::GenerateTestAndBranch(HInstruction* instruction,
@@ -3221,9 +3069,7 @@ void InstructionCodeGeneratorARMVIXL::VisitSelect(HSelect* select) {
return;
}
- if (!Primitive::IsFloatingPointType(type) &&
- (IsBooleanValueOrMaterializedCondition(condition) ||
- CanGenerateTest(condition->AsCondition(), codegen_->GetAssembler()))) {
+ if (!Primitive::IsFloatingPointType(type)) {
bool invert = false;
if (out.Equals(second)) {