-// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --function-signature
// Example input for update_cc_test_checks
// RUN: %clang_cc1 -triple=x86_64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s
--- /dev/null
+// RUN: %clang_cc1 -triple=x86_64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s
+
+int checks_please() {
+ return 1;
+}
+
+// UTC_ARGS: --disable
+
+int no_checks_please() {
+ // Manual CHECK line should be retained:
+ // CHECK: manual check line
+ return -1;
+}
+
+// UTC_ARGS: --enable
+
+
+int checks_again() {
+ return 2;
+}
--- /dev/null
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
+// RUN: %clang_cc1 -triple=x86_64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s
+
+// CHECK-LABEL: @checks_please(
+// CHECK-NEXT: entry:
+// CHECK-NEXT: ret i32 1
+//
+int checks_please() {
+ return 1;
+}
+
+// UTC_ARGS: --disable
+
+int no_checks_please() {
+ // Manual CHECK line should be retained:
+ // CHECK: manual check line
+ return -1;
+}
+
+// UTC_ARGS: --enable
+
+
+// CHECK-LABEL: @checks_again(
+// CHECK-NEXT: entry:
+// CHECK-NEXT: ret i32 2
+//
+int checks_again() {
+ return 2;
+}
## Also try the --function-signature flag
# RUN: %update_cc_test_checks %t.c --function-signature
# RUN: diff -u %t.c %S/Inputs/mangled_names.c.funcsig.expected
-## Verify that running without the --function-signature flag removes the -SAME: lines:
+## Running it again should implicitly add the function-signature flag due to UTC_ARGS:
# RUN: %update_cc_test_checks %t.c
-# RUN: diff -u %t.c %S/Inputs/mangled_names.c.expected
+# RUN: diff -u %t.c %S/Inputs/mangled_names.c.funcsig.expected
+## Verify that running without the --function-signature flag removes the -SAME: lines:
+## We have to remove the UTC_ARGS comment first:
+# RUN: grep -v UTC_ARGS %t.c > %t-no-args.c
+# RUN: %update_cc_test_checks %t-no-args.c
+# RUN: diff -u %t-no-args.c %S/Inputs/mangled_names.c.expected
--- /dev/null
+# RUN: cp -f %S/Inputs/on_the_fly_arg_change.c %t.c
+# RUN: %update_cc_test_checks %t.c
+# RUN: diff -u %t.c %S/Inputs/on_the_fly_arg_change.c.expected
+## Check that running the script again does not change the result:
+# RUN: %update_cc_test_checks %t.c
+# RUN: diff -u %t.c %S/Inputs/on_the_fly_arg_change.c.expected
-; 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
--- /dev/null
+; 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
+}
--- /dev/null
+; 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
+}
## 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
--- /dev/null
+# 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
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': [],
return ret
+def str_to_commandline(value):
+ if not value:
+ return []
+ return shlex.split(value)
+
def config():
parser = argparse.ArgumentParser(
description=__doc__,
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')
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:
# 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):
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
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
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:
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]:
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
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__)
'--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
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(',')]
# 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:
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
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
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)
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])