Instead of visiting call sites in Attribute::checkForAllUses, we now keep track of returns in AAPointerInfo and use the call site return information as required. This way, the user of AAPointerInfo(CallSite)Argument can determine if the call return should be visited. We do not collect them as "may accesses" in the AAPointerInfo(CallSite)Argument itself in case a return user is found.
127 lines
6.3 KiB
LLVM
127 lines
6.3 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
|
|
; 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
|
|
;
|
|
; #include <pthread.h>
|
|
;
|
|
; ptr GlobalVPtr;
|
|
;
|
|
; static ptr foo(ptr arg) { return arg; }
|
|
; static ptr bar(ptr arg) { return arg; }
|
|
;
|
|
; int main() {
|
|
; pthread_t thread;
|
|
; pthread_create(&thread, NULL, foo, NULL);
|
|
; pthread_create(&thread, NULL, bar, &GlobalVPtr);
|
|
; return 0;
|
|
; }
|
|
;
|
|
; Verify the constant values NULL and &GlobalVPtr are propagated into foo and
|
|
; bar, respectively.
|
|
;
|
|
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
|
|
|
%union.pthread_attr_t = type { i64, [48 x i8] }
|
|
|
|
@GlobalVPtr = common dso_local global ptr null, align 8
|
|
|
|
; FIXME: nocapture & noalias for @GlobalVPtr in %call1
|
|
; FIXME: nocapture & noalias for %alloc2 in %call3
|
|
|
|
;.
|
|
; CHECK: @GlobalVPtr = common dso_local global ptr null, align 8
|
|
;.
|
|
define dso_local i32 @main() {
|
|
; TUNIT-LABEL: define {{[^@]+}}@main() {
|
|
; TUNIT-NEXT: entry:
|
|
; TUNIT-NEXT: [[ALLOC1:%.*]] = alloca i8, align 8
|
|
; TUNIT-NEXT: [[ALLOC2:%.*]] = alloca i8, align 8
|
|
; TUNIT-NEXT: [[THREAD:%.*]] = alloca i64, align 8
|
|
; TUNIT-NEXT: [[CALL:%.*]] = call i32 @pthread_create(ptr noundef nonnull align 8 dereferenceable(8) [[THREAD]], ptr noundef align 4294967296 null, ptr noundef nonnull @foo, ptr nofree readnone align 4294967296 undef)
|
|
; TUNIT-NEXT: [[CALL1:%.*]] = call i32 @pthread_create(ptr noundef nonnull align 8 dereferenceable(8) [[THREAD]], ptr noundef align 4294967296 null, ptr noundef nonnull @bar, ptr noalias nocapture nofree nonnull readnone align 8 dereferenceable(8) undef)
|
|
; TUNIT-NEXT: [[CALL2:%.*]] = call i32 @pthread_create(ptr noundef nonnull align 8 dereferenceable(8) [[THREAD]], ptr noundef align 4294967296 null, ptr noundef nonnull @baz, ptr noalias nocapture nofree noundef nonnull readnone align 8 dereferenceable(1) [[ALLOC1]])
|
|
; TUNIT-NEXT: [[CALL3:%.*]] = call i32 @pthread_create(ptr noundef nonnull align 8 dereferenceable(8) [[THREAD]], ptr noundef align 4294967296 null, ptr noundef nonnull @buz, ptr noalias nofree noundef nonnull readnone align 8 dereferenceable(1) "no-capture-maybe-returned" [[ALLOC2]])
|
|
; TUNIT-NEXT: ret i32 0
|
|
;
|
|
; CGSCC-LABEL: define {{[^@]+}}@main() {
|
|
; CGSCC-NEXT: entry:
|
|
; CGSCC-NEXT: [[ALLOC1:%.*]] = alloca i8, align 8
|
|
; CGSCC-NEXT: [[ALLOC2:%.*]] = alloca i8, align 8
|
|
; CGSCC-NEXT: [[THREAD:%.*]] = alloca i64, align 8
|
|
; CGSCC-NEXT: [[CALL:%.*]] = call i32 @pthread_create(ptr noundef nonnull align 8 dereferenceable(8) [[THREAD]], ptr noundef align 4294967296 null, ptr noundef nonnull @foo, ptr nofree noundef readnone align 4294967296 null)
|
|
; CGSCC-NEXT: [[CALL1:%.*]] = call i32 @pthread_create(ptr noundef nonnull align 8 dereferenceable(8) [[THREAD]], ptr noundef align 4294967296 null, ptr noundef nonnull @bar, ptr noalias nocapture nofree noundef nonnull readnone align 8 dereferenceable(8) @GlobalVPtr)
|
|
; CGSCC-NEXT: [[CALL2:%.*]] = call i32 @pthread_create(ptr noundef nonnull align 8 dereferenceable(8) [[THREAD]], ptr noundef align 4294967296 null, ptr noundef nonnull @baz, ptr noalias nocapture nofree noundef nonnull readnone align 8 dereferenceable(1) [[ALLOC1]])
|
|
; CGSCC-NEXT: [[CALL3:%.*]] = call i32 @pthread_create(ptr noundef nonnull align 8 dereferenceable(8) [[THREAD]], ptr noundef align 4294967296 null, ptr noundef nonnull @buz, ptr noalias nofree noundef nonnull readnone align 8 dereferenceable(1) [[ALLOC2]])
|
|
; CGSCC-NEXT: ret i32 0
|
|
;
|
|
entry:
|
|
%alloc1 = alloca i8, align 8
|
|
%alloc2 = alloca i8, align 8
|
|
%thread = alloca i64, align 8
|
|
%call = call i32 @pthread_create(ptr nonnull %thread, ptr null, ptr nonnull @foo, ptr null)
|
|
%call1 = call i32 @pthread_create(ptr nonnull %thread, ptr null, ptr nonnull @bar, ptr @GlobalVPtr)
|
|
%call2 = call i32 @pthread_create(ptr nonnull %thread, ptr null, ptr nonnull @baz, ptr nocapture %alloc1)
|
|
%call3 = call i32 @pthread_create(ptr nonnull %thread, ptr null, ptr nonnull @buz, ptr %alloc2)
|
|
ret i32 0
|
|
}
|
|
|
|
declare !callback !0 dso_local i32 @pthread_create(ptr, ptr, ptr, ptr)
|
|
|
|
define internal ptr @foo(ptr %arg) {
|
|
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
|
|
; CHECK-LABEL: define {{[^@]+}}@foo
|
|
; CHECK-SAME: (ptr noalias nocapture nofree readnone align 4294967296 [[ARG:%.*]]) #[[ATTR0:[0-9]+]] {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: ret ptr null
|
|
;
|
|
entry:
|
|
ret ptr %arg
|
|
}
|
|
|
|
define internal ptr @bar(ptr %arg) {
|
|
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
|
|
; CHECK-LABEL: define {{[^@]+}}@bar
|
|
; CHECK-SAME: (ptr noalias nocapture nofree nonnull readnone align 8 dereferenceable(8) [[ARG:%.*]]) #[[ATTR0]] {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: ret ptr @GlobalVPtr
|
|
;
|
|
entry:
|
|
ret ptr %arg
|
|
}
|
|
|
|
define internal ptr @baz(ptr %arg) {
|
|
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
|
|
; CHECK-LABEL: define {{[^@]+}}@baz
|
|
; CHECK-SAME: (ptr noalias nofree noundef nonnull readnone returned align 8 dereferenceable(1) "no-capture-maybe-returned" [[ARG:%.*]]) #[[ATTR0]] {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: ret ptr [[ARG]]
|
|
;
|
|
entry:
|
|
ret ptr %arg
|
|
}
|
|
|
|
define internal ptr @buz(ptr %arg) {
|
|
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
|
|
; CHECK-LABEL: define {{[^@]+}}@buz
|
|
; CHECK-SAME: (ptr noalias nofree noundef nonnull readnone returned align 8 dereferenceable(1) "no-capture-maybe-returned" [[ARG:%.*]]) #[[ATTR0]] {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: ret ptr [[ARG]]
|
|
;
|
|
entry:
|
|
ret ptr %arg
|
|
}
|
|
|
|
!1 = !{i64 2, i64 3, i1 false}
|
|
!0 = !{!1}
|
|
;.
|
|
; TUNIT: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
|
|
;.
|
|
; CGSCC: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
|
|
;.
|
|
; TUNIT: [[META0:![0-9]+]] = !{[[META1:![0-9]+]]}
|
|
; TUNIT: [[META1]] = !{i64 2, i64 3, i1 false}
|
|
;.
|
|
; CGSCC: [[META0:![0-9]+]] = !{[[META1:![0-9]+]]}
|
|
; CGSCC: [[META1]] = !{i64 2, i64 3, i1 false}
|
|
;.
|