diff --git a/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/check_attrs.ll.funcattrs.expected b/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/check_attrs.ll.funcattrs.expected --- a/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/check_attrs.ll.funcattrs.expected +++ b/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/check_attrs.ll.funcattrs.expected @@ -26,3 +26,5 @@ %arrayidx = getelementptr inbounds %struct.ST, %struct.ST* %s, i64 1, i32 2, i32 1, i64 5, i64 13 ret i32* %arrayidx } +; IS__TUNIT____: attributes [[ATTR0]] = { nofree nosync nounwind optsize readnone ssp uwtable willreturn } +; IS__CGSCC____: attributes [[ATTR0]] = { nofree norecurse nosync nounwind optsize readnone ssp uwtable willreturn } diff --git a/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/check_attrs.ll.plain.expected b/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/check_attrs.ll.plain.expected --- a/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/check_attrs.ll.plain.expected +++ b/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/check_attrs.ll.plain.expected @@ -18,3 +18,5 @@ %arrayidx = getelementptr inbounds %struct.ST, %struct.ST* %s, i64 1, i32 2, i32 1, i64 5, i64 13 ret i32* %arrayidx } +; IS__TUNIT____: attributes [[ATTR0]] = { nofree nosync nounwind optsize readnone ssp uwtable willreturn } +; IS__CGSCC____: attributes [[ATTR0]] = { nofree norecurse nosync nounwind optsize readnone ssp uwtable willreturn } diff --git a/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/on_the_fly_arg_change.ll.expected b/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/on_the_fly_arg_change.ll.expected --- a/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/on_the_fly_arg_change.ll.expected +++ b/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/on_the_fly_arg_change.ll.expected @@ -43,3 +43,4 @@ ; ret i32 %arg } +; CHECK: attributes [[ATTR0:#.*]] = { readnone } diff --git a/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/on_the_fly_arg_change.ll.initially_disabled.expected b/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/on_the_fly_arg_change.ll.initially_disabled.expected --- a/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/on_the_fly_arg_change.ll.initially_disabled.expected +++ b/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/on_the_fly_arg_change.ll.initially_disabled.expected @@ -40,3 +40,4 @@ ; ret i32 %arg } +; CHECK: attributes [[ATTR0:#.*]] = { readnone } diff --git a/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/scrub_attrs.ll.plain.expected b/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/scrub_attrs.ll.plain.expected --- a/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/scrub_attrs.ll.plain.expected +++ b/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/scrub_attrs.ll.plain.expected @@ -11,3 +11,4 @@ call void @foo() readnone ret void } +; CHECK: attributes [[ATTR0]] = { readnone } diff --git a/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/scrub_attrs.ll.scrub.expected b/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/scrub_attrs.ll.scrub.expected --- a/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/scrub_attrs.ll.scrub.expected +++ b/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/scrub_attrs.ll.scrub.expected @@ -11,3 +11,4 @@ call void @foo() readnone ret void } +; CHECK: attributes [[ATTR0:#.*]] = { readnone } diff --git a/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/various_ir_values.ll.expected b/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/various_ir_values.ll.expected --- a/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/various_ir_values.ll.expected +++ b/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/various_ir_values.ll.expected @@ -244,3 +244,7 @@ !58 = distinct !{!58, !52, !59} !59 = !DILocation(line: 10, column: 12, scope: !43) !60 = !DILocation(line: 11, column: 1, scope: !39) +; CHECK: attributes [[ATTR0:#.*]] = { nounwind uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "denormal-fp-math"="ieee,ieee" "denormal-fp-math-f32"="ieee,ieee" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +; CHECK: attributes [[ATTR1:#.*]] = { nounwind readnone speculatable willreturn } +; CHECK: attributes [[ATTR2:#.*]] = { argmemonly nounwind willreturn } +; CHECK: attributes [[ATTR3]] = { nounwind } diff --git a/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/various_ir_values.ll.funcsig.expected b/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/various_ir_values.ll.funcsig.expected --- a/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/various_ir_values.ll.funcsig.expected +++ b/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/various_ir_values.ll.funcsig.expected @@ -246,3 +246,7 @@ !58 = distinct !{!58, !52, !59} !59 = !DILocation(line: 10, column: 12, scope: !43) !60 = !DILocation(line: 11, column: 1, scope: !39) +; CHECK: attributes [[ATTR0]] = { nounwind uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "denormal-fp-math"="ieee,ieee" "denormal-fp-math-f32"="ieee,ieee" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +; CHECK: attributes [[ATTR1:#.*]] = { nounwind readnone speculatable willreturn } +; CHECK: attributes [[ATTR2:#.*]] = { argmemonly nounwind willreturn } +; CHECK: attributes [[ATTR3]] = { nounwind } diff --git a/llvm/utils/UpdateTestChecks/common.py b/llvm/utils/UpdateTestChecks/common.py --- a/llvm/utils/UpdateTestChecks/common.py +++ b/llvm/utils/UpdateTestChecks/common.py @@ -104,9 +104,9 @@ comment_prefix, argparse_callback) -def should_add_line_to_output(input_line, prefix_set): +def should_add_line_to_output(input_line, prefix_set, skip_global_checks = False): # Skip any blank comment lines in the IR. - if input_line.strip() == ';': + if not skip_global_checks and input_line.strip() == ';': return False # Skip any blank lines in the IR. #if input_line.strip() == '': @@ -114,6 +114,13 @@ # And skip any CHECK lines. We're building our own. m = CHECK_RE.match(input_line) if m and m.group(1) in prefix_set: + if(skip_global_checks): + for nameless_value in nameless_values: + if not nameless_value.global_ir_prefix: + continue + if re.compile(nameless_value.global_ir_prefix).search(input_line): + return False + return True return False return True @@ -229,10 +236,14 @@ def is_same_except_arg_names(self, extrascrub, args_and_sig, attrs): arg_names = set() def drop_arg_names(match): - arg_names.add(match.group(3)) - return match.group(1) + match.group(match.lastindex) + arg_names.add(match.group(variable_group_in_ir_value_match)) + if match.group(attribute_group_in_ir_value_match): + attr = match.group(attribute_group_in_ir_value_match) + else: + attr = '' + return match.group(1) + attr + match.group(match.lastindex) def repl_arg_names(match): - if match.group(3) is not None and match.group(3) in arg_names: + if match.group(variable_group_in_ir_value_match) is not None and match.group(variable_group_in_ir_value_match) in arg_names: return match.group(1) + match.group(match.lastindex) return match.group(1) + match.group(2) + match.group(match.lastindex) if self.attrs != attrs: @@ -283,6 +294,7 @@ if func_dict[prefix][func] and func_dict[prefix][func].is_same_except_arg_names(scrubbed_extra, args_and_sig, attrs): func_dict[prefix][func].scrub = scrubbed_extra func_dict[prefix][func].args_and_sig = args_and_sig + func_dict[prefix][func].attrs = attrs continue else: if prefix == prefixes[-1]: @@ -300,22 +312,25 @@ # TODO: We should also derive check lines for global, debug, loop declarations, etc.. class NamelessValue: - def __init__(self, check_prefix, ir_prefix, ir_regexp): + def __init__(self, check_prefix, ir_prefix, global_ir_prefix, global_ir_prefix_regexp, ir_regexp, global_ir_regexp): self.check_prefix = check_prefix self.ir_prefix = ir_prefix + self.global_ir_prefix = global_ir_prefix + self.global_ir_prefix_regexp = global_ir_prefix_regexp self.ir_regexp = ir_regexp + self.global_ir_regexp = global_ir_regexp # Description of the different "unnamed" values we match in the IR, e.g., # (local) ssa values, (debug) metadata, etc. nameless_values = [ - NamelessValue(r'TMP', r'%', r'[\w.-]+?'), - NamelessValue(r'GLOB', r'@', r'[0-9]+?'), - NamelessValue(r'ATTR', r'#', r'[0-9]+?'), - NamelessValue(r'DBG', r'!dbg !', r'[0-9]+?'), - NamelessValue(r'TBAA', r'!tbaa !', r'[0-9]+?'), - NamelessValue(r'RNG', r'!range !', r'[0-9]+?'), - NamelessValue(r'LOOP', r'!llvm.loop !', r'[0-9]+?'), - NamelessValue(r'META', r'metadata !', r'[0-9]+?'), + NamelessValue(r'TMP', r'%', r'', r'', r'[\w.-]+?', r''), + NamelessValue(r'ATTR', r'#', r'attributes', r'\s\#', r'[0-9]+?', r'{[^}]*}'), + NamelessValue(r'GLOB', r'@', r'', r'', r'[0-9]+?', r''), + NamelessValue(r'DBG', r'!dbg !', r'', r'', r'[0-9]+?', r''), + NamelessValue(r'TBAA', r'!tbaa !', r'', r'', r'[0-9]+?', r''), + NamelessValue(r'RNG', r'!range !', r'', r'', r'[0-9]+?', r''), + NamelessValue(r'LOOP', r'!llvm.loop !', r'', r'', r'[0-9]+?', r''), + NamelessValue(r'META', r'metadata !', r'', r'', r'[0-9]+?', r''), ] # Build the regexp that matches an "IR value". This can be a local variable, @@ -327,7 +342,7 @@ for nameless_value in nameless_values: if IR_VALUE_REGEXP_STRING: IR_VALUE_REGEXP_STRING += '|' - IR_VALUE_REGEXP_STRING += nameless_value.ir_prefix + r'(' + nameless_value.ir_regexp + r')' + IR_VALUE_REGEXP_STRING += nameless_value.ir_prefix + r'(' + nameless_value.ir_regexp + '|' + nameless_value.global_ir_prefix_regexp + r')' IR_VALUE_REGEXP_SUFFIX = r'([,\s\(\)]|\Z)' IR_VALUE_RE = re.compile(IR_VALUE_REGEXP_PREFIX + r'(' + IR_VALUE_REGEXP_STRING + r')' + IR_VALUE_REGEXP_SUFFIX) @@ -335,6 +350,10 @@ # IR_VALUE_REGEXP_STRING is one group (=2), and then the nameless values start. first_nameless_group_in_ir_value_match = 3 +# constants for the group id of special matches +variable_group_in_ir_value_match = 3 +attribute_group_in_ir_value_match = 4 + # Check a match for IR_VALUE_RE and inspect it to determine if it was a local # value, %..., global @..., debug number !dbg !..., etc. See the PREFIXES above. def get_idx_from_ir_value_match(match): @@ -536,6 +555,58 @@ add_checks(output_lines, comment_marker, prefix_list, func_dict, func_name, check_label_format, False, True, global_vars_seen_dict) +def build_global_values_dictionary(glob_val_dict, raw_tool_output, prefixes): + for nameless_value in nameless_values: + if not nameless_value.global_ir_prefix: + continue + + lhs_re_str = nameless_value.global_ir_prefix + nameless_value.global_ir_prefix_regexp + nameless_value.ir_regexp + rhs_re_str = nameless_value.global_ir_regexp + + global_ir_value_re_str = r'^' + lhs_re_str + r'\s=\s' + rhs_re_str + r'$' + global_ir_value_re = re.compile(global_ir_value_re_str, flags=(re.M)) + lines = [] + for m in global_ir_value_re.finditer(raw_tool_output): + lines.append(m.group(0)) + + for prefix in prefixes: + if glob_val_dict[prefix] is None: + continue + if nameless_value.check_prefix in glob_val_dict[prefix]: + if lines == glob_val_dict[prefix][nameless_value.check_prefix]: + continue + if prefix == prefixes[-1]: + warn('Found conflicting asm under the same prefix: %r!' % (prefix,)) + else: + glob_val_dict[prefix][nameless_value.check_prefix] = None + continue + glob_val_dict[prefix][nameless_value.check_prefix] = lines + +def add_global_checks(glob_val_dict, comment_marker, prefix_list, output_lines, global_vars_seen_dict, is_analyze): + for nameless_value in nameless_values: + printed_prefixes = set() + for p in prefix_list: + global_vars_seen = set() + checkprefixes = p[0] + for checkprefix in checkprefixes: + if checkprefix in global_vars_seen_dict: + global_vars_seen = global_vars_seen.union(global_vars_seen_dict[checkprefix]) + if checkprefix in printed_prefixes: + break + if not glob_val_dict[checkprefix]: + continue + if nameless_value.check_prefix not in glob_val_dict[checkprefix]: + continue + if not glob_val_dict[checkprefix][nameless_value.check_prefix]: + continue + + for line in glob_val_dict[checkprefix][nameless_value.check_prefix]: + tmp = generalize_check_lines([line], is_analyze, set(), global_vars_seen) + check_line = '%s %s: %s' % (comment_marker, checkprefix, tmp[0]) + output_lines.append(check_line) + printed_prefixes.add(checkprefix) + break + def check_prefix(prefix): if not PREFIX_RE.match(prefix): diff --git a/llvm/utils/update_test_checks.py b/llvm/utils/update_test_checks.py --- a/llvm/utils/update_test_checks.py +++ b/llvm/utils/update_test_checks.py @@ -103,9 +103,11 @@ global_vars_seen_dict = {} func_dict = {} + glob_val_dict = {} for prefixes, _ in prefix_list: for prefix in prefixes: func_dict.update({prefix: dict()}) + glob_val_dict.update({prefix: dict()}) for prefixes, opt_args in prefix_list: common.debug('Extracted opt cmd: ' + opt_basename + ' ' + opt_args) common.debug('Extracted FileCheck prefixes: ' + str(prefixes)) @@ -116,6 +118,8 @@ raw_tool_output, prefixes, func_dict, ti.args.verbose, ti.args.function_signature, ti.args.check_attributes) + common.build_global_values_dictionary(glob_val_dict, raw_tool_output, prefixes) + is_in_function = False is_in_function_start = False prefix_set = set([prefix for prefixes, _ in prefix_list for prefix in prefixes]) @@ -139,21 +143,19 @@ global_vars_seen_dict) is_in_function_start = False + # Skip all CHECK lines. + if common.should_add_line_to_output(input_line, prefix_set, not is_in_function): + # This input line of the function body will go as-is into the output. + # Except make leading whitespace uniform: 2 spaces. + input_line = common.SCRUB_LEADING_WHITESPACE_RE.sub(r' ', input_line) + output_lines.append(input_line) + else: + continue if is_in_function: - if common.should_add_line_to_output(input_line, prefix_set): - # This input line of the function body will go as-is into the output. - # Except make leading whitespace uniform: 2 spaces. - input_line = common.SCRUB_LEADING_WHITESPACE_RE.sub(r' ', input_line) - output_lines.append(input_line) - else: - continue if input_line.strip() == '}': is_in_function = False continue - # If it's outside a function, it just gets copied to the output. - output_lines.append(input_line) - m = common.IR_FUNCTION_RE.match(input_line) if not m: continue @@ -163,6 +165,7 @@ continue is_in_function = is_in_function_start = True + common.add_global_checks(glob_val_dict, ';', prefix_list, output_lines, global_vars_seen_dict, args.preserve_names) common.debug('Writing %d lines to %s...' % (len(output_lines), ti.path)) with open(ti.path, 'wb') as f: