llvm-project/polly/utils/pollycc

404 lines
13 KiB
Python
Executable File

#!/usr/bin/env python
import argparse
import subprocess
import tempfile
import os
import sys
def createAssemblyFile(tmpDir, file, number, args, polly):
# Check if file exists
if not os.path.isfile(file):
print "File '" + file + "' does not exist. Compilation aborted."
sys.exit(1)
# Create an LLVM-IR .ll file
tmpDir = tmpDir + "/" + str(number)
subprocess.call(["mkdir", tmpDir])
llFile = tmpDir + '/output.ll'
includeFlags = ['-I' + x for x in args.includes]
preprocessorFlags = ['-D' + x for x in args.preprocessor]
if args.progress:
print "Optimizing file: " + file
print "- Compiling C to LLVM-IR"
commandLine = ["clang","-emit-llvm", "-S", file, '-o', llFile,
'-std=' + args.standard] + includeFlags + preprocessorFlags \
+ args.unknown_args
if args.commands:
print ' '.join(commandLine)
exit = subprocess.call(commandLine)
if exit:
print 'Translation from C to LLVM-IR failed. This command did not work:'
print ' '.join(commandLine)
sys.exit(1)
# Preprocess the programm such that as many optimization opportunities
# as possible are exposed.
preoptFile = tmpDir + '/output.preopt.ll'
preoptPasses = '-basicaa -mem2reg -simplify-libcalls ' \
'-simplifycfg -instcombine -tailcallelim -loop-simplify ' \
'-lcssa -loop-rotate -lcssa -loop-unswitch -instcombine ' \
'-loop-simplify -lcssa -indvars -loop-deletion -instcombine ' \
'-polly-prepare -polly-region-simplify -indvars'
if args.progress:
print "- Preoptimizing to expose optimization opportunities"
commandLine = ['opt', '-load', polly] + preoptPasses.split(' ') \
+ ['-S', llFile, '-o', preoptFile]
if args.commands:
print ' '.join(commandLine)
exit = subprocess.call(commandLine)
if exit:
print 'Preoptimizing failed: This command did not work'
print ' '.join(commandLine)
sys.exit(1)
# Run the Polly optimizers
pollyFile = tmpDir + '/output.polly.ll'
if args.view or args.viewonly:
commandLine = ['opt', '-load', polly, '-basicaa'] \
+ [preoptFile, '-disable-output']
if args.view:
commandLine.append('-view-scops')
else:
commandLine.append('-view-scops-only')
if args.commands:
print ' '.join(commandLine)
exit = subprocess.call(commandLine)
if exit:
print 'Polly optimizations failed: This command did not work'
print ' '.join(commandLine)
sys.exit(1)
if args.fpolly:
commandLine = ['opt', '-load', polly, '-basicaa'] \
+ [preoptFile, '-disable-polly-legality']
if args.pollyimport:
commandLine.append('-polly-import-jscop')
if args.fpluto:
commandLine.append('-polly-optimize')
if args.foptimize:
commandLine.append('-polly-optimize-isl')
if args.fatLeastOnce:
commandLine.append('-enable-polly-atLeastOnce')
if args.faligned:
commandLine.append('-enable-polly-aligned')
if args.ftile:
commandLine.append('-enable-pluto-tile')
if args.pluto_fuse:
commandLine.append('-pluto-fuse')
commandLine.append(args.pluto_fuse)
if args.fparallel:
commandLine.append('-enable-polly-openmp')
if args.fvector:
commandLine.append('-enable-polly-vector')
commandLine.append('-enable-schedule-prevector')
if (args.ftile or args.fpluto):
commandLine.append('-enable-pluto-prevector')
if args.pollyexport:
commandLine.append('-polly-export-jscop')
if args.debug:
debugCommandLine = commandLine + ['-polly-cloog', '-analyze', '-q']
subprocess.call(debugCommandLine)
if args.progress:
print "- Running polly",
if args.fpluto:
print "with pluto",
if args.ftile:
print "and tiling",
if args.fparallel:
print "and parallel",
print ""
commandLine = commandLine + ['-polly-codegen', '-S', '-o', pollyFile]
if args.commands:
print ' '.join(commandLine)
exit = subprocess.call(commandLine)
if exit:
print 'Polly optimizations failed: This command did not work'
print ' '.join(commandLine)
sys.exit(1)
# Run optimizations to clean up the redundant calculations Polly introduced
# and to take advantage of non polyhedral optimizations.
optFile = tmpDir + '/output.opt.ll'
commandLine = ['opt', '-S', '-o', optFile + "tmp"]
commandLine2 = ['opt', '-S', '-o', optFile]
if args.optlevel != '0':
commandLine.append('-O' + args.optlevel)
commandLine2.append('-O' + args.optlevel)
if args.fpolly:
commandLine.append(pollyFile)
else:
commandLine.append(preoptFile)
commandLine2.append(optFile + "tmp");
if args.progress:
print "- Running normal LLVM -O3 passes"
exit = subprocess.call(commandLine)
if exit:
print 'LLVM -O3 optimizations failed: This command did not work'
print ' '.join(commandLine)
sys.exit(1)
exit = subprocess.call(commandLine2)
if exit:
print 'LLVM -O3 optimizations failed: This command did not work'
print ' '.join(commandLine)
sys.exit(1)
if args.emitllvm:
return optFile
# Create assembly file
assemblyFile = tmpDir + '/output.opt.s'
commandLine = ['llc', optFile, '-o', assemblyFile]
if args.progress:
print "- Translating LLVM-IR to assembly"
subprocess.call(commandLine)
if exit:
print 'Translating LLVM-IR to assembly failed: This command did not work'
print ' '.join(commandLine)
sys.exit(1)
return assemblyFile
def parseArguments():
description = 'pollycc is a simple replacement for compiler drivers like ' \
'gcc, clang or icc. It uses clang to compile C code and can ' \
'optimize the code with Polly. It will either produce an ' \
'optimized binary or an optimized \'.o\' file.'
parser = argparse.ArgumentParser(description=description)
parser.add_argument('files', nargs='+')
parser.add_argument('-o', dest='output', help='the name of the output file')
parser.add_argument('-I', action='append', dest='includes', default=[],
help='include path to pass to clang')
parser.add_argument('-D', action='append', dest='preprocessor', default=[],
help='preprocessor directives to pass to clang')
parser.add_argument('-l', action='append', dest='libraries', default=[],
help='library flags to pass to the linker')
parser.add_argument('-L', action='append', dest='librarypath', default=[],
help='library paths to pass to the linker')
parser.add_argument('-O', dest='optlevel', choices='0123s', default='3',
help='optimization level.')
parser.add_argument('-S', action='store_true',
help='compile only; do not link or assemble')
parser.add_argument('-emit-llvm', action='store_true', dest='emitllvm',
help='output LLVM-IR instead of assembly if -S is set')
parser.add_argument('-std', dest='standard', help='The C standard to use',
default='gnu89')
parser.add_argument('-p', '--progress', action='store_true',
help='Show the compilation progress')
parser.add_argument('-c', action='store_true',
help='compile and assemble, but do not link')
parser.add_argument('-fpolly', help='enable polly', action='store_true')
parser.add_argument('-fpluto', help='enable pluto', action='store_true')
parser.add_argument('-fpluto-fuse', dest='pluto_fuse', help='enable pluto')
parser.add_argument('-foptimize',
help='Optimize schedule with isl pluto like algorithm',
action='store_true')
parser.add_argument('-faligned', help='Assume aligned vector accesses',
action='store_true')
parser.add_argument('-fatLeastOnce',
help='Assume all loops are executed at least once',
action='store_true')
parser.add_argument('-fview-scops', dest='view',
help='Show the scops with graphviz',
action='store_true')
parser.add_argument('-fview-scops-only', dest='viewonly',
help='Show the scops with graphviz (Only Basic Blocks)',
action='store_true')
parser.add_argument('-ftile', '-fpluto-tile',
help='enable pluto tiling', action='store_true')
parser.add_argument('-fparallel',
help='enable openmp code generation (in development)',
action='store_true')
parser.add_argument('-fvector',
help='enable SIMD code generation (in development)',
action='store_true')
parser.add_argument('-fpolly-export', dest='pollyexport',
help='Export Polly jscop', action='store_true')
parser.add_argument('-fpolly-import', dest='pollyimport',
help='Import Polly jscop', action='store_true')
parser.add_argument('-commands', help='print command lines executed',
action='store_true')
parser.add_argument('-d', '--debug', help='print debugging output',
action='store_true')
parser.add_argument('-v', '--version', dest='version', action='store_true',
help='print version info')
arguments, argv = parser.parse_known_args()
if argv:
arguments.unknown_args = filter(lambda x: x[0] == '-', argv)
arguments.files = arguments.files + filter(lambda x: x[0] != '-', argv)
if arguments.unknown_args:
print 'warning: The following arguments are unknown and will \n' \
' be passed directly to clang: ' + \
' '.join(arguments.unknown_args)
else:
arguments.unknown_args = []
# Post process arguments
if arguments.ftile:
arguments.fpluto = True
if arguments.pollyimport:
arguments.fpolly = True
if arguments.view or arguments.viewonly:
arguments.fpolly = True
if arguments.fpluto:
arguments.fpolly = True
if arguments.foptimize:
arguments.fpolly = True
return arguments
def createAssemblyFiles(files, args, pollyLib):
assemblyFiles = []
tmpDir = tempfile.mkdtemp(prefix='pollycc-');
number = 0
for file in args.files:
assemblyFiles.append(createAssemblyFile(tmpDir, file, number, args, pollyLib))
if args.progress:
print ""
number = number + 1
return assemblyFiles
def createOutputFiles(assemblyFiles, args):
if args.output:
outputFile = args.output
elif len(args.files) == 1 and args.c:
outputFile = args.files[0].replace('.c', '.o')
elif len(args.files) == 1 and args.S:
outputFile = args.files[0].replace('.c', '.s')
else:
outputFile = 'a.out'
linkerFlags = ['-l' + x for x in args.libraries]
libraryPath = ['-L' + x for x in args.librarypath]
commandLine = ['gcc', '-o', outputFile] + assemblyFiles
if args.S:
subprocess.call(['mv', assemblyFiles[0], outputFile])
return
if args.c:
commandLine.append('-c')
else:
commandLine = commandLine + linkerFlags + libraryPath
if args.fparallel:
commandLine.append('-lgomp')
if args.progress:
print "Final linking"
subprocess.call(commandLine)
def checkExecutables(pollyLib, pluto):
commandLine = ['opt', '-load', pollyLib, '-help']
try:
proc = subprocess.Popen(commandLine, stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdout_value = proc.communicate()[0]
if not stdout_value.count('polly-prepare'):
sys.exit('Polly support not available in opt')
if pluto and not stdout_value.count('Optimize the scop using pocc'):
sys.exit('Polly compiled without POCC/Pluto support. -ftile and -fpluto'
' will not work.')
except OSError:
print 'error: opt cannot be executed: '
print 'failing command: \n' + " ".join(commandLine)
sys.exit(1)
commandLine = ['clang', '-v']
try:
subprocess.call(commandLine, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
except OSError:
print 'error: clang cannot be executed: '
print 'failing command: \n' + " ".join(commandLine)
sys.exit(1)
commandLine = ['lli', '-help']
try:
subprocess.call(commandLine, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
except OSError:
print 'error: lli cannot be executed: '
print 'failing command: \n' + " ".join(commandLine)
sys.exit(1)
def main():
args = parseArguments()
if not 'LIBPOLLY' in os.environ:
sys.exit('Polly library not provided. Please set LIBPOLLY environment ' + \
'variable to the LLVMPolly.so file')
pollyLib = os.environ['LIBPOLLY']
checkExecutables(pollyLib, args.fpluto)
assemblyFiles = createAssemblyFiles(args.files, args, pollyLib)
createOutputFiles(assemblyFiles, args)
if __name__ == '__main__':
main()