[PATCH] D84664: [InstCombine] Fold shift-select if all the operands are constant

Matteo Favaro via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 28 06:44:39 PDT 2020


fvrmatteo added a comment.

OK I think I figured it out.

The **hasOneUse** in **canEvaluateShifted** is absolutely necessary because after its evaluation by **FoldShiftByConstant** the original **select** instruction it's replaced with a new shifted **select** instruction, which means that the original users of `%v0 = select i1 %arg, i64 64, i64 0` will now use its shifted version `%v0 = select i1 %arg, i64 1, i64 0` generated by **FoldShiftByConstant**.

The relevant code is the following:

  // See if we can propagate this shift into the input, this covers the trivial
  // cast of lshr(shl(x,c1),c2) as well as other more complex cases.
  if (I.getOpcode() != Instruction::AShr &&
      canEvaluateShifted(Op0, Op1C->getZExtValue(), isLeftShift, *this, &I)) {
    LLVM_DEBUG(
        dbgs() << "ICE: GetShiftedValue propagating shift through expression"
                  " to eliminate shift:\n  IN: "
               << *Op0 << "\n  SH: " << I << "\n");
  
    return replaceInstUsesWith(
        I, getShiftedValue(Op0, Op1C->getZExtValue(), isLeftShift, *this, DL));  // NOTE: here we are replacing the instruction with more than 1 use
  }

>From the debug output we can see that disabling `if (!I->hasOneUse()) return false;` leads to the following (wrong) sequences:

Substitution of `%v0 = select i1 %arg, i64 64, i64 0` with `%v0 = select i1 %arg, i64 1, i64 0`:

  IC: Visiting:   %v1 = lshr exact i64 %v0, 6
  ICE: GetShiftedValue propagating shift through expression to eliminate shift:
    IN:   %v0 = select i1 %arg, i64 64, i64 0
    SH:   %v1 = lshr exact i64 %v0, 6
  IC: ADD:   %v0 = select i1 %arg, i64 64, i64 0
  IC: Replacing   %v1 = lshr exact i64 %v0, 6
      with   %v0 = select i1 %arg, i64 1, i64 0
  IC: Mod =   %v1 = lshr exact i64 %v0, 6
      New =   %v1 = lshr exact i64 %v0, 6
  IC: ERASE   %v1 = lshr exact i64 %v0, 6
  IC: ADD DEFERRED:   %v0 = select i1 %arg, i64 1, i64 0

Transformation of `%v0 = select i1 %arg, i64 1, i64 0` in `%v0 = zext i1 %arg to i64`:

  IC: Visiting:   %v0 = select i1 %arg, i64 1, i64 0
  IC: Old =   %v0 = select i1 %arg, i64 1, i64 0
      New =   <badref> = zext i1 %arg to i64
  IC: ADD:   %v0 = zext i1 %arg to i64
  IC: ERASE   %0 = select i1 %arg, i64 1, i64 0
  IC: Visiting:   %v0 = zext i1 %arg to i64

Wrong input to `%v3 = shl nuw i64 %v0, 57` that will now use `%v0 = zext i1 %arg to i64` instead of the original `%v0 = select i1 %arg, i64 64, i64 0`:

  IC: Visiting:   %v2 = xor i64 %v0, 1
  IC: Visiting:   %v3 = shl nuw i64 %v0, 57
  IC: Mod =   %v3 = shl nuw i64 %v0, 57
      New =   %v3 = shl nuw nsw i64 %v0, 57
  IC: ADD:   %v3 = shl nuw nsw i64 %v0, 57
  IC: Visiting:   %v3 = shl nuw nsw i64 %v0, 57
  IC: Old =   %v3 = shl nuw nsw i64 %v0, 57
      New =   <badref> = select i1 %arg, i64 144115188075855872, i64 0
  IC: ADD:   %v3 = select i1 %arg, i64 144115188075855872, i64 0

@lebedev.ri I think that calling the patched version of ** SimplifySelectsFeedingBinaryOp** (issuing a direct call to **commonShiftTransforms** from **visitLShr**, **visitShl** and **visitAShr** as you suggested) may be the safest solution, as it is meant to precisely simplify this case. Additionally **commonShiftTransforms** will replace the **lshr** instruction (which is the correct one to be simplified) instead of the **select** (used as input).

I also think that we may try to modify the **canEvaluateShifted** and **FoldShiftByConstant** to handle the multiple-uses case, but that seems way more complex as the code around those functions it's really one-use centric.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D84664/new/

https://reviews.llvm.org/D84664



More information about the llvm-commits mailing list