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

Jakub Kuderski via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Wed Dec 18 10:35:34 PST 2019


kuhar marked 2 inline comments as done.
kuhar 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);
----------------
nikic wrote:
> 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.
You approach seems to like a better way than silently skipping some uses.

I ran the in-source test suite and compiled a few large projects with -O3 to make sure it works.


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

https://reviews.llvm.org/D71093





More information about the llvm-commits mailing list