1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals 2; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT 3; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC 4; PR36543 5 6; Don't promote arguments of musttail callee 7 8%T = type { i32, i32, i32, i32 } 9 10define internal i32 @test(ptr %p) { 11; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) 12; CHECK-LABEL: define {{[^@]+}}@test 13; CHECK-SAME: (ptr nofree readonly captures(none) [[P:%.*]]) #[[ATTR0:[0-9]+]] { 14; CHECK-NEXT: [[A_GEP:%.*]] = getelementptr [[T:%.*]], ptr [[P]], i64 0, i32 3 15; CHECK-NEXT: [[B_GEP:%.*]] = getelementptr [[T]], ptr [[P]], i64 0, i32 2 16; CHECK-NEXT: [[A:%.*]] = load i32, ptr [[A_GEP]], align 4 17; CHECK-NEXT: [[B:%.*]] = load i32, ptr [[B_GEP]], align 4 18; CHECK-NEXT: [[V:%.*]] = add i32 [[A]], [[B]] 19; CHECK-NEXT: ret i32 [[V]] 20; 21 %a.gep = getelementptr %T, ptr %p, i64 0, i32 3 22 %b.gep = getelementptr %T, ptr %p, i64 0, i32 2 23 %a = load i32, ptr %a.gep 24 %b = load i32, ptr %b.gep 25 %v = add i32 %a, %b 26 ret i32 %v 27} 28 29define i32 @caller(ptr %p) { 30; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) 31; TUNIT-LABEL: define {{[^@]+}}@caller 32; TUNIT-SAME: (ptr nofree readonly captures(none) [[P:%.*]]) #[[ATTR0]] { 33; TUNIT-NEXT: [[V:%.*]] = musttail call i32 @test(ptr nofree readonly captures(none) [[P]]) #[[ATTR4:[0-9]+]] 34; TUNIT-NEXT: ret i32 [[V]] 35; 36; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(argmem: read) 37; CGSCC-LABEL: define {{[^@]+}}@caller 38; CGSCC-SAME: (ptr nofree readonly captures(none) [[P:%.*]]) #[[ATTR1:[0-9]+]] { 39; CGSCC-NEXT: [[V:%.*]] = musttail call i32 @test(ptr nofree readonly captures(none) [[P]]) #[[ATTR5:[0-9]+]] 40; CGSCC-NEXT: ret i32 [[V]] 41; 42 %v = musttail call i32 @test(ptr %p) 43 ret i32 %v 44} 45 46; Don't promote arguments of musttail caller 47 48define i32 @foo(ptr %p, i32 %v) { 49; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 50; TUNIT-LABEL: define {{[^@]+}}@foo 51; TUNIT-SAME: (ptr nofree readnone captures(none) [[P:%.*]], i32 [[V:%.*]]) #[[ATTR1:[0-9]+]] { 52; TUNIT-NEXT: ret i32 0 53; 54; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 55; CGSCC-LABEL: define {{[^@]+}}@foo 56; CGSCC-SAME: (ptr nofree readnone captures(none) [[P:%.*]], i32 [[V:%.*]]) #[[ATTR2:[0-9]+]] { 57; CGSCC-NEXT: ret i32 0 58; 59 ret i32 0 60} 61 62define internal i32 @test2(ptr %p, i32 %p2) { 63; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(argmem: read) 64; CGSCC-LABEL: define {{[^@]+}}@test2 65; CGSCC-SAME: (ptr nofree readonly captures(none) [[P:%.*]], i32 [[P2:%.*]]) #[[ATTR1]] { 66; CGSCC-NEXT: [[A_GEP:%.*]] = getelementptr [[T:%.*]], ptr [[P]], i64 0, i32 3 67; CGSCC-NEXT: [[B_GEP:%.*]] = getelementptr [[T]], ptr [[P]], i64 0, i32 2 68; CGSCC-NEXT: [[A:%.*]] = load i32, ptr [[A_GEP]], align 4 69; CGSCC-NEXT: [[B:%.*]] = load i32, ptr [[B_GEP]], align 4 70; CGSCC-NEXT: [[V:%.*]] = add i32 [[A]], [[B]] 71; CGSCC-NEXT: [[CA:%.*]] = musttail call noundef i32 @foo(ptr nofree undef, i32 [[V]]) #[[ATTR6:[0-9]+]] 72; CGSCC-NEXT: ret i32 [[CA]] 73; 74 %a.gep = getelementptr %T, ptr %p, i64 0, i32 3 75 %b.gep = getelementptr %T, ptr %p, i64 0, i32 2 76 %a = load i32, ptr %a.gep 77 %b = load i32, ptr %b.gep 78 %v = add i32 %a, %b 79 %ca = musttail call i32 @foo(ptr undef, i32 %v) 80 ret i32 %ca 81} 82 83define i32 @caller2(ptr %g) { 84; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 85; TUNIT-LABEL: define {{[^@]+}}@caller2 86; TUNIT-SAME: (ptr nofree readnone captures(none) [[G:%.*]]) #[[ATTR1]] { 87; TUNIT-NEXT: ret i32 0 88; 89; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(argmem: read) 90; CGSCC-LABEL: define {{[^@]+}}@caller2 91; CGSCC-SAME: (ptr nofree readonly align 4 captures(none) [[G:%.*]]) #[[ATTR1]] { 92; CGSCC-NEXT: [[V:%.*]] = call noundef i32 @test2(ptr nofree readonly captures(none) [[G]], i32 noundef 0) #[[ATTR5]] 93; CGSCC-NEXT: ret i32 [[V]] 94; 95 %v = call i32 @test2(ptr %g, i32 0) 96 ret i32 %v 97} 98 99; In the version above we can remove the call to foo completely. 100; In the version below we keep the call and verify the return value 101; is kept as well. 102 103define i32 @bar(ptr %p, i32 %v) { 104; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) 105; TUNIT-LABEL: define {{[^@]+}}@bar 106; TUNIT-SAME: (ptr nofree nonnull writeonly captures(none) dereferenceable(4) [[P:%.*]], i32 [[V:%.*]]) #[[ATTR2:[0-9]+]] { 107; TUNIT-NEXT: store i32 [[V]], ptr [[P]], align 4 108; TUNIT-NEXT: ret i32 0 109; 110; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) 111; CGSCC-LABEL: define {{[^@]+}}@bar 112; CGSCC-SAME: (ptr nofree nonnull writeonly captures(none) dereferenceable(4) [[P:%.*]], i32 [[V:%.*]]) #[[ATTR3:[0-9]+]] { 113; CGSCC-NEXT: store i32 [[V]], ptr [[P]], align 4 114; CGSCC-NEXT: ret i32 0 115; 116 %i32ptr = getelementptr %T, ptr %p, i64 0, i32 0 117 store i32 %v, ptr %i32ptr 118 ret i32 0 119} 120 121define internal i32 @test2b(ptr %p, i32 %p2) { 122; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) 123; TUNIT-LABEL: define {{[^@]+}}@test2b 124; TUNIT-SAME: (ptr nofree readonly captures(none) [[P:%.*]], i32 [[P2:%.*]]) #[[ATTR3:[0-9]+]] { 125; TUNIT-NEXT: [[A_GEP:%.*]] = getelementptr [[T:%.*]], ptr [[P]], i64 0, i32 3 126; TUNIT-NEXT: [[B_GEP:%.*]] = getelementptr [[T]], ptr [[P]], i64 0, i32 2 127; TUNIT-NEXT: [[A:%.*]] = load i32, ptr [[A_GEP]], align 4 128; TUNIT-NEXT: [[B:%.*]] = load i32, ptr [[B_GEP]], align 4 129; TUNIT-NEXT: [[V:%.*]] = add i32 [[A]], [[B]] 130; TUNIT-NEXT: [[CA:%.*]] = musttail call i32 @bar(ptr undef, i32 [[V]]) #[[ATTR5:[0-9]+]] 131; TUNIT-NEXT: ret i32 [[CA]] 132; 133; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(argmem: readwrite) 134; CGSCC-LABEL: define {{[^@]+}}@test2b 135; CGSCC-SAME: (ptr nofree readonly captures(none) [[P:%.*]], i32 [[P2:%.*]]) #[[ATTR4:[0-9]+]] { 136; CGSCC-NEXT: [[A_GEP:%.*]] = getelementptr [[T:%.*]], ptr [[P]], i64 0, i32 3 137; CGSCC-NEXT: [[B_GEP:%.*]] = getelementptr [[T]], ptr [[P]], i64 0, i32 2 138; CGSCC-NEXT: [[A:%.*]] = load i32, ptr [[A_GEP]], align 4 139; CGSCC-NEXT: [[B:%.*]] = load i32, ptr [[B_GEP]], align 4 140; CGSCC-NEXT: [[V:%.*]] = add i32 [[A]], [[B]] 141; CGSCC-NEXT: [[CA:%.*]] = musttail call noundef i32 @bar(ptr nofree nonnull undef, i32 [[V]]) #[[ATTR7:[0-9]+]] 142; CGSCC-NEXT: ret i32 [[CA]] 143; 144 %a.gep = getelementptr %T, ptr %p, i64 0, i32 3 145 %b.gep = getelementptr %T, ptr %p, i64 0, i32 2 146 %a = load i32, ptr %a.gep 147 %b = load i32, ptr %b.gep 148 %v = add i32 %a, %b 149 %ca = musttail call i32 @bar(ptr undef, i32 %v) 150 ret i32 %ca 151} 152 153define i32 @caller2b(ptr %g) { 154; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) 155; TUNIT-LABEL: define {{[^@]+}}@caller2b 156; TUNIT-SAME: (ptr nofree readonly captures(none) [[G:%.*]]) #[[ATTR3]] { 157; TUNIT-NEXT: [[V:%.*]] = call i32 @test2b(ptr nofree readonly captures(none) [[G]], i32 undef) #[[ATTR6:[0-9]+]] 158; TUNIT-NEXT: ret i32 0 159; 160; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(argmem: readwrite) 161; CGSCC-LABEL: define {{[^@]+}}@caller2b 162; CGSCC-SAME: (ptr nofree readonly align 4 captures(none) [[G:%.*]]) #[[ATTR4]] { 163; CGSCC-NEXT: [[V:%.*]] = call noundef i32 @test2b(ptr nofree readonly captures(none) [[G]], i32 noundef 0) #[[ATTR8:[0-9]+]] 164; CGSCC-NEXT: ret i32 [[V]] 165; 166 %v = call i32 @test2b(ptr %g, i32 0) 167 ret i32 %v 168} 169;. 170; TUNIT: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) } 171; TUNIT: attributes #[[ATTR1]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) } 172; TUNIT: attributes #[[ATTR2]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) } 173; TUNIT: attributes #[[ATTR3]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) } 174; TUNIT: attributes #[[ATTR4]] = { nofree nosync nounwind willreturn memory(read) } 175; TUNIT: attributes #[[ATTR5]] = { nofree nosync nounwind willreturn memory(write) } 176; TUNIT: attributes #[[ATTR6]] = { nofree nosync nounwind willreturn } 177;. 178; CGSCC: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) } 179; CGSCC: attributes #[[ATTR1]] = { mustprogress nofree nosync nounwind willreturn memory(argmem: read) } 180; CGSCC: attributes #[[ATTR2]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) } 181; CGSCC: attributes #[[ATTR3]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) } 182; CGSCC: attributes #[[ATTR4]] = { mustprogress nofree nosync nounwind willreturn memory(argmem: readwrite) } 183; CGSCC: attributes #[[ATTR5]] = { nofree willreturn memory(read) } 184; CGSCC: attributes #[[ATTR6]] = { nofree nosync willreturn } 185; CGSCC: attributes #[[ATTR7]] = { nofree nounwind willreturn memory(write) } 186; CGSCC: attributes #[[ATTR8]] = { nofree nounwind willreturn } 187;. 188