ART: Generalize "x >> (s & m)" simplification.
Extend the simplification from
x SHIFT (s & mask), mask contains relevant bits
where SHIFT is Shl/Shr/UShr/Ror to
x SHIFT (s | mask), mask does not contain relevant bits,
x SHIFT (s ^ mask), mask does not contain relevant bits,
x SHIFT (s + mask), mask does not contain relevant bits,
x SHIFT (s - mask), mask does not contain relevant bits,
x SHIFT ((type)s), s is non-64-bit integral type.
The simplification for the TypeConversion case is motivated
by the work to introduce Uint8 and convert '& 0xff' to
TypeConversion. This CL makes sure the old simplifications
shall still work. The simplifications for Or/Xor/Add/Sub
are added just because we can.
Test: Add tests to 548-checker-instruct-simplification.
Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing
Bug: 23964345
Change-Id: I71210cb63496fae607a457a627f115260669c2c9
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index 1a2494a..cf1cbd5 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -360,18 +360,36 @@
}
// Shift operations implicitly mask the shift amount according to the type width. Get rid of
- // unnecessary explicit masking operations on the shift amount.
+ // unnecessary And/Or/Xor/Add/Sub/TypeConversion operations on the shift amount that do not
+ // affect the relevant bits.
// Replace code looking like
- // AND masked_shift, shift, <superset of implicit mask>
- // SHL dst, value, masked_shift
+ // AND adjusted_shift, shift, <superset of implicit mask>
+ // [OR/XOR/ADD/SUB adjusted_shift, shift, <value not overlapping with implicit mask>]
+ // [<conversion-from-integral-non-64-bit-type> adjusted_shift, shift]
+ // SHL dst, value, adjusted_shift
// with
// SHL dst, value, shift
- if (shift_amount->IsAnd()) {
- HAnd* and_insn = shift_amount->AsAnd();
- HConstant* mask = and_insn->GetConstantRight();
- if ((mask != nullptr) && ((Int64FromConstant(mask) & implicit_mask) == implicit_mask)) {
- instruction->ReplaceInput(and_insn->GetLeastConstantLeft(), 1);
+ if (shift_amount->IsAnd() ||
+ shift_amount->IsOr() ||
+ shift_amount->IsXor() ||
+ shift_amount->IsAdd() ||
+ shift_amount->IsSub()) {
+ int64_t required_result = shift_amount->IsAnd() ? implicit_mask : 0;
+ HBinaryOperation* bin_op = shift_amount->AsBinaryOperation();
+ HConstant* mask = bin_op->GetConstantRight();
+ if (mask != nullptr && (Int64FromConstant(mask) & implicit_mask) == required_result) {
+ instruction->ReplaceInput(bin_op->GetLeastConstantLeft(), 1);
RecordSimplification();
+ return;
+ }
+ } else if (shift_amount->IsTypeConversion()) {
+ DCHECK_NE(shift_amount->GetType(), DataType::Type::kBool); // We never convert to bool.
+ DataType::Type source_type = shift_amount->InputAt(0)->GetType();
+ // Non-integral and 64-bit source types require an explicit type conversion.
+ if (DataType::IsIntegralType(source_type) && !DataType::Is64BitType(source_type)) {
+ instruction->ReplaceInput(shift_amount->AsTypeConversion()->GetInput(), 1);
+ RecordSimplification();
+ return;
}
}
}
diff --git a/test/458-checker-instruct-simplification/src/Main.java b/test/458-checker-instruct-simplification/src/Main.java
index 5c36ce9..f36c261 100644
--- a/test/458-checker-instruct-simplification/src/Main.java
+++ b/test/458-checker-instruct-simplification/src/Main.java
@@ -2038,6 +2038,84 @@
return (value >> temp) + temp;
}
+ /// CHECK-START: int Main.$noinline$intUnnecessaryShiftModifications(int, int) instruction_simplifier (before)
+ /// CHECK: <<Value:i\d+>> ParameterValue
+ /// CHECK: <<Shift:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Const32:i\d+>> IntConstant 32
+ /// CHECK-DAG: <<Const64:i\d+>> IntConstant 64
+ /// CHECK-DAG: <<Const96:i\d+>> IntConstant 96
+ /// CHECK-DAG: <<Const128:i\d+>> IntConstant 128
+ /// CHECK-DAG: <<Or:i\d+>> Or [<<Shift>>,<<Const32>>]
+ /// CHECK-DAG: <<Xor:i\d+>> Xor [<<Shift>>,<<Const64>>]
+ /// CHECK-DAG: <<Add:i\d+>> Add [<<Shift>>,<<Const96>>]
+ /// CHECK-DAG: <<Sub:i\d+>> Sub [<<Shift>>,<<Const128>>]
+ /// CHECK-DAG: <<Conv:b\d+>> TypeConversion [<<Shift>>]
+ /// CHECK-DAG: Shl [<<Value>>,<<Or>>]
+ /// CHECK-DAG: Shr [<<Value>>,<<Xor>>]
+ /// CHECK-DAG: UShr [<<Value>>,<<Add>>]
+ /// CHECK-DAG: Shl [<<Value>>,<<Sub>>]
+ /// CHECK-DAG: Shr [<<Value>>,<<Conv>>]
+
+ /// CHECK-START: int Main.$noinline$intUnnecessaryShiftModifications(int, int) instruction_simplifier (after)
+ /// CHECK: <<Value:i\d+>> ParameterValue
+ /// CHECK: <<Shift:i\d+>> ParameterValue
+ /// CHECK-DAG: Shl [<<Value>>,<<Shift>>]
+ /// CHECK-DAG: Shr [<<Value>>,<<Shift>>]
+ /// CHECK-DAG: UShr [<<Value>>,<<Shift>>]
+ /// CHECK-DAG: Shl [<<Value>>,<<Shift>>]
+ /// CHECK-DAG: Shr [<<Value>>,<<Shift>>]
+
+ public static int $noinline$intUnnecessaryShiftModifications(int value, int shift) {
+ if (doThrow) { throw new Error(); }
+ int c128 = 128;
+ return (value << (shift | 32)) +
+ (value >> (shift ^ 64)) +
+ (value >>> (shift + 96)) +
+ (value << (shift - c128)) + // Needs a named constant to generate Sub.
+ (value >> ((byte) shift));
+ }
+
+ /// CHECK-START: int Main.$noinline$intNecessaryShiftModifications(int, int) instruction_simplifier (before)
+ /// CHECK: <<Value:i\d+>> ParameterValue
+ /// CHECK: <<Shift:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Const33:i\d+>> IntConstant 33
+ /// CHECK-DAG: <<Const65:i\d+>> IntConstant 65
+ /// CHECK-DAG: <<Const97:i\d+>> IntConstant 97
+ /// CHECK-DAG: <<Const129:i\d+>> IntConstant 129
+ /// CHECK-DAG: <<Or:i\d+>> Or [<<Shift>>,<<Const33>>]
+ /// CHECK-DAG: <<Xor:i\d+>> Xor [<<Shift>>,<<Const65>>]
+ /// CHECK-DAG: <<Add:i\d+>> Add [<<Shift>>,<<Const97>>]
+ /// CHECK-DAG: <<Sub:i\d+>> Sub [<<Shift>>,<<Const129>>]
+ /// CHECK-DAG: Shl [<<Value>>,<<Or>>]
+ /// CHECK-DAG: Shr [<<Value>>,<<Xor>>]
+ /// CHECK-DAG: UShr [<<Value>>,<<Add>>]
+ /// CHECK-DAG: Shl [<<Value>>,<<Sub>>]
+
+ /// CHECK-START: int Main.$noinline$intNecessaryShiftModifications(int, int) instruction_simplifier (after)
+ /// CHECK: <<Value:i\d+>> ParameterValue
+ /// CHECK: <<Shift:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Const33:i\d+>> IntConstant 33
+ /// CHECK-DAG: <<Const65:i\d+>> IntConstant 65
+ /// CHECK-DAG: <<Const97:i\d+>> IntConstant 97
+ /// CHECK-DAG: <<Const129:i\d+>> IntConstant 129
+ /// CHECK-DAG: <<Or:i\d+>> Or [<<Shift>>,<<Const33>>]
+ /// CHECK-DAG: <<Xor:i\d+>> Xor [<<Shift>>,<<Const65>>]
+ /// CHECK-DAG: <<Add:i\d+>> Add [<<Shift>>,<<Const97>>]
+ /// CHECK-DAG: <<Sub:i\d+>> Sub [<<Shift>>,<<Const129>>]
+ /// CHECK-DAG: Shl [<<Value>>,<<Or>>]
+ /// CHECK-DAG: Shr [<<Value>>,<<Xor>>]
+ /// CHECK-DAG: UShr [<<Value>>,<<Add>>]
+ /// CHECK-DAG: Shl [<<Value>>,<<Sub>>]
+
+ public static int $noinline$intNecessaryShiftModifications(int value, int shift) {
+ if (doThrow) { throw new Error(); }
+ int c129 = 129;
+ return (value << (shift | 33)) +
+ (value >> (shift ^ 65)) +
+ (value >>> (shift + 97)) +
+ (value << (shift - c129)); // Needs a named constant to generate Sub.
+ }
+
/// CHECK-START: int Main.$noinline$intAddSubSimplifyArg1(int, int) instruction_simplifier (before)
/// CHECK: <<X:i\d+>> ParameterValue
/// CHECK: <<Y:i\d+>> ParameterValue
@@ -2363,14 +2441,22 @@
assertIntEquals(26, $noinline$runSmaliTestInt("SubSubConst3", 5));
assertIntEquals(0x5e6f7808, $noinline$intUnnecessaryShiftMasking(0xabcdef01, 3));
assertIntEquals(0x5e6f7808, $noinline$intUnnecessaryShiftMasking(0xabcdef01, 3 + 32));
- assertLongEquals(0xffffffffffffeaf3L, $noinline$longUnnecessaryShiftMasking(0xabcdef0123456789L, 50));
- assertLongEquals(0xffffffffffffeaf3L, $noinline$longUnnecessaryShiftMasking(0xabcdef0123456789L, 50 + 64));
+ assertLongEquals(0xffffffffffffeaf3L,
+ $noinline$longUnnecessaryShiftMasking(0xabcdef0123456789L, 50));
+ assertLongEquals(0xffffffffffffeaf3L,
+ $noinline$longUnnecessaryShiftMasking(0xabcdef0123456789L, 50 + 64));
assertIntEquals(0x2af37b, $noinline$intUnnecessaryWiderShiftMasking(0xabcdef01, 10));
assertIntEquals(0x2af37b, $noinline$intUnnecessaryWiderShiftMasking(0xabcdef01, 10 + 128));
- assertLongEquals(0xaf37bc048d159e24L, $noinline$longSmallerShiftMasking(0xabcdef0123456789L, 2));
- assertLongEquals(0xaf37bc048d159e24L, $noinline$longSmallerShiftMasking(0xabcdef0123456789L, 2 + 256));
+ assertLongEquals(0xaf37bc048d159e24L,
+ $noinline$longSmallerShiftMasking(0xabcdef0123456789L, 2));
+ assertLongEquals(0xaf37bc048d159e24L,
+ $noinline$longSmallerShiftMasking(0xabcdef0123456789L, 2 + 256));
assertIntEquals(0xfffd5e7c, $noinline$otherUseOfUnnecessaryShiftMasking(0xabcdef01, 13));
assertIntEquals(0xfffd5e7c, $noinline$otherUseOfUnnecessaryShiftMasking(0xabcdef01, 13 + 512));
+ assertIntEquals(0x5f49eb48, $noinline$intUnnecessaryShiftModifications(0xabcdef01, 2));
+ assertIntEquals(0xbd4c29b0, $noinline$intUnnecessaryShiftModifications(0xabcdef01, 3));
+ assertIntEquals(0xc0fed1ca, $noinline$intNecessaryShiftModifications(0xabcdef01, 2));
+ assertIntEquals(0x03578ebc, $noinline$intNecessaryShiftModifications(0xabcdef01, 3));
assertIntEquals(654321, $noinline$intAddSubSimplifyArg1(arg, 654321));
assertIntEquals(arg, $noinline$intAddSubSimplifyArg2(arg, 654321));