I think a late loop optimization (vectorization) pipeline makes sense. I think we just have to carefully evaluate benefit over compile time.
Runing loop rotation makes sense. Critical edge splitting can transform loops into a form that prevents loop vectorization.
Both the loop vectorizer and the SLPVectorizer perform limited (restricted in region) forms of CSE to cleanup. EarlyCSE runs across the whole function and so might catch more opportunities.
The downside of always running passes is that we pay the cost irrespective of benefit. There might not be much to cleanup if we don’t vectorize a loop but we still have to pay for running the cleanup passes. This has been the motivator to have “pass local” CSE but this also stems from a time where we ran within the inlining pass manager which meant running over and over again.
I think we will just have to look at compile time and decide what makes sense.
> The rationale I have for this:
>
> 1) Zinovy pointed out that the loop vectorizer really needs the input loops to still be rotated. One counter point is that perhaps we should prevent any pass from un-rotating loops?
>
> 2) I cherrypicked the core of the scalar optimization pipeline that seems like it would be relevant to code which looks like runtime checks. Things like correlated values for overlap predicates, loop invariant code, or predicates that can be unswitched out of loops. Then I added the canonicalizing passes that might be relevant given those passes.
>
> 3) I pulled the EarlyCSE from the BB vectorize stuff. Maybe it isn't relevant for SLP vectorize, no idea. I did say this was a straw man. =D
>
>
> My benchmarking has shown some modest improvements to benchmarks, but nothing huge. However, it shows only a 2% slowdown for building the 'opt' binary, which I'm actually happy with so that we can work to improve the loop vectorizer's overhead *knowing* that these passes will clean up stuff. Thoughts? I'm currently OK with this, but it's pretty borderline so I just wanted to start the discussion and see what other folks observe in their benchmarking.
>
> -Chandler
_______________________________________________
LLVM Developers mailing list
LLV...@cs.uiuc.edu http://llvm.cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
In my experience, running a late EarlyCSE produces generic speedups across the board.
-Hal
--
Hal Finkel
Assistant Computational Scientist
Leadership Computing Facility
Argonne National Laboratory
It’s great that we’re running the vectorizers late, outside CGSCC. Regarding the set of passes that we rerun, I completely agree with Arnold. Naturally, iterating over the pass pipeline produces speedups, and I understand the engineering advantage. But rerunning several expensive function passes on the slim chance that a loop was transformed is an awful design for compile time.
>> + loop-rotate
I have no concern about loop-rotate. It should be very fast.
>> loop-vectorize
>> + early-cse
Passes like loop-vectorize should be able to do their own CSE without much engineering effort.
>> + correlated-propagation
A little worried about this.
>> + instcombine
I'm *very* concerned about rerunning instcombine, but understand it may help cleanup the vectorized preheader.
>> + licm
>> + loop-unswitch
These should limited to the relevant loop nest.
>> + simplifycfg
OK if the CFG actually changed.
>> + instcombine
instcombine again! This can’t be good.
>> slp-vectorize
>> + early-cse
SLP should do its own CSE.
—
I think it’s generally useful to have an “extreme” level of optimization without much regard for compile time, and in that scenario this pipeline makes sense. But this is hardly something that should happen at -O2/-Os, unless real data shows otherwise.
If the pass manager were designed to conditionally invoke late passes triggered by certain transformation passes, that would solve my immediate concern.
Long term, I think a much better design is for function transformations to be conditionally rerun within a scope/region. For example, loop-vectorize should be able to trigger instcombine on the loop preheader, which I think is the real problem here.
-Andy
Why? I understand that it is not cheap (especially because it calls into ValueTracking a lot), but how expensive is it when it has nothing to do?
> but understand it
> may help cleanup the vectorized preheader.
>
> >> + licm
> >> + loop-unswitch
>
> These should limited to the relevant loop nest.
>
> >> + simplifycfg
>
> OK if the CFG actually changed.
>
> >> + instcombine
>
> instcombine again! This can’t be good.
>
> >> slp-vectorize
> >> + early-cse
>
> SLP should do its own CSE.
I'm not sure how much of this is reasonable. Obviously, it can do its own CSE within each vectorization tree. But across trees (where multiple independent parts of the function are vectorized), finding and reusing gather sequences, etc. is a general CSE problem, and I'm not sure how much of that we want to replicate in the SLP vectorizer.
When I switched my internal builds from using the BBVectorizer by default to using the SLP vectorizer by default, I saw a number of performance regressions (mostly not from the vectorization, but from the lack of the 'cleanup' passes, EarlyCSE and InstCombine, that were generally being run afterward). My general impression is that running these passes late in the pipeline brings general benefits.
>
> —
>
> I think it’s generally useful to have an “extreme” level of
> optimization without much regard for compile time, and in that
> scenario this pipeline makes sense. But this is hardly something
> that should happen at -O2/-Os, unless real data shows otherwise.
Doing all this only at >= -O3 does not seem unreasonable to me.
>
> If the pass manager were designed to conditionally invoke late passes
> triggered by certain transformation passes, that would solve my
> immediate concern.
>
> Long term, I think a much better design is for function
> transformations to be conditionally rerun within a scope/region. For
> example, loop-vectorize should be able to trigger instcombine on the
> loop preheader, which I think is the real problem here.
As Chandler might recall ;) -- I've made several requests that the new pass manager design specifically support this.
-Hal
>
> -Andy
>
> >> The rationale I have for this:
> >>
> >> 1) Zinovy pointed out that the loop vectorizer really needs the
> >> input loops to still be rotated. One counter point is that
> >> perhaps we should prevent any pass from un-rotating loops?
> >>
> >> 2) I cherrypicked the core of the scalar optimization pipeline
> >> that seems like it would be relevant to code which looks like
> >> runtime checks. Things like correlated values for overlap
> >> predicates, loop invariant code, or predicates that can be
> >> unswitched out of loops. Then I added the canonicalizing passes
> >> that might be relevant given those passes.
> >>
> >> 3) I pulled the EarlyCSE from the BB vectorize stuff. Maybe it
> >> isn't relevant for SLP vectorize, no idea. I did say this was a
> >> straw man. =D
> >>
> >>
> >> My benchmarking has shown some modest improvements to benchmarks,
> >> but nothing huge. However, it shows only a 2% slowdown for
> >> building the 'opt' binary, which I'm actually happy with so that
> >> we can work to improve the loop vectorizer's overhead *knowing*
> >> that these passes will clean up stuff. Thoughts? I'm currently OK
> >> with this, but it's pretty borderline so I just wanted to start
> >> the discussion and see what other folks observe in their
> >> benchmarking.
> >>
> >> -Chandler
> >
>
>
--
Hal Finkel
Assistant Computational Scientist
Leadership Computing Facility
Argonne National Laboratory
_______________________________________________
On Oct 14, 2014, at 10:28 AM, Hal Finkel <hfi...@anl.gov> wrote:+ instcombine
I'm *very* concerned about rerunning instcombine,
Why? I understand that it is not cheap (especially because it calls into ValueTracking a lot), but how expensive is it when it has nothing to do?
> I think it’s generally useful to have an “extreme” level of
> optimization without much regard for compile time, and in that
> scenario this pipeline makes sense. But this is hardly something
> that should happen at -O2/-Os, unless real data shows otherwise.
Doing all this only at >= -O3 does not seem unreasonable to me.
While I think it is not unreasonable not to do it, I also think it would be reasonable to do it. Late cleanup is currently a place where we could use some improvement.
>
>
> I actually agree that the set I proposed is on the aggressive end --
I did say 'all' ;)
> that was the point -- but we have more than 2% fluctuations in the
> optimizers' runtime from month to month. If we want to rip stuff out
> it should be because of a principled reason that it isn't going to
> help the code in that phase.
I completely agree.
-Hal
I mentioned this in another mail, but to be specific, I'm also inclined to think that, globally, it shouldn't materialize. SLP should do its own internal cleanup, per tree, but cross-tree CSE should likely be left to an actual CSE pass (or perhaps GVN at -O3, but that's another matter).
What I mean is that if we have:
entry:
br %cond, %block1, %block2
block1:
stuff in here is SLP vectorized
...
block2:
stuff in here is SLP vectorized
...
or even just:
entry:
...
stuff in here is SLP vectorized
...
stuff here is also SLP vectorized (using some of the same inputs)
...
there might be some common vector shuffles, insert/extractelement instructions, etc. that are generated in both blocks that CSE might combine. But this is a general CSE problem (especially as these things might be memory operations, and thus need to deal with memory dependency issues), and we should not have new generalized CSE logic in the vectorizers (although we could certainly think about factoring some of the current logic out into utility functions).
-Hal
On Oct 14, 2014, at 11:21 AM, Andrew Trick <atr...@apple.com> wrote:I actually agree with you in principle, but I would rather run the pass now (and avoid hacks downstream to essentially do CSE in the backend) than hold up progress on the hope of advanced on-demand CSE layers being added to the vectorizers. I don't know of anyone actually working on that, and so I'm somewhat concerned it will never materialize.
Sure, but we should also have a plan ;) -- I think this is important, and we should make sure this doesn't get dropped. I don't think that the vectorizers are the only thing for which the concept of 'cleanup' passes are relevant. The critical piece here is that, if we don't need to run a cleanup pass, we also don't need to compute any analysis passes on which the pass might depend.
While I'm in favor of the new passes, I also want us to have a plan in this area. I understand that the pass manager is being rewritten, and maybe putting effort into the old one is not worthwhile now, but the new one should certainly have a design compatible with this requirement. Chandler?
-Hal
Thanks for taking the time to explain! I wasn’t aware of the need to CSE across trees. In general, it would be great to see more comments either in the pass setup or the pass header explaining the dependencies between passes and motivation for those dependencies. Otherwise it gets hard to distinguish between coincidental vs. intentional pass order as things evolve.
-Andy
I don't think this is a prerequisite for the particular pass-manager change you're proposing, but I'd like to make sure we're on the same page regarding what should happen in the future.
> I have and will continue to push
> back on trying to add it until we at least get a sane framework for
> our *existing* pass pipelines though.
And this makes me even more convinced that we might not all be on the same page ;) -- I really would like you to clarify exactly what this means, and what it has to do with registration of cleanup passes; or to put it another way, why cleanup-pass registration is not part of bringing further sanity to the configuration.
> It's definitely something I want to see
> happen long-term.
Good.
Thanks again,
Hal
> I have and will continue to push
> back on trying to add it until we at least get a sane framework for
> our *existing* pass pipelines though.
And this makes me even more convinced that we might not all be on the same page ;) -- I really would like you to clarify exactly what this means, and what it has to do with registration of cleanup passes; or to put it another way, why cleanup-pass registration is not part of bringing further sanity to the configuration.