summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Anton Kirilov <anton.kirilov@linaro.org> 2016-05-13 17:56:15 +0100
committer Anton Kirilov <anton.kirilov@linaro.org> 2016-07-01 17:45:30 +0100
commite14dc86d4e84d52426510d0fafbac3d7e04f960c (patch)
tree7ec03801e3dd8d4a6f428239308f1f7700c815fc
parent1fdb340de4e608a88e8683c857cad5d0da2c16de (diff)
Simplification for associative and commutative operations on constants
The purpose of this change is to enable the instruction simplifier to recognize patterns such as OP y, x, const1 OP z, y, const2 where OP is both an associative and a commutative operation on integral types, and replace them with OP z, x, const3 Since subtraction on integral types is equivalent to addition with a negated operand, it receives a similar treatment, even though it is not commutative. Change-Id: I278cac39bd39bc843d250a976931cb000876ea88
-rw-r--r--compiler/optimizing/instruction_simplifier.cc199
-rw-r--r--test/458-checker-instruction-simplification/smali/SmaliTests.smali136
-rw-r--r--test/458-checker-instruction-simplification/src/Main.java122
3 files changed, 453 insertions, 4 deletions
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index 3041c4d2c7..e0410dcdb2 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -54,6 +54,9 @@ class InstructionSimplifierVisitor : public HGraphDelegateVisitor {
// De Morgan's laws:
// ~a & ~b = ~(a | b) and ~a | ~b = ~(a & b)
bool TryDeMorganNegationFactoring(HBinaryOperation* op);
+ bool TryHandleAssociativeAndCommutativeOperation(HBinaryOperation* instruction);
+ bool TrySubtractionChainSimplification(HBinaryOperation* instruction);
+
void VisitShift(HBinaryOperation* shift);
void VisitEqual(HEqual* equal) OVERRIDE;
@@ -963,7 +966,18 @@ void InstructionSimplifierVisitor::VisitAdd(HAdd* instruction) {
return;
}
- TryReplaceWithRotate(instruction);
+ if (TryReplaceWithRotate(instruction)) {
+ return;
+ }
+
+ // TryHandleAssociativeAndCommutativeOperation() does not remove its input,
+ // so no need to return.
+ TryHandleAssociativeAndCommutativeOperation(instruction);
+
+ if ((instruction->GetLeft()->IsSub() || instruction->GetRight()->IsSub()) &&
+ TrySubtractionChainSimplification(instruction)) {
+ return;
+ }
}
void InstructionSimplifierVisitor::VisitAnd(HAnd* instruction) {
@@ -1025,7 +1039,13 @@ void InstructionSimplifierVisitor::VisitAnd(HAnd* instruction) {
return;
}
- TryDeMorganNegationFactoring(instruction);
+ if (TryDeMorganNegationFactoring(instruction)) {
+ return;
+ }
+
+ // TryHandleAssociativeAndCommutativeOperation() does not remove its input,
+ // so no need to return.
+ TryHandleAssociativeAndCommutativeOperation(instruction);
}
void InstructionSimplifierVisitor::VisitGreaterThan(HGreaterThan* condition) {
@@ -1242,6 +1262,7 @@ void InstructionSimplifierVisitor::VisitMul(HMul* instruction) {
instruction->ReplaceWith(input_cst);
instruction->GetBlock()->RemoveInstruction(instruction);
RecordSimplification();
+ return;
} else if (IsPowerOfTwo(factor)) {
// Replace code looking like
// MUL dst, src, pow_of_2
@@ -1251,6 +1272,7 @@ void InstructionSimplifierVisitor::VisitMul(HMul* instruction) {
HShl* shl = new (allocator) HShl(type, input_other, shift);
block->ReplaceAndRemoveInstructionWith(instruction, shl);
RecordSimplification();
+ return;
} else if (IsPowerOfTwo(factor - 1)) {
// Transform code looking like
// MUL dst, src, (2^n + 1)
@@ -1265,6 +1287,7 @@ void InstructionSimplifierVisitor::VisitMul(HMul* instruction) {
block->InsertInstructionBefore(shl, instruction);
block->ReplaceAndRemoveInstructionWith(instruction, add);
RecordSimplification();
+ return;
} else if (IsPowerOfTwo(factor + 1)) {
// Transform code looking like
// MUL dst, src, (2^n - 1)
@@ -1279,8 +1302,13 @@ void InstructionSimplifierVisitor::VisitMul(HMul* instruction) {
block->InsertInstructionBefore(shl, instruction);
block->ReplaceAndRemoveInstructionWith(instruction, sub);
RecordSimplification();
+ return;
}
}
+
+ // TryHandleAssociativeAndCommutativeOperation() does not remove its input,
+ // so no need to return.
+ TryHandleAssociativeAndCommutativeOperation(instruction);
}
void InstructionSimplifierVisitor::VisitNeg(HNeg* instruction) {
@@ -1380,7 +1408,13 @@ void InstructionSimplifierVisitor::VisitOr(HOr* instruction) {
if (TryDeMorganNegationFactoring(instruction)) return;
- TryReplaceWithRotate(instruction);
+ if (TryReplaceWithRotate(instruction)) {
+ return;
+ }
+
+ // TryHandleAssociativeAndCommutativeOperation() does not remove its input,
+ // so no need to return.
+ TryHandleAssociativeAndCommutativeOperation(instruction);
}
void InstructionSimplifierVisitor::VisitShl(HShl* instruction) {
@@ -1471,6 +1505,11 @@ void InstructionSimplifierVisitor::VisitSub(HSub* instruction) {
instruction->GetBlock()->RemoveInstruction(instruction);
RecordSimplification();
left->GetBlock()->RemoveInstruction(left);
+ return;
+ }
+
+ if (TrySubtractionChainSimplification(instruction)) {
+ return;
}
}
@@ -1524,7 +1563,13 @@ void InstructionSimplifierVisitor::VisitXor(HXor* instruction) {
return;
}
- TryReplaceWithRotate(instruction);
+ if (TryReplaceWithRotate(instruction)) {
+ return;
+ }
+
+ // TryHandleAssociativeAndCommutativeOperation() does not remove its input,
+ // so no need to return.
+ TryHandleAssociativeAndCommutativeOperation(instruction);
}
void InstructionSimplifierVisitor::SimplifyStringEquals(HInvoke* instruction) {
@@ -1823,4 +1868,150 @@ void InstructionSimplifierVisitor::VisitDeoptimize(HDeoptimize* deoptimize) {
}
}
+// Replace code looking like
+// OP y, x, const1
+// OP z, y, const2
+// with
+// OP z, x, const3
+// where OP is both an associative and a commutative operation.
+bool InstructionSimplifierVisitor::TryHandleAssociativeAndCommutativeOperation(
+ HBinaryOperation* instruction) {
+ DCHECK(instruction->IsCommutative());
+
+ if (!Primitive::IsIntegralType(instruction->GetType())) {
+ return false;
+ }
+
+ HInstruction* left = instruction->GetLeft();
+ HInstruction* right = instruction->GetRight();
+ // Variable names as described above.
+ HConstant* const2;
+ HBinaryOperation* y;
+
+ if (instruction->InstructionTypeEquals(left) && right->IsConstant()) {
+ const2 = right->AsConstant();
+ y = left->AsBinaryOperation();
+ } else if (left->IsConstant() && instruction->InstructionTypeEquals(right)) {
+ const2 = left->AsConstant();
+ y = right->AsBinaryOperation();
+ } else {
+ // The node does not match the pattern.
+ return false;
+ }
+
+ // If `y` has more than one use, we do not perform the optimization
+ // because it might increase code size (e.g. if the new constant is
+ // no longer encodable as an immediate operand in the target ISA).
+ if (!y->HasOnlyOneNonEnvironmentUse()) {
+ return false;
+ }
+
+ // GetConstantRight() can return both left and right constants
+ // for commutative operations.
+ HConstant* const1 = y->GetConstantRight();
+ if (const1 == nullptr) {
+ return false;
+ }
+
+ instruction->ReplaceInput(const1, 0);
+ instruction->ReplaceInput(const2, 1);
+ HConstant* const3 = instruction->TryStaticEvaluation();
+ DCHECK(const3 != nullptr);
+ instruction->ReplaceInput(y->GetLeastConstantLeft(), 0);
+ instruction->ReplaceInput(const3, 1);
+ RecordSimplification();
+ return true;
+}
+
+static HBinaryOperation* AsAddOrSub(HInstruction* binop) {
+ return (binop->IsAdd() || binop->IsSub()) ? binop->AsBinaryOperation() : nullptr;
+}
+
+// Helper function that performs addition statically, considering the result type.
+static int64_t ComputeAddition(Primitive::Type type, int64_t x, int64_t y) {
+ // Use the Compute() method for consistency with TryStaticEvaluation().
+ if (type == Primitive::kPrimInt) {
+ return HAdd::Compute<int32_t>(x, y);
+ } else {
+ DCHECK_EQ(type, Primitive::kPrimLong);
+ return HAdd::Compute<int64_t>(x, y);
+ }
+}
+
+// Helper function that handles the child classes of HConstant
+// and returns an integer with the appropriate sign.
+static int64_t GetValue(HConstant* constant, bool is_negated) {
+ int64_t ret = Int64FromConstant(constant);
+ return is_negated ? -ret : ret;
+}
+
+// Replace code looking like
+// OP1 y, x, const1
+// OP2 z, y, const2
+// with
+// OP3 z, x, const3
+// where OPx is either ADD or SUB, and at least one of OP{1,2} is SUB.
+bool InstructionSimplifierVisitor::TrySubtractionChainSimplification(
+ HBinaryOperation* instruction) {
+ DCHECK(instruction->IsAdd() || instruction->IsSub()) << instruction->DebugName();
+
+ Primitive::Type type = instruction->GetType();
+ if (!Primitive::IsIntegralType(type)) {
+ return false;
+ }
+
+ HInstruction* left = instruction->GetLeft();
+ HInstruction* right = instruction->GetRight();
+ // Variable names as described above.
+ HConstant* const2 = right->IsConstant() ? right->AsConstant() : left->AsConstant();
+ if (const2 == nullptr) {
+ return false;
+ }
+
+ HBinaryOperation* y = (AsAddOrSub(left) != nullptr)
+ ? left->AsBinaryOperation()
+ : AsAddOrSub(right);
+ // If y has more than one use, we do not perform the optimization because
+ // it might increase code size (e.g. if the new constant is no longer
+ // encodable as an immediate operand in the target ISA).
+ if ((y == nullptr) || !y->HasOnlyOneNonEnvironmentUse()) {
+ return false;
+ }
+
+ left = y->GetLeft();
+ HConstant* const1 = left->IsConstant() ? left->AsConstant() : y->GetRight()->AsConstant();
+ if (const1 == nullptr) {
+ return false;
+ }
+
+ HInstruction* x = (const1 == left) ? y->GetRight() : left;
+ // If both inputs are constants, let the constant folding pass deal with it.
+ if (x->IsConstant()) {
+ return false;
+ }
+
+ bool is_const2_negated = (const2 == right) && instruction->IsSub();
+ int64_t const2_val = GetValue(const2, is_const2_negated);
+ bool is_y_negated = (y == right) && instruction->IsSub();
+ right = y->GetRight();
+ bool is_const1_negated = is_y_negated ^ ((const1 == right) && y->IsSub());
+ int64_t const1_val = GetValue(const1, is_const1_negated);
+ bool is_x_negated = is_y_negated ^ ((x == right) && y->IsSub());
+ int64_t const3_val = ComputeAddition(type, const1_val, const2_val);
+ HBasicBlock* block = instruction->GetBlock();
+ HConstant* const3 = block->GetGraph()->GetConstant(type, const3_val);
+ ArenaAllocator* arena = instruction->GetArena();
+ HInstruction* z;
+
+ if (is_x_negated) {
+ z = new (arena) HSub(type, const3, x, instruction->GetDexPc());
+ } else {
+ z = new (arena) HAdd(type, x, const3, instruction->GetDexPc());
+ }
+
+ block->ReplaceAndRemoveInstructionWith(instruction, z);
+ RecordSimplification();
+ return true;
+}
+
} // namespace art
diff --git a/test/458-checker-instruction-simplification/smali/SmaliTests.smali b/test/458-checker-instruction-simplification/smali/SmaliTests.smali
index ede599b213..6845961f39 100644
--- a/test/458-checker-instruction-simplification/smali/SmaliTests.smali
+++ b/test/458-checker-instruction-simplification/smali/SmaliTests.smali
@@ -191,3 +191,139 @@
.end method
+## CHECK-START: int SmaliTests.AddSubConst(int) instruction_simplifier (before)
+## CHECK-DAG: <<ArgValue:i\d+>> ParameterValue
+## CHECK-DAG: <<Const7:i\d+>> IntConstant 7
+## CHECK-DAG: <<Const8:i\d+>> IntConstant 8
+## CHECK-DAG: <<Add:i\d+>> Add [<<ArgValue>>,<<Const7>>]
+## CHECK-DAG: <<Sub:i\d+>> Sub [<<Add>>,<<Const8>>]
+## CHECK-DAG: Return [<<Sub>>]
+
+## CHECK-START: int SmaliTests.AddSubConst(int) instruction_simplifier (after)
+## CHECK-DAG: <<ArgValue:i\d+>> ParameterValue
+## CHECK-DAG: <<ConstM1:i\d+>> IntConstant -1
+## CHECK-DAG: <<Add:i\d+>> Add [<<ArgValue>>,<<ConstM1>>]
+## CHECK-DAG: Return [<<Add>>]
+
+.method public static AddSubConst(I)I
+ .registers 3
+
+ .prologue
+ add-int/lit8 v0, p0, 7
+
+ const/16 v1, 8
+
+ sub-int v0, v0, v1
+
+ return v0
+.end method
+
+## CHECK-START: int SmaliTests.SubAddConst(int) instruction_simplifier (before)
+## CHECK-DAG: <<ArgValue:i\d+>> ParameterValue
+## CHECK-DAG: <<Const3:i\d+>> IntConstant 3
+## CHECK-DAG: <<Const4:i\d+>> IntConstant 4
+## CHECK-DAG: <<Sub:i\d+>> Sub [<<ArgValue>>,<<Const3>>]
+## CHECK-DAG: <<Add:i\d+>> Add [<<Sub>>,<<Const4>>]
+## CHECK-DAG: Return [<<Add>>]
+
+## CHECK-START: int SmaliTests.SubAddConst(int) instruction_simplifier (after)
+## CHECK-DAG: <<ArgValue:i\d+>> ParameterValue
+## CHECK-DAG: <<Const1:i\d+>> IntConstant 1
+## CHECK-DAG: <<Add:i\d+>> Add [<<ArgValue>>,<<Const1>>]
+## CHECK-DAG: Return [<<Add>>]
+
+.method public static SubAddConst(I)I
+ .registers 2
+
+ .prologue
+ const/4 v0, 3
+
+ sub-int v0, p0, v0
+
+ add-int/lit8 v0, v0, 4
+
+ return v0
+.end method
+
+## CHECK-START: int SmaliTests.SubSubConst1(int) instruction_simplifier (before)
+## CHECK-DAG: <<ArgValue:i\d+>> ParameterValue
+## CHECK-DAG: <<Const9:i\d+>> IntConstant 9
+## CHECK-DAG: <<Const10:i\d+>> IntConstant 10
+## CHECK-DAG: <<Sub1:i\d+>> Sub [<<ArgValue>>,<<Const9>>]
+## CHECK-DAG: <<Sub2:i\d+>> Sub [<<Sub1>>,<<Const10>>]
+## CHECK-DAG: Return [<<Sub2>>]
+
+## CHECK-START: int SmaliTests.SubSubConst1(int) instruction_simplifier (after)
+## CHECK-DAG: <<ArgValue:i\d+>> ParameterValue
+## CHECK-DAG: <<ConstM19:i\d+>> IntConstant -19
+## CHECK-DAG: <<Add:i\d+>> Add [<<ArgValue>>,<<ConstM19>>]
+## CHECK-DAG: Return [<<Add>>]
+
+.method public static SubSubConst1(I)I
+ .registers 3
+
+ .prologue
+ const/16 v1, 9
+
+ sub-int v0, p0, v1
+
+ const/16 v1, 10
+
+ sub-int v0, v0, v1
+
+ return v0
+.end method
+
+## CHECK-START: int SmaliTests.SubSubConst2(int) instruction_simplifier (before)
+## CHECK-DAG: <<ArgValue:i\d+>> ParameterValue
+## CHECK-DAG: <<Const11:i\d+>> IntConstant 11
+## CHECK-DAG: <<Const12:i\d+>> IntConstant 12
+## CHECK-DAG: <<Sub1:i\d+>> Sub [<<Const11>>,<<ArgValue>>]
+## CHECK-DAG: <<Sub2:i\d+>> Sub [<<Sub1>>,<<Const12>>]
+## CHECK-DAG: Return [<<Sub2>>]
+
+## CHECK-START: int SmaliTests.SubSubConst2(int) instruction_simplifier (after)
+## CHECK-DAG: <<ArgValue:i\d+>> ParameterValue
+## CHECK-DAG: <<ConstM1:i\d+>> IntConstant -1
+## CHECK-DAG: <<Sub:i\d+>> Sub [<<ConstM1>>,<<ArgValue>>]
+## CHECK-DAG: Return [<<Sub>>]
+
+.method public static SubSubConst2(I)I
+ .registers 3
+
+ .prologue
+ rsub-int/lit8 v0, p0, 11
+
+ const/16 v1, 12
+
+ sub-int v0, v0, v1
+
+ return v0
+.end method
+
+## CHECK-START: int SmaliTests.SubSubConst3(int) instruction_simplifier (before)
+## CHECK-DAG: <<ArgValue:i\d+>> ParameterValue
+## CHECK-DAG: <<Const15:i\d+>> IntConstant 15
+## CHECK-DAG: <<Const16:i\d+>> IntConstant 16
+## CHECK-DAG: <<Sub1:i\d+>> Sub [<<ArgValue>>,<<Const16>>]
+## CHECK-DAG: <<Sub2:i\d+>> Sub [<<Const15>>,<<Sub1>>]
+## CHECK-DAG: Return [<<Sub2>>]
+
+## CHECK-START: int SmaliTests.SubSubConst3(int) instruction_simplifier (after)
+## CHECK-DAG: <<ArgValue:i\d+>> ParameterValue
+## CHECK-DAG: <<Const31:i\d+>> IntConstant 31
+## CHECK-DAG: <<Sub:i\d+>> Sub [<<Const31>>,<<ArgValue>>]
+## CHECK-DAG: Return [<<Sub>>]
+
+.method public static SubSubConst3(I)I
+ .registers 2
+
+ .prologue
+ const/16 v0, 16
+
+ sub-int v0, p0, v0
+
+ rsub-int/lit8 v0, v0, 15
+
+ return v0
+.end method
diff --git a/test/458-checker-instruction-simplification/src/Main.java b/test/458-checker-instruction-simplification/src/Main.java
index ffce49d2e1..c717eaa85e 100644
--- a/test/458-checker-instruction-simplification/src/Main.java
+++ b/test/458-checker-instruction-simplification/src/Main.java
@@ -78,6 +78,29 @@ public class Main {
return 0 + arg;
}
+ /// CHECK-START: int Main.$noinline$AddAddSubAddConst(int) instruction_simplifier (before)
+ /// CHECK-DAG: <<ArgValue:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
+ /// CHECK-DAG: <<Const2:i\d+>> IntConstant 2
+ /// CHECK-DAG: <<ConstM3:i\d+>> IntConstant -3
+ /// CHECK-DAG: <<Const4:i\d+>> IntConstant 4
+ /// CHECK-DAG: <<Add1:i\d+>> Add [<<ArgValue>>,<<Const1>>]
+ /// CHECK-DAG: <<Add2:i\d+>> Add [<<Add1>>,<<Const2>>]
+ /// CHECK-DAG: <<Add3:i\d+>> Add [<<Add2>>,<<ConstM3>>]
+ /// CHECK-DAG: <<Add4:i\d+>> Add [<<Add3>>,<<Const4>>]
+ /// CHECK-DAG: Return [<<Add4>>]
+
+ /// CHECK-START: int Main.$noinline$AddAddSubAddConst(int) instruction_simplifier (after)
+ /// CHECK-DAG: <<ArgValue:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Const4:i\d+>> IntConstant 4
+ /// CHECK-DAG: <<Add:i\d+>> Add [<<ArgValue>>,<<Const4>>]
+ /// CHECK-DAG: Return [<<Add>>]
+
+ public static int $noinline$AddAddSubAddConst(int arg) {
+ if (doThrow) { throw new Error(); }
+ return arg + 1 + 2 - 3 + 4;
+ }
+
/// CHECK-START: int Main.$noinline$AndAllOnes(int) instruction_simplifier (before)
/// CHECK-DAG: <<Arg:i\d+>> ParameterValue
/// CHECK-DAG: <<ConstF:i\d+>> IntConstant -1
@@ -364,6 +387,27 @@ public class Main {
return arg * 128;
}
+ /// CHECK-START: long Main.$noinline$MulMulMulConst(long) instruction_simplifier (before)
+ /// CHECK-DAG: <<ArgValue:j\d+>> ParameterValue
+ /// CHECK-DAG: <<Const10:j\d+>> LongConstant 10
+ /// CHECK-DAG: <<Const11:j\d+>> LongConstant 11
+ /// CHECK-DAG: <<Const12:j\d+>> LongConstant 12
+ /// CHECK-DAG: <<Mul1:j\d+>> Mul [<<Const10>>,<<ArgValue>>]
+ /// CHECK-DAG: <<Mul2:j\d+>> Mul [<<Mul1>>,<<Const11>>]
+ /// CHECK-DAG: <<Mul3:j\d+>> Mul [<<Mul2>>,<<Const12>>]
+ /// CHECK-DAG: Return [<<Mul3>>]
+
+ /// CHECK-START: long Main.$noinline$MulMulMulConst(long) instruction_simplifier (after)
+ /// CHECK-DAG: <<ArgValue:j\d+>> ParameterValue
+ /// CHECK-DAG: <<Const1320:j\d+>> LongConstant 1320
+ /// CHECK-DAG: <<Mul:j\d+>> Mul [<<ArgValue>>,<<Const1320>>]
+ /// CHECK-DAG: Return [<<Mul>>]
+
+ public static long $noinline$MulMulMulConst(long arg) {
+ if (doThrow) { throw new Error(); }
+ return 10 * arg * 11 * 12;
+ }
+
/// CHECK-START: int Main.$noinline$Or0(int) instruction_simplifier (before)
/// CHECK-DAG: <<Arg:i\d+>> ParameterValue
/// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
@@ -490,6 +534,63 @@ public class Main {
return 0 - arg;
}
+ /// CHECK-START: int Main.$noinline$SubAddConst1(int) instruction_simplifier (before)
+ /// CHECK-DAG: <<ArgValue:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Const5:i\d+>> IntConstant 5
+ /// CHECK-DAG: <<Const6:i\d+>> IntConstant 6
+ /// CHECK-DAG: <<Sub:i\d+>> Sub [<<Const5>>,<<ArgValue>>]
+ /// CHECK-DAG: <<Add:i\d+>> Add [<<Sub>>,<<Const6>>]
+ /// CHECK-DAG: Return [<<Add>>]
+
+ /// CHECK-START: int Main.$noinline$SubAddConst1(int) instruction_simplifier (after)
+ /// CHECK-DAG: <<ArgValue:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Const11:i\d+>> IntConstant 11
+ /// CHECK-DAG: <<Sub:i\d+>> Sub [<<Const11>>,<<ArgValue>>]
+ /// CHECK-DAG: Return [<<Sub>>]
+
+ public static int $noinline$SubAddConst1(int arg) {
+ if (doThrow) { throw new Error(); }
+ return 5 - arg + 6;
+ }
+
+ /// CHECK-START: int Main.$noinline$SubAddConst2(int) instruction_simplifier (before)
+ /// CHECK-DAG: <<ArgValue:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Const14:i\d+>> IntConstant 14
+ /// CHECK-DAG: <<Const13:i\d+>> IntConstant 13
+ /// CHECK-DAG: <<Add:i\d+>> Add [<<ArgValue>>,<<Const13>>]
+ /// CHECK-DAG: <<Sub:i\d+>> Sub [<<Const14>>,<<Add>>]
+ /// CHECK-DAG: Return [<<Sub>>]
+
+ /// CHECK-START: int Main.$noinline$SubAddConst2(int) instruction_simplifier (after)
+ /// CHECK-DAG: <<ArgValue:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
+ /// CHECK-DAG: <<Sub:i\d+>> Sub [<<Const1>>,<<ArgValue>>]
+ /// CHECK-DAG: Return [<<Sub>>]
+
+ public static int $noinline$SubAddConst2(int arg) {
+ if (doThrow) { throw new Error(); }
+ return 14 - (arg + 13);
+ }
+
+ /// CHECK-START: long Main.$noinline$SubSubConst(long) instruction_simplifier (before)
+ /// CHECK-DAG: <<ArgValue:j\d+>> ParameterValue
+ /// CHECK-DAG: <<Const17:j\d+>> LongConstant 17
+ /// CHECK-DAG: <<Const18:j\d+>> LongConstant 18
+ /// CHECK-DAG: <<Sub1:j\d+>> Sub [<<Const18>>,<<ArgValue>>]
+ /// CHECK-DAG: <<Sub2:j\d+>> Sub [<<Const17>>,<<Sub1>>]
+ /// CHECK-DAG: Return [<<Sub2>>]
+
+ /// CHECK-START: long Main.$noinline$SubSubConst(long) instruction_simplifier (after)
+ /// CHECK-DAG: <<ArgValue:j\d+>> ParameterValue
+ /// CHECK-DAG: <<ConstM1:j\d+>> LongConstant -1
+ /// CHECK-DAG: <<Add:j\d+>> Add [<<ArgValue>>,<<ConstM1>>]
+ /// CHECK-DAG: Return [<<Add>>]
+
+ public static long $noinline$SubSubConst(long arg) {
+ if (doThrow) { throw new Error(); }
+ return 17 - (18 - arg);
+ }
+
/// CHECK-START: long Main.$noinline$UShr0(long) instruction_simplifier (before)
/// CHECK-DAG: <<Arg:j\d+>> ParameterValue
/// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
@@ -1757,6 +1858,17 @@ public class Main {
}
}
+ public static int $noinline$runSmaliTestConst(String name, int arg) {
+ if (doThrow) { throw new Error(); }
+ try {
+ Class<?> c = Class.forName("SmaliTests");
+ Method m = c.getMethod(name, int.class);
+ return (Integer) m.invoke(null, arg);
+ } catch (Exception ex) {
+ throw new Error(ex);
+ }
+ }
+
/// CHECK-START: int Main.$noinline$intUnnecessaryShiftMasking(int, int) instruction_simplifier (before)
/// CHECK: <<Value:i\d+>> ParameterValue
/// CHECK: <<Shift:i\d+>> ParameterValue
@@ -1863,12 +1975,14 @@ public static void main(String[] args) {
int arg = 123456;
assertLongEquals(arg, $noinline$Add0(arg));
+ assertIntEquals(5, $noinline$AddAddSubAddConst(1));
assertIntEquals(arg, $noinline$AndAllOnes(arg));
assertLongEquals(arg, $noinline$Div1(arg));
assertIntEquals(-arg, $noinline$DivN1(arg));
assertLongEquals(arg, $noinline$Mul1(arg));
assertIntEquals(-arg, $noinline$MulN1(arg));
assertLongEquals((128 * arg), $noinline$MulPowerOfTwo128(arg));
+ assertLongEquals(2640, $noinline$MulMulMulConst(2));
assertIntEquals(arg, $noinline$Or0(arg));
assertLongEquals(arg, $noinline$OrSame(arg));
assertIntEquals(arg, $noinline$Shl0(arg));
@@ -1876,6 +1990,9 @@ public static void main(String[] args) {
assertLongEquals(arg, $noinline$Shr64(arg));
assertLongEquals(arg, $noinline$Sub0(arg));
assertIntEquals(-arg, $noinline$SubAliasNeg(arg));
+ assertIntEquals(9, $noinline$SubAddConst1(2));
+ assertIntEquals(-2, $noinline$SubAddConst2(3));
+ assertLongEquals(3, $noinline$SubSubConst(4));
assertLongEquals(arg, $noinline$UShr0(arg));
assertIntEquals(arg, $noinline$Xor0(arg));
assertIntEquals(~arg, $noinline$XorAllOnes(arg));
@@ -2011,6 +2128,11 @@ public static void main(String[] args) {
}
}
+ assertIntEquals(0, $noinline$runSmaliTestConst("AddSubConst", 1));
+ assertIntEquals(3, $noinline$runSmaliTestConst("SubAddConst", 2));
+ assertIntEquals(-16, $noinline$runSmaliTestConst("SubSubConst1", 3));
+ assertIntEquals(-5, $noinline$runSmaliTestConst("SubSubConst2", 4));
+ assertIntEquals(26, $noinline$runSmaliTestConst("SubSubConst3", 5));
assertIntEquals(0x5e6f7808, $noinline$intUnnecessaryShiftMasking(0xabcdef01, 3));
assertIntEquals(0x5e6f7808, $noinline$intUnnecessaryShiftMasking(0xabcdef01, 3 + 32));
assertLongEquals(0xffffffffffffeaf3L, $noinline$longUnnecessaryShiftMasking(0xabcdef0123456789L, 50));