[llvm-dev] Wrong code bug after GVN/PRE?
Friedman, Eli via llvm-dev
llvm-dev at lists.llvm.org
Fri Jan 13 10:31:26 PST 2017
On 1/13/2017 12:31 AM, Mikael Holmén via llvm-dev wrote:
> Hi,
>
> I've stumbled upon a case where I think gvn does a bad (wrong)
> optimization. It's a bit messy to debug though so I'm not sure if I
> should just write a PR about it a let someone who knows the code look
> at it instead.
>
> Anyway, for the bug to trigger I need to run the following passes in
> the same opt invocation:
> -sroa -instcombine -simplifycfg -instcombine -gvn
>
> The problem seems to be that GVN::PerformLoadPRE triggers and I see a
>
> GVN REMOVING PRE LOAD: %_tmp79 = load i16, i16* %_tmp78, align 2
>
> printout.
>
> If I instead first run
>
> -sroa -instcombine -simplifycfg -instcombine
>
> and then
>
> -gvn
>
> I don't get the
>
> GVN REMOVING PRE LOAD
>
> printout, and the resulting code looks ok to me.
>
> Is this expected? Should the output differ in these two cases?
>
>
> The input to gvn looks the same when running all passes and just gvn,
> but I see a difference in how GVN::processNonLocalLoad(LoadInst *LI)
> behaves:
>
> I get different results from
>
> // Step 1: Find the non-local dependencies of the load.
> LoadDepVect Deps;
> MD->getNonLocalPointerDependency(LI, Deps);
>
> So we get different results from MemoryDependenceResults when invoking
> gvn alone or after a bunch of other passes.
>
> Is this expected or not?
>
>
> I tried to dig into
> MemoryDependenceResults::getNonLocalPointerDependency but I have to
> say I'm quite lost.
>
> I ran some git bisect and as far as I can tell it starts going wrong
> with commit
>
> [SimplifyCFG] Change the algorithm in SinkThenElseCodeToEnd
>
> 2016-09-01, but that commit doesn't change GVN/MemoryDependenceResults
> so I suppose it just changes the input to GVN so the problem suddenly
> surfaces.
>
> Finally, the problem that I see is:
>
> In the input we have something like
>
> for (int step1 = 0; step1 < LOOP_AMOUNT; step1++)
> {
> lb[step1] = step1 + 7;
> ub[step1] = (step1 == 0 ? 10: ub[step1-1]*10);
>
> switch(lb[step1]) {
> case 7: CVAL_VERIFY(step1 == 0);
> CVAL_VERIFY(ub[step1] == 10);
> __label(511);
> break;
> case 8: CVAL_VERIFY(step1 == 1);
> CVAL_VERIFY(ub[step1] == 100);
> __label(512);
> break;
> case 9: CVAL_VERIFY(step1 == 2);
> CVAL_VERIFY(ub[step1] == 1000);
> __label(513);
> break;
> default:;
> }
>
> [...]
> }
>
> int i, j;
> for ( j = 10, i = 0; j < 101; j=j*10, i++ )
> {
> CVAL_VERIFY(ub[i] == j);
> }
>
> So we have two loops. In the first one the array ub is written (low
> index first, high index last), and then in the second loop the content
> of ub is checked (low index first, high index last).
>
> After gvn this is changed into something like
>
> int tmp;
> for (int step1 = 0; step1 < LOOP_AMOUNT; step1++)
> {
> lb[step1] = step1 + 7;
> ub[step1] = (step1 == 0 ? 10: ub[step1-1]*10);
>
> switch(lb[step1]) {
> case 7: CVAL_VERIFY(step1 == 0);
> tmp = ub[step1];
> CVAL_VERIFY(tmp == 10);
> __label(511);
> break;
> case 8: CVAL_VERIFY(step1 == 1);
> tmp = ub[step1];
> CVAL_VERIFY(tmp == 100);
> __label(512);
> break;
> case 9: CVAL_VERIFY(step1 == 2);
> tmp = ub[step1];
> CVAL_VERIFY(tmp == 1000);
> __label(513);
> break;
> default:;
> }
>
> [...]
> }
>
> int i, j;
> for ( j = 10, i = 0; j < 101; j=j*10, i++ )
> {
> CVAL_VERIFY((i == 0 ? tmp : ub[i]) == j);
> }
>
> Note the introduced variable tmp.
>
> Also note that with this rewrite, after the first loop tmp will
> contain the value of the element at the highest index in ub, and then
> we use tmp in the first round of the second loop, but there we expect
> the value of the lowest index element in ub.
>
> Any ideas? Should I file a PR?
Ooh, wow, that's nasty: it looks like PRE is somehow deciding that
ub[step1] and ub[0] are equivalent. Please file a bug.
The reason you're having trouble splitting the "opt" invocation is that
you aren't passing in "-preserve-ll-uselistorder"; it usually doesn't
matter, but occasionally you'll run into an optimization which is
sensitive to it.
-Eli
--
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project
More information about the llvm-dev
mailing list