arichardson created this revision.
arichardson added reviewers: jdoerfert, MaskRay.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

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.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D78478

Files:
  clang/test/utils/update_cc_test_checks/Inputs/mangled_names.c.funcsig.expected
  clang/test/utils/update_cc_test_checks/Inputs/on_the_fly_arg_change.c
  clang/test/utils/update_cc_test_checks/Inputs/on_the_fly_arg_change.c.expected
  clang/test/utils/update_cc_test_checks/mangled_names.test
  clang/test/utils/update_cc_test_checks/on_the_fly_arg_change.test
  
llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/basic.ll.expected
  
llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/on_the_fly_arg_change.ll
  
llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/on_the_fly_arg_change.ll.expected
  llvm/test/tools/UpdateTestChecks/update_llc_test_checks/basic.test
  
llvm/test/tools/UpdateTestChecks/update_llc_test_checks/on_the_fly_arg_change.test
  llvm/utils/UpdateTestChecks/common.py
  llvm/utils/update_cc_test_checks.py
  llvm/utils/update_llc_test_checks.py
  llvm/utils/update_test_checks.py

Index: llvm/utils/update_test_checks.py
===================================================================
--- llvm/utils/update_test_checks.py
+++ llvm/utils/update_test_checks.py
@@ -32,18 +32,12 @@
 from __future__ import print_function
 
 import argparse
-import glob
-import itertools
-import os         # Used to advertise this file's name ("autogenerated_note").
-import string
-import subprocess
-import sys
-import tempfile
+import os  # Used to advertise this file's name ("autogenerated_note").
 import re
+import sys
 
 from UpdateTestChecks import common
 
-ADVERT = '; NOTE: Assertions have been autogenerated by '
 
 def main():
   from argparse import RawTextHelpFormatter
@@ -58,58 +52,26 @@
                       help='Keep function signature information around for the check line')
   parser.add_argument('--scrub-attributes', action='store_true',
                       help='Remove attribute annotations (#0) from the end of check line')
-  parser.add_argument('--enable', action='store_true', dest='enabled', default=True,
-                      help='Activate CHECK line generation from this point forward')
-  parser.add_argument('--disable', action='store_false', dest='enabled',
-                      help='Deactivate CHECK line generation from this point forward')
   parser.add_argument('tests', nargs='+')
-  args = common.parse_commandline_args(parser)
+  initial_args = common.parse_commandline_args(parser)
 
   script_name = os.path.basename(__file__)
-  autogenerated_note = (ADVERT + 'utils/' + script_name)
-
-  opt_basename = os.path.basename(args.opt_binary)
+  opt_basename = os.path.basename(initial_args.opt_binary)
   if not re.match(r'^opt(-\d+)?$', opt_basename):
     common.error('Unexpected opt name: ' + opt_basename)
     sys.exit(1)
   opt_basename = 'opt'
 
-  for test in args.tests:
-    if not glob.glob(test):
-      common.warn("Test file pattern '%s' was not found. Ignoring it." % (test,))
-      continue
-
-  # On Windows we must expand the patterns ourselves.
-  test_paths = [test for pattern in args.tests for test in glob.glob(pattern)]
-  for test in test_paths:
-    argv = sys.argv[:]
-    args = parser.parse_args()
-    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 first_line and 'autogenerated' in first_line:
-      args, argv = common.check_for_command(first_line, parser, args, argv)
-    test_autogenerated_note = autogenerated_note + common.get_autogennote_suffix(parser, args)
-
-    if args.update_only:
-      if not first_line or 'autogenerated' not in first_line:
-        common.warn("Skipping test which isn't autogenerated: " + test)
-        continue
-
-    run_lines = common.find_run_lines(test, input_lines)
-
+  for ti in common.itertests(initial_args.tests, parser,
+                             script_name='utils/' + script_name):
     # If requested we scrub trailing attribute annotations, e.g., '#0', together with whitespaces
-    if args.scrub_attributes:
+    if ti.args.scrub_attributes:
       common.SCRUB_TRAILING_WHITESPACE_TEST_RE = common.SCRUB_TRAILING_WHITESPACE_AND_ATTRIBUTES_RE
     else:
       common.SCRUB_TRAILING_WHITESPACE_TEST_RE = common.SCRUB_TRAILING_WHITESPACE_RE
 
     prefix_list = []
-    for l in run_lines:
+    for l in ti.run_lines:
       if '|' not in l:
         common.warn('Skipping unparseable RUN line: ' + l)
         continue
