1
1
from __future__ import print_function
2
2
import re
3
+ import string
3
4
import subprocess
4
5
import sys
5
6
6
- RUN_LINE_RE = re .compile ('^\s*;\s*RUN:\s*(.*)$' )
7
- CHECK_PREFIX_RE = re .compile ('--?check-prefix(?:es)?=(\S+)' )
8
- CHECK_RE = re .compile (r'^\s*;\s*([^:]+?)(?:-NEXT|-NOT|-DAG|-LABEL)?:' )
9
-
10
- IR_FUNCTION_RE = re .compile ('^\s*define\s+(?:internal\s+)?[^@]*@(\w+)\s*\(' )
11
- TRIPLE_IR_RE = re .compile (r'^target\s+triple\s*=\s*"([^"]+)"$' )
12
- TRIPLE_ARG_RE = re .compile (r'-mtriple=([^ ]+)' )
7
+ if sys .version_info [0 ] > 2 :
8
+ class string :
9
+ expandtabs = str .expandtabs
10
+ else :
11
+ import string
13
12
14
- SCRUB_LEADING_WHITESPACE_RE = re .compile (r'^(\s+)' )
15
- SCRUB_WHITESPACE_RE = re .compile (r'(?!^(| \w))[ \t]+' , flags = re .M )
16
- SCRUB_TRAILING_WHITESPACE_RE = re .compile (r'[ \t]+$' , flags = re .M )
17
- SCRUB_KILL_COMMENT_RE = re .compile (r'^ *#+ +kill:.*\n' )
18
- SCRUB_LOOP_COMMENT_RE = re .compile (
19
- r'# =>This Inner Loop Header:.*|# in Loop:.*' , flags = re .M )
13
+ ##### Common utilities for update_*test_checks.py
20
14
21
15
def should_add_line_to_output (input_line , prefix_set ):
22
16
# Skip any blank comment lines in the IR.
@@ -42,6 +36,38 @@ def invoke_tool(exe, cmd_args, ir):
42
36
# Fix line endings to unix CR style.
43
37
return stdout .replace ('\r \n ' , '\n ' )
44
38
39
+ ##### LLVM IR parser
40
+
41
+ RUN_LINE_RE = re .compile ('^\s*;\s*RUN:\s*(.*)$' )
42
+ CHECK_PREFIX_RE = re .compile ('--?check-prefix(?:es)?=(\S+)' )
43
+ CHECK_RE = re .compile (r'^\s*;\s*([^:]+?)(?:-NEXT|-NOT|-DAG|-LABEL)?:' )
44
+
45
+ OPT_FUNCTION_RE = re .compile (
46
+ r'^\s*define\s+(?:internal\s+)?[^@]*@(?P<func>[\w-]+?)\s*\('
47
+ r'(\s+)?[^)]*[^{]*\{\n(?P<body>.*?)^\}$' ,
48
+ flags = (re .M | re .S ))
49
+
50
+ IR_FUNCTION_RE = re .compile ('^\s*define\s+(?:internal\s+)?[^@]*@(\w+)\s*\(' )
51
+ TRIPLE_IR_RE = re .compile (r'^target\s+triple\s*=\s*"([^"]+)"$' )
52
+ TRIPLE_ARG_RE = re .compile (r'-mtriple=([^ ]+)' )
53
+
54
+ SCRUB_LEADING_WHITESPACE_RE = re .compile (r'^(\s+)' )
55
+ SCRUB_WHITESPACE_RE = re .compile (r'(?!^(| \w))[ \t]+' , flags = re .M )
56
+ SCRUB_TRAILING_WHITESPACE_RE = re .compile (r'[ \t]+$' , flags = re .M )
57
+ SCRUB_KILL_COMMENT_RE = re .compile (r'^ *#+ +kill:.*\n' )
58
+ SCRUB_LOOP_COMMENT_RE = re .compile (
59
+ r'# =>This Inner Loop Header:.*|# in Loop:.*' , flags = re .M )
60
+
61
+ def scrub_body (body ):
62
+ # Scrub runs of whitespace out of the assembly, but leave the leading
63
+ # whitespace in place.
64
+ body = SCRUB_WHITESPACE_RE .sub (r' ' , body )
65
+ # Expand the tabs used for indentation.
66
+ body = string .expandtabs (body , 2 )
67
+ # Strip trailing whitespace.
68
+ body = SCRUB_TRAILING_WHITESPACE_RE .sub (r'' , body )
69
+ return body
70
+
45
71
# Build up a dictionary of all the function bodies.
46
72
def build_function_body_dictionary (function_re , scrubber , scrubber_args , raw_tool_output , prefixes , func_dict , verbose ):
47
73
for m in function_re .finditer (raw_tool_output ):
@@ -66,3 +92,114 @@ def build_function_body_dictionary(function_re, scrubber, scrubber_args, raw_too
66
92
continue
67
93
68
94
func_dict [prefix ][func ] = scrubbed_body
95
+
96
+ ##### Generator of LLVM IR CHECK lines
97
+
98
+ SCRUB_IR_COMMENT_RE = re .compile (r'\s*;.*' )
99
+
100
+ # Match things that look at identifiers, but only if they are followed by
101
+ # spaces, commas, paren, or end of the string
102
+ IR_VALUE_RE = re .compile (r'(\s+)%([\w\.]+?)([,\s\(\)]|\Z)' )
103
+
104
+ # Create a FileCheck variable name based on an IR name.
105
+ def get_value_name (var ):
106
+ if var .isdigit ():
107
+ var = 'TMP' + var
108
+ var = var .replace ('.' , '_' )
109
+ return var .upper ()
110
+
111
+
112
+ # Create a FileCheck variable from regex.
113
+ def get_value_definition (var ):
114
+ return '[[' + get_value_name (var ) + ':%.*]]'
115
+
116
+
117
+ # Use a FileCheck variable.
118
+ def get_value_use (var ):
119
+ return '[[' + get_value_name (var ) + ']]'
120
+
121
+ # Replace IR value defs and uses with FileCheck variables.
122
+ def genericize_check_lines (lines ):
123
+ # This gets called for each match that occurs in
124
+ # a line. We transform variables we haven't seen
125
+ # into defs, and variables we have seen into uses.
126
+ def transform_line_vars (match ):
127
+ var = match .group (2 )
128
+ if var in vars_seen :
129
+ rv = get_value_use (var )
130
+ else :
131
+ vars_seen .add (var )
132
+ rv = get_value_definition (var )
133
+ # re.sub replaces the entire regex match
134
+ # with whatever you return, so we have
135
+ # to make sure to hand it back everything
136
+ # including the commas and spaces.
137
+ return match .group (1 ) + rv + match .group (3 )
138
+
139
+ vars_seen = set ()
140
+ lines_with_def = []
141
+
142
+ for i , line in enumerate (lines ):
143
+ # An IR variable named '%.' matches the FileCheck regex string.
144
+ line = line .replace ('%.' , '%dot' )
145
+ # Ignore any comments, since the check lines will too.
146
+ scrubbed_line = SCRUB_IR_COMMENT_RE .sub (r'' , line )
147
+ lines [i ] = IR_VALUE_RE .sub (transform_line_vars , scrubbed_line )
148
+ return lines
149
+
150
+
151
+ def add_ir_checks (output_lines , prefix_list , func_dict , func_name , opt_basename ):
152
+ # Label format is based on IR string.
153
+ check_label_format = "; %s-LABEL: @%s("
154
+
155
+ printed_prefixes = []
156
+ for checkprefixes , _ in prefix_list :
157
+ for checkprefix in checkprefixes :
158
+ if checkprefix in printed_prefixes :
159
+ break
160
+ if not func_dict [checkprefix ][func_name ]:
161
+ continue
162
+ # Add some space between different check prefixes, but not after the last
163
+ # check line (before the test code).
164
+ #if len(printed_prefixes) != 0:
165
+ # output_lines.append(';')
166
+ printed_prefixes .append (checkprefix )
167
+ output_lines .append (check_label_format % (checkprefix , func_name ))
168
+ func_body = func_dict [checkprefix ][func_name ].splitlines ()
169
+
170
+ # For IR output, change all defs to FileCheck variables, so we're immune
171
+ # to variable naming fashions.
172
+ func_body = genericize_check_lines (func_body )
173
+
174
+ # This could be selectively enabled with an optional invocation argument.
175
+ # Disabled for now: better to check everything. Be safe rather than sorry.
176
+
177
+ # Handle the first line of the function body as a special case because
178
+ # it's often just noise (a useless asm comment or entry label).
179
+ #if func_body[0].startswith("#") or func_body[0].startswith("entry:"):
180
+ # is_blank_line = True
181
+ #else:
182
+ # output_lines.append('; %s: %s' % (checkprefix, func_body[0]))
183
+ # is_blank_line = False
184
+
185
+ is_blank_line = False
186
+
187
+ for func_line in func_body :
188
+ if func_line .strip () == '' :
189
+ is_blank_line = True
190
+ continue
191
+ # Do not waste time checking IR comments.
192
+ func_line = SCRUB_IR_COMMENT_RE .sub (r'' , func_line )
193
+
194
+ # Skip blank lines instead of checking them.
195
+ if is_blank_line == True :
196
+ output_lines .append ('; %s: %s' % (checkprefix , func_line ))
197
+ else :
198
+ output_lines .append ('; %s-NEXT: %s' % (checkprefix , func_line ))
199
+ is_blank_line = False
200
+
201
+ # Add space between different check prefixes and also before the first
202
+ # line of code in the test function.
203
+ output_lines .append (';' )
204
+ break
205
+ return output_lines
0 commit comments