| OLD | NEW |
| (Empty) |
| 1 #!/usr/bin/env python2 | |
| 2 | |
| 3 import argparse | |
| 4 import os | |
| 5 import re | |
| 6 import subprocess | |
| 7 import sys | |
| 8 import tempfile | |
| 9 | |
| 10 sys.path.insert(0, '../pydir') | |
| 11 from utils import shellcmd | |
| 12 from utils import FindBaseNaCl | |
| 13 | |
| 14 if __name__ == '__main__': | |
| 15 """Builds a cross-test binary that allows functions translated by | |
| 16 Subzero and llc to be compared. | |
| 17 | |
| 18 Each --test argument is compiled once by llc and once by Subzero. | |
| 19 C/C++ tests are first compiled down to PNaCl bitcode by the | |
| 20 build-pnacl-ir.py script. The --prefix argument ensures that | |
| 21 symbol names are different between the two object files, to avoid | |
| 22 linking errors. | |
| 23 | |
| 24 There is also a --driver argument that specifies the C/C++ file | |
| 25 that calls the test functions with a variety of interesting inputs | |
| 26 and compares their results. | |
| 27 """ | |
| 28 # arch_map maps a Subzero target string to an llvm-mc -arch string. | |
| 29 arch_map = { 'x8632':'x86', 'x8664':'x86-64', 'arm':'arm' } | |
| 30 desc = 'Build a cross-test that compares Subzero and llc translation.' | |
| 31 argparser = argparse.ArgumentParser(description=desc) | |
| 32 argparser.add_argument('--test', required=True, action='append', | |
| 33 metavar='TESTFILE_LIST', | |
| 34 help='List of C/C++/.ll files with test functions') | |
| 35 argparser.add_argument('--driver', required=True, | |
| 36 metavar='DRIVER', | |
| 37 help='Driver program') | |
| 38 argparser.add_argument('--target', required=False, default='x8632', | |
| 39 choices=arch_map.keys(), | |
| 40 metavar='TARGET', | |
| 41 help='Translation target architecture') | |
| 42 argparser.add_argument('-O', required=False, default='2', dest='optlevel', | |
| 43 choices=['m1', '-1', '0', '1', '2'], | |
| 44 metavar='OPTLEVEL', | |
| 45 help='Optimization level ' + | |
| 46 '(m1 and -1 are equivalent)') | |
| 47 argparser.add_argument('--mattr', required=False, default='sse2', | |
| 48 dest='attr', choices=['sse2', 'sse4.1'], | |
| 49 metavar='ATTRIBUTE', help='Target attribute') | |
| 50 argparser.add_argument('--prefix', required=True, | |
| 51 metavar='SZ_PREFIX', | |
| 52 help='String prepended to Subzero symbol names') | |
| 53 argparser.add_argument('--output', '-o', required=True, | |
| 54 metavar='EXECUTABLE', | |
| 55 help='Executable to produce') | |
| 56 argparser.add_argument('--dir', required=False, default='.', | |
| 57 metavar='OUTPUT_DIR', | |
| 58 help='Output directory for all files') | |
| 59 argparser.add_argument('--crosstest-bitcode', required=False, | |
| 60 default=1, type=int, | |
| 61 help='Compile non-subzero crosstest object file ' + | |
| 62 'from the same bitcode as the subzero object. ' + | |
| 63 'If 0, then compile it straight from source.') | |
| 64 args = argparser.parse_args() | |
| 65 | |
| 66 nacl_root = FindBaseNaCl() | |
| 67 # Prepend host_x86_32/bin to $PATH. | |
| 68 os.environ['PATH'] = nacl_root + \ | |
| 69 '/toolchain/linux_x86/pnacl_newlib/host_x86_32/bin' + \ | |
| 70 os.pathsep + os.environ['PATH'] | |
| 71 | |
| 72 objs = [] | |
| 73 remove_internal = re.compile('^define internal ') | |
| 74 fix_target = re.compile('le32-unknown-nacl') | |
| 75 for arg in args.test: | |
| 76 base, ext = os.path.splitext(arg) | |
| 77 if ext == '.ll': | |
| 78 bitcode = arg | |
| 79 else: | |
| 80 bitcode = os.path.join(args.dir, base + '.pnacl.ll') | |
| 81 shellcmd(['../pydir/build-pnacl-ir.py', '--disable-verify', | |
| 82 '--dir', args.dir, arg]) | |
| 83 # Read in the bitcode file, fix it up, and rewrite the file. | |
| 84 f = open(bitcode) | |
| 85 ll_lines = f.readlines() | |
| 86 f.close() | |
| 87 f = open(bitcode, 'w') | |
| 88 for line in ll_lines: | |
| 89 line = remove_internal.sub('define ', line) | |
| 90 line = fix_target.sub('i686-pc-linux-gnu', line) | |
| 91 f.write(line) | |
| 92 f.close() | |
| 93 | |
| 94 base_sz = '%s.O%s.%s' % (base, args.optlevel, args.target) | |
| 95 asm_sz = os.path.join(args.dir, base_sz + '.sz.s') | |
| 96 obj_sz = os.path.join(args.dir, base_sz + '.sz.o') | |
| 97 obj_llc = os.path.join(args.dir, base + '.llc.o') | |
| 98 shellcmd(['../llvm2ice', | |
| 99 '-O' + args.optlevel, | |
| 100 '-mattr=' + args.attr, | |
| 101 '--target=' + args.target, | |
| 102 '--prefix=' + args.prefix, | |
| 103 '-o=' + asm_sz, | |
| 104 bitcode]) | |
| 105 shellcmd(['llvm-mc', | |
| 106 '-arch=' + arch_map[args.target], | |
| 107 '-x86-asm-syntax=intel', | |
| 108 '-filetype=obj', | |
| 109 '-o=' + obj_sz, | |
| 110 asm_sz]) | |
| 111 objs.append(obj_sz) | |
| 112 # Each original bitcode file needs to be translated by the | |
| 113 # LLVM toolchain and have its object file linked in. There | |
| 114 # are two ways to do this: explicitly use llc, or include the | |
| 115 # .ll file in the link command. It turns out that these two | |
| 116 # approaches can produce different semantics on some undefined | |
| 117 # bitcode behavior. Specifically, LLVM produces different | |
| 118 # results for overflowing fptoui instructions for i32 and i64 | |
| 119 # on x86-32. As it turns out, Subzero lowering was based on | |
| 120 # inspecting the object code produced by the direct llc | |
| 121 # command, so we need to directly run llc on the bitcode, even | |
| 122 # though it makes this script longer, to avoid spurious | |
| 123 # failures. This behavior can be inspected by switching | |
| 124 # use_llc between True and False. | |
| 125 use_llc = False | |
| 126 if not args.crosstest_bitcode: | |
| 127 objs.append(arg) | |
| 128 elif use_llc: | |
| 129 shellcmd(['llc' | |
| 130 '-filetype=obj', | |
| 131 '-o=' + obj_llc, | |
| 132 bitcode]) | |
| 133 objs.append(obj_llc) | |
| 134 else: | |
| 135 objs.append(bitcode) | |
| 136 | |
| 137 linker = 'clang' if os.path.splitext(args.driver)[1] == '.c' else 'clang++' | |
| 138 shellcmd([linker, '-g', '-m32', args.driver] + | |
| 139 objs + | |
| 140 ['-lm', '-lpthread', '-o', os.path.join(args.dir, args.output)]) | |
| OLD | NEW |