@@ -127,8 +89,9 @@
       tool_cmd_args = tool_cmd[len(opt_basename):].strip()
       tool_cmd_args = tool_cmd_args.replace('< %s', '').replace('%s', '').strip()
 
-      check_prefixes = [item for m in common.CHECK_PREFIX_RE.finditer(filecheck_cmd)
-                               for item in m.group(1).split(',')]
+      check_prefixes = [item for m in
+                        common.CHECK_PREFIX_RE.finditer(filecheck_cmd)
+                        for item in m.group(1).split(',')]
       if not check_prefixes:
         check_prefixes = ['CHECK']
 
@@ -144,28 +107,21 @@
       common.debug('Extracted opt cmd: ' + opt_basename + ' ' + opt_args)
       common.debug('Extracted FileCheck prefixes: ' + str(prefixes))
 
-      raw_tool_output = common.invoke_tool(args.opt_binary, opt_args, test)
+      raw_tool_output = common.invoke_tool(ti.args.opt_binary, opt_args, ti.path)
       common.build_function_body_dictionary(
               common.OPT_FUNCTION_RE, common.scrub_body, [],
-              raw_tool_output, prefixes, func_dict, args.verbose,
-              args.function_signature)
+              raw_tool_output, prefixes, func_dict, ti.args.verbose,
+              ti.args.function_signature)
 
     is_in_function = False
     is_in_function_start = False
+    func_name = 'error-this-should-not-be-dereferenced-yet'
     prefix_set = set([prefix for prefixes, _ in prefix_list for prefix in prefixes])
     common.debug('Rewriting FileCheck prefixes:', str(prefix_set))
     output_lines = []
-    output_lines.append(test_autogenerated_note)
-
-    for input_line in input_lines:
-      # Discard any previous script advertising.
-      if input_line.startswith(ADVERT):
-        continue
-
-      args, argv = common.check_for_command(input_line, parser, args, argv)
-      if not args.enabled:
-          output_lines.append(input_line)
-          continue
+    for input_line_info in ti.iterlines(output_lines):
+      input_line = input_line_info.line
+      args = input_line_info.args
       if is_in_function_start:
         if input_line == '':
           continue
@@ -204,9 +160,9 @@
         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])
 
 
Index: llvm/utils/update_llc_test_checks.py
===================================================================
--- llvm/utils/update_llc_test_checks.py
+++ llvm/utils/update_llc_test_checks.py
@@ -10,17 +10,10 @@
 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 '
-
 
 def main():
   parser = argparse.ArgumentParser(description=__doc__)
@@ -40,35 +33,21 @@
       '--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
@@ -101,7 +80,7 @@
 
       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(',')]
@@ -112,13 +91,10 @@
       # 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:
@@ -129,12 +105,12 @@
       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, llc_args, test)
+      raw_tool_output = common.invoke_tool(ti.args.llc_binary, 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
@@ -143,9 +119,9 @@
     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
@@ -169,10 +145,6 @@
           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)
 
@@ -185,9 +157,9 @@
         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])
 
 
Index: llvm/utils/update_cc_test_checks.py
===================================================================
--- llvm/utils/update_cc_test_checks.py
+++ llvm/utils/update_cc_test_checks.py
@@ -19,16 +19,13 @@
 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': [],
@@ -97,6 +94,11 @@
   return ret
 
 
+def str_to_commandline(value):
+  if not value:
+    return []
+  return shlex.split(value)
+
 def config():
   parser = argparse.ArgumentParser(
       description=__doc__,
@@ -104,7 +106,7 @@
   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')
@@ -118,7 +120,6 @@
                       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:
@@ -152,7 +153,7 @@
     # 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):
@@ -183,31 +184,15 @@
 
 
 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
@@ -221,7 +206,7 @@
         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
@@ -240,18 +225,6 @@
         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:
@@ -262,18 +235,23 @@
       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]:
@@ -285,16 +263,25 @@
           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
Index: llvm/utils/UpdateTestChecks/common.py
===================================================================
--- llvm/utils/UpdateTestChecks/common.py
+++ llvm/utils/UpdateTestChecks/common.py
@@ -1,9 +1,10 @@
 from __future__ import print_function
+
+import copy
+import glob
 import re
-import string
 import subprocess
 import sys
-import copy
 
 if sys.version_info[0] > 2:
   class string:
@@ -21,11 +22,85 @@
                       help='Show verbose output')
   parser.add_argument('-u', '--update-only', action='store_true',
                       help='Only update test if it was already autogened')
