188 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals2; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT3; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC4; PR365435 6; Don't promote arguments of musttail callee7 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 {{[^@]+}}@test13; CHECK-SAME: (ptr nofree readonly captures(none) [[P:%.*]]) #[[ATTR0:[0-9]+]] {14; CHECK-NEXT: [[A_GEP:%.*]] = getelementptr [[T:%.*]], ptr [[P]], i64 0, i32 315; CHECK-NEXT: [[B_GEP:%.*]] = getelementptr [[T]], ptr [[P]], i64 0, i32 216; CHECK-NEXT: [[A:%.*]] = load i32, ptr [[A_GEP]], align 417; CHECK-NEXT: [[B:%.*]] = load i32, ptr [[B_GEP]], align 418; CHECK-NEXT: [[V:%.*]] = add i32 [[A]], [[B]]19; CHECK-NEXT: ret i32 [[V]]20;21 %a.gep = getelementptr %T, ptr %p, i64 0, i32 322 %b.gep = getelementptr %T, ptr %p, i64 0, i32 223 %a = load i32, ptr %a.gep24 %b = load i32, ptr %b.gep25 %v = add i32 %a, %b26 ret i32 %v27}28 29define i32 @caller(ptr %p) {30; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)31; TUNIT-LABEL: define {{[^@]+}}@caller32; 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 {{[^@]+}}@caller38; 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 %v44}45 46; Don't promote arguments of musttail caller47 48define i32 @foo(ptr %p, i32 %v) {49; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)50; TUNIT-LABEL: define {{[^@]+}}@foo51; TUNIT-SAME: (ptr nofree readnone captures(none) [[P:%.*]], i32 [[V:%.*]]) #[[ATTR1:[0-9]+]] {52; TUNIT-NEXT: ret i32 053;54; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)55; CGSCC-LABEL: define {{[^@]+}}@foo56; CGSCC-SAME: (ptr nofree readnone captures(none) [[P:%.*]], i32 [[V:%.*]]) #[[ATTR2:[0-9]+]] {57; CGSCC-NEXT: ret i32 058;59 ret i32 060}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 {{[^@]+}}@test265; CGSCC-SAME: (ptr nofree readonly captures(none) [[P:%.*]], i32 [[P2:%.*]]) #[[ATTR1]] {66; CGSCC-NEXT: [[A_GEP:%.*]] = getelementptr [[T:%.*]], ptr [[P]], i64 0, i32 367; CGSCC-NEXT: [[B_GEP:%.*]] = getelementptr [[T]], ptr [[P]], i64 0, i32 268; CGSCC-NEXT: [[A:%.*]] = load i32, ptr [[A_GEP]], align 469; CGSCC-NEXT: [[B:%.*]] = load i32, ptr [[B_GEP]], align 470; 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 375 %b.gep = getelementptr %T, ptr %p, i64 0, i32 276 %a = load i32, ptr %a.gep77 %b = load i32, ptr %b.gep78 %v = add i32 %a, %b79 %ca = musttail call i32 @foo(ptr undef, i32 %v)80 ret i32 %ca81}82 83define i32 @caller2(ptr %g) {84; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)85; TUNIT-LABEL: define {{[^@]+}}@caller286; TUNIT-SAME: (ptr nofree readnone captures(none) [[G:%.*]]) #[[ATTR1]] {87; TUNIT-NEXT: ret i32 088;89; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(argmem: read)90; CGSCC-LABEL: define {{[^@]+}}@caller291; 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 %v97}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 value101; 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 {{[^@]+}}@bar106; 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 4108; TUNIT-NEXT: ret i32 0109;110; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)111; CGSCC-LABEL: define {{[^@]+}}@bar112; 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 4114; CGSCC-NEXT: ret i32 0115;116 %i32ptr = getelementptr %T, ptr %p, i64 0, i32 0117 store i32 %v, ptr %i32ptr118 ret i32 0119}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 {{[^@]+}}@test2b124; 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 3126; TUNIT-NEXT: [[B_GEP:%.*]] = getelementptr [[T]], ptr [[P]], i64 0, i32 2127; TUNIT-NEXT: [[A:%.*]] = load i32, ptr [[A_GEP]], align 4128; TUNIT-NEXT: [[B:%.*]] = load i32, ptr [[B_GEP]], align 4129; 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 {{[^@]+}}@test2b135; 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 3137; CGSCC-NEXT: [[B_GEP:%.*]] = getelementptr [[T]], ptr [[P]], i64 0, i32 2138; CGSCC-NEXT: [[A:%.*]] = load i32, ptr [[A_GEP]], align 4139; CGSCC-NEXT: [[B:%.*]] = load i32, ptr [[B_GEP]], align 4140; 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 3145 %b.gep = getelementptr %T, ptr %p, i64 0, i32 2146 %a = load i32, ptr %a.gep147 %b = load i32, ptr %b.gep148 %v = add i32 %a, %b149 %ca = musttail call i32 @bar(ptr undef, i32 %v)150 ret i32 %ca151}152 153define i32 @caller2b(ptr %g) {154; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite)155; TUNIT-LABEL: define {{[^@]+}}@caller2b156; 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 0159;160; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(argmem: readwrite)161; CGSCC-LABEL: define {{[^@]+}}@caller2b162; 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 %v168}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