Optimize away useless masking operations on shift amounts.
Change-Id: I90d69757cc45312eda3d57cc2d32bfb4e47963f5
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index 62d6370..3041c4d 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -236,22 +236,40 @@
void InstructionSimplifierVisitor::VisitShift(HBinaryOperation* instruction) {
DCHECK(instruction->IsShl() || instruction->IsShr() || instruction->IsUShr());
- HConstant* input_cst = instruction->GetConstantRight();
- HInstruction* input_other = instruction->GetLeastConstantLeft();
+ HInstruction* shift_amount = instruction->GetRight();
+ HInstruction* value = instruction->GetLeft();
- if (input_cst != nullptr) {
- int64_t cst = Int64FromConstant(input_cst);
- int64_t mask = (input_other->GetType() == Primitive::kPrimLong)
- ? kMaxLongShiftDistance
- : kMaxIntShiftDistance;
- if ((cst & mask) == 0) {
+ int64_t implicit_mask = (value->GetType() == Primitive::kPrimLong)
+ ? kMaxLongShiftDistance
+ : kMaxIntShiftDistance;
+
+ if (shift_amount->IsConstant()) {
+ int64_t cst = Int64FromConstant(shift_amount->AsConstant());
+ if ((cst & implicit_mask) == 0) {
// Replace code looking like
- // SHL dst, src, 0
+ // SHL dst, value, 0
// with
- // src
- instruction->ReplaceWith(input_other);
+ // value
+ instruction->ReplaceWith(value);
instruction->GetBlock()->RemoveInstruction(instruction);
RecordSimplification();
+ return;
+ }
+ }
+
+ // Shift operations implicitly mask the shift amount according to the type width. Get rid of
+ // unnecessary explicit masking operations on the shift amount.
+ // Replace code looking like
+ // AND masked_shift, shift, <superset of implicit mask>
+ // SHL dst, value, masked_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);
+ RecordSimplification();
}
}
}
diff --git a/test/458-checker-instruction-simplification/src/Main.java b/test/458-checker-instruction-simplification/src/Main.java
index a885204..ffce49d 100644
--- a/test/458-checker-instruction-simplification/src/Main.java
+++ b/test/458-checker-instruction-simplification/src/Main.java
@@ -1757,6 +1757,108 @@
}
}
+ /// CHECK-START: int Main.$noinline$intUnnecessaryShiftMasking(int, int) instruction_simplifier (before)
+ /// CHECK: <<Value:i\d+>> ParameterValue
+ /// CHECK: <<Shift:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Const31:i\d+>> IntConstant 31
+ /// CHECK-DAG: <<And:i\d+>> And [<<Shift>>,<<Const31>>]
+ /// CHECK-DAG: <<Shl:i\d+>> Shl [<<Value>>,<<And>>]
+ /// CHECK-DAG: Return [<<Shl>>]
+
+ /// CHECK-START: int Main.$noinline$intUnnecessaryShiftMasking(int, int) instruction_simplifier (after)
+ /// CHECK: <<Value:i\d+>> ParameterValue
+ /// CHECK: <<Shift:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Shl:i\d+>> Shl [<<Value>>,<<Shift>>]
+ /// CHECK-DAG: Return [<<Shl>>]
+
+ public static int $noinline$intUnnecessaryShiftMasking(int value, int shift) {
+ if (doThrow) { throw new Error(); }
+ return value << (shift & 31);
+ }
+
+ /// CHECK-START: long Main.$noinline$longUnnecessaryShiftMasking(long, int) instruction_simplifier (before)
+ /// CHECK: <<Value:j\d+>> ParameterValue
+ /// CHECK: <<Shift:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Const63:i\d+>> IntConstant 63
+ /// CHECK-DAG: <<And:i\d+>> And [<<Shift>>,<<Const63>>]
+ /// CHECK-DAG: <<Shr:j\d+>> Shr [<<Value>>,<<And>>]
+ /// CHECK-DAG: Return [<<Shr>>]
+
+ /// CHECK-START: long Main.$noinline$longUnnecessaryShiftMasking(long, int) instruction_simplifier (after)
+ /// CHECK: <<Value:j\d+>> ParameterValue
+ /// CHECK: <<Shift:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Shr:j\d+>> Shr [<<Value>>,<<Shift>>]
+ /// CHECK-DAG: Return [<<Shr>>]
+
+ public static long $noinline$longUnnecessaryShiftMasking(long value, int shift) {
+ if (doThrow) { throw new Error(); }
+ return value >> (shift & 63);
+ }
+
+ /// CHECK-START: int Main.$noinline$intUnnecessaryWiderShiftMasking(int, int) instruction_simplifier (before)
+ /// CHECK: <<Value:i\d+>> ParameterValue
+ /// CHECK: <<Shift:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Const255:i\d+>> IntConstant 255
+ /// CHECK-DAG: <<And:i\d+>> And [<<Shift>>,<<Const255>>]
+ /// CHECK-DAG: <<UShr:i\d+>> UShr [<<Value>>,<<And>>]
+ /// CHECK-DAG: Return [<<UShr>>]
+
+ /// CHECK-START: int Main.$noinline$intUnnecessaryWiderShiftMasking(int, int) instruction_simplifier (after)
+ /// CHECK: <<Value:i\d+>> ParameterValue
+ /// CHECK: <<Shift:i\d+>> ParameterValue
+ /// CHECK-DAG: <<UShr:i\d+>> UShr [<<Value>>,<<Shift>>]
+ /// CHECK-DAG: Return [<<UShr>>]
+
+ public static int $noinline$intUnnecessaryWiderShiftMasking(int value, int shift) {
+ if (doThrow) { throw new Error(); }
+ return value >>> (shift & 0xff);
+ }
+
+ /// CHECK-START: long Main.$noinline$longSmallerShiftMasking(long, int) instruction_simplifier (before)
+ /// CHECK: <<Value:j\d+>> ParameterValue
+ /// CHECK: <<Shift:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Const3:i\d+>> IntConstant 3
+ /// CHECK-DAG: <<And:i\d+>> And [<<Shift>>,<<Const3>>]
+ /// CHECK-DAG: <<Shl:j\d+>> Shl [<<Value>>,<<And>>]
+ /// CHECK-DAG: Return [<<Shl>>]
+
+ /// CHECK-START: long Main.$noinline$longSmallerShiftMasking(long, int) instruction_simplifier (after)
+ /// CHECK: <<Value:j\d+>> ParameterValue
+ /// CHECK: <<Shift:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Const3:i\d+>> IntConstant 3
+ /// CHECK-DAG: <<And:i\d+>> And [<<Shift>>,<<Const3>>]
+ /// CHECK-DAG: <<Shl:j\d+>> Shl [<<Value>>,<<And>>]
+ /// CHECK-DAG: Return [<<Shl>>]
+
+ public static long $noinline$longSmallerShiftMasking(long value, int shift) {
+ if (doThrow) { throw new Error(); }
+ return value << (shift & 3);
+ }
+
+ /// CHECK-START: int Main.$noinline$otherUseOfUnnecessaryShiftMasking(int, int) instruction_simplifier (before)
+ /// CHECK: <<Value:i\d+>> ParameterValue
+ /// CHECK: <<Shift:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Const31:i\d+>> IntConstant 31
+ /// CHECK-DAG: <<And:i\d+>> And [<<Shift>>,<<Const31>>]
+ /// CHECK-DAG: <<Shr:i\d+>> Shr [<<Value>>,<<And>>]
+ /// CHECK-DAG: <<Add:i\d+>> Add [<<Shr>>,<<And>>]
+ /// CHECK-DAG: Return [<<Add>>]
+
+ /// CHECK-START: int Main.$noinline$otherUseOfUnnecessaryShiftMasking(int, int) instruction_simplifier (after)
+ /// CHECK: <<Value:i\d+>> ParameterValue
+ /// CHECK: <<Shift:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Const31:i\d+>> IntConstant 31
+ /// CHECK-DAG: <<And:i\d+>> And [<<Shift>>,<<Const31>>]
+ /// CHECK-DAG: <<Shr:i\d+>> Shr [<<Value>>,<<Shift>>]
+ /// CHECK-DAG: <<Add:i\d+>> Add [<<Shr>>,<<And>>]
+ /// CHECK-DAG: Return [<<Add>>]
+
+ public static int $noinline$otherUseOfUnnecessaryShiftMasking(int value, int shift) {
+ if (doThrow) { throw new Error(); }
+ int temp = shift & 31;
+ return (value >> temp) + temp;
+ }
+
public static void main(String[] args) {
int arg = 123456;
@@ -1908,6 +2010,17 @@
}
}
}
+
+ 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));
+ 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));
+ assertIntEquals(0xfffd5e7c, $noinline$otherUseOfUnnecessaryShiftMasking(0xabcdef01, 13));
+ assertIntEquals(0xfffd5e7c, $noinline$otherUseOfUnnecessaryShiftMasking(0xabcdef01, 13 + 512));
}
private static boolean $inline$true() { return true; }