1 from __future__
import print_function
13 from typing
import List
15 ##### Common utilities for update_*test_checks.py
19 _prefix_filecheck_ir_name
= ""
24 1: Initial version, used by tests that don't specify --version explicitly.
25 2: --function-signature is now enabled by default and also checks return
27 3: Opening parenthesis of function args is kept on the first LABEL line
28 in case arguments are split to a separate SAME line.
34 """Wrap a compiled regular expression object to allow deep copy of a regexp.
35 This is required for the deep copy done in do_scrub.
39 def __init__(self
, regex
):
42 def __deepcopy__(self
, memo
):
43 result
= copy
.copy(self
)
44 result
.regex
= self
.regex
47 def search(self
, line
):
48 return self
.regex
.search(line
)
50 def sub(self
, repl
, line
):
51 return self
.regex
.sub(repl
, line
)
54 return self
.regex
.pattern
57 return self
.regex
.flags
61 """Augment a Regex object with a flag indicating whether a match should be
62 added (!is_filter_out) or removed (is_filter_out) from the generated checks.
66 def __init__(self
, regex
, is_filter_out
):
67 super(Filter
, self
).__init
__(regex
)
68 self
.is_filter_out
= is_filter_out
70 def __deepcopy__(self
, memo
):
71 result
= copy
.deepcopy(super(Filter
, self
), memo
)
72 result
.is_filter_out
= copy
.deepcopy(self
.is_filter_out
, memo
)
76 def parse_commandline_args(parser
):
77 class RegexAction(argparse
.Action
):
78 """Add a regular expression option value to a list of regular expressions.
79 This compiles the expression, wraps it in a Regex and adds it to the option
82 def __init__(self
, option_strings
, dest
, nargs
=None, **kwargs
):
84 raise ValueError("nargs not allowed")
85 super(RegexAction
, self
).__init
__(option_strings
, dest
, **kwargs
)
87 def do_call(self
, namespace
, values
, flags
):
88 value_list
= getattr(namespace
, self
.dest
)
89 if value_list
is None:
93 value_list
.append(Regex(re
.compile(values
, flags
)))
94 except re
.error
as error
:
96 "{}: Invalid regular expression '{}' ({})".format(
97 option_string
, error
.pattern
, error
.msg
101 setattr(namespace
, self
.dest
, value_list
)
103 def __call__(self
, parser
, namespace
, values
, option_string
=None):
104 self
.do_call(namespace
, values
, 0)
106 class FilterAction(RegexAction
):
107 """Add a filter to a list of filter option values."""
109 def __init__(self
, option_strings
, dest
, nargs
=None, **kwargs
):
110 super(FilterAction
, self
).__init
__(option_strings
, dest
, nargs
, **kwargs
)
112 def __call__(self
, parser
, namespace
, values
, option_string
=None):
113 super(FilterAction
, self
).__call
__(parser
, namespace
, values
, option_string
)
115 value_list
= getattr(namespace
, self
.dest
)
117 is_filter_out
= option_string
== "--filter-out"
119 value_list
[-1] = Filter(value_list
[-1].regex
, is_filter_out
)
121 setattr(namespace
, self
.dest
, value_list
)
123 filter_group
= parser
.add_argument_group(
125 """Filters are applied to each output line according to the order given. The
126 first matching filter terminates filter processing for that current line.""",
129 filter_group
.add_argument(
134 help="Only include lines matching REGEX (may be specified multiple times)",
136 filter_group
.add_argument(
141 help="Exclude lines matching REGEX",
145 "--include-generated-funcs",
147 help="Output checks for functions not in source",
150 "-v", "--verbose", action
="store_true", help="Show verbose output"
156 help="Only update test if it was already autogened",
161 help="Update test even if it was autogened by a different script",
168 help="Activate CHECK line generation from this point forward",
172 action
="store_false",
174 help="Deactivate CHECK line generation from this point forward",
177 "--replace-value-regex",
180 help="List of regular expressions to replace matching value names",
183 "--prefix-filecheck-ir-name",
185 help="Add a prefix to FileCheck IR value names to avoid conflicts with scripted names",
188 "--global-value-regex",
191 help="List of regular expressions that a global value declaration must match to generate a check (has no effect if checking globals is not enabled)",
194 "--global-hex-value-regex",
197 help="List of regular expressions such that, for matching global value declarations, literal integer values should be encoded in hex in the associated FileCheck directives",
199 # FIXME: in 3.9, we can use argparse.BooleanOptionalAction. At that point,
200 # we need to rename the flag to just -generate-body-for-unused-prefixes.
202 "--no-generate-body-for-unused-prefixes",
203 action
="store_false",
204 dest
="gen_unused_prefix_body",
206 help="Generate a function body that always matches for unused prefixes. This is useful when unused prefixes are desired, and it avoids needing to annotate each FileCheck as allowing them.",
208 # This is the default when regenerating existing tests. The default when
209 # generating new tests is determined by DEFAULT_VERSION.
211 "--version", type=int, default
=1, help="The version of output format"
213 args
= parser
.parse_args()
214 # TODO: This should not be handled differently from the other options
215 global _verbose
, _global_value_regex
, _global_hex_value_regex
216 _verbose
= args
.verbose
217 _global_value_regex
= args
.global_value_regex
218 _global_hex_value_regex
= args
.global_hex_value_regex
222 def parse_args(parser
, argv
):
223 args
= parser
.parse_args(argv
)
224 if args
.version
>= 2:
225 args
.function_signature
= True
226 # TODO: This should not be handled differently from the other options
227 global _verbose
, _global_value_regex
, _global_hex_value_regex
228 _verbose
= args
.verbose
229 _global_value_regex
= args
.global_value_regex
230 _global_hex_value_regex
= args
.global_hex_value_regex
234 class InputLineInfo(object):
235 def __init__(self
, line
, line_number
, args
, argv
):
237 self
.line_number
= line_number
242 class TestInfo(object):
255 self
.argparse_callback
= argparse_callback
258 if args
.prefix_filecheck_ir_name
:
259 global _prefix_filecheck_ir_name
260 _prefix_filecheck_ir_name
= args
.prefix_filecheck_ir_name
262 self
.input_lines
= input_lines
263 self
.run_lines
= find_run_lines(test
, self
.input_lines
)
264 self
.comment_prefix
= comment_prefix
265 if self
.comment_prefix
is None:
266 if self
.path
.endswith(".mir"):
267 self
.comment_prefix
= "#"
269 self
.comment_prefix
= ";"
270 self
.autogenerated_note_prefix
= self
.comment_prefix
+ " " + UTC_ADVERT
271 self
.test_autogenerated_note
= self
.autogenerated_note_prefix
+ script_name
272 self
.test_autogenerated_note
+= get_autogennote_suffix(parser
, self
.args
)
273 self
.test_unused_note
= (
274 self
.comment_prefix
+ self
.comment_prefix
+ " " + UNUSED_NOTE
277 def ro_iterlines(self
):
278 for line_num
, input_line
in enumerate(self
.input_lines
):
279 args
, argv
= check_for_command(
280 input_line
, self
.parser
, self
.args
, self
.argv
, self
.argparse_callback
282 yield InputLineInfo(input_line
, line_num
, args
, argv
)
284 def iterlines(self
, output_lines
):
285 output_lines
.append(self
.test_autogenerated_note
)
286 for line_info
in self
.ro_iterlines():
287 input_line
= line_info
.line
288 # Discard any previous script advertising.
289 if input_line
.startswith(self
.autogenerated_note_prefix
):
291 self
.args
= line_info
.args
292 self
.argv
= line_info
.argv
293 if not self
.args
.enabled
:
294 output_lines
.append(input_line
)
298 def get_checks_for_unused_prefixes(
299 self
, run_list
, used_prefixes
: List
[str]
301 run_list
= [element
for element
in run_list
if element
[0] is not None]
302 unused_prefixes
= set(
303 [prefix
for sublist
in run_list
for prefix
in sublist
[0]]
304 ).difference(set(used_prefixes
))
307 if not unused_prefixes
:
309 ret
.append(self
.test_unused_note
)
310 for unused
in sorted(unused_prefixes
):
312 "{comment} {prefix}: {match_everything}".format(
313 comment
=self
.comment_prefix
,
315 match_everything
=r
"""{{.*}}""",
322 test_patterns
, parser
, script_name
, comment_prefix
=None, argparse_callback
=None
324 for pattern
in test_patterns
:
325 # On Windows we must expand the patterns ourselves.
326 tests_list
= glob
.glob(pattern
)
328 warn("Test file pattern '%s' was not found. Ignoring it." % (pattern
,))
330 for test
in tests_list
:
331 with
open(test
) as f
:
332 input_lines
= [l
.rstrip() for l
in f
]
333 first_line
= input_lines
[0] if input_lines
else ""
334 if UTC_AVOID
in first_line
:
335 warn("Skipping test that must not be autogenerated: " + test
)
337 is_regenerate
= UTC_ADVERT
in first_line
339 # If we're generating a new test, set the default version to the latest.
341 if not is_regenerate
:
342 argv
.insert(1, "--version=" + str(DEFAULT_VERSION
))
344 args
= parse_args(parser
, argv
[1:])
345 if argparse_callback
is not None:
346 argparse_callback(args
)
348 if script_name
not in first_line
and not args
.force_update
:
350 "Skipping test which wasn't autogenerated by " + script_name
,
354 args
, argv
= check_for_command(
355 first_line
, parser
, args
, argv
, argparse_callback
357 elif args
.update_only
:
358 assert UTC_ADVERT
not in first_line
359 warn("Skipping test which isn't autogenerated: " + test
)
361 final_input_lines
= []
362 for l
in input_lines
:
365 final_input_lines
.append(l
)
378 def should_add_line_to_output(
379 input_line
, prefix_set
, skip_global_checks
=False, comment_marker
=";"
381 # Skip any blank comment lines in the IR.
382 if not skip_global_checks
and input_line
.strip() == comment_marker
:
384 # Skip a special double comment line we use as a separator.
385 if input_line
.strip() == comment_marker
+ SEPARATOR
:
387 # Skip any blank lines in the IR.
388 # if input_line.strip() == '':
390 # And skip any CHECK lines. We're building our own.
391 m
= CHECK_RE
.match(input_line
)
392 if m
and m
.group(1) in prefix_set
:
393 if skip_global_checks
:
394 global_ir_value_re
= re
.compile(r
"\[\[", flags
=(re
.M
))
395 return not global_ir_value_re
.search(input_line
)
401 # Perform lit-like substitutions
402 def getSubstitutions(sourcepath
):
403 sourcedir
= os
.path
.dirname(sourcepath
)
408 ("%{pathsep}", os
.pathsep
),
412 def applySubstitutions(s
, substitutions
):
413 for a
, b
in substitutions
:
418 # Invoke the tool that is being tested.
419 def invoke_tool(exe
, cmd_args
, ir
, preprocess_cmd
=None, verbose
=False):
420 with
open(ir
) as ir_file
:
421 substitutions
= getSubstitutions(ir
)
423 # TODO Remove the str form which is used by update_test_checks.py and
424 # update_llc_test_checks.py
425 # The safer list form is used by update_cc_test_checks.py
427 # Allow pre-processing the IR file (e.g. using sed):
430 ) # TODO: use a list instead of using shell
431 preprocess_cmd
= applySubstitutions(preprocess_cmd
, substitutions
).strip()
434 "Pre-processing input file: ",
442 # Python 2.7 doesn't have subprocess.DEVNULL:
443 with
open(os
.devnull
, "w") as devnull
:
444 pp
= subprocess
.Popen(
445 preprocess_cmd
, shell
=True, stdin
=devnull
, stdout
=subprocess
.PIPE
449 if isinstance(cmd_args
, list):
450 args
= [applySubstitutions(a
, substitutions
) for a
in cmd_args
]
451 stdout
= subprocess
.check_output([exe
] + args
, stdin
=ir_file
)
453 stdout
= subprocess
.check_output(
454 exe
+ " " + applySubstitutions(cmd_args
, substitutions
),
458 if sys
.version_info
[0] > 2:
459 # FYI, if you crashed here with a decode error, your run line probably
460 # results in bitcode or other binary format being written to the pipe.
461 # For an opt test, you probably want to add -S or -disable-output.
462 stdout
= stdout
.decode()
463 # Fix line endings to unix CR style.
464 return stdout
.replace("\r\n", "\n")
468 RUN_LINE_RE
= re
.compile(r
"^\s*(?://|[;#])\s*RUN:\s*(.*)$")
469 CHECK_PREFIX_RE
= re
.compile(r
"--?check-prefix(?:es)?[= ](\S+)")
470 PREFIX_RE
= re
.compile("^[a-zA-Z0-9_-]+$")
471 CHECK_RE
= re
.compile(
472 r
"^\s*(?://|[;#])\s*([^:]+?)(?:-NEXT|-NOT|-DAG|-LABEL|-SAME|-EMPTY)?:"
475 UTC_ARGS_KEY
= "UTC_ARGS:"
476 UTC_ARGS_CMD
= re
.compile(r
".*" + UTC_ARGS_KEY
+ "\s*(?P<cmd>.*)\s*$")
477 UTC_ADVERT
= "NOTE: Assertions have been autogenerated by "
478 UTC_AVOID
= "NOTE: Do not autogenerate"
479 UNUSED_NOTE
= "NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:"
481 OPT_FUNCTION_RE
= re
.compile(
482 r
"^(\s*;\s*Function\sAttrs:\s(?P<attrs>[\w\s():,]+?))?\s*define\s+(?P<funcdef_attrs_and_ret>[^@]*)@(?P<func>[\w.$-]+?)\s*"
483 r
"(?P<args_and_sig>\((\)|(.*?[\w.-]+?)\))[^{]*\{)\n(?P<body>.*?)^\}$",
487 ANALYZE_FUNCTION_RE
= re
.compile(
488 r
"^\s*\'(?P<analysis>[\w\s-]+?)\'\s+for\s+function\s+\'(?P<func>[\w.$-]+?)\':"
489 r
"\s*\n(?P<body>.*)$",
493 LV_DEBUG_RE
= re
.compile(
494 r
"^\s*\'(?P<func>[\w.$-]+?)\'[^\n]*" r
"\s*\n(?P<body>.*)$", flags
=(re
.X | re
.S
)
497 IR_FUNCTION_RE
= re
.compile(r
'^\s*define\s+(?:internal\s+)?[^@]*@"?([\w.$-]+)"?\s*\(')
498 TRIPLE_IR_RE
= re
.compile(r
'^\s*target\s+triple\s*=\s*"([^"]+)"$')
499 TRIPLE_ARG_RE
= re
.compile(r
"-mtriple[= ]([^ ]+)")
500 MARCH_ARG_RE
= re
.compile(r
"-march[= ]([^ ]+)")
501 DEBUG_ONLY_ARG_RE
= re
.compile(r
"-debug-only[= ]([^ ]+)")
503 SCRUB_LEADING_WHITESPACE_RE
= re
.compile(r
"^(\s+)")
504 SCRUB_WHITESPACE_RE
= re
.compile(r
"(?!^(| \w))[ \t]+", flags
=re
.M
)
505 SCRUB_TRAILING_WHITESPACE_RE
= re
.compile(r
"[ \t]+$", flags
=re
.M
)
506 SCRUB_TRAILING_WHITESPACE_TEST_RE
= SCRUB_TRAILING_WHITESPACE_RE
507 SCRUB_TRAILING_WHITESPACE_AND_ATTRIBUTES_RE
= re
.compile(
508 r
"([ \t]|(#[0-9]+))+$", flags
=re
.M
510 SCRUB_KILL_COMMENT_RE
= re
.compile(r
"^ *#+ +kill:.*\n")
511 SCRUB_LOOP_COMMENT_RE
= re
.compile(
512 r
"# =>This Inner Loop Header:.*|# in Loop:.*", flags
=re
.M
514 SCRUB_TAILING_COMMENT_TOKEN_RE
= re
.compile(r
"(?<=\S)+[ \t]*#$", flags
=re
.M
)
519 def error(msg
, test_file
=None):
521 msg
= "{}: {}".format(msg
, test_file
)
522 print("ERROR: {}".format(msg
), file=sys
.stderr
)
525 def warn(msg
, test_file
=None):
527 msg
= "{}: {}".format(msg
, test_file
)
528 print("WARNING: {}".format(msg
), file=sys
.stderr
)
531 def debug(*args
, **kwargs
):
532 # Python2 does not allow def debug(*args, file=sys.stderr, **kwargs):
533 if "file" not in kwargs
:
534 kwargs
["file"] = sys
.stderr
536 print(*args
, **kwargs
)
539 def find_run_lines(test
, lines
):
540 debug("Scanning for RUN lines in test file:", test
)
541 raw_lines
= [m
.group(1) for m
in [RUN_LINE_RE
.match(l
) for l
in lines
] if m
]
542 run_lines
= [raw_lines
[0]] if len(raw_lines
) > 0 else []
543 for l
in raw_lines
[1:]:
544 if run_lines
[-1].endswith("\\"):
545 run_lines
[-1] = run_lines
[-1].rstrip("\\") + " " + l
548 debug("Found {} RUN lines in {}:".format(len(run_lines
), test
))
550 debug(" RUN: {}".format(l
))
554 def get_triple_from_march(march
):
560 "hexagon": "hexagon",
563 for prefix
, triple
in triples
.items():
564 if march
.startswith(prefix
):
566 print("Cannot find a triple. Assume 'x86'", file=sys
.stderr
)
570 def apply_filters(line
, filters
):
573 if not f
.is_filter_out
:
576 return False if f
.is_filter_out
else True
577 # If we only used filter-out, keep the line, otherwise discard it since no
579 return False if has_filter
else True
582 def do_filter(body
, filters
):
587 filter(lambda line
: apply_filters(line
, filters
), body
.splitlines())
592 def scrub_body(body
):
593 # Scrub runs of whitespace out of the assembly, but leave the leading
594 # whitespace in place.
595 body
= SCRUB_WHITESPACE_RE
.sub(r
" ", body
)
596 # Expand the tabs used for indentation.
597 body
= str.expandtabs(body
, 2)
598 # Strip trailing whitespace.
599 body
= SCRUB_TRAILING_WHITESPACE_TEST_RE
.sub(r
"", body
)
603 def do_scrub(body
, scrubber
, scrubber_args
, extra
):
605 local_args
= copy
.deepcopy(scrubber_args
)
606 local_args
[0].extra_scrub
= extra
607 return scrubber(body
, *local_args
)
608 return scrubber(body
, *scrubber_args
)
611 # Build up a dictionary of all the function bodies.
612 class function_body(object):
617 funcdef_attrs_and_ret
,
623 self
.extrascrub
= extra
624 self
.funcdef_attrs_and_ret
= funcdef_attrs_and_ret
625 self
.args_and_sig
= args_and_sig
627 self
.func_name_separator
= func_name_separator
629 def is_same_except_arg_names(
630 self
, extrascrub
, funcdef_attrs_and_ret
, args_and_sig
, attrs
, is_backend
634 def drop_arg_names(match
):
635 arg_names
.add(match
.group(variable_group_in_ir_value_match
))
636 if match
.group(attribute_group_in_ir_value_match
):
637 attr
= match
.group(attribute_group_in_ir_value_match
)
640 return match
.group(1) + attr
+ match
.group(match
.lastindex
)
642 def repl_arg_names(match
):
644 match
.group(variable_group_in_ir_value_match
) is not None
645 and match
.group(variable_group_in_ir_value_match
) in arg_names
647 return match
.group(1) + match
.group(match
.lastindex
)
648 return match
.group(1) + match
.group(2) + match
.group(match
.lastindex
)
650 if self
.funcdef_attrs_and_ret
!= funcdef_attrs_and_ret
:
652 if self
.attrs
!= attrs
:
654 ans0
= IR_VALUE_RE
.sub(drop_arg_names
, self
.args_and_sig
)
655 ans1
= IR_VALUE_RE
.sub(drop_arg_names
, args_and_sig
)
659 # Check without replacements, the replacements are not applied to the
660 # body for backend checks.
661 return self
.extrascrub
== extrascrub
663 es0
= IR_VALUE_RE
.sub(repl_arg_names
, self
.extrascrub
)
664 es1
= IR_VALUE_RE
.sub(repl_arg_names
, extrascrub
)
665 es0
= SCRUB_IR_COMMENT_RE
.sub(r
"", es0
)
666 es1
= SCRUB_IR_COMMENT_RE
.sub(r
"", es1
)
673 class FunctionTestBuilder
:
674 def __init__(self
, run_list
, flags
, scrubber_args
, path
):
675 self
._verbose
= flags
.verbose
676 self
._record
_args
= flags
.function_signature
677 self
._check
_attributes
= flags
.check_attributes
678 # Strip double-quotes if input was read by UTC_ARGS
683 re
.compile(f
.pattern().strip('"'), f
.flags()), f
.is_filter_out
691 self
._scrubber
_args
= scrubber_args
693 # Strip double-quotes if input was read by UTC_ARGS
694 self
._replace
_value
_regex
= list(
695 map(lambda x
: x
.strip('"'), flags
.replace_value_regex
)
698 self
._func
_order
= {}
699 self
._global
_var
_dict
= {}
700 self
._processed
_prefixes
= set()
701 for tuple in run_list
:
702 for prefix
in tuple[0]:
703 self
._func
_dict
.update({prefix
: dict()})
704 self
._func
_order
.update({prefix
: []})
705 self
._global
_var
_dict
.update({prefix
: dict()})
707 def finish_and_get_func_dict(self
):
708 for prefix
in self
.get_failed_prefixes():
710 "Prefix %s had conflicting output from different RUN lines for all functions in test %s"
716 return self
._func
_dict
718 def func_order(self
):
719 return self
._func
_order
721 def global_var_dict(self
):
722 return self
._global
_var
_dict
724 def is_filtered(self
):
725 return bool(self
._filters
)
727 def process_run_line(
728 self
, function_re
, scrubber
, raw_tool_output
, prefixes
, is_backend
730 build_global_values_dictionary(self
._global
_var
_dict
, raw_tool_output
, prefixes
)
731 for m
in function_re
.finditer(raw_tool_output
):
734 func
= m
.group("func")
735 body
= m
.group("body")
736 # func_name_separator is the string that is placed right after function name at the
737 # beginning of assembly function definition. In most assemblies, that is just a
738 # colon: `foo:`. But, for example, in nvptx it is a brace: `foo(`. If is_backend is
739 # False, just assume that separator is an empty string.
741 # Use ':' as default separator.
742 func_name_separator
= (
743 m
.group("func_name_separator")
744 if "func_name_separator" in m
.groupdict()
748 func_name_separator
= ""
749 attrs
= m
.group("attrs") if self
._check
_attributes
else ""
750 funcdef_attrs_and_ret
= (
751 m
.group("funcdef_attrs_and_ret") if self
._record
_args
else ""
753 # Determine if we print arguments, the opening brace, or nothing after the
755 if self
._record
_args
and "args_and_sig" in m
.groupdict():
756 args_and_sig
= scrub_body(m
.group("args_and_sig").strip())
757 elif "args_and_sig" in m
.groupdict():
761 filtered_body
= do_filter(body
, self
._filters
)
762 scrubbed_body
= do_scrub(
763 filtered_body
, scrubber
, self
._scrubber
_args
, extra
=False
765 scrubbed_extra
= do_scrub(
766 filtered_body
, scrubber
, self
._scrubber
_args
, extra
=True
768 if "analysis" in m
.groupdict():
769 analysis
= m
.group("analysis")
770 supported_analyses
= {
771 "cost model analysis",
772 "scalar evolution analysis",
774 if analysis
.lower() not in supported_analyses
:
775 warn("Unsupported analysis mode: %r!" % (analysis
,))
776 if func
.startswith("stress"):
777 # We only use the last line of the function body for stress tests.
778 scrubbed_body
= "\n".join(scrubbed_body
.splitlines()[-1:])
780 print("Processing function: " + func
, file=sys
.stderr
)
781 for l
in scrubbed_body
.splitlines():
782 print(" " + l
, file=sys
.stderr
)
783 for prefix
in prefixes
:
784 # Replace function names matching the regex.
785 for regex
in self
._replace
_value
_regex
:
786 # Pattern that matches capture groups in the regex in leftmost order.
787 group_regex
= re
.compile(r
"\(.*?\)")
788 # Replace function name with regex.
789 match
= re
.match(regex
, func
)
792 # Replace any capture groups with their matched strings.
793 for g
in match
.groups():
794 func_repl
= group_regex
.sub(
795 re
.escape(g
), func_repl
, count
=1
797 func
= re
.sub(func_repl
, "{{" + func_repl
+ "}}", func
)
799 # Replace all calls to regex matching functions.
800 matches
= re
.finditer(regex
, scrubbed_body
)
801 for match
in matches
:
803 # Replace any capture groups with their matched strings.
804 for g
in match
.groups():
805 func_repl
= group_regex
.sub(
806 re
.escape(g
), func_repl
, count
=1
808 # Substitute function call names that match the regex with the same
809 # capture groups set.
810 scrubbed_body
= re
.sub(
811 func_repl
, "{{" + func_repl
+ "}}", scrubbed_body
814 if func
in self
._func
_dict
[prefix
]:
815 if self
._func
_dict
[prefix
][func
] is not None and (
816 str(self
._func
_dict
[prefix
][func
]) != scrubbed_body
817 or self
._func
_dict
[prefix
][func
].args_and_sig
!= args_and_sig
818 or self
._func
_dict
[prefix
][func
].attrs
!= attrs
819 or self
._func
_dict
[prefix
][func
].funcdef_attrs_and_ret
820 != funcdef_attrs_and_ret
822 if self
._func
_dict
[prefix
][func
].is_same_except_arg_names(
824 funcdef_attrs_and_ret
,
829 self
._func
_dict
[prefix
][func
].scrub
= scrubbed_extra
830 self
._func
_dict
[prefix
][func
].args_and_sig
= args_and_sig
832 # This means a previous RUN line produced a body for this function
833 # that is different from the one produced by this current RUN line,
834 # so the body can't be common across RUN lines. We use None to
836 self
._func
_dict
[prefix
][func
] = None
838 if prefix
not in self
._processed
_prefixes
:
839 self
._func
_dict
[prefix
][func
] = function_body(
842 funcdef_attrs_and_ret
,
847 self
._func
_order
[prefix
].append(func
)
849 # An earlier RUN line used this check prefixes but didn't produce
850 # a body for this function. This happens in Clang tests that use
851 # preprocesser directives to exclude individual functions from some
853 self
._func
_dict
[prefix
][func
] = None
855 def processed_prefixes(self
, prefixes
):
857 Mark a set of prefixes as having had at least one applicable RUN line fully
858 processed. This is used to filter out function bodies that don't have
859 outputs for all RUN lines.
861 self
._processed
_prefixes
.update(prefixes
)
863 def get_failed_prefixes(self
):
864 # This returns the list of those prefixes that failed to match any function,
865 # because there were conflicting bodies produced by different RUN lines, in
866 # all instances of the prefix.
867 for prefix
in self
._func
_dict
:
868 if self
._func
_dict
[prefix
] and (
871 for fct
in self
._func
_dict
[prefix
]
872 if self
._func
_dict
[prefix
][fct
] is not None
878 ##### Generator of LLVM IR CHECK lines
880 SCRUB_IR_COMMENT_RE
= re
.compile(r
"\s*;.*")
882 # TODO: We should also derive check lines for global, debug, loop declarations, etc..
892 global_ir_rhs_regexp
,
894 is_before_functions
=False,
896 replace_number_with_counter
=False
898 self
.check_prefix
= check_prefix
899 self
.check_key
= check_key
900 self
.ir_prefix
= ir_prefix
901 self
.ir_regexp
= ir_regexp
902 self
.global_ir_rhs_regexp
= global_ir_rhs_regexp
903 self
.is_before_functions
= is_before_functions
904 self
.is_number
= is_number
905 # Some variable numbers (e.g. MCINST1234) will change based on unrelated
906 # modifications to LLVM, replace those with an incrementing counter.
907 self
.replace_number_with_counter
= replace_number_with_counter
908 self
.variable_mapping
= {}
910 # Return true if this kind of IR value is "local", basically if it matches '%{{.*}}'.
911 def is_local_def_ir_value_match(self
, match
):
912 return self
.ir_prefix
== "%"
914 # Return true if this kind of IR value is "global", basically if it matches '#{{.*}}'.
915 def is_global_scope_ir_value_match(self
, match
):
916 return self
.global_ir_rhs_regexp
is not None
918 # Return the IR prefix and check prefix we use for this kind or IR value,
919 # e.g., (%, TMP) for locals.
920 def get_ir_prefix_from_ir_value_match(self
, match
):
921 return self
.ir_prefix
, self
.check_prefix
923 # Return the IR regexp we use for this kind or IR value, e.g., [\w.-]+? for locals
924 def get_ir_regex_from_ir_value_re_match(self
, match
):
925 # for backwards compatibility we check locals with '.*'
926 if self
.is_local_def_ir_value_match(match
):
928 return self
.ir_regexp
930 # Create a FileCheck variable name based on an IR name.
931 def get_value_name(self
, var
: str, check_prefix
: str):
932 var
= var
.replace("!", "")
933 if self
.replace_number_with_counter
:
934 assert var
.isdigit(), var
935 replacement
= self
.variable_mapping
.get(var
, None)
936 if replacement
is None:
937 # Replace variable with an incrementing counter
938 replacement
= str(len(self
.variable_mapping
) + 1)
939 self
.variable_mapping
[var
] = replacement
941 # This is a nameless value, prepend check_prefix.
943 var
= check_prefix
+ var
945 # This is a named value that clashes with the check_prefix, prepend with
946 # _prefix_filecheck_ir_name, if it has been defined.
948 may_clash_with_default_check_prefix_name(check_prefix
, var
)
949 and _prefix_filecheck_ir_name
951 var
= _prefix_filecheck_ir_name
+ var
952 var
= var
.replace(".", "_")
953 var
= var
.replace("-", "_")
956 # Create a FileCheck variable from regex.
957 def get_value_definition(self
, var
, match
):
958 # for backwards compatibility we check locals with '.*'
959 varname
= self
.get_value_name(var
, self
.check_prefix
)
960 prefix
= self
.get_ir_prefix_from_ir_value_match(match
)[0]
962 regex
= "" # always capture a number in the default format
963 capture_start
= "[[#"
965 regex
= self
.get_ir_regex_from_ir_value_re_match(match
)
967 if self
.is_local_def_ir_value_match(match
):
968 return capture_start
+ varname
+ ":" + prefix
+ regex
+ "]]"
969 return prefix
+ capture_start
+ varname
+ ":" + regex
+ "]]"
971 # Use a FileCheck variable.
972 def get_value_use(self
, var
, match
, var_prefix
=None):
973 if var_prefix
is None:
974 var_prefix
= self
.check_prefix
975 capture_start
= "[[#" if self
.is_number
else "[["
976 if self
.is_local_def_ir_value_match(match
):
977 return capture_start
+ self
.get_value_name(var
, var_prefix
) + "]]"
978 prefix
= self
.get_ir_prefix_from_ir_value_match(match
)[0]
979 return prefix
+ capture_start
+ self
.get_value_name(var
, var_prefix
) + "]]"
982 # Description of the different "unnamed" values we match in the IR, e.g.,
983 # (local) ssa values, (debug) metadata, etc.
984 ir_nameless_values
= [
985 # check_prefix check_key ir_prefix ir_regexp global_ir_rhs_regexp
986 NamelessValue(r
"TMP", "%", r
"%", r
"[\w$.-]+?", None),
987 NamelessValue(r
"ATTR", "#", r
"#", r
"[0-9]+", None),
988 NamelessValue(r
"ATTR", "#", r
"attributes #", r
"[0-9]+", r
"{[^}]*}"),
989 NamelessValue(r
"GLOB", "@", r
"@", r
"[0-9]+", None),
991 r
"GLOB", "@", r
"@", r
'[a-zA-Z0-9_$"\\.-]+', r
".+", is_before_functions
=True
993 NamelessValue(r
"DBG", "!", r
"!dbg ", r
"![0-9]+", None),
994 NamelessValue(r
"DIASSIGNID", "!", r
"!DIAssignID ", r
"![0-9]+", None),
995 NamelessValue(r
"PROF", "!", r
"!prof ", r
"![0-9]+", None),
996 NamelessValue(r
"TBAA", "!", r
"!tbaa ", r
"![0-9]+", None),
997 NamelessValue(r
"TBAA_STRUCT", "!", r
"!tbaa.struct ", r
"![0-9]+", None),
998 NamelessValue(r
"RNG", "!", r
"!range ", r
"![0-9]+", None),
999 NamelessValue(r
"LOOP", "!", r
"!llvm.loop ", r
"![0-9]+", None),
1000 NamelessValue(r
"META", "!", r
"metadata ", r
"![0-9]+", None),
1001 NamelessValue(r
"META", "!", r
"", r
"![0-9]+", r
"(?:distinct |)!.*"),
1002 NamelessValue(r
"ACC_GRP", "!", r
"!llvm.access.group ", r
"![0-9]+", None),
1005 asm_nameless_values
= [
1013 replace_number_with_counter
=True,
1022 replace_number_with_counter
=True,
1027 def createOrRegexp(old
, new
):
1032 return old
+ "|" + new
1035 def createPrefixMatch(prefix_str
, prefix_re
):
1036 return "(?:" + prefix_str
+ "(" + prefix_re
+ "))"
1039 # Build the regexp that matches an "IR value". This can be a local variable,
1040 # argument, global, or metadata, anything that is "named". It is important that
1041 # the PREFIX and SUFFIX below only contain a single group, if that changes
1042 # other locations will need adjustment as well.
1043 IR_VALUE_REGEXP_PREFIX
= r
"(\s*)"
1044 IR_VALUE_REGEXP_STRING
= r
""
1045 for nameless_value
in ir_nameless_values
:
1046 match
= createPrefixMatch(nameless_value
.ir_prefix
, nameless_value
.ir_regexp
)
1047 if nameless_value
.global_ir_rhs_regexp
is not None:
1049 IR_VALUE_REGEXP_STRING
= createOrRegexp(IR_VALUE_REGEXP_STRING
, match
)
1050 IR_VALUE_REGEXP_SUFFIX
= r
"([,\s\(\)]|\Z)"
1051 IR_VALUE_RE
= re
.compile(
1052 IR_VALUE_REGEXP_PREFIX
1054 + IR_VALUE_REGEXP_STRING
1056 + IR_VALUE_REGEXP_SUFFIX
1059 # Build the regexp that matches an "ASM value" (currently only for --asm-show-inst comments).
1060 ASM_VALUE_REGEXP_STRING
= ""
1061 for nameless_value
in asm_nameless_values
:
1062 match
= createPrefixMatch(nameless_value
.ir_prefix
, nameless_value
.ir_regexp
)
1063 ASM_VALUE_REGEXP_STRING
= createOrRegexp(ASM_VALUE_REGEXP_STRING
, match
)
1064 ASM_VALUE_REGEXP_SUFFIX
= r
"([>\s]|\Z)"
1065 ASM_VALUE_RE
= re
.compile(
1066 r
"((?:#|//)\s*)" + "(" + ASM_VALUE_REGEXP_STRING
+ ")" + ASM_VALUE_REGEXP_SUFFIX
1069 # The entire match is group 0, the prefix has one group (=1), the entire
1070 # IR_VALUE_REGEXP_STRING is one group (=2), and then the nameless values start.
1071 first_nameless_group_in_ir_value_match
= 3
1073 # constants for the group id of special matches
1074 variable_group_in_ir_value_match
= 3
1075 attribute_group_in_ir_value_match
= 4
1077 # Check a match for IR_VALUE_RE and inspect it to determine if it was a local
1078 # value, %..., global @..., debug number !dbg !..., etc. See the PREFIXES above.
1079 def get_idx_from_ir_value_match(match
):
1080 for i
in range(first_nameless_group_in_ir_value_match
, match
.lastindex
):
1081 if match
.group(i
) is not None:
1082 return i
- first_nameless_group_in_ir_value_match
1083 error("Unable to identify the kind of IR value from the match!")
1087 # See get_idx_from_ir_value_match
1088 def get_name_from_ir_value_match(match
):
1090 get_idx_from_ir_value_match(match
) + first_nameless_group_in_ir_value_match
1094 def get_nameless_value_from_match(match
, nameless_values
) -> NamelessValue
:
1095 return nameless_values
[get_idx_from_ir_value_match(match
)]
1098 # Return true if var clashes with the scripted FileCheck check_prefix.
1099 def may_clash_with_default_check_prefix_name(check_prefix
, var
):
1100 return check_prefix
and re
.match(
1101 r
"^" + check_prefix
+ r
"[0-9]+?$", var
, re
.IGNORECASE
1105 def generalize_check_lines_common(
1111 nameless_value_regex
,
1114 # This gets called for each match that occurs in
1115 # a line. We transform variables we haven't seen
1116 # into defs, and variables we have seen into uses.
1117 def transform_line_vars(match
):
1118 var
= get_name_from_ir_value_match(match
)
1119 nameless_value
= get_nameless_value_from_match(match
, nameless_values
)
1120 if may_clash_with_default_check_prefix_name(nameless_value
.check_prefix
, var
):
1122 "Change IR value name '%s' or use --prefix-filecheck-ir-name to prevent possible conflict"
1123 " with scripted FileCheck name." % (var
,)
1125 key
= (var
, nameless_value
.check_key
)
1126 is_local_def
= nameless_value
.is_local_def_ir_value_match(match
)
1127 if is_local_def
and key
in vars_seen
:
1128 rv
= nameless_value
.get_value_use(var
, match
)
1129 elif not is_local_def
and key
in global_vars_seen
:
1130 # We could have seen a different prefix for the global variables first,
1131 # ensure we use that one instead of the prefix for the current match.
1132 rv
= nameless_value
.get_value_use(var
, match
, global_vars_seen
[key
])
1137 global_vars_seen
[key
] = nameless_value
.check_prefix
1138 rv
= nameless_value
.get_value_definition(var
, match
)
1139 # re.sub replaces the entire regex match
1140 # with whatever you return, so we have
1141 # to make sure to hand it back everything
1142 # including the commas and spaces.
1143 return match
.group(1) + rv
+ match
.group(match
.lastindex
)
1147 for i
, line
in enumerate(lines
):
1149 # An IR variable named '%.' matches the FileCheck regex string.
1150 line
= line
.replace("%.", "%dot")
1151 for regex
in _global_hex_value_regex
:
1152 if re
.match("^@" + regex
+ " = ", line
):
1154 r
"\bi([0-9]+) ([0-9]+)",
1158 + hex(int(m
.group(2)))
1163 # Ignore any comments, since the check lines will too.
1164 scrubbed_line
= SCRUB_IR_COMMENT_RE
.sub(r
"", line
)
1165 lines
[i
] = scrubbed_line
1166 if is_asm
or not is_analyze
:
1167 # It can happen that two matches are back-to-back and for some reason sub
1168 # will not replace both of them. For now we work around this by
1169 # substituting until there is no more match.
1172 (lines
[i
], changed
) = nameless_value_regex
.subn(
1173 transform_line_vars
, lines
[i
], count
=1
1178 # Replace IR value defs and uses with FileCheck variables.
1179 def generalize_check_lines(lines
, is_analyze
, vars_seen
, global_vars_seen
):
1180 return generalize_check_lines_common(
1191 def generalize_asm_check_lines(lines
, vars_seen
, global_vars_seen
):
1192 return generalize_check_lines_common(
1197 asm_nameless_values
,
1213 global_vars_seen_dict
,
1216 # 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.
1217 prefix_exclusions
= set()
1218 printed_prefixes
= []
1219 for p
in prefix_list
:
1220 checkprefixes
= p
[0]
1221 # If not all checkprefixes of this run line produced the function we cannot check for it as it does not
1222 # exist for this run line. A subset of the check prefixes might know about the function but only because
1223 # other run lines created it.
1226 lambda checkprefix
: func_name
not in func_dict
[checkprefix
],
1230 prefix_exclusions |
= set(checkprefixes
)
1233 # prefix_exclusions is constructed, we can now emit the output
1234 for p
in prefix_list
:
1235 global_vars_seen
= {}
1236 checkprefixes
= p
[0]
1237 for checkprefix
in checkprefixes
:
1238 if checkprefix
in global_vars_seen_dict
:
1239 global_vars_seen
.update(global_vars_seen_dict
[checkprefix
])
1241 global_vars_seen_dict
[checkprefix
] = {}
1242 if checkprefix
in printed_prefixes
:
1245 # Check if the prefix is excluded.
1246 if checkprefix
in prefix_exclusions
:
1249 # If we do not have output for this prefix we skip it.
1250 if not func_dict
[checkprefix
][func_name
]:
1253 # Add some space between different check prefixes, but not after the last
1254 # check line (before the test code).
1256 if len(printed_prefixes
) != 0:
1257 output_lines
.append(comment_marker
)
1259 if checkprefix
not in global_vars_seen_dict
:
1260 global_vars_seen_dict
[checkprefix
] = {}
1262 global_vars_seen_before
= [key
for key
in global_vars_seen
.keys()]
1265 printed_prefixes
.append(checkprefix
)
1266 attrs
= str(func_dict
[checkprefix
][func_name
].attrs
)
1267 attrs
= "" if attrs
== "None" else attrs
1269 funcdef_attrs_and_ret
= func_dict
[checkprefix
][
1271 ].funcdef_attrs_and_ret
1273 funcdef_attrs_and_ret
= ""
1276 output_lines
.append(
1277 "%s %s: Function Attrs: %s" % (comment_marker
, checkprefix
, attrs
)
1279 args_and_sig
= str(func_dict
[checkprefix
][func_name
].args_and_sig
)
1281 args_and_sig
= generalize_check_lines(
1282 [args_and_sig
], is_analyze
, vars_seen
, global_vars_seen
1284 func_name_separator
= func_dict
[checkprefix
][func_name
].func_name_separator
1285 if "[[" in args_and_sig
:
1286 # Captures in label lines are not supported, thus split into a -LABEL
1287 # and a separate -SAME line that contains the arguments with captures.
1288 args_and_sig_prefix
= ""
1289 if version
>= 3 and args_and_sig
.startswith("("):
1290 # Ensure the "(" separating function name and arguments is in the
1291 # label line. This is required in case of function names that are
1292 # prefixes of each other. Otherwise, the label line for "foo" might
1293 # incorrectly match on "foo.specialized".
1294 args_and_sig_prefix
= args_and_sig
[0]
1295 args_and_sig
= args_and_sig
[1:]
1297 # Removing args_and_sig from the label match line requires
1298 # func_name_separator to be empty. Otherwise, the match will not work.
1299 assert func_name_separator
== ""
1300 output_lines
.append(
1304 funcdef_attrs_and_ret
,
1306 args_and_sig_prefix
,
1307 func_name_separator
,
1310 output_lines
.append(
1311 "%s %s-SAME: %s" % (comment_marker
, checkprefix
, args_and_sig
)
1314 output_lines
.append(
1318 funcdef_attrs_and_ret
,
1321 func_name_separator
,
1324 func_body
= str(func_dict
[checkprefix
][func_name
]).splitlines()
1326 # We have filtered everything.
1329 # For ASM output, just emit the check lines.
1333 # For filtered output we don't add "-NEXT" so don't add extra spaces
1334 # before the first line.
1337 output_lines
.append(
1338 "%s %s: %s" % (comment_marker
, checkprefix
, func_body
[0])
1340 func_lines
= generalize_asm_check_lines(
1341 func_body
[body_start
:], vars_seen
, global_vars_seen
1343 for func_line
in func_lines
:
1344 if func_line
.strip() == "":
1345 output_lines
.append(
1346 "%s %s-EMPTY:" % (comment_marker
, checkprefix
)
1349 check_suffix
= "-NEXT" if not is_filtered
else ""
1350 output_lines
.append(
1352 % (comment_marker
, checkprefix
, check_suffix
, func_line
)
1354 # Remember new global variables we have not seen before
1355 for key
in global_vars_seen
:
1356 if key
not in global_vars_seen_before
:
1357 global_vars_seen_dict
[checkprefix
][key
] = global_vars_seen
[key
]
1360 # For IR output, change all defs to FileCheck variables, so we're immune
1361 # to variable naming fashions.
1362 func_body
= generalize_check_lines(
1363 func_body
, is_analyze
, vars_seen
, global_vars_seen
1366 # This could be selectively enabled with an optional invocation argument.
1367 # Disabled for now: better to check everything. Be safe rather than sorry.
1369 # Handle the first line of the function body as a special case because
1370 # it's often just noise (a useless asm comment or entry label).
1371 # if func_body[0].startswith("#") or func_body[0].startswith("entry:"):
1372 # is_blank_line = True
1374 # output_lines.append('%s %s: %s' % (comment_marker, checkprefix, func_body[0]))
1375 # is_blank_line = False
1377 is_blank_line
= False
1379 for func_line
in func_body
:
1380 if func_line
.strip() == "":
1381 is_blank_line
= True
1383 # Do not waste time checking IR comments.
1384 func_line
= SCRUB_IR_COMMENT_RE
.sub(r
"", func_line
)
1386 # Skip blank lines instead of checking them.
1388 output_lines
.append(
1389 "{} {}: {}".format(comment_marker
, checkprefix
, func_line
)
1392 check_suffix
= "-NEXT" if not is_filtered
else ""
1393 output_lines
.append(
1394 "{} {}{}: {}".format(
1395 comment_marker
, checkprefix
, check_suffix
, func_line
1398 is_blank_line
= False
1400 # Add space between different check prefixes and also before the first
1401 # line of code in the test function.
1402 output_lines
.append(comment_marker
)
1404 # Remember new global variables we have not seen before
1405 for key
in global_vars_seen
:
1406 if key
not in global_vars_seen_before
:
1407 global_vars_seen_dict
[checkprefix
][key
] = global_vars_seen
[key
]
1409 return printed_prefixes
1421 global_vars_seen_dict
,
1424 # Label format is based on IR string.
1425 if function_sig
and version
> 1:
1426 function_def_regex
= "define %s"
1428 function_def_regex
= "define {{[^@]+}}%s"
1430 function_def_regex
= "%s"
1431 check_label_format
= "{} %s-LABEL: {}@%s%s%s".format(
1432 comment_marker
, function_def_regex
1444 global_vars_seen_dict
,
1449 def add_analyze_checks(
1450 output_lines
, comment_marker
, prefix_list
, func_dict
, func_name
, is_filtered
1452 check_label_format
= "{} %s-LABEL: '%s%s%s%s'".format(comment_marker
)
1453 global_vars_seen_dict
= {}
1464 global_vars_seen_dict
,
1469 def build_global_values_dictionary(glob_val_dict
, raw_tool_output
, prefixes
):
1470 for nameless_value
in itertools
.chain(ir_nameless_values
, asm_nameless_values
):
1471 if nameless_value
.global_ir_rhs_regexp
is None:
1474 lhs_re_str
= nameless_value
.ir_prefix
+ nameless_value
.ir_regexp
1475 rhs_re_str
= nameless_value
.global_ir_rhs_regexp
1477 global_ir_value_re_str
= r
"^" + lhs_re_str
+ r
"\s=\s" + rhs_re_str
+ r
"$"
1478 global_ir_value_re
= re
.compile(global_ir_value_re_str
, flags
=(re
.M
))
1480 for m
in global_ir_value_re
.finditer(raw_tool_output
):
1481 lines
.append(m
.group(0))
1483 for prefix
in prefixes
:
1484 if glob_val_dict
[prefix
] is None:
1486 if nameless_value
.check_prefix
in glob_val_dict
[prefix
]:
1487 if lines
== glob_val_dict
[prefix
][nameless_value
.check_prefix
]:
1489 if prefix
== prefixes
[-1]:
1490 warn("Found conflicting asm under the same prefix: %r!" % (prefix
,))
1492 glob_val_dict
[prefix
][nameless_value
.check_prefix
] = None
1494 glob_val_dict
[prefix
][nameless_value
.check_prefix
] = lines
1497 def add_global_checks(
1502 global_vars_seen_dict
,
1504 is_before_functions
,
1506 printed_prefixes
= set()
1507 for nameless_value
in ir_nameless_values
:
1508 if nameless_value
.global_ir_rhs_regexp
is None:
1510 if nameless_value
.is_before_functions
!= is_before_functions
:
1512 for p
in prefix_list
:
1513 global_vars_seen
= {}
1514 checkprefixes
= p
[0]
1515 if checkprefixes
is None:
1517 for checkprefix
in checkprefixes
:
1518 if checkprefix
in global_vars_seen_dict
:
1519 global_vars_seen
.update(global_vars_seen_dict
[checkprefix
])
1521 global_vars_seen_dict
[checkprefix
] = {}
1522 if (checkprefix
, nameless_value
.check_prefix
) in printed_prefixes
:
1524 if not glob_val_dict
[checkprefix
]:
1526 if nameless_value
.check_prefix
not in glob_val_dict
[checkprefix
]:
1528 if not glob_val_dict
[checkprefix
][nameless_value
.check_prefix
]:
1532 global_vars_seen_before
= [key
for key
in global_vars_seen
.keys()]
1533 for line
in glob_val_dict
[checkprefix
][nameless_value
.check_prefix
]:
1534 if _global_value_regex
:
1536 for regex
in _global_value_regex
:
1537 if re
.match("^@" + regex
+ " = ", line
):
1542 tmp
= generalize_check_lines(
1543 [line
], is_analyze
, set(), global_vars_seen
1545 check_line
= "%s %s: %s" % (comment_marker
, checkprefix
, tmp
[0])
1546 check_lines
.append(check_line
)
1550 output_lines
.append(comment_marker
+ SEPARATOR
)
1551 for check_line
in check_lines
:
1552 output_lines
.append(check_line
)
1554 printed_prefixes
.add((checkprefix
, nameless_value
.check_prefix
))
1556 # Remembe new global variables we have not seen before
1557 for key
in global_vars_seen
:
1558 if key
not in global_vars_seen_before
:
1559 global_vars_seen_dict
[checkprefix
][key
] = global_vars_seen
[key
]
1562 if printed_prefixes
:
1563 output_lines
.append(comment_marker
+ SEPARATOR
)
1564 return printed_prefixes
1567 def check_prefix(prefix
):
1568 if not PREFIX_RE
.match(prefix
):
1571 hint
= " Did you mean '--check-prefixes=" + prefix
+ "'?"
1574 "Supplied prefix '%s' is invalid. Prefix must contain only alphanumeric characters, hyphens and underscores."
1581 def get_check_prefixes(filecheck_cmd
):
1584 for m
in CHECK_PREFIX_RE
.finditer(filecheck_cmd
)
1585 for item
in m
.group(1).split(",")
1587 if not check_prefixes
:
1588 check_prefixes
= ["CHECK"]
1589 return check_prefixes
1592 def verify_filecheck_prefixes(fc_cmd
):
1593 fc_cmd_parts
= fc_cmd
.split()
1594 for part
in fc_cmd_parts
:
1595 if "check-prefix=" in part
:
1596 prefix
= part
.split("=", 1)[1]
1597 check_prefix(prefix
)
1598 elif "check-prefixes=" in part
:
1599 prefixes
= part
.split("=", 1)[1].split(",")
1600 for prefix
in prefixes
:
1601 check_prefix(prefix
)
1602 if prefixes
.count(prefix
) > 1:
1604 "Supplied prefix '%s' is not unique in the prefix list."
1609 def get_autogennote_suffix(parser
, args
):
1610 autogenerated_note_args
= ""
1611 for action
in parser
._actions
:
1612 if not hasattr(args
, action
.dest
):
1613 continue # Ignore options such as --help that aren't included in args
1614 # Ignore parameters such as paths to the binary or the list of tests
1628 value
= getattr(args
, action
.dest
)
1629 if action
.const
is not None: # action stores a constant (usually True/False)
1630 # Skip actions with different constant values (this happens with boolean
1631 # --foo/--no-foo options)
1632 if value
!= action
.const
:
1634 if parser
.get_default(action
.dest
) == value
:
1635 continue # Don't add default values
1636 if action
.dest
== "function_signature" and args
.version
>= 2:
1637 continue # Enabled by default in version 2
1638 if action
.dest
== "filters":
1639 # Create a separate option for each filter element. The value is a list
1640 # of Filter objects.
1642 opt_name
= "filter-out" if elem
.is_filter_out
else "filter"
1643 opt_value
= elem
.pattern()
1644 new_arg
= '--%s "%s" ' % (opt_name
, opt_value
.strip('"'))
1645 if new_arg
not in autogenerated_note_args
:
1646 autogenerated_note_args
+= new_arg
1648 autogenerated_note_args
+= action
.option_strings
[0] + " "
1649 if action
.const
is None: # action takes a parameter
1650 if action
.nargs
== "+":
1651 value
= " ".join(map(lambda v
: '"' + v
.strip('"') + '"', value
))
1652 autogenerated_note_args
+= "%s " % value
1653 if autogenerated_note_args
:
1654 autogenerated_note_args
= " %s %s" % (
1656 autogenerated_note_args
[:-1],
1658 return autogenerated_note_args
1661 def check_for_command(line
, parser
, args
, argv
, argparse_callback
):
1662 cmd_m
= UTC_ARGS_CMD
.match(line
)
1664 for option
in shlex
.split(cmd_m
.group("cmd").strip()):
1667 args
= parse_args(parser
, filter(lambda arg
: arg
not in args
.tests
, argv
))
1668 if argparse_callback
is not None:
1669 argparse_callback(args
)
1673 def find_arg_in_test(test_info
, get_arg_to_check
, arg_string
, is_global
):
1674 result
= get_arg_to_check(test_info
.args
)
1675 if not result
and is_global
:
1676 # See if this has been specified via UTC_ARGS. This is a "global" option
1677 # that affects the entire generation of test checks. If it exists anywhere
1678 # in the test, apply it to everything.
1680 for line_info
in test_info
.ro_iterlines():
1681 line
= line_info
.line
1682 if not line
.startswith(";") and line
.strip() != "":
1684 result
= get_arg_to_check(line_info
.args
)
1686 if warn
and saw_line
:
1687 # We saw the option after already reading some test input lines.
1690 "WARNING: Found {} in line following test start: ".format(
1697 "WARNING: Consider moving {} to top of file".format(arg_string
),
1704 def dump_input_lines(output_lines
, test_info
, prefix_set
, comment_string
):
1705 for input_line_info
in test_info
.iterlines(output_lines
):
1706 line
= input_line_info
.line
1707 args
= input_line_info
.args
1708 if line
.strip() == comment_string
:
1710 if line
.strip() == comment_string
+ SEPARATOR
:
1712 if line
.lstrip().startswith(comment_string
):
1713 m
= CHECK_RE
.match(line
)
1714 if m
and m
.group(1) in prefix_set
:
1716 output_lines
.append(line
.rstrip("\n"))
1719 def add_checks_at_end(
1720 output_lines
, prefix_list
, func_order
, comment_string
, check_generator
1723 generated_prefixes
= set()
1724 for prefix
in prefix_list
:
1725 prefixes
= prefix
[0]
1726 tool_args
= prefix
[1]
1727 for prefix
in prefixes
:
1728 for func
in func_order
[prefix
]:
1729 # The func order can contain the same functions multiple times.
1730 # If we see one again we are done.
1731 if (func
, prefix
) in added
:
1734 output_lines
.append(comment_string
)
1736 # The add_*_checks routines expect a run list whose items are
1737 # tuples that have a list of prefixes as their first element and
1738 # tool command args string as their second element. They output
1739 # checks for each prefix in the list of prefixes. By doing so, it
1740 # implicitly assumes that for each function every run line will
1741 # generate something for that function. That is not the case for
1742 # generated functions as some run lines might not generate them
1743 # (e.g. -fopenmp vs. no -fopenmp).
1745 # Therefore, pass just the prefix we're interested in. This has
1746 # the effect of generating all of the checks for functions of a
1747 # single prefix before moving on to the next prefix. So checks
1748 # are ordered by prefix instead of by function as in "normal"
1750 for generated_prefix
in check_generator(
1751 output_lines
, [([prefix
], tool_args
)], func
1753 added
.add((func
, generated_prefix
))
1754 generated_prefixes
.add(generated_prefix
)
1755 return generated_prefixes