xref: /llvm-project/mlir/utils/generate-test-checks.py (revision dbf798fa646811c03e40c25f9bb3a456267c5a73)
17bfcb912SWen-Heng (Jack) Chung#!/usr/bin/env python3
2a9d4015dSRiver Riddle"""A script to generate FileCheck statements for mlir unit tests.
3a9d4015dSRiver Riddle
4a9d4015dSRiver RiddleThis script is a utility to add FileCheck patterns to an mlir file.
5a9d4015dSRiver Riddle
6a9d4015dSRiver RiddleNOTE: The input .mlir is expected to be the output from the parser, not a
7a9d4015dSRiver Riddlestripped down variant.
8a9d4015dSRiver Riddle
9a9d4015dSRiver RiddleExample usage:
10a9d4015dSRiver Riddle$ generate-test-checks.py foo.mlir
11a9d4015dSRiver Riddle$ mlir-opt foo.mlir -transformation | generate-test-checks.py
12b877f33dSTim Shen$ mlir-opt foo.mlir -transformation | generate-test-checks.py --source foo.mlir
13b877f33dSTim Shen$ mlir-opt foo.mlir -transformation | generate-test-checks.py --source foo.mlir -i
14b877f33dSTim Shen$ mlir-opt foo.mlir -transformation | generate-test-checks.py --source foo.mlir -i --source_delim_regex='gpu.func @'
15a9d4015dSRiver Riddle
16b877f33dSTim ShenThe script will heuristically generate CHECK/CHECK-LABEL commands for each line
17a9d4015dSRiver Riddlewithin the file. By default this script will also try to insert string
18b877f33dSTim Shensubstitution blocks for all SSA value names. If --source file is specified, the
19b877f33dSTim Shenscript will attempt to insert the generated CHECKs to the source file by looking
20b877f33dSTim Shenfor line positions matched by --source_delim_regex.
21b877f33dSTim Shen
22b877f33dSTim ShenThe script is designed to make adding checks to a test case fast, it is *not*
23b877f33dSTim Shendesigned to be authoritative about what constitutes a good test!
24a9d4015dSRiver Riddle"""
25a9d4015dSRiver Riddle
2656222a06SMehdi Amini# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
2756222a06SMehdi Amini# See https://llvm.org/LICENSE.txt for license information.
2856222a06SMehdi Amini# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
29a9d4015dSRiver Riddle
30a9d4015dSRiver Riddleimport argparse
31a9d4015dSRiver Riddleimport os  # Used to advertise this file's name ("autogenerated_note").
32a9d4015dSRiver Riddleimport re
33a9d4015dSRiver Riddleimport sys
34a9d4015dSRiver Riddle
35f9008e63STobias HietaADVERT_BEGIN = "// NOTE: Assertions have been autogenerated by "
364e7c0a37SMehdi AminiADVERT_END = """
374e7c0a37SMehdi Amini// The script is designed to make adding checks to
384e7c0a37SMehdi Amini// a test case fast, it is *not* designed to be authoritative
394e7c0a37SMehdi Amini// about what constitutes a good test! The CHECK should be
404e7c0a37SMehdi Amini// minimized and named to reflect the test intent.
414e7c0a37SMehdi Amini"""
424e7c0a37SMehdi Amini
43a9d4015dSRiver Riddle
44a9d4015dSRiver Riddle# Regex command to match an SSA identifier.
45f9008e63STobias HietaSSA_RE_STR = "[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*"
46a9d4015dSRiver RiddleSSA_RE = re.compile(SSA_RE_STR)
47a9d4015dSRiver Riddle
48dea01f5eSRafael Ubal Tena# Regex matching the left-hand side of an assignment
49dea01f5eSRafael Ubal TenaSSA_RESULTS_STR = r'\s*(%' + SSA_RE_STR + r')(\s*,\s*(%' + SSA_RE_STR + r'))*\s*='
50dea01f5eSRafael Ubal TenaSSA_RESULTS_RE = re.compile(SSA_RESULTS_STR)
51dea01f5eSRafael Ubal Tena
52dea01f5eSRafael Ubal Tena# Regex matching attributes
53dea01f5eSRafael Ubal TenaATTR_RE_STR = r'(#[a-zA-Z._-][a-zA-Z0-9._-]*)'
54dea01f5eSRafael Ubal TenaATTR_RE = re.compile(ATTR_RE_STR)
55dea01f5eSRafael Ubal Tena
56dea01f5eSRafael Ubal Tena# Regex matching the left-hand side of an attribute definition
57dea01f5eSRafael Ubal TenaATTR_DEF_RE_STR = r'\s*' + ATTR_RE_STR + r'\s*='
58dea01f5eSRafael Ubal TenaATTR_DEF_RE = re.compile(ATTR_DEF_RE_STR)
59dea01f5eSRafael Ubal Tena
60a9d4015dSRiver Riddle
61a9d4015dSRiver Riddle# Class used to generate and manage string substitution blocks for SSA value
62a9d4015dSRiver Riddle# names.
63dea01f5eSRafael Ubal Tenaclass VariableNamer:
64dea01f5eSRafael Ubal Tena    def __init__(self, variable_names):
65a9d4015dSRiver Riddle        self.scopes = []
66a9d4015dSRiver Riddle        self.name_counter = 0
67a9d4015dSRiver Riddle
68dea01f5eSRafael Ubal Tena        # Number of variable names to still generate in parent scope
69dea01f5eSRafael Ubal Tena        self.generate_in_parent_scope_left = 0
70dea01f5eSRafael Ubal Tena
71dea01f5eSRafael Ubal Tena        # Parse variable names
72dea01f5eSRafael Ubal Tena        self.variable_names = [name.upper() for name in variable_names.split(',')]
73dea01f5eSRafael Ubal Tena        self.used_variable_names = set()
74dea01f5eSRafael Ubal Tena
75dea01f5eSRafael Ubal Tena    # Generate the following 'n' variable names in the parent scope.
76dea01f5eSRafael Ubal Tena    def generate_in_parent_scope(self, n):
77dea01f5eSRafael Ubal Tena        self.generate_in_parent_scope_left = n
78dea01f5eSRafael Ubal Tena
79f28c5acaSKazuaki Ishizaki    # Generate a substitution name for the given ssa value name.
80dea01f5eSRafael Ubal Tena    def generate_name(self, source_variable_name):
81dea01f5eSRafael Ubal Tena
82dea01f5eSRafael Ubal Tena        # Compute variable name
83dea01f5eSRafael Ubal Tena        variable_name = self.variable_names.pop(0) if len(self.variable_names) > 0 else ''
84dea01f5eSRafael Ubal Tena        if variable_name == '':
85dea01f5eSRafael Ubal Tena            variable_name = "VAL_" + str(self.name_counter)
86a9d4015dSRiver Riddle            self.name_counter += 1
87dea01f5eSRafael Ubal Tena
88dea01f5eSRafael Ubal Tena        # Scope where variable name is saved
89dea01f5eSRafael Ubal Tena        scope = len(self.scopes) - 1
90dea01f5eSRafael Ubal Tena        if self.generate_in_parent_scope_left > 0:
91dea01f5eSRafael Ubal Tena            self.generate_in_parent_scope_left -= 1
92dea01f5eSRafael Ubal Tena            scope = len(self.scopes) - 2
93dea01f5eSRafael Ubal Tena        assert(scope >= 0)
94dea01f5eSRafael Ubal Tena
95dea01f5eSRafael Ubal Tena        # Save variable
96dea01f5eSRafael Ubal Tena        if variable_name in self.used_variable_names:
97dea01f5eSRafael Ubal Tena            raise RuntimeError(variable_name + ': duplicate variable name')
98dea01f5eSRafael Ubal Tena        self.scopes[scope][source_variable_name] = variable_name
99dea01f5eSRafael Ubal Tena        self.used_variable_names.add(variable_name)
100dea01f5eSRafael Ubal Tena
101dea01f5eSRafael Ubal Tena        return variable_name
102a9d4015dSRiver Riddle
103a9d4015dSRiver Riddle    # Push a new variable name scope.
104a9d4015dSRiver Riddle    def push_name_scope(self):
105a9d4015dSRiver Riddle        self.scopes.append({})
106a9d4015dSRiver Riddle
107a9d4015dSRiver Riddle    # Pop the last variable name scope.
108a9d4015dSRiver Riddle    def pop_name_scope(self):
109a9d4015dSRiver Riddle        self.scopes.pop()
110a9d4015dSRiver Riddle
111b877f33dSTim Shen    # Return the level of nesting (number of pushed scopes).
11225b38067STim Shen    def num_scopes(self):
11325b38067STim Shen        return len(self.scopes)
11425b38067STim Shen
115*dbf798faSBenjamin Maxwell    # Reset the counter and used variable names.
116*dbf798faSBenjamin Maxwell    def clear_names(self):
11725b38067STim Shen        self.name_counter = 0
118*dbf798faSBenjamin Maxwell        self.used_variable_names = set()
11925b38067STim Shen
120dea01f5eSRafael Ubal Tenaclass AttributeNamer:
121dea01f5eSRafael Ubal Tena
122dea01f5eSRafael Ubal Tena    def __init__(self, attribute_names):
123dea01f5eSRafael Ubal Tena        self.name_counter = 0
124dea01f5eSRafael Ubal Tena        self.attribute_names = [name.upper() for name in attribute_names.split(',')]
125dea01f5eSRafael Ubal Tena        self.map = {}
126dea01f5eSRafael Ubal Tena        self.used_attribute_names = set()
127dea01f5eSRafael Ubal Tena
128dea01f5eSRafael Ubal Tena    # Generate a substitution name for the given attribute name.
129dea01f5eSRafael Ubal Tena    def generate_name(self, source_attribute_name):
130dea01f5eSRafael Ubal Tena
131dea01f5eSRafael Ubal Tena        # Compute FileCheck name
132dea01f5eSRafael Ubal Tena        attribute_name = self.attribute_names.pop(0) if len(self.attribute_names) > 0 else ''
133dea01f5eSRafael Ubal Tena        if attribute_name == '':
134dea01f5eSRafael Ubal Tena            attribute_name = "ATTR_" + str(self.name_counter)
135dea01f5eSRafael Ubal Tena            self.name_counter += 1
136dea01f5eSRafael Ubal Tena
137dea01f5eSRafael Ubal Tena        # Prepend global symbol
138dea01f5eSRafael Ubal Tena        attribute_name = '$' + attribute_name
139dea01f5eSRafael Ubal Tena
140dea01f5eSRafael Ubal Tena        # Save attribute
141dea01f5eSRafael Ubal Tena        if attribute_name in self.used_attribute_names:
142dea01f5eSRafael Ubal Tena            raise RuntimeError(attribute_name + ': duplicate attribute name')
143dea01f5eSRafael Ubal Tena        self.map[source_attribute_name] = attribute_name
144dea01f5eSRafael Ubal Tena        self.used_attribute_names.add(attribute_name)
145dea01f5eSRafael Ubal Tena        return attribute_name
146dea01f5eSRafael Ubal Tena
147dea01f5eSRafael Ubal Tena    # Get the saved substitution name for the given attribute name. If no name
148dea01f5eSRafael Ubal Tena    # has been generated for the given attribute yet, the source attribute name
149dea01f5eSRafael Ubal Tena    # itself is returned.
150dea01f5eSRafael Ubal Tena    def get_name(self, source_attribute_name):
151dea01f5eSRafael Ubal Tena        return self.map[source_attribute_name] if source_attribute_name in self.map else '?'
152dea01f5eSRafael Ubal Tena
153dea01f5eSRafael Ubal Tena# Return the number of SSA results in a line of type
154dea01f5eSRafael Ubal Tena#   %0, %1, ... = ...
155dea01f5eSRafael Ubal Tena# The function returns 0 if there are no results.
156dea01f5eSRafael Ubal Tenadef get_num_ssa_results(input_line):
157dea01f5eSRafael Ubal Tena    m = SSA_RESULTS_RE.match(input_line)
158dea01f5eSRafael Ubal Tena    return m.group().count('%') if m else 0
159dea01f5eSRafael Ubal Tena
160a9d4015dSRiver Riddle
161a9d4015dSRiver Riddle# Process a line of input that has been split at each SSA identifier '%'.
162a9d4015dSRiver Riddledef process_line(line_chunks, variable_namer):
163f9008e63STobias Hieta    output_line = ""
164a9d4015dSRiver Riddle
165a9d4015dSRiver Riddle    # Process the rest that contained an SSA value name.
166a9d4015dSRiver Riddle    for chunk in line_chunks:
167a9d4015dSRiver Riddle        m = SSA_RE.match(chunk)
168dea01f5eSRafael Ubal Tena        ssa_name = m.group(0) if m is not None else ''
169a9d4015dSRiver Riddle
170a9d4015dSRiver Riddle        # Check if an existing variable exists for this name.
171a9d4015dSRiver Riddle        variable = None
172a9d4015dSRiver Riddle        for scope in variable_namer.scopes:
173a9d4015dSRiver Riddle            variable = scope.get(ssa_name)
174a9d4015dSRiver Riddle            if variable is not None:
175a9d4015dSRiver Riddle                break
176a9d4015dSRiver Riddle
177a9d4015dSRiver Riddle        # If one exists, then output the existing name.
178a9d4015dSRiver Riddle        if variable is not None:
179f9008e63STobias Hieta            output_line += "%[[" + variable + "]]"
180a9d4015dSRiver Riddle        else:
181a9d4015dSRiver Riddle            # Otherwise, generate a new variable.
182a9d4015dSRiver Riddle            variable = variable_namer.generate_name(ssa_name)
183f9008e63STobias Hieta            output_line += "%[[" + variable + ":.*]]"
184a9d4015dSRiver Riddle
185a9d4015dSRiver Riddle        # Append the non named group.
186a9d4015dSRiver Riddle        output_line += chunk[len(ssa_name) :]
187a9d4015dSRiver Riddle
188f9008e63STobias Hieta    return output_line.rstrip() + "\n"
189a9d4015dSRiver Riddle
190a9d4015dSRiver Riddle
191b877f33dSTim Shen# Process the source file lines. The source file doesn't have to be .mlir.
19225b38067STim Shendef process_source_lines(source_lines, note, args):
19325b38067STim Shen    source_split_re = re.compile(args.source_delim_regex)
19425b38067STim Shen
19525b38067STim Shen    source_segments = [[]]
19625b38067STim Shen    for line in source_lines:
197b877f33dSTim Shen        # Remove previous note.
19825b38067STim Shen        if line == note:
19925b38067STim Shen            continue
200b877f33dSTim Shen        # Remove previous CHECK lines.
20125b38067STim Shen        if line.find(args.check_prefix) != -1:
20225b38067STim Shen            continue
203b877f33dSTim Shen        # Segment the file based on --source_delim_regex.
20425b38067STim Shen        if source_split_re.search(line):
20525b38067STim Shen            source_segments.append([])
20625b38067STim Shen
207f9008e63STobias Hieta        source_segments[-1].append(line + "\n")
20825b38067STim Shen    return source_segments
20925b38067STim Shen
210dea01f5eSRafael Ubal Tenadef process_attribute_definition(line, attribute_namer, output):
211dea01f5eSRafael Ubal Tena    m = ATTR_DEF_RE.match(line)
212dea01f5eSRafael Ubal Tena    if m:
213dea01f5eSRafael Ubal Tena        attribute_name = attribute_namer.generate_name(m.group(1))
214dea01f5eSRafael Ubal Tena        line = '// CHECK: #[[' + attribute_name + ':.+]] =' + line[len(m.group(0)):] + '\n'
215dea01f5eSRafael Ubal Tena        output.write(line)
216dea01f5eSRafael Ubal Tena
217dea01f5eSRafael Ubal Tenadef process_attribute_references(line, attribute_namer):
218dea01f5eSRafael Ubal Tena
219dea01f5eSRafael Ubal Tena    output_line = ''
220dea01f5eSRafael Ubal Tena    components = ATTR_RE.split(line)
221dea01f5eSRafael Ubal Tena    for component in components:
222dea01f5eSRafael Ubal Tena        m = ATTR_RE.match(component)
223dea01f5eSRafael Ubal Tena        if m:
224dea01f5eSRafael Ubal Tena            output_line += '#[[' + attribute_namer.get_name(m.group(1)) + ']]'
225dea01f5eSRafael Ubal Tena            output_line += component[len(m.group()):]
226dea01f5eSRafael Ubal Tena        else:
227dea01f5eSRafael Ubal Tena            output_line += component
228dea01f5eSRafael Ubal Tena    return output_line
22925b38067STim Shen
2303e2ac62bSRiver Riddle# Pre-process a line of input to remove any character sequences that will be
2313e2ac62bSRiver Riddle# problematic with FileCheck.
2323e2ac62bSRiver Riddledef preprocess_line(line):
2333e2ac62bSRiver Riddle    # Replace any double brackets, '[[' with escaped replacements. '[['
2343e2ac62bSRiver Riddle    # corresponds to variable names in FileCheck.
235f9008e63STobias Hieta    output_line = line.replace("[[", "{{\\[\\[}}")
2363e2ac62bSRiver Riddle
2373e2ac62bSRiver Riddle    # Replace any single brackets that are followed by an SSA identifier, the
2383e2ac62bSRiver Riddle    # identifier will be replace by a variable; Creating the same situation as
2393e2ac62bSRiver Riddle    # above.
240f9008e63STobias Hieta    output_line = output_line.replace("[%", "{{\\[}}%")
2413e2ac62bSRiver Riddle
2423e2ac62bSRiver Riddle    return output_line
2433e2ac62bSRiver Riddle
2443e2ac62bSRiver Riddle
245a9d4015dSRiver Riddledef main():
246a9d4015dSRiver Riddle    parser = argparse.ArgumentParser(
247f9008e63STobias Hieta        description=__doc__, formatter_class=argparse.RawTextHelpFormatter
248f9008e63STobias Hieta    )
249a9d4015dSRiver Riddle    parser.add_argument(
250f9008e63STobias Hieta        "--check-prefix", default="CHECK", help="Prefix to use from check file."
251f9008e63STobias Hieta    )
252a9d4015dSRiver Riddle    parser.add_argument(
253f9008e63STobias Hieta        "-o", "--output", nargs="?", type=argparse.FileType("w"), default=None
254f9008e63STobias Hieta    )
255a9d4015dSRiver Riddle    parser.add_argument(
256f9008e63STobias Hieta        "input", nargs="?", type=argparse.FileType("r"), default=sys.stdin
257f9008e63STobias Hieta    )
25825b38067STim Shen    parser.add_argument(
259f9008e63STobias Hieta        "--source",
260f9008e63STobias Hieta        type=str,
261f9008e63STobias Hieta        help="Print each CHECK chunk before each delimeter line in the source"
262f9008e63STobias Hieta        "file, respectively. The delimeter lines are identified by "
263f9008e63STobias Hieta        "--source_delim_regex.",
264f9008e63STobias Hieta    )
265f9008e63STobias Hieta    parser.add_argument("--source_delim_regex", type=str, default="func @")
26625b38067STim Shen    parser.add_argument(
267f9008e63STobias Hieta        "--starts_from_scope",
268f9008e63STobias Hieta        type=int,
269f9008e63STobias Hieta        default=1,
270f9008e63STobias Hieta        help="Omit the top specified level of content. For example, by default "
271f9008e63STobias Hieta        'it omits "module {"',
272f9008e63STobias Hieta    )
273f9008e63STobias Hieta    parser.add_argument("-i", "--inplace", action="store_true", default=False)
274dea01f5eSRafael Ubal Tena    parser.add_argument(
275dea01f5eSRafael Ubal Tena        "--variable_names",
276dea01f5eSRafael Ubal Tena        type=str,
277dea01f5eSRafael Ubal Tena        default='',
278dea01f5eSRafael Ubal Tena        help="Names to be used in FileCheck regular expression to represent SSA "
279dea01f5eSRafael Ubal Tena        "variables in the order they are encountered. Separate names with commas, "
280dea01f5eSRafael Ubal Tena        "and leave empty entries for default names (e.g.: 'DIM,,SUM,RESULT')")
281dea01f5eSRafael Ubal Tena    parser.add_argument(
282dea01f5eSRafael Ubal Tena        "--attribute_names",
283dea01f5eSRafael Ubal Tena        type=str,
284dea01f5eSRafael Ubal Tena        default='',
285dea01f5eSRafael Ubal Tena        help="Names to be used in FileCheck regular expression to represent "
286dea01f5eSRafael Ubal Tena        "attributes in the order they are defined. Separate names with commas,"
287dea01f5eSRafael Ubal Tena        "commas, and leave empty entries for default names (e.g.: 'MAP0,,,MAP1')")
28825b38067STim Shen
289a9d4015dSRiver Riddle    args = parser.parse_args()
290a9d4015dSRiver Riddle
291a9d4015dSRiver Riddle    # Open the given input file.
292a9d4015dSRiver Riddle    input_lines = [l.rstrip() for l in args.input]
293a9d4015dSRiver Riddle    args.input.close()
294a9d4015dSRiver Riddle
295a9d4015dSRiver Riddle    # Generate a note used for the generated check file.
296a9d4015dSRiver Riddle    script_name = os.path.basename(__file__)
297f9008e63STobias Hieta    autogenerated_note = ADVERT_BEGIN + "utils/" + script_name + "\n" + ADVERT_END
298a9d4015dSRiver Riddle
29925b38067STim Shen    source_segments = None
30025b38067STim Shen    if args.source:
30125b38067STim Shen        source_segments = process_source_lines(
302f9008e63STobias Hieta            [l.rstrip() for l in open(args.source, "r")], autogenerated_note, args
30325b38067STim Shen        )
30425b38067STim Shen
30525b38067STim Shen    if args.inplace:
30625b38067STim Shen        assert args.output is None
307f9008e63STobias Hieta        output = open(args.source, "w")
30825b38067STim Shen    elif args.output is None:
30925b38067STim Shen        output = sys.stdout
31025b38067STim Shen    else:
31125b38067STim Shen        output = args.output
31225b38067STim Shen
31325b38067STim Shen    output_segments = [[]]
314dea01f5eSRafael Ubal Tena
315dea01f5eSRafael Ubal Tena    # Namers
316dea01f5eSRafael Ubal Tena    variable_namer = VariableNamer(args.variable_names)
317dea01f5eSRafael Ubal Tena    attribute_namer = AttributeNamer(args.attribute_names)
318dea01f5eSRafael Ubal Tena
319dea01f5eSRafael Ubal Tena    # Process lines
320a9d4015dSRiver Riddle    for input_line in input_lines:
321a9d4015dSRiver Riddle        if not input_line:
322a9d4015dSRiver Riddle            continue
323dea01f5eSRafael Ubal Tena
324dea01f5eSRafael Ubal Tena        # Check if this is an attribute definition and process it
325dea01f5eSRafael Ubal Tena        process_attribute_definition(input_line, attribute_namer, output)
326a9d4015dSRiver Riddle
327a9d4015dSRiver Riddle        # Lines with blocks begin with a ^. These lines have a trailing comment
328a9d4015dSRiver Riddle        # that needs to be stripped.
329dea01f5eSRafael Ubal Tena        lstripped_input_line = input_line.lstrip()
330f9008e63STobias Hieta        is_block = lstripped_input_line[0] == "^"
331a9d4015dSRiver Riddle        if is_block:
332f9008e63STobias Hieta            input_line = input_line.rsplit("//", 1)[0].rstrip()
333a9d4015dSRiver Riddle
33425b38067STim Shen        cur_level = variable_namer.num_scopes()
335a9d4015dSRiver Riddle
336a9d4015dSRiver Riddle        # If the line starts with a '}', pop the last name scope.
337f9008e63STobias Hieta        if lstripped_input_line[0] == "}":
338a9d4015dSRiver Riddle            variable_namer.pop_name_scope()
33925b38067STim Shen            cur_level = variable_namer.num_scopes()
340a9d4015dSRiver Riddle
341a9d4015dSRiver Riddle        # If the line ends with a '{', push a new name scope.
342f9008e63STobias Hieta        if input_line[-1] == "{":
343a9d4015dSRiver Riddle            variable_namer.push_name_scope()
34425b38067STim Shen            if cur_level == args.starts_from_scope:
34525b38067STim Shen                output_segments.append([])
34625b38067STim Shen
347dea01f5eSRafael Ubal Tena            # Result SSA values must still be pushed to parent scope
348dea01f5eSRafael Ubal Tena            num_ssa_results = get_num_ssa_results(input_line)
349dea01f5eSRafael Ubal Tena            variable_namer.generate_in_parent_scope(num_ssa_results)
350dea01f5eSRafael Ubal Tena
35125b38067STim Shen        # Omit lines at the near top level e.g. "module {".
35225b38067STim Shen        if cur_level < args.starts_from_scope:
35325b38067STim Shen            continue
35425b38067STim Shen
35525b38067STim Shen        if len(output_segments[-1]) == 0:
356*dbf798faSBenjamin Maxwell            variable_namer.clear_names()
357a9d4015dSRiver Riddle
3583e2ac62bSRiver Riddle        # Preprocess the input to remove any sequences that may be problematic with
3593e2ac62bSRiver Riddle        # FileCheck.
3603e2ac62bSRiver Riddle        input_line = preprocess_line(input_line)
3613e2ac62bSRiver Riddle
362dea01f5eSRafael Ubal Tena        # Process uses of attributes in this line
363dea01f5eSRafael Ubal Tena        input_line = process_attribute_references(input_line, attribute_namer)
364dea01f5eSRafael Ubal Tena
365a9d4015dSRiver Riddle        # Split the line at the each SSA value name.
366f9008e63STobias Hieta        ssa_split = input_line.split("%")
367a9d4015dSRiver Riddle
368a9d4015dSRiver Riddle        # If this is a top-level operation use 'CHECK-LABEL', otherwise 'CHECK:'.
36925b38067STim Shen        if len(output_segments[-1]) != 0 or not ssa_split[0]:
370f9008e63STobias Hieta            output_line = "// " + args.check_prefix + ": "
371a9d4015dSRiver Riddle            # Pad to align with the 'LABEL' statements.
372f9008e63STobias Hieta            output_line += " " * len("-LABEL")
373a9d4015dSRiver Riddle
374a9d4015dSRiver Riddle            # Output the first line chunk that does not contain an SSA name.
375a9d4015dSRiver Riddle            output_line += ssa_split[0]
376a9d4015dSRiver Riddle
377a9d4015dSRiver Riddle            # Process the rest of the input line.
378a9d4015dSRiver Riddle            output_line += process_line(ssa_split[1:], variable_namer)
379a9d4015dSRiver Riddle
380a9d4015dSRiver Riddle        else:
381a9d4015dSRiver Riddle            # Output the first line chunk that does not contain an SSA name for the
382a9d4015dSRiver Riddle            # label.
383f9008e63STobias Hieta            output_line = "// " + args.check_prefix + "-LABEL: " + ssa_split[0] + "\n"
384a9d4015dSRiver Riddle
38525b38067STim Shen            # Process the rest of the input line on separate check lines.
38625b38067STim Shen            for argument in ssa_split[1:]:
387f9008e63STobias Hieta                output_line += "// " + args.check_prefix + "-SAME:  "
388a9d4015dSRiver Riddle
389a9d4015dSRiver Riddle                # Pad to align with the original position in the line.
390f9008e63STobias Hieta                output_line += " " * len(ssa_split[0])
391a9d4015dSRiver Riddle
392a9d4015dSRiver Riddle                # Process the rest of the line.
39325b38067STim Shen                output_line += process_line([argument], variable_namer)
394a9d4015dSRiver Riddle
395a9d4015dSRiver Riddle        # Append the output line.
39625b38067STim Shen        output_segments[-1].append(output_line)
39725b38067STim Shen
398f9008e63STobias Hieta    output.write(autogenerated_note + "\n")
399a9d4015dSRiver Riddle
400a9d4015dSRiver Riddle    # Write the output.
40125b38067STim Shen    if source_segments:
40225b38067STim Shen        assert len(output_segments) == len(source_segments)
40325b38067STim Shen        for check_segment, source_segment in zip(output_segments, source_segments):
40425b38067STim Shen            for line in check_segment:
40525b38067STim Shen                output.write(line)
40625b38067STim Shen            for line in source_segment:
40725b38067STim Shen                output.write(line)
40825b38067STim Shen    else:
40925b38067STim Shen        for segment in output_segments:
410f9008e63STobias Hieta            output.write("\n")
41125b38067STim Shen            for output_line in segment:
41225b38067STim Shen                output.write(output_line)
413f9008e63STobias Hieta        output.write("\n")
41425b38067STim Shen    output.close()
415a9d4015dSRiver Riddle
416a9d4015dSRiver Riddle
417f9008e63STobias Hietaif __name__ == "__main__":
418a9d4015dSRiver Riddle    main()
419