+  parser.add_argument('--force-update', action='store_true',
+                      help='Update test even if it was autogened by a different script')
+  parser.add_argument('--enable', action='store_true', dest='enabled', default=True,
+                       help='Activate CHECK line generation from this point forward')
+  parser.add_argument('--disable', action='store_false', dest='enabled',
+                      help='Deactivate CHECK line generation from this point forward')
   args = parser.parse_args()
   global _verbose
   _verbose = args.verbose
   return args
 
+
+class InputLineInfo(object):
+  def __init__(self, line, line_number, args, argv):
+    self.line = line
+    self.line_number = line_number
+    self.args = args
+    self.argv = argv
+
+
+class TestInfo(object):
+  def __init__(self, test, parser, script_name, input_lines, args, argv,
+               comment_prefix):
+    self.parser = parser
+    self.path = test
+    self.args = args
+    self.argv = argv
+    self.input_lines = input_lines
+    self.run_lines = find_run_lines(test, self.input_lines)
+    self.comment_prefix = comment_prefix
+    if self.comment_prefix is None:
+      if self.path.endswith('.mir'):
+        self.comment_prefix = '#'
+      else:
+        self.comment_prefix = ';'
+    self.autogenerated_note_prefix = self.comment_prefix + ' ' + UTC_ADVERT
+    self.test_autogenerated_note = self.autogenerated_note_prefix + script_name
+    self.test_autogenerated_note += get_autogennote_suffix(parser, self.args)
+
+  def iterlines(self, output_lines):
+    output_lines.append(self.test_autogenerated_note)
+    for line_num, input_line in enumerate(self.input_lines):
+      # Discard any previous script advertising.
+      if input_line.startswith(self.autogenerated_note_prefix):
+        continue
+      self.args, self.argv = check_for_command(input_line, self.parser,
+                                               self.args, self.argv)
+      if not self.args.enabled:
+        output_lines.append(input_line)
+        continue
+      yield InputLineInfo(input_line, line_num, self.args, self.argv)
+
+
+def itertests(test_patterns, parser, script_name, comment_prefix=None):
+  for pattern in test_patterns:
+    # On Windows we must expand the patterns ourselves.
+    tests_list = glob.glob(pattern)
+    if not tests_list:
+      warn("Test file pattern '%s' was not found. Ignoring it." % (pattern,))
+      continue
+    for test in tests_list:
+      with open(test) as f:
+        input_lines = [l.rstrip() for l in f]
+      args = parser.parse_args()
+      argv = sys.argv[:]
+      first_line = input_lines[0] if input_lines else ""
+      if 'autogenerated' in first_line:
+        if script_name not in first_line and not args.force_update:
+          warn("Skipping test which wasn't autogenerated by " + script_name, test)
+          continue
+        args, argv = check_for_command(first_line, parser, args, argv)
+      elif args.update_only:
+        assert 'autogenerated' not in first_line
+        warn("Skipping test which isn't autogenerated: " + test)
+        continue
+      yield TestInfo(test, parser, script_name, input_lines, args, argv,
+                     comment_prefix)
+
+
 def should_add_line_to_output(input_line, prefix_set):
   # Skip any blank comment lines in the IR.
   if input_line.strip() == ';':
@@ -57,7 +132,6 @@
   return stdout.replace('\r\n', '\n')
 
 ##### LLVM IR parser
-
 RUN_LINE_RE = re.compile(r'^\s*(?://|[;#])\s*RUN:\s*(.*)$')
 CHECK_PREFIX_RE = re.compile(r'--?check-prefix(?:es)?[= ](\S+)')
 PREFIX_RE = re.compile('^[a-zA-Z0-9_-]+$')
@@ -65,6 +139,7 @@
 
 UTC_ARGS_KEY = 'UTC_ARGS:'
 UTC_ARGS_CMD = re.compile(r'.*' + UTC_ARGS_KEY + '\s*(?P<cmd>.*)\s*$')
