1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-attributes --version 2 2; RUN: opt -passes=function-attrs -S < %s | FileCheck --check-prefixes=COMMON,FNATTRS %s 3; RUN: opt -passes=attributor-light -S < %s | FileCheck --check-prefixes=COMMON,ATTRIBUTOR %s 4 5@g = global ptr null ; <ptr> [#uses=1] 6 7define ptr @c1(ptr %q) { 8; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 9; FNATTRS-LABEL: define ptr @c1 10; FNATTRS-SAME: (ptr readnone returned [[Q:%.*]]) #[[ATTR0:[0-9]+]] { 11; FNATTRS-NEXT: ret ptr [[Q]] 12; 13; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 14; ATTRIBUTOR-LABEL: define ptr @c1 15; ATTRIBUTOR-SAME: (ptr nofree readnone [[Q:%.*]]) #[[ATTR0:[0-9]+]] { 16; ATTRIBUTOR-NEXT: ret ptr [[Q]] 17; 18 ret ptr %q 19} 20 21; It would also be acceptable to mark %q as readnone. Update @c3 too. 22define void @c2(ptr %q) { 23; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write, argmem: none, inaccessiblemem: none) 24; FNATTRS-LABEL: define void @c2 25; FNATTRS-SAME: (ptr [[Q:%.*]]) #[[ATTR1:[0-9]+]] { 26; FNATTRS-NEXT: store ptr [[Q]], ptr @g, align 8 27; FNATTRS-NEXT: ret void 28; 29; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write) 30; ATTRIBUTOR-LABEL: define void @c2 31; ATTRIBUTOR-SAME: (ptr nofree writeonly [[Q:%.*]]) #[[ATTR1:[0-9]+]] { 32; ATTRIBUTOR-NEXT: store ptr [[Q]], ptr @g, align 8 33; ATTRIBUTOR-NEXT: ret void 34; 35 store ptr %q, ptr @g 36 ret void 37} 38 39define void @c3(ptr %q) { 40; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write, inaccessiblemem: none) 41; FNATTRS-LABEL: define void @c3 42; FNATTRS-SAME: (ptr [[Q:%.*]]) #[[ATTR2:[0-9]+]] { 43; FNATTRS-NEXT: call void @c2(ptr [[Q]]) 44; FNATTRS-NEXT: ret void 45; 46; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write) 47; ATTRIBUTOR-LABEL: define void @c3 48; ATTRIBUTOR-SAME: (ptr nofree writeonly [[Q:%.*]]) #[[ATTR1]] { 49; ATTRIBUTOR-NEXT: call void @c2(ptr nofree writeonly [[Q]]) #[[ATTR16:[0-9]+]] 50; ATTRIBUTOR-NEXT: ret void 51; 52 call void @c2(ptr %q) 53 ret void 54} 55 56define i1 @c4(ptr %q, i32 %bitno) { 57; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 58; FNATTRS-LABEL: define noundef i1 @c4 59; FNATTRS-SAME: (ptr [[Q:%.*]], i32 [[BITNO:%.*]]) #[[ATTR0]] { 60; FNATTRS-NEXT: [[TMP:%.*]] = ptrtoint ptr [[Q]] to i32 61; FNATTRS-NEXT: [[TMP2:%.*]] = lshr i32 [[TMP]], [[BITNO]] 62; FNATTRS-NEXT: [[BIT:%.*]] = trunc i32 [[TMP2]] to i1 63; FNATTRS-NEXT: br i1 [[BIT]], label [[L1:%.*]], label [[L0:%.*]] 64; FNATTRS: l0: 65; FNATTRS-NEXT: ret i1 false 66; FNATTRS: l1: 67; FNATTRS-NEXT: ret i1 true 68; 69; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 70; ATTRIBUTOR-LABEL: define i1 @c4 71; ATTRIBUTOR-SAME: (ptr nofree readnone [[Q:%.*]], i32 [[BITNO:%.*]]) #[[ATTR0]] { 72; ATTRIBUTOR-NEXT: [[TMP:%.*]] = ptrtoint ptr [[Q]] to i32 73; ATTRIBUTOR-NEXT: [[TMP2:%.*]] = lshr i32 [[TMP]], [[BITNO]] 74; ATTRIBUTOR-NEXT: [[BIT:%.*]] = trunc i32 [[TMP2]] to i1 75; ATTRIBUTOR-NEXT: br i1 [[BIT]], label [[L1:%.*]], label [[L0:%.*]] 76; ATTRIBUTOR: l0: 77; ATTRIBUTOR-NEXT: ret i1 false 78; ATTRIBUTOR: l1: 79; ATTRIBUTOR-NEXT: ret i1 true 80; 81 %tmp = ptrtoint ptr %q to i32 82 %tmp2 = lshr i32 %tmp, %bitno 83 %bit = trunc i32 %tmp2 to i1 84 br i1 %bit, label %l1, label %l0 85l0: 86 ret i1 0 ; escaping value not caught by def-use chaining. 87l1: 88 ret i1 1 ; escaping value not caught by def-use chaining. 89} 90 91; c4b is c4 but without the escaping part 92define i1 @c4b(ptr %q, i32 %bitno) { 93; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 94; FNATTRS-LABEL: define noundef i1 @c4b 95; FNATTRS-SAME: (ptr [[Q:%.*]], i32 [[BITNO:%.*]]) #[[ATTR0]] { 96; FNATTRS-NEXT: [[TMP:%.*]] = ptrtoint ptr [[Q]] to i32 97; FNATTRS-NEXT: [[TMP2:%.*]] = lshr i32 [[TMP]], [[BITNO]] 98; FNATTRS-NEXT: [[BIT:%.*]] = trunc i32 [[TMP2]] to i1 99; FNATTRS-NEXT: br i1 [[BIT]], label [[L1:%.*]], label [[L0:%.*]] 100; FNATTRS: l0: 101; FNATTRS-NEXT: ret i1 false 102; FNATTRS: l1: 103; FNATTRS-NEXT: ret i1 false 104; 105; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 106; ATTRIBUTOR-LABEL: define i1 @c4b 107; ATTRIBUTOR-SAME: (ptr nofree readnone [[Q:%.*]], i32 [[BITNO:%.*]]) #[[ATTR0]] { 108; ATTRIBUTOR-NEXT: [[TMP:%.*]] = ptrtoint ptr [[Q]] to i32 109; ATTRIBUTOR-NEXT: [[TMP2:%.*]] = lshr i32 [[TMP]], [[BITNO]] 110; ATTRIBUTOR-NEXT: [[BIT:%.*]] = trunc i32 [[TMP2]] to i1 111; ATTRIBUTOR-NEXT: br i1 [[BIT]], label [[L1:%.*]], label [[L0:%.*]] 112; ATTRIBUTOR: l0: 113; ATTRIBUTOR-NEXT: ret i1 false 114; ATTRIBUTOR: l1: 115; ATTRIBUTOR-NEXT: ret i1 false 116; 117 %tmp = ptrtoint ptr %q to i32 118 %tmp2 = lshr i32 %tmp, %bitno 119 %bit = trunc i32 %tmp2 to i1 120 br i1 %bit, label %l1, label %l0 121l0: 122 ret i1 0 ; not escaping! 123l1: 124 ret i1 0 ; not escaping! 125} 126 127@lookup_table = global [2 x i1] [ i1 0, i1 1 ] 128 129define i1 @c5(ptr %q, i32 %bitno) { 130; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read, argmem: none, inaccessiblemem: none) 131; FNATTRS-LABEL: define i1 @c5 132; FNATTRS-SAME: (ptr [[Q:%.*]], i32 [[BITNO:%.*]]) #[[ATTR3:[0-9]+]] { 133; FNATTRS-NEXT: [[TMP:%.*]] = ptrtoint ptr [[Q]] to i32 134; FNATTRS-NEXT: [[TMP2:%.*]] = lshr i32 [[TMP]], [[BITNO]] 135; FNATTRS-NEXT: [[BIT:%.*]] = and i32 [[TMP2]], 1 136; FNATTRS-NEXT: [[LOOKUP:%.*]] = getelementptr [2 x i1], ptr @lookup_table, i32 0, i32 [[BIT]] 137; FNATTRS-NEXT: [[VAL:%.*]] = load i1, ptr [[LOOKUP]], align 1 138; FNATTRS-NEXT: ret i1 [[VAL]] 139; 140; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read) 141; ATTRIBUTOR-LABEL: define i1 @c5 142; ATTRIBUTOR-SAME: (ptr nofree readonly [[Q:%.*]], i32 [[BITNO:%.*]]) #[[ATTR2:[0-9]+]] { 143; ATTRIBUTOR-NEXT: [[TMP:%.*]] = ptrtoint ptr [[Q]] to i32 144; ATTRIBUTOR-NEXT: [[TMP2:%.*]] = lshr i32 [[TMP]], [[BITNO]] 145; ATTRIBUTOR-NEXT: [[BIT:%.*]] = and i32 [[TMP2]], 1 146; ATTRIBUTOR-NEXT: [[LOOKUP:%.*]] = getelementptr [2 x i1], ptr @lookup_table, i32 0, i32 [[BIT]] 147; ATTRIBUTOR-NEXT: [[VAL:%.*]] = load i1, ptr [[LOOKUP]], align 1 148; ATTRIBUTOR-NEXT: ret i1 [[VAL]] 149; 150 %tmp = ptrtoint ptr %q to i32 151 %tmp2 = lshr i32 %tmp, %bitno 152 %bit = and i32 %tmp2, 1 153 ; subtle escape mechanism follows 154 %lookup = getelementptr [2 x i1], ptr @lookup_table, i32 0, i32 %bit 155 %val = load i1, ptr %lookup 156 ret i1 %val 157} 158 159declare void @throw_if_bit_set(ptr, i8) readonly 160 161define i1 @c6(ptr %q, i8 %bit) personality ptr @__gxx_personality_v0 { 162; FNATTRS: Function Attrs: nofree memory(read) 163; FNATTRS-LABEL: define noundef i1 @c6 164; FNATTRS-SAME: (ptr readonly [[Q:%.*]], i8 [[BIT:%.*]]) #[[ATTR5:[0-9]+]] personality ptr @__gxx_personality_v0 { 165; FNATTRS-NEXT: invoke void @throw_if_bit_set(ptr [[Q]], i8 [[BIT]]) 166; FNATTRS-NEXT: to label [[RET0:%.*]] unwind label [[RET1:%.*]] 167; FNATTRS: ret0: 168; FNATTRS-NEXT: ret i1 false 169; FNATTRS: ret1: 170; FNATTRS-NEXT: [[EXN:%.*]] = landingpad { ptr, i32 } 171; FNATTRS-NEXT: cleanup 172; FNATTRS-NEXT: ret i1 true 173; 174; ATTRIBUTOR: Function Attrs: nosync memory(read) 175; ATTRIBUTOR-LABEL: define i1 @c6 176; ATTRIBUTOR-SAME: (ptr readonly [[Q:%.*]], i8 [[BIT:%.*]]) #[[ATTR4:[0-9]+]] personality ptr @__gxx_personality_v0 { 177; ATTRIBUTOR-NEXT: invoke void @throw_if_bit_set(ptr [[Q]], i8 [[BIT]]) #[[ATTR4]] 178; ATTRIBUTOR-NEXT: to label [[RET0:%.*]] unwind label [[RET1:%.*]] 179; ATTRIBUTOR: ret0: 180; ATTRIBUTOR-NEXT: ret i1 false 181; ATTRIBUTOR: ret1: 182; ATTRIBUTOR-NEXT: [[EXN:%.*]] = landingpad { ptr, i32 } 183; ATTRIBUTOR-NEXT: cleanup 184; ATTRIBUTOR-NEXT: ret i1 true 185; 186 invoke void @throw_if_bit_set(ptr %q, i8 %bit) 187 to label %ret0 unwind label %ret1 188ret0: 189 ret i1 0 190ret1: 191 %exn = landingpad {ptr, i32} 192 cleanup 193 ret i1 1 194} 195 196declare i32 @__gxx_personality_v0(...) 197 198define ptr @lookup_bit(ptr %q, i32 %bitno) readnone nounwind { 199; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 200; FNATTRS-LABEL: define ptr @lookup_bit 201; FNATTRS-SAME: (ptr [[Q:%.*]], i32 [[BITNO:%.*]]) #[[ATTR0]] { 202; FNATTRS-NEXT: [[TMP:%.*]] = ptrtoint ptr [[Q]] to i32 203; FNATTRS-NEXT: [[TMP2:%.*]] = lshr i32 [[TMP]], [[BITNO]] 204; FNATTRS-NEXT: [[BIT:%.*]] = and i32 [[TMP2]], 1 205; FNATTRS-NEXT: [[LOOKUP:%.*]] = getelementptr [2 x i1], ptr @lookup_table, i32 0, i32 [[BIT]] 206; FNATTRS-NEXT: ret ptr [[LOOKUP]] 207; 208; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 209; ATTRIBUTOR-LABEL: define ptr @lookup_bit 210; ATTRIBUTOR-SAME: (ptr nofree readnone [[Q:%.*]], i32 [[BITNO:%.*]]) #[[ATTR0]] { 211; ATTRIBUTOR-NEXT: [[TMP:%.*]] = ptrtoint ptr [[Q]] to i32 212; ATTRIBUTOR-NEXT: [[TMP2:%.*]] = lshr i32 [[TMP]], [[BITNO]] 213; ATTRIBUTOR-NEXT: [[BIT:%.*]] = and i32 [[TMP2]], 1 214; ATTRIBUTOR-NEXT: [[LOOKUP:%.*]] = getelementptr [2 x i1], ptr @lookup_table, i32 0, i32 [[BIT]] 215; ATTRIBUTOR-NEXT: ret ptr [[LOOKUP]] 216; 217 %tmp = ptrtoint ptr %q to i32 218 %tmp2 = lshr i32 %tmp, %bitno 219 %bit = and i32 %tmp2, 1 220 %lookup = getelementptr [2 x i1], ptr @lookup_table, i32 0, i32 %bit 221 ret ptr %lookup 222} 223 224define i1 @c7(ptr %q, i32 %bitno) { 225; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read, inaccessiblemem: none) 226; FNATTRS-LABEL: define i1 @c7 227; FNATTRS-SAME: (ptr readonly [[Q:%.*]], i32 [[BITNO:%.*]]) #[[ATTR6:[0-9]+]] { 228; FNATTRS-NEXT: [[PTR:%.*]] = call ptr @lookup_bit(ptr [[Q]], i32 [[BITNO]]) 229; FNATTRS-NEXT: [[VAL:%.*]] = load i1, ptr [[PTR]], align 1 230; FNATTRS-NEXT: ret i1 [[VAL]] 231; 232; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read) 233; ATTRIBUTOR-LABEL: define i1 @c7 234; ATTRIBUTOR-SAME: (ptr nofree readonly [[Q:%.*]], i32 [[BITNO:%.*]]) #[[ATTR2]] { 235; ATTRIBUTOR-NEXT: [[PTR:%.*]] = call ptr @lookup_bit(ptr nofree readnone [[Q]], i32 [[BITNO]]) #[[ATTR17:[0-9]+]] 236; ATTRIBUTOR-NEXT: [[VAL:%.*]] = load i1, ptr [[PTR]], align 1 237; ATTRIBUTOR-NEXT: ret i1 [[VAL]] 238; 239 %ptr = call ptr @lookup_bit(ptr %q, i32 %bitno) 240 %val = load i1, ptr %ptr 241 ret i1 %val 242} 243 244 245define i32 @nc1(ptr %q, ptr %p, i1 %b) { 246; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(readwrite, inaccessiblemem: none) 247; FNATTRS-LABEL: define i32 @nc1 248; FNATTRS-SAME: (ptr [[Q:%.*]], ptr captures(none) [[P:%.*]], i1 [[B:%.*]]) #[[ATTR7:[0-9]+]] { 249; FNATTRS-NEXT: e: 250; FNATTRS-NEXT: br label [[L:%.*]] 251; FNATTRS: l: 252; FNATTRS-NEXT: [[X:%.*]] = phi ptr [ [[P]], [[E:%.*]] ] 253; FNATTRS-NEXT: [[Y:%.*]] = phi ptr [ [[Q]], [[E]] ] 254; FNATTRS-NEXT: [[TMP2:%.*]] = select i1 [[B]], ptr [[X]], ptr [[Y]] 255; FNATTRS-NEXT: [[VAL:%.*]] = load i32, ptr [[TMP2]], align 4 256; FNATTRS-NEXT: store i32 0, ptr [[X]], align 4 257; FNATTRS-NEXT: store ptr [[Y]], ptr @g, align 8 258; FNATTRS-NEXT: ret i32 [[VAL]] 259; 260; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn 261; ATTRIBUTOR-LABEL: define i32 @nc1 262; ATTRIBUTOR-SAME: (ptr nofree [[Q:%.*]], ptr nofree captures(none) [[P:%.*]], i1 [[B:%.*]]) #[[ATTR5:[0-9]+]] { 263; ATTRIBUTOR-NEXT: e: 264; ATTRIBUTOR-NEXT: br label [[L:%.*]] 265; ATTRIBUTOR: l: 266; ATTRIBUTOR-NEXT: [[X:%.*]] = phi ptr [ [[P]], [[E:%.*]] ] 267; ATTRIBUTOR-NEXT: [[Y:%.*]] = phi ptr [ [[Q]], [[E]] ] 268; ATTRIBUTOR-NEXT: [[TMP2:%.*]] = select i1 [[B]], ptr [[X]], ptr [[Y]] 269; ATTRIBUTOR-NEXT: [[VAL:%.*]] = load i32, ptr [[TMP2]], align 4 270; ATTRIBUTOR-NEXT: store i32 0, ptr [[X]], align 4 271; ATTRIBUTOR-NEXT: store ptr [[Y]], ptr @g, align 8 272; ATTRIBUTOR-NEXT: ret i32 [[VAL]] 273; 274e: 275 br label %l 276l: 277 %x = phi ptr [ %p, %e ] 278 %y = phi ptr [ %q, %e ] 279 %tmp2 = select i1 %b, ptr %x, ptr %y 280 %val = load i32, ptr %tmp2 ; <i32> [#uses=1] 281 store i32 0, ptr %x 282 store ptr %y, ptr @g 283 ret i32 %val 284} 285 286define i32 @nc1_addrspace(ptr %q, ptr addrspace(1) %p, i1 %b) { 287; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(readwrite, inaccessiblemem: none) 288; FNATTRS-LABEL: define i32 @nc1_addrspace 289; FNATTRS-SAME: (ptr [[Q:%.*]], ptr addrspace(1) captures(none) [[P:%.*]], i1 [[B:%.*]]) #[[ATTR7]] { 290; FNATTRS-NEXT: e: 291; FNATTRS-NEXT: br label [[L:%.*]] 292; FNATTRS: l: 293; FNATTRS-NEXT: [[X:%.*]] = phi ptr addrspace(1) [ [[P]], [[E:%.*]] ] 294; FNATTRS-NEXT: [[Y:%.*]] = phi ptr [ [[Q]], [[E]] ] 295; FNATTRS-NEXT: [[TMP:%.*]] = addrspacecast ptr addrspace(1) [[X]] to ptr 296; FNATTRS-NEXT: [[TMP2:%.*]] = select i1 [[B]], ptr [[TMP]], ptr [[Y]] 297; FNATTRS-NEXT: [[VAL:%.*]] = load i32, ptr [[TMP2]], align 4 298; FNATTRS-NEXT: store i32 0, ptr [[TMP]], align 4 299; FNATTRS-NEXT: store ptr [[Y]], ptr @g, align 8 300; FNATTRS-NEXT: ret i32 [[VAL]] 301; 302; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn 303; ATTRIBUTOR-LABEL: define i32 @nc1_addrspace 304; ATTRIBUTOR-SAME: (ptr nofree [[Q:%.*]], ptr addrspace(1) nofree captures(none) [[P:%.*]], i1 [[B:%.*]]) #[[ATTR5]] { 305; ATTRIBUTOR-NEXT: e: 306; ATTRIBUTOR-NEXT: br label [[L:%.*]] 307; ATTRIBUTOR: l: 308; ATTRIBUTOR-NEXT: [[X:%.*]] = phi ptr addrspace(1) [ [[P]], [[E:%.*]] ] 309; ATTRIBUTOR-NEXT: [[Y:%.*]] = phi ptr [ [[Q]], [[E]] ] 310; ATTRIBUTOR-NEXT: [[TMP:%.*]] = addrspacecast ptr addrspace(1) [[X]] to ptr 311; ATTRIBUTOR-NEXT: [[TMP2:%.*]] = select i1 [[B]], ptr [[TMP]], ptr [[Y]] 312; ATTRIBUTOR-NEXT: [[VAL:%.*]] = load i32, ptr [[TMP2]], align 4 313; ATTRIBUTOR-NEXT: store i32 0, ptr [[TMP]], align 4 314; ATTRIBUTOR-NEXT: store ptr [[Y]], ptr @g, align 8 315; ATTRIBUTOR-NEXT: ret i32 [[VAL]] 316; 317e: 318 br label %l 319l: 320 %x = phi ptr addrspace(1) [ %p, %e ] 321 %y = phi ptr [ %q, %e ] 322 %tmp = addrspacecast ptr addrspace(1) %x to ptr ; <ptr> [#uses=2] 323 %tmp2 = select i1 %b, ptr %tmp, ptr %y 324 %val = load i32, ptr %tmp2 ; <i32> [#uses=1] 325 store i32 0, ptr %tmp 326 store ptr %y, ptr @g 327 ret i32 %val 328} 329 330define void @nc2(ptr %p, ptr %q) { 331; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(readwrite, inaccessiblemem: none) 332; FNATTRS-LABEL: define void @nc2 333; FNATTRS-SAME: (ptr captures(none) [[P:%.*]], ptr [[Q:%.*]]) #[[ATTR7]] { 334; FNATTRS-NEXT: [[TMP1:%.*]] = call i32 @nc1(ptr [[Q]], ptr [[P]], i1 false) 335; FNATTRS-NEXT: ret void 336; 337; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn 338; ATTRIBUTOR-LABEL: define void @nc2 339; ATTRIBUTOR-SAME: (ptr nofree captures(none) [[P:%.*]], ptr nofree [[Q:%.*]]) #[[ATTR5]] { 340; ATTRIBUTOR-NEXT: [[TMP1:%.*]] = call i32 @nc1(ptr nofree [[Q]], ptr nofree captures(none) [[P]], i1 false) #[[ATTR18:[0-9]+]] 341; ATTRIBUTOR-NEXT: ret void 342; 343 %1 = call i32 @nc1(ptr %q, ptr %p, i1 0) ; <i32> [#uses=0] 344 ret void 345} 346 347 348define void @nc3(ptr %p) { 349; FNATTRS-LABEL: define void @nc3 350; FNATTRS-SAME: (ptr readonly captures(none) [[P:%.*]]) { 351; FNATTRS-NEXT: call void [[P]]() 352; FNATTRS-NEXT: ret void 353; 354; ATTRIBUTOR-LABEL: define void @nc3 355; ATTRIBUTOR-SAME: (ptr nofree nonnull captures(none) [[P:%.*]]) { 356; ATTRIBUTOR-NEXT: call void [[P]]() 357; ATTRIBUTOR-NEXT: ret void 358; 359 call void %p() 360 ret void 361} 362 363declare void @external(ptr) readonly nounwind 364define void @nc4(ptr %p) { 365; FNATTRS: Function Attrs: nofree nounwind memory(read) 366; FNATTRS-LABEL: define void @nc4 367; FNATTRS-SAME: (ptr readonly captures(none) [[P:%.*]]) #[[ATTR9:[0-9]+]] { 368; FNATTRS-NEXT: call void @external(ptr [[P]]) 369; FNATTRS-NEXT: ret void 370; 371; ATTRIBUTOR: Function Attrs: nosync nounwind memory(read) 372; ATTRIBUTOR-LABEL: define void @nc4 373; ATTRIBUTOR-SAME: (ptr readonly captures(none) [[P:%.*]]) #[[ATTR7:[0-9]+]] { 374; ATTRIBUTOR-NEXT: call void @external(ptr readonly captures(none) [[P]]) #[[ATTR4]] 375; ATTRIBUTOR-NEXT: ret void 376; 377 call void @external(ptr %p) 378 ret void 379} 380 381define void @nc5(ptr %f, ptr %p) { 382; FNATTRS-LABEL: define void @nc5 383; FNATTRS-SAME: (ptr readonly captures(none) [[F:%.*]], ptr captures(none) [[P:%.*]]) { 384; FNATTRS-NEXT: call void [[F]](ptr [[P]]) #[[ATTR8:[0-9]+]] 385; FNATTRS-NEXT: call void [[F]](ptr captures(none) [[P]]) 386; FNATTRS-NEXT: ret void 387; 388; ATTRIBUTOR-LABEL: define void @nc5 389; ATTRIBUTOR-SAME: (ptr nofree nonnull captures(none) [[F:%.*]], ptr captures(none) [[P:%.*]]) { 390; ATTRIBUTOR-NEXT: call void [[F]](ptr [[P]]) #[[ATTR6:[0-9]+]] 391; ATTRIBUTOR-NEXT: call void [[F]](ptr captures(none) [[P]]) 392; ATTRIBUTOR-NEXT: ret void 393; 394 call void %f(ptr %p) readonly nounwind 395 call void %f(ptr nocapture %p) 396 ret void 397} 398 399; It would be acceptable to add readnone to %y1_1 and %y1_2. 400define void @test1_1(ptr %x1_1, ptr %y1_1, i1 %c) { 401; FNATTRS: Function Attrs: nofree nosync nounwind memory(write, argmem: none, inaccessiblemem: none) 402; FNATTRS-LABEL: define void @test1_1 403; FNATTRS-SAME: (ptr readnone captures(none) [[X1_1:%.*]], ptr [[Y1_1:%.*]], i1 [[C:%.*]]) #[[ATTR10:[0-9]+]] { 404; FNATTRS-NEXT: [[TMP1:%.*]] = call ptr @test1_2(ptr [[X1_1]], ptr [[Y1_1]], i1 [[C]]) 405; FNATTRS-NEXT: store ptr null, ptr @g, align 8 406; FNATTRS-NEXT: ret void 407; 408; ATTRIBUTOR: Function Attrs: nofree nosync nounwind memory(write) 409; ATTRIBUTOR-LABEL: define void @test1_1 410; ATTRIBUTOR-SAME: (ptr nofree readnone captures(none) [[X1_1:%.*]], ptr nofree readnone captures(none) [[Y1_1:%.*]], i1 [[C:%.*]]) #[[ATTR8:[0-9]+]] { 411; ATTRIBUTOR-NEXT: [[TMP1:%.*]] = call ptr @test1_2(ptr nofree readnone captures(none) [[X1_1]], ptr nofree readnone [[Y1_1]], i1 [[C]]) #[[ATTR8]] 412; ATTRIBUTOR-NEXT: store ptr null, ptr @g, align 8 413; ATTRIBUTOR-NEXT: ret void 414; 415 call ptr @test1_2(ptr %x1_1, ptr %y1_1, i1 %c) 416 store ptr null, ptr @g 417 ret void 418} 419 420define ptr @test1_2(ptr %x1_2, ptr %y1_2, i1 %c) { 421; FNATTRS: Function Attrs: nofree nosync nounwind memory(write, argmem: none, inaccessiblemem: none) 422; FNATTRS-LABEL: define ptr @test1_2 423; FNATTRS-SAME: (ptr readnone captures(none) [[X1_2:%.*]], ptr returned [[Y1_2:%.*]], i1 [[C:%.*]]) #[[ATTR10]] { 424; FNATTRS-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]] 425; FNATTRS: t: 426; FNATTRS-NEXT: call void @test1_1(ptr [[X1_2]], ptr [[Y1_2]], i1 [[C]]) 427; FNATTRS-NEXT: store ptr null, ptr @g, align 8 428; FNATTRS-NEXT: br label [[F]] 429; FNATTRS: f: 430; FNATTRS-NEXT: ret ptr [[Y1_2]] 431; 432; ATTRIBUTOR: Function Attrs: nofree nosync nounwind memory(write) 433; ATTRIBUTOR-LABEL: define ptr @test1_2 434; ATTRIBUTOR-SAME: (ptr nofree readnone captures(none) [[X1_2:%.*]], ptr nofree readnone [[Y1_2:%.*]], i1 [[C:%.*]]) #[[ATTR8]] { 435; ATTRIBUTOR-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]] 436; ATTRIBUTOR: t: 437; ATTRIBUTOR-NEXT: call void @test1_1(ptr nofree readnone captures(none) [[X1_2]], ptr nofree readnone captures(none) [[Y1_2]], i1 [[C]]) #[[ATTR8]] 438; ATTRIBUTOR-NEXT: store ptr null, ptr @g, align 8 439; ATTRIBUTOR-NEXT: br label [[F]] 440; ATTRIBUTOR: f: 441; ATTRIBUTOR-NEXT: ret ptr [[Y1_2]] 442; 443 br i1 %c, label %t, label %f 444t: 445 call void @test1_1(ptr %x1_2, ptr %y1_2, i1 %c) 446 store ptr null, ptr @g 447 br label %f 448f: 449 ret ptr %y1_2 450} 451 452define void @test2(ptr %x2) { 453; FNATTRS: Function Attrs: nofree nosync nounwind memory(write, argmem: none, inaccessiblemem: none) 454; FNATTRS-LABEL: define void @test2 455; FNATTRS-SAME: (ptr readnone captures(none) [[X2:%.*]]) #[[ATTR10]] { 456; FNATTRS-NEXT: call void @test2(ptr [[X2]]) 457; FNATTRS-NEXT: store ptr null, ptr @g, align 8 458; FNATTRS-NEXT: ret void 459; 460; ATTRIBUTOR: Function Attrs: nofree nosync nounwind memory(write) 461; ATTRIBUTOR-LABEL: define void @test2 462; ATTRIBUTOR-SAME: (ptr nofree readnone captures(none) [[X2:%.*]]) #[[ATTR8]] { 463; ATTRIBUTOR-NEXT: call void @test2(ptr nofree readnone captures(none) [[X2]]) #[[ATTR8]] 464; ATTRIBUTOR-NEXT: store ptr null, ptr @g, align 8 465; ATTRIBUTOR-NEXT: ret void 466; 467 call void @test2(ptr %x2) 468 store ptr null, ptr @g 469 ret void 470} 471 472define void @test3(ptr %x3, ptr %y3, ptr %z3) { 473; FNATTRS: Function Attrs: nofree nosync nounwind memory(write, argmem: none, inaccessiblemem: none) 474; FNATTRS-LABEL: define void @test3 475; FNATTRS-SAME: (ptr readnone captures(none) [[X3:%.*]], ptr readnone captures(none) [[Y3:%.*]], ptr readnone captures(none) [[Z3:%.*]]) #[[ATTR10]] { 476; FNATTRS-NEXT: call void @test3(ptr [[Z3]], ptr [[Y3]], ptr [[X3]]) 477; FNATTRS-NEXT: store ptr null, ptr @g, align 8 478; FNATTRS-NEXT: ret void 479; 480; ATTRIBUTOR: Function Attrs: nofree nosync nounwind memory(write) 481; ATTRIBUTOR-LABEL: define void @test3 482; ATTRIBUTOR-SAME: (ptr nofree readnone captures(none) [[X3:%.*]], ptr nofree readnone captures(none) [[Y3:%.*]], ptr nofree readnone captures(none) [[Z3:%.*]]) #[[ATTR8]] { 483; ATTRIBUTOR-NEXT: call void @test3(ptr nofree readnone captures(none) [[Z3]], ptr nofree readnone captures(none) [[Y3]], ptr nofree readnone captures(none) [[X3]]) #[[ATTR8]] 484; ATTRIBUTOR-NEXT: store ptr null, ptr @g, align 8 485; ATTRIBUTOR-NEXT: ret void 486; 487 call void @test3(ptr %z3, ptr %y3, ptr %x3) 488 store ptr null, ptr @g 489 ret void 490} 491 492define void @test4_1(ptr %x4_1, i1 %c) { 493; FNATTRS: Function Attrs: nofree nosync nounwind memory(write, argmem: none, inaccessiblemem: none) 494; FNATTRS-LABEL: define void @test4_1 495; FNATTRS-SAME: (ptr [[X4_1:%.*]], i1 [[C:%.*]]) #[[ATTR10]] { 496; FNATTRS-NEXT: [[TMP1:%.*]] = call ptr @test4_2(ptr [[X4_1]], ptr [[X4_1]], ptr [[X4_1]], i1 [[C]]) 497; FNATTRS-NEXT: store ptr null, ptr @g, align 8 498; FNATTRS-NEXT: ret void 499; 500; ATTRIBUTOR: Function Attrs: nofree nosync nounwind memory(write) 501; ATTRIBUTOR-LABEL: define void @test4_1 502; ATTRIBUTOR-SAME: (ptr nofree readnone captures(none) [[X4_1:%.*]], i1 [[C:%.*]]) #[[ATTR8]] { 503; ATTRIBUTOR-NEXT: [[TMP1:%.*]] = call ptr @test4_2(ptr nofree readnone captures(none) [[X4_1]], ptr nofree readnone [[X4_1]], ptr nofree readnone captures(none) [[X4_1]], i1 [[C]]) #[[ATTR8]] 504; ATTRIBUTOR-NEXT: store ptr null, ptr @g, align 8 505; ATTRIBUTOR-NEXT: ret void 506; 507 call ptr @test4_2(ptr %x4_1, ptr %x4_1, ptr %x4_1, i1 %c) 508 store ptr null, ptr @g 509 ret void 510} 511 512define ptr @test4_2(ptr %x4_2, ptr %y4_2, ptr %z4_2, i1 %c) { 513; FNATTRS: Function Attrs: nofree nosync nounwind memory(write, argmem: none, inaccessiblemem: none) 514; FNATTRS-LABEL: define ptr @test4_2 515; FNATTRS-SAME: (ptr readnone captures(none) [[X4_2:%.*]], ptr readnone returned [[Y4_2:%.*]], ptr readnone captures(none) [[Z4_2:%.*]], i1 [[C:%.*]]) #[[ATTR10]] { 516; FNATTRS-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]] 517; FNATTRS: t: 518; FNATTRS-NEXT: call void @test4_1(ptr null, i1 [[C]]) 519; FNATTRS-NEXT: store ptr null, ptr @g, align 8 520; FNATTRS-NEXT: br label [[F]] 521; FNATTRS: f: 522; FNATTRS-NEXT: ret ptr [[Y4_2]] 523; 524; ATTRIBUTOR: Function Attrs: nofree nosync nounwind memory(write) 525; ATTRIBUTOR-LABEL: define ptr @test4_2 526; ATTRIBUTOR-SAME: (ptr nofree readnone captures(none) [[X4_2:%.*]], ptr nofree readnone [[Y4_2:%.*]], ptr nofree readnone captures(none) [[Z4_2:%.*]], i1 [[C:%.*]]) #[[ATTR8]] { 527; ATTRIBUTOR-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]] 528; ATTRIBUTOR: t: 529; ATTRIBUTOR-NEXT: call void @test4_1(ptr nofree readnone null, i1 [[C]]) #[[ATTR8]] 530; ATTRIBUTOR-NEXT: store ptr null, ptr @g, align 8 531; ATTRIBUTOR-NEXT: br label [[F]] 532; ATTRIBUTOR: f: 533; ATTRIBUTOR-NEXT: ret ptr [[Y4_2]] 534; 535 br i1 %c, label %t, label %f 536t: 537 call void @test4_1(ptr null, i1 %c) 538 store ptr null, ptr @g 539 br label %f 540f: 541 ret ptr %y4_2 542} 543 544declare ptr @test5_1(ptr %x5_1) 545 546define void @test5_2(ptr %x5_2) { 547; COMMON-LABEL: define void @test5_2 548; COMMON-SAME: (ptr [[X5_2:%.*]]) { 549; COMMON-NEXT: [[TMP1:%.*]] = call ptr @test5_1(ptr [[X5_2]]) 550; COMMON-NEXT: store ptr null, ptr @g, align 8 551; COMMON-NEXT: ret void 552; 553 call ptr @test5_1(ptr %x5_2) 554 store ptr null, ptr @g 555 ret void 556} 557 558declare void @test6_1(ptr %x6_1, ptr nocapture %y6_1, ...) 559 560define void @test6_2(ptr %x6_2, ptr %y6_2, ptr %z6_2) { 561; FNATTRS-LABEL: define void @test6_2 562; FNATTRS-SAME: (ptr [[X6_2:%.*]], ptr captures(none) [[Y6_2:%.*]], ptr [[Z6_2:%.*]]) { 563; FNATTRS-NEXT: call void (ptr, ptr, ...) @test6_1(ptr [[X6_2]], ptr [[Y6_2]], ptr [[Z6_2]]) 564; FNATTRS-NEXT: store ptr null, ptr @g, align 8 565; FNATTRS-NEXT: ret void 566; 567; ATTRIBUTOR-LABEL: define void @test6_2 568; ATTRIBUTOR-SAME: (ptr [[X6_2:%.*]], ptr captures(none) [[Y6_2:%.*]], ptr [[Z6_2:%.*]]) { 569; ATTRIBUTOR-NEXT: call void (ptr, ptr, ...) @test6_1(ptr [[X6_2]], ptr captures(none) [[Y6_2]], ptr [[Z6_2]]) 570; ATTRIBUTOR-NEXT: store ptr null, ptr @g, align 8 571; ATTRIBUTOR-NEXT: ret void 572; 573 call void (ptr, ptr, ...) @test6_1(ptr %x6_2, ptr %y6_2, ptr %z6_2) 574 store ptr null, ptr @g 575 ret void 576} 577 578define void @test_cmpxchg(ptr %p) { 579; FNATTRS: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) 580; FNATTRS-LABEL: define void @test_cmpxchg 581; FNATTRS-SAME: (ptr captures(none) [[P:%.*]]) #[[ATTR11:[0-9]+]] { 582; FNATTRS-NEXT: [[TMP1:%.*]] = cmpxchg ptr [[P]], i32 0, i32 1 acquire monotonic, align 4 583; FNATTRS-NEXT: ret void 584; 585; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) 586; ATTRIBUTOR-LABEL: define void @test_cmpxchg 587; ATTRIBUTOR-SAME: (ptr nofree nonnull captures(none) [[P:%.*]]) #[[ATTR9:[0-9]+]] { 588; ATTRIBUTOR-NEXT: [[TMP1:%.*]] = cmpxchg ptr [[P]], i32 0, i32 1 acquire monotonic, align 4 589; ATTRIBUTOR-NEXT: ret void 590; 591 cmpxchg ptr %p, i32 0, i32 1 acquire monotonic 592 ret void 593} 594 595define void @test_cmpxchg_ptr(ptr %p, ptr %q) { 596; FNATTRS: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) 597; FNATTRS-LABEL: define void @test_cmpxchg_ptr 598; FNATTRS-SAME: (ptr captures(none) [[P:%.*]], ptr [[Q:%.*]]) #[[ATTR11]] { 599; FNATTRS-NEXT: [[TMP1:%.*]] = cmpxchg ptr [[P]], ptr null, ptr [[Q]] acquire monotonic, align 8 600; FNATTRS-NEXT: ret void 601; 602; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) 603; ATTRIBUTOR-LABEL: define void @test_cmpxchg_ptr 604; ATTRIBUTOR-SAME: (ptr nofree nonnull captures(none) [[P:%.*]], ptr nofree [[Q:%.*]]) #[[ATTR9]] { 605; ATTRIBUTOR-NEXT: [[TMP1:%.*]] = cmpxchg ptr [[P]], ptr null, ptr [[Q]] acquire monotonic, align 8 606; ATTRIBUTOR-NEXT: ret void 607; 608 cmpxchg ptr %p, ptr null, ptr %q acquire monotonic 609 ret void 610} 611 612define void @test_atomicrmw(ptr %p) { 613; FNATTRS: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) 614; FNATTRS-LABEL: define void @test_atomicrmw 615; FNATTRS-SAME: (ptr captures(none) [[P:%.*]]) #[[ATTR11]] { 616; FNATTRS-NEXT: [[TMP1:%.*]] = atomicrmw add ptr [[P]], i32 1 seq_cst, align 4 617; FNATTRS-NEXT: ret void 618; 619; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) 620; ATTRIBUTOR-LABEL: define void @test_atomicrmw 621; ATTRIBUTOR-SAME: (ptr nofree nonnull captures(none) [[P:%.*]]) #[[ATTR9]] { 622; ATTRIBUTOR-NEXT: [[TMP1:%.*]] = atomicrmw add ptr [[P]], i32 1 seq_cst, align 4 623; ATTRIBUTOR-NEXT: ret void 624; 625 atomicrmw add ptr %p, i32 1 seq_cst 626 ret void 627} 628 629define void @test_volatile(ptr %x) { 630; FNATTRS: Function Attrs: nofree norecurse nounwind memory(argmem: readwrite, inaccessiblemem: readwrite) 631; FNATTRS-LABEL: define void @test_volatile 632; FNATTRS-SAME: (ptr [[X:%.*]]) #[[ATTR12:[0-9]+]] { 633; FNATTRS-NEXT: entry: 634; FNATTRS-NEXT: [[GEP:%.*]] = getelementptr i32, ptr [[X]], i64 1 635; FNATTRS-NEXT: store volatile i32 0, ptr [[GEP]], align 4 636; FNATTRS-NEXT: ret void 637; 638; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) 639; ATTRIBUTOR-LABEL: define void @test_volatile 640; ATTRIBUTOR-SAME: (ptr nofree [[X:%.*]]) #[[ATTR9]] { 641; ATTRIBUTOR-NEXT: entry: 642; ATTRIBUTOR-NEXT: [[GEP:%.*]] = getelementptr i32, ptr [[X]], i64 1 643; ATTRIBUTOR-NEXT: store volatile i32 0, ptr [[GEP]], align 4 644; ATTRIBUTOR-NEXT: ret void 645; 646entry: 647 %gep = getelementptr i32, ptr %x, i64 1 648 store volatile i32 0, ptr %gep, align 4 649 ret void 650} 651 652define void @nocaptureLaunder(ptr %p) { 653; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write, inaccessiblemem: readwrite) 654; FNATTRS-LABEL: define void @nocaptureLaunder 655; FNATTRS-SAME: (ptr writeonly captures(none) [[P:%.*]]) #[[ATTR13:[0-9]+]] { 656; FNATTRS-NEXT: entry: 657; FNATTRS-NEXT: [[B:%.*]] = call ptr @llvm.launder.invariant.group.p0(ptr [[P]]) 658; FNATTRS-NEXT: store i8 42, ptr [[B]], align 1 659; FNATTRS-NEXT: ret void 660; 661; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite, inaccessiblemem: readwrite) 662; ATTRIBUTOR-LABEL: define void @nocaptureLaunder 663; ATTRIBUTOR-SAME: (ptr nofree captures(none) [[P:%.*]]) #[[ATTR10:[0-9]+]] { 664; ATTRIBUTOR-NEXT: entry: 665; ATTRIBUTOR-NEXT: [[B:%.*]] = call ptr @llvm.launder.invariant.group.p0(ptr [[P]]) #[[ATTR19:[0-9]+]] 666; ATTRIBUTOR-NEXT: store i8 42, ptr [[B]], align 1 667; ATTRIBUTOR-NEXT: ret void 668; 669entry: 670 %b = call ptr @llvm.launder.invariant.group.p0(ptr %p) 671 store i8 42, ptr %b 672 ret void 673} 674 675@g2 = global ptr null 676define void @captureLaunder(ptr %p) { 677; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write, argmem: none, inaccessiblemem: readwrite) 678; FNATTRS-LABEL: define void @captureLaunder 679; FNATTRS-SAME: (ptr [[P:%.*]]) #[[ATTR14:[0-9]+]] { 680; FNATTRS-NEXT: [[B:%.*]] = call ptr @llvm.launder.invariant.group.p0(ptr [[P]]) 681; FNATTRS-NEXT: store ptr [[B]], ptr @g2, align 8 682; FNATTRS-NEXT: ret void 683; 684; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn 685; ATTRIBUTOR-LABEL: define void @captureLaunder 686; ATTRIBUTOR-SAME: (ptr nofree [[P:%.*]]) #[[ATTR5]] { 687; ATTRIBUTOR-NEXT: [[B:%.*]] = call ptr @llvm.launder.invariant.group.p0(ptr [[P]]) #[[ATTR19]] 688; ATTRIBUTOR-NEXT: store ptr [[B]], ptr @g2, align 8 689; ATTRIBUTOR-NEXT: ret void 690; 691 %b = call ptr @llvm.launder.invariant.group.p0(ptr %p) 692 store ptr %b, ptr @g2 693 ret void 694} 695 696define void @nocaptureStrip(ptr %p) { 697; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) 698; FNATTRS-LABEL: define void @nocaptureStrip 699; FNATTRS-SAME: (ptr writeonly captures(none) [[P:%.*]]) #[[ATTR15:[0-9]+]] { 700; FNATTRS-NEXT: entry: 701; FNATTRS-NEXT: [[B:%.*]] = call ptr @llvm.strip.invariant.group.p0(ptr [[P]]) 702; FNATTRS-NEXT: store i8 42, ptr [[B]], align 1 703; FNATTRS-NEXT: ret void 704; 705; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) 706; ATTRIBUTOR-LABEL: define void @nocaptureStrip 707; ATTRIBUTOR-SAME: (ptr nofree writeonly captures(none) [[P:%.*]]) #[[ATTR11:[0-9]+]] { 708; ATTRIBUTOR-NEXT: entry: 709; ATTRIBUTOR-NEXT: [[B:%.*]] = call ptr @llvm.strip.invariant.group.p0(ptr [[P]]) #[[ATTR17]] 710; ATTRIBUTOR-NEXT: store i8 42, ptr [[B]], align 1 711; ATTRIBUTOR-NEXT: ret void 712; 713entry: 714 %b = call ptr @llvm.strip.invariant.group.p0(ptr %p) 715 store i8 42, ptr %b 716 ret void 717} 718 719@g3 = global ptr null 720define void @captureStrip(ptr %p) { 721; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write, argmem: none, inaccessiblemem: none) 722; FNATTRS-LABEL: define void @captureStrip 723; FNATTRS-SAME: (ptr [[P:%.*]]) #[[ATTR1]] { 724; FNATTRS-NEXT: [[B:%.*]] = call ptr @llvm.strip.invariant.group.p0(ptr [[P]]) 725; FNATTRS-NEXT: store ptr [[B]], ptr @g3, align 8 726; FNATTRS-NEXT: ret void 727; 728; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write) 729; ATTRIBUTOR-LABEL: define void @captureStrip 730; ATTRIBUTOR-SAME: (ptr nofree writeonly [[P:%.*]]) #[[ATTR1]] { 731; ATTRIBUTOR-NEXT: [[B:%.*]] = call ptr @llvm.strip.invariant.group.p0(ptr [[P]]) #[[ATTR17]] 732; ATTRIBUTOR-NEXT: store ptr [[B]], ptr @g3, align 8 733; ATTRIBUTOR-NEXT: ret void 734; 735 %b = call ptr @llvm.strip.invariant.group.p0(ptr %p) 736 store ptr %b, ptr @g3 737 ret void 738} 739 740define i1 @captureICmp(ptr %x) { 741; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 742; FNATTRS-LABEL: define i1 @captureICmp 743; FNATTRS-SAME: (ptr readnone [[X:%.*]]) #[[ATTR0]] { 744; FNATTRS-NEXT: [[TMP1:%.*]] = icmp eq ptr [[X]], null 745; FNATTRS-NEXT: ret i1 [[TMP1]] 746; 747; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 748; ATTRIBUTOR-LABEL: define i1 @captureICmp 749; ATTRIBUTOR-SAME: (ptr nofree readnone [[X:%.*]]) #[[ATTR0]] { 750; ATTRIBUTOR-NEXT: [[TMP1:%.*]] = icmp eq ptr [[X]], null 751; ATTRIBUTOR-NEXT: ret i1 [[TMP1]] 752; 753 %1 = icmp eq ptr %x, null 754 ret i1 %1 755} 756 757define i1 @captureICmpRev(ptr %x) { 758; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 759; FNATTRS-LABEL: define i1 @captureICmpRev 760; FNATTRS-SAME: (ptr readnone [[X:%.*]]) #[[ATTR0]] { 761; FNATTRS-NEXT: [[TMP1:%.*]] = icmp eq ptr null, [[X]] 762; FNATTRS-NEXT: ret i1 [[TMP1]] 763; 764; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 765; ATTRIBUTOR-LABEL: define i1 @captureICmpRev 766; ATTRIBUTOR-SAME: (ptr nofree readnone [[X:%.*]]) #[[ATTR0]] { 767; ATTRIBUTOR-NEXT: [[TMP1:%.*]] = icmp eq ptr null, [[X]] 768; ATTRIBUTOR-NEXT: ret i1 [[TMP1]] 769; 770 %1 = icmp eq ptr null, %x 771 ret i1 %1 772} 773 774define i1 @nocaptureInboundsGEPICmp(ptr %x) { 775; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 776; FNATTRS-LABEL: define i1 @nocaptureInboundsGEPICmp 777; FNATTRS-SAME: (ptr readnone [[X:%.*]]) #[[ATTR0]] { 778; FNATTRS-NEXT: [[TMP1:%.*]] = getelementptr inbounds i32, ptr [[X]], i32 5 779; FNATTRS-NEXT: [[TMP2:%.*]] = icmp eq ptr [[TMP1]], null 780; FNATTRS-NEXT: ret i1 [[TMP2]] 781; 782; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 783; ATTRIBUTOR-LABEL: define i1 @nocaptureInboundsGEPICmp 784; ATTRIBUTOR-SAME: (ptr nofree readnone [[X:%.*]]) #[[ATTR0]] { 785; ATTRIBUTOR-NEXT: [[TMP1:%.*]] = getelementptr inbounds i32, ptr [[X]], i32 5 786; ATTRIBUTOR-NEXT: [[TMP2:%.*]] = icmp eq ptr [[TMP1]], null 787; ATTRIBUTOR-NEXT: ret i1 [[TMP2]] 788; 789 %1 = getelementptr inbounds i32, ptr %x, i32 5 790 %2 = icmp eq ptr %1, null 791 ret i1 %2 792} 793 794define i1 @nocaptureInboundsGEPICmpRev(ptr %x) { 795; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 796; FNATTRS-LABEL: define i1 @nocaptureInboundsGEPICmpRev 797; FNATTRS-SAME: (ptr readnone [[X:%.*]]) #[[ATTR0]] { 798; FNATTRS-NEXT: [[TMP1:%.*]] = getelementptr inbounds i32, ptr [[X]], i32 5 799; FNATTRS-NEXT: [[TMP2:%.*]] = icmp eq ptr null, [[TMP1]] 800; FNATTRS-NEXT: ret i1 [[TMP2]] 801; 802; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 803; ATTRIBUTOR-LABEL: define i1 @nocaptureInboundsGEPICmpRev 804; ATTRIBUTOR-SAME: (ptr nofree readnone [[X:%.*]]) #[[ATTR0]] { 805; ATTRIBUTOR-NEXT: [[TMP1:%.*]] = getelementptr inbounds i32, ptr [[X]], i32 5 806; ATTRIBUTOR-NEXT: [[TMP2:%.*]] = icmp eq ptr null, [[TMP1]] 807; ATTRIBUTOR-NEXT: ret i1 [[TMP2]] 808; 809 %1 = getelementptr inbounds i32, ptr %x, i32 5 810 %2 = icmp eq ptr null, %1 811 ret i1 %2 812} 813 814define i1 @nocaptureDereferenceableOrNullICmp(ptr dereferenceable_or_null(4) %x) { 815; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 816; FNATTRS-LABEL: define noundef i1 @nocaptureDereferenceableOrNullICmp 817; FNATTRS-SAME: (ptr readnone captures(none) dereferenceable_or_null(4) [[X:%.*]]) #[[ATTR0]] { 818; FNATTRS-NEXT: [[TMP1:%.*]] = icmp eq ptr [[X]], null 819; FNATTRS-NEXT: ret i1 [[TMP1]] 820; 821; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 822; ATTRIBUTOR-LABEL: define i1 @nocaptureDereferenceableOrNullICmp 823; ATTRIBUTOR-SAME: (ptr nofree readnone dereferenceable_or_null(4) [[X:%.*]]) #[[ATTR0]] { 824; ATTRIBUTOR-NEXT: [[TMP1:%.*]] = icmp eq ptr [[X]], null 825; ATTRIBUTOR-NEXT: ret i1 [[TMP1]] 826; 827 %1 = icmp eq ptr %x, null 828 ret i1 %1 829} 830 831define i1 @captureDereferenceableOrNullICmp(ptr dereferenceable_or_null(4) %x) null_pointer_is_valid { 832; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind null_pointer_is_valid willreturn memory(none) 833; FNATTRS-LABEL: define noundef i1 @captureDereferenceableOrNullICmp 834; FNATTRS-SAME: (ptr readnone dereferenceable_or_null(4) [[X:%.*]]) #[[ATTR16:[0-9]+]] { 835; FNATTRS-NEXT: [[TMP1:%.*]] = icmp eq ptr [[X]], null 836; FNATTRS-NEXT: ret i1 [[TMP1]] 837; 838; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind null_pointer_is_valid willreturn memory(none) 839; ATTRIBUTOR-LABEL: define i1 @captureDereferenceableOrNullICmp 840; ATTRIBUTOR-SAME: (ptr nofree readnone dereferenceable_or_null(4) [[X:%.*]]) #[[ATTR12:[0-9]+]] { 841; ATTRIBUTOR-NEXT: [[TMP1:%.*]] = icmp eq ptr [[X]], null 842; ATTRIBUTOR-NEXT: ret i1 [[TMP1]] 843; 844 %1 = icmp eq ptr %x, null 845 ret i1 %1 846} 847 848declare void @capture(ptr) 849 850define void @nocapture_fptr(ptr %f, ptr %p) { 851; FNATTRS-LABEL: define void @nocapture_fptr 852; FNATTRS-SAME: (ptr readonly captures(none) [[F:%.*]], ptr [[P:%.*]]) { 853; FNATTRS-NEXT: [[RES:%.*]] = call ptr [[F]](ptr [[P]]) 854; FNATTRS-NEXT: call void @capture(ptr [[RES]]) 855; FNATTRS-NEXT: ret void 856; 857; ATTRIBUTOR-LABEL: define void @nocapture_fptr 858; ATTRIBUTOR-SAME: (ptr nofree nonnull captures(none) [[F:%.*]], ptr [[P:%.*]]) { 859; ATTRIBUTOR-NEXT: [[RES:%.*]] = call ptr [[F]](ptr [[P]]) 860; ATTRIBUTOR-NEXT: call void @capture(ptr [[RES]]) 861; ATTRIBUTOR-NEXT: ret void 862; 863 %res = call ptr %f(ptr %p) 864 call void @capture(ptr %res) 865 ret void 866} 867 868define void @recurse_fptr(ptr %f, ptr %p) { 869; FNATTRS-LABEL: define void @recurse_fptr 870; FNATTRS-SAME: (ptr readonly captures(none) [[F:%.*]], ptr [[P:%.*]]) { 871; FNATTRS-NEXT: [[RES:%.*]] = call ptr [[F]](ptr [[P]]) 872; FNATTRS-NEXT: store i8 0, ptr [[RES]], align 1 873; FNATTRS-NEXT: ret void 874; 875; ATTRIBUTOR-LABEL: define void @recurse_fptr 876; ATTRIBUTOR-SAME: (ptr nofree nonnull captures(none) [[F:%.*]], ptr [[P:%.*]]) { 877; ATTRIBUTOR-NEXT: [[RES:%.*]] = call ptr [[F]](ptr [[P]]) 878; ATTRIBUTOR-NEXT: store i8 0, ptr [[RES]], align 1 879; ATTRIBUTOR-NEXT: ret void 880; 881 %res = call ptr %f(ptr %p) 882 store i8 0, ptr %res 883 ret void 884} 885 886define void @readnone_indirec(ptr %f, ptr %p) { 887; FNATTRS: Function Attrs: nofree nosync memory(none) 888; FNATTRS-LABEL: define void @readnone_indirec 889; FNATTRS-SAME: (ptr readonly captures(none) [[F:%.*]], ptr readnone [[P:%.*]]) #[[ATTR17:[0-9]+]] { 890; FNATTRS-NEXT: call void [[F]](ptr [[P]]) #[[ATTR20:[0-9]+]] 891; FNATTRS-NEXT: ret void 892; 893; ATTRIBUTOR: Function Attrs: nosync memory(none) 894; ATTRIBUTOR-LABEL: define void @readnone_indirec 895; ATTRIBUTOR-SAME: (ptr nofree nonnull readnone captures(none) [[F:%.*]], ptr readnone [[P:%.*]]) #[[ATTR13:[0-9]+]] { 896; ATTRIBUTOR-NEXT: call void [[F]](ptr [[P]]) #[[ATTR20:[0-9]+]] 897; ATTRIBUTOR-NEXT: ret void 898; 899 call void %f(ptr %p) readnone 900 ret void 901} 902 903 904declare ptr @llvm.launder.invariant.group.p0(ptr) 905declare ptr @llvm.strip.invariant.group.p0(ptr) 906