| #!/usr/bin/env python2 | 
 |  | 
 | import argparse | 
 | import os | 
 | import re | 
 | import subprocess | 
 | import sys | 
 | import tempfile | 
 |  | 
 | from utils import shellcmd | 
 | from utils import FindBaseNaCl | 
 |  | 
 | if __name__ == '__main__': | 
 |     """Builds a cross-test binary that allows functions translated by | 
 |     Subzero and llc to be compared. | 
 |  | 
 |     Each --test argument is compiled once by llc and once by Subzero. | 
 |     C/C++ tests are first compiled down to PNaCl bitcode by the | 
 |     build-pnacl-ir.py script.  The --prefix argument ensures that | 
 |     symbol names are different between the two object files, to avoid | 
 |     linking errors. | 
 |  | 
 |     There is also a --driver argument that specifies the C/C++ file | 
 |     that calls the test functions with a variety of interesting inputs | 
 |     and compares their results. | 
 |     """ | 
 |     # arch_map maps a Subzero target string to an llvm-mc -arch string. | 
 |     arch_map = { 'x8632':'x86', 'x8664':'x86-64', 'arm':'arm' } | 
 |     desc = 'Build a cross-test that compares Subzero and llc translation.' | 
 |     argparser = argparse.ArgumentParser(description=desc) | 
 |     argparser.add_argument('--test', required=True, action='append', | 
 |                            metavar='TESTFILE_LIST', | 
 |                            help='List of C/C++/.ll files with test functions') | 
 |     argparser.add_argument('--driver', required=True, | 
 |                            metavar='DRIVER', | 
 |                            help='Driver program') | 
 |     argparser.add_argument('--target', required=False, default='x8632', | 
 |                            choices=arch_map.keys(), | 
 |                            metavar='TARGET', | 
 |                            help='Translation target architecture.' + | 
 |                                 ' Default %(default)s.') | 
 |     argparser.add_argument('-O', required=False, default='2', dest='optlevel', | 
 |                            choices=['m1', '-1', '0', '1', '2'], | 
 |                            metavar='OPTLEVEL', | 
 |                            help='Optimization level ' + | 
 |                                 '(m1 and -1 are equivalent).' + | 
 |                                 ' Default %(default)s.') | 
 |     argparser.add_argument('--mattr',  required=False, default='sse2', | 
 |                            dest='attr', choices=['sse2', 'sse4.1'], | 
 |                            metavar='ATTRIBUTE', | 
 |                            help='Target attribute. Default %(default)s.') | 
 |     argparser.add_argument('--prefix', required=True, | 
 |                            metavar='SZ_PREFIX', | 
 |                            help='String prepended to Subzero symbol names') | 
 |     argparser.add_argument('--output', '-o', required=True, | 
 |                            metavar='EXECUTABLE', | 
 |                            help='Executable to produce') | 
 |     argparser.add_argument('--dir', required=False, default='.', | 
 |                            metavar='OUTPUT_DIR', | 
 |                            help='Output directory for all files.' + | 
 |                                 ' Default "%(default)s".') | 
 |     argparser.add_argument('--crosstest-bitcode', required=False, | 
 |                            default=1, type=int, | 
 |                            help='Compile non-subzero crosstest object file ' + | 
 |                            'from the same bitcode as the subzero object. ' + | 
 |                            'If 0, then compile it straight from source.' + | 
 |                            ' Default %(default)d.') | 
 |     args = argparser.parse_args() | 
 |  | 
 |     nacl_root = FindBaseNaCl() | 
 |     # Prepend host_x86_32/bin to $PATH. | 
 |     os.environ['PATH'] = nacl_root + \ | 
 |         '/toolchain/linux_x86/pnacl_newlib/host_x86_32/bin' + \ | 
 |         os.pathsep + os.environ['PATH'] | 
 |  | 
 |     objs = [] | 
 |     remove_internal = re.compile('^define internal ') | 
 |     fix_target = re.compile('le32-unknown-nacl') | 
 |     for arg in args.test: | 
 |         base, ext = os.path.splitext(arg) | 
 |         if ext == '.ll': | 
 |             bitcode = arg | 
 |         else: | 
 |             bitcode = os.path.join(args.dir, base + '.pnacl.ll') | 
 |             shellcmd(['../pydir/build-pnacl-ir.py', '--disable-verify', | 
 |                       '--dir', args.dir, arg]) | 
 |             # Read in the bitcode file, fix it up, and rewrite the file. | 
 |             f = open(bitcode) | 
 |             ll_lines = f.readlines() | 
 |             f.close() | 
 |             f = open(bitcode, 'w') | 
 |             for line in ll_lines: | 
 |                 line = remove_internal.sub('define ', line) | 
 |                 line = fix_target.sub('i686-pc-linux-gnu', line) | 
 |                 f.write(line) | 
 |             f.close() | 
 |  | 
 |         base_sz = '%s.O%s.%s' % (base, args.optlevel, args.target) | 
 |         asm_sz = os.path.join(args.dir, base_sz + '.sz.s') | 
 |         obj_sz = os.path.join(args.dir, base_sz + '.sz.o') | 
 |         obj_llc = os.path.join(args.dir, base + '.llc.o') | 
 |         shellcmd(['../llvm2ice', | 
 |                   '-O' + args.optlevel, | 
 |                   '-mattr=' + args.attr, | 
 |                   '--target=' + args.target, | 
 |                   '--prefix=' + args.prefix, | 
 |                   '-o=' + asm_sz, | 
 |                   bitcode]) | 
 |         shellcmd(['llvm-mc', | 
 |                   '-arch=' + arch_map[args.target], | 
 |                   '-x86-asm-syntax=intel', | 
 |                   '-filetype=obj', | 
 |                   '-o=' + obj_sz, | 
 |                   asm_sz]) | 
 |         objs.append(obj_sz) | 
 |         # Each original bitcode file needs to be translated by the | 
 |         # LLVM toolchain and have its object file linked in.  There | 
 |         # are two ways to do this: explicitly use llc, or include the | 
 |         # .ll file in the link command.  It turns out that these two | 
 |         # approaches can produce different semantics on some undefined | 
 |         # bitcode behavior.  Specifically, LLVM produces different | 
 |         # results for overflowing fptoui instructions for i32 and i64 | 
 |         # on x86-32.  As it turns out, Subzero lowering was based on | 
 |         # inspecting the object code produced by the direct llc | 
 |         # command, so we need to directly run llc on the bitcode, even | 
 |         # though it makes this script longer, to avoid spurious | 
 |         # failures.  This behavior can be inspected by switching | 
 |         # use_llc between True and False. | 
 |         use_llc = False | 
 |         pure_c = os.path.splitext(args.driver)[1] == '.c' | 
 |         if not args.crosstest_bitcode: | 
 |             objs.append(arg) | 
 |         elif use_llc: | 
 |             shellcmd(['llc' | 
 |                       '-filetype=obj', | 
 |                       '-o=' + obj_llc, | 
 |                       bitcode]) | 
 |             objs.append(obj_llc) | 
 |         else: | 
 |             objs.append(bitcode) | 
 |  | 
 |     # Use 'clang szrt.c'  -or-  'clang++ szrt.cpp' | 
 |     objs.append(( | 
 |             '{root}/toolchain_build/src/subzero/runtime/szrt.{ext}' | 
 |             ).format(root=nacl_root, ext='c' if pure_c else 'cpp')) | 
 |     linker = 'clang' if pure_c else 'clang++' | 
 |     shellcmd([linker, '-g', '-m32', args.driver] + | 
 |              objs + | 
 |              ['-lm', '-lpthread', '-o', os.path.join(args.dir, args.output)]) |