xref: /llvm-project/llvm/utils/UpdateTestChecks/common.py (revision dbde3969ba8e2b396333dc6b139a0b3a88dfbc80)
1from __future__ import print_function
2
3import copy
4import glob
5import re
6import subprocess
7import sys
8
9if sys.version_info[0] > 2:
10  class string:
11    expandtabs = str.expandtabs
12else:
13  import string
14
15##### Common utilities for update_*test_checks.py
16
17
18_verbose = False
19
20def parse_commandline_args(parser):
21  parser.add_argument('-v', '--verbose', action='store_true',
22                      help='Show verbose output')
23  parser.add_argument('-u', '--update-only', action='store_true',
24                      help='Only update test if it was already autogened')
25  parser.add_argument('--force-update', action='store_true',
26                      help='Update test even if it was autogened by a different script')
27  parser.add_argument('--enable', action='store_true', dest='enabled', default=True,
28                       help='Activate CHECK line generation from this point forward')
29  parser.add_argument('--disable', action='store_false', dest='enabled',
30                      help='Deactivate CHECK line generation from this point forward')
31  args = parser.parse_args()
32  global _verbose
33  _verbose = args.verbose
34  return args
35
36
37class InputLineInfo(object):
38  def __init__(self, line, line_number, args, argv):
39    self.line = line
40    self.line_number = line_number
41    self.args = args
42    self.argv = argv
43
44
45class TestInfo(object):
46  def __init__(self, test, parser, script_name, input_lines, args, argv,
47               comment_prefix, argparse_callback):
48    self.parser = parser
49    self.argparse_callback = argparse_callback
50    self.path = test
51    self.args = args
52    self.argv = argv
53    self.input_lines = input_lines
54    self.run_lines = find_run_lines(test, self.input_lines)
55    self.comment_prefix = comment_prefix
56    if self.comment_prefix is None:
57      if self.path.endswith('.mir'):
58        self.comment_prefix = '#'
59      else:
60        self.comment_prefix = ';'
61    self.autogenerated_note_prefix = self.comment_prefix + ' ' + UTC_ADVERT
62    self.test_autogenerated_note = self.autogenerated_note_prefix + script_name
63    self.test_autogenerated_note += get_autogennote_suffix(parser, self.args)
64
65  def iterlines(self, output_lines):
66    output_lines.append(self.test_autogenerated_note)
67    for line_num, input_line in enumerate(self.input_lines):
68      # Discard any previous script advertising.
69      if input_line.startswith(self.autogenerated_note_prefix):
70        continue
71      self.args, self.argv = check_for_command(input_line, self.parser,
72                                               self.args, self.argv, self.argparse_callback)
73      if not self.args.enabled:
74        output_lines.append(input_line)
75        continue
76      yield InputLineInfo(input_line, line_num, self.args, self.argv)
77
78
79def itertests(test_patterns, parser, script_name, comment_prefix=None, argparse_callback=None):
80  for pattern in test_patterns:
81    # On Windows we must expand the patterns ourselves.
82    tests_list = glob.glob(pattern)
83    if not tests_list:
84      warn("Test file pattern '%s' was not found. Ignoring it." % (pattern,))
85      continue
86    for test in tests_list:
87      with open(test) as f:
88        input_lines = [l.rstrip() for l in f]
89      args = parser.parse_args()
90      if argparse_callback is not None:
91        argparse_callback(args)
92      argv = sys.argv[:]
93      first_line = input_lines[0] if input_lines else ""
94      if UTC_ADVERT in first_line:
95        if script_name not in first_line and not args.force_update:
96          warn("Skipping test which wasn't autogenerated by " + script_name, test)
97          continue
98        args, argv = check_for_command(first_line, parser, args, argv, argparse_callback)
99      elif args.update_only:
100        assert UTC_ADVERT not in first_line
101        warn("Skipping test which isn't autogenerated: " + test)
102        continue
103      yield TestInfo(test, parser, script_name, input_lines, args, argv,
104                     comment_prefix, argparse_callback)
105
106
107def should_add_line_to_output(input_line, prefix_set):
108  # Skip any blank comment lines in the IR.
109  if input_line.strip() == ';':
110    return False
111  # Skip any blank lines in the IR.
112  #if input_line.strip() == '':
113  #  return False
114  # And skip any CHECK lines. We're building our own.
115  m = CHECK_RE.match(input_line)
116  if m and m.group(1) in prefix_set:
117    return False
118
119  return True
120
121# Invoke the tool that is being tested.
122def invoke_tool(exe, cmd_args, ir):
123  with open(ir) as ir_file:
124    # TODO Remove the str form which is used by update_test_checks.py and
125    # update_llc_test_checks.py
126    # The safer list form is used by update_cc_test_checks.py
127    if isinstance(cmd_args, list):
128      stdout = subprocess.check_output([exe] + cmd_args, stdin=ir_file)
129    else:
130      stdout = subprocess.check_output(exe + ' ' + cmd_args,
131                                       shell=True, stdin=ir_file)
132    if sys.version_info[0] > 2:
133      stdout = stdout.decode()
134  # Fix line endings to unix CR style.
135  return stdout.replace('\r\n', '\n')
136
137##### LLVM IR parser
138RUN_LINE_RE = re.compile(r'^\s*(?://|[;#])\s*RUN:\s*(.*)$')
139CHECK_PREFIX_RE = re.compile(r'--?check-prefix(?:es)?[= ](\S+)')
140PREFIX_RE = re.compile('^[a-zA-Z0-9_-]+$')
141CHECK_RE = re.compile(r'^\s*(?://|[;#])\s*([^:]+?)(?:-NEXT|-NOT|-DAG|-LABEL|-SAME|-EMPTY)?:')
142
143UTC_ARGS_KEY = 'UTC_ARGS:'
144UTC_ARGS_CMD = re.compile(r'.*' + UTC_ARGS_KEY + '\s*(?P<cmd>.*)\s*$')
145UTC_ADVERT = 'NOTE: Assertions have been autogenerated by '
146
147OPT_FUNCTION_RE = re.compile(
148    r'^(\s*;\s*Function\sAttrs:\s(?P<attrs>[\w\s]+?))?\s*define\s+(?:internal\s+)?[^@]*@(?P<func>[\w.-]+?)\s*'
149    r'(?P<args_and_sig>\((\)|(.*?[\w.-]+?)\))[^{]*\{)\n(?P<body>.*?)^\}$',
150    flags=(re.M | re.S))
151
152ANALYZE_FUNCTION_RE = re.compile(
153    r'^\s*\'(?P<analysis>[\w\s-]+?)\'\s+for\s+function\s+\'(?P<func>[\w.-]+?)\':'
154    r'\s*\n(?P<body>.*)$',
155    flags=(re.X | re.S))
156
157IR_FUNCTION_RE = re.compile(r'^\s*define\s+(?:internal\s+)?[^@]*@([\w.-]+)\s*\(')
158TRIPLE_IR_RE = re.compile(r'^\s*target\s+triple\s*=\s*"([^"]+)"$')
159TRIPLE_ARG_RE = re.compile(r'-mtriple[= ]([^ ]+)')
160MARCH_ARG_RE = re.compile(r'-march[= ]([^ ]+)')
161
162SCRUB_LEADING_WHITESPACE_RE = re.compile(r'^(\s+)')
163SCRUB_WHITESPACE_RE = re.compile(r'(?!^(|  \w))[ \t]+', flags=re.M)
164SCRUB_TRAILING_WHITESPACE_RE = re.compile(r'[ \t]+$', flags=re.M)
165SCRUB_TRAILING_WHITESPACE_TEST_RE = SCRUB_TRAILING_WHITESPACE_RE
166SCRUB_TRAILING_WHITESPACE_AND_ATTRIBUTES_RE = re.compile(r'([ \t]|(#[0-9]+))+$', flags=re.M)
167SCRUB_KILL_COMMENT_RE = re.compile(r'^ *#+ +kill:.*\n')
168SCRUB_LOOP_COMMENT_RE = re.compile(
169    r'# =>This Inner Loop Header:.*|# in Loop:.*', flags=re.M)
170SCRUB_TAILING_COMMENT_TOKEN_RE = re.compile(r'(?<=\S)+[ \t]*#$', flags=re.M)
171
172
173def error(msg, test_file=None):
174  if test_file:
175    msg = '{}: {}'.format(msg, test_file)
176  print('ERROR: {}'.format(msg), file=sys.stderr)
177
178def warn(msg, test_file=None):
179  if test_file:
180    msg = '{}: {}'.format(msg, test_file)
181  print('WARNING: {}'.format(msg), file=sys.stderr)
182
183def debug(*args, **kwargs):
184  # Python2 does not allow def debug(*args, file=sys.stderr, **kwargs):
185  if 'file' not in kwargs:
186    kwargs['file'] = sys.stderr
187  if _verbose:
188    print(*args, **kwargs)
189
190def find_run_lines(test, lines):
191  debug('Scanning for RUN lines in test file:', test)
192  raw_lines = [m.group(1)
193               for m in [RUN_LINE_RE.match(l) for l in lines] if m]
194  run_lines = [raw_lines[0]] if len(raw_lines) > 0 else []
195  for l in raw_lines[1:]:
196    if run_lines[-1].endswith('\\'):
197      run_lines[-1] = run_lines[-1].rstrip('\\') + ' ' + l
198    else:
199      run_lines.append(l)
200  debug('Found {} RUN lines in {}:'.format(len(run_lines), test))
201  for l in run_lines:
202    debug('  RUN: {}'.format(l))
203  return run_lines
204
205def scrub_body(body):
206  # Scrub runs of whitespace out of the assembly, but leave the leading
207  # whitespace in place.
208  body = SCRUB_WHITESPACE_RE.sub(r' ', body)
209  # Expand the tabs used for indentation.
210  body = string.expandtabs(body, 2)
211  # Strip trailing whitespace.
212  body = SCRUB_TRAILING_WHITESPACE_TEST_RE.sub(r'', body)
213  return body
214
215def do_scrub(body, scrubber, scrubber_args, extra):
216  if scrubber_args:
217    local_args = copy.deepcopy(scrubber_args)
218    local_args[0].extra_scrub = extra
219    return scrubber(body, *local_args)
220  return scrubber(body, *scrubber_args)
221
222# Build up a dictionary of all the function bodies.
223class function_body(object):
224  def __init__(self, string, extra, args_and_sig, attrs):
225    self.scrub = string
226    self.extrascrub = extra
227    self.args_and_sig = args_and_sig
228    self.attrs = attrs
229  def is_same_except_arg_names(self, extrascrub, args_and_sig, attrs):
230    arg_names = set()
231    def drop_arg_names(match):
232        arg_names.add(match.group(3))
233        return match.group(1) + match.group(match.lastindex)
234    def repl_arg_names(match):
235        if match.group(3) is not None and match.group(3) in arg_names:
236            return match.group(1) + match.group(match.lastindex)
237        return match.group(1) + match.group(2) + match.group(match.lastindex)
238    if self.attrs != attrs:
239      return False
240    ans0 = IR_VALUE_RE.sub(drop_arg_names, self.args_and_sig)
241    ans1 = IR_VALUE_RE.sub(drop_arg_names, args_and_sig)
242    if ans0 != ans1:
243        return False
244    es0 = IR_VALUE_RE.sub(repl_arg_names, self.extrascrub)
245    es1 = IR_VALUE_RE.sub(repl_arg_names, extrascrub)
246    es0 = SCRUB_IR_COMMENT_RE.sub(r'', es0)
247    es1 = SCRUB_IR_COMMENT_RE.sub(r'', es1)
248    return es0 == es1
249
250  def __str__(self):
251    return self.scrub
252
253def build_function_body_dictionary(function_re, scrubber, scrubber_args, raw_tool_output, prefixes, func_dict, verbose, record_args, check_attributes):
254  for m in function_re.finditer(raw_tool_output):
255    if not m:
256      continue
257    func = m.group('func')
258    body = m.group('body')
259    attrs = m.group('attrs') if check_attributes else ''
260    # Determine if we print arguments, the opening brace, or nothing after the function name
261    if record_args and 'args_and_sig' in m.groupdict():
262        args_and_sig = scrub_body(m.group('args_and_sig').strip())
263    elif 'args_and_sig' in m.groupdict():
264        args_and_sig = '('
265    else:
266        args_and_sig = ''
267    scrubbed_body = do_scrub(body, scrubber, scrubber_args, extra = False)
268    scrubbed_extra = do_scrub(body, scrubber, scrubber_args, extra = True)
269    if 'analysis' in m.groupdict():
270      analysis = m.group('analysis')
271      if analysis.lower() != 'cost model analysis':
272        warn('Unsupported analysis mode: %r!' % (analysis,))
273    if func.startswith('stress'):
274      # We only use the last line of the function body for stress tests.
275      scrubbed_body = '\n'.join(scrubbed_body.splitlines()[-1:])
276    if verbose:
277      print('Processing function: ' + func, file=sys.stderr)
278      for l in scrubbed_body.splitlines():
279        print('  ' + l, file=sys.stderr)
280    for prefix in prefixes:
281      if func in func_dict[prefix]:
282        if str(func_dict[prefix][func]) != scrubbed_body or (func_dict[prefix][func] and (func_dict[prefix][func].args_and_sig != args_and_sig or func_dict[prefix][func].attrs != attrs)):
283          if func_dict[prefix][func] and func_dict[prefix][func].is_same_except_arg_names(scrubbed_extra, args_and_sig, attrs):
284            func_dict[prefix][func].scrub = scrubbed_extra
285            func_dict[prefix][func].args_and_sig = args_and_sig
286            continue
287          else:
288            if prefix == prefixes[-1]:
289              warn('Found conflicting asm under the same prefix: %r!' % (prefix,))
290            else:
291              func_dict[prefix][func] = None
292              continue
293
294      func_dict[prefix][func] = function_body(scrubbed_body, scrubbed_extra, args_and_sig, attrs)
295
296##### Generator of LLVM IR CHECK lines
297
298SCRUB_IR_COMMENT_RE = re.compile(r'\s*;.*')
299
300# TODO: We should also derive check lines for global, debug, loop declarations, etc..
301
302class NamelessValue:
303    def __init__(self, check_prefix, ir_prefix, ir_regexp):
304        self.check_prefix = check_prefix
305        self.ir_prefix = ir_prefix
306        self.ir_regexp = ir_regexp
307
308# Description of the different "unnamed" values we match in the IR, e.g.,
309# (local) ssa values, (debug) metadata, etc.
310nameless_values = [
311    NamelessValue(r'TMP',   r'%',            r'[\w.-]+?'),
312    NamelessValue(r'GLOB',  r'@',            r'[0-9]+?'),
313    NamelessValue(r'ATTR',  r'#',            r'[0-9]+?'),
314    NamelessValue(r'DBG',   r'!dbg !',       r'[0-9]+?'),
315    NamelessValue(r'TBAA',  r'!tbaa !',      r'[0-9]+?'),
316    NamelessValue(r'RNG',   r'!range !',     r'[0-9]+?'),
317    NamelessValue(r'LOOP',  r'!llvm.loop !', r'[0-9]+?'),
318    NamelessValue(r'META',  r'metadata !',   r'[0-9]+?'),
319]
320
321# Build the regexp that matches an "IR value". This can be a local variable,
322# argument, global, or metadata, anything that is "named". It is important that
323# the PREFIX and SUFFIX below only contain a single group, if that changes
324# other locations will need adjustment as well.
325IR_VALUE_REGEXP_PREFIX = r'(\s+)'
326IR_VALUE_REGEXP_STRING = r''
327for nameless_value in nameless_values:
328    if IR_VALUE_REGEXP_STRING:
329        IR_VALUE_REGEXP_STRING += '|'
330    IR_VALUE_REGEXP_STRING += nameless_value.ir_prefix + r'(' + nameless_value.ir_regexp + r')'
331IR_VALUE_REGEXP_SUFFIX = r'([,\s\(\)]|\Z)'
332IR_VALUE_RE = re.compile(IR_VALUE_REGEXP_PREFIX + r'(' + IR_VALUE_REGEXP_STRING + r')' + IR_VALUE_REGEXP_SUFFIX)
333
334# The entire match is group 0, the prefix has one group (=1), the entire
335# IR_VALUE_REGEXP_STRING is one group (=2), and then the nameless values start.
336first_nameless_group_in_ir_value_match = 3
337
338# Check a match for IR_VALUE_RE and inspect it to determine if it was a local
339# value, %..., global @..., debug number !dbg !..., etc. See the PREFIXES above.
340def get_idx_from_ir_value_match(match):
341    for i in range(first_nameless_group_in_ir_value_match, match.lastindex):
342        if match.group(i) is not None:
343            return i - first_nameless_group_in_ir_value_match
344    error("Unable to identify the kind of IR value from the match!")
345    return 0;
346
347# See get_idx_from_ir_value_match
348def get_name_from_ir_value_match(match):
349    return match.group(get_idx_from_ir_value_match(match) + first_nameless_group_in_ir_value_match)
350
351# Return the nameless prefix we use for this kind or IR value, see also
352# get_idx_from_ir_value_match
353def get_nameless_check_prefix_from_ir_value_match(match):
354    return nameless_values[get_idx_from_ir_value_match(match)].check_prefix
355
356# Return the IR prefix we use for this kind or IR value, e.g., % for locals,
357# see also get_idx_from_ir_value_match
358def get_ir_prefix_from_ir_value_match(match):
359    return nameless_values[get_idx_from_ir_value_match(match)].ir_prefix
360
361# Return true if this kind or IR value is "local", basically if it matches '%{{.*}}'.
362def is_local_ir_value_match(match):
363    return nameless_values[get_idx_from_ir_value_match(match)].ir_prefix == '%'
364
365# Create a FileCheck variable name based on an IR name.
366def get_value_name(var, match):
367  if var.isdigit():
368    var = get_nameless_check_prefix_from_ir_value_match(match) + var
369  var = var.replace('.', '_')
370  var = var.replace('-', '_')
371  return var.upper()
372
373# Create a FileCheck variable from regex.
374def get_value_definition(var, match):
375  return '[[' + get_value_name(var, match) + ':' + get_ir_prefix_from_ir_value_match(match) + '.*]]'
376
377# Use a FileCheck variable.
378def get_value_use(var, match):
379  return '[[' + get_value_name(var, match) + ']]'
380
381# Replace IR value defs and uses with FileCheck variables.
382def generalize_check_lines(lines, is_analyze, vars_seen, global_vars_seen):
383  # This gets called for each match that occurs in
384  # a line. We transform variables we haven't seen
385  # into defs, and variables we have seen into uses.
386  def transform_line_vars(match):
387    pre = get_ir_prefix_from_ir_value_match(match)
388    var = get_name_from_ir_value_match(match)
389    for nameless_value in nameless_values:
390        if re.match(r'^' + nameless_value.check_prefix + r'[0-9]+?$', var, re.IGNORECASE):
391            warn("Change IR value name '%s' to prevent possible conflict with scripted FileCheck name." % (var,))
392    if (pre, var) in vars_seen or (pre, var) in global_vars_seen:
393      rv = get_value_use(var, match)
394    else:
395      if is_local_ir_value_match(match):
396         vars_seen.add((pre, var))
397      else:
398         global_vars_seen.add((pre, var))
399      rv = get_value_definition(var, match)
400    # re.sub replaces the entire regex match
401    # with whatever you return, so we have
402    # to make sure to hand it back everything
403    # including the commas and spaces.
404    return match.group(1) + rv + match.group(match.lastindex)
405
406  lines_with_def = []
407
408  for i, line in enumerate(lines):
409    # An IR variable named '%.' matches the FileCheck regex string.
410    line = line.replace('%.', '%dot')
411    # Ignore any comments, since the check lines will too.
412    scrubbed_line = SCRUB_IR_COMMENT_RE.sub(r'', line)
413    lines[i] = scrubbed_line
414    if not is_analyze:
415      # It can happen that two matches are back-to-back and for some reason sub
416      # will not replace both of them. For now we work around this by
417      # substituting until there is no more match.
418      changed = True
419      while changed:
420          (lines[i], changed) = IR_VALUE_RE.subn(transform_line_vars, lines[i], count=1)
421  return lines
422
423
424def add_checks(output_lines, comment_marker, prefix_list, func_dict, func_name, check_label_format, is_asm, is_analyze, global_vars_seen_dict):
425  # prefix_exclusions are prefixes we cannot use to print the function because it doesn't exist in run lines that use these prefixes as well.
426  prefix_exclusions = set()
427  printed_prefixes = []
428  for p in prefix_list:
429    checkprefixes = p[0]
430    # If not all checkprefixes of this run line produced the function we cannot check for it as it does not
431    # exist for this run line. A subset of the check prefixes might know about the function but only because
432    # other run lines created it.
433    if any(map(lambda checkprefix: func_name not in func_dict[checkprefix], checkprefixes)):
434        prefix_exclusions |= set(checkprefixes)
435        continue
436
437  # prefix_exclusions is constructed, we can now emit the output
438  for p in prefix_list:
439    checkprefixes = p[0]
440    for checkprefix in checkprefixes:
441      if checkprefix in printed_prefixes:
442        break
443
444      # Check if the prefix is excluded.
445      if checkprefix in prefix_exclusions:
446        continue
447
448      # If we do not have output for this prefix we skip it.
449      if not func_dict[checkprefix][func_name]:
450        continue
451
452      # Add some space between different check prefixes, but not after the last
453      # check line (before the test code).
454      if is_asm:
455        if len(printed_prefixes) != 0:
456          output_lines.append(comment_marker)
457
458      if checkprefix not in global_vars_seen_dict:
459          global_vars_seen_dict[checkprefix] = set()
460      global_vars_seen = global_vars_seen_dict[checkprefix]
461
462      vars_seen = set()
463      printed_prefixes.append(checkprefix)
464      attrs = str(func_dict[checkprefix][func_name].attrs)
465      attrs = '' if attrs == 'None' else attrs
466      if attrs:
467        output_lines.append('%s %s: Function Attrs: %s' % (comment_marker, checkprefix, attrs))
468      args_and_sig = str(func_dict[checkprefix][func_name].args_and_sig)
469      args_and_sig = generalize_check_lines([args_and_sig], is_analyze, vars_seen, global_vars_seen)[0]
470      if '[[' in args_and_sig:
471        output_lines.append(check_label_format % (checkprefix, func_name, ''))
472        output_lines.append('%s %s-SAME: %s' % (comment_marker, checkprefix, args_and_sig))
473      else:
474        output_lines.append(check_label_format % (checkprefix, func_name, args_and_sig))
475      func_body = str(func_dict[checkprefix][func_name]).splitlines()
476
477      # For ASM output, just emit the check lines.
478      if is_asm:
479        output_lines.append('%s %s:       %s' % (comment_marker, checkprefix, func_body[0]))
480        for func_line in func_body[1:]:
481          if func_line.strip() == '':
482            output_lines.append('%s %s-EMPTY:' % (comment_marker, checkprefix))
483          else:
484            output_lines.append('%s %s-NEXT:  %s' % (comment_marker, checkprefix, func_line))
485        break
486
487      # For IR output, change all defs to FileCheck variables, so we're immune
488      # to variable naming fashions.
489      func_body = generalize_check_lines(func_body, is_analyze, vars_seen, global_vars_seen)
490
491      # This could be selectively enabled with an optional invocation argument.
492      # Disabled for now: better to check everything. Be safe rather than sorry.
493
494      # Handle the first line of the function body as a special case because
495      # it's often just noise (a useless asm comment or entry label).
496      #if func_body[0].startswith("#") or func_body[0].startswith("entry:"):
497      #  is_blank_line = True
498      #else:
499      #  output_lines.append('%s %s:       %s' % (comment_marker, checkprefix, func_body[0]))
500      #  is_blank_line = False
501
502      is_blank_line = False
503
504      for func_line in func_body:
505        if func_line.strip() == '':
506          is_blank_line = True
507          continue
508        # Do not waste time checking IR comments.
509        func_line = SCRUB_IR_COMMENT_RE.sub(r'', func_line)
510
511        # Skip blank lines instead of checking them.
512        if is_blank_line:
513          output_lines.append('{} {}:       {}'.format(
514              comment_marker, checkprefix, func_line))
515        else:
516          output_lines.append('{} {}-NEXT:  {}'.format(
517              comment_marker, checkprefix, func_line))
518        is_blank_line = False
519
520      # Add space between different check prefixes and also before the first
521      # line of code in the test function.
522      output_lines.append(comment_marker)
523      break
524
525def add_ir_checks(output_lines, comment_marker, prefix_list, func_dict,
526                  func_name, preserve_names, function_sig, global_vars_seen_dict):
527  # Label format is based on IR string.
528  function_def_regex = 'define {{[^@]+}}' if function_sig else ''
529  check_label_format = '{} %s-LABEL: {}@%s%s'.format(comment_marker, function_def_regex)
530  add_checks(output_lines, comment_marker, prefix_list, func_dict, func_name,
531             check_label_format, False, preserve_names, global_vars_seen_dict)
532
533def add_analyze_checks(output_lines, comment_marker, prefix_list, func_dict, func_name):
534  check_label_format = '{} %s-LABEL: \'%s%s\''.format(comment_marker)
535  global_vars_seen_dict = {}
536  add_checks(output_lines, comment_marker, prefix_list, func_dict, func_name,
537             check_label_format, False, True, global_vars_seen_dict)
538
539
540def check_prefix(prefix):
541  if not PREFIX_RE.match(prefix):
542        hint = ""
543        if ',' in prefix:
544          hint = " Did you mean '--check-prefixes=" + prefix + "'?"
545        warn(("Supplied prefix '%s' is invalid. Prefix must contain only alphanumeric characters, hyphens and underscores." + hint) %
546             (prefix))
547
548
549def verify_filecheck_prefixes(fc_cmd):
550  fc_cmd_parts = fc_cmd.split()
551  for part in fc_cmd_parts:
552    if "check-prefix=" in part:
553      prefix = part.split('=', 1)[1]
554      check_prefix(prefix)
555    elif "check-prefixes=" in part:
556      prefixes = part.split('=', 1)[1].split(',')
557      for prefix in prefixes:
558        check_prefix(prefix)
559        if prefixes.count(prefix) > 1:
560          warn("Supplied prefix '%s' is not unique in the prefix list." % (prefix,))
561
562
563def get_autogennote_suffix(parser, args):
564  autogenerated_note_args = ''
565  for action in parser._actions:
566    if not hasattr(args, action.dest):
567      continue  # Ignore options such as --help that aren't included in args
568    # Ignore parameters such as paths to the binary or the list of tests
569    if action.dest in ('tests', 'update_only', 'opt_binary', 'llc_binary',
570                       'clang', 'opt', 'llvm_bin', 'verbose'):
571      continue
572    value = getattr(args, action.dest)
573    if action.const is not None:  # action stores a constant (usually True/False)
574      # Skip actions with different constant values (this happens with boolean
575      # --foo/--no-foo options)
576      if value != action.const:
577        continue
578    if parser.get_default(action.dest) == value:
579      continue  # Don't add default values
580    autogenerated_note_args += action.option_strings[0] + ' '
581    if action.const is None:  # action takes a parameter
582      autogenerated_note_args += '%s ' % value
583  if autogenerated_note_args:
584    autogenerated_note_args = ' %s %s' % (UTC_ARGS_KEY, autogenerated_note_args[:-1])
585  return autogenerated_note_args
586
587
588def check_for_command(line, parser, args, argv, argparse_callback):
589    cmd_m = UTC_ARGS_CMD.match(line)
590    if cmd_m:
591        cmd = cmd_m.group('cmd').strip().split(' ')
592        argv = argv + cmd
593        args = parser.parse_args(filter(lambda arg: arg not in args.tests, argv))
594        if argparse_callback is not None:
595          argparse_callback(args)
596    return args, argv
597