2019-11-26 10:40:52 -08:00
|
|
|
#!/usr/bin/env python3
|
Add a new utility script that helps update very simple regression tests.
This script is currently specific to x86 and limited to use with very
small regression or feature tests using 'llc' and 'FileCheck' in
a reasonably canonical way. It is in no way general purpose or robust at
this point. However, it works quite well for simple examples. Here is
the intended workflow:
- Make a change that requires updating N test files and M functions'
assertions within those files.
- Stash the change.
- Update those N test files' RUN-lines to look "canonical"[1].
- Refresh the FileCheck lines for either the entire file or select
functions by running this script.
- The script will parse the RUN lines and run the 'llc' binary you
give it according to each line, collecting the asm.
- It will then annotate each function with the appropriate FileCheck
comments to check every instruction from the start of the first
basic block to the last return.
- There will be numerous cases where the script either fails to remove
the old lines, or inserts checks which need to be manually editted,
but the manual edits tend to be deletions or replacements of
registers with FileCheck variables which are fast manual edits.
- A common pattern is to have the script insert complete checking of
every instruction, and then edit it down to only check the relevant
ones.
- Be careful to do all of these cleanups though! The script is
designed to make transferring and formatting the asm output of llc
into a test case fast, it is *not* designed to be authoratitive
about what constitutes a good test!
- Commit the nice fresh baseline of checks.
- Unstash your change and rebuild llc.
- Re-run script to regenerate the FileCheck annotations
- Remember to re-cleanup these annotations!!!
- Check the diff to make sure this is sane, checking the things you
expected it to, and check that the newly updated tests actually pass.
- Profit!
Also, I'm *terrible* at writing Python, and frankly I didn't spend a lot
of time making this script beautiful or well engineered. But it's useful
to me and may be useful to others so I thought I'd send it out.
http://reviews.llvm.org/D5546
llvm-svn: 225618
2015-01-12 04:43:18 +00:00
|
|
|
|
|
|
|
"""A test case update script.
|
|
|
|
|
2018-01-30 00:40:05 +00:00
|
|
|
This script is a utility to update LLVM 'llc' based test cases with new
|
Add a new utility script that helps update very simple regression tests.
This script is currently specific to x86 and limited to use with very
small regression or feature tests using 'llc' and 'FileCheck' in
a reasonably canonical way. It is in no way general purpose or robust at
this point. However, it works quite well for simple examples. Here is
the intended workflow:
- Make a change that requires updating N test files and M functions'
assertions within those files.
- Stash the change.
- Update those N test files' RUN-lines to look "canonical"[1].
- Refresh the FileCheck lines for either the entire file or select
functions by running this script.
- The script will parse the RUN lines and run the 'llc' binary you
give it according to each line, collecting the asm.
- It will then annotate each function with the appropriate FileCheck
comments to check every instruction from the start of the first
basic block to the last return.
- There will be numerous cases where the script either fails to remove
the old lines, or inserts checks which need to be manually editted,
but the manual edits tend to be deletions or replacements of
registers with FileCheck variables which are fast manual edits.
- A common pattern is to have the script insert complete checking of
every instruction, and then edit it down to only check the relevant
ones.
- Be careful to do all of these cleanups though! The script is
designed to make transferring and formatting the asm output of llc
into a test case fast, it is *not* designed to be authoratitive
about what constitutes a good test!
- Commit the nice fresh baseline of checks.
- Unstash your change and rebuild llc.
- Re-run script to regenerate the FileCheck annotations
- Remember to re-cleanup these annotations!!!
- Check the diff to make sure this is sane, checking the things you
expected it to, and check that the newly updated tests actually pass.
- Profit!
Also, I'm *terrible* at writing Python, and frankly I didn't spend a lot
of time making this script beautiful or well engineered. But it's useful
to me and may be useful to others so I thought I'd send it out.
http://reviews.llvm.org/D5546
llvm-svn: 225618
2015-01-12 04:43:18 +00:00
|
|
|
FileCheck patterns. It can either update all of the tests in the file or
|
|
|
|
a single test function.
|
|
|
|
"""
|
|
|
|
|
2019-01-03 14:11:33 +00:00
|
|
|
from __future__ import print_function
|
|
|
|
|
Add a new utility script that helps update very simple regression tests.
This script is currently specific to x86 and limited to use with very
small regression or feature tests using 'llc' and 'FileCheck' in
a reasonably canonical way. It is in no way general purpose or robust at
this point. However, it works quite well for simple examples. Here is
the intended workflow:
- Make a change that requires updating N test files and M functions'
assertions within those files.
- Stash the change.
- Update those N test files' RUN-lines to look "canonical"[1].
- Refresh the FileCheck lines for either the entire file or select
functions by running this script.
- The script will parse the RUN lines and run the 'llc' binary you
give it according to each line, collecting the asm.
- It will then annotate each function with the appropriate FileCheck
comments to check every instruction from the start of the first
basic block to the last return.
- There will be numerous cases where the script either fails to remove
the old lines, or inserts checks which need to be manually editted,
but the manual edits tend to be deletions or replacements of
registers with FileCheck variables which are fast manual edits.
- A common pattern is to have the script insert complete checking of
every instruction, and then edit it down to only check the relevant
ones.
- Be careful to do all of these cleanups though! The script is
designed to make transferring and formatting the asm output of llc
into a test case fast, it is *not* designed to be authoratitive
about what constitutes a good test!
- Commit the nice fresh baseline of checks.
- Unstash your change and rebuild llc.
- Re-run script to regenerate the FileCheck annotations
- Remember to re-cleanup these annotations!!!
- Check the diff to make sure this is sane, checking the things you
expected it to, and check that the newly updated tests actually pass.
- Profit!
Also, I'm *terrible* at writing Python, and frankly I didn't spend a lot
of time making this script beautiful or well engineered. But it's useful
to me and may be useful to others so I thought I'd send it out.
http://reviews.llvm.org/D5546
llvm-svn: 225618
2015-01-12 04:43:18 +00:00
|
|
|
import argparse
|
2020-07-08 10:59:50 +01:00
|
|
|
import os # Used to advertise this file's name ("autogenerated_note").
|
Add a new utility script that helps update very simple regression tests.
This script is currently specific to x86 and limited to use with very
small regression or feature tests using 'llc' and 'FileCheck' in
a reasonably canonical way. It is in no way general purpose or robust at
this point. However, it works quite well for simple examples. Here is
the intended workflow:
- Make a change that requires updating N test files and M functions'
assertions within those files.
- Stash the change.
- Update those N test files' RUN-lines to look "canonical"[1].
- Refresh the FileCheck lines for either the entire file or select
functions by running this script.
- The script will parse the RUN lines and run the 'llc' binary you
give it according to each line, collecting the asm.
- It will then annotate each function with the appropriate FileCheck
comments to check every instruction from the start of the first
basic block to the last return.
- There will be numerous cases where the script either fails to remove
the old lines, or inserts checks which need to be manually editted,
but the manual edits tend to be deletions or replacements of
registers with FileCheck variables which are fast manual edits.
- A common pattern is to have the script insert complete checking of
every instruction, and then edit it down to only check the relevant
ones.
- Be careful to do all of these cleanups though! The script is
designed to make transferring and formatting the asm output of llc
into a test case fast, it is *not* designed to be authoratitive
about what constitutes a good test!
- Commit the nice fresh baseline of checks.
- Unstash your change and rebuild llc.
- Re-run script to regenerate the FileCheck annotations
- Remember to re-cleanup these annotations!!!
- Check the diff to make sure this is sane, checking the things you
expected it to, and check that the newly updated tests actually pass.
- Profit!
Also, I'm *terrible* at writing Python, and frankly I didn't spend a lot
of time making this script beautiful or well engineered. But it's useful
to me and may be useful to others so I thought I'd send it out.
http://reviews.llvm.org/D5546
llvm-svn: 225618
2015-01-12 04:43:18 +00:00
|
|
|
|
2022-03-01 10:54:24 +01:00
|
|
|
from UpdateTestChecks import common
|
2016-03-24 17:15:42 +00:00
|
|
|
|
2020-06-01 11:50:53 -07:00
|
|
|
# llc is the only llc-like in the LLVM tree but downstream forks can add
|
|
|
|
# additional ones here if they have them.
|
2024-05-27 19:17:04 +02:00
|
|
|
LLC_LIKE_TOOLS = [
|
|
|
|
"llc",
|
|
|
|
]
|
2023-05-15 11:02:42 +02:00
|
|
|
|
2016-03-24 17:15:42 +00:00
|
|
|
|
Add a new utility script that helps update very simple regression tests.
This script is currently specific to x86 and limited to use with very
small regression or feature tests using 'llc' and 'FileCheck' in
a reasonably canonical way. It is in no way general purpose or robust at
this point. However, it works quite well for simple examples. Here is
the intended workflow:
- Make a change that requires updating N test files and M functions'
assertions within those files.
- Stash the change.
- Update those N test files' RUN-lines to look "canonical"[1].
- Refresh the FileCheck lines for either the entire file or select
functions by running this script.
- The script will parse the RUN lines and run the 'llc' binary you
give it according to each line, collecting the asm.
- It will then annotate each function with the appropriate FileCheck
comments to check every instruction from the start of the first
basic block to the last return.
- There will be numerous cases where the script either fails to remove
the old lines, or inserts checks which need to be manually editted,
but the manual edits tend to be deletions or replacements of
registers with FileCheck variables which are fast manual edits.
- A common pattern is to have the script insert complete checking of
every instruction, and then edit it down to only check the relevant
ones.
- Be careful to do all of these cleanups though! The script is
designed to make transferring and formatting the asm output of llc
into a test case fast, it is *not* designed to be authoratitive
about what constitutes a good test!
- Commit the nice fresh baseline of checks.
- Unstash your change and rebuild llc.
- Re-run script to regenerate the FileCheck annotations
- Remember to re-cleanup these annotations!!!
- Check the diff to make sure this is sane, checking the things you
expected it to, and check that the newly updated tests actually pass.
- Profit!
Also, I'm *terrible* at writing Python, and frankly I didn't spend a lot
of time making this script beautiful or well engineered. But it's useful
to me and may be useful to others so I thought I'd send it out.
http://reviews.llvm.org/D5546
llvm-svn: 225618
2015-01-12 04:43:18 +00:00
|
|
|
def main():
|
2023-05-15 11:02:42 +02:00
|
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
|
|
parser.add_argument(
|
|
|
|
"--llc-binary",
|
|
|
|
default=None,
|
|
|
|
help='The "llc" binary to use to generate the test case',
|
|
|
|
)
|
|
|
|
parser.add_argument("--function", help="The function in the test file to update")
|
|
|
|
parser.add_argument(
|
|
|
|
"--extra_scrub",
|
|
|
|
action="store_true",
|
|
|
|
help="Always use additional regex to further reduce diffs between various subtargets",
|
|
|
|
)
|
|
|
|
parser.add_argument(
|
|
|
|
"--x86_scrub_sp",
|
|
|
|
action="store_true",
|
|
|
|
default=True,
|
|
|
|
help="Use regex for x86 sp matching to reduce diffs between various subtargets",
|
|
|
|
)
|
|
|
|
parser.add_argument("--no_x86_scrub_sp", action="store_false", dest="x86_scrub_sp")
|
|
|
|
parser.add_argument(
|
|
|
|
"--x86_scrub_rip",
|
|
|
|
action="store_true",
|
|
|
|
default=False,
|
|
|
|
help="Use more regex for x86 rip matching to reduce diffs between various subtargets",
|
|
|
|
)
|
|
|
|
parser.add_argument(
|
|
|
|
"--no_x86_scrub_rip", action="store_false", dest="x86_scrub_rip"
|
|
|
|
)
|
|
|
|
parser.add_argument(
|
|
|
|
"--no_x86_scrub_mem_shuffle",
|
|
|
|
action="store_true",
|
|
|
|
default=False,
|
|
|
|
help="Reduce scrubbing shuffles with memory operands",
|
|
|
|
)
|
2024-05-27 19:17:04 +02:00
|
|
|
parser.add_argument(
|
|
|
|
"--tool",
|
|
|
|
default=None,
|
|
|
|
help="Treat the given tool name as an llc-like tool for which check lines should be generated",
|
|
|
|
)
|
|
|
|
parser.add_argument(
|
|
|
|
"--default-march",
|
|
|
|
default=None,
|
|
|
|
help="Set a default -march for when neither triple nor arch are found in a RUN line",
|
|
|
|
)
|
2023-05-15 11:02:42 +02:00
|
|
|
parser.add_argument("tests", nargs="+")
|
|
|
|
initial_args = common.parse_commandline_args(parser)
|
|
|
|
|
|
|
|
script_name = os.path.basename(__file__)
|
|
|
|
|
|
|
|
for ti in common.itertests(
|
|
|
|
initial_args.tests, parser, script_name="utils/" + script_name
|
|
|
|
):
|
|
|
|
triple_in_ir = None
|
|
|
|
for l in ti.input_lines:
|
|
|
|
m = common.TRIPLE_IR_RE.match(l)
|
|
|
|
if m:
|
|
|
|
triple_in_ir = m.groups()[0]
|
|
|
|
break
|
|
|
|
|
|
|
|
run_list = []
|
|
|
|
for l in ti.run_lines:
|
|
|
|
if "|" not in l:
|
|
|
|
common.warn("Skipping unparsable RUN line: " + l)
|
|
|
|
continue
|
|
|
|
|
|
|
|
commands = [cmd.strip() for cmd in l.split("|")]
|
|
|
|
assert len(commands) >= 2
|
|
|
|
preprocess_cmd = None
|
|
|
|
if len(commands) > 2:
|
|
|
|
preprocess_cmd = " | ".join(commands[:-2])
|
|
|
|
llc_cmd = commands[-2]
|
|
|
|
filecheck_cmd = commands[-1]
|
|
|
|
llc_tool = llc_cmd.split(" ")[0]
|
|
|
|
|
|
|
|
triple_in_cmd = None
|
|
|
|
m = common.TRIPLE_ARG_RE.search(llc_cmd)
|
|
|
|
if m:
|
|
|
|
triple_in_cmd = m.groups()[0]
|
|
|
|
|
2024-05-27 19:17:04 +02:00
|
|
|
march_in_cmd = ti.args.default_march
|
2023-05-15 11:02:42 +02:00
|
|
|
m = common.MARCH_ARG_RE.search(llc_cmd)
|
|
|
|
if m:
|
|
|
|
march_in_cmd = m.groups()[0]
|
|
|
|
|
|
|
|
m = common.DEBUG_ONLY_ARG_RE.search(llc_cmd)
|
|
|
|
if m and m.groups()[0] == "isel":
|
|
|
|
from UpdateTestChecks import isel as output_type
|
|
|
|
else:
|
|
|
|
from UpdateTestChecks import asm as output_type
|
|
|
|
|
|
|
|
common.verify_filecheck_prefixes(filecheck_cmd)
|
2024-05-27 19:17:04 +02:00
|
|
|
|
|
|
|
llc_like_tools = LLC_LIKE_TOOLS[:]
|
|
|
|
if ti.args.tool:
|
|
|
|
llc_like_tools.append(ti.args.tool)
|
|
|
|
if llc_tool not in llc_like_tools:
|
2023-05-15 11:02:42 +02:00
|
|
|
common.warn("Skipping non-llc RUN line: " + l)
|
|
|
|
continue
|
|
|
|
|
|
|
|
if not filecheck_cmd.startswith("FileCheck "):
|
|
|
|
common.warn("Skipping non-FileChecked RUN line: " + l)
|
|
|
|
continue
|
|
|
|
|
|
|
|
llc_cmd_args = llc_cmd[len(llc_tool) :].strip()
|
|
|
|
llc_cmd_args = llc_cmd_args.replace("< %s", "").replace("%s", "").strip()
|
|
|
|
if ti.path.endswith(".mir"):
|
|
|
|
llc_cmd_args += " -x mir"
|
|
|
|
check_prefixes = common.get_check_prefixes(filecheck_cmd)
|
|
|
|
|
|
|
|
# FIXME: We should use multiple check prefixes to common check lines. For
|
|
|
|
# now, we just ignore all but the last.
|
|
|
|
run_list.append(
|
|
|
|
(
|
|
|
|
check_prefixes,
|
|
|
|
llc_tool,
|
|
|
|
llc_cmd_args,
|
|
|
|
preprocess_cmd,
|
|
|
|
triple_in_cmd,
|
|
|
|
march_in_cmd,
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
if ti.path.endswith(".mir"):
|
|
|
|
check_indent = " "
|
|
|
|
else:
|
|
|
|
check_indent = ""
|
|
|
|
|
update_test_checks: match IR basic block labels (#88979)
Labels are matched using a regexp of the form '^(pattern):', which
requires the addition of a "suffix" concept to NamelessValue.
Aside from that, the key challenge is that block labels are values, and
we typically capture values including the prefix '%'. However, when
labels appear at the start of a basic block, the prefix '%' is not
included, so we must capture block label values *without* the prefix
'%'.
We don't know ahead of time whether an IR value is a label or not. In
most cases, they are prefixed by the word "label" (their type), but this
isn't the case in phi nodes. We solve this issue by leveraging the
two-phase nature of variable generalization: the first pass finds all
occurences of a variable and determines whether the '%' prefix can be
included or not. The second pass does the actual substitution.
This change also unifies the generalization path for assembly with that
for IR and analysis, in the hope that any future changes avoid diverging
those cases future.
I also considered the alternative of trying to detect the phi node case
using more regular expression special cases but ultimately decided
against that because it seemed more fragile, and perhaps the approach of
keeping a tentative prefix that may later be discarded could also be
eventually applied to some metadata and attribute cases.
Note that an early version of this change was reviewed as
https://reviews.llvm.org/D142452, before version numbers were
introduced. This is a substantially updated version of that change.
2024-05-19 01:39:47 +02:00
|
|
|
ginfo = common.make_asm_generalizer(version=1)
|
2023-05-15 11:02:42 +02:00
|
|
|
builder = common.FunctionTestBuilder(
|
|
|
|
run_list=run_list,
|
|
|
|
flags=type(
|
|
|
|
"",
|
|
|
|
(object,),
|
|
|
|
{
|
|
|
|
"verbose": ti.args.verbose,
|
|
|
|
"filters": ti.args.filters,
|
|
|
|
"function_signature": False,
|
|
|
|
"check_attributes": False,
|
|
|
|
"replace_value_regex": [],
|
|
|
|
},
|
|
|
|
),
|
|
|
|
scrubber_args=[ti.args],
|
|
|
|
path=ti.path,
|
update_test_checks: match IR basic block labels (#88979)
Labels are matched using a regexp of the form '^(pattern):', which
requires the addition of a "suffix" concept to NamelessValue.
Aside from that, the key challenge is that block labels are values, and
we typically capture values including the prefix '%'. However, when
labels appear at the start of a basic block, the prefix '%' is not
included, so we must capture block label values *without* the prefix
'%'.
We don't know ahead of time whether an IR value is a label or not. In
most cases, they are prefixed by the word "label" (their type), but this
isn't the case in phi nodes. We solve this issue by leveraging the
two-phase nature of variable generalization: the first pass finds all
occurences of a variable and determines whether the '%' prefix can be
included or not. The second pass does the actual substitution.
This change also unifies the generalization path for assembly with that
for IR and analysis, in the hope that any future changes avoid diverging
those cases future.
I also considered the alternative of trying to detect the phi node case
using more regular expression special cases but ultimately decided
against that because it seemed more fragile, and perhaps the approach of
keeping a tentative prefix that may later be discarded could also be
eventually applied to some metadata and attribute cases.
Note that an early version of this change was reviewed as
https://reviews.llvm.org/D142452, before version numbers were
introduced. This is a substantially updated version of that change.
2024-05-19 01:39:47 +02:00
|
|
|
ginfo=ginfo,
|
2023-05-15 11:02:42 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
for (
|
|
|
|
prefixes,
|
|
|
|
llc_tool,
|
|
|
|
llc_args,
|
|
|
|
preprocess_cmd,
|
|
|
|
triple_in_cmd,
|
|
|
|
march_in_cmd,
|
|
|
|
) in run_list:
|
|
|
|
common.debug("Extracted LLC cmd:", llc_tool, llc_args)
|
|
|
|
common.debug("Extracted FileCheck prefixes:", str(prefixes))
|
|
|
|
|
|
|
|
raw_tool_output = common.invoke_tool(
|
|
|
|
ti.args.llc_binary or llc_tool,
|
|
|
|
llc_args,
|
|
|
|
ti.path,
|
|
|
|
preprocess_cmd,
|
|
|
|
verbose=ti.args.verbose,
|
|
|
|
)
|
|
|
|
triple = triple_in_cmd or triple_in_ir
|
|
|
|
if not triple:
|
|
|
|
triple = common.get_triple_from_march(march_in_cmd)
|
|
|
|
|
|
|
|
scrubber, function_re = output_type.get_run_handler(triple)
|
update_test_checks: match IR basic block labels (#88979)
Labels are matched using a regexp of the form '^(pattern):', which
requires the addition of a "suffix" concept to NamelessValue.
Aside from that, the key challenge is that block labels are values, and
we typically capture values including the prefix '%'. However, when
labels appear at the start of a basic block, the prefix '%' is not
included, so we must capture block label values *without* the prefix
'%'.
We don't know ahead of time whether an IR value is a label or not. In
most cases, they are prefixed by the word "label" (their type), but this
isn't the case in phi nodes. We solve this issue by leveraging the
two-phase nature of variable generalization: the first pass finds all
occurences of a variable and determines whether the '%' prefix can be
included or not. The second pass does the actual substitution.
This change also unifies the generalization path for assembly with that
for IR and analysis, in the hope that any future changes avoid diverging
those cases future.
I also considered the alternative of trying to detect the phi node case
using more regular expression special cases but ultimately decided
against that because it seemed more fragile, and perhaps the approach of
keeping a tentative prefix that may later be discarded could also be
eventually applied to some metadata and attribute cases.
Note that an early version of this change was reviewed as
https://reviews.llvm.org/D142452, before version numbers were
introduced. This is a substantially updated version of that change.
2024-05-19 01:39:47 +02:00
|
|
|
builder.process_run_line(function_re, scrubber, raw_tool_output, prefixes)
|
2023-05-15 11:02:42 +02:00
|
|
|
builder.processed_prefixes(prefixes)
|
|
|
|
|
|
|
|
func_dict = builder.finish_and_get_func_dict()
|
|
|
|
global_vars_seen_dict = {}
|
|
|
|
|
|
|
|
is_in_function = False
|
|
|
|
is_in_function_start = False
|
|
|
|
func_name = None
|
|
|
|
prefix_set = set([prefix for p in run_list for prefix in p[0]])
|
|
|
|
common.debug("Rewriting FileCheck prefixes:", str(prefix_set))
|
|
|
|
output_lines = []
|
|
|
|
|
|
|
|
include_generated_funcs = common.find_arg_in_test(
|
|
|
|
ti,
|
|
|
|
lambda args: ti.args.include_generated_funcs,
|
|
|
|
"--include-generated-funcs",
|
|
|
|
True,
|
|
|
|
)
|
|
|
|
|
|
|
|
generated_prefixes = []
|
|
|
|
if include_generated_funcs:
|
|
|
|
# Generate the appropriate checks for each function. We need to emit
|
|
|
|
# these in the order according to the generated output so that CHECK-LABEL
|
|
|
|
# works properly. func_order provides that.
|
|
|
|
|
|
|
|
# We can't predict where various passes might insert functions so we can't
|
|
|
|
# be sure the input function order is maintained. Therefore, first spit
|
|
|
|
# out all the source lines.
|
|
|
|
common.dump_input_lines(output_lines, ti, prefix_set, ";")
|
|
|
|
|
|
|
|
# Now generate all the checks.
|
|
|
|
generated_prefixes = common.add_checks_at_end(
|
|
|
|
output_lines,
|
|
|
|
run_list,
|
|
|
|
builder.func_order(),
|
|
|
|
check_indent + ";",
|
|
|
|
lambda my_output_lines, prefixes, func: output_type.add_checks(
|
|
|
|
my_output_lines,
|
|
|
|
check_indent + ";",
|
|
|
|
prefixes,
|
|
|
|
func_dict,
|
|
|
|
func,
|
update_test_checks: match IR basic block labels (#88979)
Labels are matched using a regexp of the form '^(pattern):', which
requires the addition of a "suffix" concept to NamelessValue.
Aside from that, the key challenge is that block labels are values, and
we typically capture values including the prefix '%'. However, when
labels appear at the start of a basic block, the prefix '%' is not
included, so we must capture block label values *without* the prefix
'%'.
We don't know ahead of time whether an IR value is a label or not. In
most cases, they are prefixed by the word "label" (their type), but this
isn't the case in phi nodes. We solve this issue by leveraging the
two-phase nature of variable generalization: the first pass finds all
occurences of a variable and determines whether the '%' prefix can be
included or not. The second pass does the actual substitution.
This change also unifies the generalization path for assembly with that
for IR and analysis, in the hope that any future changes avoid diverging
those cases future.
I also considered the alternative of trying to detect the phi node case
using more regular expression special cases but ultimately decided
against that because it seemed more fragile, and perhaps the approach of
keeping a tentative prefix that may later be discarded could also be
eventually applied to some metadata and attribute cases.
Note that an early version of this change was reviewed as
https://reviews.llvm.org/D142452, before version numbers were
introduced. This is a substantially updated version of that change.
2024-05-19 01:39:47 +02:00
|
|
|
ginfo,
|
2023-05-15 11:02:42 +02:00
|
|
|
global_vars_seen_dict,
|
|
|
|
is_filtered=builder.is_filtered(),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
else:
|
|
|
|
for input_info in ti.iterlines(output_lines):
|
|
|
|
input_line = input_info.line
|
|
|
|
args = input_info.args
|
|
|
|
if is_in_function_start:
|
|
|
|
if input_line == "":
|
|
|
|
continue
|
|
|
|
if input_line.lstrip().startswith(";"):
|
|
|
|
m = common.CHECK_RE.match(input_line)
|
|
|
|
if not m or m.group(1) not in prefix_set:
|
|
|
|
output_lines.append(input_line)
|
|
|
|
continue
|
|
|
|
|
|
|
|
# Print out the various check lines here.
|
|
|
|
generated_prefixes.extend(
|
|
|
|
output_type.add_checks(
|
|
|
|
output_lines,
|
|
|
|
check_indent + ";",
|
|
|
|
run_list,
|
|
|
|
func_dict,
|
|
|
|
func_name,
|
update_test_checks: match IR basic block labels (#88979)
Labels are matched using a regexp of the form '^(pattern):', which
requires the addition of a "suffix" concept to NamelessValue.
Aside from that, the key challenge is that block labels are values, and
we typically capture values including the prefix '%'. However, when
labels appear at the start of a basic block, the prefix '%' is not
included, so we must capture block label values *without* the prefix
'%'.
We don't know ahead of time whether an IR value is a label or not. In
most cases, they are prefixed by the word "label" (their type), but this
isn't the case in phi nodes. We solve this issue by leveraging the
two-phase nature of variable generalization: the first pass finds all
occurences of a variable and determines whether the '%' prefix can be
included or not. The second pass does the actual substitution.
This change also unifies the generalization path for assembly with that
for IR and analysis, in the hope that any future changes avoid diverging
those cases future.
I also considered the alternative of trying to detect the phi node case
using more regular expression special cases but ultimately decided
against that because it seemed more fragile, and perhaps the approach of
keeping a tentative prefix that may later be discarded could also be
eventually applied to some metadata and attribute cases.
Note that an early version of this change was reviewed as
https://reviews.llvm.org/D142452, before version numbers were
introduced. This is a substantially updated version of that change.
2024-05-19 01:39:47 +02:00
|
|
|
ginfo,
|
2023-05-15 11:02:42 +02:00
|
|
|
global_vars_seen_dict,
|
|
|
|
is_filtered=builder.is_filtered(),
|
|
|
|
)
|
|
|
|
)
|
|
|
|
is_in_function_start = False
|
|
|
|
|
|
|
|
if is_in_function:
|
|
|
|
if common.should_add_line_to_output(input_line, prefix_set):
|
|
|
|
# This input line of the function body will go as-is into the output.
|
|
|
|
output_lines.append(input_line)
|
|
|
|
else:
|
|
|
|
continue
|
|
|
|
if input_line.strip() == "}":
|
|
|
|
is_in_function = False
|
|
|
|
continue
|
|
|
|
|
|
|
|
# If it's outside a function, it just gets copied to the output.
|
|
|
|
output_lines.append(input_line)
|
|
|
|
|
|
|
|
m = common.IR_FUNCTION_RE.match(input_line)
|
|
|
|
if not m:
|
|
|
|
continue
|
|
|
|
func_name = m.group(1)
|
|
|
|
if args.function is not None and func_name != args.function:
|
|
|
|
# When filtering on a specific function, skip all others.
|
|
|
|
continue
|
|
|
|
is_in_function = is_in_function_start = True
|
|
|
|
|
|
|
|
if ti.args.gen_unused_prefix_body:
|
|
|
|
output_lines.extend(
|
|
|
|
ti.get_checks_for_unused_prefixes(run_list, generated_prefixes)
|
|
|
|
)
|
|
|
|
|
|
|
|
common.debug("Writing %d lines to %s..." % (len(output_lines), ti.path))
|
|
|
|
with open(ti.path, "wb") as f:
|
|
|
|
f.writelines(["{}\n".format(l).encode("utf-8") for l in output_lines])
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
main()
|