; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt < %s -inline-threshold=0 -passes=always-inline -S | FileCheck %s ; RUN: opt < %s -passes=always-inline -S | FileCheck %s declare ptr @foo(ptr) nounwind willreturn define ptr @callee(ptr %p) alwaysinline { ; CHECK-LABEL: @callee( ; CHECK-NEXT: [[R:%.*]] = call ptr @foo(ptr noalias [[P:%.*]]) ; CHECK-NEXT: ret ptr [[R]] ; %r = call ptr @foo(ptr noalias %p) ret ptr %r } define ptr @caller(ptr %ptr, i64 %x) { ; CHECK-LABEL: @caller( ; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr [[PTR:%.*]], i64 [[X:%.*]] ; CHECK-NEXT: [[R_I:%.*]] = call nonnull ptr @foo(ptr noalias [[GEP]]) ; CHECK-NEXT: ret ptr [[R_I]] ; %gep = getelementptr inbounds i8, ptr %ptr, i64 %x %p = call nonnull ptr @callee(ptr %gep) ret ptr %p } declare void @llvm.experimental.guard(i1,...) ; Cannot add nonnull attribute to foo ; because the guard is a throwing call define internal ptr @callee_with_throwable(ptr %p) alwaysinline { %r = call ptr @foo(ptr %p) %cond = icmp ne ptr %r, null call void (i1, ...) @llvm.experimental.guard(i1 %cond) [ "deopt"() ] ret ptr %r } declare ptr @bar(ptr) readonly nounwind ; Here also we cannot add nonnull attribute to the call bar. define internal ptr @callee_with_explicit_control_flow(ptr %p) alwaysinline { %r = call ptr @bar(ptr %p) %cond = icmp ne ptr %r, null br i1 %cond, label %ret, label %orig ret: ret ptr %r orig: ret ptr %p } define ptr @caller2(ptr %ptr, i64 %x, i1 %cond) { ; CHECK-LABEL: @caller2( ; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr [[PTR:%.*]], i64 [[X:%.*]] ; CHECK-NEXT: [[R_I:%.*]] = call ptr @foo(ptr [[GEP]]) ; CHECK-NEXT: [[COND_I:%.*]] = icmp ne ptr [[R_I]], null ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[COND_I]]) [ "deopt"() ] ; CHECK-NEXT: [[R_I1:%.*]] = call ptr @bar(ptr [[GEP]]) ; CHECK-NEXT: [[COND_I2:%.*]] = icmp ne ptr [[R_I1]], null ; CHECK-NEXT: br i1 [[COND_I2]], label [[RET_I:%.*]], label [[ORIG_I:%.*]] ; CHECK: ret.i: ; CHECK-NEXT: br label [[CALLEE_WITH_EXPLICIT_CONTROL_FLOW_EXIT:%.*]] ; CHECK: orig.i: ; CHECK-NEXT: br label [[CALLEE_WITH_EXPLICIT_CONTROL_FLOW_EXIT]] ; CHECK: callee_with_explicit_control_flow.exit: ; CHECK-NEXT: [[Q3:%.*]] = phi ptr [ [[R_I1]], [[RET_I]] ], [ [[GEP]], [[ORIG_I]] ] ; CHECK-NEXT: br i1 [[COND:%.*]], label [[PRET:%.*]], label [[QRET:%.*]] ; CHECK: pret: ; CHECK-NEXT: ret ptr [[R_I]] ; CHECK: qret: ; CHECK-NEXT: ret ptr [[Q3]] ; %gep = getelementptr inbounds i8, ptr %ptr, i64 %x %p = call nonnull ptr @callee_with_throwable(ptr %gep) %q = call nonnull ptr @callee_with_explicit_control_flow(ptr %gep) br i1 %cond, label %pret, label %qret pret: ret ptr %p qret: ret ptr %q } define internal ptr @callee3(ptr %p) alwaysinline { %r = call noalias ptr @foo(ptr %p) ret ptr %r } ; add the deref attribute to the existing attributes on foo. define ptr @caller3(ptr %ptr, i64 %x) { ; CHECK-LABEL: @caller3( ; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr [[PTR:%.*]], i64 [[X:%.*]] ; CHECK-NEXT: [[R_I:%.*]] = call noalias dereferenceable_or_null(12) ptr @foo(ptr [[GEP]]) ; CHECK-NEXT: ret ptr [[R_I]] ; %gep = getelementptr inbounds i8, ptr %ptr, i64 %x %p = call dereferenceable_or_null(12) ptr @callee3(ptr %gep) ret ptr %p } declare ptr @inf_loop_call(ptr) nounwind ; We cannot propagate attributes to foo because we do not know whether inf_loop_call ; will return execution. define internal ptr @callee_with_sideeffect_callsite(ptr %p) alwaysinline { %r = call ptr @foo(ptr %p) %v = call ptr @inf_loop_call(ptr %p) ret ptr %r } ; do not add deref attribute to foo define ptr @test4(ptr %ptr, i64 %x) { ; CHECK-LABEL: @test4( ; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr [[PTR:%.*]], i64 [[X:%.*]] ; CHECK-NEXT: [[R_I:%.*]] = call ptr @foo(ptr [[GEP]]) ; CHECK-NEXT: [[V_I:%.*]] = call ptr @inf_loop_call(ptr [[GEP]]) ; CHECK-NEXT: ret ptr [[R_I]] ; %gep = getelementptr inbounds i8, ptr %ptr, i64 %x %p = call dereferenceable_or_null(12) ptr @callee_with_sideeffect_callsite(ptr %gep) ret ptr %p } declare ptr @baz(ptr) nounwind willreturn define internal ptr @callee5(ptr %p) alwaysinline { %r = call ptr @foo(ptr %p) %v = call ptr @baz(ptr %p) ret ptr %r } ; add the deref attribute to foo. define ptr @test5(ptr %ptr, i64 %x) { ; CHECK-LABEL: @test5( ; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr [[PTR:%.*]], i64 [[X:%.*]] ; CHECK-NEXT: [[R_I:%.*]] = call dereferenceable_or_null(12) ptr @foo(ptr [[GEP]]) ; CHECK-NEXT: [[V_I:%.*]] = call ptr @baz(ptr [[GEP]]) ; CHECK-NEXT: ret ptr [[R_I]] ; %gep = getelementptr inbounds i8, ptr %ptr, i64 %x %s = call dereferenceable_or_null(12) ptr @callee5(ptr %gep) ret ptr %s } ; deref attributes have different values on the callee and the call feeding into ; the return. ; AttrBuilder overwrites the existing value. define internal ptr @callee6(ptr %p) alwaysinline { %r = call dereferenceable_or_null(16) ptr @foo(ptr %p) %v = call ptr @baz(ptr %p) ret ptr %r } define ptr @test6(ptr %ptr, i64 %x) { ; CHECK-LABEL: @test6( ; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr [[PTR:%.*]], i64 [[X:%.*]] ; CHECK-NEXT: [[R_I:%.*]] = call dereferenceable_or_null(12) ptr @foo(ptr [[GEP]]) ; CHECK-NEXT: [[V_I:%.*]] = call ptr @baz(ptr [[GEP]]) ; CHECK-NEXT: ret ptr [[R_I]] ; %gep = getelementptr inbounds i8, ptr %ptr, i64 %x %s = call dereferenceable_or_null(12) ptr @callee6(ptr %gep) ret ptr %s } ; We add the attributes from the callee to both the calls below. define internal ptr @callee7(ptr %ptr, i1 %cond) alwaysinline { br i1 %cond, label %pass, label %fail pass: %r = call ptr @foo(ptr noalias %ptr) ret ptr %r fail: %s = call ptr @baz(ptr %ptr) ret ptr %s } define void @test7(ptr %ptr, i64 %x, i1 %cond) { ; CHECK-LABEL: @test7( ; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr [[PTR:%.*]], i64 [[X:%.*]] ; CHECK-NEXT: br i1 [[COND:%.*]], label [[PASS_I:%.*]], label [[FAIL_I:%.*]] ; CHECK: pass.i: ; CHECK-NEXT: [[R_I:%.*]] = call nonnull ptr @foo(ptr noalias [[GEP]]) ; CHECK-NEXT: br label [[CALLEE7_EXIT:%.*]] ; CHECK: fail.i: ; CHECK-NEXT: [[S_I:%.*]] = call nonnull ptr @baz(ptr [[GEP]]) ; CHECK-NEXT: br label [[CALLEE7_EXIT]] ; CHECK: callee7.exit: ; CHECK-NEXT: [[T1:%.*]] = phi ptr [ [[R_I]], [[PASS_I]] ], [ [[S_I]], [[FAIL_I]] ] ; CHECK-NEXT: call void @snort(ptr [[T1]]) ; CHECK-NEXT: ret void ; %gep = getelementptr inbounds i8, ptr %ptr, i64 %x %t = call nonnull ptr @callee7(ptr %gep, i1 %cond) call void @snort(ptr %t) ret void } declare void @snort(ptr) declare i32 @intrinsic(ptr) nounwind argmemonly define internal i32 @callee8(ptr %ptr) alwaysinline { %r = call i32 @intrinsic(ptr noalias %ptr) ret i32 %r } ; signext is an attribute specific to the target ABI and not the ; callee/callsite. ; We cannot propagate that attribute to another call since it can be invalid at ; that call. define i32 @test8(ptr %ptr, i64 %x) { ; CHECK-LABEL: @test8( ; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr [[PTR:%.*]], i64 [[X:%.*]] ; CHECK-NEXT: [[R_I:%.*]] = call i32 @intrinsic(ptr noalias [[GEP]]) ; CHECK-NEXT: ret i32 [[R_I]] ; %gep = getelementptr inbounds i8, ptr %ptr, i64 %x %t = call signext i32 @callee8(ptr %gep) ret i32 %t }