[PATCH] D71093: [InstCombine] Insert instructions before adding them to worklist

Nikita Popov via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Tue Dec 17 12:17:47 PST 2019


nikic added inline comments.


================
Comment at: llvm/include/llvm/Transforms/InstCombine/InstCombineWorklist.h:95-96
+      auto *UI = cast<Instruction>(U);
+      // Do not add instructions that haven't been properly inserted yet.
+      if (UI->getParent()) {
+        Add(UI);
----------------
kuhar wrote:
> nikic wrote:
> > kuhar wrote:
> > > lebedev.ri wrote:
> > > > The described behavior sounds like a bug to me.
> > > > More importantly, it's not related to the printing changes?
> > > The users that I refer to here are new instructions that are being constructed; InstCombine inserts them in subsequent calls to `Add()`. This happens in a few places and it's not obvious to me make it more straight-forward.
> > > With the changes to the worklist here, everything works like before and the order of iteration is exactly the same.
> > > 
> > > Let me know if you want me to dig up some concrete examples for this behavior here.
> > I'd appreciate an example for this. I can see how it can happen in principle, but not really why we'd write the code that way in practice.
> Consider the test `llvm/test/Transforms/InstCombine/zext-or-icmp.ll`, function `zext_or_icmp_icmp`:
> ```
> define i8 @zext_or_icmp_icmp(i8 %a, i8 %b) {
>   %mask = and i8 %a, 1
>   %toBool1 = icmp eq i8 %mask, 0
>   %toBool2 = icmp eq i8 %b, 0
>   %bothCond = or i1 %toBool1, %toBool2
>   %zext = zext i1 %bothCond to i8
>   ret i8 %zext
> }
> ```
> 
> Instcombine starts like this:
> ```
> INSTCOMBINE ITERATION #1 on zext_or_icmp_icmp
> IC: ADDING: 6 instrs to worklist
> IC: Visiting:   %mask = and i8 %a, 1
> IC: Visiting:   %toBool1 = icmp eq i8 %mask, 0
> IC: Visiting:   %toBool2 = icmp eq i8 %b, 0
> IC: Visiting:   %bothCond = or i1 %toBool1, %toBool2
> IC: Visiting:   %zext = zext i1 %bothCond to i8
> IC: ADD:   %toBool11 = zext i1 %toBool1 to i8
> IC: ADD:   %toBool22 = zext i1 %toBool2 to i8
> IC: ADD:   %1 = xor i8 %mask, 1
> ```
> 
> Instcombine wants to replace all uses of `%toBool11 = zext i1 %toBool1 to i8` with `%1 = xor i8 %mask, 1`. One of the uses is `<badref> = or i8 %toBool11, %toBool22`:
> ```
> IC: Replacing   %toBool11 = zext i1 %toBool1 to i8
>     with   %1 = xor i8 %mask, 1
> IC: Old =   %zext = zext i1 %bothCond to i8
>     New =   <badref> = or i8 %1, %toBool22
> IC: ADD:   %zext = or i8 %1, %toBool22
> ```
> 
> The way I understand the issue is that one of the uses is the instructions that currently being simplified. This instruction will be added to the worklist anyway once the simplification is finished.
> 
Thanks for the example. This transform seems to be a pretty special case that manually runs other InstCombine transforms to prevent an infinite loop.

Assuming that this is the only case (at least I didn't get anything else running InstCombine tests), possibly we might just want to adjust the transform to insert the instruction earlier? Something along these lines:

```
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
index 5112fb1a6c3..70a7b9bfbba 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
@@ -1189,7 +1189,8 @@ Instruction *InstCombiner::visitZExt(ZExtInst &CI) {
       // zext (or icmp, icmp) -> or (zext icmp), (zext icmp)
       Value *LCast = Builder.CreateZExt(LHS, CI.getType(), LHS->getName());
       Value *RCast = Builder.CreateZExt(RHS, CI.getType(), RHS->getName());
-      BinaryOperator *Or = BinaryOperator::Create(Instruction::Or, LCast, RCast);
+      Value *Or = Builder.CreateOr(LCast, RCast);
+      Builder.SetInsertPoint(cast<Instruction>(Or));
 
       // Perform the elimination.
       if (auto *LZExt = dyn_cast<ZExtInst>(LCast))
@@ -1197,7 +1198,7 @@ Instruction *InstCombiner::visitZExt(ZExtInst &CI) {
       if (auto *RZExt = dyn_cast<ZExtInst>(RCast))
         transformZExtICmp(RHS, *RZExt);
 
-      return Or;
+      return replaceInstUsesWith(CI, Or);
     }
   }
```

I feel like doing this might be better than carving out an exception in the worklist management itself.


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

https://reviews.llvm.org/D71093





More information about the llvm-commits mailing list