diff options
-rw-r--r-- | compiler/optimizing/data_type.h | 21 | ||||
-rw-r--r-- | compiler/optimizing/instruction_simplifier.cc | 106 | ||||
-rw-r--r-- | test/458-checker-instruct-simplification/src/Main.java | 634 |
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; } |