1; RUN: opt -S -functionattrs -enable-nonnull-arg-prop %s | FileCheck %s 2; RUN: opt -S -passes=function-attrs -enable-nonnull-arg-prop %s | FileCheck %s 3 4declare nonnull i8* @ret_nonnull() 5 6; Return a pointer trivially nonnull (call return attribute) 7define i8* @test1() { 8; CHECK: define nonnull i8* @test1 9 %ret = call i8* @ret_nonnull() 10 ret i8* %ret 11} 12 13; Return a pointer trivially nonnull (argument attribute) 14define i8* @test2(i8* nonnull %p) { 15; CHECK: define nonnull i8* @test2 16 ret i8* %p 17} 18 19; Given an SCC where one of the functions can not be marked nonnull, 20; can we still mark the other one which is trivially nonnull 21define i8* @scc_binder() { 22; CHECK: define i8* @scc_binder 23 call i8* @test3() 24 ret i8* null 25} 26 27define i8* @test3() { 28; CHECK: define nonnull i8* @test3 29 call i8* @scc_binder() 30 %ret = call i8* @ret_nonnull() 31 ret i8* %ret 32} 33 34; Given a mutual recursive set of functions, we can mark them 35; nonnull if neither can ever return null. (In this case, they 36; just never return period.) 37define i8* @test4_helper() { 38; CHECK: define noalias nonnull i8* @test4_helper 39 %ret = call i8* @test4() 40 ret i8* %ret 41} 42 43define i8* @test4() { 44; CHECK: define noalias nonnull i8* @test4 45 %ret = call i8* @test4_helper() 46 ret i8* %ret 47} 48 49; Given a mutual recursive set of functions which *can* return null 50; make sure we haven't marked them as nonnull. 51define i8* @test5_helper() { 52; CHECK: define noalias i8* @test5_helper 53 %ret = call i8* @test5() 54 ret i8* null 55} 56 57define i8* @test5() { 58; CHECK: define noalias i8* @test5 59 %ret = call i8* @test5_helper() 60 ret i8* %ret 61} 62 63; Local analysis, but going through a self recursive phi 64define i8* @test6() { 65entry: 66; CHECK: define nonnull i8* @test6 67 %ret = call i8* @ret_nonnull() 68 br label %loop 69loop: 70 %phi = phi i8* [%ret, %entry], [%phi, %loop] 71 br i1 undef, label %loop, label %exit 72exit: 73 ret i8* %phi 74} 75 76; Test propagation of nonnull callsite args back to caller. 77 78declare void @use1(i8* %x) 79declare void @use2(i8* %x, i8* %y); 80declare void @use3(i8* %x, i8* %y, i8* %z); 81 82declare void @use1nonnull(i8* nonnull %x); 83declare void @use2nonnull(i8* nonnull %x, i8* nonnull %y); 84declare void @use3nonnull(i8* nonnull %x, i8* nonnull %y, i8* nonnull %z); 85 86declare i8 @use1safecall(i8* %x) readonly nounwind ; readonly+nounwind guarantees that execution continues to successor 87 88; Can't extend non-null to parent for any argument because the 2nd call is not guaranteed to execute. 89 90define void @parent1(i8* %a, i8* %b, i8* %c) { 91; CHECK-LABEL: @parent1(i8* %a, i8* %b, i8* %c) 92; CHECK-NEXT: call void @use3(i8* %c, i8* %a, i8* %b) 93; CHECK-NEXT: call void @use3nonnull(i8* %b, i8* %c, i8* %a) 94; CHECK-NEXT: ret void 95; 96 call void @use3(i8* %c, i8* %a, i8* %b) 97 call void @use3nonnull(i8* %b, i8* %c, i8* %a) 98 ret void 99} 100 101; Extend non-null to parent for all arguments. 102 103define void @parent2(i8* %a, i8* %b, i8* %c) { 104; CHECK-LABEL: @parent2(i8* nonnull %a, i8* nonnull %b, i8* nonnull %c) 105; CHECK-NEXT: call void @use3nonnull(i8* %b, i8* %c, i8* %a) 106; CHECK-NEXT: call void @use3(i8* %c, i8* %a, i8* %b) 107; CHECK-NEXT: ret void 108; 109 call void @use3nonnull(i8* %b, i8* %c, i8* %a) 110 call void @use3(i8* %c, i8* %a, i8* %b) 111 ret void 112} 113 114; Extend non-null to parent for 1st argument. 115 116define void @parent3(i8* %a, i8* %b, i8* %c) { 117; CHECK-LABEL: @parent3(i8* nonnull %a, i8* %b, i8* %c) 118; CHECK-NEXT: call void @use1nonnull(i8* %a) 119; CHECK-NEXT: call void @use3(i8* %c, i8* %b, i8* %a) 120; CHECK-NEXT: ret void 121; 122 call void @use1nonnull(i8* %a) 123 call void @use3(i8* %c, i8* %b, i8* %a) 124 ret void 125} 126 127; Extend non-null to parent for last 2 arguments. 128 129define void @parent4(i8* %a, i8* %b, i8* %c) { 130; CHECK-LABEL: @parent4(i8* %a, i8* nonnull %b, i8* nonnull %c) 131; CHECK-NEXT: call void @use2nonnull(i8* %c, i8* %b) 132; CHECK-NEXT: call void @use2(i8* %a, i8* %c) 133; CHECK-NEXT: call void @use1(i8* %b) 134; CHECK-NEXT: ret void 135; 136 call void @use2nonnull(i8* %c, i8* %b) 137 call void @use2(i8* %a, i8* %c) 138 call void @use1(i8* %b) 139 ret void 140} 141 142; The callsite must execute in order for the attribute to transfer to the parent. 143; It appears benign to extend non-null to the parent in this case, but we can't do that 144; because it would incorrectly propagate the wrong information to its callers. 145 146define void @parent5(i8* %a, i1 %a_is_notnull) { 147; CHECK-LABEL: @parent5(i8* %a, i1 %a_is_notnull) 148; CHECK-NEXT: br i1 %a_is_notnull, label %t, label %f 149; CHECK: t: 150; CHECK-NEXT: call void @use1nonnull(i8* %a) 151; CHECK-NEXT: ret void 152; CHECK: f: 153; CHECK-NEXT: ret void 154; 155 br i1 %a_is_notnull, label %t, label %f 156t: 157 call void @use1nonnull(i8* %a) 158 ret void 159f: 160 ret void 161} 162 163; The callsite must execute in order for the attribute to transfer to the parent. 164; The volatile load might trap, so there's no guarantee that we'll ever get to the call. 165 166define i8 @parent6(i8* %a, i8* %b) { 167; CHECK-LABEL: @parent6(i8* %a, i8* %b) 168; CHECK-NEXT: [[C:%.*]] = load volatile i8, i8* %b 169; CHECK-NEXT: call void @use1nonnull(i8* %a) 170; CHECK-NEXT: ret i8 [[C]] 171; 172 %c = load volatile i8, i8* %b 173 call void @use1nonnull(i8* %a) 174 ret i8 %c 175} 176 177; The nonnull callsite is guaranteed to execute, so the argument must be nonnull throughout the parent. 178 179define i8 @parent7(i8* %a) { 180; CHECK-LABEL: @parent7(i8* nonnull %a) 181; CHECK-NEXT: [[RET:%.*]] = call i8 @use1safecall(i8* %a) 182; CHECK-NEXT: call void @use1nonnull(i8* %a) 183; CHECK-NEXT: ret i8 [[RET]] 184; 185 %ret = call i8 @use1safecall(i8* %a) 186 call void @use1nonnull(i8* %a) 187 ret i8 %ret 188} 189 190; Make sure that an invoke works similarly to a call. 191 192declare i32 @esfp(...) 193 194define i1 @parent8(i8* %a, i8* %bogus1, i8* %b) personality i8* bitcast (i32 (...)* @esfp to i8*){ 195; CHECK-LABEL: @parent8(i8* nonnull %a, i8* nocapture readnone %bogus1, i8* nonnull %b) 196; CHECK-NEXT: entry: 197; CHECK-NEXT: invoke void @use2nonnull(i8* %a, i8* %b) 198; CHECK-NEXT: to label %cont unwind label %exc 199; CHECK: cont: 200; CHECK-NEXT: [[NULL_CHECK:%.*]] = icmp eq i8* %b, null 201; CHECK-NEXT: ret i1 [[NULL_CHECK]] 202; CHECK: exc: 203; CHECK-NEXT: [[LP:%.*]] = landingpad { i8*, i32 } 204; CHECK-NEXT: filter [0 x i8*] zeroinitializer 205; CHECK-NEXT: unreachable 206; 207entry: 208 invoke void @use2nonnull(i8* %a, i8* %b) 209 to label %cont unwind label %exc 210 211cont: 212 %null_check = icmp eq i8* %b, null 213 ret i1 %null_check 214 215exc: 216 %lp = landingpad { i8*, i32 } 217 filter [0 x i8*] zeroinitializer 218 unreachable 219} 220 221; CHECK: define nonnull i32* @gep1( 222define i32* @gep1(i32* %p) { 223 %q = getelementptr inbounds i32, i32* %p, i32 1 224 ret i32* %q 225} 226 227define i32* @gep1_no_null_opt(i32* %p) #0 { 228; Should't be able to derive nonnull based on gep. 229; CHECK: define i32* @gep1_no_null_opt( 230 %q = getelementptr inbounds i32, i32* %p, i32 1 231 ret i32* %q 232} 233 234; CHECK: define i32 addrspace(3)* @gep2( 235define i32 addrspace(3)* @gep2(i32 addrspace(3)* %p) { 236 %q = getelementptr inbounds i32, i32 addrspace(3)* %p, i32 1 237 ret i32 addrspace(3)* %q 238} 239 240attributes #0 = { "null-pointer-is-valid"="true" } 241