Script for automatic 'opt' pipeline reduction for when using the new pass-manager (NPM). Based around the '-print-pipeline-passes' option. The reduction algorithm consists of several phases (steps). Step #0: Verify that input fails with the given pipeline and make note of the error code. Step #1: Split pipeline in two starting from front and move forward as long as first pipeline exits normally and the second pipeline fails with the expected error code. Move on to step #2 with the IR from the split point and the pipeline from the second invocation. Step #2: Remove passes from end of the pipeline as long as the pipeline fails with the expected error code. Step #3: Make several sweeps over the remaining pipeline trying to remove one pass at a time. Repeat sweeps until unable to remove any more passes. Usage example: ./utils/reduce_pipeline.py --opt-binary=./build-all-Debug/bin/opt --input=input.ll --output=output.ll --passes=PIPELINE [EXTRA-OPT-ARGS ...]
Details
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
For testing the following can be tried. First re-introduce a bug in opt by reverting the following revert
commit 1fbdbb559569641f6d509b569966901c8fb02b63 Author: Florian Hahn <flo@fhahn.com> Date: Thu Sep 30 18:52:38 2021 +0100 Revert "Recommit "[SCEV] Look through single value PHIs." (take 2)" This reverts commit 764d9aa97905f202385b4f25f8d234630b4feef3. This patch exposed a few additional cases where SCEV expressions are not properly invalidated. See PR52024, PR52023.
then running
./utils/reduce_pipeline.py --opt-binary=../build-debug/bin/opt --input=bbi-60925.ll --output=test2.ll --passes='canonicalize-aliases,objc-arc-apelim,cgscc(require<no-op-cgscc>,argpromotion,invalidate<all>,no-op-cgscc),objc-arc-apelim,function(function(aa-eval,loop-mssa(lnicm,licm,loop-instsimplify,indvars,loop-idiom),loop(indvars,require<iv-users>,loop-unroll-and-jam,simple-loop-unswitch<nontrivial>,loop-unroll-full),invalidate<all>)),function(early-cse<memssa>,loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only>,early-cse<memssa>,verify<memoryssa>,loop-mssa(require<pass-instrumentation>,loop-deletion),alignment-from-assumptions)'
should result in
The following extra args will be passed to opt: [] ---Starting step #0--- -passes="canonicalize-aliases,objc-arc-apelim,cgscc(require<no-op-cgscc>,argpromotion,invalidate<all>,no-op-cgscc),objc-arc-apelim,function(function(aa-eval,loop-mssa(lnicm,licm,loop-instsimplify,indvars,loop-idiom),loop(indvars,require<iv-users>,loop-unroll-and-jam,simple-loop-unswitch<nontrivial>,loop-unroll-full),invalidate<all>)),function(early-cse<memssa>,loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only>,early-cse<memssa>,verify<memoryssa>,loop-mssa(require<pass-instrumentation>,loop-deletion),alignment-from-assumptions)" ---Starting step #1--- -passes="function(function(loop-mssa(lnicm,licm,loop-instsimplify,indvars,loop-idiom),loop(indvars,require<iv-users>,loop-unroll-and-jam,simple-loop-unswitch<nontrivial>,loop-unroll-full),invalidate<all>)),function(early-cse<memssa>,loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only>,early-cse<memssa>,verify<memoryssa>,loop-mssa(require<pass-instrumentation>,loop-deletion),alignment-from-assumptions)" ---Starting step #2--- -passes="function(function(loop-mssa(lnicm,licm,loop-instsimplify,indvars,loop-idiom),loop(indvars,require<iv-users>,loop-unroll-and-jam,simple-loop-unswitch<nontrivial>,loop-unroll-full)))" ---Starting step #3--- -passes="function(function(loop-mssa(licm,loop-instsimplify,indvars),loop(indvars,simple-loop-unswitch<nontrivial>,loop-unroll-full)))" ---FINISHED--- Wrote output to 'test2.ll'. -passes="function(function(loop-mssa(licm,loop-instsimplify,indvars),loop(indvars,simple-loop-unswitch<nontrivial>,loop-unroll-full)))"
We could have a test by passing a fake --opt-binary that checks the -passes it receives and returns 0 or 1 by checking that some arbitrary set of passes is in the -passes pipeline
I've done https://reviews.llvm.org/D107184 before, basically put tests in their own directory.
Ok, cool. I guess it is sufficient to have the tests separated like that since they only need to be run when changes are made to the script.
Something like this and then perhaps add a few more tests and documenting them a bit?
Great to see progress on this! For a bit of extra convenience, it might be helpful to accept -passes=defaults<O3> & co and automatically translate that to the explicit pass invocation.
One can always do e.g. ./utils/reduce_pipeline.py --opt-binary=../build-debug/bin/opt --input=bbi-60925.ll --output=test2.ll --passes=$(../build-debug/bin/opt -passes='default<O3>' -print-pipeline-passes -disable-output bbi-60925.ll) but I agree that is a bit inconvenient and requires a bit of redundant typing.
Maybe it is worth it to have the script automatically invoke opt one time at the start to expand the pipeline with -print-pipeline-passes, if the pipeline is already expanded it should simply be an identity operation.
Added option for automatic expansion of default pipelines. E.g. now one can do
./utils/reduce_pipeline.py --opt-binary=../build-debug/bin/opt --input=bbi-60925.ll --output=test2.ll --passes='default<O3>' --expand-passes
and that will expand the pipeline (using a separate opt invocation with -print-pipeline-passes) before starting the reduction. In this particular case there will be no reduction as the crash does not reproduce with the default pipeline but that is a different matter. One test has been added for the expansion using fake_opt.py.
I think automatically doing this would be a bit simpler, but not a huge deal