+UTC_ADVERT = 'NOTE: Assertions have been autogenerated by '
 
 OPT_FUNCTION_RE = re.compile(
     r'^\s*define\s+(?:internal\s+)?[^@]*@(?P<func>[\w.-]+?)\s*'
@@ -396,19 +471,31 @@
         if prefixes.count(prefix) > 1:
           warn("Supplied prefix '%s' is not unique in the prefix list." % (prefix,))
 
+
 def get_autogennote_suffix(parser, args):
-    autogenerated_note_args = ''
-    for k, v in args._get_kwargs():
-        if parser.get_default(k) == v or k == 'tests' or k == 'update_only' or k == 'opt_binary':
-            continue
-        k = k.replace('_', '-')
-        if type(v) is bool:
-            autogenerated_note_args += '--%s ' % (k)
-        else:
-            autogenerated_note_args += '--%s %s ' % (k, v)
-    if autogenerated_note_args:
-        autogenerated_note_args = ' %s %s' % (UTC_ARGS_KEY, autogenerated_note_args[:-1])
-    return autogenerated_note_args
+  import argparse
+  autogenerated_note_args = ''
+  for action in parser._actions:
+    if not hasattr(args, action.dest):
+      continue  # Ignore options such as --help that aren't included in args
+    # Ignore parameters such as paths to the binary or the list of tests
+    if action.dest in ('tests', 'update_only', 'opt_binary', 'llc_binary',
+                       'clang', 'opt', 'llvm_bin', 'verbose'):
+      continue
+    value = getattr(args, action.dest)
+    if action.const is not None:  # action stores a constant (usually True/False)
+      # Skip actions with different constant values (this happens with boolean
+      # --foo/--no-foo options)
+      if value != action.const:
+        continue
+    if parser.get_default(action.dest) == value:
+      continue  # Don't add default values
+    autogenerated_note_args += action.option_strings[0] + ' '
+    if action.const is None:  # action takes a parameter
+      autogenerated_note_args += '%s ' % value
+  if autogenerated_note_args:
+    autogenerated_note_args = ' %s %s' % (UTC_ARGS_KEY, autogenerated_note_args[:-1])
+  return autogenerated_note_args
 
 
 def check_for_command(line, parser, args, argv):
Index: llvm/test/tools/UpdateTestChecks/update_llc_test_checks/on_the_fly_arg_change.test
===================================================================
--- /dev/null
+++ llvm/test/tools/UpdateTestChecks/update_llc_test_checks/on_the_fly_arg_change.test
@@ -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
Index: llvm/test/tools/UpdateTestChecks/update_llc_test_checks/basic.test
===================================================================
--- llvm/test/tools/UpdateTestChecks/update_llc_test_checks/basic.test
+++ llvm/test/tools/UpdateTestChecks/update_llc_test_checks/basic.test
@@ -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
Index: llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/on_the_fly_arg_change.ll.expected
===================================================================
--- /dev/null
+++ llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/on_the_fly_arg_change.ll.expected
@@ -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
+}
Index: llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/on_the_fly_arg_change.ll
===================================================================
--- /dev/null
+++ llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/on_the_fly_arg_change.ll
@@ -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
+}
Index: llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/basic.ll.expected
===================================================================
--- llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/basic.ll.expected
+++ llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/basic.ll.expected
@@ -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
Index: clang/test/utils/update_cc_test_checks/on_the_fly_arg_change.test
===================================================================
--- /dev/null
+++ clang/test/utils/update_cc_test_checks/on_the_fly_arg_change.test
@@ -0,0 +1,6 @@
+# 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
Index: clang/test/utils/update_cc_test_checks/mangled_names.test
===================================================================
--- clang/test/utils/update_cc_test_checks/mangled_names.test
+++ clang/test/utils/update_cc_test_checks/mangled_names.test
@@ -8,6 +8,11 @@
 ## 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
Index: clang/test/utils/update_cc_test_checks/Inputs/on_the_fly_arg_change.c.expected
===================================================================
--- /dev/null
+++ clang/test/utils/update_cc_test_checks/Inputs/on_the_fly_arg_change.c.expected
@@ -0,0 +1,29 @@
+// 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;
+}
Index: clang/test/utils/update_cc_test_checks/Inputs/on_the_fly_arg_change.c
===================================================================
--- /dev/null
+++ clang/test/utils/update_cc_test_checks/Inputs/on_the_fly_arg_change.c
@@ -0,0 +1,20 @@
+// 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;
+}
Index: clang/test/utils/update_cc_test_checks/Inputs/mangled_names.c.funcsig.expected
===================================================================
--- clang/test/utils/update_cc_test_checks/Inputs/mangled_names.c.funcsig.expected
+++ clang/test/utils/update_cc_test_checks/Inputs/mangled_names.c.funcsig.expected
@@ -1,4 +1,4 @@
-// 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
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D78478: [Upda... Alexander Richardson via Phabricator via cfe-commits

Reply via email to