summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/optimizing/data_type.h21
-rw-r--r--compiler/optimizing/instruction_simplifier.cc106
-rw-r--r--test/458-checker-instruct-simplification/src/Main.java634
3 files changed, 761 insertions, 0 deletions
diff --git a/compiler/optimizing/data_type.h b/compiler/optimizing/data_type.h
index b6d9519150..40d5e56d08 100644
--- a/compiler/optimizing/data_type.h
+++ b/compiler/optimizing/data_type.h
@@ -101,6 +101,27 @@ class DataType {
}
}
+ static constexpr Type SignedIntegralTypeFromSize(size_t size) {
+ switch (size) {
+ case 0:
+ case 1:
+ return Type::kInt8;
+ case 2:
+ return Type::kInt16;
+ case 3:
+ case 4:
+ return Type::kInt32;
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ return Type::kInt64;
+ default:
+ LOG(FATAL) << "Invalid size " << size;
+ UNREACHABLE();
+ }
+ }
+
static bool IsFloatingPointType(Type type) {
return type == Type::kFloat32 || type == Type::kFloat64;
}
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index 5d552411db..5db8235e29 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -363,6 +363,107 @@ bool InstructionSimplifierVisitor::TryCombineVecMultiplyAccumulate(HVecMul* mul)
return true;
}
+// Replace code looking like (x << N >>> N or x << N >> N):
+// SHL tmp, x, N
+// USHR/SHR dst, tmp, N
+// with the corresponding type conversion:
+// TypeConversion<Unsigned<T>/Signed<T>> dst, x
+// if
+// SHL has only one non environment use
+// TypeOf(tmp) is not 64-bit type (they are not supported yet)
+// N % kBitsPerByte = 0
+// where
+// T = SignedIntegralTypeFromSize(source_integral_size)
+// source_integral_size = ByteSize(tmp) - N / kBitsPerByte
+//
+// We calculate source_integral_size from shift amount instead of
+// assuming that it is equal to ByteSize(x) to be able to optimize
+// cases like this:
+// int x = ...
+// int y = x << 24 >>> 24
+// that is equavalent to
+// int y = (unsigned byte) x
+// in this case:
+// N = 24
+// tmp = x << 24
+// source_integral_size is 1 (= 4 - 24 / 8) that corresponds to unsigned byte.
+static bool TryReplaceShiftsByConstantWithTypeConversion(HBinaryOperation *instruction) {
+ if (!instruction->IsUShr() && !instruction->IsShr()) {
+ return false;
+ }
+
+ if (DataType::Is64BitType(instruction->GetResultType())) {
+ return false;
+ }
+
+ HInstruction* shr_amount = instruction->GetRight();
+ if (!shr_amount->IsIntConstant()) {
+ return false;
+ }
+
+ int32_t shr_amount_cst = shr_amount->AsIntConstant()->GetValue();
+
+ // We assume that shift amount simplification was applied first so it doesn't
+ // exceed maximum distance that is kMaxIntShiftDistance as 64-bit shifts aren't
+ // supported.
+ DCHECK_LE(shr_amount_cst, kMaxIntShiftDistance);
+
+ if ((shr_amount_cst % kBitsPerByte) != 0) {
+ return false;
+ }
+
+ // Calculate size of the significant part of the input, e.g. a part that is not
+ // discarded due to left shift.
+ // Shift amount here should be less than size of right shift type.
+ DCHECK_GT(DataType::Size(instruction->GetType()), shr_amount_cst / kBitsPerByte);
+ size_t source_significant_part_size =
+ DataType::Size(instruction->GetType()) - shr_amount_cst / kBitsPerByte;
+
+ // Look for the smallest signed integer type that is suitable to store the
+ // significant part of the input.
+ DataType::Type source_integral_type =
+ DataType::SignedIntegralTypeFromSize(source_significant_part_size);
+
+ // If the size of the significant part of the input isn't equal to the size of the
+ // found type, shifts cannot be replaced by type conversion.
+ if (DataType::Size(source_integral_type) != source_significant_part_size) {
+ return false;
+ }
+
+ HInstruction* shr_value = instruction->GetLeft();
+ if (!shr_value->IsShl()) {
+ return false;
+ }
+
+ HShl *shl = shr_value->AsShl();
+ if (!shl->HasOnlyOneNonEnvironmentUse()) {
+ return false;
+ }
+
+ // Constants are unique so we just compare pointer here.
+ if (shl->GetRight() != shr_amount) {
+ return false;
+ }
+
+ // Type of shift's value is always int so sign/zero extension only
+ // depends on the type of the shift (shr/ushr).
+ bool is_signed = instruction->IsShr();
+ DataType::Type conv_type =
+ is_signed ? source_integral_type : DataType::ToUnsigned(source_integral_type);
+ HInstruction* shl_value = shl->GetLeft();
+ HBasicBlock *block = instruction->GetBlock();
+
+ HTypeConversion* new_conversion =
+ new (block->GetGraph()->GetAllocator()) HTypeConversion(conv_type, shl_value);
+
+ DCHECK(DataType::IsTypeConversionImplicit(conv_type, instruction->GetResultType()));
+
+ block->ReplaceAndRemoveInstructionWith(instruction, new_conversion);
+ shl->GetBlock()->RemoveInstruction(shl);
+
+ return true;
+}
+
void InstructionSimplifierVisitor::VisitShift(HBinaryOperation* instruction) {
DCHECK(instruction->IsShl() || instruction->IsShr() || instruction->IsUShr());
HInstruction* shift_amount = instruction->GetRight();
@@ -396,6 +497,11 @@ void InstructionSimplifierVisitor::VisitShift(HBinaryOperation* instruction) {
RecordSimplification();
return;
}
+
+ if (TryReplaceShiftsByConstantWithTypeConversion(instruction)) {
+ RecordSimplification();
+ return;
+ }
}
// Shift operations implicitly mask the shift amount according to the type width. Get rid of
diff --git a/test/458-checker-instruct-simplification/src/Main.java b/test/458-checker-instruct-simplification/src/Main.java
index fb3d184203..76239be741 100644
--- a/test/458-checker-instruct-simplification/src/Main.java
+++ b/test/458-checker-instruct-simplification/src/Main.java
@@ -3120,6 +3120,578 @@ public class Main {
return a != b ? b : a;
}
+ // Check that (x << N >>> N) and (x << N >> N) are simplified to corresponding TypeConversion.
+
+ // Check T -> int -> Unsigned<T> -> int cases.
+
+ /// CHECK-START: int Main.$noinline$testByteToIntAsUnsigned(byte) instruction_simplifier (before)
+ /// CHECK: <<Param:b\d+>> ParameterValue
+ /// CHECK: <<Const24:i\d+>> IntConstant 24
+ /// CHECK: <<Shl:i\d+>> Shl [<<Param>>,<<Const24>>]
+ /// CHECK: <<UShr:i\d+>> UShr [<<Shl>>,<<Const24>>]
+ /// CHECK: <<Return:v\d+>> Return [<<UShr>>]
+
+ /// CHECK-START: int Main.$noinline$testByteToIntAsUnsigned(byte) instruction_simplifier (after)
+ /// CHECK: <<Param:b\d+>> ParameterValue
+ /// CHECK: <<Conv:a\d+>> TypeConversion [<<Param>>]
+ /// CHECK: <<Return:v\d+>> Return [<<Conv>>]
+
+ /// CHECK-START: int Main.$noinline$testByteToIntAsUnsigned(byte) instruction_simplifier (after)
+ /// CHECK-NOT: Shl
+
+ /// CHECK-START: int Main.$noinline$testByteToIntAsUnsigned(byte) instruction_simplifier (after)
+ /// CHECK-NOT: UShr
+ private static int $noinline$testByteToIntAsUnsigned(byte arg) {
+ return arg << 24 >>> 24;
+ }
+
+ /// CHECK-START: int Main.$noinline$testShortToIntAsUnsigned(short) instruction_simplifier (before)
+ /// CHECK: <<Param:s\d+>> ParameterValue
+ /// CHECK: <<Const16:i\d+>> IntConstant 16
+ /// CHECK: <<Shl:i\d+>> Shl [<<Param>>,<<Const16>>]
+ /// CHECK: <<UShr:i\d+>> UShr [<<Shl>>,<<Const16>>]
+ /// CHECK: <<Return:v\d+>> Return [<<UShr>>]
+
+ /// CHECK-START: int Main.$noinline$testShortToIntAsUnsigned(short) instruction_simplifier (after)
+ /// CHECK: <<Param:s\d+>> ParameterValue
+ /// CHECK: <<Conv:c\d+>> TypeConversion [<<Param>>]
+ /// CHECK: <<Return:v\d+>> Return [<<Conv>>]
+
+ /// CHECK-START: int Main.$noinline$testShortToIntAsUnsigned(short) instruction_simplifier (after)
+ /// CHECK-NOT: Shl
+
+ /// CHECK-START: int Main.$noinline$testShortToIntAsUnsigned(short) instruction_simplifier (after)
+ /// CHECK-NOT: UShr
+ private static int $noinline$testShortToIntAsUnsigned(short arg) {
+ return arg << 16 >>> 16;
+ }
+
+ /// CHECK-START: int Main.$noinline$testCharToIntAsUnsigned(char) instruction_simplifier (before)
+ /// CHECK: <<Param:c\d+>> ParameterValue
+ /// CHECK: <<Const16:i\d+>> IntConstant 16
+ /// CHECK: <<Shl:i\d+>> Shl [<<Param>>,<<Const16>>]
+ /// CHECK: <<UShr:i\d+>> UShr [<<Shl>>,<<Const16>>]
+ /// CHECK: <<Return:v\d+>> Return [<<UShr>>]
+
+ /// CHECK-START: int Main.$noinline$testCharToIntAsUnsigned(char) instruction_simplifier (after)
+ /// CHECK: <<Param:c\d+>> ParameterValue
+ /// CHECK: <<Return:v\d+>> Return [<<Param>>]
+
+ /// CHECK-START: int Main.$noinline$testCharToIntAsUnsigned(char) instruction_simplifier (after)
+ /// CHECK-NOT: Shl
+
+ /// CHECK-START: int Main.$noinline$testCharToIntAsUnsigned(char) instruction_simplifier (after)
+ /// CHECK-NOT: UShr
+ private static int $noinline$testCharToIntAsUnsigned(char arg) {
+ return arg << 16 >>> 16;
+ }
+
+ // Check T -> int -> Signed<T> -> int cases.
+
+ /// CHECK-START: int Main.$noinline$testByteToIntAsSigned(byte) instruction_simplifier (before)
+ /// CHECK: <<Param:b\d+>> ParameterValue
+ /// CHECK: <<Const24:i\d+>> IntConstant 24
+ /// CHECK: <<Shl:i\d+>> Shl [<<Param>>,<<Const24>>]
+ /// CHECK: <<Shr:i\d+>> Shr [<<Shl>>,<<Const24>>]
+ /// CHECK: <<Return:v\d+>> Return [<<Shr>>]
+
+ /// CHECK-START: int Main.$noinline$testByteToIntAsSigned(byte) instruction_simplifier (after)
+ /// CHECK: <<Param:b\d+>> ParameterValue
+ /// CHECK: <<Return:v\d+>> Return [<<Param>>]
+
+ /// CHECK-START: int Main.$noinline$testByteToIntAsSigned(byte) instruction_simplifier (after)
+ /// CHECK-NOT: Shl
+
+ /// CHECK-START: int Main.$noinline$testByteToIntAsSigned(byte) instruction_simplifier (after)
+ /// CHECK-NOT: Shr
+ private static int $noinline$testByteToIntAsSigned(byte arg) {
+ return arg << 24 >> 24;
+ }
+
+ /// CHECK-START: int Main.$noinline$testShortToIntAsSigned(short) instruction_simplifier (before)
+ /// CHECK: <<Param:s\d+>> ParameterValue
+ /// CHECK: <<Const16:i\d+>> IntConstant 16
+ /// CHECK: <<Shl:i\d+>> Shl [<<Param>>,<<Const16>>]
+ /// CHECK: <<Shr:i\d+>> Shr [<<Shl>>,<<Const16>>]
+ /// CHECK: <<Return:v\d+>> Return [<<Shr>>]
+
+ /// CHECK-START: int Main.$noinline$testShortToIntAsSigned(short) instruction_simplifier (after)
+ /// CHECK: <<Param:s\d+>> ParameterValue
+ /// CHECK: <<Return:v\d+>> Return [<<Param>>]
+
+ /// CHECK-START: int Main.$noinline$testShortToIntAsSigned(short) instruction_simplifier (after)
+ /// CHECK-NOT: Shl
+
+ /// CHECK-START: int Main.$noinline$testShortToIntAsSigned(short) instruction_simplifier (after)
+ /// CHECK-NOT: Shr
+ private static int $noinline$testShortToIntAsSigned(short arg) {
+ return arg << 16 >> 16;
+ }
+
+ /// CHECK-START: int Main.$noinline$testCharToIntAsSigned(char) instruction_simplifier (before)
+ /// CHECK: <<Param:c\d+>> ParameterValue
+ /// CHECK: <<Const16:i\d+>> IntConstant 16
+ /// CHECK: <<Shl:i\d+>> Shl [<<Param>>,<<Const16>>]
+ /// CHECK: <<Shr:i\d+>> Shr [<<Shl>>,<<Const16>>]
+ /// CHECK: <<Return:v\d+>> Return [<<Shr>>]
+
+ /// CHECK-START: int Main.$noinline$testCharToIntAsSigned(char) instruction_simplifier (after)
+ /// CHECK: <<Param:c\d+>> ParameterValue
+ /// CHECK: <<Conv:s\d+>> TypeConversion [<<Param>>]
+ /// CHECK: <<Return:v\d+>> Return [<<Conv>>]
+
+ /// CHECK-START: int Main.$noinline$testCharToIntAsSigned(char) instruction_simplifier (after)
+ /// CHECK-NOT: Shl
+
+ /// CHECK-START: int Main.$noinline$testCharToIntAsSigned(char) instruction_simplifier (after)
+ /// CHECK-NOT: Shr
+ private static int $noinline$testCharToIntAsSigned(char arg) {
+ return arg << 16 >> 16;
+ }
+
+ // Check T -> U (narrowing) -> int cases where M is unsigned type.
+
+ /// CHECK-START: int Main.$noinline$testShortToByteToIntAsUnsigned(short) instruction_simplifier (before)
+ /// CHECK: <<Param:s\d+>> ParameterValue
+ /// CHECK: <<Const24:i\d+>> IntConstant 24
+ /// CHECK: <<Shl:i\d+>> Shl [<<Param>>,<<Const24>>]
+ /// CHECK: <<UShr:i\d+>> UShr [<<Shl>>,<<Const24>>]
+ /// CHECK: <<Return:v\d+>> Return [<<UShr>>]
+
+ /// CHECK-START: int Main.$noinline$testShortToByteToIntAsUnsigned(short) instruction_simplifier (after)
+ /// CHECK: <<Param:s\d+>> ParameterValue
+ /// CHECK: <<Conv:a\d+>> TypeConversion [<<Param>>]
+ /// CHECK: <<Return:v\d+>> Return [<<Conv>>]
+
+ /// CHECK-START: int Main.$noinline$testShortToByteToIntAsUnsigned(short) instruction_simplifier (after)
+ /// CHECK-NOT: Shl
+
+ /// CHECK-START: int Main.$noinline$testShortToByteToIntAsUnsigned(short) instruction_simplifier (after)
+ /// CHECK-NOT: UShr
+ private static int $noinline$testShortToByteToIntAsUnsigned(short arg) {
+ return arg << 24 >>> 24;
+ }
+
+ /// CHECK-START: int Main.$noinline$testCharToByteToIntAsUnsigned(char) instruction_simplifier (before)
+ /// CHECK: <<Param:c\d+>> ParameterValue
+ /// CHECK: <<Const24:i\d+>> IntConstant 24
+ /// CHECK: <<Shl:i\d+>> Shl [<<Param>>,<<Const24>>]
+ /// CHECK: <<UShr:i\d+>> UShr [<<Shl>>,<<Const24>>]
+ /// CHECK: <<Return:v\d+>> Return [<<UShr>>]
+
+ /// CHECK-START: int Main.$noinline$testCharToByteToIntAsUnsigned(char) instruction_simplifier (after)
+ /// CHECK: <<Param:c\d+>> ParameterValue
+ /// CHECK: <<Conv:a\d+>> TypeConversion [<<Param>>]
+ /// CHECK: <<Return:v\d+>> Return [<<Conv>>]
+
+ /// CHECK-START: int Main.$noinline$testCharToByteToIntAsUnsigned(char) instruction_simplifier (after)
+ /// CHECK-NOT: Shl
+
+ /// CHECK-START: int Main.$noinline$testCharToByteToIntAsUnsigned(char) instruction_simplifier (after)
+ /// CHECK-NOT: UShr
+ private static int $noinline$testCharToByteToIntAsUnsigned(char arg) {
+ return arg << 24 >>> 24;
+ }
+
+ // Check T -> S (narrowing) -> int cases where S is signed type.
+
+ /// CHECK-START: int Main.$noinline$testShortToByteToIntAsSigned(short) instruction_simplifier (before)
+ /// CHECK: <<Param:s\d+>> ParameterValue
+ /// CHECK: <<Const24:i\d+>> IntConstant 24
+ /// CHECK: <<Shl:i\d+>> Shl [<<Param>>,<<Const24>>]
+ /// CHECK: <<Shr:i\d+>> Shr [<<Shl>>,<<Const24>>]
+ /// CHECK: <<Return:v\d+>> Return [<<Shr>>]
+
+ /// CHECK-START: int Main.$noinline$testShortToByteToIntAsSigned(short) instruction_simplifier (after)
+ /// CHECK: <<Param:s\d+>> ParameterValue
+ /// CHECK: <<Conv:b\d+>> TypeConversion [<<Param>>]
+ /// CHECK: <<Return:v\d+>> Return [<<Conv>>]
+
+ /// CHECK-START: int Main.$noinline$testShortToByteToIntAsSigned(short) instruction_simplifier (after)
+ /// CHECK-NOT: Shl
+
+ /// CHECK-START: int Main.$noinline$testShortToByteToIntAsSigned(short) instruction_simplifier (after)
+ /// CHECK-NOT: Shr
+ private static int $noinline$testShortToByteToIntAsSigned(short arg) {
+ return arg << 24 >> 24;
+ }
+
+ /// CHECK-START: int Main.$noinline$testCharToByteToIntAsSigned(char) instruction_simplifier (before)
+ /// CHECK: <<Param:c\d+>> ParameterValue
+ /// CHECK: <<Const24:i\d+>> IntConstant 24
+ /// CHECK: <<Shl:i\d+>> Shl [<<Param>>,<<Const24>>]
+ /// CHECK: <<Shr:i\d+>> Shr [<<Shl>>,<<Const24>>]
+ /// CHECK: <<Return:v\d+>> Return [<<Shr>>]
+
+ /// CHECK-START: int Main.$noinline$testCharToByteToIntAsSigned(char) instruction_simplifier (after)
+ /// CHECK: <<Param:c\d+>> ParameterValue
+ /// CHECK: <<Conv:b\d+>> TypeConversion [<<Param>>]
+ /// CHECK: <<Return:v\d+>> Return [<<Conv>>]
+
+ /// CHECK-START: int Main.$noinline$testCharToByteToIntAsSigned(char) instruction_simplifier (after)
+ /// CHECK-NOT: Shl
+
+ /// CHECK-START: int Main.$noinline$testCharToByteToIntAsSigned(char) instruction_simplifier (after)
+ /// CHECK-NOT: Shr
+ private static int $noinline$testCharToByteToIntAsSigned(char arg) {
+ return arg << 24 >> 24;
+ }
+
+ // Check int -> U -> int cases where U is a unsigned type.
+
+ /// CHECK-START: int Main.$noinline$testIntToUnsignedByteToInt(int) instruction_simplifier (before)
+ /// CHECK: <<Param:i\d+>> ParameterValue
+ /// CHECK: <<Const24:i\d+>> IntConstant 24
+ /// CHECK: <<Shl:i\d+>> Shl [<<Param>>,<<Const24>>]
+ /// CHECK: <<UShr:i\d+>> UShr [<<Shl>>,<<Const24>>]
+ /// CHECK: <<Return:v\d+>> Return [<<UShr>>]
+
+ /// CHECK-START: int Main.$noinline$testIntToUnsignedByteToInt(int) instruction_simplifier (after)
+ /// CHECK: <<Param:i\d+>> ParameterValue
+ /// CHECK: <<Conv:a\d+>> TypeConversion [<<Param>>]
+ /// CHECK: <<Return:v\d+>> Return [<<Conv>>]
+
+ /// CHECK-START: int Main.$noinline$testIntToUnsignedByteToInt(int) instruction_simplifier (after)
+ /// CHECK-NOT: Shl
+
+ /// CHECK-START: int Main.$noinline$testIntToUnsignedByteToInt(int) instruction_simplifier (after)
+ /// CHECK-NOT: UShr
+ private static int $noinline$testIntToUnsignedByteToInt(int arg) {
+ return arg << 24 >>> 24;
+ }
+
+ /// CHECK-START: int Main.$noinline$testIntToUnsignedShortToInt(int) instruction_simplifier (before)
+ /// CHECK: <<Param:i\d+>> ParameterValue
+ /// CHECK: <<Const16:i\d+>> IntConstant 16
+ /// CHECK: <<Shl:i\d+>> Shl [<<Param>>,<<Const16>>]
+ /// CHECK: <<UShr:i\d+>> UShr [<<Shl>>,<<Const16>>]
+ /// CHECK: <<Return:v\d+>> Return [<<UShr>>]
+
+ /// CHECK-START: int Main.$noinline$testIntToUnsignedShortToInt(int) instruction_simplifier (after)
+ /// CHECK: <<Param:i\d+>> ParameterValue
+ /// CHECK: <<Conv:c\d+>> TypeConversion [<<Param>>]
+ /// CHECK: <<Return:v\d+>> Return [<<Conv>>]
+
+ /// CHECK-START: int Main.$noinline$testIntToUnsignedShortToInt(int) instruction_simplifier (after)
+ /// CHECK-NOT: Shl
+
+ /// CHECK-START: int Main.$noinline$testIntToUnsignedShortToInt(int) instruction_simplifier (after)
+ /// CHECK-NOT: UShr
+ private static int $noinline$testIntToUnsignedShortToInt(int arg) {
+ return arg << 16 >>> 16;
+ }
+
+ // Check int -> S -> int cases where S is a signed type.
+
+ /// CHECK-START: int Main.$noinline$testIntToSignedByteToInt(int) instruction_simplifier (before)
+ /// CHECK: <<Param:i\d+>> ParameterValue
+ /// CHECK: <<Const24:i\d+>> IntConstant 24
+ /// CHECK: <<Shl:i\d+>> Shl [<<Param>>,<<Const24>>]
+ /// CHECK: <<Shr:i\d+>> Shr [<<Shl>>,<<Const24>>]
+ /// CHECK: <<Return:v\d+>> Return [<<Shr>>]
+
+ /// CHECK-START: int Main.$noinline$testIntToSignedByteToInt(int) instruction_simplifier (after)
+ /// CHECK: <<Param:i\d+>> ParameterValue
+ /// CHECK: <<Conv:b\d+>> TypeConversion [<<Param>>]
+ /// CHECK: <<Return:v\d+>> Return [<<Conv>>]
+
+ /// CHECK-START: int Main.$noinline$testIntToSignedByteToInt(int) instruction_simplifier (after)
+ /// CHECK-NOT: Shl
+
+ /// CHECK-START: int Main.$noinline$testIntToSignedByteToInt(int) instruction_simplifier (after)
+ /// CHECK-NOT: Shr
+ private static int $noinline$testIntToSignedByteToInt(int arg) {
+ return arg << 24 >> 24;
+ }
+
+ /// CHECK-START: int Main.$noinline$testIntToSignedShortToInt(int) instruction_simplifier (before)
+ /// CHECK: <<Param:i\d+>> ParameterValue
+ /// CHECK: <<Const16:i\d+>> IntConstant 16
+ /// CHECK: <<Shl:i\d+>> Shl [<<Param>>,<<Const16>>]
+ /// CHECK: <<Shr:i\d+>> Shr [<<Shl>>,<<Const16>>]
+ /// CHECK: <<Return:v\d+>> Return [<<Shr>>]
+
+ /// CHECK-START: int Main.$noinline$testIntToSignedShortToInt(int) instruction_simplifier (after)
+ /// CHECK: <<Param:i\d+>> ParameterValue
+ /// CHECK: <<Conv:s\d+>> TypeConversion [<<Param>>]
+ /// CHECK: <<Return:v\d+>> Return [<<Conv>>]
+
+ /// CHECK-START: int Main.$noinline$testIntToSignedShortToInt(int) instruction_simplifier (after)
+ /// CHECK-NOT: Shl
+
+ /// CHECK-START: int Main.$noinline$testIntToSignedShortToInt(int) instruction_simplifier (after)
+ /// CHECK-NOT: Shr
+ private static int $noinline$testIntToSignedShortToInt(int arg) {
+ return arg << 16 >> 16;
+ }
+
+ // Check T -> U -> int cases where U is a unsigned type.
+
+ /// CHECK-START: int Main.$noinline$testCharToUnsignedByteToInt(char) instruction_simplifier (before)
+ /// CHECK: <<Param:c\d+>> ParameterValue
+ /// CHECK: <<Const24:i\d+>> IntConstant 24
+ /// CHECK: <<Shl:i\d+>> Shl [<<Param>>,<<Const24>>]
+ /// CHECK: <<UShr:i\d+>> UShr [<<Shl>>,<<Const24>>]
+ /// CHECK: <<Return:v\d+>> Return [<<UShr>>]
+
+ /// CHECK-START: int Main.$noinline$testCharToUnsignedByteToInt(char) instruction_simplifier (after)
+ /// CHECK: <<Param:c\d+>> ParameterValue
+ /// CHECK: <<Conv:a\d+>> TypeConversion [<<Param>>]
+ /// CHECK: <<Return:v\d+>> Return [<<Conv>>]
+
+ /// CHECK-START: int Main.$noinline$testCharToUnsignedByteToInt(char) instruction_simplifier (after)
+ /// CHECK-NOT: Shl
+
+ /// CHECK-START: int Main.$noinline$testCharToUnsignedByteToInt(char) instruction_simplifier (after)
+ /// CHECK-NOT: UShr
+ private static int $noinline$testCharToUnsignedByteToInt(char arg) {
+ return arg << 24 >>> 24;
+ }
+
+ /// CHECK-START: int Main.$noinline$testShortToUnsignedByteToInt(short) instruction_simplifier (before)
+ /// CHECK: <<Param:s\d+>> ParameterValue
+ /// CHECK: <<Const24:i\d+>> IntConstant 24
+ /// CHECK: <<Shl:i\d+>> Shl [<<Param>>,<<Const24>>]
+ /// CHECK: <<UShr:i\d+>> UShr [<<Shl>>,<<Const24>>]
+ /// CHECK: <<Return:v\d+>> Return [<<UShr>>]
+
+ /// CHECK-START: int Main.$noinline$testShortToUnsignedByteToInt(short) instruction_simplifier (after)
+ /// CHECK: <<Param:s\d+>> ParameterValue
+ /// CHECK: <<Conv:a\d+>> TypeConversion [<<Param>>]
+ /// CHECK: <<Return:v\d+>> Return [<<Conv>>]
+
+ /// CHECK-START: int Main.$noinline$testShortToUnsignedByteToInt(short) instruction_simplifier (after)
+ /// CHECK-NOT: Shl
+
+ /// CHECK-START: int Main.$noinline$testShortToUnsignedByteToInt(short) instruction_simplifier (after)
+ /// CHECK-NOT: UShr
+ private static int $noinline$testShortToUnsignedByteToInt(short arg) {
+ return arg << 24 >>> 24;
+ }
+
+ // Check T -> S -> int cases where S is a signed type.
+
+ /// CHECK-START: int Main.$noinline$testCharToSignedByteToInt(char) instruction_simplifier (before)
+ /// CHECK: <<Param:c\d+>> ParameterValue
+ /// CHECK: <<Const24:i\d+>> IntConstant 24
+ /// CHECK: <<Shl:i\d+>> Shl [<<Param>>,<<Const24>>]
+ /// CHECK: <<Shr:i\d+>> Shr [<<Shl>>,<<Const24>>]
+ /// CHECK: <<Return:v\d+>> Return [<<Shr>>]
+
+ /// CHECK-START: int Main.$noinline$testCharToSignedByteToInt(char) instruction_simplifier (after)
+ /// CHECK: <<Param:c\d+>> ParameterValue
+ /// CHECK: <<Conv:b\d+>> TypeConversion [<<Param>>]
+ /// CHECK: <<Return:v\d+>> Return [<<Conv>>]
+
+ /// CHECK-START: int Main.$noinline$testCharToSignedByteToInt(char) instruction_simplifier (after)
+ /// CHECK-NOT: Shl
+
+ /// CHECK-START: int Main.$noinline$testCharToSignedByteToInt(char) instruction_simplifier (after)
+ /// CHECK-NOT: Shr
+ private static int $noinline$testCharToSignedByteToInt(char arg) {
+ return arg << 24 >> 24;
+ }
+
+ /// CHECK-START: int Main.$noinline$testShortToSignedByteToInt(short) instruction_simplifier (before)
+ /// CHECK: <<Param:s\d+>> ParameterValue
+ /// CHECK: <<Const24:i\d+>> IntConstant 24
+ /// CHECK: <<Shl:i\d+>> Shl [<<Param>>,<<Const24>>]
+ /// CHECK: <<Shr:i\d+>> Shr [<<Shl>>,<<Const24>>]
+ /// CHECK: <<Return:v\d+>> Return [<<Shr>>]
+
+ /// CHECK-START: int Main.$noinline$testShortToSignedByteToInt(short) instruction_simplifier (after)
+ /// CHECK: <<Param:s\d+>> ParameterValue
+ /// CHECK: <<Conv:b\d+>> TypeConversion [<<Param>>]
+ /// CHECK: <<Return:v\d+>> Return [<<Conv>>]
+
+ /// CHECK-START: int Main.$noinline$testShortToSignedByteToInt(short) instruction_simplifier (after)
+ /// CHECK-NOT: Shl
+
+ /// CHECK-START: int Main.$noinline$testShortToSignedByteToInt(short) instruction_simplifier (after)
+ /// CHECK-NOT: Shr
+ private static int $noinline$testShortToSignedByteToInt(short arg) {
+ return arg << 24 >> 24;
+ }
+
+ // Check cases with shift amounts > 32.
+
+ /// CHECK-START: int Main.$noinline$testUnsignedPromotionWithHugeShiftAmount(int) instruction_simplifier (before)
+ /// CHECK: <<Param:i\d+>> ParameterValue
+ /// CHECK: <<Const48:i\d+>> IntConstant 48
+ /// CHECK: <<Shl:i\d+>> Shl [<<Param>>,<<Const48>>]
+ /// CHECK: <<UShr:i\d+>> UShr [<<Shl>>,<<Const48>>]
+ /// CHECK: <<Return:v\d+>> Return [<<UShr>>]
+
+ /// CHECK-START: int Main.$noinline$testUnsignedPromotionWithHugeShiftAmount(int) instruction_simplifier (after)
+ /// CHECK: <<Param:i\d+>> ParameterValue
+ /// CHECK: <<Conv:c\d+>> TypeConversion [<<Param>>]
+ /// CHECK: <<Return:v\d+>> Return [<<Conv>>]
+
+ /// CHECK-START: int Main.$noinline$testUnsignedPromotionWithHugeShiftAmount(int) instruction_simplifier (after)
+ /// CHECK-NOT: Shl
+
+ /// CHECK-START: int Main.$noinline$testUnsignedPromotionWithHugeShiftAmount(int) instruction_simplifier (after)
+ /// CHECK-NOT: UShr
+ private static int $noinline$testUnsignedPromotionWithHugeShiftAmount(int arg) {
+ return arg << 48 >>> 48;
+ }
+
+ /// CHECK-START: int Main.$noinline$testUnsignedPromotionWithHugeMismatchedShiftAmount(int) instruction_simplifier (before)
+ /// CHECK: <<Param:i\d+>> ParameterValue
+ /// CHECK: <<Const48:i\d+>> IntConstant 48
+ /// CHECK: <<Const16:i\d+>> IntConstant 16
+ /// CHECK: <<Shl:i\d+>> Shl [<<Param>>,<<Const48>>]
+ /// CHECK: <<UShr:i\d+>> UShr [<<Shl>>,<<Const16>>]
+ /// CHECK: <<Return:v\d+>> Return [<<UShr>>]
+
+ /// CHECK-START: int Main.$noinline$testUnsignedPromotionWithHugeMismatchedShiftAmount(int) instruction_simplifier (after)
+ /// CHECK: <<Param:i\d+>> ParameterValue
+ /// CHECK: <<Conv:c\d+>> TypeConversion [<<Param>>]
+ /// CHECK: <<Return:v\d+>> Return [<<Conv>>]
+
+ /// CHECK-START: int Main.$noinline$testUnsignedPromotionWithHugeMismatchedShiftAmount(int) instruction_simplifier (after)
+ /// CHECK-NOT: Shl
+
+ /// CHECK-START: int Main.$noinline$testUnsignedPromotionWithHugeMismatchedShiftAmount(int) instruction_simplifier (after)
+ /// CHECK-NOT: UShr
+ private static int $noinline$testUnsignedPromotionWithHugeMismatchedShiftAmount(int arg) {
+ return arg << 48 >>> 16;
+ }
+
+ // Negative checks.
+
+ /// CHECK-START: long Main.$noinline$testUnsignedPromotionToLong(long) instruction_simplifier (after)
+ /// CHECK: <<Param:j\d+>> ParameterValue
+ /// CHECK: <<Const56:i\d+>> IntConstant 56
+ /// CHECK: <<Shl:j\d+>> Shl [<<Param>>,<<Const56>>]
+ /// CHECK: <<UShr:j\d+>> UShr [<<Shl>>,<<Const56>>]
+ /// CHECK: <<Return:v\d+>> Return [<<UShr>>]
+ private static long $noinline$testUnsignedPromotionToLong(long arg) {
+ // Check that we don't do simplification in the case of unsigned promotion to long.
+ return arg << 56 >>> 56;
+ }
+
+ /// CHECK-START: long Main.$noinline$testSignedPromotionToLong(long) instruction_simplifier (after)
+ /// CHECK: <<Param:j\d+>> ParameterValue
+ /// CHECK: <<Const56:i\d+>> IntConstant 56
+ /// CHECK: <<Shl:j\d+>> Shl [<<Param>>,<<Const56>>]
+ /// CHECK: <<Shr:j\d+>> Shr [<<Shl>>,<<Const56>>]
+ /// CHECK: <<Return:v\d+>> Return [<<Shr>>]
+ private static long $noinline$testSignedPromotionToLong(long arg) {
+ // Check that we don't do simplification in the case of signed promotion to long.
+ return arg << 56 >> 56;
+ }
+
+ /// CHECK-START: int Main.$noinline$testUnsignedPromotionWithNonConstantShiftAmount(int, int) instruction_simplifier (after)
+ /// CHECK: <<Param1:i\d+>> ParameterValue
+ /// CHECK: <<Param2:i\d+>> ParameterValue
+ /// CHECK: <<Shl:i\d+>> Shl [<<Param1>>,<<Param2>>]
+ /// CHECK: <<UShr:i\d+>> UShr [<<Shl>>,<<Param2>>]
+ /// CHECK: <<Return:v\d+>> Return [<<UShr>>]
+ private static int
+ $noinline$testUnsignedPromotionWithNonConstantShiftAmount(int value, int shift_amount) {
+ // Check that we don't do simplification in the case of unsigned promotion with
+ // non constant shift amount.
+ return value << shift_amount >>> shift_amount;
+ }
+
+ /// CHECK-START: int Main.$noinline$testSignedPromotionWithNonConstantShiftAmount(int, int) instruction_simplifier (after)
+ /// CHECK: <<Param1:i\d+>> ParameterValue
+ /// CHECK: <<Param2:i\d+>> ParameterValue
+ /// CHECK: <<Shl:i\d+>> Shl [<<Param1>>,<<Param2>>]
+ /// CHECK: <<Shr:i\d+>> Shr [<<Shl>>,<<Param2>>]
+ /// CHECK: <<Return:v\d+>> Return [<<Shr>>]
+ private static int
+ $noinline$testSignedPromotionWithNonConstantShiftAmount(int value, int shift_amount) {
+ // Check that we don't do simplification in the case of signed promotion with
+ // non constant shift amount.
+ return value << shift_amount >> shift_amount;
+ }
+
+ /// CHECK-START: int Main.$noinline$testUnsignedPromotionWithShlUse(int) instruction_simplifier (after)
+ /// CHECK: <<Param:i\d+>> ParameterValue
+ /// CHECK: <<Const24:i\d+>> IntConstant 24
+ /// CHECK: <<Shl:i\d+>> Shl [<<Param>>,<<Const24>>]
+ /// CHECK: <<UShr:i\d+>> UShr [<<Shl>>,<<Const24>>]
+ /// CHECK: <<Add:i\d+>> Add [<<UShr>>,<<Shl>>]
+ /// CHECK: <<Return:v\d+>> Return [<<Add>>]
+ private static int $noinline$testUnsignedPromotionWithShlUse(int arg) {
+ // Check that we don't do simplification in the case of unsigned promotion
+ // with shl instruction that has more than 1 user.
+ int tmp = arg << 24;
+ return (tmp >>> 24) + tmp;
+ }
+
+ /// CHECK-START: int Main.$noinline$testSignedPromotionWithShlUse(int) instruction_simplifier (after)
+ /// CHECK: <<Param:i\d+>> ParameterValue
+ /// CHECK: <<Const24:i\d+>> IntConstant 24
+ /// CHECK: <<Shl:i\d+>> Shl [<<Param>>,<<Const24>>]
+ /// CHECK: <<Shr:i\d+>> Shr [<<Shl>>,<<Const24>>]
+ /// CHECK: <<Add:i\d+>> Add [<<Shr>>,<<Shl>>]
+ /// CHECK: <<Return:v\d+>> Return [<<Add>>]
+ private static int $noinline$testSignedPromotionWithShlUse(int arg) {
+ // Check that we don't do simplification in the case of signed promotion
+ // with shl instruction that has more than 1 user.
+ int tmp = arg << 24;
+ return (tmp >> 24) + tmp;
+ }
+
+ /// CHECK-START: int Main.$noinline$testUnsignedPromotionPatternWithIncorrectShiftAmountConstant(int) instruction_simplifier (after)
+ /// CHECK: <<Param:i\d+>> ParameterValue
+ /// CHECK: <<Const25:i\d+>> IntConstant 25
+ /// CHECK: <<Shl:i\d+>> Shl [<<Param>>,<<Const25>>]
+ /// CHECK: <<UShr:i\d+>> UShr [<<Shl>>,<<Const25>>]
+ /// CHECK: <<Return:v\d+>> Return [<<UShr>>]
+
+ private static int
+ $noinline$testUnsignedPromotionPatternWithIncorrectShiftAmountConstant(int arg) {
+ // Check that we don't do simplification in the case of 32 - N doesn't correspond
+ // to the size of an integral type.
+ return arg << 25 >>> 25;
+ }
+
+ /// CHECK-START: int Main.$noinline$testSignedPromotionPatternWithIncorrectShiftAmountConstant(int) instruction_simplifier (after)
+ /// CHECK: <<Param:i\d+>> ParameterValue
+ /// CHECK: <<Const25:i\d+>> IntConstant 25
+ /// CHECK: <<Shl:i\d+>> Shl [<<Param>>,<<Const25>>]
+ /// CHECK: <<Shr:i\d+>> Shr [<<Shl>>,<<Const25>>]
+ /// CHECK: <<Return:v\d+>> Return [<<Shr>>]
+
+ private static int
+ $noinline$testSignedPromotionPatternWithIncorrectShiftAmountConstant(int arg) {
+ // Check that we don't do simplification in the case of 32 - N doesn't correspond
+ // to the size of an integral type.
+ return arg << 25 >> 25;
+ }
+
+ /// CHECK-START: int Main.$noinline$testUnsignedPromotionPatternWithDifferentShiftAmountConstants(int) instruction_simplifier (after)
+ /// CHECK: <<Param:i\d+>> ParameterValue
+ /// CHECK: <<Const24:i\d+>> IntConstant 24
+ /// CHECK: <<Const16:i\d+>> IntConstant 16
+ /// CHECK: <<Shl:i\d+>> Shl [<<Param>>,<<Const24>>]
+ /// CHECK: <<UShr:i\d+>> UShr [<<Shl>>,<<Const16>>]
+ /// CHECK: <<Return:v\d+>> Return [<<UShr>>]
+
+ private static int
+ $noinline$testUnsignedPromotionPatternWithDifferentShiftAmountConstants(int arg) {
+ // Check that we don't do simplification in the case of different shift amounts.
+ return arg << 24 >>> 16;
+ }
+
+ /// CHECK-START: int Main.$noinline$testSignedPromotionPatternWithDifferentShiftAmountConstants(int) instruction_simplifier (after)
+ /// CHECK: <<Param:i\d+>> ParameterValue
+ /// CHECK: <<Const25:i\d+>> IntConstant 25
+ /// CHECK: <<Const26:i\d+>> IntConstant 26
+ /// CHECK: <<Shl:i\d+>> Shl [<<Param>>,<<Const25>>]
+ /// CHECK: <<Shr:i\d+>> Shr [<<Shl>>,<<Const26>>]
+ /// CHECK: <<Return:v\d+>> Return [<<Shr>>]
+
+ private static
+ int $noinline$testSignedPromotionPatternWithDifferentShiftAmountConstants(int arg) {
+ // Check that we do not simplification in the case of different shift amounts.
+ return arg << 25 >> 26;
+ }
+
public static void main(String[] args) throws Exception {
Class smaliTests2 = Class.forName("SmaliTests2");
Method $noinline$XorAllOnes = smaliTests2.getMethod("$noinline$XorAllOnes", int.class);
@@ -3473,6 +4045,68 @@ public class Main {
assertLongEquals(y, $noinline$returnSecondIfNotEqualElseFirstLong(x, y));
}
}
+
+ assertIntEquals(0xaa, $noinline$testByteToIntAsUnsigned((byte) 0xaa));
+ assertIntEquals(0xaabb, $noinline$testShortToIntAsUnsigned((short) 0xaabb));
+ assertIntEquals(0xaabb, $noinline$testCharToIntAsUnsigned((char) 0xaabb));
+
+ assertIntEquals(0xffffffaa, $noinline$testByteToIntAsSigned((byte) 0xaa));
+ assertIntEquals(0x0a, $noinline$testByteToIntAsSigned((byte) 0x0a));
+ assertIntEquals(0xffffaabb, $noinline$testShortToIntAsSigned((short) 0xaabb));
+ assertIntEquals(0x0abb, $noinline$testShortToIntAsSigned((short) 0x0abb));
+ assertIntEquals(0xffffaabb, $noinline$testCharToIntAsSigned((char) 0xaabb));
+ assertIntEquals(0x0abb, $noinline$testCharToIntAsSigned((char) 0x0abb));
+
+ assertIntEquals(0xbb, $noinline$testShortToByteToIntAsUnsigned((short) 0xaabb));
+ assertIntEquals(0xbb, $noinline$testCharToByteToIntAsUnsigned((char) 0x0abb));
+
+ assertIntEquals(0xffffffbb, $noinline$testShortToByteToIntAsSigned((short) 0xaabb));
+ assertIntEquals(0x0b, $noinline$testShortToByteToIntAsSigned((short) 0xaa0b));
+ assertIntEquals(0xffffffbb, $noinline$testCharToByteToIntAsSigned((char) 0x0abb));
+ assertIntEquals(0x0b, $noinline$testCharToByteToIntAsSigned((char) 0x0a0b));
+
+ assertIntEquals(0xdd, $noinline$testIntToUnsignedByteToInt(0xaabbccdd));
+ assertIntEquals(0xccdd, $noinline$testIntToUnsignedShortToInt(0xaabbccdd));
+
+ assertIntEquals(0xffffffdd, $noinline$testIntToSignedByteToInt(0xaabbccdd));
+ assertIntEquals(0x0a, $noinline$testIntToSignedByteToInt(0x0a));
+ assertIntEquals(0xffffccdd, $noinline$testIntToSignedShortToInt(0xaabbccdd));
+ assertIntEquals(0x0abb, $noinline$testIntToSignedShortToInt(0x0abb));
+
+ assertIntEquals(0xbb, $noinline$testCharToUnsignedByteToInt((char) 0xaabb));
+ assertIntEquals(0xbb, $noinline$testShortToUnsignedByteToInt((short) 0xaabb));
+
+ assertIntEquals(0xffffffbb, $noinline$testCharToSignedByteToInt((char) 0xaabb));
+ assertIntEquals(0xffffffbb, $noinline$testShortToSignedByteToInt((short) 0xaabb));
+ assertIntEquals(0x0b, $noinline$testCharToSignedByteToInt((char) 0xaa0b));
+ assertIntEquals(0x0b, $noinline$testShortToSignedByteToInt((short) 0xaa0b));
+
+ assertIntEquals(0xccdd,
+ $noinline$testUnsignedPromotionWithHugeShiftAmount(0xaabbccdd));
+ assertIntEquals(0xccdd,
+ $noinline$testUnsignedPromotionWithHugeMismatchedShiftAmount(0xaabbccdd));
+
+ assertLongEquals(0xdd, $noinline$testUnsignedPromotionToLong(0x11223344aabbccddL));
+ assertLongEquals(0xffffffffffffffddL,
+ $noinline$testSignedPromotionToLong(0x11223344aabbccddL));
+
+ assertIntEquals(0xccdd,
+ $noinline$testUnsignedPromotionWithNonConstantShiftAmount(0xaabbccdd, 16));
+ assertIntEquals(0xffffffdd,
+ $noinline$testSignedPromotionWithNonConstantShiftAmount(0xaabbccdd, 24));
+
+ assertIntEquals(0xdd0000dd, $noinline$testUnsignedPromotionWithShlUse(0xaabbccdd));
+ assertIntEquals(0xdcffffdd, $noinline$testSignedPromotionWithShlUse(0xaabbccdd));
+
+ assertIntEquals(0x5d,
+ $noinline$testUnsignedPromotionPatternWithIncorrectShiftAmountConstant(0xaabbccdd));
+ assertIntEquals(0xffffffdd,
+ $noinline$testSignedPromotionPatternWithIncorrectShiftAmountConstant(0xaabbccdd));
+
+ assertIntEquals(0xdd00,
+ $noinline$testUnsignedPromotionPatternWithDifferentShiftAmountConstants(0xaabbccdd));
+ assertIntEquals(0xffffffee,
+ $noinline$testSignedPromotionPatternWithDifferentShiftAmountConstants(0xaabbccdd));
}
private static boolean $inline$true() { return true; }