45
45
SSA_RE_STR = "[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*"
46
46
SSA_RE = re .compile (SSA_RE_STR )
47
47
48
+ # Regex matching the left-hand side of an assignment
49
+ SSA_RESULTS_STR = r'\s*(%' + SSA_RE_STR + r')(\s*,\s*(%' + SSA_RE_STR + r'))*\s*='
50
+ SSA_RESULTS_RE = re .compile (SSA_RESULTS_STR )
51
+
52
+ # Regex matching attributes
53
+ ATTR_RE_STR = r'(#[a-zA-Z._-][a-zA-Z0-9._-]*)'
54
+ ATTR_RE = re .compile (ATTR_RE_STR )
55
+
56
+ # Regex matching the left-hand side of an attribute definition
57
+ ATTR_DEF_RE_STR = r'\s*' + ATTR_RE_STR + r'\s*='
58
+ ATTR_DEF_RE = re .compile (ATTR_DEF_RE_STR )
59
+
48
60
49
61
# Class used to generate and manage string substitution blocks for SSA value
50
62
# names.
51
- class SSAVariableNamer :
52
- def __init__ (self ):
63
+ class VariableNamer :
64
+ def __init__ (self , variable_names ):
53
65
self .scopes = []
54
66
self .name_counter = 0
55
67
68
+ # Number of variable names to still generate in parent scope
69
+ self .generate_in_parent_scope_left = 0
70
+
71
+ # Parse variable names
72
+ self .variable_names = [name .upper () for name in variable_names .split (',' )]
73
+ self .used_variable_names = set ()
74
+
75
+ # Generate the following 'n' variable names in the parent scope.
76
+ def generate_in_parent_scope (self , n ):
77
+ self .generate_in_parent_scope_left = n
78
+
56
79
# Generate a substitution name for the given ssa value name.
57
- def generate_name (self , ssa_name ):
58
- variable = "VAL_" + str (self .name_counter )
59
- self .name_counter += 1
60
- self .scopes [- 1 ][ssa_name ] = variable
61
- return variable
80
+ def generate_name (self , source_variable_name ):
81
+
82
+ # Compute variable name
83
+ variable_name = self .variable_names .pop (0 ) if len (self .variable_names ) > 0 else ''
84
+ if variable_name == '' :
85
+ variable_name = "VAL_" + str (self .name_counter )
86
+ self .name_counter += 1
87
+
88
+ # Scope where variable name is saved
89
+ scope = len (self .scopes ) - 1
90
+ if self .generate_in_parent_scope_left > 0 :
91
+ self .generate_in_parent_scope_left -= 1
92
+ scope = len (self .scopes ) - 2
93
+ assert (scope >= 0 )
94
+
95
+ # Save variable
96
+ if variable_name in self .used_variable_names :
97
+ raise RuntimeError (variable_name + ': duplicate variable name' )
98
+ self .scopes [scope ][source_variable_name ] = variable_name
99
+ self .used_variable_names .add (variable_name )
100
+
101
+ return variable_name
62
102
63
103
# Push a new variable name scope.
64
104
def push_name_scope (self ):
@@ -76,6 +116,46 @@ def num_scopes(self):
76
116
def clear_counter (self ):
77
117
self .name_counter = 0
78
118
119
+ class AttributeNamer :
120
+
121
+ def __init__ (self , attribute_names ):
122
+ self .name_counter = 0
123
+ self .attribute_names = [name .upper () for name in attribute_names .split (',' )]
124
+ self .map = {}
125
+ self .used_attribute_names = set ()
126
+
127
+ # Generate a substitution name for the given attribute name.
128
+ def generate_name (self , source_attribute_name ):
129
+
130
+ # Compute FileCheck name
131
+ attribute_name = self .attribute_names .pop (0 ) if len (self .attribute_names ) > 0 else ''
132
+ if attribute_name == '' :
133
+ attribute_name = "ATTR_" + str (self .name_counter )
134
+ self .name_counter += 1
135
+
136
+ # Prepend global symbol
137
+ attribute_name = '$' + attribute_name
138
+
139
+ # Save attribute
140
+ if attribute_name in self .used_attribute_names :
141
+ raise RuntimeError (attribute_name + ': duplicate attribute name' )
142
+ self .map [source_attribute_name ] = attribute_name
143
+ self .used_attribute_names .add (attribute_name )
144
+ return attribute_name
145
+
146
+ # Get the saved substitution name for the given attribute name. If no name
147
+ # has been generated for the given attribute yet, the source attribute name
148
+ # itself is returned.
149
+ def get_name (self , source_attribute_name ):
150
+ return self .map [source_attribute_name ] if source_attribute_name in self .map else '?'
151
+
152
+ # Return the number of SSA results in a line of type
153
+ # %0, %1, ... = ...
154
+ # The function returns 0 if there are no results.
155
+ def get_num_ssa_results (input_line ):
156
+ m = SSA_RESULTS_RE .match (input_line )
157
+ return m .group ().count ('%' ) if m else 0
158
+
79
159
80
160
# Process a line of input that has been split at each SSA identifier '%'.
81
161
def process_line (line_chunks , variable_namer ):
@@ -84,7 +164,7 @@ def process_line(line_chunks, variable_namer):
84
164
# Process the rest that contained an SSA value name.
85
165
for chunk in line_chunks :
86
166
m = SSA_RE .match (chunk )
87
- ssa_name = m .group (0 )
167
+ ssa_name = m .group (0 ) if m is not None else ''
88
168
89
169
# Check if an existing variable exists for this name.
90
170
variable = None
@@ -126,6 +206,25 @@ def process_source_lines(source_lines, note, args):
126
206
source_segments [- 1 ].append (line + "\n " )
127
207
return source_segments
128
208
209
+ def process_attribute_definition (line , attribute_namer , output ):
210
+ m = ATTR_DEF_RE .match (line )
211
+ if m :
212
+ attribute_name = attribute_namer .generate_name (m .group (1 ))
213
+ line = '// CHECK: #[[' + attribute_name + ':.+]] =' + line [len (m .group (0 )):] + '\n '
214
+ output .write (line )
215
+
216
+ def process_attribute_references (line , attribute_namer ):
217
+
218
+ output_line = ''
219
+ components = ATTR_RE .split (line )
220
+ for component in components :
221
+ m = ATTR_RE .match (component )
222
+ if m :
223
+ output_line += '#[[' + attribute_namer .get_name (m .group (1 )) + ']]'
224
+ output_line += component [len (m .group ()):]
225
+ else :
226
+ output_line += component
227
+ return output_line
129
228
130
229
# Pre-process a line of input to remove any character sequences that will be
131
230
# problematic with FileCheck.
@@ -171,6 +270,20 @@ def main():
171
270
'it omits "module {"' ,
172
271
)
173
272
parser .add_argument ("-i" , "--inplace" , action = "store_true" , default = False )
273
+ parser .add_argument (
274
+ "--variable_names" ,
275
+ type = str ,
276
+ default = '' ,
277
+ help = "Names to be used in FileCheck regular expression to represent SSA "
278
+ "variables in the order they are encountered. Separate names with commas, "
279
+ "and leave empty entries for default names (e.g.: 'DIM,,SUM,RESULT')" )
280
+ parser .add_argument (
281
+ "--attribute_names" ,
282
+ type = str ,
283
+ default = '' ,
284
+ help = "Names to be used in FileCheck regular expression to represent "
285
+ "attributes in the order they are defined. Separate names with commas,"
286
+ "commas, and leave empty entries for default names (e.g.: 'MAP0,,,MAP1')" )
174
287
175
288
args = parser .parse_args ()
176
289
@@ -197,15 +310,22 @@ def main():
197
310
output = args .output
198
311
199
312
output_segments = [[]]
200
- # A map containing data used for naming SSA value names.
201
- variable_namer = SSAVariableNamer ()
313
+
314
+ # Namers
315
+ variable_namer = VariableNamer (args .variable_names )
316
+ attribute_namer = AttributeNamer (args .attribute_names )
317
+
318
+ # Process lines
202
319
for input_line in input_lines :
203
320
if not input_line :
204
321
continue
205
- lstripped_input_line = input_line .lstrip ()
322
+
323
+ # Check if this is an attribute definition and process it
324
+ process_attribute_definition (input_line , attribute_namer , output )
206
325
207
326
# Lines with blocks begin with a ^. These lines have a trailing comment
208
327
# that needs to be stripped.
328
+ lstripped_input_line = input_line .lstrip ()
209
329
is_block = lstripped_input_line [0 ] == "^"
210
330
if is_block :
211
331
input_line = input_line .rsplit ("//" , 1 )[0 ].rstrip ()
@@ -222,6 +342,10 @@ def main():
222
342
variable_namer .push_name_scope ()
223
343
if cur_level == args .starts_from_scope :
224
344
output_segments .append ([])
345
+
346
+ # Result SSA values must still be pushed to parent scope
347
+ num_ssa_results = get_num_ssa_results (input_line )
348
+ variable_namer .generate_in_parent_scope (num_ssa_results )
225
349
226
350
# Omit lines at the near top level e.g. "module {".
227
351
if cur_level < args .starts_from_scope :
@@ -234,6 +358,9 @@ def main():
234
358
# FileCheck.
235
359
input_line = preprocess_line (input_line )
236
360
361
+ # Process uses of attributes in this line
362
+ input_line = process_attribute_references (input_line , attribute_namer )
363
+
237
364
# Split the line at the each SSA value name.
238
365
ssa_split = input_line .split ("%" )
239
366
0 commit comments