| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 | |
| ; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT | |
| ; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC | |
| ; Check that nocapture introduction respects null_pointer_is_valid | |
| @g = global ptr null | |
| define void @capture(ptr %p) { | |
| ; CHECK-LABEL: define void @capture( | |
| ; CHECK-SAME: ptr nofree writeonly [[P:%.*]]) #[[ATTR0:[0-9]+]] { | |
| ; CHECK-NEXT: store ptr [[P]], ptr @g, align 8 | |
| ; CHECK-NEXT: ret void | |
| ; | |
| store ptr %p, ptr @g | |
| ret void | |
| } | |
| define i8 @nocapture(ptr %p) { | |
| ; CHECK-LABEL: define i8 @nocapture( | |
| ; CHECK-SAME: ptr nofree noundef nonnull readonly captures(none) dereferenceable(1) [[P:%.*]]) #[[ATTR1:[0-9]+]] { | |
| ; CHECK-NEXT: [[V:%.*]] = load i8, ptr [[P]], align 1 | |
| ; CHECK-NEXT: ret i8 [[V]] | |
| ; | |
| %v = load i8, ptr %p | |
| ret i8 %v | |
| } | |
| define i8 @null_arg_null_pointer_is_valid() null_pointer_is_valid { | |
| ; TUNIT-LABEL: define i8 @null_arg_null_pointer_is_valid( | |
| ; TUNIT-SAME: ) #[[ATTR2:[0-9]+]] { | |
| ; TUNIT-NEXT: call void @capture(ptr noalias nofree noundef writeonly null) #[[ATTR6:[0-9]+]] | |
| ; TUNIT-NEXT: [[V:%.*]] = call i8 @nocapture(ptr noalias nofree noundef readonly captures(none) null) #[[ATTR7:[0-9]+]] | |
| ; TUNIT-NEXT: ret i8 [[V]] | |
| ; | |
| ; CGSCC-LABEL: define i8 @null_arg_null_pointer_is_valid( | |
| ; CGSCC-SAME: ) #[[ATTR2:[0-9]+]] { | |
| ; CGSCC-NEXT: call void @capture(ptr noalias nofree noundef writeonly null) #[[ATTR6:[0-9]+]] | |
| ; CGSCC-NEXT: unreachable | |
| ; | |
| call void @capture(ptr null) | |
| %v = call i8 @nocapture(ptr null) | |
| ret i8 %v | |
| } | |
| define void @capture_null_pointer_is_valid(ptr %p) null_pointer_is_valid { | |
| ; CHECK-LABEL: define void @capture_null_pointer_is_valid( | |
| ; CHECK-SAME: ptr nofree writeonly [[P:%.*]]) #[[ATTR3:[0-9]+]] { | |
| ; CHECK-NEXT: store ptr [[P]], ptr @g, align 8 | |
| ; CHECK-NEXT: ret void | |
| ; | |
| store ptr %p, ptr @g | |
| ret void | |
| } | |
| define i8 @nocapture_null_pointer_is_valid(ptr %p) null_pointer_is_valid { | |
| ; CHECK-LABEL: define i8 @nocapture_null_pointer_is_valid( | |
| ; CHECK-SAME: ptr nofree noundef readonly captures(none) dereferenceable_or_null(1) [[P:%.*]]) #[[ATTR4:[0-9]+]] { | |
| ; CHECK-NEXT: [[V:%.*]] = load i8, ptr [[P]], align 1 | |
| ; CHECK-NEXT: ret i8 [[V]] | |
| ; | |
| %v = load i8, ptr %p | |
| ret i8 %v | |
| } | |
| define i8 @null_arg_callee_null_pointer_is_valid() { | |
| ; TUNIT-LABEL: define i8 @null_arg_callee_null_pointer_is_valid( | |
| ; TUNIT-SAME: ) #[[ATTR5:[0-9]+]] { | |
| ; TUNIT-NEXT: call void @capture_null_pointer_is_valid(ptr nofree noundef writeonly null) #[[ATTR6]] | |
| ; TUNIT-NEXT: [[V:%.*]] = call i8 @nocapture_null_pointer_is_valid(ptr nofree noundef readonly null) #[[ATTR7]] | |
| ; TUNIT-NEXT: ret i8 [[V]] | |
| ; | |
| ; CGSCC-LABEL: define i8 @null_arg_callee_null_pointer_is_valid( | |
| ; CGSCC-SAME: ) #[[ATTR5:[0-9]+]] { | |
| ; CGSCC-NEXT: call void @capture_null_pointer_is_valid(ptr nofree noundef writeonly null) #[[ATTR6]] | |
| ; CGSCC-NEXT: [[V:%.*]] = call i8 @nocapture_null_pointer_is_valid(ptr nofree noundef readonly dereferenceable_or_null(1) null) #[[ATTR7:[0-9]+]] | |
| ; CGSCC-NEXT: ret i8 [[V]] | |
| ; | |
| call void @capture_null_pointer_is_valid(ptr null) | |
| %v = call i8 @nocapture_null_pointer_is_valid(ptr null) | |
| ret i8 %v | |
| } | |
| define i8 @null_arg_null_pointer_is_valid_callee_null_pointer_is_valid() null_pointer_is_valid { | |
| ; TUNIT-LABEL: define i8 @null_arg_null_pointer_is_valid_callee_null_pointer_is_valid( | |
| ; TUNIT-SAME: ) #[[ATTR2]] { | |
| ; TUNIT-NEXT: call void @capture_null_pointer_is_valid(ptr noalias nofree noundef writeonly null) #[[ATTR6]] | |
| ; TUNIT-NEXT: [[V:%.*]] = call i8 @nocapture_null_pointer_is_valid(ptr noalias nofree noundef readonly captures(none) null) #[[ATTR7]] | |
| ; TUNIT-NEXT: ret i8 [[V]] | |
| ; | |
| ; CGSCC-LABEL: define i8 @null_arg_null_pointer_is_valid_callee_null_pointer_is_valid( | |
| ; CGSCC-SAME: ) #[[ATTR2]] { | |
| ; CGSCC-NEXT: call void @capture_null_pointer_is_valid(ptr noalias nofree noundef writeonly null) #[[ATTR6]] | |
| ; CGSCC-NEXT: [[V:%.*]] = call i8 @nocapture_null_pointer_is_valid(ptr noalias nofree noundef readonly captures(none) dereferenceable_or_null(1) null) #[[ATTR7]] | |
| ; CGSCC-NEXT: ret i8 [[V]] | |
| ; | |
| call void @capture_null_pointer_is_valid(ptr null) | |
| %v = call i8 @nocapture_null_pointer_is_valid(ptr null) | |
| ret i8 %v | |
| } |