[PATCH][instcombine] Remove preservesCFG from instcombine

Mark Heffernan meheff at google.com
Tue Nov 4 12:03:42 PST 2014


It seems to me that LoopSimplify is the problem here.  Should
LoopSimplifyPass be marked as IsCFGOnlyPass?  It clearly modifies the CFG.
>From the "writing an llvm pass" manual:  "if a pass walks CFG without
modifying it then the third argument [isCFGOnly] is set to true", however,
I don't know how definitive that is and the logic of that statement doesn't
exactly imply that a CFG-modifying pass can't be marked isCFGOnly.  If
LoopSimplifyPass is changed to !isCFGOnly, then preservesCFG can be added
back to instcombine (at least for the purposes of the bug I ran into).

Mark

On Tue, Nov 4, 2014 at 11:23 AM, Nick Lewycky <nicholas at mxc.ca> wrote:

> Hal Finkel wrote:
>
>> ----- Original Message -----
>>
>>> From: "Nick Lewycky"<nicholas at mxc.ca>
>>> To: "Mark Heffernan"<meheff at google.com>
>>> Cc: llvm-commits at cs.uiuc.edu
>>> Sent: Tuesday, November 4, 2014 2:28:20 AM
>>> Subject: Re: [PATCH][instcombine] Remove preservesCFG from instcombine
>>>
>>> Mark Heffernan wrote:
>>>
>>>> Hi Andrew,
>>>>
>>>> (Let me know if someone else is more appropriate to review this).
>>>>   This
>>>> patch removes setPreservesCFG() from the instcombine pass.
>>>>
>>>
>>> NAK. Please don't commit this.
>>>
>>
>> Already happened (r221223) [but, via the wonders of version control...]
>>
>
> Fair enough. I would like it changed, either fixed forwards or backed out,
> but this is not urgent and we can decide what the right thing to do is
> first.
>
>      The reason
>>>
>>>> is that InstCombine can modify terminator instructions (branches)
>>>> specifically the predicate.
>>>>
>>>
>>> This is the thing where it removes an '%newcond = xor %cond, true'
>>> and
>>> switches 'br %newcond, label %A, label %B' with 'br %cond, label %B,
>>> label %A'?
>>>
>>> If it's actually causing you problems, please just move that
>>> transform
>>> to simplifycfg instead of removing preserves-cfg from instcombine.
>>>
>>
>> It seems like the problem is more general than that:
>>
>>  The reason is that InstCombine can modify terminator instructions
>>>> (branches) specifically the predicate.  Instcombine clears out dead blocks
>>>> and replaces all the dead instruction uses with undef:
>>>>
>>>> http://llvm.org/docs/doxygen/html/InstructionCombining_
>>>> 8cpp_source.html#l02792
>>>>
>>>> These new undefs can be predicates of branches, and from the comment of
>>>> setPreservesCFG():
>>>>
>>>
>> So perhaps any optimization that produces an undef, where that undef
>> could possibly propagate to a branch condition, could under iteration cause
>> this problem. And the code above there says:
>>
>>      // Do a quick scan over the function.  If we find any blocks that are
>>      // unreachable, remove any instructions inside of them.  This
>> prevents
>>      // the instcombine code from having to deal with some bad special
>> cases.
>>
>> So this may actually be trickier to solve otherwise than it at-first
>> appears.
>>
>
> Clearly a CFG preserving pass may change the predicate to a branch. An
> optimization which determines that i1 %x is always true may run %x->RAUW(i1
> true), it would be terrible if preserving the CFG would prevent that.
>
> This implies that CFG driven analyses need to be prepared to have the
> branch predicates (and switch predicates, and invoke arguments) change
> under them, so long as the change doesn't have a semantic difference. If an
> SSA value gets replaced with undef, that's because it always was undef, it
> just wasn't easy to see previously. So I think the place to look is at
> LoopInfo and its handling of undef. Currently we treat undef as "can branch
> to either side, not sure which". What is LoopInfo doing?
>
> Nick
>
>
>
>>   -Hal
>>
>>
>>> Nick
>>>
>>>     Instcombine clears out dead blocks and
>>>
>>>> replaces all the dead instruction uses with undef:
>>>>
>>>> http://llvm.org/docs/doxygen/html/InstructionCombining_
>>>> 8cpp_source.html#l02792
>>>>
>>>> These new undefs can be predicates of branches, and from the
>>>> comment
>>>> of setPreservesCFG():
>>>>
>>>> // setPreservesCFG - This function should be called to by the pass,
>>>> iff
>>>> they do
>>>> // not:
>>>> //
>>>> //  1. Add or remove basic blocks from the function
>>>> //  2. Modify terminator instructions in any way.
>>>>
>>>> Clearly instcombine is modifying terminator instructions so should
>>>> not
>>>> be calling setPreservesCFG().  The specific issue I ran into was a
>>>> dead
>>>> loop not being deleted because of stale analysis data.  Repro:
>>>>
>>>> void foo(int *a, int start_x, int end_x, int start_y, int end_y,
>>>> int k) {
>>>>     for (int y = start_y; y<  end_y; y++) {
>>>>       for (int x = start_x; x<  end_x; x++) {
>>>>         for (int i = 0; i<  1000; i++) {
>>>>           a[x + y + k*i] = 0;
>>>>         }
>>>>       }
>>>>     }
>>>> }
>>>>
>>>> # Dead loop left after loop deletion:
>>>> clang -S -emit-llvm foo.c -o - | opt -O1 -loop-rotate
>>>> -loop-unswitch
>>>> -instcombine -loop-deletion -S>  bad.ll
>>>>
>>>> # Dead loop removed by splitting out loop-deletion into separate
>>>> opt
>>>> invocation:
>>>> clang -S -emit-llvm foo.c -o - | opt -O1 -loop-rotate
>>>> -loop-unswitch
>>>> -instcombine | opt -loop-deletion -S>  good.ll
>>>>
>>>> This patch fixes this discrepancy.
>>>>
>>>> Mark
>>>>
>>>>
>>>> _______________________________________________
>>>> llvm-commits mailing list
>>>> llvm-commits at cs.uiuc.edu
>>>> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>>>>
>>>
>>> _______________________________________________
>>> llvm-commits mailing list
>>> llvm-commits at cs.uiuc.edu
>>> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>>>
>>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20141104/9d2050ae/attachment.html>


More information about the llvm-commits mailing list