Index: clang/test/utils/update_cc_test_checks/Inputs/mangled_names.c.fullfuncsig.expected =================================================================== --- /dev/null +++ clang/test/utils/update_cc_test_checks/Inputs/mangled_names.c.fullfuncsig.expected @@ -0,0 +1,43 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --function-signature --full-function-signature +// Example input for update_cc_test_checks +// RUN: %clang_cc1 -no-opaque-pointers -triple=x86_64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s + +// CHECK-LABEL: define dso_local i64 @test +// CHECK-SAME: (i64 noundef [[A:%.*]], i32 noundef [[B:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i64, align 8 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store i64 [[A]], i64* [[A_ADDR]], align 8 +// CHECK-NEXT: store i32 [[B]], i32* [[B_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load i64, i64* [[A_ADDR]], align 8 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* [[B_ADDR]], align 4 +// CHECK-NEXT: [[CONV:%.*]] = sext i32 [[TMP1]] to i64 +// CHECK-NEXT: [[ADD:%.*]] = add nsw i64 [[TMP0]], [[CONV]] +// CHECK-NEXT: ret i64 [[ADD]] +// +long test(long a, int b) { + return a + b; +} + +// A function with a mangled name +// CHECK-LABEL: define dso_local i64 @_Z4testlii +// CHECK-SAME: (i64 noundef [[A:%.*]], i32 noundef [[B:%.*]], i32 noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i64, align 8 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[C_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store i64 [[A]], i64* [[A_ADDR]], align 8 +// CHECK-NEXT: store i32 [[B]], i32* [[B_ADDR]], align 4 +// CHECK-NEXT: store i32 [[C]], i32* [[C_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load i64, i64* [[A_ADDR]], align 8 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* [[B_ADDR]], align 4 +// CHECK-NEXT: [[CONV:%.*]] = sext i32 [[TMP1]] to i64 +// CHECK-NEXT: [[ADD:%.*]] = add nsw i64 [[TMP0]], [[CONV]] +// CHECK-NEXT: [[TMP2:%.*]] = load i32, i32* [[C_ADDR]], align 4 +// CHECK-NEXT: [[CONV1:%.*]] = sext i32 [[TMP2]] to i64 +// CHECK-NEXT: [[ADD2:%.*]] = add nsw i64 [[ADD]], [[CONV1]] +// CHECK-NEXT: ret i64 [[ADD2]] +// +__attribute__((overloadable)) long test(long a, int b, int c) { + return a + b + c; +} Index: clang/test/utils/update_cc_test_checks/mangled_names.test =================================================================== --- clang/test/utils/update_cc_test_checks/mangled_names.test +++ clang/test/utils/update_cc_test_checks/mangled_names.test @@ -16,3 +16,6 @@ # RUN: grep -v UTC_ARGS %t.c > %t-no-args.c # RUN: %update_cc_test_checks %t-no-args.c # RUN: diff -u %t-no-args.c %S/Inputs/mangled_names.c.expected +## Also try the --full-function-signature flag +# RUN: %update_cc_test_checks %t.c --full-function-signature +# RUN: diff -u %t.c %S/Inputs/mangled_names.c.fullfuncsig.expected Index: llvm/utils/UpdateTestChecks/asm.py =================================================================== --- llvm/utils/UpdateTestChecks/asm.py +++ llvm/utils/UpdateTestChecks/asm.py @@ -534,7 +534,7 @@ def add_checks(output_lines, comment_marker, prefix_list, func_dict, func_name, global_vars_seen_dict, is_filtered): # Label format is based on ASM string. - check_label_format = '{} %s-LABEL: %s%s%s'.format(comment_marker) + check_label_format = '{} %s-LABEL: %s%s%s%s'.format(comment_marker) return common.add_checks(output_lines, comment_marker, prefix_list, func_dict, - func_name, check_label_format, True, False, + func_name, check_label_format, True, False, False, global_vars_seen_dict, is_filtered=is_filtered) Index: llvm/utils/UpdateTestChecks/common.py =================================================================== --- llvm/utils/UpdateTestChecks/common.py +++ llvm/utils/UpdateTestChecks/common.py @@ -329,7 +329,7 @@ UNUSED_NOTE = 'NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:' OPT_FUNCTION_RE = re.compile( - r'^(\s*;\s*Function\sAttrs:\s(?P[\w\s():,]+?))?\s*define\s+(?:internal\s+)?[^@]*@(?P[\w.$-]+?)\s*' + r'^(\s*;\s*Function\sAttrs:\s(?P[\w\s():,]+?))?\s*define\s+(?P[^@]*)@(?P[\w.$-]+?)\s*' r'(?P\((\)|(.*?[\w.-]+?)\))[^{]*\{)\n(?P.*?)^\}$', flags=(re.M | re.S)) @@ -442,13 +442,14 @@ # Build up a dictionary of all the function bodies. class function_body(object): - def __init__(self, string, extra, args_and_sig, attrs, func_name_separator): + def __init__(self, string, extra, funcdef_attrs_and_ret, args_and_sig, attrs, func_name_separator): self.scrub = string self.extrascrub = extra + self.funcdef_attrs_and_ret = funcdef_attrs_and_ret self.args_and_sig = args_and_sig self.attrs = attrs self.func_name_separator = func_name_separator - def is_same_except_arg_names(self, extrascrub, args_and_sig, attrs, is_backend): + def is_same_except_arg_names(self, extrascrub, funcdef_attrs_and_ret, args_and_sig, attrs, is_backend): arg_names = set() def drop_arg_names(match): arg_names.add(match.group(variable_group_in_ir_value_match)) @@ -461,6 +462,8 @@ 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.funcdef_attrs_and_ret != funcdef_attrs_and_ret: + return False if self.attrs != attrs: return False ans0 = IR_VALUE_RE.sub(drop_arg_names, self.args_and_sig) @@ -536,6 +539,7 @@ else: func_name_separator = '' attrs = m.group('attrs') if self._check_attributes else '' + funcdef_attrs_and_ret = m.group('funcdef_attrs_and_ret') if self._record_args else '' # Determine if we print arguments, the opening brace, or nothing after the # function name if self._record_args and 'args_and_sig' in m.groupdict(): @@ -590,9 +594,11 @@ if (self._func_dict[prefix][func] is not None and (str(self._func_dict[prefix][func]) != scrubbed_body or self._func_dict[prefix][func].args_and_sig != args_and_sig or - self._func_dict[prefix][func].attrs != attrs)): + self._func_dict[prefix][func].attrs != attrs or + self._func_dict[prefix][func].funcdef_attrs_and_ret != funcdef_attrs_and_ret)): if self._func_dict[prefix][func].is_same_except_arg_names( scrubbed_extra, + funcdef_attrs_and_ret, args_and_sig, attrs, is_backend): @@ -607,8 +613,8 @@ else: if prefix not in self._processed_prefixes: self._func_dict[prefix][func] = function_body( - scrubbed_body, scrubbed_extra, args_and_sig, attrs, - func_name_separator) + scrubbed_body, scrubbed_extra, funcdef_attrs_and_ret, + args_and_sig, attrs, func_name_separator) self._func_order[prefix].append(func) else: # An earlier RUN line used this check prefixes but didn't produce @@ -893,7 +899,7 @@ global_vars_seen, asm_nameless_values, ASM_VALUE_RE, True) -def add_checks(output_lines, comment_marker, prefix_list, func_dict, func_name, check_label_format, is_backend, is_analyze, global_vars_seen_dict, is_filtered): +def add_checks(output_lines, comment_marker, prefix_list, func_dict, func_name, check_label_format, is_backend, is_analyze, check_funcdef_attrs_and_ret, global_vars_seen_dict, is_filtered): # 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. prefix_exclusions = set() printed_prefixes = [] @@ -941,6 +947,11 @@ printed_prefixes.append(checkprefix) attrs = str(func_dict[checkprefix][func_name].attrs) attrs = '' if attrs == 'None' else attrs + if check_funcdef_attrs_and_ret: + funcdef_attrs_and_ret = '' + func_dict[checkprefix][func_name].funcdef_attrs_and_ret + else: + funcdef_attrs_and_ret = '' + if attrs: output_lines.append('%s %s: Function Attrs: %s' % (comment_marker, checkprefix, attrs)) args_and_sig = str(func_dict[checkprefix][func_name].args_and_sig) @@ -948,10 +959,10 @@ args_and_sig = generalize_check_lines([args_and_sig], is_analyze, vars_seen, global_vars_seen)[0] func_name_separator = func_dict[checkprefix][func_name].func_name_separator if '[[' in args_and_sig: - output_lines.append(check_label_format % (checkprefix, func_name, '', func_name_separator)) + output_lines.append(check_label_format % (checkprefix, funcdef_attrs_and_ret, func_name, '', func_name_separator)) output_lines.append('%s %s-SAME: %s' % (comment_marker, checkprefix, args_and_sig)) else: - output_lines.append(check_label_format % (checkprefix, func_name, args_and_sig, func_name_separator)) + output_lines.append(check_label_format % (checkprefix, funcdef_attrs_and_ret, func_name, args_and_sig, func_name_separator)) func_body = str(func_dict[checkprefix][func_name]).splitlines() if not func_body: # We have filtered everything. @@ -1027,20 +1038,28 @@ return printed_prefixes def add_ir_checks(output_lines, comment_marker, prefix_list, func_dict, - func_name, preserve_names, function_sig, + func_name, preserve_names, function_sig, full_function_sig, global_vars_seen_dict, is_filtered): + function_sig = function_sig or full_function_sig # Label format is based on IR string. - function_def_regex = 'define {{[^@]+}}' if function_sig else '' + if full_function_sig: + function_def_regex = 'define %s' + elif function_sig: + function_def_regex = 'define %s{{[^@]+}}' + else: + function_def_regex = '%s' + check_label_format = '{} %s-LABEL: {}@%s%s%s'.format(comment_marker, function_def_regex) return add_checks(output_lines, comment_marker, prefix_list, func_dict, func_name, - check_label_format, False, preserve_names, global_vars_seen_dict, + check_label_format, False, preserve_names, + full_function_sig, global_vars_seen_dict, is_filtered) def add_analyze_checks(output_lines, comment_marker, prefix_list, func_dict, func_name, is_filtered): - check_label_format = '{} %s-LABEL: \'%s%s%s\''.format(comment_marker) + check_label_format = '{} %s-LABEL: \'%s%s%s%s\''.format(comment_marker) global_vars_seen_dict = {} return add_checks(output_lines, comment_marker, prefix_list, func_dict, func_name, - check_label_format, False, True, global_vars_seen_dict, + check_label_format, False, True, False, global_vars_seen_dict, is_filtered) def build_global_values_dictionary(glob_val_dict, raw_tool_output, prefixes): Index: llvm/utils/UpdateTestChecks/isel.py =================================================================== --- llvm/utils/UpdateTestChecks/isel.py +++ llvm/utils/UpdateTestChecks/isel.py @@ -51,7 +51,7 @@ def add_checks(output_lines, comment_marker, prefix_list, func_dict, func_name, global_vars_seen_dict, is_filtered): # Label format is based on iSel string. - check_label_format = '{} %s-LABEL: %s%s%s'.format(comment_marker) + check_label_format = '{} %s-LABEL: %s%s%s%s'.format(comment_marker) return common.add_checks(output_lines, comment_marker, prefix_list, func_dict, func_name, check_label_format, True, False, - global_vars_seen_dict, is_filtered=is_filtered) + False, global_vars_seen_dict, is_filtered=is_filtered) Index: llvm/utils/update_cc_test_checks.py =================================================================== --- llvm/utils/update_cc_test_checks.py +++ llvm/utils/update_cc_test_checks.py @@ -138,6 +138,8 @@ args.opt = 'opt' else: args.opt = os.path.join(args.llvm_bin, 'opt') + if args.full_function_signature and not args.function_signature: + args.function_signature = True def find_executable(executable): @@ -167,6 +169,8 @@ help='Use more regex for x86 matching to reduce diffs between various subtargets') parser.add_argument('--function-signature', action='store_true', help='Keep function signature information around for the check line') + parser.add_argument('--full-function-signature', action='store_true', + help='Keep function signature information (including return type) around for the check line') parser.add_argument('--check-attributes', action='store_true', help='Check "Function Attributes" for functions') parser.add_argument('--check-globals', action='store_true', @@ -353,6 +357,7 @@ prefixes, func_dict, func, False, ti.args.function_signature, + ti.args.full_function_signature, global_vars_seen_dict, is_filtered=builder.is_filtered()) else: @@ -420,6 +425,7 @@ mangled, False, args.function_signature, + args.full_function_signature, global_vars_seen_dict, is_filtered=builder.is_filtered())) if line.rstrip('\n') == '//': Index: llvm/utils/update_test_checks.py =================================================================== --- llvm/utils/update_test_checks.py +++ llvm/utils/update_test_checks.py @@ -181,6 +181,7 @@ func, False, args.function_signature, + False, global_vars_seen_dict, is_filtered=builder.is_filtered()))) else: @@ -207,6 +208,7 @@ func_name, args.preserve_names, args.function_signature, + False, global_vars_seen_dict, is_filtered=builder.is_filtered())) is_in_function_start = False