1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt < %s -inline-threshold=0 -always-inline -S | FileCheck %s 3; RUN: opt < %s -passes=always-inline -S | FileCheck %s 4 5declare i8* @foo(i8*) argmemonly nounwind 6 7define i8* @callee(i8 *%p) alwaysinline { 8; CHECK-LABEL: @callee( 9; CHECK-NEXT: [[R:%.*]] = call i8* @foo(i8* noalias [[P:%.*]]) 10; CHECK-NEXT: ret i8* [[R]] 11; 12 %r = call i8* @foo(i8* noalias %p) 13 ret i8* %r 14} 15 16define i8* @caller(i8* %ptr, i64 %x) { 17; CHECK-LABEL: @caller( 18; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, i8* [[PTR:%.*]], i64 [[X:%.*]] 19; CHECK-NEXT: [[R_I:%.*]] = call nonnull i8* @foo(i8* noalias [[GEP]]) 20; CHECK-NEXT: ret i8* [[R_I]] 21; 22 %gep = getelementptr inbounds i8, i8* %ptr, i64 %x 23 %p = call nonnull i8* @callee(i8* %gep) 24 ret i8* %p 25} 26 27declare void @llvm.experimental.guard(i1,...) 28; Cannot add nonnull attribute to foo 29; because the guard is a throwing call 30define internal i8* @callee_with_throwable(i8* %p) alwaysinline { 31 %r = call i8* @foo(i8* %p) 32 %cond = icmp ne i8* %r, null 33 call void (i1, ...) @llvm.experimental.guard(i1 %cond) [ "deopt"() ] 34 ret i8* %r 35} 36 37declare i8* @bar(i8*) readonly nounwind 38; Here also we cannot add nonnull attribute to the call bar. 39define internal i8* @callee_with_explicit_control_flow(i8* %p) alwaysinline { 40 %r = call i8* @bar(i8* %p) 41 %cond = icmp ne i8* %r, null 42 br i1 %cond, label %ret, label %orig 43 44ret: 45 ret i8* %r 46 47orig: 48 ret i8* %p 49} 50 51define i8* @caller2(i8* %ptr, i64 %x, i1 %cond) { 52; CHECK-LABEL: @caller2( 53; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, i8* [[PTR:%.*]], i64 [[X:%.*]] 54; CHECK-NEXT: [[R_I:%.*]] = call i8* @foo(i8* [[GEP]]) 55; CHECK-NEXT: [[COND_I:%.*]] = icmp ne i8* [[R_I]], null 56; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[COND_I]]) [ "deopt"() ] 57; CHECK-NEXT: [[R_I1:%.*]] = call i8* @bar(i8* [[GEP]]) 58; CHECK-NEXT: [[COND_I2:%.*]] = icmp ne i8* [[R_I1]], null 59; CHECK-NEXT: br i1 [[COND_I2]], label [[RET_I:%.*]], label [[ORIG_I:%.*]] 60; CHECK: ret.i: 61; CHECK-NEXT: br label [[CALLEE_WITH_EXPLICIT_CONTROL_FLOW_EXIT:%.*]] 62; CHECK: orig.i: 63; CHECK-NEXT: br label [[CALLEE_WITH_EXPLICIT_CONTROL_FLOW_EXIT]] 64; CHECK: callee_with_explicit_control_flow.exit: 65; CHECK-NEXT: [[Q3:%.*]] = phi i8* [ [[R_I1]], [[RET_I]] ], [ [[GEP]], [[ORIG_I]] ] 66; CHECK-NEXT: br i1 [[COND:%.*]], label [[PRET:%.*]], label [[QRET:%.*]] 67; CHECK: pret: 68; CHECK-NEXT: ret i8* [[R_I]] 69; CHECK: qret: 70; CHECK-NEXT: ret i8* [[Q3]] 71; 72 %gep = getelementptr inbounds i8, i8* %ptr, i64 %x 73 %p = call nonnull i8* @callee_with_throwable(i8* %gep) 74 %q = call nonnull i8* @callee_with_explicit_control_flow(i8* %gep) 75 br i1 %cond, label %pret, label %qret 76 77pret: 78 ret i8* %p 79 80qret: 81 ret i8* %q 82} 83 84define internal i8* @callee3(i8 *%p) alwaysinline { 85 %r = call noalias i8* @foo(i8* %p) 86 ret i8* %r 87} 88 89; add the deref attribute to the existing attributes on foo. 90define i8* @caller3(i8* %ptr, i64 %x) { 91; CHECK-LABEL: @caller3( 92; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, i8* [[PTR:%.*]], i64 [[X:%.*]] 93; CHECK-NEXT: [[R_I:%.*]] = call noalias dereferenceable_or_null(12) i8* @foo(i8* [[GEP]]) 94; CHECK-NEXT: ret i8* [[R_I]] 95; 96 %gep = getelementptr inbounds i8, i8* %ptr, i64 %x 97 %p = call dereferenceable_or_null(12) i8* @callee3(i8* %gep) 98 ret i8* %p 99} 100 101declare i8* @inf_loop_call(i8*) nounwind 102; We cannot propagate attributes to foo because we do not know whether inf_loop_call 103; will return execution. 104define internal i8* @callee_with_sideeffect_callsite(i8* %p) alwaysinline { 105 %r = call i8* @foo(i8* %p) 106 %v = call i8* @inf_loop_call(i8* %p) 107 ret i8* %r 108} 109 110; do not add deref attribute to foo 111define i8* @test4(i8* %ptr, i64 %x) { 112; CHECK-LABEL: @test4( 113; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, i8* [[PTR:%.*]], i64 [[X:%.*]] 114; CHECK-NEXT: [[R_I:%.*]] = call i8* @foo(i8* [[GEP]]) 115; CHECK-NEXT: [[V_I:%.*]] = call i8* @inf_loop_call(i8* [[GEP]]) 116; CHECK-NEXT: ret i8* [[R_I]] 117; 118 %gep = getelementptr inbounds i8, i8* %ptr, i64 %x 119 %p = call dereferenceable_or_null(12) i8* @callee_with_sideeffect_callsite(i8* %gep) 120 ret i8* %p 121} 122 123declare i8* @baz(i8*) nounwind readonly 124define internal i8* @callee5(i8* %p) alwaysinline { 125 %r = call i8* @foo(i8* %p) 126 %v = call i8* @baz(i8* %p) 127 ret i8* %r 128} 129 130; add the deref attribute to foo. 131define i8* @test5(i8* %ptr, i64 %x) { 132; CHECK-LABEL: @test5( 133; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, i8* [[PTR:%.*]], i64 [[X:%.*]] 134; CHECK-NEXT: [[R_I:%.*]] = call dereferenceable_or_null(12) i8* @foo(i8* [[GEP]]) 135; CHECK-NEXT: [[V_I:%.*]] = call i8* @baz(i8* [[GEP]]) 136; CHECK-NEXT: ret i8* [[R_I]] 137; 138 %gep = getelementptr inbounds i8, i8* %ptr, i64 %x 139 %s = call dereferenceable_or_null(12) i8* @callee5(i8* %gep) 140 ret i8* %s 141} 142 143; deref attributes have different values on the callee and the call feeding into 144; the return. 145; AttrBuilder chooses the already existing value and does not overwrite it. 146define internal i8* @callee6(i8* %p) alwaysinline { 147 %r = call dereferenceable_or_null(16) i8* @foo(i8* %p) 148 %v = call i8* @baz(i8* %p) 149 ret i8* %r 150} 151 152 153define i8* @test6(i8* %ptr, i64 %x) { 154; CHECK-LABEL: @test6( 155; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, i8* [[PTR:%.*]], i64 [[X:%.*]] 156; CHECK-NEXT: [[R_I:%.*]] = call dereferenceable_or_null(16) i8* @foo(i8* [[GEP]]) 157; CHECK-NEXT: [[V_I:%.*]] = call i8* @baz(i8* [[GEP]]) 158; CHECK-NEXT: ret i8* [[R_I]] 159; 160 %gep = getelementptr inbounds i8, i8* %ptr, i64 %x 161 %s = call dereferenceable_or_null(12) i8* @callee6(i8* %gep) 162 ret i8* %s 163} 164 165; We add the attributes from the callee to both the calls below. 166define internal i8* @callee7(i8 *%ptr, i1 %cond) alwaysinline { 167 br i1 %cond, label %pass, label %fail 168 169pass: 170 %r = call i8* @foo(i8* noalias %ptr) 171 ret i8* %r 172 173fail: 174 %s = call i8* @baz(i8* %ptr) 175 ret i8* %s 176} 177 178define void @test7(i8* %ptr, i64 %x, i1 %cond) { 179; CHECK-LABEL: @test7( 180; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, i8* [[PTR:%.*]], i64 [[X:%.*]] 181; CHECK-NEXT: br i1 [[COND:%.*]], label [[PASS_I:%.*]], label [[FAIL_I:%.*]] 182; CHECK: pass.i: 183; CHECK-NEXT: [[R_I:%.*]] = call nonnull i8* @foo(i8* noalias [[GEP]]) 184; CHECK-NEXT: br label [[CALLEE7_EXIT:%.*]] 185; CHECK: fail.i: 186; CHECK-NEXT: [[S_I:%.*]] = call nonnull i8* @baz(i8* [[GEP]]) 187; CHECK-NEXT: br label [[CALLEE7_EXIT]] 188; CHECK: callee7.exit: 189; CHECK-NEXT: [[T1:%.*]] = phi i8* [ [[R_I]], [[PASS_I]] ], [ [[S_I]], [[FAIL_I]] ] 190; CHECK-NEXT: call void @snort(i8* [[T1]]) 191; CHECK-NEXT: ret void 192; 193 194 %gep = getelementptr inbounds i8, i8* %ptr, i64 %x 195 %t = call nonnull i8* @callee7(i8* %gep, i1 %cond) 196 call void @snort(i8* %t) 197 ret void 198} 199declare void @snort(i8*) 200 201declare i32 @intrinsic(i8*) nounwind argmemonly 202 203define internal i32 @callee8(i8* %ptr) alwaysinline { 204 %r = call i32 @intrinsic(i8* noalias %ptr) 205 ret i32 %r 206} 207 208 209; signext is an attribute specific to the target ABI and not the 210; callee/callsite. 211; We cannot propagate that attribute to another call since it can be invalid at 212; that call. 213define i32 @test8(i8* %ptr, i64 %x) { 214; CHECK-LABEL: @test8( 215; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, i8* [[PTR:%.*]], i64 [[X:%.*]] 216; CHECK-NEXT: [[R_I:%.*]] = call i32 @intrinsic(i8* noalias [[GEP]]) 217; CHECK-NEXT: ret i32 [[R_I]] 218; 219 220 %gep = getelementptr inbounds i8, i8* %ptr, i64 %x 221 %t = call signext i32 @callee8(i8* %gep) 222 ret i32 %t 223} 224