// 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;
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) {
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) {
instruction->ReplaceWith(input_cst);
instruction->GetBlock()->RemoveInstruction(instruction);
RecordSimplification();
+ return;
} else if (IsPowerOfTwo(factor)) {
// Replace code looking like
// MUL dst, src, pow_of_2
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)
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)
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) {
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) {
instruction->GetBlock()->RemoveInstruction(instruction);
RecordSimplification();
left->GetBlock()->RemoveInstruction(left);
+ return;
+ }
+
+ if (TrySubtractionChainSimplification(instruction)) {
+ return;
}
}
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) {
}
}
+// 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
.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
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
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
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
}
}
+ 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
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));
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));
}
}
+ 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));