Recognize ABS cases.
Rationale:
enables more optimizations on ABS, such as SIMDization
Background:
this is a breakout CL for SAD
Bug: 64091002
Test: test-art-host test-art-target
Change-Id: I4551c66114a04d51e4140ff222722fdd52ea6e63
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index f2a829f..337177f 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -813,6 +813,57 @@
}
}
+// Constructs a new ABS(x) node in the HIR.
+static HInstruction* NewIntegralAbs(ArenaAllocator* arena, HInstruction* x, HInstruction* cursor) {
+ Primitive::Type type = x->GetType();
+ DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong);
+ // Construct a fake intrinsic with as much context as is needed to allocate one.
+ // The intrinsic will always be lowered into code later anyway.
+ // TODO: b/65164101 : moving towards a real HAbs node makes more sense.
+ HInvokeStaticOrDirect::DispatchInfo dispatch_info = {
+ HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress,
+ HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod,
+ 0u
+ };
+ HInvokeStaticOrDirect* invoke = new (arena) HInvokeStaticOrDirect(
+ arena,
+ 1,
+ type,
+ x->GetDexPc(),
+ /*method_idx*/ -1,
+ /*resolved_method*/ nullptr,
+ dispatch_info,
+ kStatic,
+ MethodReference(nullptr, dex::kDexNoIndex),
+ HInvokeStaticOrDirect::ClinitCheckRequirement::kNone);
+ invoke->SetArgumentAt(0, x);
+ invoke->SetIntrinsic(type == Primitive::kPrimInt ? Intrinsics::kMathAbsInt
+ : Intrinsics::kMathAbsLong,
+ kNoEnvironmentOrCache,
+ kNoSideEffects,
+ kNoThrow);
+ cursor->GetBlock()->InsertInstructionBefore(invoke, cursor);
+ return invoke;
+}
+
+// Returns true if operands a and b consists of widening type conversions
+// (either explicit or implicit) to the given to_type.
+static bool AreLowerPrecisionArgs(Primitive::Type to_type, HInstruction* a, HInstruction* b) {
+ if (a->IsTypeConversion() && a->GetType() == to_type) {
+ a = a->InputAt(0);
+ }
+ if (b->IsTypeConversion() && b->GetType() == to_type) {
+ b = b->InputAt(0);
+ }
+ Primitive::Type type1 = a->GetType();
+ Primitive::Type type2 = b->GetType();
+ return (type1 == Primitive::kPrimByte && type2 == Primitive::kPrimByte) ||
+ (type1 == Primitive::kPrimShort && type2 == Primitive::kPrimShort) ||
+ (type1 == Primitive::kPrimChar && type2 == Primitive::kPrimChar) ||
+ (type1 == Primitive::kPrimInt && type2 == Primitive::kPrimInt &&
+ to_type == Primitive::kPrimLong);
+}
+
void InstructionSimplifierVisitor::VisitSelect(HSelect* select) {
HInstruction* replace_with = nullptr;
HInstruction* condition = select->GetCondition();
@@ -849,6 +900,47 @@
// Replace (cond ? false : true) with (!cond).
replace_with = GetGraph()->InsertOppositeCondition(condition, select);
}
+ } else if (condition->IsCondition()) {
+ IfCondition cmp = condition->AsCondition()->GetCondition();
+ HInstruction* a = condition->InputAt(0);
+ HInstruction* b = condition->InputAt(1);
+ Primitive::Type t_type = true_value->GetType();
+ Primitive::Type f_type = false_value->GetType();
+ // Here we have a <cmp> b ? true_value : false_value.
+ // Test if both values are same-typed int or long.
+ if (t_type == f_type && (t_type == Primitive::kPrimInt || t_type == Primitive::kPrimLong)) {
+ // Try to replace typical integral ABS constructs.
+ if (true_value->IsNeg()) {
+ HInstruction* negated = true_value->InputAt(0);
+ if ((cmp == kCondLT || cmp == kCondLE) &&
+ (a == negated && a == false_value && IsInt64Value(b, 0))) {
+ // Found a < 0 ? -a : a which can be replaced by ABS(a).
+ replace_with = NewIntegralAbs(GetGraph()->GetArena(), false_value, select);
+ }
+ } else if (false_value->IsNeg()) {
+ HInstruction* negated = false_value->InputAt(0);
+ if ((cmp == kCondGT || cmp == kCondGE) &&
+ (a == true_value && a == negated && IsInt64Value(b, 0))) {
+ // Found a > 0 ? a : -a which can be replaced by ABS(a).
+ replace_with = NewIntegralAbs(GetGraph()->GetArena(), true_value, select);
+ }
+ } else if (true_value->IsSub() && false_value->IsSub()) {
+ HInstruction* true_sub1 = true_value->InputAt(0);
+ HInstruction* true_sub2 = true_value->InputAt(1);
+ HInstruction* false_sub1 = false_value->InputAt(0);
+ HInstruction* false_sub2 = false_value->InputAt(1);
+ if ((((cmp == kCondGT || cmp == kCondGE) &&
+ (a == true_sub1 && b == true_sub2 && a == false_sub2 && b == false_sub1)) ||
+ ((cmp == kCondLT || cmp == kCondLE) &&
+ (a == true_sub2 && b == true_sub1 && a == false_sub1 && b == false_sub2))) &&
+ AreLowerPrecisionArgs(t_type, a, b)) {
+ // Found a > b ? a - b : b - a or
+ // a < b ? b - a : a - b
+ // which can be replaced by ABS(a - b) for lower precision operands a, b.
+ replace_with = NewIntegralAbs(GetGraph()->GetArena(), true_value, select);
+ }
+ }
+ }
}
if (replace_with != nullptr) {