blob: b25681f33cb2ad9ee25619dd9e81d868652fff8f [file] [log] [blame]
Jim Stichnothf7c9a142014-04-29 10:52:43 -07001#!/usr/bin/env python2
2
3import argparse
4import itertools
Jim Stichnothf7c9a142014-04-29 10:52:43 -07005import re
6
7if __name__ == '__main__':
Karl Schimpfa667fb82014-05-19 14:56:51 -07008 """Compares a LLVM file with a subzero file for differences.
Jim Stichnothf7c9a142014-04-29 10:52:43 -07009
Karl Schimpfa667fb82014-05-19 14:56:51 -070010 Before comparing, the LLVM file is massaged to remove comments,
Jim Stichnothf7c9a142014-04-29 10:52:43 -070011 blank lines, global variable definitions, external function
12 declarations, and possibly other patterns that llvm2ice does not
13 handle.
14
Karl Schimpfa667fb82014-05-19 14:56:51 -070015 The subzero file and the massaged LLVM file are compared line by
Jim Stichnothf7c9a142014-04-29 10:52:43 -070016 line for differences. However, there is a regex defined such that
Karl Schimpfa667fb82014-05-19 14:56:51 -070017 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
Jim Stichnothf7c9a142014-04-29 10:52:43 -070019 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
Karl Schimpfa667fb82014-05-19 14:56:51 -070023 printed as two lines, one starting with 'SZ' (subzero) and one
24 starting with 'LL' (LLVM).
Jim Stichnothf7c9a142014-04-29 10:52:43 -070025 """
Karl Schimpfa667fb82014-05-19 14:56:51 -070026 desc = 'Compare LLVM and subzero bitcode files.'
Jim Stichnothf7c9a142014-04-29 10:52:43 -070027 argparser = argparse.ArgumentParser(description=desc)
28 argparser.add_argument(
Karl Schimpfa667fb82014-05-19 14:56:51 -070029 'llfile', nargs=1,
30 type=argparse.FileType('r'), metavar='LLVM_FILE',
31 help='LLVM bitcode file')
Jim Stichnothf7c9a142014-04-29 10:52:43 -070032 argparser.add_argument(
Karl Schimpfa667fb82014-05-19 14:56:51 -070033 'szfile', nargs='?', default='-',
34 type=argparse.FileType('r'), metavar='SUBZERO_FILE',
35 help='Subzero bitcode file [default stdin]')
Jim Stichnothf7c9a142014-04-29 10:52:43 -070036 args = argparser.parse_args()
Karl Schimpfa667fb82014-05-19 14:56:51 -070037 bitcode = args.llfile[0].readlines()
38 sz_out = [ line.rstrip() for line in args.szfile.readlines()]
Jim Stichnothf7c9a142014-04-29 10:52:43 -070039
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(';.*')
Jim Stichnothde4ca712014-06-29 08:13:48 -070045 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 ]))
Jan Voung3bd9f1a2014-06-18 10:50:57 -070051 prev_line = None
Jim Stichnothf7c9a142014-04-29 10:52:43 -070052 for line in bitcode:
Jan Voung3bd9f1a2014-06-18 10:50:57 -070053 if prev_line:
54 line = prev_line + line
55 prev_line = None
Jim Stichnothf7c9a142014-04-29 10:52:43 -070056 # 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.
Jan Voung3bd9f1a2014-06-18 10:50:57 -070061 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)
Jim Stichnothf7c9a142014-04-29 10:52:43 -070068
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(
Karl Schimpfa667fb82014-05-19 14:56:51 -070075 '|'.join([' -[0-9]', # negative constants
76 ' (float|double) [-0-9]', # FP constants
Jim Stichnothf7c9a142014-04-29 10:52:43 -070077 ' (float|double) %\w+, [-0-9]',
Jan Voung3bd9f1a2014-06-18 10:50:57 -070078 ' @llvm\..*i\d+\*', # intrinsic calls w/ pointer args
79 ' i\d+\* @llvm\.', # intrinsic calls w/ pointer ret
Karl Schimpfa667fb82014-05-19 14:56:51 -070080 ' inttoptr ', # inttoptr pointer types
81 ' ptrtoint ', # ptrtoint pointer types
82 ' bitcast .*\* .* to .*\*' # bitcast pointer types
Jim Stichnothf7c9a142014-04-29 10:52:43 -070083 ]))
84 for (sz_line, llc_line) in itertools.izip_longest(sz_out, llc_out):
85 lines_total += 1
86 if sz_line == llc_line:
87 continue
88 if llc_line and ignore_pattern.search(llc_line):
89 lines_diff += 1
90 continue
Jan Voung3bd9f1a2014-06-18 10:50:57 -070091 if sz_line: print 'SZ (%d)> %s' % (lines_total, sz_line)
92 if llc_line: print 'LL (%d)> %s' % (lines_total, llc_line)
Jim Stichnothf7c9a142014-04-29 10:52:43 -070093 return_code = 1
94
95 if return_code == 0:
96 message = 'Success (ignored %d diffs out of %d lines)'
97 print message % (lines_diff, lines_total)
98 exit(return_code)