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; 5; When a function is marked `alwaysinline` and is able to be inlined, 6; we can IPO its boundaries 7 8; the function is not exactly defined, and marked alwaysinline and can be inlined, 9; so the function can be analyzed 10define linkonce void @inner1() alwaysinline { 11; CHECK: Function Attrs: alwaysinline mustprogress nofree norecurse nosync nounwind willreturn memory(none) 12; CHECK-LABEL: define {{[^@]+}}@inner1 13; CHECK-SAME: () #[[ATTR0:[0-9]+]] { 14; CHECK-NEXT: entry: 15; CHECK-NEXT: ret void 16; 17entry: 18 ret void 19} 20 21define void @outer1() { 22; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 23; TUNIT-LABEL: define {{[^@]+}}@outer1 24; TUNIT-SAME: () #[[ATTR1:[0-9]+]] { 25; TUNIT-NEXT: entry: 26; TUNIT-NEXT: ret void 27; 28; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none) 29; CGSCC-LABEL: define {{[^@]+}}@outer1 30; CGSCC-SAME: () #[[ATTR1:[0-9]+]] { 31; CGSCC-NEXT: entry: 32; CGSCC-NEXT: ret void 33; 34entry: 35 call void @inner1() 36 ret void 37} 38 39; The function is not alwaysinline and is not exactly defined 40; so it will not be analyzed 41define linkonce i32 @inner2() { 42; CHECK-LABEL: define {{[^@]+}}@inner2() { 43; CHECK-NEXT: entry: 44; CHECK-NEXT: ret i32 1 45; 46entry: 47 ret i32 1 48} 49 50; CHECK-NOT: Function Attrs 51define i32 @outer2() { 52; CHECK-LABEL: define {{[^@]+}}@outer2() { 53; CHECK-NEXT: entry: 54; CHECK-NEXT: [[R:%.*]] = call i32 @inner2() #[[ATTR2:[0-9]+]] 55; CHECK-NEXT: ret i32 [[R]] 56; 57entry: 58 %r = call i32 @inner2() alwaysinline 59 ret i32 %r 60} 61 62; This function cannot be inlined although it is marked alwaysinline 63; it is `unexactly defined` and alwaysinline but cannot be inlined. 64; so it will not be analyzed 65define linkonce i32 @inner3(ptr %addr) alwaysinline { 66; CHECK: Function Attrs: alwaysinline 67; CHECK-LABEL: define {{[^@]+}}@inner3 68; CHECK-SAME: (ptr [[ADDR:%.*]]) #[[ATTR2]] { 69; CHECK-NEXT: entry: 70; CHECK-NEXT: indirectbr ptr [[ADDR]], [label [[ONE:%.*]], label %two] 71; CHECK: one: 72; CHECK-NEXT: ret i32 42 73; CHECK: two: 74; CHECK-NEXT: ret i32 44 75; 76entry: 77 indirectbr ptr %addr, [ label %one, label %two ] 78 79one: 80 ret i32 42 81 82two: 83 ret i32 44 84} 85 86define i32 @outer3(i32 %x) { 87; CHECK-LABEL: define {{[^@]+}}@outer3 88; CHECK-SAME: (i32 [[X:%.*]]) { 89; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[X]], 42 90; CHECK-NEXT: [[ADDR:%.*]] = select i1 [[CMP]], ptr blockaddress(@inner3, [[ONE:%.*]]), ptr blockaddress(@inner3, [[TWO:%.*]]) 91; CHECK-NEXT: [[CALL:%.*]] = call i32 @inner3(ptr [[ADDR]]) 92; CHECK-NEXT: ret i32 [[CALL]] 93; 94 %cmp = icmp slt i32 %x, 42 95 %addr = select i1 %cmp, ptr blockaddress(@inner3, %one), ptr blockaddress(@inner3, %two) 96 %call = call i32 @inner3(ptr %addr) 97 ret i32 %call 98} 99;. 100; TUNIT: attributes #[[ATTR0]] = { alwaysinline mustprogress nofree norecurse nosync nounwind willreturn memory(none) } 101; TUNIT: attributes #[[ATTR1]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) } 102; TUNIT: attributes #[[ATTR2]] = { alwaysinline } 103;. 104; CGSCC: attributes #[[ATTR0]] = { alwaysinline mustprogress nofree norecurse nosync nounwind willreturn memory(none) } 105; CGSCC: attributes #[[ATTR1]] = { mustprogress nofree nosync nounwind willreturn memory(none) } 106; CGSCC: attributes #[[ATTR2]] = { alwaysinline } 107;. 108