1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes 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 5define void @nouses-argworn-funrn(ptr writeonly %.aaa) { 6; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 7; FNATTRS-LABEL: define {{[^@]+}}@nouses-argworn-funrn 8; FNATTRS-SAME: (ptr readnone captures(none) [[DOTAAA:%.*]]) #[[ATTR0:[0-9]+]] { 9; FNATTRS-NEXT: nouses-argworn-funrn_entry: 10; FNATTRS-NEXT: ret void 11; 12; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 13; ATTRIBUTOR-LABEL: define {{[^@]+}}@nouses-argworn-funrn 14; ATTRIBUTOR-SAME: (ptr nofree readnone captures(none) [[DOTAAA:%.*]]) #[[ATTR0:[0-9]+]] { 15; ATTRIBUTOR-NEXT: nouses-argworn-funrn_entry: 16; ATTRIBUTOR-NEXT: ret void 17; 18nouses-argworn-funrn_entry: 19 ret void 20} 21 22define void @nouses-argworn-funro(ptr writeonly %.aaa, ptr %.bbb) { 23; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) 24; FNATTRS-LABEL: define {{[^@]+}}@nouses-argworn-funro 25; FNATTRS-SAME: (ptr readnone captures(none) [[DOTAAA:%.*]], ptr readonly captures(none) [[DOTBBB:%.*]]) #[[ATTR1:[0-9]+]] { 26; FNATTRS-NEXT: nouses-argworn-funro_entry: 27; FNATTRS-NEXT: [[VAL:%.*]] = load i32, ptr [[DOTBBB]], align 4 28; FNATTRS-NEXT: ret void 29; 30; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) 31; ATTRIBUTOR-LABEL: define {{[^@]+}}@nouses-argworn-funro 32; ATTRIBUTOR-SAME: (ptr nofree readnone captures(none) [[DOTAAA:%.*]], ptr nofree nonnull readonly captures(none) [[DOTBBB:%.*]]) #[[ATTR1:[0-9]+]] { 33; ATTRIBUTOR-NEXT: nouses-argworn-funro_entry: 34; ATTRIBUTOR-NEXT: [[VAL:%.*]] = load i32, ptr [[DOTBBB]], align 4 35; ATTRIBUTOR-NEXT: ret void 36; 37nouses-argworn-funro_entry: 38 %val = load i32 , ptr %.bbb 39 ret void 40} 41 42%_type_of_d-ccc = type <{ ptr, i8, i8, i8, i8 }> 43 44@d-ccc = internal global %_type_of_d-ccc <{ ptr null, i8 1, i8 13, i8 0, i8 -127 }>, align 8 45 46define void @nouses-argworn-funwo(ptr writeonly %.aaa) { 47; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write, argmem: none, inaccessiblemem: none) 48; FNATTRS-LABEL: define {{[^@]+}}@nouses-argworn-funwo 49; FNATTRS-SAME: (ptr readnone captures(none) [[DOTAAA:%.*]]) #[[ATTR2:[0-9]+]] { 50; FNATTRS-NEXT: nouses-argworn-funwo_entry: 51; FNATTRS-NEXT: store i8 0, ptr getelementptr inbounds ([[_TYPE_OF_D_CCC:%.*]], ptr @d-ccc, i32 0, i32 3), align 1 52; FNATTRS-NEXT: ret void 53; 54; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write) 55; ATTRIBUTOR-LABEL: define {{[^@]+}}@nouses-argworn-funwo 56; ATTRIBUTOR-SAME: (ptr nofree readnone captures(none) [[DOTAAA:%.*]]) #[[ATTR2:[0-9]+]] { 57; ATTRIBUTOR-NEXT: nouses-argworn-funwo_entry: 58; ATTRIBUTOR-NEXT: store i8 0, ptr getelementptr inbounds ([[_TYPE_OF_D_CCC:%.*]], ptr @d-ccc, i32 0, i32 3), align 1 59; ATTRIBUTOR-NEXT: ret void 60; 61nouses-argworn-funwo_entry: 62 store i8 0, ptr getelementptr inbounds (%_type_of_d-ccc, ptr @d-ccc, i32 0, i32 3) 63 ret void 64} 65 66define void @test_store(ptr %p) { 67; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) 68; FNATTRS-LABEL: define {{[^@]+}}@test_store 69; FNATTRS-SAME: (ptr writeonly captures(none) initializes((0, 1)) [[P:%.*]]) #[[ATTR3:[0-9]+]] { 70; FNATTRS-NEXT: store i8 0, ptr [[P]], align 1 71; FNATTRS-NEXT: ret void 72; 73; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) 74; ATTRIBUTOR-LABEL: define {{[^@]+}}@test_store 75; ATTRIBUTOR-SAME: (ptr nofree nonnull writeonly captures(none) [[P:%.*]]) #[[ATTR3:[0-9]+]] { 76; ATTRIBUTOR-NEXT: store i8 0, ptr [[P]], align 1 77; ATTRIBUTOR-NEXT: ret void 78; 79 store i8 0, ptr %p 80 ret void 81} 82 83@G = external global ptr 84define i8 @test_store_capture(ptr %p) { 85; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(readwrite, argmem: read, inaccessiblemem: none) 86; FNATTRS-LABEL: define {{[^@]+}}@test_store_capture 87; FNATTRS-SAME: (ptr [[P:%.*]]) #[[ATTR4:[0-9]+]] { 88; FNATTRS-NEXT: store ptr [[P]], ptr @G, align 8 89; FNATTRS-NEXT: [[P2:%.*]] = load ptr, ptr @G, align 8 90; FNATTRS-NEXT: [[V:%.*]] = load i8, ptr [[P2]], align 1 91; FNATTRS-NEXT: ret i8 [[V]] 92; 93; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn 94; ATTRIBUTOR-LABEL: define {{[^@]+}}@test_store_capture 95; ATTRIBUTOR-SAME: (ptr nofree [[P:%.*]]) #[[ATTR4:[0-9]+]] { 96; ATTRIBUTOR-NEXT: store ptr [[P]], ptr @G, align 8 97; ATTRIBUTOR-NEXT: [[P2:%.*]] = load ptr, ptr @G, align 8 98; ATTRIBUTOR-NEXT: [[V:%.*]] = load i8, ptr [[P2]], align 1 99; ATTRIBUTOR-NEXT: ret i8 [[V]] 100; 101 store ptr %p, ptr @G 102 %p2 = load ptr, ptr @G 103 %v = load i8, ptr %p2 104 ret i8 %v 105} 106 107define void @test_addressing(ptr %p) { 108; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) 109; FNATTRS-LABEL: define {{[^@]+}}@test_addressing 110; FNATTRS-SAME: (ptr writeonly captures(none) initializes((8, 12)) [[P:%.*]]) #[[ATTR3]] { 111; FNATTRS-NEXT: [[GEP:%.*]] = getelementptr i8, ptr [[P]], i64 8 112; FNATTRS-NEXT: store i32 0, ptr [[GEP]], align 4 113; FNATTRS-NEXT: ret void 114; 115; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) 116; ATTRIBUTOR-LABEL: define {{[^@]+}}@test_addressing 117; ATTRIBUTOR-SAME: (ptr nofree writeonly captures(none) [[P:%.*]]) #[[ATTR3]] { 118; ATTRIBUTOR-NEXT: [[GEP:%.*]] = getelementptr i8, ptr [[P]], i64 8 119; ATTRIBUTOR-NEXT: store i32 0, ptr [[GEP]], align 4 120; ATTRIBUTOR-NEXT: ret void 121; 122 %gep = getelementptr i8, ptr %p, i64 8 123 store i32 0, ptr %gep 124 ret void 125} 126 127define void @test_readwrite(ptr %p) { 128; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) 129; FNATTRS-LABEL: define {{[^@]+}}@test_readwrite 130; FNATTRS-SAME: (ptr captures(none) [[P:%.*]]) #[[ATTR5:[0-9]+]] { 131; FNATTRS-NEXT: [[V:%.*]] = load i8, ptr [[P]], align 1 132; FNATTRS-NEXT: store i8 [[V]], ptr [[P]], align 1 133; FNATTRS-NEXT: ret void 134; 135; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) 136; ATTRIBUTOR-LABEL: define {{[^@]+}}@test_readwrite 137; ATTRIBUTOR-SAME: (ptr nofree nonnull captures(none) [[P:%.*]]) #[[ATTR5:[0-9]+]] { 138; ATTRIBUTOR-NEXT: [[V:%.*]] = load i8, ptr [[P]], align 1 139; ATTRIBUTOR-NEXT: store i8 [[V]], ptr [[P]], align 1 140; ATTRIBUTOR-NEXT: ret void 141; 142 %v = load i8, ptr %p 143 store i8 %v, ptr %p 144 ret void 145} 146 147define void @test_volatile(ptr %p) { 148; FNATTRS: Function Attrs: nofree norecurse nounwind memory(argmem: readwrite, inaccessiblemem: readwrite) 149; FNATTRS-LABEL: define {{[^@]+}}@test_volatile 150; FNATTRS-SAME: (ptr [[P:%.*]]) #[[ATTR6:[0-9]+]] { 151; FNATTRS-NEXT: store volatile i8 0, ptr [[P]], align 1 152; FNATTRS-NEXT: ret void 153; 154; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) 155; ATTRIBUTOR-LABEL: define {{[^@]+}}@test_volatile 156; ATTRIBUTOR-SAME: (ptr nofree [[P:%.*]]) #[[ATTR6:[0-9]+]] { 157; ATTRIBUTOR-NEXT: store volatile i8 0, ptr [[P]], align 1 158; ATTRIBUTOR-NEXT: ret void 159; 160 store volatile i8 0, ptr %p 161 ret void 162} 163 164define void @test_atomicrmw(ptr %p) { 165; FNATTRS: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) 166; FNATTRS-LABEL: define {{[^@]+}}@test_atomicrmw 167; FNATTRS-SAME: (ptr captures(none) [[P:%.*]]) #[[ATTR7:[0-9]+]] { 168; FNATTRS-NEXT: [[TMP1:%.*]] = atomicrmw add ptr [[P]], i8 0 seq_cst, align 1 169; FNATTRS-NEXT: ret void 170; 171; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) 172; ATTRIBUTOR-LABEL: define {{[^@]+}}@test_atomicrmw 173; ATTRIBUTOR-SAME: (ptr nofree nonnull captures(none) [[P:%.*]]) #[[ATTR6]] { 174; ATTRIBUTOR-NEXT: [[TMP1:%.*]] = atomicrmw add ptr [[P]], i8 0 seq_cst, align 1 175; ATTRIBUTOR-NEXT: ret void 176; 177 atomicrmw add ptr %p, i8 0 seq_cst 178 ret void 179} 180 181define void @test_ptrmask(ptr %p) { 182; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) 183; FNATTRS-LABEL: define {{[^@]+}}@test_ptrmask 184; FNATTRS-SAME: (ptr writeonly [[P:%.*]]) #[[ATTR3]] { 185; FNATTRS-NEXT: [[MASK:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P]], i64 -5) 186; FNATTRS-NEXT: store i8 0, ptr [[MASK]], align 1 187; FNATTRS-NEXT: ret void 188; 189; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) 190; ATTRIBUTOR-LABEL: define {{[^@]+}}@test_ptrmask 191; ATTRIBUTOR-SAME: (ptr nofree writeonly [[P:%.*]]) #[[ATTR3]] { 192; ATTRIBUTOR-NEXT: [[MASK:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P]], i64 -5) #[[ATTR9:[0-9]+]] 193; ATTRIBUTOR-NEXT: store i8 0, ptr [[MASK]], align 1 194; ATTRIBUTOR-NEXT: ret void 195; 196 %mask = call ptr @llvm.ptrmask.p0.i64(ptr %p, i64 -5) 197 store i8 0, ptr %mask 198 ret void 199} 200 201declare ptr @llvm.ptrmask.p0.i64(ptr, i64) 202 203declare void @direct1_callee(ptr %p) 204 205define void @direct1(ptr %p) { 206; COMMON-LABEL: define {{[^@]+}}@direct1 207; COMMON-SAME: (ptr [[P:%.*]]) { 208; COMMON-NEXT: call void @direct1_callee(ptr [[P]]) 209; COMMON-NEXT: ret void 210; 211 call void @direct1_callee(ptr %p) 212 ret void 213} 214 215declare void @direct2_callee(ptr %p) writeonly 216 217; writeonly w/o nocapture is not enough 218define void @direct2(ptr %p) { 219; FNATTRS: Function Attrs: memory(write) 220; FNATTRS-LABEL: define {{[^@]+}}@direct2 221; FNATTRS-SAME: (ptr [[P:%.*]]) #[[ATTR9:[0-9]+]] { 222; FNATTRS-NEXT: call void @direct2_callee(ptr [[P]]) 223; FNATTRS-NEXT: ret void 224; 225; ATTRIBUTOR: Function Attrs: memory(write) 226; ATTRIBUTOR-LABEL: define {{[^@]+}}@direct2 227; ATTRIBUTOR-SAME: (ptr writeonly [[P:%.*]]) #[[ATTR8:[0-9]+]] { 228; ATTRIBUTOR-NEXT: call void @direct2_callee(ptr [[P]]) #[[ATTR8]] 229; ATTRIBUTOR-NEXT: ret void 230; 231 call void @direct2_callee(ptr %p) 232 ; read back from global, read through pointer... 233 ret void 234} 235 236define void @direct2b(ptr %p) { 237; FNATTRS: Function Attrs: memory(write) 238; FNATTRS-LABEL: define {{[^@]+}}@direct2b 239; FNATTRS-SAME: (ptr writeonly captures(none) [[P:%.*]]) #[[ATTR9]] { 240; FNATTRS-NEXT: call void @direct2_callee(ptr captures(none) [[P]]) 241; FNATTRS-NEXT: ret void 242; 243; ATTRIBUTOR: Function Attrs: memory(write) 244; ATTRIBUTOR-LABEL: define {{[^@]+}}@direct2b 245; ATTRIBUTOR-SAME: (ptr writeonly captures(none) [[P:%.*]]) #[[ATTR8]] { 246; ATTRIBUTOR-NEXT: call void @direct2_callee(ptr writeonly captures(none) [[P]]) #[[ATTR8]] 247; ATTRIBUTOR-NEXT: ret void 248; 249 call void @direct2_callee(ptr nocapture %p) 250 ret void 251} 252 253declare void @direct3_callee(ptr nocapture writeonly %p) 254 255define void @direct3(ptr %p) { 256; FNATTRS-LABEL: define {{[^@]+}}@direct3 257; FNATTRS-SAME: (ptr writeonly captures(none) [[P:%.*]]) { 258; FNATTRS-NEXT: call void @direct3_callee(ptr [[P]]) 259; FNATTRS-NEXT: ret void 260; 261; ATTRIBUTOR-LABEL: define {{[^@]+}}@direct3 262; ATTRIBUTOR-SAME: (ptr writeonly captures(none) [[P:%.*]]) { 263; ATTRIBUTOR-NEXT: call void @direct3_callee(ptr writeonly captures(none) [[P]]) 264; ATTRIBUTOR-NEXT: ret void 265; 266 call void @direct3_callee(ptr %p) 267 ret void 268} 269 270define void @direct3b(ptr %p) { 271; COMMON-LABEL: define {{[^@]+}}@direct3b 272; COMMON-SAME: (ptr [[P:%.*]]) { 273; COMMON-NEXT: call void @direct3_callee(ptr [[P]]) [ "may-read-and-capture"(ptr [[P]]) ] 274; COMMON-NEXT: ret void 275; 276 call void @direct3_callee(ptr %p) ["may-read-and-capture"(ptr %p)] 277 ret void 278} 279 280define void @direct3c(ptr %p) { 281; FNATTRS-LABEL: define {{[^@]+}}@direct3c 282; FNATTRS-SAME: (ptr captures(none) [[P:%.*]]) { 283; FNATTRS-NEXT: call void @direct3_callee(ptr [[P]]) [ "may-read"() ] 284; FNATTRS-NEXT: ret void 285; 286; ATTRIBUTOR-LABEL: define {{[^@]+}}@direct3c 287; ATTRIBUTOR-SAME: (ptr captures(none) [[P:%.*]]) { 288; ATTRIBUTOR-NEXT: call void @direct3_callee(ptr captures(none) [[P]]) [ "may-read"() ] 289; ATTRIBUTOR-NEXT: ret void 290; 291 call void @direct3_callee(ptr %p) ["may-read"()] 292 ret void 293} 294 295define void @fptr_test1(ptr %p, ptr %f) { 296; FNATTRS-LABEL: define {{[^@]+}}@fptr_test1 297; FNATTRS-SAME: (ptr [[P:%.*]], ptr readonly captures(none) [[F:%.*]]) { 298; FNATTRS-NEXT: call void [[F]](ptr [[P]]) 299; FNATTRS-NEXT: ret void 300; 301; ATTRIBUTOR-LABEL: define {{[^@]+}}@fptr_test1 302; ATTRIBUTOR-SAME: (ptr [[P:%.*]], ptr nofree nonnull captures(none) [[F:%.*]]) { 303; ATTRIBUTOR-NEXT: call void [[F]](ptr [[P]]) 304; ATTRIBUTOR-NEXT: ret void 305; 306 call void %f(ptr %p) 307 ret void 308} 309 310define void @fptr_test2(ptr %p, ptr %f) { 311; FNATTRS-LABEL: define {{[^@]+}}@fptr_test2 312; FNATTRS-SAME: (ptr writeonly captures(none) [[P:%.*]], ptr readonly captures(none) [[F:%.*]]) { 313; FNATTRS-NEXT: call void [[F]](ptr writeonly captures(none) [[P]]) 314; FNATTRS-NEXT: ret void 315; 316; ATTRIBUTOR-LABEL: define {{[^@]+}}@fptr_test2 317; ATTRIBUTOR-SAME: (ptr captures(none) [[P:%.*]], ptr nofree nonnull captures(none) [[F:%.*]]) { 318; ATTRIBUTOR-NEXT: call void [[F]](ptr writeonly captures(none) [[P]]) 319; ATTRIBUTOR-NEXT: ret void 320; 321 call void %f(ptr nocapture writeonly %p) 322 ret void 323} 324 325define void @fptr_test3(ptr %p, ptr %f) { 326; FNATTRS: Function Attrs: memory(write) 327; FNATTRS-LABEL: define {{[^@]+}}@fptr_test3 328; FNATTRS-SAME: (ptr writeonly captures(none) [[P:%.*]], ptr readonly captures(none) [[F:%.*]]) #[[ATTR9]] { 329; FNATTRS-NEXT: call void [[F]](ptr captures(none) [[P]]) #[[ATTR9]] 330; FNATTRS-NEXT: ret void 331; 332; ATTRIBUTOR: Function Attrs: memory(write) 333; ATTRIBUTOR-LABEL: define {{[^@]+}}@fptr_test3 334; ATTRIBUTOR-SAME: (ptr writeonly captures(none) [[P:%.*]], ptr nofree nonnull writeonly captures(none) [[F:%.*]]) #[[ATTR8]] { 335; ATTRIBUTOR-NEXT: call void [[F]](ptr captures(none) [[P]]) #[[ATTR8]] 336; ATTRIBUTOR-NEXT: ret void 337; 338 call void %f(ptr nocapture %p) writeonly 339 ret void 340} 341 342define void @test_argmem_none_callee(ptr %p) { 343; FNATTRS-LABEL: define {{[^@]+}}@test_argmem_none_callee 344; FNATTRS-SAME: (ptr readnone captures(none) [[P:%.*]]) { 345; FNATTRS-NEXT: call void @direct1_callee(ptr captures(none) [[P]]) #[[ATTR10:[0-9]+]] 346; FNATTRS-NEXT: ret void 347; 348; ATTRIBUTOR-LABEL: define {{[^@]+}}@test_argmem_none_callee 349; ATTRIBUTOR-SAME: (ptr captures(none) [[P:%.*]]) { 350; ATTRIBUTOR-NEXT: call void @direct1_callee(ptr captures(none) [[P]]) #[[ATTR10:[0-9]+]] 351; ATTRIBUTOR-NEXT: ret void 352; 353 call void @direct1_callee(ptr nocapture %p) memory(readwrite, argmem: none) 354 ret void 355} 356 357define void @test_argmem_read_callee(ptr %p) { 358; FNATTRS-LABEL: define {{[^@]+}}@test_argmem_read_callee 359; FNATTRS-SAME: (ptr readonly captures(none) [[P:%.*]]) { 360; FNATTRS-NEXT: call void @direct1_callee(ptr captures(none) [[P]]) #[[ATTR11:[0-9]+]] 361; FNATTRS-NEXT: ret void 362; 363; ATTRIBUTOR-LABEL: define {{[^@]+}}@test_argmem_read_callee 364; ATTRIBUTOR-SAME: (ptr captures(none) [[P:%.*]]) { 365; ATTRIBUTOR-NEXT: call void @direct1_callee(ptr captures(none) [[P]]) #[[ATTR11:[0-9]+]] 366; ATTRIBUTOR-NEXT: ret void 367; 368 call void @direct1_callee(ptr nocapture %p) memory(readwrite, argmem: read) 369 ret void 370} 371 372define void @test_argmem_write_callee(ptr %p) { 373; FNATTRS-LABEL: define {{[^@]+}}@test_argmem_write_callee 374; FNATTRS-SAME: (ptr writeonly captures(none) [[P:%.*]]) { 375; FNATTRS-NEXT: call void @direct1_callee(ptr captures(none) [[P]]) #[[ATTR12:[0-9]+]] 376; FNATTRS-NEXT: ret void 377; 378; ATTRIBUTOR-LABEL: define {{[^@]+}}@test_argmem_write_callee 379; ATTRIBUTOR-SAME: (ptr captures(none) [[P:%.*]]) { 380; ATTRIBUTOR-NEXT: call void @direct1_callee(ptr captures(none) [[P]]) #[[ATTR12:[0-9]+]] 381; ATTRIBUTOR-NEXT: ret void 382; 383 call void @direct1_callee(ptr nocapture %p) memory(readwrite, argmem: write) 384 ret void 385} 386