1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 3 2; RUN: opt -S -passes=function-attrs -enable-nonnull-arg-prop %s | FileCheck %s --check-prefixes=COMMON,FNATTRS 3; RUN: opt -S -passes=attributor-light %s | FileCheck %s --check-prefixes=COMMON,ATTRIBUTOR 4 5target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" 6 7declare nonnull ptr @ret_nonnull() 8 9; Return a pointer trivially nonnull (call return attribute) 10define ptr @test1() { 11; COMMON-LABEL: define nonnull ptr @test1() { 12; COMMON-NEXT: [[RET:%.*]] = call ptr @ret_nonnull() 13; COMMON-NEXT: ret ptr [[RET]] 14; 15 %ret = call ptr @ret_nonnull() 16 ret ptr %ret 17} 18 19; Return a pointer trivially nonnull (argument attribute) 20define ptr @test2(ptr nonnull %p) { 21; FNATTRS-LABEL: define nonnull ptr @test2( 22; FNATTRS-SAME: ptr nonnull readnone returned [[P:%.*]]) #[[ATTR0:[0-9]+]] { 23; FNATTRS-NEXT: ret ptr [[P]] 24; 25; ATTRIBUTOR-LABEL: define nonnull ptr @test2( 26; ATTRIBUTOR-SAME: ptr nofree nonnull readnone [[P:%.*]]) #[[ATTR0:[0-9]+]] { 27; ATTRIBUTOR-NEXT: ret ptr [[P]] 28; 29 ret ptr %p 30} 31 32; Given an SCC where one of the functions can not be marked nonnull, 33; can we still mark the other one which is trivially nonnull 34define ptr @scc_binder(i1 %c) { 35; FNATTRS-LABEL: define noundef ptr @scc_binder( 36; FNATTRS-SAME: i1 [[C:%.*]]) { 37; FNATTRS-NEXT: br i1 [[C]], label [[REC:%.*]], label [[END:%.*]] 38; FNATTRS: rec: 39; FNATTRS-NEXT: [[TMP1:%.*]] = call ptr @test3(i1 [[C]]) 40; FNATTRS-NEXT: br label [[END]] 41; FNATTRS: end: 42; FNATTRS-NEXT: ret ptr null 43; 44; ATTRIBUTOR-LABEL: define ptr @scc_binder( 45; ATTRIBUTOR-SAME: i1 [[C:%.*]]) { 46; ATTRIBUTOR-NEXT: br i1 [[C]], label [[REC:%.*]], label [[END:%.*]] 47; ATTRIBUTOR: rec: 48; ATTRIBUTOR-NEXT: [[TMP1:%.*]] = call ptr @test3(i1 [[C]]) 49; ATTRIBUTOR-NEXT: br label [[END]] 50; ATTRIBUTOR: end: 51; ATTRIBUTOR-NEXT: ret ptr null 52; 53 br i1 %c, label %rec, label %end 54rec: 55 call ptr @test3(i1 %c) 56 br label %end 57end: 58 ret ptr null 59} 60 61define ptr @test3(i1 %c) { 62; COMMON-LABEL: define nonnull ptr @test3( 63; COMMON-SAME: i1 [[C:%.*]]) { 64; COMMON-NEXT: [[TMP1:%.*]] = call ptr @scc_binder(i1 [[C]]) 65; COMMON-NEXT: [[RET:%.*]] = call ptr @ret_nonnull() 66; COMMON-NEXT: ret ptr [[RET]] 67; 68 call ptr @scc_binder(i1 %c) 69 %ret = call ptr @ret_nonnull() 70 ret ptr %ret 71} 72 73; Given a mutual recursive set of functions, we can mark them 74; nonnull if neither can ever return null. (In this case, they 75; just never return period.) 76define ptr @test4_helper() { 77; FNATTRS-LABEL: define noalias nonnull ptr @test4_helper( 78; FNATTRS-SAME: ) #[[ATTR1:[0-9]+]] { 79; FNATTRS-NEXT: [[RET:%.*]] = call ptr @test4() 80; FNATTRS-NEXT: ret ptr [[RET]] 81; 82; ATTRIBUTOR-LABEL: define ptr @test4_helper( 83; ATTRIBUTOR-SAME: ) #[[ATTR1:[0-9]+]] { 84; ATTRIBUTOR-NEXT: [[RET:%.*]] = call ptr @test4() #[[ATTR1]] 85; ATTRIBUTOR-NEXT: ret ptr [[RET]] 86; 87 %ret = call ptr @test4() 88 ret ptr %ret 89} 90 91define ptr @test4() { 92; FNATTRS-LABEL: define noalias nonnull ptr @test4( 93; FNATTRS-SAME: ) #[[ATTR1]] { 94; FNATTRS-NEXT: [[RET:%.*]] = call ptr @test4_helper() 95; FNATTRS-NEXT: ret ptr [[RET]] 96; 97; ATTRIBUTOR-LABEL: define ptr @test4( 98; ATTRIBUTOR-SAME: ) #[[ATTR1]] { 99; ATTRIBUTOR-NEXT: [[RET:%.*]] = call ptr @test4_helper() #[[ATTR1]] 100; ATTRIBUTOR-NEXT: ret ptr [[RET]] 101; 102 %ret = call ptr @test4_helper() 103 ret ptr %ret 104} 105 106; Given a mutual recursive set of functions which *can* return null 107; make sure we haven't marked them as nonnull. 108define ptr @test5_helper(i1 %c) { 109; FNATTRS-LABEL: define noalias noundef ptr @test5_helper( 110; FNATTRS-SAME: i1 [[C:%.*]]) #[[ATTR1]] { 111; FNATTRS-NEXT: br i1 [[C]], label [[REC:%.*]], label [[END:%.*]] 112; FNATTRS: rec: 113; FNATTRS-NEXT: [[RET:%.*]] = call ptr @test5(i1 [[C]]) 114; FNATTRS-NEXT: br label [[END]] 115; FNATTRS: end: 116; FNATTRS-NEXT: ret ptr null 117; 118; ATTRIBUTOR-LABEL: define ptr @test5_helper( 119; ATTRIBUTOR-SAME: i1 [[C:%.*]]) #[[ATTR1]] { 120; ATTRIBUTOR-NEXT: br i1 [[C]], label [[REC:%.*]], label [[END:%.*]] 121; ATTRIBUTOR: rec: 122; ATTRIBUTOR-NEXT: [[RET:%.*]] = call ptr @test5(i1 [[C]]) #[[ATTR1]] 123; ATTRIBUTOR-NEXT: br label [[END]] 124; ATTRIBUTOR: end: 125; ATTRIBUTOR-NEXT: ret ptr null 126; 127 br i1 %c, label %rec, label %end 128rec: 129 %ret = call ptr @test5(i1 %c) 130 br label %end 131end: 132 ret ptr null 133} 134 135define ptr @test5(i1 %c) { 136; FNATTRS-LABEL: define noalias noundef ptr @test5( 137; FNATTRS-SAME: i1 [[C:%.*]]) #[[ATTR1]] { 138; FNATTRS-NEXT: [[RET:%.*]] = call ptr @test5_helper(i1 [[C]]) 139; FNATTRS-NEXT: ret ptr [[RET]] 140; 141; ATTRIBUTOR-LABEL: define ptr @test5( 142; ATTRIBUTOR-SAME: i1 [[C:%.*]]) #[[ATTR1]] { 143; ATTRIBUTOR-NEXT: [[RET:%.*]] = call ptr @test5_helper(i1 [[C]]) #[[ATTR1]] 144; ATTRIBUTOR-NEXT: ret ptr [[RET]] 145; 146 %ret = call ptr @test5_helper(i1 %c) 147 ret ptr %ret 148} 149 150; Local analysis, but going through a self recursive phi 151define ptr @test6a(i1 %arg) { 152; COMMON-LABEL: define nonnull ptr @test6a( 153; COMMON-SAME: i1 [[ARG:%.*]]) { 154; COMMON-NEXT: entry: 155; COMMON-NEXT: [[RET:%.*]] = call ptr @ret_nonnull() 156; COMMON-NEXT: br label [[LOOP:%.*]] 157; COMMON: loop: 158; COMMON-NEXT: [[PHI:%.*]] = phi ptr [ [[RET]], [[ENTRY:%.*]] ], [ [[PHI]], [[LOOP]] ] 159; COMMON-NEXT: br i1 [[ARG]], label [[LOOP]], label [[EXIT:%.*]] 160; COMMON: exit: 161; COMMON-NEXT: ret ptr [[PHI]] 162; 163entry: 164 %ret = call ptr @ret_nonnull() 165 br label %loop 166loop: 167 %phi = phi ptr [%ret, %entry], [%phi, %loop] 168 br i1 %arg, label %loop, label %exit 169exit: 170 ret ptr %phi 171} 172 173define ptr @test6b(i1 %c) { 174; COMMON-LABEL: define nonnull ptr @test6b( 175; COMMON-SAME: i1 [[C:%.*]]) { 176; COMMON-NEXT: entry: 177; COMMON-NEXT: [[RET:%.*]] = call ptr @ret_nonnull() 178; COMMON-NEXT: br label [[LOOP:%.*]] 179; COMMON: loop: 180; COMMON-NEXT: [[PHI:%.*]] = phi ptr [ [[RET]], [[ENTRY:%.*]] ], [ [[PHI]], [[LOOP]] ] 181; COMMON-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]] 182; COMMON: exit: 183; COMMON-NEXT: ret ptr [[PHI]] 184; 185entry: 186 %ret = call ptr @ret_nonnull() 187 br label %loop 188loop: 189 %phi = phi ptr [%ret, %entry], [%phi, %loop] 190 br i1 %c, label %loop, label %exit 191exit: 192 ret ptr %phi 193} 194 195define ptr @test7(ptr %a) { 196; FNATTRS-LABEL: define ptr @test7( 197; FNATTRS-SAME: ptr readnone returned [[A:%.*]]) #[[ATTR0]] { 198; FNATTRS-NEXT: ret ptr [[A]] 199; 200; ATTRIBUTOR-LABEL: define ptr @test7( 201; ATTRIBUTOR-SAME: ptr nofree readnone [[A:%.*]]) #[[ATTR0]] { 202; ATTRIBUTOR-NEXT: ret ptr [[A]] 203; 204 ret ptr %a 205} 206 207define ptr @test8(ptr %a) { 208; FNATTRS-LABEL: define nonnull ptr @test8( 209; FNATTRS-SAME: ptr readnone [[A:%.*]]) #[[ATTR0]] { 210; FNATTRS-NEXT: [[B:%.*]] = getelementptr inbounds i8, ptr [[A]], i64 1 211; FNATTRS-NEXT: ret ptr [[B]] 212; 213; ATTRIBUTOR-LABEL: define nonnull ptr @test8( 214; ATTRIBUTOR-SAME: ptr nofree readnone [[A:%.*]]) #[[ATTR0]] { 215; ATTRIBUTOR-NEXT: [[B:%.*]] = getelementptr inbounds i8, ptr [[A]], i64 1 216; ATTRIBUTOR-NEXT: ret ptr [[B]] 217; 218 %b = getelementptr inbounds i8, ptr %a, i64 1 219 ret ptr %b 220} 221 222define ptr @test9(ptr %a, i64 %n) { 223; FNATTRS-LABEL: define ptr @test9( 224; FNATTRS-SAME: ptr readnone [[A:%.*]], i64 [[N:%.*]]) #[[ATTR0]] { 225; FNATTRS-NEXT: [[B:%.*]] = getelementptr inbounds i8, ptr [[A]], i64 [[N]] 226; FNATTRS-NEXT: ret ptr [[B]] 227; 228; ATTRIBUTOR-LABEL: define ptr @test9( 229; ATTRIBUTOR-SAME: ptr nofree readnone [[A:%.*]], i64 [[N:%.*]]) #[[ATTR0]] { 230; ATTRIBUTOR-NEXT: [[B:%.*]] = getelementptr inbounds i8, ptr [[A]], i64 [[N]] 231; ATTRIBUTOR-NEXT: ret ptr [[B]] 232; 233 %b = getelementptr inbounds i8, ptr %a, i64 %n 234 ret ptr %b 235} 236 237declare void @llvm.assume(i1) 238; FIXME: missing nonnull 239define ptr @test10(ptr %a, i64 %n) { 240; FNATTRS-LABEL: define ptr @test10( 241; FNATTRS-SAME: ptr readnone [[A:%.*]], i64 [[N:%.*]]) #[[ATTR3:[0-9]+]] { 242; FNATTRS-NEXT: [[CMP:%.*]] = icmp ne i64 [[N]], 0 243; FNATTRS-NEXT: call void @llvm.assume(i1 [[CMP]]) 244; FNATTRS-NEXT: [[B:%.*]] = getelementptr inbounds i8, ptr [[A]], i64 [[N]] 245; FNATTRS-NEXT: ret ptr [[B]] 246; 247; ATTRIBUTOR-LABEL: define ptr @test10( 248; ATTRIBUTOR-SAME: ptr nofree readnone [[A:%.*]], i64 [[N:%.*]]) #[[ATTR3:[0-9]+]] { 249; ATTRIBUTOR-NEXT: [[CMP:%.*]] = icmp ne i64 [[N]], 0 250; ATTRIBUTOR-NEXT: call void @llvm.assume(i1 [[CMP]]) #[[ATTR13:[0-9]+]] 251; ATTRIBUTOR-NEXT: [[B:%.*]] = getelementptr inbounds i8, ptr [[A]], i64 [[N]] 252; ATTRIBUTOR-NEXT: ret ptr [[B]] 253; 254 %cmp = icmp ne i64 %n, 0 255 call void @llvm.assume(i1 %cmp) 256 %b = getelementptr inbounds i8, ptr %a, i64 %n 257 ret ptr %b 258} 259 260; TEST 11 261; char* test11(char *p) { 262; return p? p: nonnull(); 263; } 264define ptr @test11(ptr) local_unnamed_addr { 265; FNATTRS-LABEL: define nonnull ptr @test11( 266; FNATTRS-SAME: ptr readnone [[TMP0:%.*]]) local_unnamed_addr { 267; FNATTRS-NEXT: [[TMP2:%.*]] = icmp eq ptr [[TMP0]], null 268; FNATTRS-NEXT: br i1 [[TMP2]], label [[TMP3:%.*]], label [[TMP5:%.*]] 269; FNATTRS: 3: 270; FNATTRS-NEXT: [[TMP4:%.*]] = tail call ptr @ret_nonnull() 271; FNATTRS-NEXT: br label [[TMP5]] 272; FNATTRS: 5: 273; FNATTRS-NEXT: [[TMP6:%.*]] = phi ptr [ [[TMP4]], [[TMP3]] ], [ [[TMP0]], [[TMP1:%.*]] ] 274; FNATTRS-NEXT: ret ptr [[TMP6]] 275; 276; ATTRIBUTOR-LABEL: define nonnull ptr @test11( 277; ATTRIBUTOR-SAME: ptr [[TMP0:%.*]]) local_unnamed_addr { 278; ATTRIBUTOR-NEXT: [[TMP2:%.*]] = icmp eq ptr [[TMP0]], null 279; ATTRIBUTOR-NEXT: br i1 [[TMP2]], label [[TMP3:%.*]], label [[TMP5:%.*]] 280; ATTRIBUTOR: 3: 281; ATTRIBUTOR-NEXT: [[TMP4:%.*]] = tail call ptr @ret_nonnull() 282; ATTRIBUTOR-NEXT: br label [[TMP5]] 283; ATTRIBUTOR: 5: 284; ATTRIBUTOR-NEXT: [[TMP6:%.*]] = phi ptr [ [[TMP4]], [[TMP3]] ], [ [[TMP0]], [[TMP1:%.*]] ] 285; ATTRIBUTOR-NEXT: ret ptr [[TMP6]] 286; 287 %2 = icmp eq ptr %0, null 288 br i1 %2, label %3, label %5 289 290; <label>:3: ; preds = %1 291 %4 = tail call ptr @ret_nonnull() 292 br label %5 293 294; <label>:5: ; preds = %3, %1 295 %6 = phi ptr [ %4, %3 ], [ %0, %1 ] 296 ret ptr %6 297} 298 299; TEST 12 300; Simple CallSite Test 301declare void @test12_helper(ptr) 302define void @test12(ptr nonnull %a) { 303; COMMON-LABEL: define void @test12( 304; COMMON-SAME: ptr nonnull [[A:%.*]]) { 305; COMMON-NEXT: tail call void @test12_helper(ptr [[A]]) 306; COMMON-NEXT: ret void 307; 308 tail call void @test12_helper(ptr %a) 309 ret void 310} 311 312; TEST 13 313; Simple Argument Tests 314declare ptr @unknown() 315define void @test13_helper() { 316; FNATTRS-LABEL: define void @test13_helper() { 317; FNATTRS-NEXT: [[NONNULLPTR:%.*]] = tail call ptr @ret_nonnull() 318; FNATTRS-NEXT: [[MAYBENULLPTR:%.*]] = tail call ptr @unknown() 319; FNATTRS-NEXT: tail call void @test13(ptr [[NONNULLPTR]], ptr [[NONNULLPTR]], ptr [[MAYBENULLPTR]]) 320; FNATTRS-NEXT: tail call void @test13(ptr [[NONNULLPTR]], ptr [[MAYBENULLPTR]], ptr [[NONNULLPTR]]) 321; FNATTRS-NEXT: ret void 322; 323; ATTRIBUTOR-LABEL: define void @test13_helper() { 324; ATTRIBUTOR-NEXT: [[NONNULLPTR:%.*]] = tail call ptr @ret_nonnull() 325; ATTRIBUTOR-NEXT: [[MAYBENULLPTR:%.*]] = tail call ptr @unknown() 326; ATTRIBUTOR-NEXT: tail call void @test13(ptr nofree nonnull readnone captures(none) [[NONNULLPTR]], ptr nofree nonnull readnone captures(none) [[NONNULLPTR]], ptr nofree readnone captures(none) [[MAYBENULLPTR]]) 327; ATTRIBUTOR-NEXT: tail call void @test13(ptr nofree nonnull readnone captures(none) [[NONNULLPTR]], ptr nofree readnone captures(none) [[MAYBENULLPTR]], ptr nofree nonnull readnone captures(none) [[NONNULLPTR]]) 328; ATTRIBUTOR-NEXT: ret void 329; 330 %nonnullptr = tail call ptr @ret_nonnull() 331 %maybenullptr = tail call ptr @unknown() 332 tail call void @test13(ptr %nonnullptr, ptr %nonnullptr, ptr %maybenullptr) 333 tail call void @test13(ptr %nonnullptr, ptr %maybenullptr, ptr %nonnullptr) 334 ret void 335} 336define internal void @test13(ptr %a, ptr %b, ptr %c) { 337; FNATTRS-LABEL: define internal void @test13( 338; FNATTRS-SAME: ptr readnone captures(none) [[A:%.*]], ptr readnone captures(none) [[B:%.*]], ptr readnone captures(none) [[C:%.*]]) #[[ATTR0]] { 339; FNATTRS-NEXT: ret void 340; 341; ATTRIBUTOR-LABEL: define internal void @test13( 342; ATTRIBUTOR-SAME: ptr nofree nonnull readnone captures(none) [[A:%.*]], ptr nofree readnone captures(none) [[B:%.*]], ptr nofree readnone captures(none) [[C:%.*]]) #[[ATTR0]] { 343; ATTRIBUTOR-NEXT: ret void 344; 345 ret void 346} 347 348declare nonnull ptr @nonnull() 349 350; TEST 14 351; Complex propagation 352; Argument of f1, f2, f3 can be marked with nonnull. 353 354; * Argument 355; 1. In f1:bb6, %arg can be marked with nonnull because of the comparison in bb1 356; 2. Because f2 is internal function, f2(ptr %arg) -> @f2(ptr nonnull %arg) 357; 3. In f1:bb4 %tmp5 is nonnull and f3 is internal function. 358; Then, f3(ptr %arg) -> @f3(ptr nonnull %arg) 359; 4. We get nonnull in whole f1 call sites so f1(ptr %arg) -> @f1(ptr nonnull %arg) 360 361 362define internal ptr @f1(ptr %arg) { 363; FIXME: missing nonnull It should be nonnull @f1(ptr nonnull readonly %arg) 364; FNATTRS-LABEL: define internal nonnull ptr @f1( 365; FNATTRS-SAME: ptr readonly [[ARG:%.*]]) #[[ATTR4:[0-9]+]] { 366; FNATTRS-NEXT: bb: 367; FNATTRS-NEXT: [[TMP:%.*]] = icmp eq ptr [[ARG]], null 368; FNATTRS-NEXT: br i1 [[TMP]], label [[BB9:%.*]], label [[BB1:%.*]] 369; FNATTRS: bb1: 370; FNATTRS-NEXT: [[TMP2:%.*]] = load i32, ptr [[ARG]], align 4 371; FNATTRS-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP2]], 0 372; FNATTRS-NEXT: br i1 [[TMP3]], label [[BB6:%.*]], label [[BB4:%.*]] 373; FNATTRS: bb4: 374; FNATTRS-NEXT: [[TMP5:%.*]] = getelementptr inbounds i32, ptr [[ARG]], i64 1 375; FNATTRS-NEXT: [[TMP5B:%.*]] = tail call ptr @f3(ptr [[TMP5]]) 376; FNATTRS-NEXT: [[TMP5C:%.*]] = getelementptr inbounds i32, ptr [[TMP5B]], i64 -1 377; FNATTRS-NEXT: br label [[BB9]] 378; FNATTRS: bb6: 379; FNATTRS-NEXT: [[TMP7:%.*]] = tail call ptr @f2(ptr [[ARG]]) 380; FNATTRS-NEXT: ret ptr [[TMP7]] 381; FNATTRS: bb9: 382; FNATTRS-NEXT: [[TMP10:%.*]] = phi ptr [ [[TMP5C]], [[BB4]] ], [ inttoptr (i64 4 to ptr), [[BB:%.*]] ] 383; FNATTRS-NEXT: ret ptr [[TMP10]] 384; 385; ATTRIBUTOR-LABEL: define internal ptr @f1( 386; ATTRIBUTOR-SAME: ptr nofree readonly [[ARG:%.*]]) #[[ATTR4:[0-9]+]] { 387; ATTRIBUTOR-NEXT: bb: 388; ATTRIBUTOR-NEXT: [[TMP:%.*]] = icmp eq ptr [[ARG]], null 389; ATTRIBUTOR-NEXT: br i1 [[TMP]], label [[BB9:%.*]], label [[BB1:%.*]] 390; ATTRIBUTOR: bb1: 391; ATTRIBUTOR-NEXT: [[TMP2:%.*]] = load i32, ptr [[ARG]], align 4 392; ATTRIBUTOR-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP2]], 0 393; ATTRIBUTOR-NEXT: br i1 [[TMP3]], label [[BB6:%.*]], label [[BB4:%.*]] 394; ATTRIBUTOR: bb4: 395; ATTRIBUTOR-NEXT: [[TMP5:%.*]] = getelementptr inbounds i32, ptr [[ARG]], i64 1 396; ATTRIBUTOR-NEXT: [[TMP5B:%.*]] = tail call ptr @f3(ptr nofree nonnull readonly [[TMP5]]) #[[ATTR14:[0-9]+]] 397; ATTRIBUTOR-NEXT: [[TMP5C:%.*]] = getelementptr inbounds i32, ptr [[TMP5B]], i64 -1 398; ATTRIBUTOR-NEXT: br label [[BB9]] 399; ATTRIBUTOR: bb6: 400; ATTRIBUTOR-NEXT: [[TMP7:%.*]] = tail call ptr @f2(ptr nofree nonnull readonly [[ARG]]) #[[ATTR14]] 401; ATTRIBUTOR-NEXT: ret ptr [[TMP7]] 402; ATTRIBUTOR: bb9: 403; ATTRIBUTOR-NEXT: [[TMP10:%.*]] = phi ptr [ [[TMP5C]], [[BB4]] ], [ inttoptr (i64 4 to ptr), [[BB:%.*]] ] 404; ATTRIBUTOR-NEXT: ret ptr [[TMP10]] 405; 406bb: 407 %tmp = icmp eq ptr %arg, null 408 br i1 %tmp, label %bb9, label %bb1 409 410bb1: ; preds = %bb 411 %tmp2 = load i32, ptr %arg, align 4 412 %tmp3 = icmp eq i32 %tmp2, 0 413 br i1 %tmp3, label %bb6, label %bb4 414 415bb4: ; preds = %bb1 416 %tmp5 = getelementptr inbounds i32, ptr %arg, i64 1 417 %tmp5b = tail call ptr @f3(ptr %tmp5) 418 %tmp5c = getelementptr inbounds i32, ptr %tmp5b, i64 -1 419 br label %bb9 420 421bb6: ; preds = %bb1 422; FIXME: missing nonnull. It should be @f2(ptr nonnull %arg) 423 %tmp7 = tail call ptr @f2(ptr %arg) 424 ret ptr %tmp7 425 426bb9: ; preds = %bb4, %bb 427 %tmp10 = phi ptr [ %tmp5c, %bb4 ], [ inttoptr (i64 4 to ptr), %bb ] 428 ret ptr %tmp10 429} 430 431define internal ptr @f2(ptr %arg) { 432; FIXME: missing nonnull. It should be nonnull @f2(ptr nonnull %arg) 433; FNATTRS-LABEL: define internal nonnull ptr @f2( 434; FNATTRS-SAME: ptr [[ARG:%.*]]) #[[ATTR4]] { 435; FNATTRS-NEXT: bb: 436; FNATTRS-NEXT: [[TMP:%.*]] = tail call ptr @f1(ptr [[ARG]]) 437; FNATTRS-NEXT: ret ptr [[TMP]] 438; 439; ATTRIBUTOR-LABEL: define internal ptr @f2( 440; ATTRIBUTOR-SAME: ptr nofree nonnull readonly [[ARG:%.*]]) #[[ATTR4]] { 441; ATTRIBUTOR-NEXT: bb: 442; ATTRIBUTOR-NEXT: [[TMP:%.*]] = tail call ptr @f1(ptr nofree nonnull readonly [[ARG]]) #[[ATTR14]] 443; ATTRIBUTOR-NEXT: ret ptr [[TMP]] 444; 445bb: 446 447; FIXME: missing nonnull. It should be @f1(ptr nonnull readonly %arg) 448 %tmp = tail call ptr @f1(ptr %arg) 449 ret ptr %tmp 450} 451 452define dso_local noalias ptr @f3(ptr %arg) { 453; FIXME: missing nonnull. It should be nonnull @f3(ptr nonnull readonly %arg) 454; FNATTRS-LABEL: define dso_local noalias nonnull ptr @f3( 455; FNATTRS-SAME: ptr [[ARG:%.*]]) #[[ATTR4]] { 456; FNATTRS-NEXT: bb: 457; FNATTRS-NEXT: [[TMP:%.*]] = call ptr @f1(ptr [[ARG]]) 458; FNATTRS-NEXT: ret ptr [[TMP]] 459; 460; ATTRIBUTOR-LABEL: define dso_local noalias ptr @f3( 461; ATTRIBUTOR-SAME: ptr nofree readonly [[ARG:%.*]]) #[[ATTR4]] { 462; ATTRIBUTOR-NEXT: bb: 463; ATTRIBUTOR-NEXT: [[TMP:%.*]] = call ptr @f1(ptr nofree readonly [[ARG]]) #[[ATTR14]] 464; ATTRIBUTOR-NEXT: ret ptr [[TMP]] 465; 466bb: 467; FIXME: missing nonnull. It should be @f1(ptr nonnull readonly %arg) 468 %tmp = call ptr @f1(ptr %arg) 469 ret ptr %tmp 470} 471 472; TEST 15 473define void @f15(ptr %arg) { 474; FNATTRS-LABEL: define void @f15( 475; FNATTRS-SAME: ptr [[ARG:%.*]]) { 476; FNATTRS-NEXT: tail call void @use1(ptr dereferenceable(4) [[ARG]]) 477; FNATTRS-NEXT: ret void 478; 479; ATTRIBUTOR-LABEL: define void @f15( 480; ATTRIBUTOR-SAME: ptr nonnull [[ARG:%.*]]) { 481; ATTRIBUTOR-NEXT: tail call void @use1(ptr nonnull dereferenceable(4) [[ARG]]) 482; ATTRIBUTOR-NEXT: ret void 483; 484 tail call void @use1(ptr dereferenceable(4) %arg) 485 ret void 486} 487 488declare void @fun0() #1 489declare void @fun1(ptr) #1 490declare void @fun2(ptr, ptr) #1 491declare void @fun3(ptr, ptr, ptr) #1 492; TEST 16 simple path test 493; if(..) 494; fun2(nonnull %a, nonnull %b) 495; else 496; fun2(nonnull %a, %b) 497; We can say that %a is nonnull but %b is not. 498define void @f16(ptr %a, ptr %b, i8 %c) { 499; FIXME: missing nonnull on %a 500; FNATTRS-LABEL: define void @f16( 501; FNATTRS-SAME: ptr [[A:%.*]], ptr [[B:%.*]], i8 [[C:%.*]]) #[[ATTR6:[0-9]+]] { 502; FNATTRS-NEXT: [[CMP:%.*]] = icmp eq i8 [[C]], 0 503; FNATTRS-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] 504; FNATTRS: if.then: 505; FNATTRS-NEXT: tail call void @fun2(ptr nonnull [[A]], ptr nonnull [[B]]) 506; FNATTRS-NEXT: ret void 507; FNATTRS: if.else: 508; FNATTRS-NEXT: tail call void @fun2(ptr nonnull [[A]], ptr [[B]]) 509; FNATTRS-NEXT: ret void 510; 511; ATTRIBUTOR-LABEL: define void @f16( 512; ATTRIBUTOR-SAME: ptr nonnull [[A:%.*]], ptr [[B:%.*]], i8 [[C:%.*]]) #[[ATTR6:[0-9]+]] { 513; ATTRIBUTOR-NEXT: [[CMP:%.*]] = icmp eq i8 [[C]], 0 514; ATTRIBUTOR-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] 515; ATTRIBUTOR: if.then: 516; ATTRIBUTOR-NEXT: tail call void @fun2(ptr nonnull [[A]], ptr nonnull [[B]]) #[[ATTR15:[0-9]+]] 517; ATTRIBUTOR-NEXT: ret void 518; ATTRIBUTOR: if.else: 519; ATTRIBUTOR-NEXT: tail call void @fun2(ptr nonnull [[A]], ptr [[B]]) #[[ATTR15]] 520; ATTRIBUTOR-NEXT: ret void 521; 522 %cmp = icmp eq i8 %c, 0 523 br i1 %cmp, label %if.then, label %if.else 524if.then: 525 tail call void @fun2(ptr nonnull %a, ptr nonnull %b) 526 ret void 527if.else: 528 tail call void @fun2(ptr nonnull %a, ptr %b) 529 ret void 530} 531; TEST 17 explore child BB test 532; if(..) 533; ... (willreturn & nounwind) 534; else 535; ... (willreturn & nounwind) 536; fun1(nonnull %a) 537; We can say that %a is nonnull 538define void @f17(ptr %a, i8 %c) { 539; FNATTRS-LABEL: define void @f17( 540; FNATTRS-SAME: ptr [[A:%.*]], i8 [[C:%.*]]) #[[ATTR6]] { 541; FNATTRS-NEXT: [[CMP:%.*]] = icmp eq i8 [[C]], 0 542; FNATTRS-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] 543; FNATTRS: if.then: 544; FNATTRS-NEXT: tail call void @fun0() 545; FNATTRS-NEXT: br label [[CONT:%.*]] 546; FNATTRS: if.else: 547; FNATTRS-NEXT: tail call void @fun0() 548; FNATTRS-NEXT: br label [[CONT]] 549; FNATTRS: cont: 550; FNATTRS-NEXT: tail call void @fun1(ptr nonnull [[A]]) 551; FNATTRS-NEXT: ret void 552; 553; ATTRIBUTOR-LABEL: define void @f17( 554; ATTRIBUTOR-SAME: ptr nonnull [[A:%.*]], i8 [[C:%.*]]) #[[ATTR6]] { 555; ATTRIBUTOR-NEXT: [[CMP:%.*]] = icmp eq i8 [[C]], 0 556; ATTRIBUTOR-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] 557; ATTRIBUTOR: if.then: 558; ATTRIBUTOR-NEXT: tail call void @fun0() #[[ATTR15]] 559; ATTRIBUTOR-NEXT: br label [[CONT:%.*]] 560; ATTRIBUTOR: if.else: 561; ATTRIBUTOR-NEXT: tail call void @fun0() #[[ATTR15]] 562; ATTRIBUTOR-NEXT: br label [[CONT]] 563; ATTRIBUTOR: cont: 564; ATTRIBUTOR-NEXT: tail call void @fun1(ptr nonnull [[A]]) #[[ATTR15]] 565; ATTRIBUTOR-NEXT: ret void 566; 567 %cmp = icmp eq i8 %c, 0 568 br i1 %cmp, label %if.then, label %if.else 569if.then: 570 tail call void @fun0() 571 br label %cont 572if.else: 573 tail call void @fun0() 574 br label %cont 575cont: 576 tail call void @fun1(ptr nonnull %a) 577 ret void 578} 579; TEST 18 More complex test 580; if(..) 581; ... (willreturn & nounwind) 582; else 583; ... (willreturn & nounwind) 584; if(..) 585; ... (willreturn & nounwind) 586; else 587; ... (willreturn & nounwind) 588; fun1(nonnull %a) 589 590define void @f18(ptr %a, ptr %b, i8 %c) { 591; FNATTRS-LABEL: define void @f18( 592; FNATTRS-SAME: ptr [[A:%.*]], ptr [[B:%.*]], i8 [[C:%.*]]) #[[ATTR6]] { 593; FNATTRS-NEXT: [[CMP1:%.*]] = icmp eq i8 [[C]], 0 594; FNATTRS-NEXT: br i1 [[CMP1]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] 595; FNATTRS: if.then: 596; FNATTRS-NEXT: tail call void @fun0() 597; FNATTRS-NEXT: br label [[CONT:%.*]] 598; FNATTRS: if.else: 599; FNATTRS-NEXT: tail call void @fun0() 600; FNATTRS-NEXT: br label [[CONT]] 601; FNATTRS: cont: 602; FNATTRS-NEXT: [[CMP2:%.*]] = icmp eq i8 [[C]], 1 603; FNATTRS-NEXT: br i1 [[CMP2]], label [[CONT_THEN:%.*]], label [[CONT_ELSE:%.*]] 604; FNATTRS: cont.then: 605; FNATTRS-NEXT: tail call void @fun1(ptr nonnull [[B]]) 606; FNATTRS-NEXT: br label [[CONT2:%.*]] 607; FNATTRS: cont.else: 608; FNATTRS-NEXT: tail call void @fun0() 609; FNATTRS-NEXT: br label [[CONT2]] 610; FNATTRS: cont2: 611; FNATTRS-NEXT: tail call void @fun1(ptr nonnull [[A]]) 612; FNATTRS-NEXT: ret void 613; 614; ATTRIBUTOR-LABEL: define void @f18( 615; ATTRIBUTOR-SAME: ptr nonnull [[A:%.*]], ptr [[B:%.*]], i8 [[C:%.*]]) #[[ATTR6]] { 616; ATTRIBUTOR-NEXT: [[CMP1:%.*]] = icmp eq i8 [[C]], 0 617; ATTRIBUTOR-NEXT: br i1 [[CMP1]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] 618; ATTRIBUTOR: if.then: 619; ATTRIBUTOR-NEXT: tail call void @fun0() #[[ATTR15]] 620; ATTRIBUTOR-NEXT: br label [[CONT:%.*]] 621; ATTRIBUTOR: if.else: 622; ATTRIBUTOR-NEXT: tail call void @fun0() #[[ATTR15]] 623; ATTRIBUTOR-NEXT: br label [[CONT]] 624; ATTRIBUTOR: cont: 625; ATTRIBUTOR-NEXT: [[CMP2:%.*]] = icmp eq i8 [[C]], 1 626; ATTRIBUTOR-NEXT: br i1 [[CMP2]], label [[CONT_THEN:%.*]], label [[CONT_ELSE:%.*]] 627; ATTRIBUTOR: cont.then: 628; ATTRIBUTOR-NEXT: tail call void @fun1(ptr nonnull [[B]]) #[[ATTR15]] 629; ATTRIBUTOR-NEXT: br label [[CONT2:%.*]] 630; ATTRIBUTOR: cont.else: 631; ATTRIBUTOR-NEXT: tail call void @fun0() #[[ATTR15]] 632; ATTRIBUTOR-NEXT: br label [[CONT2]] 633; ATTRIBUTOR: cont2: 634; ATTRIBUTOR-NEXT: tail call void @fun1(ptr nonnull [[A]]) #[[ATTR15]] 635; ATTRIBUTOR-NEXT: ret void 636; 637 %cmp1 = icmp eq i8 %c, 0 638 br i1 %cmp1, label %if.then, label %if.else 639if.then: 640 tail call void @fun0() 641 br label %cont 642if.else: 643 tail call void @fun0() 644 br label %cont 645cont: 646 %cmp2 = icmp eq i8 %c, 1 647 br i1 %cmp2, label %cont.then, label %cont.else 648cont.then: 649 tail call void @fun1(ptr nonnull %b) 650 br label %cont2 651cont.else: 652 tail call void @fun0() 653 br label %cont2 654cont2: 655 tail call void @fun1(ptr nonnull %a) 656 ret void 657} 658 659; TEST 19: Loop 660 661define void @f19(ptr %a, ptr %b, i8 %c) { 662; FIXME: missing nonnull on %b 663; FNATTRS-LABEL: define void @f19( 664; FNATTRS-SAME: ptr [[A:%.*]], ptr [[B:%.*]], i8 [[C:%.*]]) #[[ATTR7:[0-9]+]] { 665; FNATTRS-NEXT: br label [[LOOP_HEADER:%.*]] 666; FNATTRS: loop.header: 667; FNATTRS-NEXT: [[CMP2:%.*]] = icmp eq i8 [[C]], 0 668; FNATTRS-NEXT: br i1 [[CMP2]], label [[LOOP_BODY:%.*]], label [[LOOP_EXIT:%.*]] 669; FNATTRS: loop.body: 670; FNATTRS-NEXT: tail call void @fun1(ptr nonnull [[B]]) 671; FNATTRS-NEXT: tail call void @fun1(ptr nonnull [[A]]) 672; FNATTRS-NEXT: br label [[LOOP_HEADER]] 673; FNATTRS: loop.exit: 674; FNATTRS-NEXT: tail call void @fun1(ptr nonnull [[B]]) 675; FNATTRS-NEXT: ret void 676; 677; ATTRIBUTOR-LABEL: define void @f19( 678; ATTRIBUTOR-SAME: ptr [[A:%.*]], ptr nonnull [[B:%.*]], i8 [[C:%.*]]) #[[ATTR7:[0-9]+]] { 679; ATTRIBUTOR-NEXT: br label [[LOOP_HEADER:%.*]] 680; ATTRIBUTOR: loop.header: 681; ATTRIBUTOR-NEXT: [[CMP2:%.*]] = icmp eq i8 [[C]], 0 682; ATTRIBUTOR-NEXT: br i1 [[CMP2]], label [[LOOP_BODY:%.*]], label [[LOOP_EXIT:%.*]] 683; ATTRIBUTOR: loop.body: 684; ATTRIBUTOR-NEXT: tail call void @fun1(ptr nonnull [[B]]) 685; ATTRIBUTOR-NEXT: tail call void @fun1(ptr nonnull [[A]]) 686; ATTRIBUTOR-NEXT: br label [[LOOP_HEADER]] 687; ATTRIBUTOR: loop.exit: 688; ATTRIBUTOR-NEXT: tail call void @fun1(ptr nonnull [[B]]) 689; ATTRIBUTOR-NEXT: ret void 690; 691 br label %loop.header 692loop.header: 693 %cmp2 = icmp eq i8 %c, 0 694 br i1 %cmp2, label %loop.body, label %loop.exit 695loop.body: 696 tail call void @fun1(ptr nonnull %b) 697 tail call void @fun1(ptr nonnull %a) 698 br label %loop.header 699loop.exit: 700 tail call void @fun1(ptr nonnull %b) 701 ret void 702} 703 704; Test propagation of nonnull callsite args back to caller. 705 706declare void @use1(ptr %x) 707declare void @use2(ptr %x, ptr %y); 708declare void @use3(ptr %x, ptr %y, ptr %z); 709 710declare void @use1nonnull(ptr nonnull noundef %x); 711declare void @use1nonnull_without_noundef(ptr nonnull %x); 712declare void @use2nonnull(ptr nonnull noundef %x, ptr nonnull noundef %y); 713declare void @use3nonnull(ptr nonnull noundef %x, ptr nonnull noundef %y, ptr nonnull noundef %z); 714 715declare i8 @use1safecall(ptr %x) nounwind willreturn ; nounwind+willreturn guarantees that execution continues to successor 716 717; Without noundef, nonnull cannot be propagated to the parent 718 719define void @parent_poison(ptr %a) { 720; FNATTR-LABEL: @parent_poison(ptr %a) 721; FNATTRS-LABEL: define void @parent_poison( 722; FNATTRS-SAME: ptr [[A:%.*]]) { 723; FNATTRS-NEXT: call void @use1nonnull_without_noundef(ptr [[A]]) 724; FNATTRS-NEXT: ret void 725; 726; ATTRIBUTOR-LABEL: define void @parent_poison( 727; ATTRIBUTOR-SAME: ptr nonnull [[A:%.*]]) { 728; ATTRIBUTOR-NEXT: call void @use1nonnull_without_noundef(ptr nonnull [[A]]) 729; ATTRIBUTOR-NEXT: ret void 730; 731 call void @use1nonnull_without_noundef(ptr %a) 732 ret void 733} 734 735; Can't extend non-null to parent for any argument because the 2nd call is not guaranteed to execute. 736 737define void @parent1(ptr %a, ptr %b, ptr %c) { 738; COMMON-LABEL: define void @parent1( 739; COMMON-SAME: ptr [[A:%.*]], ptr [[B:%.*]], ptr [[C:%.*]]) { 740; COMMON-NEXT: call void @use3(ptr [[C]], ptr [[A]], ptr [[B]]) 741; COMMON-NEXT: call void @use3nonnull(ptr [[B]], ptr [[C]], ptr [[A]]) 742; COMMON-NEXT: ret void 743; 744 call void @use3(ptr %c, ptr %a, ptr %b) 745 call void @use3nonnull(ptr %b, ptr %c, ptr %a) 746 ret void 747} 748 749; Extend non-null to parent for all arguments. 750 751define void @parent2(ptr %a, ptr %b, ptr %c) { 752; FNATTRS-LABEL: define void @parent2( 753; FNATTRS-SAME: ptr nonnull [[A:%.*]], ptr nonnull [[B:%.*]], ptr nonnull [[C:%.*]]) { 754; FNATTRS-NEXT: call void @use3nonnull(ptr [[B]], ptr [[C]], ptr [[A]]) 755; FNATTRS-NEXT: call void @use3(ptr [[C]], ptr [[A]], ptr [[B]]) 756; FNATTRS-NEXT: ret void 757; 758; ATTRIBUTOR-LABEL: define void @parent2( 759; ATTRIBUTOR-SAME: ptr nonnull [[A:%.*]], ptr nonnull [[B:%.*]], ptr nonnull [[C:%.*]]) { 760; ATTRIBUTOR-NEXT: call void @use3nonnull(ptr nonnull [[B]], ptr nonnull [[C]], ptr nonnull [[A]]) 761; ATTRIBUTOR-NEXT: call void @use3(ptr [[C]], ptr [[A]], ptr [[B]]) 762; ATTRIBUTOR-NEXT: ret void 763; 764 765 766 call void @use3nonnull(ptr %b, ptr %c, ptr %a) 767 call void @use3(ptr %c, ptr %a, ptr %b) 768 ret void 769} 770 771; Extend non-null to parent for 1st argument. 772 773define void @parent3(ptr %a, ptr %b, ptr %c) { 774; FNATTRS-LABEL: define void @parent3( 775; FNATTRS-SAME: ptr nonnull [[A:%.*]], ptr [[B:%.*]], ptr [[C:%.*]]) { 776; FNATTRS-NEXT: call void @use1nonnull(ptr [[A]]) 777; FNATTRS-NEXT: call void @use3(ptr [[C]], ptr [[B]], ptr [[A]]) 778; FNATTRS-NEXT: ret void 779; 780; ATTRIBUTOR-LABEL: define void @parent3( 781; ATTRIBUTOR-SAME: ptr nonnull [[A:%.*]], ptr [[B:%.*]], ptr [[C:%.*]]) { 782; ATTRIBUTOR-NEXT: call void @use1nonnull(ptr nonnull [[A]]) 783; ATTRIBUTOR-NEXT: call void @use3(ptr [[C]], ptr [[B]], ptr [[A]]) 784; ATTRIBUTOR-NEXT: ret void 785; 786 787 788 789 call void @use1nonnull(ptr %a) 790 call void @use3(ptr %c, ptr %b, ptr %a) 791 ret void 792} 793 794; Extend non-null to parent for last 2 arguments. 795 796define void @parent4(ptr %a, ptr %b, ptr %c) { 797; CHECK-LABEL: @parent4(ptr %a, ptr nonnull %b, ptr nonnull %c) 798; CHECK-NEXT: call void @use2nonnull(ptr %c, ptr %b) 799; CHECK-NEXT: call void @use2(ptr %a, ptr %c) 800; CHECK-NEXT: call void @use1(ptr %b) 801; FNATTRS-LABEL: define void @parent4( 802; FNATTRS-SAME: ptr [[A:%.*]], ptr nonnull [[B:%.*]], ptr nonnull [[C:%.*]]) { 803; FNATTRS-NEXT: call void @use2nonnull(ptr [[C]], ptr [[B]]) 804; FNATTRS-NEXT: call void @use2(ptr [[A]], ptr [[C]]) 805; FNATTRS-NEXT: call void @use1(ptr [[B]]) 806; FNATTRS-NEXT: ret void 807; 808; ATTRIBUTOR-LABEL: define void @parent4( 809; ATTRIBUTOR-SAME: ptr [[A:%.*]], ptr nonnull [[B:%.*]], ptr nonnull [[C:%.*]]) { 810; ATTRIBUTOR-NEXT: call void @use2nonnull(ptr nonnull [[C]], ptr nonnull [[B]]) 811; ATTRIBUTOR-NEXT: call void @use2(ptr [[A]], ptr [[C]]) 812; ATTRIBUTOR-NEXT: call void @use1(ptr [[B]]) 813; ATTRIBUTOR-NEXT: ret void 814; 815 816 call void @use2nonnull(ptr %c, ptr %b) 817 call void @use2(ptr %a, ptr %c) 818 call void @use1(ptr %b) 819 ret void 820} 821 822; The callsite must execute in order for the attribute to transfer to the parent. 823; It appears benign to extend non-null to the parent in this case, but we can't do that 824; because it would incorrectly propagate the wrong information to its callers. 825 826define void @parent5(ptr %a, i1 %a_is_notnull) { 827; FNATTRS-LABEL: define void @parent5( 828; FNATTRS-SAME: ptr [[A:%.*]], i1 [[A_IS_NOTNULL:%.*]]) { 829; FNATTRS-NEXT: br i1 [[A_IS_NOTNULL]], label [[T:%.*]], label [[F:%.*]] 830; FNATTRS: t: 831; FNATTRS-NEXT: call void @use1nonnull(ptr [[A]]) 832; FNATTRS-NEXT: ret void 833; FNATTRS: f: 834; FNATTRS-NEXT: ret void 835; 836; ATTRIBUTOR-LABEL: define void @parent5( 837; ATTRIBUTOR-SAME: ptr [[A:%.*]], i1 [[A_IS_NOTNULL:%.*]]) { 838; ATTRIBUTOR-NEXT: br i1 [[A_IS_NOTNULL]], label [[T:%.*]], label [[F:%.*]] 839; ATTRIBUTOR: t: 840; ATTRIBUTOR-NEXT: call void @use1nonnull(ptr nonnull [[A]]) 841; ATTRIBUTOR-NEXT: ret void 842; ATTRIBUTOR: f: 843; ATTRIBUTOR-NEXT: ret void 844; 845 846 br i1 %a_is_notnull, label %t, label %f 847t: 848 call void @use1nonnull(ptr %a) 849 ret void 850f: 851 ret void 852} 853 854; The callsite must execute in order for the attribute to transfer to the parent. 855; The volatile load can't trap, so we can guarantee that we'll get to the call. 856 857define i8 @parent6(ptr %a, ptr %b) { 858; FNATTRS-LABEL: define i8 @parent6( 859; FNATTRS-SAME: ptr nonnull [[A:%.*]], ptr [[B:%.*]]) { 860; FNATTRS-NEXT: [[C:%.*]] = load volatile i8, ptr [[B]], align 1 861; FNATTRS-NEXT: call void @use1nonnull(ptr [[A]]) 862; FNATTRS-NEXT: ret i8 [[C]] 863; 864; ATTRIBUTOR-LABEL: define i8 @parent6( 865; ATTRIBUTOR-SAME: ptr nonnull [[A:%.*]], ptr nofree [[B:%.*]]) { 866; ATTRIBUTOR-NEXT: [[C:%.*]] = load volatile i8, ptr [[B]], align 1 867; ATTRIBUTOR-NEXT: call void @use1nonnull(ptr nonnull [[A]]) 868; ATTRIBUTOR-NEXT: ret i8 [[C]] 869; 870 871 %c = load volatile i8, ptr %b 872 call void @use1nonnull(ptr %a) 873 ret i8 %c 874} 875 876; The nonnull callsite is guaranteed to execute, so the argument must be nonnull throughout the parent. 877 878define i8 @parent7(ptr %a) { 879; FNATTRS-LABEL: define i8 @parent7( 880; FNATTRS-SAME: ptr nonnull [[A:%.*]]) { 881; FNATTRS-NEXT: [[RET:%.*]] = call i8 @use1safecall(ptr [[A]]) 882; FNATTRS-NEXT: call void @use1nonnull(ptr [[A]]) 883; FNATTRS-NEXT: ret i8 [[RET]] 884; 885; ATTRIBUTOR-LABEL: define i8 @parent7( 886; ATTRIBUTOR-SAME: ptr nonnull [[A:%.*]]) { 887; ATTRIBUTOR-NEXT: [[RET:%.*]] = call i8 @use1safecall(ptr nonnull [[A]]) #[[ATTR15]] 888; ATTRIBUTOR-NEXT: call void @use1nonnull(ptr nonnull [[A]]) 889; ATTRIBUTOR-NEXT: ret i8 [[RET]] 890; 891 892 893 894 895 %ret = call i8 @use1safecall(ptr %a) 896 call void @use1nonnull(ptr %a) 897 ret i8 %ret 898} 899 900; Make sure that an invoke works similarly to a call. 901 902declare i32 @esfp(...) 903 904define i1 @parent8(ptr %a, ptr %bogus1, ptr %b) personality ptr @esfp{ 905; FNATTRS-LABEL: define noundef i1 @parent8( 906; FNATTRS-SAME: ptr nonnull [[A:%.*]], ptr readnone captures(none) [[BOGUS1:%.*]], ptr nonnull [[B:%.*]]) #[[ATTR7]] personality ptr @esfp { 907; FNATTRS-NEXT: entry: 908; FNATTRS-NEXT: invoke void @use2nonnull(ptr [[A]], ptr [[B]]) 909; FNATTRS-NEXT: to label [[CONT:%.*]] unwind label [[EXC:%.*]] 910; FNATTRS: cont: 911; FNATTRS-NEXT: [[NULL_CHECK:%.*]] = icmp eq ptr [[B]], null 912; FNATTRS-NEXT: ret i1 [[NULL_CHECK]] 913; FNATTRS: exc: 914; FNATTRS-NEXT: [[LP:%.*]] = landingpad { ptr, i32 } 915; FNATTRS-NEXT: filter [0 x ptr] zeroinitializer 916; FNATTRS-NEXT: unreachable 917; 918; ATTRIBUTOR-LABEL: define i1 @parent8( 919; ATTRIBUTOR-SAME: ptr nonnull [[A:%.*]], ptr nofree readnone captures(none) [[BOGUS1:%.*]], ptr nonnull [[B:%.*]]) #[[ATTR7]] personality ptr @esfp { 920; ATTRIBUTOR-NEXT: entry: 921; ATTRIBUTOR-NEXT: invoke void @use2nonnull(ptr nonnull [[A]], ptr nonnull [[B]]) 922; ATTRIBUTOR-NEXT: to label [[CONT:%.*]] unwind label [[EXC:%.*]] 923; ATTRIBUTOR: cont: 924; ATTRIBUTOR-NEXT: [[NULL_CHECK:%.*]] = icmp eq ptr [[B]], null 925; ATTRIBUTOR-NEXT: ret i1 [[NULL_CHECK]] 926; ATTRIBUTOR: exc: 927; ATTRIBUTOR-NEXT: [[LP:%.*]] = landingpad { ptr, i32 } 928; ATTRIBUTOR-NEXT: filter [0 x ptr] zeroinitializer 929; ATTRIBUTOR-NEXT: unreachable 930; 931 932entry: 933 invoke void @use2nonnull(ptr %a, ptr %b) 934 to label %cont unwind label %exc 935 936cont: 937 %null_check = icmp eq ptr %b, null 938 ret i1 %null_check 939 940exc: 941 %lp = landingpad { ptr, i32 } 942 filter [0 x ptr] zeroinitializer 943 unreachable 944} 945 946define ptr @gep1(ptr %p) { 947; FNATTRS-LABEL: define nonnull ptr @gep1( 948; FNATTRS-SAME: ptr readnone [[P:%.*]]) #[[ATTR0]] { 949; FNATTRS-NEXT: [[Q:%.*]] = getelementptr inbounds i32, ptr [[P]], i32 1 950; FNATTRS-NEXT: ret ptr [[Q]] 951; 952; ATTRIBUTOR-LABEL: define nonnull ptr @gep1( 953; ATTRIBUTOR-SAME: ptr nofree readnone [[P:%.*]]) #[[ATTR0]] { 954; ATTRIBUTOR-NEXT: [[Q:%.*]] = getelementptr inbounds i32, ptr [[P]], i32 1 955; ATTRIBUTOR-NEXT: ret ptr [[Q]] 956; 957 %q = getelementptr inbounds i32, ptr %p, i32 1 958 ret ptr %q 959} 960 961define ptr @gep1_no_null_opt(ptr %p) #0 { 962; Should't be able to derive nonnull based on gep. 963; FNATTRS-LABEL: define ptr @gep1_no_null_opt( 964; FNATTRS-SAME: ptr readnone [[P:%.*]]) #[[ATTR8:[0-9]+]] { 965; FNATTRS-NEXT: [[Q:%.*]] = getelementptr inbounds i32, ptr [[P]], i32 1 966; FNATTRS-NEXT: ret ptr [[Q]] 967; 968; ATTRIBUTOR-LABEL: define ptr @gep1_no_null_opt( 969; ATTRIBUTOR-SAME: ptr nofree readnone [[P:%.*]]) #[[ATTR8:[0-9]+]] { 970; ATTRIBUTOR-NEXT: [[Q:%.*]] = getelementptr inbounds i32, ptr [[P]], i32 1 971; ATTRIBUTOR-NEXT: ret ptr [[Q]] 972; 973 %q = getelementptr inbounds i32, ptr %p, i32 1 974 ret ptr %q 975} 976 977define ptr addrspace(3) @gep2(ptr addrspace(3) %p) { 978; FNATTRS-LABEL: define ptr addrspace(3) @gep2( 979; FNATTRS-SAME: ptr addrspace(3) readnone [[P:%.*]]) #[[ATTR0]] { 980; FNATTRS-NEXT: [[Q:%.*]] = getelementptr inbounds i32, ptr addrspace(3) [[P]], i32 1 981; FNATTRS-NEXT: ret ptr addrspace(3) [[Q]] 982; 983; ATTRIBUTOR-LABEL: define ptr addrspace(3) @gep2( 984; ATTRIBUTOR-SAME: ptr addrspace(3) nofree readnone [[P:%.*]]) #[[ATTR0]] { 985; ATTRIBUTOR-NEXT: [[Q:%.*]] = getelementptr inbounds i32, ptr addrspace(3) [[P]], i32 1 986; ATTRIBUTOR-NEXT: ret ptr addrspace(3) [[Q]] 987; 988 %q = getelementptr inbounds i32, ptr addrspace(3) %p, i32 1 989 ret ptr addrspace(3) %q 990} 991 992; FIXME: We should propagate dereferenceable here but *not* nonnull 993define ptr addrspace(3) @as(ptr addrspace(3) dereferenceable(4) %p) { 994; FNATTRS-LABEL: define noundef ptr addrspace(3) @as( 995; FNATTRS-SAME: ptr addrspace(3) readnone returned dereferenceable(4) [[P:%.*]]) #[[ATTR0]] { 996; FNATTRS-NEXT: ret ptr addrspace(3) [[P]] 997; 998; ATTRIBUTOR-LABEL: define ptr addrspace(3) @as( 999; ATTRIBUTOR-SAME: ptr addrspace(3) nofree readnone dereferenceable(4) [[P:%.*]]) #[[ATTR0]] { 1000; ATTRIBUTOR-NEXT: ret ptr addrspace(3) [[P]] 1001; 1002 ret ptr addrspace(3) %p 1003} 1004 1005define internal ptr @g2() { 1006; FNATTRS-LABEL: define internal noundef nonnull ptr @g2( 1007; FNATTRS-SAME: ) #[[ATTR0]] { 1008; FNATTRS-NEXT: ret ptr inttoptr (i64 4 to ptr) 1009; 1010; ATTRIBUTOR-LABEL: define internal nonnull ptr @g2( 1011; ATTRIBUTOR-SAME: ) #[[ATTR0]] { 1012; ATTRIBUTOR-NEXT: ret ptr inttoptr (i64 4 to ptr) 1013; 1014 ret ptr inttoptr (i64 4 to ptr) 1015} 1016 1017define ptr @g1() { 1018; FNATTRS-LABEL: define noundef nonnull ptr @g1( 1019; FNATTRS-SAME: ) #[[ATTR0]] { 1020; FNATTRS-NEXT: [[C:%.*]] = call ptr @g2() 1021; FNATTRS-NEXT: ret ptr [[C]] 1022; 1023; ATTRIBUTOR-LABEL: define ptr @g1( 1024; ATTRIBUTOR-SAME: ) #[[ATTR0]] { 1025; ATTRIBUTOR-NEXT: [[C:%.*]] = call ptr @g2() #[[ATTR16:[0-9]+]] 1026; ATTRIBUTOR-NEXT: ret ptr [[C]] 1027; 1028 %c = call ptr @g2() 1029 ret ptr %c 1030} 1031 1032declare void @use_i32_ptr(ptr) readnone nounwind 1033define internal void @called_by_weak(ptr %a) { 1034; FNATTRS-LABEL: define internal void @called_by_weak( 1035; FNATTRS-SAME: ptr readnone captures(none) [[A:%.*]]) #[[ATTR1]] { 1036; FNATTRS-NEXT: call void @use_i32_ptr(ptr [[A]]) 1037; FNATTRS-NEXT: ret void 1038; 1039; ATTRIBUTOR-LABEL: define internal void @called_by_weak( 1040; ATTRIBUTOR-SAME: ptr nonnull readnone captures(none) [[A:%.*]]) #[[ATTR10:[0-9]+]] { 1041; ATTRIBUTOR-NEXT: call void @use_i32_ptr(ptr nonnull [[A]]) #[[ATTR17:[0-9]+]] 1042; ATTRIBUTOR-NEXT: ret void 1043; 1044 call void @use_i32_ptr(ptr %a) 1045 ret void 1046} 1047 1048; Check we do not annotate the function interface of this weak function. 1049define weak_odr void @weak_caller(ptr nonnull %a) { 1050; FNATTRS-LABEL: define weak_odr void @weak_caller( 1051; FNATTRS-SAME: ptr nonnull [[A:%.*]]) { 1052; FNATTRS-NEXT: call void @called_by_weak(ptr [[A]]) 1053; FNATTRS-NEXT: ret void 1054; 1055; ATTRIBUTOR-LABEL: define weak_odr void @weak_caller( 1056; ATTRIBUTOR-SAME: ptr nonnull [[A:%.*]]) { 1057; ATTRIBUTOR-NEXT: call void @called_by_weak(ptr nonnull readnone captures(none) [[A]]) 1058; ATTRIBUTOR-NEXT: ret void 1059; 1060 call void @called_by_weak(ptr %a) 1061 ret void 1062} 1063 1064; Expect nonnull 1065define internal void @control(ptr dereferenceable(4) %a) { 1066; FNATTRS-LABEL: define internal void @control( 1067; FNATTRS-SAME: ptr readnone captures(none) dereferenceable(4) [[A:%.*]]) #[[ATTR1]] { 1068; FNATTRS-NEXT: call void @use_i32_ptr(ptr [[A]]) 1069; FNATTRS-NEXT: ret void 1070; 1071; ATTRIBUTOR-LABEL: define internal void @control( 1072; ATTRIBUTOR-SAME: ptr nonnull readnone captures(none) dereferenceable(4) [[A:%.*]]) #[[ATTR10]] { 1073; ATTRIBUTOR-NEXT: call void @use_i32_ptr(ptr [[A]]) #[[ATTR17]] 1074; ATTRIBUTOR-NEXT: ret void 1075; 1076 call void @use_i32_ptr(ptr %a) 1077 ret void 1078} 1079; Avoid nonnull as we do not touch naked functions 1080define internal void @naked(ptr dereferenceable(4) %a) naked { 1081; FNATTRS-LABEL: define internal void @naked( 1082; FNATTRS-SAME: ptr dereferenceable(4) [[A:%.*]]) #[[ATTR10:[0-9]+]] { 1083; FNATTRS-NEXT: ret void 1084; 1085; ATTRIBUTOR-LABEL: define internal void @naked( 1086; ATTRIBUTOR-SAME: ptr nonnull dereferenceable(4) [[A:%.*]]) #[[ATTR11:[0-9]+]] { 1087; ATTRIBUTOR-NEXT: ret void 1088; 1089 ret void 1090} 1091; Avoid nonnull as we do not touch optnone 1092define internal void @optnone(ptr dereferenceable(4) %a) optnone noinline { 1093; FNATTRS-LABEL: define internal void @optnone( 1094; FNATTRS-SAME: ptr dereferenceable(4) [[A:%.*]]) #[[ATTR11:[0-9]+]] { 1095; FNATTRS-NEXT: call void @use_i32_ptr(ptr [[A]]) 1096; FNATTRS-NEXT: ret void 1097; 1098; ATTRIBUTOR-LABEL: define internal void @optnone( 1099; ATTRIBUTOR-SAME: ptr nonnull dereferenceable(4) [[A:%.*]]) #[[ATTR12:[0-9]+]] { 1100; ATTRIBUTOR-NEXT: call void @use_i32_ptr(ptr [[A]]) 1101; ATTRIBUTOR-NEXT: ret void 1102; 1103 call void @use_i32_ptr(ptr %a) 1104 ret void 1105} 1106define void @make_live(ptr nonnull dereferenceable(8) %a) { 1107; FNATTRS-LABEL: define void @make_live( 1108; FNATTRS-SAME: ptr nonnull dereferenceable(8) [[A:%.*]]) { 1109; FNATTRS-NEXT: call void @naked(ptr nonnull align 16 dereferenceable(8) [[A]]) 1110; FNATTRS-NEXT: call void @control(ptr nonnull align 16 dereferenceable(8) [[A]]) 1111; FNATTRS-NEXT: call void @optnone(ptr nonnull align 16 dereferenceable(8) [[A]]) 1112; FNATTRS-NEXT: ret void 1113; 1114; ATTRIBUTOR-LABEL: define void @make_live( 1115; ATTRIBUTOR-SAME: ptr nonnull dereferenceable(8) [[A:%.*]]) { 1116; ATTRIBUTOR-NEXT: call void @naked(ptr nonnull align 16 dereferenceable(8) [[A]]) 1117; ATTRIBUTOR-NEXT: call void @control(ptr nonnull readnone align 16 captures(none) dereferenceable(8) [[A]]) 1118; ATTRIBUTOR-NEXT: call void @optnone(ptr nonnull align 16 dereferenceable(8) [[A]]) 1119; ATTRIBUTOR-NEXT: ret void 1120; 1121 call void @naked(ptr nonnull dereferenceable(8) align 16 %a) 1122 call void @control(ptr nonnull dereferenceable(8) align 16 %a) 1123 call void @optnone(ptr nonnull dereferenceable(8) align 16 %a) 1124 ret void 1125} 1126 1127;int f(int *u, int n){ 1128; for(int i = 0;i<n;i++){ 1129; h(u); 1130; } 1131; return g(nonnull u); 1132;} 1133declare void @h(ptr) willreturn nounwind 1134declare i32 @g(ptr) willreturn nounwind 1135define i32 @nonnull_exec_ctx_1(ptr %a, i32 %b) { 1136; COMMON-LABEL: define i32 @nonnull_exec_ctx_1( 1137; COMMON-SAME: ptr [[A:%.*]], i32 [[B:%.*]]) #[[ATTR7:[0-9]+]] { 1138; COMMON-NEXT: en: 1139; COMMON-NEXT: [[TMP3:%.*]] = icmp eq i32 [[B]], 0 1140; COMMON-NEXT: br i1 [[TMP3]], label [[EX:%.*]], label [[HD:%.*]] 1141; COMMON: ex: 1142; COMMON-NEXT: [[TMP5:%.*]] = tail call i32 @g(ptr nonnull [[A]]) 1143; COMMON-NEXT: ret i32 [[TMP5]] 1144; COMMON: hd: 1145; COMMON-NEXT: [[TMP7:%.*]] = phi i32 [ [[TMP8:%.*]], [[HD]] ], [ 0, [[EN:%.*]] ] 1146; COMMON-NEXT: tail call void @h(ptr [[A]]) 1147; COMMON-NEXT: [[TMP8]] = add nuw i32 [[TMP7]], 1 1148; COMMON-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], [[B]] 1149; COMMON-NEXT: br i1 [[TMP9]], label [[EX]], label [[HD]] 1150; 1151en: 1152 %tmp3 = icmp eq i32 %b, 0 1153 br i1 %tmp3, label %ex, label %hd 1154 1155ex: 1156 %tmp5 = tail call i32 @g(ptr nonnull %a) 1157 ret i32 %tmp5 1158 1159hd: 1160 %tmp7 = phi i32 [ %tmp8, %hd ], [ 0, %en ] 1161 tail call void @h(ptr %a) 1162 %tmp8 = add nuw i32 %tmp7, 1 1163 %tmp9 = icmp eq i32 %tmp8, %b 1164 br i1 %tmp9, label %ex, label %hd 1165} 1166 1167define i32 @nonnull_exec_ctx_1b(ptr %a, i32 %b) { 1168; COMMON-LABEL: define i32 @nonnull_exec_ctx_1b( 1169; COMMON-SAME: ptr [[A:%.*]], i32 [[B:%.*]]) #[[ATTR7]] { 1170; COMMON-NEXT: en: 1171; COMMON-NEXT: [[TMP3:%.*]] = icmp eq i32 [[B]], 0 1172; COMMON-NEXT: br i1 [[TMP3]], label [[EX:%.*]], label [[HD:%.*]] 1173; COMMON: ex: 1174; COMMON-NEXT: [[TMP5:%.*]] = tail call i32 @g(ptr nonnull [[A]]) 1175; COMMON-NEXT: ret i32 [[TMP5]] 1176; COMMON: hd: 1177; COMMON-NEXT: [[TMP7:%.*]] = phi i32 [ [[TMP8:%.*]], [[HD2:%.*]] ], [ 0, [[EN:%.*]] ] 1178; COMMON-NEXT: tail call void @h(ptr [[A]]) 1179; COMMON-NEXT: br label [[HD2]] 1180; COMMON: hd2: 1181; COMMON-NEXT: [[TMP8]] = add nuw i32 [[TMP7]], 1 1182; COMMON-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], [[B]] 1183; COMMON-NEXT: br i1 [[TMP9]], label [[EX]], label [[HD]] 1184; 1185en: 1186 %tmp3 = icmp eq i32 %b, 0 1187 br i1 %tmp3, label %ex, label %hd 1188 1189ex: 1190 %tmp5 = tail call i32 @g(ptr nonnull %a) 1191 ret i32 %tmp5 1192 1193hd: 1194 %tmp7 = phi i32 [ %tmp8, %hd2 ], [ 0, %en ] 1195 tail call void @h(ptr %a) 1196 br label %hd2 1197 1198hd2: 1199 %tmp8 = add nuw i32 %tmp7, 1 1200 %tmp9 = icmp eq i32 %tmp8, %b 1201 br i1 %tmp9, label %ex, label %hd 1202} 1203 1204define i32 @nonnull_exec_ctx_2(ptr %a, i32 %b) willreturn nounwind { 1205; FNATTRS-LABEL: define i32 @nonnull_exec_ctx_2( 1206; FNATTRS-SAME: ptr [[A:%.*]], i32 [[B:%.*]]) #[[ATTR6]] { 1207; FNATTRS-NEXT: en: 1208; FNATTRS-NEXT: [[TMP3:%.*]] = icmp eq i32 [[B]], 0 1209; FNATTRS-NEXT: br i1 [[TMP3]], label [[EX:%.*]], label [[HD:%.*]] 1210; FNATTRS: ex: 1211; FNATTRS-NEXT: [[TMP5:%.*]] = tail call i32 @g(ptr nonnull [[A]]) 1212; FNATTRS-NEXT: ret i32 [[TMP5]] 1213; FNATTRS: hd: 1214; FNATTRS-NEXT: [[TMP7:%.*]] = phi i32 [ [[TMP8:%.*]], [[HD]] ], [ 0, [[EN:%.*]] ] 1215; FNATTRS-NEXT: tail call void @h(ptr [[A]]) 1216; FNATTRS-NEXT: [[TMP8]] = add nuw i32 [[TMP7]], 1 1217; FNATTRS-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], [[B]] 1218; FNATTRS-NEXT: br i1 [[TMP9]], label [[EX]], label [[HD]] 1219; 1220; ATTRIBUTOR-LABEL: define i32 @nonnull_exec_ctx_2( 1221; ATTRIBUTOR-SAME: ptr nonnull [[A:%.*]], i32 [[B:%.*]]) #[[ATTR6]] { 1222; ATTRIBUTOR-NEXT: en: 1223; ATTRIBUTOR-NEXT: [[TMP3:%.*]] = icmp eq i32 [[B]], 0 1224; ATTRIBUTOR-NEXT: br i1 [[TMP3]], label [[EX:%.*]], label [[HD:%.*]] 1225; ATTRIBUTOR: ex: 1226; ATTRIBUTOR-NEXT: [[TMP5:%.*]] = tail call i32 @g(ptr nonnull [[A]]) 1227; ATTRIBUTOR-NEXT: ret i32 [[TMP5]] 1228; ATTRIBUTOR: hd: 1229; ATTRIBUTOR-NEXT: [[TMP7:%.*]] = phi i32 [ [[TMP8:%.*]], [[HD]] ], [ 0, [[EN:%.*]] ] 1230; ATTRIBUTOR-NEXT: tail call void @h(ptr nonnull [[A]]) 1231; ATTRIBUTOR-NEXT: [[TMP8]] = add nuw i32 [[TMP7]], 1 1232; ATTRIBUTOR-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], [[B]] 1233; ATTRIBUTOR-NEXT: br i1 [[TMP9]], label [[EX]], label [[HD]] 1234; 1235en: 1236 %tmp3 = icmp eq i32 %b, 0 1237 br i1 %tmp3, label %ex, label %hd 1238 1239ex: 1240 %tmp5 = tail call i32 @g(ptr nonnull %a) 1241 ret i32 %tmp5 1242 1243hd: 1244 %tmp7 = phi i32 [ %tmp8, %hd ], [ 0, %en ] 1245 tail call void @h(ptr %a) 1246 %tmp8 = add nuw i32 %tmp7, 1 1247 %tmp9 = icmp eq i32 %tmp8, %b 1248 br i1 %tmp9, label %ex, label %hd 1249} 1250 1251define i32 @nonnull_exec_ctx_2b(ptr %a, i32 %b) willreturn nounwind { 1252; FNATTRS-LABEL: define i32 @nonnull_exec_ctx_2b( 1253; FNATTRS-SAME: ptr [[A:%.*]], i32 [[B:%.*]]) #[[ATTR6]] { 1254; FNATTRS-NEXT: en: 1255; FNATTRS-NEXT: [[TMP3:%.*]] = icmp eq i32 [[B]], 0 1256; FNATTRS-NEXT: br i1 [[TMP3]], label [[EX:%.*]], label [[HD:%.*]] 1257; FNATTRS: ex: 1258; FNATTRS-NEXT: [[TMP5:%.*]] = tail call i32 @g(ptr nonnull [[A]]) 1259; FNATTRS-NEXT: ret i32 [[TMP5]] 1260; FNATTRS: hd: 1261; FNATTRS-NEXT: [[TMP7:%.*]] = phi i32 [ [[TMP8:%.*]], [[HD2:%.*]] ], [ 0, [[EN:%.*]] ] 1262; FNATTRS-NEXT: tail call void @h(ptr [[A]]) 1263; FNATTRS-NEXT: br label [[HD2]] 1264; FNATTRS: hd2: 1265; FNATTRS-NEXT: [[TMP8]] = add nuw i32 [[TMP7]], 1 1266; FNATTRS-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], [[B]] 1267; FNATTRS-NEXT: br i1 [[TMP9]], label [[EX]], label [[HD]] 1268; 1269; ATTRIBUTOR-LABEL: define i32 @nonnull_exec_ctx_2b( 1270; ATTRIBUTOR-SAME: ptr nonnull [[A:%.*]], i32 [[B:%.*]]) #[[ATTR6]] { 1271; ATTRIBUTOR-NEXT: en: 1272; ATTRIBUTOR-NEXT: [[TMP3:%.*]] = icmp eq i32 [[B]], 0 1273; ATTRIBUTOR-NEXT: br i1 [[TMP3]], label [[EX:%.*]], label [[HD:%.*]] 1274; ATTRIBUTOR: ex: 1275; ATTRIBUTOR-NEXT: [[TMP5:%.*]] = tail call i32 @g(ptr nonnull [[A]]) 1276; ATTRIBUTOR-NEXT: ret i32 [[TMP5]] 1277; ATTRIBUTOR: hd: 1278; ATTRIBUTOR-NEXT: [[TMP7:%.*]] = phi i32 [ [[TMP8:%.*]], [[HD2:%.*]] ], [ 0, [[EN:%.*]] ] 1279; ATTRIBUTOR-NEXT: tail call void @h(ptr nonnull [[A]]) 1280; ATTRIBUTOR-NEXT: br label [[HD2]] 1281; ATTRIBUTOR: hd2: 1282; ATTRIBUTOR-NEXT: [[TMP8]] = add nuw i32 [[TMP7]], 1 1283; ATTRIBUTOR-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], [[B]] 1284; ATTRIBUTOR-NEXT: br i1 [[TMP9]], label [[EX]], label [[HD]] 1285; 1286en: 1287 %tmp3 = icmp eq i32 %b, 0 1288 br i1 %tmp3, label %ex, label %hd 1289 1290ex: 1291 %tmp5 = tail call i32 @g(ptr nonnull %a) 1292 ret i32 %tmp5 1293 1294hd: 1295 %tmp7 = phi i32 [ %tmp8, %hd2 ], [ 0, %en ] 1296 tail call void @h(ptr %a) 1297 br label %hd2 1298 1299hd2: 1300 %tmp8 = add nuw i32 %tmp7, 1 1301 %tmp9 = icmp eq i32 %tmp8, %b 1302 br i1 %tmp9, label %ex, label %hd 1303} 1304 1305; Original from PR43833 1306declare void @sink(ptr) 1307 1308; FIXME: the sink argument should be marked nonnull as in @PR43833_simple. 1309define void @PR43833(ptr %0, i32 %1) { 1310; COMMON-LABEL: define void @PR43833( 1311; COMMON-SAME: ptr [[TMP0:%.*]], i32 [[TMP1:%.*]]) { 1312; COMMON-NEXT: [[TMP3:%.*]] = icmp sgt i32 [[TMP1]], 1 1313; COMMON-NEXT: br i1 [[TMP3]], label [[TMP4:%.*]], label [[TMP7:%.*]] 1314; COMMON: 4: 1315; COMMON-NEXT: [[TMP5:%.*]] = zext i32 [[TMP1]] to i64 1316; COMMON-NEXT: [[TMP6:%.*]] = getelementptr inbounds i32, ptr [[TMP0]], i64 [[TMP5]] 1317; COMMON-NEXT: br label [[TMP8:%.*]] 1318; COMMON: 7: 1319; COMMON-NEXT: ret void 1320; COMMON: 8: 1321; COMMON-NEXT: [[TMP9:%.*]] = phi i32 [ 1, [[TMP4]] ], [ [[TMP10:%.*]], [[TMP8]] ] 1322; COMMON-NEXT: tail call void @sink(ptr [[TMP6]]) 1323; COMMON-NEXT: [[TMP10]] = add nuw nsw i32 [[TMP9]], 1 1324; COMMON-NEXT: [[TMP11:%.*]] = icmp eq i32 [[TMP10]], [[TMP1]] 1325; COMMON-NEXT: br i1 [[TMP11]], label [[TMP7]], label [[TMP8]] 1326; 1327 %3 = icmp sgt i32 %1, 1 1328 br i1 %3, label %4, label %7 1329 13304: ; preds = %2 1331 %5 = zext i32 %1 to i64 1332 %6 = getelementptr inbounds i32, ptr %0, i64 %5 1333 br label %8 1334 13357: ; preds = %8, %2 1336 ret void 1337 13388: ; preds = %8, %4 1339 %9 = phi i32 [ 1, %4 ], [ %10, %8 ] 1340 tail call void @sink(ptr %6) 1341 %10 = add nuw nsw i32 %9, 1 1342 %11 = icmp eq i32 %10, %1 1343 br i1 %11, label %7, label %8 1344} 1345 1346; Adjusted from PR43833 1347define void @PR43833_simple(ptr %0, i32 %1) { 1348; COMMON-LABEL: define void @PR43833_simple( 1349; COMMON-SAME: ptr [[TMP0:%.*]], i32 [[TMP1:%.*]]) { 1350; COMMON-NEXT: [[TMP3:%.*]] = icmp ne i32 [[TMP1]], 0 1351; COMMON-NEXT: br i1 [[TMP3]], label [[TMP4:%.*]], label [[TMP7:%.*]] 1352; COMMON: 4: 1353; COMMON-NEXT: [[TMP5:%.*]] = zext i32 [[TMP1]] to i64 1354; COMMON-NEXT: [[TMP6:%.*]] = getelementptr inbounds i32, ptr [[TMP0]], i64 [[TMP5]] 1355; COMMON-NEXT: br label [[TMP8:%.*]] 1356; COMMON: 7: 1357; COMMON-NEXT: ret void 1358; COMMON: 8: 1359; COMMON-NEXT: [[TMP9:%.*]] = phi i32 [ 1, [[TMP4]] ], [ [[TMP10:%.*]], [[TMP8]] ] 1360; COMMON-NEXT: tail call void @sink(ptr [[TMP6]]) 1361; COMMON-NEXT: [[TMP10]] = add nuw nsw i32 [[TMP9]], 1 1362; COMMON-NEXT: [[TMP11:%.*]] = icmp eq i32 [[TMP10]], [[TMP1]] 1363; COMMON-NEXT: br i1 [[TMP11]], label [[TMP7]], label [[TMP8]] 1364; 1365 %3 = icmp ne i32 %1, 0 1366 br i1 %3, label %4, label %7 1367 13684: ; preds = %2 1369 %5 = zext i32 %1 to i64 1370 %6 = getelementptr inbounds i32, ptr %0, i64 %5 1371 br label %8 1372 13737: ; preds = %8, %2 1374 ret void 1375 13768: ; preds = %8, %4 1377 %9 = phi i32 [ 1, %4 ], [ %10, %8 ] 1378 tail call void @sink(ptr %6) 1379 %10 = add nuw nsw i32 %9, 1 1380 %11 = icmp eq i32 %10, %1 1381 br i1 %11, label %7, label %8 1382} 1383 1384define ptr @pr91177_non_inbounds_gep(ptr nonnull %arg) { 1385; FNATTRS-LABEL: define ptr @pr91177_non_inbounds_gep( 1386; FNATTRS-SAME: ptr nonnull readnone [[ARG:%.*]]) #[[ATTR0]] { 1387; FNATTRS-NEXT: [[RES:%.*]] = getelementptr i8, ptr [[ARG]], i64 -8 1388; FNATTRS-NEXT: ret ptr [[RES]] 1389; 1390; ATTRIBUTOR-LABEL: define ptr @pr91177_non_inbounds_gep( 1391; ATTRIBUTOR-SAME: ptr nofree nonnull readnone [[ARG:%.*]]) #[[ATTR0]] { 1392; ATTRIBUTOR-NEXT: [[RES:%.*]] = getelementptr i8, ptr [[ARG]], i64 -8 1393; ATTRIBUTOR-NEXT: ret ptr [[RES]] 1394; 1395 %res = getelementptr i8, ptr %arg, i64 -8 1396 ret ptr %res 1397} 1398 1399attributes #0 = { null_pointer_is_valid } 1400attributes #1 = { nounwind willreturn} 1401