[PATCH] InstCombineShifts: Always combine (X >>? C) << C -> X & (-1 << C)

Björn Steinbrink bsteinbr at gmail.com
Sat Mar 29 12:36:08 PDT 2014


The following code resulted from SROA breaking up a single i64 into
parts because the "match_case8.i" arm of the switch only needs a single
byte form it. InstCombine is currently unable to reconstruct the single
i64 load in the two other arms, because GetShiftedValue only handles
shifts with a single user, and FoldShiftsByConstants doesn't perform
this transformation yet, because -- according to the code comments -- it
doesn't want to hide the Shl behind a bitmask.

If both instructions shift by the same amount, the Shl isn't hidden but
replaced though. So adding this transformation to FoldShiftsByConstants
should be fine, allowing InstCombine to reduce the code in
"match_else.i" and "match_case.i" to a simple "ret i64 %4".

    %union = type { i8, [7 x i8], [2 x i64] }

    ; Function Attrs: nounwind readonly
    define i64 @test(%union* noalias nocapture readonly) unnamed_addr {
    entry-block:
      %1 = getelementptr inbounds %union* %0, i64 0, i32 0
      %2 = load i8* %1, align 8
      %3 = getelementptr inbounds %union* %0, i64 0, i32 2, i64 0
      %4 = load i64* %3, align 8
      %5 = lshr i64 %4, 40
      switch i8 %2, label %match_else.i [
        i8 0, label %match_case.i
        i8 1, label %match_case8.i
      ]

    match_else.i:                                     ; preds = %entry-block
      %6 = shl nuw i64 %5, 40
      %7 = and i64 %4, 1099511627775
      %8 = or i64 %7, %6
      ret i64 %8

    match_case.i:                                     ; preds = %entry-block
      %9 = shl nuw i64 %5, 40
      %10 = and i64 %4, 1099511627775
      %11 = or i64 %10, %9
      ret i64 %11

    match_case8.i:                                    ; preds = %entry-block
      %12 = lshr i64 %4, 32
      %.lobit = and i64 %12, 1
      ret i64 %.lobit
    }
---
 lib/Transforms/InstCombine/InstCombineShifts.cpp | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/lib/Transforms/InstCombine/InstCombineShifts.cpp b/lib/Transforms/InstCombine/InstCombineShifts.cpp
index 8273dfd..3139a78 100644
--- a/lib/Transforms/InstCombine/InstCombineShifts.cpp
+++ b/lib/Transforms/InstCombine/InstCombineShifts.cpp
@@ -571,6 +571,13 @@ Instruction *InstCombiner::FoldShiftByConstant(Value *Op0, ConstantInt *Op1,
         return BinaryOperator::CreateAnd(X,
                                         ConstantInt::get(I.getContext(), Mask));
       }
+      // If we have ((X >>? C) << C), turn this into X & (-1 << C).
+      if (I.getOpcode() == Instruction::Shl &&
+          ShiftOp->getOpcode() != Instruction::Shl) {
+        APInt Mask(APInt::getHighBitsSet(TypeBits, TypeBits - ShiftAmt1));
+        return BinaryOperator::CreateAnd(X,
+                                        ConstantInt::get(I.getContext(), Mask));
+      }
     } else if (ShiftAmt1 < ShiftAmt2) {
       uint32_t ShiftDiff = ShiftAmt2-ShiftAmt1;
 
-- 
1.9.0.rc3



More information about the llvm-commits mailing list