brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.4 KiB · 7004b57 Raw
224 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py2; RUN: opt < %s -inline-threshold=0 -passes=always-inline -S | FileCheck %s3; RUN: opt < %s -passes=always-inline -S | FileCheck %s4 5declare ptr @foo(ptr) nounwind willreturn6 7define ptr @callee(ptr %p) alwaysinline {8; CHECK-LABEL: @callee(9; CHECK-NEXT:    [[R:%.*]] = call ptr @foo(ptr noalias [[P:%.*]])10; CHECK-NEXT:    ret ptr [[R]]11;12  %r = call ptr @foo(ptr noalias %p)13  ret ptr %r14}15 16define ptr @caller(ptr %ptr, i64 %x) {17; CHECK-LABEL: @caller(18; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds i8, ptr [[PTR:%.*]], i64 [[X:%.*]]19; CHECK-NEXT:    [[R_I:%.*]] = call nonnull ptr @foo(ptr noalias [[GEP]])20; CHECK-NEXT:    ret ptr [[R_I]]21;22  %gep = getelementptr inbounds i8, ptr %ptr, i64 %x23  %p = call nonnull ptr @callee(ptr %gep)24  ret ptr %p25}26 27declare void @llvm.experimental.guard(i1,...)28; Cannot add nonnull attribute to foo29; because the guard is a throwing call30define internal ptr @callee_with_throwable(ptr %p) alwaysinline {31  %r = call ptr @foo(ptr %p)32  %cond = icmp ne ptr %r, null33  call void (i1, ...) @llvm.experimental.guard(i1 %cond) [ "deopt"() ]34  ret ptr %r35}36 37declare ptr @bar(ptr) readonly nounwind38; Here also we cannot add nonnull attribute to the call bar.39define internal ptr @callee_with_explicit_control_flow(ptr %p) alwaysinline {40  %r = call ptr @bar(ptr %p)41  %cond = icmp ne ptr %r, null42  br i1 %cond, label %ret, label %orig43 44ret:45  ret ptr %r46 47orig:48  ret ptr %p49}50 51define ptr @caller2(ptr %ptr, i64 %x, i1 %cond) {52; CHECK-LABEL: @caller2(53; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds i8, ptr [[PTR:%.*]], i64 [[X:%.*]]54; CHECK-NEXT:    [[R_I:%.*]] = call ptr @foo(ptr [[GEP]])55; CHECK-NEXT:    [[COND_I:%.*]] = icmp ne ptr [[R_I]], null56; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[COND_I]]) [ "deopt"() ]57; CHECK-NEXT:    [[R_I1:%.*]] = call ptr @bar(ptr [[GEP]])58; CHECK-NEXT:    [[COND_I2:%.*]] = icmp ne ptr [[R_I1]], null59; 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 ptr [ [[R_I1]], [[RET_I]] ], [ [[GEP]], [[ORIG_I]] ]66; CHECK-NEXT:    br i1 [[COND:%.*]], label [[PRET:%.*]], label [[QRET:%.*]]67; CHECK:       pret:68; CHECK-NEXT:    ret ptr [[R_I]]69; CHECK:       qret:70; CHECK-NEXT:    ret ptr [[Q3]]71;72  %gep = getelementptr inbounds i8, ptr %ptr, i64 %x73  %p = call nonnull ptr @callee_with_throwable(ptr %gep)74  %q = call nonnull ptr @callee_with_explicit_control_flow(ptr %gep)75  br i1 %cond, label %pret, label %qret76 77pret:78  ret ptr %p79 80qret:81  ret ptr %q82}83 84define internal ptr @callee3(ptr %p) alwaysinline {85  %r = call noalias ptr @foo(ptr %p)86  ret ptr %r87}88 89; add the deref attribute to the existing attributes on foo.90define ptr @caller3(ptr %ptr, i64 %x) {91; CHECK-LABEL: @caller3(92; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds i8, ptr [[PTR:%.*]], i64 [[X:%.*]]93; CHECK-NEXT:    [[R_I:%.*]] = call noalias dereferenceable_or_null(12) ptr @foo(ptr [[GEP]])94; CHECK-NEXT:    ret ptr [[R_I]]95;96  %gep = getelementptr inbounds i8, ptr %ptr, i64 %x97  %p = call dereferenceable_or_null(12) ptr @callee3(ptr %gep)98  ret ptr %p99}100 101declare ptr @inf_loop_call(ptr) nounwind102; We cannot propagate attributes to foo because we do not know whether inf_loop_call103; will return execution.104define internal ptr @callee_with_sideeffect_callsite(ptr %p) alwaysinline {105  %r = call ptr @foo(ptr %p)106  %v = call ptr @inf_loop_call(ptr %p)107  ret ptr %r108}109 110; do not add deref attribute to foo111define ptr @test4(ptr %ptr, i64 %x) {112; CHECK-LABEL: @test4(113; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds i8, ptr [[PTR:%.*]], i64 [[X:%.*]]114; CHECK-NEXT:    [[R_I:%.*]] = call ptr @foo(ptr [[GEP]])115; CHECK-NEXT:    [[V_I:%.*]] = call ptr @inf_loop_call(ptr [[GEP]])116; CHECK-NEXT:    ret ptr [[R_I]]117;118  %gep = getelementptr inbounds i8, ptr %ptr, i64 %x119  %p = call dereferenceable_or_null(12) ptr @callee_with_sideeffect_callsite(ptr %gep)120  ret ptr %p121}122 123declare ptr @baz(ptr) nounwind willreturn124define internal ptr @callee5(ptr %p) alwaysinline {125  %r = call ptr @foo(ptr %p)126  %v = call ptr @baz(ptr %p)127  ret ptr %r128}129 130; add the deref attribute to foo.131define ptr @test5(ptr %ptr, i64 %x) {132; CHECK-LABEL: @test5(133; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds i8, ptr [[PTR:%.*]], i64 [[X:%.*]]134; CHECK-NEXT:    [[R_I:%.*]] = call dereferenceable_or_null(12) ptr @foo(ptr [[GEP]])135; CHECK-NEXT:    [[V_I:%.*]] = call ptr @baz(ptr [[GEP]])136; CHECK-NEXT:    ret ptr [[R_I]]137;138  %gep = getelementptr inbounds i8, ptr %ptr, i64 %x139  %s = call dereferenceable_or_null(12) ptr @callee5(ptr %gep)140  ret ptr %s141}142 143; deref attributes have different values on the callee and the call feeding into144; the return.145; AttrBuilder overwrites the existing value.146define internal ptr @callee6(ptr %p) alwaysinline {147  %r = call dereferenceable_or_null(16) ptr @foo(ptr %p)148  %v = call ptr @baz(ptr %p)149  ret ptr %r150}151 152 153define ptr @test6(ptr %ptr, i64 %x) {154; CHECK-LABEL: @test6(155; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds i8, ptr [[PTR:%.*]], i64 [[X:%.*]]156; CHECK-NEXT:    [[R_I:%.*]] = call dereferenceable_or_null(16) ptr @foo(ptr [[GEP]])157; CHECK-NEXT:    [[V_I:%.*]] = call ptr @baz(ptr [[GEP]])158; CHECK-NEXT:    ret ptr [[R_I]]159;160  %gep = getelementptr inbounds i8, ptr %ptr, i64 %x161  %s = call dereferenceable_or_null(12) ptr @callee6(ptr %gep)162  ret ptr %s163}164 165; We add the attributes from the callee to both the calls below.166define internal ptr @callee7(ptr %ptr, i1 %cond) alwaysinline {167  br i1 %cond, label %pass, label %fail168 169pass:170  %r = call ptr @foo(ptr noalias %ptr)171  ret ptr %r172 173fail:174  %s = call ptr @baz(ptr %ptr)175  ret ptr %s176}177 178define void @test7(ptr %ptr, i64 %x, i1 %cond) {179; CHECK-LABEL: @test7(180; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds i8, ptr [[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 ptr @foo(ptr noalias [[GEP]])184; CHECK-NEXT:    br label [[CALLEE7_EXIT:%.*]]185; CHECK:       fail.i:186; CHECK-NEXT:    [[S_I:%.*]] = call nonnull ptr @baz(ptr [[GEP]])187; CHECK-NEXT:    br label [[CALLEE7_EXIT]]188; CHECK:       callee7.exit:189; CHECK-NEXT:    [[T1:%.*]] = phi ptr [ [[R_I]], [[PASS_I]] ], [ [[S_I]], [[FAIL_I]] ]190; CHECK-NEXT:    call void @snort(ptr [[T1]])191; CHECK-NEXT:    ret void192;193 194  %gep = getelementptr inbounds i8, ptr %ptr, i64 %x195  %t = call nonnull ptr @callee7(ptr %gep, i1 %cond)196  call void @snort(ptr %t)197  ret void198}199declare void @snort(ptr)200 201declare i32 @intrinsic(ptr) nounwind argmemonly202 203define internal i32 @callee8(ptr %ptr) alwaysinline {204  %r = call i32 @intrinsic(ptr noalias %ptr)205  ret i32 %r206}207 208 209; signext is an attribute specific to the target ABI and not the210; callee/callsite.211; We cannot propagate that attribute to another call since it can be invalid at212; that call.213define i32 @test8(ptr %ptr, i64 %x) {214; CHECK-LABEL: @test8(215; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds i8, ptr [[PTR:%.*]], i64 [[X:%.*]]216; CHECK-NEXT:    [[R_I:%.*]] = call i32 @intrinsic(ptr noalias [[GEP]])217; CHECK-NEXT:    ret i32 [[R_I]]218;219 220  %gep = getelementptr inbounds i8, ptr %ptr, i64 %x221  %t = call signext i32 @callee8(ptr %gep)222  ret i32 %t223}224