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