Skip to content

Commit 4351f10

Browse files
committed
[WIP] Consider datalayout sentinel pointer value for isKnownNonZero check
1 parent 64d4ade commit 4351f10

16 files changed

+10246
-0
lines changed

llvm/lib/Analysis/ValueTracking.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3098,6 +3098,15 @@ bool isKnownNonZero(const Value *V, const APInt &DemandedElts,
30983098
// Check for pointer simplifications.
30993099

31003100
if (PointerType *PtrTy = dyn_cast<PointerType>(Ty)) {
3101+
const DataLayout &DL = Q.DL;
3102+
if (DL.isSentinelValueDefined() && PtrTy) {
3103+
unsigned AddrSpace = PtrTy->getPointerAddressSpace();
3104+
3105+
if (DL.getSentinelPointerValue(AddrSpace) == 0)
3106+
return false;
3107+
return true;
3108+
}
3109+
31013110
// A byval, inalloca may not be null in a non-default addres space. A
31023111
// nonnull argument is assumed never 0.
31033112
if (const Argument *A = dyn_cast<Argument>(V)) {
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
2+
target datalayout = "e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32-p7:160:256:256:32-p8:128:128-p9:192:256:256:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-z0:1-z2:neg1-z3:neg1-z5:neg1-S32-A5-G1-ni:7:8:9"
3+
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
4+
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
5+
;
6+
; FIXME: The GEP + BC + GEP solution we create is not great but correct.
7+
8+
declare void @use(ptr nocapture readonly %arg)
9+
10+
define void @caller() {
11+
; TUNIT-LABEL: define {{[^@]+}}@caller() {
12+
; TUNIT-NEXT: entry:
13+
; TUNIT-NEXT: [[LEFT:%.*]] = alloca [3 x i32], align 4
14+
; TUNIT-NEXT: [[TMP0:%.*]] = load i32, ptr [[LEFT]], align 4
15+
; TUNIT-NEXT: [[LEFT_B4:%.*]] = getelementptr i8, ptr [[LEFT]], i64 4
16+
; TUNIT-NEXT: [[TMP1:%.*]] = load i32, ptr [[LEFT_B4]], align 4
17+
; TUNIT-NEXT: [[LEFT_B8:%.*]] = getelementptr i8, ptr [[LEFT]], i64 8
18+
; TUNIT-NEXT: [[TMP2:%.*]] = load i32, ptr [[LEFT_B8]], align 4
19+
; TUNIT-NEXT: call void @callee(i32 [[TMP0]], i32 [[TMP1]], i32 [[TMP2]])
20+
; TUNIT-NEXT: ret void
21+
;
22+
; CGSCC-LABEL: define {{[^@]+}}@caller() {
23+
; CGSCC-NEXT: entry:
24+
; CGSCC-NEXT: call void @callee(i32 undef, i32 undef, i32 undef)
25+
; CGSCC-NEXT: ret void
26+
;
27+
entry:
28+
%left = alloca [3 x i32], align 4
29+
call void @callee(ptr %left)
30+
ret void
31+
}
32+
33+
define internal void @callee(ptr noalias %arg) {
34+
; CHECK: Function Attrs: memory(readwrite, argmem: none)
35+
; CHECK-LABEL: define {{[^@]+}}@callee
36+
; CHECK-SAME: (i32 [[TMP0:%.*]], i32 [[TMP1:%.*]], i32 [[TMP2:%.*]]) #[[ATTR0:[0-9]+]] {
37+
; CHECK-NEXT: entry:
38+
; CHECK-NEXT: [[ARG_PRIV:%.*]] = alloca [3 x i32], align 4, addrspace(5)
39+
; CHECK-NEXT: store i32 [[TMP0]], ptr addrspace(5) [[ARG_PRIV]], align 4
40+
; CHECK-NEXT: [[ARG_PRIV_B4:%.*]] = getelementptr i8, ptr addrspace(5) [[ARG_PRIV]], i64 4
41+
; CHECK-NEXT: store i32 [[TMP1]], ptr addrspace(5) [[ARG_PRIV_B4]], align 4
42+
; CHECK-NEXT: [[ARG_PRIV_B8:%.*]] = getelementptr i8, ptr addrspace(5) [[ARG_PRIV]], i64 8
43+
; CHECK-NEXT: store i32 [[TMP2]], ptr addrspace(5) [[ARG_PRIV_B8]], align 4
44+
; CHECK-NEXT: [[TMP3:%.*]] = addrspacecast ptr addrspace(5) [[ARG_PRIV]] to ptr
45+
; CHECK-NEXT: call void @use(ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(12) [[TMP3]])
46+
; CHECK-NEXT: ret void
47+
;
48+
entry:
49+
call void @use(ptr %arg)
50+
ret void
51+
}
52+
;.
53+
; TUNIT: attributes #[[ATTR0]] = { memory(readwrite, argmem: none) }
54+
;.
55+
; CGSCC: attributes #[[ATTR0]] = { memory(readwrite, argmem: none) }
56+
;.
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
2+
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
3+
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
4+
;
5+
; #include <pthread.h>
6+
;
7+
; ptr GlobalVPtr;
8+
;
9+
; static ptr foo(ptr arg) { return arg; }
10+
; static ptr bar(ptr arg) { return arg; }
11+
;
12+
; int main() {
13+
; pthread_t thread;
14+
; pthread_create(&thread, NULL, foo, NULL);
15+
; pthread_create(&thread, NULL, bar, &GlobalVPtr);
16+
; return 0;
17+
; }
18+
;
19+
; Verify the constant values NULL and &GlobalVPtr are propagated into foo and
20+
; bar, respectively.
21+
;
22+
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-z0:1-z2:neg1-z3:neg1-z5:neg1-S128"
23+
24+
%union.pthread_attr_t = type { i64, [48 x i8] }
25+
26+
@GlobalVPtr = common dso_local global ptr null, align 8
27+
28+
; FIXME: nocapture & noalias for @GlobalVPtr in %call1
29+
; FIXME: nocapture & noalias for %alloc2 in %call3
30+
31+
;.
32+
; CHECK: @GlobalVPtr = common dso_local global ptr null, align 8
33+
;.
34+
define dso_local i32 @main() {
35+
; TUNIT-LABEL: define {{[^@]+}}@main() {
36+
; TUNIT-NEXT: entry:
37+
; TUNIT-NEXT: [[ALLOC11:%.*]] = alloca i8, i32 0, align 8
38+
; TUNIT-NEXT: [[ALLOC22:%.*]] = alloca i8, i32 0, align 8
39+
; TUNIT-NEXT: [[THREAD:%.*]] = alloca i64, align 8
40+
; 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)
41+
; 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)
42+
; 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) [[ALLOC11]])
43+
; 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" [[ALLOC22]])
44+
; TUNIT-NEXT: ret i32 0
45+
;
46+
; CGSCC-LABEL: define {{[^@]+}}@main() {
47+
; CGSCC-NEXT: entry:
48+
; CGSCC-NEXT: [[ALLOC1:%.*]] = alloca i8, align 8
49+
; CGSCC-NEXT: [[ALLOC2:%.*]] = alloca i8, align 8
50+
; CGSCC-NEXT: [[THREAD:%.*]] = alloca i64, align 8
51+
; CGSCC-NEXT: unreachable
52+
;
53+
entry:
54+
%alloc1 = alloca i8, align 8
55+
%alloc2 = alloca i8, align 8
56+
%thread = alloca i64, align 8
57+
%call = call i32 @pthread_create(ptr nonnull %thread, ptr null, ptr nonnull @foo, ptr null)
58+
%call1 = call i32 @pthread_create(ptr nonnull %thread, ptr null, ptr nonnull @bar, ptr @GlobalVPtr)
59+
%call2 = call i32 @pthread_create(ptr nonnull %thread, ptr null, ptr nonnull @baz, ptr nocapture %alloc1)
60+
%call3 = call i32 @pthread_create(ptr nonnull %thread, ptr null, ptr nonnull @buz, ptr %alloc2)
61+
ret i32 0
62+
}
63+
64+
declare !callback !0 dso_local i32 @pthread_create(ptr, ptr, ptr, ptr)
65+
66+
define internal ptr @foo(ptr %arg) {
67+
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
68+
; CHECK-LABEL: define {{[^@]+}}@foo
69+
; CHECK-SAME: (ptr noalias nocapture nofree nonnull readnone align 4294967296 [[ARG:%.*]]) #[[ATTR0:[0-9]+]] {
70+
; CHECK-NEXT: entry:
71+
; CHECK-NEXT: unreachable
72+
;
73+
entry:
74+
ret ptr %arg
75+
}
76+
77+
define internal ptr @bar(ptr %arg) {
78+
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
79+
; CHECK-LABEL: define {{[^@]+}}@bar
80+
; CHECK-SAME: (ptr noalias nocapture nofree nonnull readnone align 8 dereferenceable(8) [[ARG:%.*]]) #[[ATTR0]] {
81+
; CHECK-NEXT: entry:
82+
; CHECK-NEXT: ret ptr @GlobalVPtr
83+
;
84+
entry:
85+
ret ptr %arg
86+
}
87+
88+
define internal ptr @baz(ptr %arg) {
89+
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
90+
; CHECK-LABEL: define {{[^@]+}}@baz
91+
; CHECK-SAME: (ptr noalias nofree noundef nonnull readnone returned align 8 dereferenceable(1) "no-capture-maybe-returned" [[ARG:%.*]]) #[[ATTR0]] {
92+
; CHECK-NEXT: entry:
93+
; CHECK-NEXT: ret ptr [[ARG]]
94+
;
95+
entry:
96+
ret ptr %arg
97+
}
98+
99+
define internal ptr @buz(ptr %arg) {
100+
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
101+
; CHECK-LABEL: define {{[^@]+}}@buz
102+
; CHECK-SAME: (ptr noalias nofree noundef nonnull readnone returned align 8 dereferenceable(1) "no-capture-maybe-returned" [[ARG:%.*]]) #[[ATTR0]] {
103+
; CHECK-NEXT: entry:
104+
; CHECK-NEXT: ret ptr [[ARG]]
105+
;
106+
entry:
107+
ret ptr %arg
108+
}
109+
110+
!1 = !{i64 2, i64 3, i1 false}
111+
!0 = !{!1}
112+
;.
113+
; TUNIT: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
114+
;.
115+
; CGSCC: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
116+
;.
117+
; TUNIT: [[META0:![0-9]+]] = !{[[META1:![0-9]+]]}
118+
; TUNIT: [[META1]] = !{i64 2, i64 3, i1 false}
119+
;.
120+
; CGSCC: [[META0:![0-9]+]] = !{[[META1:![0-9]+]]}
121+
; CGSCC: [[META1]] = !{i64 2, i64 3, i1 false}
122+
;.

0 commit comments

Comments
 (0)