mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 12:41:49 +01:00
[UpdateTestChecks] Add UTC_ARGS support for update_{llc,cc}_test_checks.py
https://reviews.llvm.org/D69701 added support for on-the-fly argument changes for update scripts. I recently wanted to keep some manual check lines in a test generated by update_cc_test_checks.py in our CHERI fork, so this commit adds support for UTC_ARGS in update_cc_test_checks.py. And since I was refactoring the code to be in common.py, I also added it for update_llc_test_checks.py. Reviewed By: jdoerfert, MaskRay Differential Revision: https://reviews.llvm.org/D78478
This commit is contained in:
parent
199e49d00e
commit
e7f8cb8118
@ -1,4 +1,3 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
|
||||
; Example input for update_llc_test_checks (taken from CodeGen/X86/iabs.ll)
|
||||
; RUN: llc < %s -mtriple=i686-unknown-unknown | FileCheck %s --check-prefix=X86 --check-prefix=X86-NO-CMOV
|
||||
; RUN: llc < %s -mtriple=i686-unknown-unknown -mattr=+cmov | FileCheck %s --check-prefix=X86 --check-prefix=X86-CMOV
|
||||
|
@ -0,0 +1,22 @@
|
||||
; RUN: llc < %s -mtriple=i686-unknown-unknown | FileCheck %s
|
||||
|
||||
declare void @foo()
|
||||
|
||||
define i64 @check_lines_1() {
|
||||
ret i64 1
|
||||
}
|
||||
|
||||
; UTC_ARGS: --disable
|
||||
|
||||
define i64 @no_check_lines() {
|
||||
; A check line that would not be auto-generated (should not be removed!).
|
||||
; CHECK: manual check line
|
||||
ret i64 2
|
||||
}
|
||||
|
||||
; UTC_ARGS: --enable --no_x86_scrub_rip
|
||||
|
||||
define i64 @check_lines_2() {
|
||||
%result = call i64 @no_check_lines()
|
||||
ret i64 %result
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
|
||||
; RUN: llc < %s -mtriple=i686-unknown-unknown | FileCheck %s
|
||||
|
||||
declare void @foo()
|
||||
|
||||
define i64 @check_lines_1() {
|
||||
; CHECK-LABEL: check_lines_1:
|
||||
; CHECK: # %bb.0:
|
||||
; CHECK-NEXT: movl $1, %eax
|
||||
; CHECK-NEXT: xorl %edx, %edx
|
||||
; CHECK-NEXT: retl
|
||||
ret i64 1
|
||||
}
|
||||
|
||||
; UTC_ARGS: --disable
|
||||
|
||||
define i64 @no_check_lines() {
|
||||
; A check line that would not be auto-generated (should not be removed!).
|
||||
; CHECK: manual check line
|
||||
ret i64 2
|
||||
}
|
||||
|
||||
; UTC_ARGS: --enable --no_x86_scrub_rip
|
||||
|
||||
define i64 @check_lines_2() {
|
||||
; CHECK-LABEL: check_lines_2:
|
||||
; CHECK: # %bb.0:
|
||||
; CHECK-NEXT: calll no_check_lines
|
||||
; CHECK-NEXT: retl
|
||||
%result = call i64 @no_check_lines()
|
||||
ret i64 %result
|
||||
}
|
@ -2,14 +2,24 @@
|
||||
## Basic test checking that update_llc_test_checks.py can update a file with multiple check prefixes
|
||||
|
||||
# RUN: cp -f %S/Inputs/basic.ll %t.ll && %update_llc_test_checks %t.ll
|
||||
# RUN: diff -u %S/Inputs/basic.ll.expected %t.ll
|
||||
## The flags --x86_scrub_rip and --extra_scrub should have any effect for this
|
||||
# RUN: echo '; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py' > %t.expected.ll
|
||||
# RUN: cat %S/Inputs/basic.ll.expected >> %t.expected.ll
|
||||
# RUN: diff -u %t.expected.ll %t.ll
|
||||
|
||||
## The flags --x86_scrub_rip and --extra_scrub should not have any effect on this
|
||||
## test. Check the output is identical.
|
||||
# RUN: cp -f %S/Inputs/basic.ll %t.ll && %update_llc_test_checks --extra_scrub %t.ll
|
||||
# RUN: diff -u %S/Inputs/basic.ll.expected %t.ll
|
||||
# RUN: cp -f %S/Inputs/basic.ll %t.ll && %update_llc_test_checks --x86_scrub_rip %t.ll
|
||||
# RUN: diff -u %S/Inputs/basic.ll.expected %t.ll
|
||||
# RUN: cp -f %S/Inputs/basic.ll %t.ll && %update_llc_test_checks --extra_scrub %t.ll
|
||||
# RUN: echo '; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --extra_scrub' > %t.expected.ll
|
||||
# RUN: cat %S/Inputs/basic.ll.expected >> %t.expected.ll
|
||||
# RUN: diff -u %t.expected.ll %t.ll
|
||||
# RUN: cp -f %S/Inputs/basic.ll %t.ll && %update_llc_test_checks --no_x86_scrub_rip %t.ll
|
||||
# RUN: echo '; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --no_x86_scrub_rip' > %t.expected.ll
|
||||
# RUN: cat %S/Inputs/basic.ll.expected >> %t.expected.ll
|
||||
# RUN: diff -u %t.expected.ll %t.ll
|
||||
|
||||
## Finally, run the script on an already updated file and verify that all previous
|
||||
## CHECK lines are removed.
|
||||
# RUN: %update_llc_test_checks %t.ll
|
||||
# RUN: diff -u %S/Inputs/basic.ll.expected %t.ll
|
||||
# RUN: echo '; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --no_x86_scrub_rip' > %t.expected.ll
|
||||
# RUN: cat %S/Inputs/basic.ll.expected >> %t.expected.ll
|
||||
# RUN: diff -u %t.expected.ll %t.ll
|
||||
|
@ -0,0 +1,6 @@
|
||||
# RUN: cp -f %S/Inputs/on_the_fly_arg_change.ll %t.ll
|
||||
# RUN: %update_llc_test_checks %t.ll
|
||||
# RUN: diff -u %t.ll %S/Inputs/on_the_fly_arg_change.ll.expected
|
||||
## Check that running the script again does not change the result:
|
||||
# RUN: %update_llc_test_checks %t.ll
|
||||
# RUN: diff -u %t.ll %S/Inputs/on_the_fly_arg_change.ll.expected
|
@ -19,16 +19,13 @@ import collections
|
||||
import distutils.spawn
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import shlex
|
||||
import string
|
||||
import subprocess
|
||||
import sys
|
||||
import re
|
||||
import tempfile
|
||||
|
||||
from UpdateTestChecks import asm, common
|
||||
|
||||
ADVERT = '// NOTE: Assertions have been autogenerated by '
|
||||
from UpdateTestChecks import common
|
||||
|
||||
SUBST = {
|
||||
'%clang': [],
|
||||
@ -110,6 +107,11 @@ def get_line2spell_and_mangled(args, clang_args):
|
||||
return ret
|
||||
|
||||
|
||||
def str_to_commandline(value):
|
||||
if not value:
|
||||
return []
|
||||
return shlex.split(value)
|
||||
|
||||
def config():
|
||||
parser = argparse.ArgumentParser(
|
||||
description=__doc__,
|
||||
@ -117,7 +119,7 @@ def config():
|
||||
parser.add_argument('--llvm-bin', help='llvm $prefix/bin path')
|
||||
parser.add_argument('--clang',
|
||||
help='"clang" executable, defaults to $llvm_bin/clang')
|
||||
parser.add_argument('--clang-args',
|
||||
parser.add_argument('--clang-args', default=[], type=str_to_commandline,
|
||||
help='Space-separated extra args to clang, e.g. --clang-args=-v')
|
||||
parser.add_argument('--opt',
|
||||
help='"opt" executable, defaults to $llvm_bin/opt')
|
||||
@ -131,7 +133,6 @@ def config():
|
||||
help='Keep function signature information around for the check line')
|
||||
parser.add_argument('tests', nargs='+')
|
||||
args = common.parse_commandline_args(parser)
|
||||
args.clang_args = shlex.split(args.clang_args or '')
|
||||
|
||||
if args.clang is None:
|
||||
if args.llvm_bin is None:
|
||||
@ -165,7 +166,7 @@ def config():
|
||||
# defer this error message until we find that opt is actually needed.
|
||||
args.opt = None
|
||||
|
||||
return args
|
||||
return args, parser
|
||||
|
||||
|
||||
def get_function_body(args, filename, clang_args, extra_commands, prefixes, triple_in_cmd, func_dict):
|
||||
@ -196,31 +197,15 @@ def get_function_body(args, filename, clang_args, extra_commands, prefixes, trip
|
||||
|
||||
|
||||
def main():
|
||||
args = config()
|
||||
initial_args, parser = config()
|
||||
script_name = os.path.basename(__file__)
|
||||
autogenerated_note = (ADVERT + 'utils/' + script_name)
|
||||
|
||||
for filename in args.tests:
|
||||
with open(filename) as f:
|
||||
input_lines = [l.rstrip() for l in f]
|
||||
|
||||
first_line = input_lines[0] if input_lines else ""
|
||||
if 'autogenerated' in first_line and script_name not in first_line:
|
||||
common.warn("Skipping test which wasn't autogenerated by " + script_name, filename)
|
||||
continue
|
||||
|
||||
if args.update_only:
|
||||
if not first_line or 'autogenerated' not in first_line:
|
||||
common.warn("Skipping test which isn't autogenerated: " + filename)
|
||||
continue
|
||||
|
||||
# Extract RUN lines.
|
||||
run_lines = common.find_run_lines(filename, input_lines)
|
||||
|
||||
for ti in common.itertests(initial_args.tests, parser, 'utils/' + script_name,
|
||||
comment_prefix='//'):
|
||||
# Build a list of clang command lines and check prefixes from RUN lines.
|
||||
run_list = []
|
||||
line2spell_and_mangled_list = collections.defaultdict(list)
|
||||
for l in run_lines:
|
||||
for l in ti.run_lines:
|
||||
commands = [cmd.strip() for cmd in l.split('|')]
|
||||
|
||||
triple_in_cmd = None
|
||||
@ -234,7 +219,7 @@ def main():
|
||||
print('WARNING: Skipping non-clang RUN line: ' + l, file=sys.stderr)
|
||||
continue
|
||||
clang_args[0:1] = SUBST[clang_args[0]]
|
||||
clang_args = [filename if i == '%s' else i for i in clang_args] + args.clang_args
|
||||
clang_args = [ti.path if i == '%s' else i for i in clang_args] + ti.args.clang_args
|
||||
|
||||
# Permit piping the output through opt
|
||||
if not (len(commands) == 2 or
|
||||
@ -253,18 +238,6 @@ def main():
|
||||
check_prefixes = ['CHECK']
|
||||
run_list.append((check_prefixes, clang_args, commands[1:-1], triple_in_cmd))
|
||||
|
||||
# Strip CHECK lines which are in `prefix_set`, update test file.
|
||||
prefix_set = set([prefix for p in run_list for prefix in p[0]])
|
||||
input_lines = []
|
||||
with open(filename, 'r+') as f:
|
||||
for line in f:
|
||||
m = common.CHECK_RE.match(line)
|
||||
if not (m and m.group(1) in prefix_set) and line != '//\n':
|
||||
input_lines.append(line)
|
||||
f.seek(0)
|
||||
f.writelines(input_lines)
|
||||
f.truncate()
|
||||
|
||||
# Execute clang, generate LLVM IR, and extract functions.
|
||||
func_dict = {}
|
||||
for p in run_list:
|
||||
@ -275,18 +248,23 @@ def main():
|
||||
common.debug('Extracted clang cmd: clang {}'.format(clang_args))
|
||||
common.debug('Extracted FileCheck prefixes: {}'.format(prefixes))
|
||||
|
||||
get_function_body(args, filename, clang_args, extra_commands, prefixes, triple_in_cmd, func_dict)
|
||||
get_function_body(ti.args, ti.path, clang_args, extra_commands, prefixes, triple_in_cmd, func_dict)
|
||||
|
||||
# Invoke clang -Xclang -ast-dump=json to get mapping from start lines to
|
||||
# mangled names. Forward all clang args for now.
|
||||
for k, v in get_line2spell_and_mangled(args, clang_args).items():
|
||||
for k, v in get_line2spell_and_mangled(ti.args, clang_args).items():
|
||||
line2spell_and_mangled_list[k].append(v)
|
||||
|
||||
output_lines = [autogenerated_note]
|
||||
for idx, line in enumerate(input_lines):
|
||||
# Discard any previous script advertising.
|
||||
if line.startswith(ADVERT):
|
||||
continue
|
||||
prefix_set = set([prefix for p in run_list for prefix in p[0]])
|
||||
output_lines = []
|
||||
for line_info in ti.iterlines(output_lines):
|
||||
idx = line_info.line_number
|
||||
line = line_info.line
|
||||
args = line_info.args
|
||||
include_line = True
|
||||
m = common.CHECK_RE.match(line)
|
||||
if m and m.group(1) in prefix_set:
|
||||
continue # Don't append the existing CHECK lines
|
||||
if idx in line2spell_and_mangled_list:
|
||||
added = set()
|
||||
for spell, mangled in line2spell_and_mangled_list[idx]:
|
||||
@ -298,16 +276,25 @@ def main():
|
||||
if mangled in added or spell not in line:
|
||||
continue
|
||||
if args.functions is None or any(re.search(regex, spell) for regex in args.functions):
|
||||
last_line = output_lines[-1].strip()
|
||||
while last_line == '//':
|
||||
# Remove the comment line since we will generate a new comment
|
||||
# line as part of common.add_ir_checks()
|
||||
output_lines.pop()
|
||||
last_line = output_lines[-1].strip()
|
||||
if added:
|
||||
output_lines.append('//')
|
||||
added.add(mangled)
|
||||
common.add_ir_checks(output_lines, '//', run_list, func_dict, mangled,
|
||||
False, args.function_signature)
|
||||
output_lines.append(line.rstrip('\n'))
|
||||
if line.rstrip('\n') == '//':
|
||||
include_line = False
|
||||
|
||||
if include_line:
|
||||
output_lines.append(line.rstrip('\n'))
|
||||
|
||||
common.debug('Writing %d lines to %s...' % (len(output_lines), filename))
|
||||
with open(filename, 'wb') as f:
|
||||
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])
|
||||
|
||||
return 0
|
||||
|
@ -10,19 +10,13 @@ a single test function.
|
||||
from __future__ import print_function
|
||||
|
||||
import argparse
|
||||
import glob
|
||||
import os # Used to advertise this file's name ("autogenerated_note").
|
||||
import string
|
||||
import subprocess
|
||||
import sys
|
||||
import re
|
||||
import os # Used to advertise this file's name ("autogenerated_note").
|
||||
|
||||
from UpdateTestChecks import asm, common
|
||||
|
||||
ADVERT = ' NOTE: Assertions have been autogenerated by '
|
||||
# llc is the only llc-like in the LLVM tree but downstream forks can add
|
||||
# additional ones here if they have them.
|
||||
LLC_LIKE_TOOLS = ('llc',)
|
||||
LLC_LIKE_TOOLS = ('llc',)
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
@ -42,35 +36,21 @@ def main():
|
||||
'--no_x86_scrub_mem_shuffle', action='store_true', default=False,
|
||||
help='Reduce scrubbing shuffles with memory operands')
|
||||
parser.add_argument('tests', nargs='+')
|
||||
args = common.parse_commandline_args(parser)
|
||||
initial_args = common.parse_commandline_args(parser)
|
||||
|
||||
script_name = os.path.basename(__file__)
|
||||
|
||||
test_paths = [test for pattern in args.tests for test in glob.glob(pattern)]
|
||||
for test in test_paths:
|
||||
with open(test) as f:
|
||||
input_lines = [l.rstrip() for l in f]
|
||||
|
||||
first_line = input_lines[0] if input_lines else ""
|
||||
if 'autogenerated' in first_line and script_name not in first_line:
|
||||
common.warn("Skipping test which wasn't autogenerated by " + script_name, test)
|
||||
continue
|
||||
|
||||
if args.update_only:
|
||||
if not first_line or 'autogenerated' not in first_line:
|
||||
common.warn("Skipping test which isn't autogenerated: " + test)
|
||||
continue
|
||||
|
||||
for ti in common.itertests(initial_args.tests, parser,
|
||||
script_name='utils/' + script_name):
|
||||
triple_in_ir = None
|
||||
for l in input_lines:
|
||||
for l in ti.input_lines:
|
||||
m = common.TRIPLE_IR_RE.match(l)
|
||||
if m:
|
||||
triple_in_ir = m.groups()[0]
|
||||
break
|
||||
|
||||
run_lines = common.find_run_lines(test, input_lines)
|
||||
run_list = []
|
||||
for l in run_lines:
|
||||
for l in ti.run_lines:
|
||||
if '|' not in l:
|
||||
common.warn('Skipping unparseable RUN line: ' + l)
|
||||
continue
|
||||
@ -103,7 +83,7 @@ def main():
|
||||
|
||||
llc_cmd_args = llc_cmd[len(llc_tool):].strip()
|
||||
llc_cmd_args = llc_cmd_args.replace('< %s', '').replace('%s', '').strip()
|
||||
if test.endswith('.mir'):
|
||||
if ti.path.endswith('.mir'):
|
||||
llc_cmd_args += ' -x mir'
|
||||
check_prefixes = [item for m in common.CHECK_PREFIX_RE.finditer(filecheck_cmd)
|
||||
for item in m.group(1).split(',')]
|
||||
@ -114,13 +94,10 @@ def main():
|
||||
# now, we just ignore all but the last.
|
||||
run_list.append((check_prefixes, llc_cmd_args, triple_in_cmd, march_in_cmd))
|
||||
|
||||
if test.endswith('.mir'):
|
||||
comment_sym = '#'
|
||||
if ti.path.endswith('.mir'):
|
||||
check_indent = ' '
|
||||
else:
|
||||
comment_sym = ';'
|
||||
check_indent = ''
|
||||
autogenerated_note = (comment_sym + ADVERT + 'utils/' + script_name)
|
||||
|
||||
func_dict = {}
|
||||
for p in run_list:
|
||||
@ -131,13 +108,12 @@ def main():
|
||||
common.debug('Extracted LLC cmd:', llc_tool, llc_args)
|
||||
common.debug('Extracted FileCheck prefixes:', str(prefixes))
|
||||
|
||||
raw_tool_output = common.invoke_tool(args.llc_binary or llc_tool,
|
||||
llc_args, test)
|
||||
raw_tool_output = common.invoke_tool(ti.args.llc_binary or llc_tool, llc_args, ti.path)
|
||||
triple = triple_in_cmd or triple_in_ir
|
||||
if not triple:
|
||||
triple = asm.get_triple_from_march(march_in_cmd)
|
||||
|
||||
asm.build_function_body_dictionary_for_triple(args, raw_tool_output,
|
||||
asm.build_function_body_dictionary_for_triple(ti.args, raw_tool_output,
|
||||
triple, prefixes, func_dict)
|
||||
|
||||
is_in_function = False
|
||||
@ -146,9 +122,9 @@ def main():
|
||||
prefix_set = set([prefix for p in run_list for prefix in p[0]])
|
||||
common.debug('Rewriting FileCheck prefixes:', str(prefix_set))
|
||||
output_lines = []
|
||||
output_lines.append(autogenerated_note)
|
||||
|
||||
for input_line in input_lines:
|
||||
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
|
||||
@ -172,10 +148,6 @@ def main():
|
||||
is_in_function = False
|
||||
continue
|
||||
|
||||
# Discard any previous script advertising.
|
||||
if input_line.startswith(comment_sym + ADVERT):
|
||||
continue
|
||||
|
||||
# If it's outside a function, it just gets copied to the output.
|
||||
output_lines.append(input_line)
|
||||
|
||||
@ -188,9 +160,9 @@ def main():
|
||||
continue
|
||||
is_in_function = is_in_function_start = True
|
||||
|
||||
common.debug('Writing %d lines to %s...' % (len(output_lines), test))
|
||||
common.debug('Writing %d lines to %s...' % (len(output_lines), ti.path))
|
||||
|
||||
with open(test, 'wb') as f:
|
||||
with open(ti.path, 'wb') as f:
|
||||
f.writelines(['{}\n'.format(l).encode('utf-8') for l in output_lines])
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user