#!/usr/bin/env python3

# Automatically formatted with yapf (https://github.com/google/yapf)

# 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:
# reduce_pipeline.py --opt-binary=./build-all-Debug/bin/opt --input=input.ll --output=output.ll --passes=PIPELINE [EXTRA-OPT-ARGS ...]

import argparse
import pipeline
import shutil
import subprocess
import tempfile

parser = argparse.ArgumentParser(
    description=
    'Automatic opt pipeline reducer. Unrecognized arguments are forwarded to opt.'
)
parser.add_argument('--opt-binary',
                    action='store',
                    dest='opt_binary',
                    default='opt')
parser.add_argument('--passes', action='store', dest='passes', required=True)
parser.add_argument('--input', action='store', dest='input', required=True)
parser.add_argument('--output', action='store', dest='output')
parser.add_argument('--dont-expand-passes',
                    action='store_true',
                    dest='dont_expand_passes',
                    help='Do not expand pipeline before starting reduction.')
parser.add_argument(
    '--dont-remove-empty-pm',
    action='store_true',
    dest='dont_remove_empty_pm',
    help='Do not remove empty pass-managers from the pipeline during reduction.'
)
[args, extra_opt_args] = parser.parse_known_args()

print('The following extra args will be passed to opt: {}'.format(
    extra_opt_args))

lst = pipeline.fromStr(args.passes)
ll_input = args.input

# Step #-1
# Launch 'opt' once with '-print-pipeline-passes' to expand pipeline before
# starting reduction. Allows specifying a default pipelines (e.g.
# '-passes=default<O3>').
if not args.dont_expand_passes:
    run_args = [
        args.opt_binary, '-disable-symbolication', '-disable-output',
        '-print-pipeline-passes', '-passes={}'.format(pipeline.toStr(lst)),
        ll_input
    ]
    run_args.extend(extra_opt_args)
    opt = subprocess.run(run_args,
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE)
    if opt.returncode != 0:
        print('Failed to expand passes. Aborting.')
        print(run_args)
        print('exitcode: {}'.format(opt.returncode))
        print(opt.stderr.decode())
        exit(1)
    stdout = opt.stdout.decode()
    stdout = stdout[:stdout.rfind('\n')]
    lst = pipeline.fromStr(stdout)
    print('Expanded pass sequence: {}'.format(pipeline.toStr(lst)))

# Step #0
# Confirm that the given input, passes and options result in failure.
print('---Starting step #0---')
run_args = [
    args.opt_binary, '-disable-symbolication', '-disable-output',
    '-passes={}'.format(pipeline.toStr(lst)), ll_input
]
run_args.extend(extra_opt_args)
opt = subprocess.run(run_args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
if opt.returncode >= 0:
    print('Input does not result in failure as expected. Aborting.')
    print(run_args)
    print('exitcode: {}'.format(opt.returncode))
    print(opt.stderr.decode())
    exit(1)

expected_error_returncode = opt.returncode
print('-passes="{}"'.format(pipeline.toStr(lst)))

# Step #1
# Try to narrow down the failing pass sequence by splitting the pipeline in two
# opt invocations (A and B) starting with invocation A only running the first
# pipeline pass and invocation B the remaining. Keep moving the split point
# forward as long as invocation A exits normally and invocation B fails with
# the expected error. This will accomplish two things first the input IR will be
# further reduced and second, with that IR, the reduced pipeline for invocation
# B will be sufficient to reproduce.
print('---Starting step #1---')
prevLstB = None
prevIntermediate = None
tmpd = tempfile.TemporaryDirectory()

for idx in range(pipeline.count(lst)):
    [lstA, lstB] = pipeline.split(lst, idx)
    if not args.dont_remove_empty_pm:
        lstA = pipeline.prune(lstA)
        lstB = pipeline.prune(lstB)

    intermediate = 'intermediate-0.ll' if idx % 2 else 'intermediate-1.ll'
    intermediate = tmpd.name + '/' + intermediate
    run_args = [
        args.opt_binary, '-disable-symbolication', '-S', '-o', intermediate,
        '-passes={}'.format(pipeline.toStr(lstA)), ll_input
    ]
    run_args.extend(extra_opt_args)
    optA = subprocess.run(run_args,
                          stdout=subprocess.PIPE,
                          stderr=subprocess.PIPE)
    run_args = [
        args.opt_binary, '-disable-symbolication', '-disable-output',
        '-passes={}'.format(pipeline.toStr(lstB)), intermediate
    ]
    run_args.extend(extra_opt_args)
    optB = subprocess.run(run_args,
                          stdout=subprocess.PIPE,
                          stderr=subprocess.PIPE)
    if not (optA.returncode == 0
            and optB.returncode == expected_error_returncode):
        break
    prevLstB = lstB
    prevIntermediate = intermediate
if prevLstB:
    lst = prevLstB
    ll_input = prevIntermediate
print('-passes="{}"'.format(pipeline.toStr(lst)))

# Step #2
# Try removing passes from the end of the remaining pipeline while still
# reproducing the error.
print('---Starting step #2---')
prevLstA = None
for idx in reversed(range(pipeline.count(lst))):
    [lstA, lstB] = pipeline.split(lst, idx)
    if not args.dont_remove_empty_pm:
        lstA = pipeline.prune(lstA)
    run_args = [
        args.opt_binary, '-disable-symbolication', '-disable-output',
        '-passes={}'.format(pipeline.toStr(lstA)), ll_input
    ]
    run_args.extend(extra_opt_args)
    optA = subprocess.run(run_args,
                          stdout=subprocess.PIPE,
                          stderr=subprocess.PIPE)
    if optA.returncode != expected_error_returncode:
        break
    prevLstA = lstA
if prevLstA:
    lst = prevLstA
print('-passes="{}"'.format(pipeline.toStr(lst)))

# Step #3
# Now that we have a pipeline that is reduced both front and back we do
# exhaustive sweeps over the remainder trying to remove one pass at a time.
# Repeat as long as reduction is possible.
print('---Starting step #3---')
while True:
    keepGoing = False
    for idx in range(pipeline.count(lst)):
        candLst = pipeline.remove(lst, idx)
        if not args.dont_remove_empty_pm:
            candLst = pipeline.prune(candLst)
        run_args = [
            args.opt_binary, '-disable-symbolication', '-disable-output',
            '-passes={}'.format(pipeline.toStr(candLst)), ll_input
        ]
        run_args.extend(extra_opt_args)
        opt = subprocess.run(run_args,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE)
        if opt.returncode == expected_error_returncode:
            lst = candLst
            keepGoing = True
    if not keepGoing:
        break
print('-passes="{}"'.format(pipeline.toStr(lst)))

print('---FINISHED---')
if args.output:
    shutil.copy(ll_input, args.output)
    print('Wrote output to \'{}\'.'.format(args.output))
print('-passes="{}"'.format(pipeline.toStr(lst)))
exit(0)
