diff options
| -rw-r--r-- | compiler/optimizing/instruction_simplifier.cc | 40 | ||||
| -rw-r--r-- | test/458-checker-instruction-simplification/src/Main.java | 113 |
2 files changed, 142 insertions, 11 deletions
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc index 62d637081d..3041c4d2c7 100644 --- a/compiler/optimizing/instruction_simplifier.cc +++ b/compiler/optimizing/instruction_simplifier.cc @@ -236,22 +236,40 @@ bool InstructionSimplifierVisitor::TryDeMorganNegationFactoring(HBinaryOperation 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 a885204313..ffce49d2e1 100644 --- a/test/458-checker-instruction-simplification/src/Main.java +++ b/test/458-checker-instruction-simplification/src/Main.java @@ -1757,6 +1757,108 @@ public class Main { } } + /// 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 @@ public static void main(String[] args) { } } } + + 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; } |