Markus Lavin 91d15aa0b8 [NPM] Automatic 'opt' pipeline reducer script.
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 ...]

Differential Revision: https://reviews.llvm.org/D110908
2021-10-06 09:09:33 +02:00

93 lines
3.4 KiB
Python
Executable File

#!/usr/bin/env python3
# Automatically formatted with yapf (https://github.com/google/yapf)
import subprocess
import unittest
def getFinalPasses(run):
stdout = run.stdout.decode()
stdout = stdout[:stdout.rfind('\n')]
stdout = stdout[stdout.rfind('\n') + 1:]
return stdout
class Test(unittest.TestCase):
def test_0(self):
"""Test all passes are removed except those required to crash. Verify
that PM structure is intact."""
run_args = [
'./utils/reduce_pipeline.py',
'--opt-binary=./utils/reduce_pipeline_test/fake_opt.py',
'--input=/dev/null', '--passes=a,b,c,A(d,B(e,f),g),h,i',
'-crash-seq=b,d,f'
]
run = subprocess.run(run_args,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
self.assertEqual(run.returncode, 0)
self.assertEqual(getFinalPasses(run), '-passes="b,A(d,B(f))"')
def test_1(self):
"""Test all passes are removed except those required to crash. The
required passes in this case are the first and last in that order
(a bit of a corner-case for the reduction algorithm)."""
run_args = [
'./utils/reduce_pipeline.py',
'--opt-binary=./utils/reduce_pipeline_test/fake_opt.py',
'--input=/dev/null', '--passes=a,b,c,A(d,B(e,f),g),h,i',
'-crash-seq=a,i'
]
run = subprocess.run(run_args,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
self.assertEqual(run.returncode, 0)
self.assertEqual(getFinalPasses(run), '-passes="a,i"')
def test_2(self):
"""Test the '--dont-expand-passes' option."""
run_args = [
'./utils/reduce_pipeline.py',
'--opt-binary=./utils/reduce_pipeline_test/fake_opt.py',
'--input=/dev/null', '--passes=a,b,c,A(d,B(e,f),g),h,i',
'-crash-seq=b,d,f', '--dont-expand-passes'
]
run = subprocess.run(run_args,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
self.assertEqual(run.returncode, 0)
self.assertEqual(getFinalPasses(run), '-passes="b,A(d,B(f))"')
def test_3(self):
"""Test that empty pass-managers get removed by default."""
run_args = [
'./utils/reduce_pipeline.py',
'--opt-binary=./utils/reduce_pipeline_test/fake_opt.py',
'--input=/dev/null', '--passes=a,b,c,A(d,B(e,f),g),h,i',
'-crash-seq=b,d,h'
]
run = subprocess.run(run_args,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
self.assertEqual(run.returncode, 0)
self.assertEqual(getFinalPasses(run), '-passes="b,A(d),h"')
def test_4(self):
"""Test the '--dont-remove-empty-pm' option."""
run_args = [
'./utils/reduce_pipeline.py',
'--opt-binary=./utils/reduce_pipeline_test/fake_opt.py',
'--input=/dev/null', '--passes=a,b,c,A(d,B(e,f),g),h,i',
'-crash-seq=b,d,h', '--dont-remove-empty-pm'
]
run = subprocess.run(run_args,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
self.assertEqual(run.returncode, 0)
self.assertEqual(getFinalPasses(run), '-passes="b,A(d,B()),h"')
unittest.main()
exit(0)