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 @@ -300,22 +307,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'GLOB', r'@', r'', r'', r'[0-9]+?', r''), + NamelessValue(r'ATTR', r'#', r'attributes', r'\s\#', r'[0-9]+?', r'{([\w\s])*(\"(.+?)\"=\"(.+?)\"\s)?}'), + 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 +337,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) @@ -532,10 +542,83 @@ def add_analyze_checks(output_lines, comment_marker, prefix_list, func_dict, func_name): check_label_format = '{} %s-LABEL: \'%s%s\''.format(comment_marker) - global_vars_see_dict = {} + global_vars_seen_dict = {} 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 + lhs_re = re.compile(lhs_re_str) + rhs_re = re.compile(rhs_re_str) + + 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)) + for m in global_ir_value_re.finditer(raw_tool_output): + line = m.group(0) + for prefix in prefixes: + if glob_val_dict[prefix] is None: + continue + if nameless_value.check_prefix not in glob_val_dict[prefix]: + glob_val_dict[prefix][nameless_value.check_prefix] = [] + + found = False + for l in glob_val_dict[prefix][nameless_value.check_prefix]: + # If LHSs are different (eg. attributes #0 and attributes #1) + # then we are looking at different line. + if lhs_re.match(line).group(0) != lhs_re.match(l).group(0): + continue + # If LHSs are the same and RHSs are same as well (eg { nounwind } and { nounwind }) + # then we are looking at the same line. + if rhs_re.search(line).group(0) == rhs_re.search(l).group(0): + found = True + break + # Found conflicting lines + if prefix == prefixes[-1]: + warn('Found conflicting asm under the same prefix: %r!' % (prefix,)) + else: + found = True + glob_val_dict[prefix] = None + break + if not found: + glob_val_dict[prefix][nameless_value.check_prefix].append(line) + +def add_global_checks(glob_val_dict, comment_marker, prefix_list, output_lines, global_vars_seen_dict, is_analyze): + printed_prefixes = set() + for p in prefix_list: + checkprefixes = p[0] + for checkprefix in checkprefixes: + if checkprefix in printed_prefixes: + break + + if glob_val_dict[checkprefix] is None: + continue + + if checkprefix not in global_vars_seen_dict: + global_vars_seen_dict[checkprefix] = set() + global_vars_seen = global_vars_seen_dict[checkprefix] + + for nameless_value in nameless_values: + if nameless_value.check_prefix not in glob_val_dict[checkprefix]: + continue + for line in glob_val_dict[checkprefix][nameless_value.check_prefix]: + # don't print identical lines + printed = False + for pp in printed_prefixes: + if pp != checkprefix and line in glob_val_dict[pp][nameless_value.check_prefix]: + printed = True + break + + if printed: + continue + tmp = genericize_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) 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: