OLD | NEW |
1 #!/usr/bin/env python2 | 1 #!/usr/bin/env python2 |
2 | 2 |
3 import argparse | 3 import argparse |
4 import itertools | 4 import itertools |
5 import subprocess | |
6 import re | 5 import re |
7 | 6 |
8 if __name__ == '__main__': | 7 if __name__ == '__main__': |
9 """Runs llvm2ice on an input .ll file, and compares the output | 8 """Compares a LLVM file with a subzero file for differences. |
10 against the input. | |
11 | 9 |
12 Before comparing, the input file is massaged to remove comments, | 10 Before comparing, the LLVM file is massaged to remove comments, |
13 blank lines, global variable definitions, external function | 11 blank lines, global variable definitions, external function |
14 declarations, and possibly other patterns that llvm2ice does not | 12 declarations, and possibly other patterns that llvm2ice does not |
15 handle. | 13 handle. |
16 | 14 |
17 The output file and the massaged input file are compared line by | 15 The subzero file and the massaged LLVM file are compared line by |
18 line for differences. However, there is a regex defined such that | 16 line for differences. However, there is a regex defined such that |
19 if the regex matches a line in the input file, that line and the | 17 if the regex matches a line in the LLVM file, that line and the |
20 corresponding line in the output file are ignored. This lets us | 18 corresponding line in the subzero file are ignored. This lets us |
21 ignore minor differences such as inttoptr and ptrtoint, and | 19 ignore minor differences such as inttoptr and ptrtoint, and |
22 printing of floating-point constants. | 20 printing of floating-point constants. |
23 | 21 |
24 On success, no output is produced. On failure, each mismatch is | 22 On success, no output is produced. On failure, each mismatch is |
25 printed as two lines, one starting with 'SZ' and one starting with | 23 printed as two lines, one starting with 'SZ' (subzero) and one |
26 'LL'. | 24 starting with 'LL' (LLVM). |
27 """ | 25 """ |
28 desc = 'Compare llvm2ice output against bitcode input.' | 26 desc = 'Compare LLVM and subzero bitcode files.' |
29 argparser = argparse.ArgumentParser(description=desc) | 27 argparser = argparse.ArgumentParser(description=desc) |
30 argparser.add_argument( | 28 argparser.add_argument( |
31 'llfile', nargs='?', default='-', | 29 'llfile', nargs=1, |
32 type=argparse.FileType('r'), metavar='FILE', | 30 type=argparse.FileType('r'), metavar='LLVM_FILE', |
33 help='Textual bitcode file [default stdin]') | 31 help='LLVM bitcode file') |
34 argparser.add_argument( | 32 argparser.add_argument( |
35 '--llvm2ice', required=False, default='./llvm2ice', metavar='LLVM2ICE', | 33 'szfile', nargs='?', default='-', |
36 help='Path to llvm2ice driver program [default ./llvm2ice]') | 34 type=argparse.FileType('r'), metavar='SUBZERO_FILE', |
| 35 help='Subzero bitcode file [default stdin]') |
37 args = argparser.parse_args() | 36 args = argparser.parse_args() |
38 bitcode = args.llfile.readlines() | 37 bitcode = args.llfile[0].readlines() |
39 | 38 sz_out = [ line.rstrip() for line in args.szfile.readlines()] |
40 # Run llvm2ice and collect its output lines into sz_out. | |
41 command = [args.llvm2ice, '-verbose', 'inst', '-notranslate', '-'] | |
42 p = subprocess.Popen(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE) | |
43 sz_out = p.communicate(input=''.join(bitcode))[0].splitlines() | |
44 | 39 |
45 # Filter certain lines and patterns from the input, and collect | 40 # Filter certain lines and patterns from the input, and collect |
46 # the remainder into llc_out. | 41 # the remainder into llc_out. |
47 llc_out = [] | 42 llc_out = [] |
48 tail_call = re.compile(' tail call '); | 43 tail_call = re.compile(' tail call '); |
49 trailing_comment = re.compile(';.*') | 44 trailing_comment = re.compile(';.*') |
50 ignore_pattern = re.compile('^ *$|^declare|^@') | 45 ignore_pattern = re.compile('^ *$|^declare|^@') |
51 for line in bitcode: | 46 for line in bitcode: |
52 # Convert tail call into regular (non-tail) call. | 47 # Convert tail call into regular (non-tail) call. |
53 line = tail_call.sub(' call ', line) | 48 line = tail_call.sub(' call ', line) |
54 # Remove trailing comments and spaces. | 49 # Remove trailing comments and spaces. |
55 line = trailing_comment.sub('', line).rstrip() | 50 line = trailing_comment.sub('', line).rstrip() |
56 # Ignore blanks lines, forward declarations, and variable definitions. | 51 # Ignore blanks lines, forward declarations, and variable definitions. |
57 if not ignore_pattern.search(line): | 52 if not ignore_pattern.search(line): |
58 llc_out.append(line) | 53 llc_out.append(line) |
59 | 54 |
60 # Compare sz_out and llc_out line by line, but ignore pairs of | 55 # Compare sz_out and llc_out line by line, but ignore pairs of |
61 # lines where the llc line matches a certain pattern. | 56 # lines where the llc line matches a certain pattern. |
62 return_code = 0 | 57 return_code = 0 |
63 lines_total = 0 | 58 lines_total = 0 |
64 lines_diff = 0 | 59 lines_diff = 0 |
65 ignore_pattern = re.compile( | 60 ignore_pattern = re.compile( |
66 '|'.join([' -[0-9]', # negative constants | 61 '|'.join([' -[0-9]', # negative constants |
67 ' (float|double) [-0-9]', # FP constants | 62 ' (float|double) [-0-9]', # FP constants |
68 ' (float|double) %\w+, [-0-9]', | 63 ' (float|double) %\w+, [-0-9]', |
69 ' inttoptr ', # inttoptr pointer types | 64 ' inttoptr ', # inttoptr pointer types |
70 ' ptrtoint ' # ptrtoint pointer types | 65 ' ptrtoint ', # ptrtoint pointer types |
| 66 ' bitcast .*\* .* to .*\*' # bitcast pointer types |
71 ])) | 67 ])) |
72 for (sz_line, llc_line) in itertools.izip_longest(sz_out, llc_out): | 68 for (sz_line, llc_line) in itertools.izip_longest(sz_out, llc_out): |
73 lines_total += 1 | 69 lines_total += 1 |
74 if sz_line == llc_line: | 70 if sz_line == llc_line: |
75 continue | 71 continue |
76 if llc_line and ignore_pattern.search(llc_line): | 72 if llc_line and ignore_pattern.search(llc_line): |
77 lines_diff += 1 | 73 lines_diff += 1 |
78 continue | 74 continue |
79 if sz_line: print 'SZ>' + sz_line | 75 if sz_line: print 'SZ>' + sz_line |
80 if llc_line: print 'LL>' + llc_line | 76 if llc_line: print 'LL>' + llc_line |
81 return_code = 1 | 77 return_code = 1 |
82 | 78 |
83 if return_code == 0: | 79 if return_code == 0: |
84 message = 'Success (ignored %d diffs out of %d lines)' | 80 message = 'Success (ignored %d diffs out of %d lines)' |
85 print message % (lines_diff, lines_total) | 81 print message % (lines_diff, lines_total) |
86 exit(return_code) | 82 exit(return_code) |
OLD | NEW |