[LLVMdev] The order of GVN and IndVarSimplify
Andrew Trick
atrick at apple.com
Mon Nov 4 17:58:34 PST 2013
On Oct 31, 2013, at 10:59 AM, Richard Sandiford <rsandifo at linux.vnet.ibm.com> wrote:
> This might be hard cases making bad law, but the loop:
>
> void
> f (unsigned short *x, int *l)
> {
> int c = *l;
> int i;
> for (i = 0; i < c; i++)
> if (x[i])
> x[i]++;
> }
>
> is converted to decrement-and-branch form by LoopStrengthReduce while:
>
> void
> f (unsigned short *x, int *l)
> {
> int i;
> for (i = 0; i < *l; i++)
> if (x[i])
> x[i]++;
> }
>
> isn't. This makes a big difference on z, which has a native decrement-and-
> branch instruction.
>
> The problem seems to be that the strength-reduction pass relies on
> IndVarSimplify to convert loop exit conditions into a canonical != form:
>
> // Equality (== and !=) ICmps are special. We can rewrite (i == N) as
> // (N - i == 0), and this allows (N - i) to be the expression that we work
> // with rather than just N or i, so we can consider the register
> // requirements for both N and i at the same time. Limiting this code to
> // equality icmps is not a problem because all interesting loops use
> // equality icmps, thanks to IndVarSimplify.
> if (ICmpInst *CI = dyn_cast<ICmpInst>(LF.UserInst))
> if (CI->isEquality()) {
>
> and this is happening for the first loop but not the second. The reason
> is that the second loop still has two loads of *l by the time IndVarSimplify
> is run; one for the precondition of the rotated loop and one for the loop
> exit. This means that IndVarSimplify can't tell that the precondition
> (skip the loop if *l <= 0) is operating on the same *l as the loop exit,
> and therefore can't work out that *l is the trip count. The two "*l"s
> are only fused by GVN, which runs after IndVarSimplify.
>
> Moving GVN before IndVarSimplify gives me the code I wanted. So does adding
> an IndVarSimplify pass before LoopStrengthReduce. Would either of these
> be OK? I was wondering whether the second made sense anyway, since
> LoopStrengthReduce is done by CodeGen and is pretty far separated from
> the usual IndVarSimplify position.
>
> I've attached the .ll form of the second loop, in case it helps.
This is a good observation, and a bug in the optimization pipeline. A couple things:
- I don’t see any good reason that the LinearFunctionTest replacement being done in IndVars can’t be done late, during LSR. AFAICT, it’s only purpose is enabling LoopStrengthReduce.
- I think GVN should run earlier, before most of the loop opts, and I think IndVars should run much later. I filed a bug for this. See PR17809: Reordering IR-level optimization passes. It’s hard to make progress on a major pass pipeline change because it requires a lot of investment in performance analysis. If you could file a bug for your test case and relate it to that bug it would be great. It can’t hurt, and may motivate someone to get around to fixing it sooner.
-Andy
More information about the llvm-dev
mailing list