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 i32 20 6 7define void @test_no_read_or_write() { 8; COMMON: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 9; COMMON-LABEL: define void @test_no_read_or_write 10; COMMON-SAME: () #[[ATTR0:[0-9]+]] { 11; COMMON-NEXT: entry: 12; COMMON-NEXT: ret void 13; 14entry: 15 ret void 16} 17 18define i32 @test_only_read_arg(ptr %ptr) { 19; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) 20; FNATTRS-LABEL: define i32 @test_only_read_arg 21; FNATTRS-SAME: (ptr readonly captures(none) [[PTR:%.*]]) #[[ATTR1:[0-9]+]] { 22; FNATTRS-NEXT: entry: 23; FNATTRS-NEXT: [[L:%.*]] = load i32, ptr [[PTR]], align 4 24; FNATTRS-NEXT: ret i32 [[L]] 25; 26; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) 27; ATTRIBUTOR-LABEL: define i32 @test_only_read_arg 28; ATTRIBUTOR-SAME: (ptr nofree nonnull readonly captures(none) [[PTR:%.*]]) #[[ATTR1:[0-9]+]] { 29; ATTRIBUTOR-NEXT: entry: 30; ATTRIBUTOR-NEXT: [[L:%.*]] = load i32, ptr [[PTR]], align 4 31; ATTRIBUTOR-NEXT: ret i32 [[L]] 32; 33entry: 34 %l = load i32, ptr %ptr 35 ret i32 %l 36} 37 38define i32 @test_only_read_arg_already_has_argmemonly(ptr %ptr) argmemonly { 39; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) 40; FNATTRS-LABEL: define i32 @test_only_read_arg_already_has_argmemonly 41; FNATTRS-SAME: (ptr readonly captures(none) [[PTR:%.*]]) #[[ATTR1]] { 42; FNATTRS-NEXT: entry: 43; FNATTRS-NEXT: [[L:%.*]] = load i32, ptr [[PTR]], align 4 44; FNATTRS-NEXT: ret i32 [[L]] 45; 46; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) 47; ATTRIBUTOR-LABEL: define i32 @test_only_read_arg_already_has_argmemonly 48; ATTRIBUTOR-SAME: (ptr nofree nonnull readonly captures(none) [[PTR:%.*]]) #[[ATTR1]] { 49; ATTRIBUTOR-NEXT: entry: 50; ATTRIBUTOR-NEXT: [[L:%.*]] = load i32, ptr [[PTR]], align 4 51; ATTRIBUTOR-NEXT: ret i32 [[L]] 52; 53entry: 54 %l = load i32, ptr %ptr 55 ret i32 %l 56} 57 58define i32 @test_read_global() { 59; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read, argmem: none, inaccessiblemem: none) 60; FNATTRS-LABEL: define i32 @test_read_global 61; FNATTRS-SAME: () #[[ATTR2:[0-9]+]] { 62; FNATTRS-NEXT: entry: 63; FNATTRS-NEXT: [[L:%.*]] = load i32, ptr @g, align 4 64; FNATTRS-NEXT: ret i32 [[L]] 65; 66; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read) 67; ATTRIBUTOR-LABEL: define i32 @test_read_global 68; ATTRIBUTOR-SAME: () #[[ATTR2:[0-9]+]] { 69; ATTRIBUTOR-NEXT: entry: 70; ATTRIBUTOR-NEXT: [[L:%.*]] = load i32, ptr @g, align 4 71; ATTRIBUTOR-NEXT: ret i32 [[L]] 72; 73entry: 74 %l = load i32, ptr @g 75 ret i32 %l 76} 77 78define i32 @test_read_loaded_ptr(ptr %ptr) { 79; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read, inaccessiblemem: none) 80; FNATTRS-LABEL: define i32 @test_read_loaded_ptr 81; FNATTRS-SAME: (ptr readonly captures(none) [[PTR:%.*]]) #[[ATTR3:[0-9]+]] { 82; FNATTRS-NEXT: entry: 83; FNATTRS-NEXT: [[L:%.*]] = load ptr, ptr [[PTR]], align 8 84; FNATTRS-NEXT: [[L_2:%.*]] = load i32, ptr [[L]], align 4 85; FNATTRS-NEXT: ret i32 [[L_2]] 86; 87; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read) 88; ATTRIBUTOR-LABEL: define i32 @test_read_loaded_ptr 89; ATTRIBUTOR-SAME: (ptr nofree nonnull readonly captures(none) [[PTR:%.*]]) #[[ATTR2]] { 90; ATTRIBUTOR-NEXT: entry: 91; ATTRIBUTOR-NEXT: [[L:%.*]] = load ptr, ptr [[PTR]], align 8 92; ATTRIBUTOR-NEXT: [[L_2:%.*]] = load i32, ptr [[L]], align 4 93; ATTRIBUTOR-NEXT: ret i32 [[L_2]] 94; 95entry: 96 %l = load ptr, ptr %ptr 97 %l.2 = load i32, ptr %l 98 ret i32 %l.2 99} 100 101define void @test_only_write_arg(ptr %ptr) { 102; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) 103; FNATTRS-LABEL: define void @test_only_write_arg 104; FNATTRS-SAME: (ptr writeonly captures(none) initializes((0, 4)) [[PTR:%.*]]) #[[ATTR4:[0-9]+]] { 105; FNATTRS-NEXT: entry: 106; FNATTRS-NEXT: store i32 0, ptr [[PTR]], align 4 107; FNATTRS-NEXT: ret void 108; 109; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) 110; ATTRIBUTOR-LABEL: define void @test_only_write_arg 111; ATTRIBUTOR-SAME: (ptr nofree nonnull writeonly captures(none) [[PTR:%.*]]) #[[ATTR3:[0-9]+]] { 112; ATTRIBUTOR-NEXT: entry: 113; ATTRIBUTOR-NEXT: store i32 0, ptr [[PTR]], align 4 114; ATTRIBUTOR-NEXT: ret void 115; 116entry: 117 store i32 0, ptr %ptr 118 ret void 119} 120 121define void @test_write_global() { 122; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write, argmem: none, inaccessiblemem: none) 123; FNATTRS-LABEL: define void @test_write_global 124; FNATTRS-SAME: () #[[ATTR5:[0-9]+]] { 125; FNATTRS-NEXT: entry: 126; FNATTRS-NEXT: store i32 0, ptr @g, align 4 127; FNATTRS-NEXT: ret void 128; 129; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write) 130; ATTRIBUTOR-LABEL: define void @test_write_global 131; ATTRIBUTOR-SAME: () #[[ATTR4:[0-9]+]] { 132; ATTRIBUTOR-NEXT: entry: 133; ATTRIBUTOR-NEXT: store i32 0, ptr @g, align 4 134; ATTRIBUTOR-NEXT: ret void 135; 136entry: 137 store i32 0, ptr @g 138 ret void 139} 140 141declare void @fn_may_access_memory() 142 143define void @test_call_may_access_memory() { 144; COMMON-LABEL: define void @test_call_may_access_memory() { 145; COMMON-NEXT: entry: 146; COMMON-NEXT: call void @fn_may_access_memory() 147; COMMON-NEXT: ret void 148; 149entry: 150 call void @fn_may_access_memory() 151 ret void 152} 153 154declare i32 @fn_readnone() readnone 155 156define void @test_call_readnone(ptr %ptr) { 157; FNATTRS: Function Attrs: memory(argmem: write) 158; FNATTRS-LABEL: define void @test_call_readnone 159; FNATTRS-SAME: (ptr writeonly captures(none) initializes((0, 4)) [[PTR:%.*]]) #[[ATTR7:[0-9]+]] { 160; FNATTRS-NEXT: entry: 161; FNATTRS-NEXT: [[C:%.*]] = call i32 @fn_readnone() 162; FNATTRS-NEXT: store i32 [[C]], ptr [[PTR]], align 4 163; FNATTRS-NEXT: ret void 164; 165; ATTRIBUTOR: Function Attrs: nosync memory(argmem: write) 166; ATTRIBUTOR-LABEL: define void @test_call_readnone 167; ATTRIBUTOR-SAME: (ptr nofree writeonly captures(none) [[PTR:%.*]]) #[[ATTR6:[0-9]+]] { 168; ATTRIBUTOR-NEXT: entry: 169; ATTRIBUTOR-NEXT: [[C:%.*]] = call i32 @fn_readnone() #[[ATTR18:[0-9]+]] 170; ATTRIBUTOR-NEXT: store i32 [[C]], ptr [[PTR]], align 4 171; ATTRIBUTOR-NEXT: ret void 172; 173entry: 174 %c = call i32 @fn_readnone() 175 store i32 %c, ptr %ptr 176 ret void 177} 178 179declare i32 @fn_argmemonly(ptr) argmemonly 180 181define i32 @test_call_argmemonly(ptr %ptr) { 182; FNATTRS: Function Attrs: memory(argmem: readwrite) 183; FNATTRS-LABEL: define i32 @test_call_argmemonly 184; FNATTRS-SAME: (ptr [[PTR:%.*]]) #[[ATTR8:[0-9]+]] { 185; FNATTRS-NEXT: entry: 186; FNATTRS-NEXT: [[C:%.*]] = call i32 @fn_argmemonly(ptr [[PTR]]) 187; FNATTRS-NEXT: ret i32 [[C]] 188; 189; ATTRIBUTOR: Function Attrs: memory(argmem: readwrite) 190; ATTRIBUTOR-LABEL: define i32 @test_call_argmemonly 191; ATTRIBUTOR-SAME: (ptr [[PTR:%.*]]) #[[ATTR7:[0-9]+]] { 192; ATTRIBUTOR-NEXT: entry: 193; ATTRIBUTOR-NEXT: [[C:%.*]] = call i32 @fn_argmemonly(ptr [[PTR]]) 194; ATTRIBUTOR-NEXT: ret i32 [[C]] 195; 196entry: 197 %c = call i32 @fn_argmemonly(ptr %ptr) 198 ret i32 %c 199} 200 201define i32 @test_call_fn_where_argmemonly_can_be_inferred(ptr %ptr) { 202; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) 203; FNATTRS-LABEL: define i32 @test_call_fn_where_argmemonly_can_be_inferred 204; FNATTRS-SAME: (ptr readonly captures(none) [[PTR:%.*]]) #[[ATTR1]] { 205; FNATTRS-NEXT: entry: 206; FNATTRS-NEXT: [[C:%.*]] = call i32 @test_only_read_arg(ptr [[PTR]]) 207; FNATTRS-NEXT: ret i32 [[C]] 208; 209; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) 210; ATTRIBUTOR-LABEL: define i32 @test_call_fn_where_argmemonly_can_be_inferred 211; ATTRIBUTOR-SAME: (ptr nofree readonly captures(none) [[PTR:%.*]]) #[[ATTR1]] { 212; ATTRIBUTOR-NEXT: entry: 213; ATTRIBUTOR-NEXT: [[C:%.*]] = call i32 @test_only_read_arg(ptr nofree readonly captures(none) [[PTR]]) #[[ATTR19:[0-9]+]] 214; ATTRIBUTOR-NEXT: ret i32 [[C]] 215; 216entry: 217 %c = call i32 @test_only_read_arg(ptr %ptr) 218 ret i32 %c 219} 220 221define void @test_memcpy_argonly(ptr %dst, ptr %src) { 222; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) 223; FNATTRS-LABEL: define void @test_memcpy_argonly 224; FNATTRS-SAME: (ptr writeonly captures(none) initializes((0, 32)) [[DST:%.*]], ptr readonly captures(none) [[SRC:%.*]]) #[[ATTR9:[0-9]+]] { 225; FNATTRS-NEXT: entry: 226; FNATTRS-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr [[DST]], ptr [[SRC]], i64 32, i1 false) 227; FNATTRS-NEXT: ret void 228; 229; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) 230; ATTRIBUTOR-LABEL: define void @test_memcpy_argonly 231; ATTRIBUTOR-SAME: (ptr nofree writeonly captures(none) [[DST:%.*]], ptr nofree readonly captures(none) [[SRC:%.*]]) #[[ATTR8:[0-9]+]] { 232; ATTRIBUTOR-NEXT: entry: 233; ATTRIBUTOR-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr writeonly captures(none) [[DST]], ptr readonly captures(none) [[SRC]], i64 32, i1 false) #[[ATTR20:[0-9]+]] 234; ATTRIBUTOR-NEXT: ret void 235; 236entry: 237 call void @llvm.memcpy.p0.p0.i64(ptr %dst, ptr %src, i64 32, i1 false) 238 ret void 239} 240 241declare void @llvm.memcpy.p0.p0.i64(ptr, ptr, i64, i1) 242 243@arr = global [32 x i8] zeroinitializer 244 245define void @test_memcpy_src_global(ptr %dst) { 246; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(readwrite, inaccessiblemem: none) 247; FNATTRS-LABEL: define void @test_memcpy_src_global 248; FNATTRS-SAME: (ptr writeonly captures(none) initializes((0, 32)) [[DST:%.*]]) #[[ATTR11:[0-9]+]] { 249; FNATTRS-NEXT: entry: 250; FNATTRS-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr [[DST]], ptr @arr, i64 32, i1 false) 251; FNATTRS-NEXT: ret void 252; 253; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn 254; ATTRIBUTOR-LABEL: define void @test_memcpy_src_global 255; ATTRIBUTOR-SAME: (ptr nofree writeonly captures(none) [[DST:%.*]]) #[[ATTR10:[0-9]+]] { 256; ATTRIBUTOR-NEXT: entry: 257; ATTRIBUTOR-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr writeonly captures(none) [[DST]], ptr readonly @arr, i64 32, i1 false) #[[ATTR20]] 258; ATTRIBUTOR-NEXT: ret void 259; 260entry: 261 call void @llvm.memcpy.p0.p0.i64(ptr %dst, ptr @arr, i64 32, i1 false) 262 ret void 263} 264 265define void @test_memcpy_dst_global(ptr %src) { 266; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(readwrite, inaccessiblemem: none) 267; FNATTRS-LABEL: define void @test_memcpy_dst_global 268; FNATTRS-SAME: (ptr readonly captures(none) [[SRC:%.*]]) #[[ATTR11]] { 269; FNATTRS-NEXT: entry: 270; FNATTRS-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr @arr, ptr [[SRC]], i64 32, i1 false) 271; FNATTRS-NEXT: ret void 272; 273; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn 274; ATTRIBUTOR-LABEL: define void @test_memcpy_dst_global 275; ATTRIBUTOR-SAME: (ptr nofree readonly captures(none) [[SRC:%.*]]) #[[ATTR10]] { 276; ATTRIBUTOR-NEXT: entry: 277; ATTRIBUTOR-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr writeonly @arr, ptr readonly captures(none) [[SRC]], i64 32, i1 false) #[[ATTR20]] 278; ATTRIBUTOR-NEXT: ret void 279; 280entry: 281 call void @llvm.memcpy.p0.p0.i64(ptr @arr, ptr %src, i64 32, i1 false) 282 ret void 283} 284 285define i32 @test_read_arg_access_alloca(ptr %ptr) { 286; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) 287; FNATTRS-LABEL: define i32 @test_read_arg_access_alloca 288; FNATTRS-SAME: (ptr readonly captures(none) [[PTR:%.*]]) #[[ATTR1]] { 289; FNATTRS-NEXT: entry: 290; FNATTRS-NEXT: [[A:%.*]] = alloca i32, align 4 291; FNATTRS-NEXT: [[L:%.*]] = load i32, ptr [[PTR]], align 4 292; FNATTRS-NEXT: store i32 [[L]], ptr [[A]], align 4 293; FNATTRS-NEXT: [[L_2:%.*]] = load i32, ptr [[A]], align 4 294; FNATTRS-NEXT: ret i32 [[L_2]] 295; 296; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) 297; ATTRIBUTOR-LABEL: define i32 @test_read_arg_access_alloca 298; ATTRIBUTOR-SAME: (ptr nofree nonnull readonly captures(none) [[PTR:%.*]]) #[[ATTR8]] { 299; ATTRIBUTOR-NEXT: entry: 300; ATTRIBUTOR-NEXT: [[A:%.*]] = alloca i32, align 4 301; ATTRIBUTOR-NEXT: [[L:%.*]] = load i32, ptr [[PTR]], align 4 302; ATTRIBUTOR-NEXT: store i32 [[L]], ptr [[A]], align 4 303; ATTRIBUTOR-NEXT: [[L_2:%.*]] = load i32, ptr [[A]], align 4 304; ATTRIBUTOR-NEXT: ret i32 [[L_2]] 305; 306entry: 307 %a = alloca i32 308 %l = load i32, ptr %ptr 309 store i32 %l, ptr %a 310 %l.2 = load i32, ptr %a 311 ret i32 %l.2 312} 313 314declare void @fn_inaccessiblememonly() inaccessiblememonly 315 316define void @test_inaccessiblememonly() { 317; FNATTRS: Function Attrs: memory(inaccessiblemem: readwrite) 318; FNATTRS-LABEL: define void @test_inaccessiblememonly 319; FNATTRS-SAME: () #[[ATTR12:[0-9]+]] { 320; FNATTRS-NEXT: call void @fn_inaccessiblememonly() 321; FNATTRS-NEXT: ret void 322; 323; ATTRIBUTOR: Function Attrs: memory(inaccessiblemem: readwrite) 324; ATTRIBUTOR-LABEL: define void @test_inaccessiblememonly 325; ATTRIBUTOR-SAME: () #[[ATTR11:[0-9]+]] { 326; ATTRIBUTOR-NEXT: call void @fn_inaccessiblememonly() 327; ATTRIBUTOR-NEXT: ret void 328; 329 call void @fn_inaccessiblememonly() 330 ret void 331} 332 333define void @test_inaccessiblememonly_readonly() { 334; FNATTRS: Function Attrs: nofree memory(inaccessiblemem: read) 335; FNATTRS-LABEL: define void @test_inaccessiblememonly_readonly 336; FNATTRS-SAME: () #[[ATTR13:[0-9]+]] { 337; FNATTRS-NEXT: call void @fn_inaccessiblememonly() #[[ATTR19:[0-9]+]] 338; FNATTRS-NEXT: ret void 339; 340; ATTRIBUTOR: Function Attrs: nosync memory(inaccessiblemem: read) 341; ATTRIBUTOR-LABEL: define void @test_inaccessiblememonly_readonly 342; ATTRIBUTOR-SAME: () #[[ATTR12:[0-9]+]] { 343; ATTRIBUTOR-NEXT: call void @fn_inaccessiblememonly() #[[ATTR21:[0-9]+]] 344; ATTRIBUTOR-NEXT: ret void 345; 346 call void @fn_inaccessiblememonly() readonly 347 ret void 348} 349 350define void @test_inaccessibleorargmemonly_readonly(ptr %arg) { 351; FNATTRS: Function Attrs: nofree memory(argmem: read, inaccessiblemem: read) 352; FNATTRS-LABEL: define void @test_inaccessibleorargmemonly_readonly 353; FNATTRS-SAME: (ptr readonly captures(none) [[ARG:%.*]]) #[[ATTR14:[0-9]+]] { 354; FNATTRS-NEXT: [[TMP1:%.*]] = load i32, ptr [[ARG]], align 4 355; FNATTRS-NEXT: call void @fn_inaccessiblememonly() #[[ATTR19]] 356; FNATTRS-NEXT: ret void 357; 358; ATTRIBUTOR: Function Attrs: nosync memory(argmem: read, inaccessiblemem: read) 359; ATTRIBUTOR-LABEL: define void @test_inaccessibleorargmemonly_readonly 360; ATTRIBUTOR-SAME: (ptr nofree nonnull readonly captures(none) [[ARG:%.*]]) #[[ATTR13:[0-9]+]] { 361; ATTRIBUTOR-NEXT: [[TMP1:%.*]] = load i32, ptr [[ARG]], align 4 362; ATTRIBUTOR-NEXT: call void @fn_inaccessiblememonly() #[[ATTR21]] 363; ATTRIBUTOR-NEXT: ret void 364; 365 load i32, ptr %arg 366 call void @fn_inaccessiblememonly() readonly 367 ret void 368} 369 370define void @test_inaccessibleorargmemonly_readwrite(ptr %arg) { 371; FNATTRS: Function Attrs: memory(argmem: write, inaccessiblemem: read) 372; FNATTRS-LABEL: define void @test_inaccessibleorargmemonly_readwrite 373; FNATTRS-SAME: (ptr writeonly captures(none) initializes((0, 4)) [[ARG:%.*]]) #[[ATTR15:[0-9]+]] { 374; FNATTRS-NEXT: store i32 0, ptr [[ARG]], align 4 375; FNATTRS-NEXT: call void @fn_inaccessiblememonly() #[[ATTR19]] 376; FNATTRS-NEXT: ret void 377; 378; ATTRIBUTOR: Function Attrs: nosync memory(argmem: readwrite, inaccessiblemem: readwrite) 379; ATTRIBUTOR-LABEL: define void @test_inaccessibleorargmemonly_readwrite 380; ATTRIBUTOR-SAME: (ptr nofree nonnull writeonly captures(none) [[ARG:%.*]]) #[[ATTR14:[0-9]+]] { 381; ATTRIBUTOR-NEXT: store i32 0, ptr [[ARG]], align 4 382; ATTRIBUTOR-NEXT: call void @fn_inaccessiblememonly() #[[ATTR21]] 383; ATTRIBUTOR-NEXT: ret void 384; 385 store i32 0, ptr %arg 386 call void @fn_inaccessiblememonly() readonly 387 ret void 388} 389 390define void @test_recursive_argmem_read(ptr %p) { 391; FNATTRS: Function Attrs: nofree nosync nounwind memory(read, inaccessiblemem: none) 392; FNATTRS-LABEL: define void @test_recursive_argmem_read 393; FNATTRS-SAME: (ptr readonly captures(none) [[P:%.*]]) #[[ATTR16:[0-9]+]] { 394; FNATTRS-NEXT: [[PVAL:%.*]] = load ptr, ptr [[P]], align 8 395; FNATTRS-NEXT: call void @test_recursive_argmem_read(ptr [[PVAL]]) 396; FNATTRS-NEXT: ret void 397; 398; ATTRIBUTOR: Function Attrs: nofree nosync nounwind memory(read) 399; ATTRIBUTOR-LABEL: define void @test_recursive_argmem_read 400; ATTRIBUTOR-SAME: (ptr nofree nonnull readonly captures(none) [[P:%.*]]) #[[ATTR15:[0-9]+]] { 401; ATTRIBUTOR-NEXT: [[PVAL:%.*]] = load ptr, ptr [[P]], align 8 402; ATTRIBUTOR-NEXT: call void @test_recursive_argmem_read(ptr nofree readonly captures(none) [[PVAL]]) #[[ATTR15]] 403; ATTRIBUTOR-NEXT: ret void 404; 405 %pval = load ptr, ptr %p 406 call void @test_recursive_argmem_read(ptr %pval) 407 ret void 408} 409 410define void @test_recursive_argmem_readwrite(ptr %p) { 411; FNATTRS: Function Attrs: nofree nosync nounwind memory(readwrite, inaccessiblemem: none) 412; FNATTRS-LABEL: define void @test_recursive_argmem_readwrite 413; FNATTRS-SAME: (ptr captures(none) [[P:%.*]]) #[[ATTR17:[0-9]+]] { 414; FNATTRS-NEXT: [[PVAL:%.*]] = load ptr, ptr [[P]], align 8 415; FNATTRS-NEXT: store i32 0, ptr [[P]], align 4 416; FNATTRS-NEXT: call void @test_recursive_argmem_readwrite(ptr [[PVAL]]) 417; FNATTRS-NEXT: ret void 418; 419; ATTRIBUTOR: Function Attrs: nofree nosync nounwind 420; ATTRIBUTOR-LABEL: define void @test_recursive_argmem_readwrite 421; ATTRIBUTOR-SAME: (ptr nofree nonnull captures(none) [[P:%.*]]) #[[ATTR16:[0-9]+]] { 422; ATTRIBUTOR-NEXT: [[PVAL:%.*]] = load ptr, ptr [[P]], align 8 423; ATTRIBUTOR-NEXT: store i32 0, ptr [[P]], align 4 424; ATTRIBUTOR-NEXT: call void @test_recursive_argmem_readwrite(ptr nofree captures(none) [[PVAL]]) #[[ATTR16]] 425; ATTRIBUTOR-NEXT: ret void 426; 427 %pval = load ptr, ptr %p 428 store i32 0, ptr %p 429 call void @test_recursive_argmem_readwrite(ptr %pval) 430 ret void 431} 432 433define void @test_recursive_argmem_read_alloca(ptr %p) { 434; FNATTRS: Function Attrs: nofree nosync nounwind memory(argmem: read) 435; FNATTRS-LABEL: define void @test_recursive_argmem_read_alloca 436; FNATTRS-SAME: (ptr readonly captures(none) [[P:%.*]]) #[[ATTR18:[0-9]+]] { 437; FNATTRS-NEXT: [[A:%.*]] = alloca ptr, align 8 438; FNATTRS-NEXT: [[TMP1:%.*]] = load i32, ptr [[P]], align 4 439; FNATTRS-NEXT: call void @test_recursive_argmem_read_alloca(ptr [[A]]) 440; FNATTRS-NEXT: ret void 441; 442; ATTRIBUTOR: Function Attrs: nofree nosync nounwind memory(argmem: read) 443; ATTRIBUTOR-LABEL: define void @test_recursive_argmem_read_alloca 444; ATTRIBUTOR-SAME: (ptr nofree nonnull readonly captures(none) [[P:%.*]]) #[[ATTR17:[0-9]+]] { 445; ATTRIBUTOR-NEXT: [[A:%.*]] = alloca ptr, align 8 446; ATTRIBUTOR-NEXT: [[TMP1:%.*]] = load i32, ptr [[P]], align 4 447; ATTRIBUTOR-NEXT: call void @test_recursive_argmem_read_alloca(ptr nofree nonnull readonly captures(none) [[A]]) #[[ATTR15]] 448; ATTRIBUTOR-NEXT: ret void 449; 450 %a = alloca ptr 451 load i32, ptr %p 452 call void @test_recursive_argmem_read_alloca(ptr %a) 453 ret void 454} 455 456define void @test_scc_argmem_read_1(ptr %p) { 457; FNATTRS: Function Attrs: nofree nosync nounwind memory(read, inaccessiblemem: none) 458; FNATTRS-LABEL: define void @test_scc_argmem_read_1 459; FNATTRS-SAME: (ptr readonly captures(none) [[P:%.*]]) #[[ATTR16]] { 460; FNATTRS-NEXT: [[PVAL:%.*]] = load ptr, ptr [[P]], align 8 461; FNATTRS-NEXT: call void @test_scc_argmem_read_2(ptr [[PVAL]]) 462; FNATTRS-NEXT: ret void 463; 464; ATTRIBUTOR: Function Attrs: nofree nosync nounwind memory(read) 465; ATTRIBUTOR-LABEL: define void @test_scc_argmem_read_1 466; ATTRIBUTOR-SAME: (ptr nofree nonnull readonly captures(none) [[P:%.*]]) #[[ATTR15]] { 467; ATTRIBUTOR-NEXT: [[PVAL:%.*]] = load ptr, ptr [[P]], align 8 468; ATTRIBUTOR-NEXT: call void @test_scc_argmem_read_2(ptr nofree readonly captures(none) [[PVAL]]) #[[ATTR15]] 469; ATTRIBUTOR-NEXT: ret void 470; 471 %pval = load ptr, ptr %p 472 call void @test_scc_argmem_read_2(ptr %pval) 473 ret void 474} 475 476define void @test_scc_argmem_read_2(ptr %p) { 477; FNATTRS: Function Attrs: nofree nosync nounwind memory(read, inaccessiblemem: none) 478; FNATTRS-LABEL: define void @test_scc_argmem_read_2 479; FNATTRS-SAME: (ptr readonly captures(none) [[P:%.*]]) #[[ATTR16]] { 480; FNATTRS-NEXT: call void @test_scc_argmem_read_1(ptr [[P]]) 481; FNATTRS-NEXT: ret void 482; 483; ATTRIBUTOR: Function Attrs: nofree nosync nounwind memory(read) 484; ATTRIBUTOR-LABEL: define void @test_scc_argmem_read_2 485; ATTRIBUTOR-SAME: (ptr nofree readonly captures(none) [[P:%.*]]) #[[ATTR15]] { 486; ATTRIBUTOR-NEXT: call void @test_scc_argmem_read_1(ptr nofree readonly captures(none) [[P]]) #[[ATTR15]] 487; ATTRIBUTOR-NEXT: ret void 488; 489 call void @test_scc_argmem_read_1(ptr %p) 490 ret void 491} 492 493define i64 @select_same_obj(i1 %c, ptr %p, i64 %x) { 494; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) 495; FNATTRS-LABEL: define i64 @select_same_obj 496; FNATTRS-SAME: (i1 [[C:%.*]], ptr readonly captures(none) [[P:%.*]], i64 [[X:%.*]]) #[[ATTR1]] { 497; FNATTRS-NEXT: entry: 498; FNATTRS-NEXT: [[P2:%.*]] = getelementptr i8, ptr [[P]], i64 [[X]] 499; FNATTRS-NEXT: [[P3:%.*]] = select i1 [[C]], ptr [[P]], ptr [[P2]] 500; FNATTRS-NEXT: [[R:%.*]] = load i64, ptr [[P3]], align 4 501; FNATTRS-NEXT: ret i64 [[R]] 502; 503; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 504; ATTRIBUTOR-LABEL: define i64 @select_same_obj 505; ATTRIBUTOR-SAME: (i1 [[C:%.*]], ptr nofree readonly captures(none) [[P:%.*]], i64 [[X:%.*]]) #[[ATTR0]] { 506; ATTRIBUTOR-NEXT: entry: 507; ATTRIBUTOR-NEXT: [[P2:%.*]] = getelementptr i8, ptr [[P]], i64 [[X]] 508; ATTRIBUTOR-NEXT: [[P3:%.*]] = select i1 [[C]], ptr [[P]], ptr [[P2]] 509; ATTRIBUTOR-NEXT: [[R:%.*]] = load i64, ptr [[P3]], align 4 510; ATTRIBUTOR-NEXT: ret i64 [[R]] 511; 512entry: 513 %p2 = getelementptr i8, ptr %p, i64 %x 514 %p3 = select i1 %c, ptr %p, ptr %p2 515 %r = load i64, ptr %p3 516 ret i64 %r 517} 518 519; FIXME: This could be `memory(argmem: read)`. 520define i64 @select_different_obj(i1 %c, ptr %p, ptr %p2) { 521; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read, inaccessiblemem: none) 522; FNATTRS-LABEL: define i64 @select_different_obj 523; FNATTRS-SAME: (i1 [[C:%.*]], ptr readonly captures(none) [[P:%.*]], ptr readonly captures(none) [[P2:%.*]]) #[[ATTR3]] { 524; FNATTRS-NEXT: entry: 525; FNATTRS-NEXT: [[P3:%.*]] = select i1 [[C]], ptr [[P]], ptr [[P2]] 526; FNATTRS-NEXT: [[R:%.*]] = load i64, ptr [[P3]], align 4 527; FNATTRS-NEXT: ret i64 [[R]] 528; 529; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 530; ATTRIBUTOR-LABEL: define i64 @select_different_obj 531; ATTRIBUTOR-SAME: (i1 [[C:%.*]], ptr nofree readonly captures(none) [[P:%.*]], ptr nofree readonly captures(none) [[P2:%.*]]) #[[ATTR0]] { 532; ATTRIBUTOR-NEXT: entry: 533; ATTRIBUTOR-NEXT: [[P3:%.*]] = select i1 [[C]], ptr [[P]], ptr [[P2]] 534; ATTRIBUTOR-NEXT: [[R:%.*]] = load i64, ptr [[P3]], align 4 535; ATTRIBUTOR-NEXT: ret i64 [[R]] 536; 537entry: 538 %p3 = select i1 %c, ptr %p, ptr %p2 539 %r = load i64, ptr %p3 540 ret i64 %r 541} 542 543define i64 @phi_same_obj(i1 %c, ptr %p, i64 %x) { 544; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) 545; FNATTRS-LABEL: define i64 @phi_same_obj 546; FNATTRS-SAME: (i1 [[C:%.*]], ptr readonly captures(none) [[P:%.*]], i64 [[X:%.*]]) #[[ATTR1]] { 547; FNATTRS-NEXT: entry: 548; FNATTRS-NEXT: [[P2:%.*]] = getelementptr i8, ptr [[P]], i64 [[X]] 549; FNATTRS-NEXT: br i1 [[C]], label [[IF:%.*]], label [[JOIN:%.*]] 550; FNATTRS: if: 551; FNATTRS-NEXT: br label [[JOIN]] 552; FNATTRS: join: 553; FNATTRS-NEXT: [[P3:%.*]] = phi ptr [ [[P]], [[IF]] ], [ [[P2]], [[ENTRY:%.*]] ] 554; FNATTRS-NEXT: [[R:%.*]] = load i64, ptr [[P3]], align 4 555; FNATTRS-NEXT: ret i64 [[R]] 556; 557; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) 558; ATTRIBUTOR-LABEL: define i64 @phi_same_obj 559; ATTRIBUTOR-SAME: (i1 [[C:%.*]], ptr nofree readonly captures(none) [[P:%.*]], i64 [[X:%.*]]) #[[ATTR1]] { 560; ATTRIBUTOR-NEXT: entry: 561; ATTRIBUTOR-NEXT: [[P2:%.*]] = getelementptr i8, ptr [[P]], i64 [[X]] 562; ATTRIBUTOR-NEXT: br i1 [[C]], label [[IF:%.*]], label [[JOIN:%.*]] 563; ATTRIBUTOR: if: 564; ATTRIBUTOR-NEXT: br label [[JOIN]] 565; ATTRIBUTOR: join: 566; ATTRIBUTOR-NEXT: [[P3:%.*]] = phi ptr [ [[P]], [[IF]] ], [ [[P2]], [[ENTRY:%.*]] ] 567; ATTRIBUTOR-NEXT: [[R:%.*]] = load i64, ptr [[P3]], align 4 568; ATTRIBUTOR-NEXT: ret i64 [[R]] 569; 570entry: 571 %p2 = getelementptr i8, ptr %p, i64 %x 572 br i1 %c, label %if, label %join 573if: 574 br label %join 575join: 576 %p3 = phi ptr [ %p, %if ], [ %p2, %entry ] 577 %r = load i64, ptr %p3 578 ret i64 %r 579} 580 581; FIXME: This could be `memory(argmem: read)`. 582define i64 @phi_different_obj(i1 %c, ptr %p, ptr %p2) { 583; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read, inaccessiblemem: none) 584; FNATTRS-LABEL: define i64 @phi_different_obj 585; FNATTRS-SAME: (i1 [[C:%.*]], ptr readonly captures(none) [[P:%.*]], ptr readonly captures(none) [[P2:%.*]]) #[[ATTR3]] { 586; FNATTRS-NEXT: entry: 587; FNATTRS-NEXT: br i1 [[C]], label [[IF:%.*]], label [[JOIN:%.*]] 588; FNATTRS: if: 589; FNATTRS-NEXT: br label [[JOIN]] 590; FNATTRS: join: 591; FNATTRS-NEXT: [[P3:%.*]] = phi ptr [ [[P]], [[IF]] ], [ [[P2]], [[ENTRY:%.*]] ] 592; FNATTRS-NEXT: [[R:%.*]] = load i64, ptr [[P3]], align 4 593; FNATTRS-NEXT: ret i64 [[R]] 594; 595; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) 596; ATTRIBUTOR-LABEL: define i64 @phi_different_obj 597; ATTRIBUTOR-SAME: (i1 [[C:%.*]], ptr nofree readonly captures(none) [[P:%.*]], ptr nofree readonly captures(none) [[P2:%.*]]) #[[ATTR1]] { 598; ATTRIBUTOR-NEXT: entry: 599; ATTRIBUTOR-NEXT: br i1 [[C]], label [[IF:%.*]], label [[JOIN:%.*]] 600; ATTRIBUTOR: if: 601; ATTRIBUTOR-NEXT: br label [[JOIN]] 602; ATTRIBUTOR: join: 603; ATTRIBUTOR-NEXT: [[P3:%.*]] = phi ptr [ [[P]], [[IF]] ], [ [[P2]], [[ENTRY:%.*]] ] 604; ATTRIBUTOR-NEXT: [[R:%.*]] = load i64, ptr [[P3]], align 4 605; ATTRIBUTOR-NEXT: ret i64 [[R]] 606; 607entry: 608 br i1 %c, label %if, label %join 609if: 610 br label %join 611join: 612 %p3 = phi ptr [ %p, %if ], [ %p2, %entry ] 613 %r = load i64, ptr %p3 614 ret i64 %r 615} 616 617; An `alloca` that won't be handled by `getModRefInfoMask` 618define i64 @alloca_with_phis(i64 %arg, i1 %cmp) { 619; COMMON: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 620; COMMON-LABEL: define i64 @alloca_with_phis 621; COMMON-SAME: (i64 [[ARG:%.*]], i1 [[CMP:%.*]]) #[[ATTR0]] { 622; COMMON-NEXT: bb: 623; COMMON-NEXT: [[I:%.*]] = alloca i64, align 8 624; COMMON-NEXT: store i64 [[ARG]], ptr [[I]], align 4 625; COMMON-NEXT: br i1 [[CMP]], label [[BB1:%.*]], label [[BB4:%.*]] 626; COMMON: bb1: 627; COMMON-NEXT: br i1 [[CMP]], label [[BB8:%.*]], label [[BB2:%.*]] 628; COMMON: bb2: 629; COMMON-NEXT: br i1 [[CMP]], label [[BB8]], label [[BB3:%.*]] 630; COMMON: bb3: 631; COMMON-NEXT: br i1 [[CMP]], label [[BB8]], label [[BB6:%.*]] 632; COMMON: bb4: 633; COMMON-NEXT: br i1 [[CMP]], label [[BB8]], label [[BB5:%.*]] 634; COMMON: bb5: 635; COMMON-NEXT: br i1 [[CMP]], label [[BB8]], label [[BB6]] 636; COMMON: bb6: 637; COMMON-NEXT: [[I7:%.*]] = phi ptr [ [[I]], [[BB3]] ], [ [[I]], [[BB5]] ] 638; COMMON-NEXT: br label [[BB8]] 639; COMMON: bb8: 640; COMMON-NEXT: [[I9:%.*]] = phi ptr [ [[I]], [[BB1]] ], [ [[I]], [[BB2]] ], [ [[I]], [[BB3]] ], [ [[I]], [[BB4]] ], [ [[I]], [[BB5]] ], [ [[I7]], [[BB6]] ] 641; COMMON-NEXT: [[RET:%.*]] = load i64, ptr [[I9]], align 4 642; COMMON-NEXT: ret i64 [[RET]] 643; 644bb: 645 %i = alloca i64 646 store i64 %arg, ptr %i 647 br i1 %cmp, label %bb1, label %bb4 648 649bb1: ; preds = %bb 650 br i1 %cmp, label %bb8, label %bb2 651 652bb2: ; preds = %bb1 653 br i1 %cmp, label %bb8, label %bb3 654 655bb3: ; preds = %bb2 656 br i1 %cmp, label %bb8, label %bb6 657 658bb4: ; preds = %bb 659 br i1 %cmp, label %bb8, label %bb5 660 661bb5: ; preds = %bb4 662 br i1 %cmp, label %bb8, label %bb6 663 664bb6: ; preds = %bb5, %bb3 665 %i7 = phi ptr [ %i, %bb3 ], [ %i, %bb5 ] 666 br label %bb8 667 668bb8: ; preds = %bb6, %bb5, %bb4, %bb3, %bb2, %bb1 669 %i9 = phi ptr [ %i, %bb1 ], [ %i, %bb2 ], [ %i, %bb3 ], [ %i, %bb4 ], [ %i, %bb5 ], [ %i7, %bb6 ] 670 %ret = load i64, ptr %i9 671 ret i64 %ret 672} 673