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