forked from OSchip/llvm-project
[Utils] Check function attributes in update_test_checks
Summary: This introduces new flag to the update_test_checks and update_cc_test_checks that allows for function attributes to be checked in a check-line. If the flag is not set, the behavior should remain the same. Reviewers: jdoerfert Subscribers: arichardson, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D83629
This commit is contained in:
parent
f7a571537a
commit
937bad3594
|
@ -0,0 +1,15 @@
|
|||
// RUN: %clang_cc1 -triple=x86_64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s
|
||||
struct RT {
|
||||
char A;
|
||||
int B[10][20];
|
||||
char C;
|
||||
};
|
||||
struct ST {
|
||||
int X;
|
||||
double Y;
|
||||
struct RT Z;
|
||||
};
|
||||
|
||||
int *foo(struct ST *s) {
|
||||
return &s[1].Z.B[5][13];
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --check-attributes
|
||||
// RUN: %clang_cc1 -triple=x86_64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s
|
||||
struct RT {
|
||||
char A;
|
||||
int B[10][20];
|
||||
char C;
|
||||
};
|
||||
struct ST {
|
||||
int X;
|
||||
double Y;
|
||||
struct RT Z;
|
||||
};
|
||||
|
||||
// CHECK: Function Attrs: noinline nounwind optnone;
|
||||
// CHECK-LABEL: @_Z3fooP2ST(
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: [[S_ADDR:%.*]] = alloca %struct.ST*, align 8
|
||||
// CHECK-NEXT: store %struct.ST* [[S:%.*]], %struct.ST** [[S_ADDR]], align 8
|
||||
// CHECK-NEXT: [[TMP0:%.*]] = load %struct.ST*, %struct.ST** [[S_ADDR]], align 8
|
||||
// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [[STRUCT_ST:%.*]], %struct.ST* [[TMP0]], i64 1
|
||||
// CHECK-NEXT: [[Z:%.*]] = getelementptr inbounds [[STRUCT_ST]], %struct.ST* [[ARRAYIDX]], i32 0, i32 2
|
||||
// CHECK-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_RT:%.*]], %struct.RT* [[Z]], i32 0, i32 1
|
||||
// CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds [10 x [20 x i32]], [10 x [20 x i32]]* [[B]], i64 0, i64 5
|
||||
// CHECK-NEXT: [[ARRAYIDX2:%.*]] = getelementptr inbounds [20 x i32], [20 x i32]* [[ARRAYIDX1]], i64 0, i64 13
|
||||
// CHECK-NEXT: ret i32* [[ARRAYIDX2]]
|
||||
//
|
||||
int *foo(struct ST *s) {
|
||||
return &s[1].Z.B[5][13];
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
|
||||
// RUN: %clang_cc1 -triple=x86_64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s
|
||||
struct RT {
|
||||
char A;
|
||||
int B[10][20];
|
||||
char C;
|
||||
};
|
||||
struct ST {
|
||||
int X;
|
||||
double Y;
|
||||
struct RT Z;
|
||||
};
|
||||
|
||||
// CHECK-LABEL: @_Z3fooP2ST(
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: [[S_ADDR:%.*]] = alloca %struct.ST*, align 8
|
||||
// CHECK-NEXT: store %struct.ST* [[S:%.*]], %struct.ST** [[S_ADDR]], align 8
|
||||
// CHECK-NEXT: [[TMP0:%.*]] = load %struct.ST*, %struct.ST** [[S_ADDR]], align 8
|
||||
// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [[STRUCT_ST:%.*]], %struct.ST* [[TMP0]], i64 1
|
||||
// CHECK-NEXT: [[Z:%.*]] = getelementptr inbounds [[STRUCT_ST]], %struct.ST* [[ARRAYIDX]], i32 0, i32 2
|
||||
// CHECK-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_RT:%.*]], %struct.RT* [[Z]], i32 0, i32 1
|
||||
// CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds [10 x [20 x i32]], [10 x [20 x i32]]* [[B]], i64 0, i64 5
|
||||
// CHECK-NEXT: [[ARRAYIDX2:%.*]] = getelementptr inbounds [20 x i32], [20 x i32]* [[ARRAYIDX1]], i64 0, i64 13
|
||||
// CHECK-NEXT: ret i32* [[ARRAYIDX2]]
|
||||
//
|
||||
int *foo(struct ST *s) {
|
||||
return &s[1].Z.B[5][13];
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
## Test that CHECK lines are generated as expected without --check-attributes
|
||||
# RUN: cp %S/Inputs/check-attributes.cpp %t.cpp && %update_cc_test_checks %t.cpp
|
||||
# RUN: diff -u %S/Inputs/check-attributes.cpp.plain.expected %t.cpp
|
||||
## Test with --check-attributes flag.
|
||||
# RUN: cp %S/Inputs/check-attributes.cpp %t.cpp && %update_cc_test_checks %t.cpp --check-attributes
|
||||
# RUN: diff -u %S/Inputs/check-attributes.cpp.funcattrs.expected %t.cpp
|
||||
## Check that re-running update_cc_test_checks doesn't change the output
|
||||
# RUN: %update_cc_test_checks %t.cpp
|
||||
# RUN: diff -u %S/Inputs/check-attributes.cpp.funcattrs.expected %t.cpp
|
|
@ -0,0 +1,13 @@
|
|||
; RUN: opt -attributor -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
|
||||
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
|
||||
; RUN: opt -attributor-cgscc -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
|
||||
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
|
||||
|
||||
%struct.RT = type { i8, [10 x [20 x i32]], i8 }
|
||||
%struct.ST = type { i32, double, %struct.RT }
|
||||
|
||||
define i32* @foo(%struct.ST* %s) nounwind uwtable readnone optsize ssp {
|
||||
entry:
|
||||
%arrayidx = getelementptr inbounds %struct.ST, %struct.ST* %s, i64 1, i32 2, i32 1, i64 5, i64 13
|
||||
ret i32* %arrayidx
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes
|
||||
; RUN: opt -attributor -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
|
||||
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
|
||||
; RUN: opt -attributor-cgscc -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
|
||||
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
|
||||
|
||||
%struct.RT = type { i8, [10 x [20 x i32]], i8 }
|
||||
%struct.ST = type { i32, double, %struct.RT }
|
||||
|
||||
define i32* @foo(%struct.ST* %s) nounwind uwtable readnone optsize ssp {
|
||||
; IS__TUNIT____: Function Attrs: nofree nosync nounwind optsize readnone ssp uwtable willreturn;
|
||||
; IS__TUNIT____-LABEL: define {{[^@]+}}@foo
|
||||
; IS__TUNIT____-SAME: (%struct.ST* nofree readnone [[S:%.*]]) #0
|
||||
; IS__TUNIT____-NEXT: entry:
|
||||
; IS__TUNIT____-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [[STRUCT_ST:%.*]], %struct.ST* [[S]], i64 1, i32 2, i32 1, i64 5, i64 13
|
||||
; IS__TUNIT____-NEXT: ret i32* [[ARRAYIDX]]
|
||||
;
|
||||
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind optsize readnone ssp uwtable willreturn;
|
||||
; IS__CGSCC____-LABEL: define {{[^@]+}}@foo
|
||||
; IS__CGSCC____-SAME: (%struct.ST* nofree readnone [[S:%.*]]) #0
|
||||
; IS__CGSCC____-NEXT: entry:
|
||||
; IS__CGSCC____-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [[STRUCT_ST:%.*]], %struct.ST* [[S]], i64 1, i32 2, i32 1, i64 5, i64 13
|
||||
; IS__CGSCC____-NEXT: ret i32* [[ARRAYIDX]]
|
||||
;
|
||||
entry:
|
||||
%arrayidx = getelementptr inbounds %struct.ST, %struct.ST* %s, i64 1, i32 2, i32 1, i64 5, i64 13
|
||||
ret i32* %arrayidx
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature
|
||||
; RUN: opt -attributor -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
|
||||
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
|
||||
; RUN: opt -attributor-cgscc -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
|
||||
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
|
||||
|
||||
%struct.RT = type { i8, [10 x [20 x i32]], i8 }
|
||||
%struct.ST = type { i32, double, %struct.RT }
|
||||
|
||||
define i32* @foo(%struct.ST* %s) nounwind uwtable readnone optsize ssp {
|
||||
; CHECK-LABEL: define {{[^@]+}}@foo
|
||||
; CHECK-SAME: (%struct.ST* nofree readnone [[S:%.*]]) #0
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [[STRUCT_ST:%.*]], %struct.ST* [[S]], i64 1, i32 2, i32 1, i64 5, i64 13
|
||||
; CHECK-NEXT: ret i32* [[ARRAYIDX]]
|
||||
;
|
||||
entry:
|
||||
%arrayidx = getelementptr inbounds %struct.ST, %struct.ST* %s, i64 1, i32 2, i32 1, i64 5, i64 13
|
||||
ret i32* %arrayidx
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
## check_attrs test checking that update_test_checks.py works correctly
|
||||
# RUN: cp -f %S/Inputs/check_attrs.ll %t.ll && %update_test_checks %t.ll --function-signature
|
||||
# RUN: diff -u %t.ll %S/Inputs/check_attrs.ll.plain.expected
|
||||
## Also try the --check-attributes flag
|
||||
# RUN: %update_test_checks %t.ll --check-attributes --function-signature
|
||||
# RUN: diff -u %t.ll %S/Inputs/check_attrs.ll.funcattrs.expected
|
||||
## Check that running the script again does not change the result:
|
||||
# RUN: %update_test_checks %t.ll
|
||||
# RUN: diff -u %t.ll %S/Inputs/check_attrs.ll.funcattrs.expected
|
|
@ -364,7 +364,7 @@ def build_function_body_dictionary_for_triple(args, raw_tool_output, triple, pre
|
|||
scrubber, function_re = handler
|
||||
common.build_function_body_dictionary(
|
||||
function_re, scrubber, [args], raw_tool_output, prefixes,
|
||||
func_dict, args.verbose, False)
|
||||
func_dict, args.verbose, False, False)
|
||||
|
||||
##### Generator of assembly CHECK lines
|
||||
|
||||
|
|
|
@ -142,7 +142,7 @@ UTC_ARGS_CMD = re.compile(r'.*' + UTC_ARGS_KEY + '\s*(?P<cmd>.*)\s*$')
|
|||
UTC_ADVERT = 'NOTE: Assertions have been autogenerated by '
|
||||
|
||||
OPT_FUNCTION_RE = re.compile(
|
||||
r'^\s*define\s+(?:internal\s+)?[^@]*@(?P<func>[\w.-]+?)\s*'
|
||||
r'^(\s*;\s*Function\sAttrs:\s(?P<attrs>[\w\s]+?))?\s*define\s+(?:internal\s+)?[^@]*@(?P<func>[\w.-]+?)\s*'
|
||||
r'(?P<args_and_sig>\((\)|(.*?[\w.-]+?)\))[^{]*)\{\n(?P<body>.*?)^\}$',
|
||||
flags=(re.M | re.S))
|
||||
|
||||
|
@ -218,11 +218,12 @@ def do_scrub(body, scrubber, scrubber_args, extra):
|
|||
|
||||
# Build up a dictionary of all the function bodies.
|
||||
class function_body(object):
|
||||
def __init__(self, string, extra, args_and_sig):
|
||||
def __init__(self, string, extra, args_and_sig, attrs):
|
||||
self.scrub = string
|
||||
self.extrascrub = extra
|
||||
self.args_and_sig = args_and_sig
|
||||
def is_same_except_arg_names(self, extrascrub, args_and_sig):
|
||||
self.attrs = attrs
|
||||
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(2))
|
||||
|
@ -231,6 +232,8 @@ class function_body(object):
|
|||
if match.group(2) in arg_names:
|
||||
return match.group(1) + match.group(3)
|
||||
return match.group(1) + match.group(2) + match.group(3)
|
||||
if self.attrs != attrs:
|
||||
return False
|
||||
ans0 = IR_VALUE_RE.sub(drop_arg_names, self.args_and_sig)
|
||||
ans1 = IR_VALUE_RE.sub(drop_arg_names, args_and_sig)
|
||||
if ans0 != ans1:
|
||||
|
@ -244,12 +247,13 @@ class function_body(object):
|
|||
def __str__(self):
|
||||
return self.scrub
|
||||
|
||||
def build_function_body_dictionary(function_re, scrubber, scrubber_args, raw_tool_output, prefixes, func_dict, verbose, record_args):
|
||||
def build_function_body_dictionary(function_re, scrubber, scrubber_args, raw_tool_output, prefixes, func_dict, verbose, record_args, check_attributes):
|
||||
for m in function_re.finditer(raw_tool_output):
|
||||
if not m:
|
||||
continue
|
||||
func = m.group('func')
|
||||
body = m.group('body')
|
||||
attrs = m.group('attrs') if check_attributes else ''
|
||||
# Determine if we print arguments, the opening brace, or nothing after the function name
|
||||
if record_args and 'args_and_sig' in m.groupdict():
|
||||
args_and_sig = scrub_body(m.group('args_and_sig').strip())
|
||||
|
@ -271,19 +275,20 @@ def build_function_body_dictionary(function_re, scrubber, scrubber_args, raw_too
|
|||
for l in scrubbed_body.splitlines():
|
||||
print(' ' + l, file=sys.stderr)
|
||||
for prefix in prefixes:
|
||||
if func in func_dict[prefix] and (str(func_dict[prefix][func]) != scrubbed_body or (func_dict[prefix][func] and func_dict[prefix][func].args_and_sig != args_and_sig)):
|
||||
if func_dict[prefix][func] and func_dict[prefix][func].is_same_except_arg_names(scrubbed_extra, args_and_sig):
|
||||
func_dict[prefix][func].scrub = scrubbed_extra
|
||||
func_dict[prefix][func].args_and_sig = args_and_sig
|
||||
continue
|
||||
else:
|
||||
if prefix == prefixes[-1]:
|
||||
warn('Found conflicting asm under the same prefix: %r!' % (prefix,))
|
||||
else:
|
||||
func_dict[prefix][func] = None
|
||||
if func in func_dict[prefix]:
|
||||
if str(func_dict[prefix][func]) != scrubbed_body or (func_dict[prefix][func] and (func_dict[prefix][func].args_and_sig != args_and_sig or func_dict[prefix][func].attrs != attrs)):
|
||||
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
|
||||
continue
|
||||
else:
|
||||
if prefix == prefixes[-1]:
|
||||
warn('Found conflicting asm under the same prefix: %r!' % (prefix,))
|
||||
else:
|
||||
func_dict[prefix][func] = None
|
||||
continue
|
||||
|
||||
func_dict[prefix][func] = function_body(scrubbed_body, scrubbed_extra, args_and_sig)
|
||||
func_dict[prefix][func] = function_body(scrubbed_body, scrubbed_extra, args_and_sig, attrs)
|
||||
|
||||
##### Generator of LLVM IR CHECK lines
|
||||
|
||||
|
@ -383,6 +388,10 @@ def add_checks(output_lines, comment_marker, prefix_list, func_dict, func_name,
|
|||
|
||||
vars_seen = set()
|
||||
printed_prefixes.append(checkprefix)
|
||||
attrs = str(func_dict[checkprefix][func_name].attrs)
|
||||
attrs = '' if attrs == 'None' else attrs
|
||||
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)
|
||||
args_and_sig = genericize_check_lines([args_and_sig], is_analyze, vars_seen)[0]
|
||||
if '[[' in args_and_sig:
|
||||
|
|
|
@ -122,7 +122,7 @@ def main():
|
|||
for raw_tool_output in re.split(r'Printing analysis ', raw_tool_outputs):
|
||||
common.build_function_body_dictionary(
|
||||
common.ANALYZE_FUNCTION_RE, common.scrub_body, [],
|
||||
raw_tool_output, prefixes, func_dict, args.verbose, False)
|
||||
raw_tool_output, prefixes, func_dict, args.verbose, False, False)
|
||||
|
||||
is_in_function = False
|
||||
is_in_function_start = False
|
||||
|
|
|
@ -131,6 +131,8 @@ def config():
|
|||
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('--check-attributes', action='store_true',
|
||||
help='Check "Function Attributes" for functions')
|
||||
parser.add_argument('tests', nargs='+')
|
||||
args = common.parse_commandline_args(parser)
|
||||
|
||||
|
@ -189,7 +191,7 @@ def get_function_body(args, filename, clang_args, extra_commands, prefixes, trip
|
|||
if '-emit-llvm' in clang_args:
|
||||
common.build_function_body_dictionary(
|
||||
common.OPT_FUNCTION_RE, common.scrub_body, [],
|
||||
raw_tool_output, prefixes, func_dict, args.verbose, args.function_signature)
|
||||
raw_tool_output, prefixes, func_dict, args.verbose, args.function_signature, args.check_attributes)
|
||||
else:
|
||||
print('The clang command line should include -emit-llvm as asm tests '
|
||||
'are discouraged in Clang testsuite.', file=sys.stderr)
|
||||
|
|
|
@ -52,6 +52,8 @@ def main():
|
|||
help='Keep function signature information around for the check line')
|
||||
parser.add_argument('--scrub-attributes', action='store_true',
|
||||
help='Remove attribute annotations (#0) from the end of check line')
|
||||
parser.add_argument('--check-attributes', action='store_true',
|
||||
help='Check "Function Attributes" for functions')
|
||||
parser.add_argument('tests', nargs='+')
|
||||
initial_args = common.parse_commandline_args(parser)
|
||||
|
||||
|
@ -111,7 +113,7 @@ def main():
|
|||
common.build_function_body_dictionary(
|
||||
common.OPT_FUNCTION_RE, common.scrub_body, [],
|
||||
raw_tool_output, prefixes, func_dict, ti.args.verbose,
|
||||
ti.args.function_signature)
|
||||
ti.args.function_signature, ti.args.check_attributes)
|
||||
|
||||
is_in_function = False
|
||||
is_in_function_start = False
|
||||
|
|
Loading…
Reference in New Issue