diff options
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)); |