brintos

brintos / llvm-project-archived public Read only

0
0
Text · 35.4 KiB · 6242a1e Raw
840 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-attributes --check-globals --version 22; 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;5; Test cases specifically designed for the "no-capture" argument attribute.6; We use FIXME's to indicate problems and missing attributes.7;8target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"9declare ptr @unknown()10 11; TEST comparison against NULL12;13; int is_null_return(int *p) {14;   return p == 0;15; }16;17; no-capture is missing on %p because it is not dereferenceable18define i32 @is_null_return(ptr %p) #0 {19; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable20; CHECK-LABEL: define i32 @is_null_return21; CHECK-SAME: (ptr nofree readnone [[P:%.*]]) #[[ATTR0:[0-9]+]] {22; CHECK-NEXT:  entry:23; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[P]], null24; CHECK-NEXT:    [[CONV:%.*]] = zext i1 [[CMP]] to i3225; CHECK-NEXT:    ret i32 [[CONV]]26;27entry:28  %cmp = icmp eq ptr %p, null29  %conv = zext i1 %cmp to i3230  ret i32 %conv31}32 33; TEST comparison against NULL in control flow34;35; int is_null_control(int *p) {36;   if (p == 0)37;     return 1;38;   if (0 == p)39;     return 1;40;   return 0;41; }42;43; no-capture is missing on %p because it is not dereferenceable44define i32 @is_null_control(ptr %p) #0 {45; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable46; CHECK-LABEL: define i32 @is_null_control47; CHECK-SAME: (ptr nofree [[P:%.*]]) #[[ATTR0]] {48; CHECK-NEXT:  entry:49; CHECK-NEXT:    [[RETVAL:%.*]] = alloca i32, align 450; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[P]], null51; CHECK-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]52; CHECK:       if.then:53; CHECK-NEXT:    store i32 1, ptr [[RETVAL]], align 454; CHECK-NEXT:    br label [[RETURN:%.*]]55; CHECK:       if.end:56; CHECK-NEXT:    br label [[IF_END3:%.*]]57; CHECK:       if.then2:58; CHECK-NEXT:    unreachable59; CHECK:       if.end3:60; CHECK-NEXT:    store i32 0, ptr [[RETVAL]], align 461; CHECK-NEXT:    br label [[RETURN]]62; CHECK:       return:63; CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr [[RETVAL]], align 464; CHECK-NEXT:    ret i32 [[TMP0]]65;66entry:67  %retval = alloca i32, align 468  %cmp = icmp eq ptr %p, null69  br i1 %cmp, label %if.then, label %if.end70 71if.then:                                          ; preds = %entry72  store i32 1, ptr %retval, align 473  br label %return74 75if.end:                                           ; preds = %entry76  %cmp1 = icmp eq ptr null, %p77  br i1 %cmp1, label %if.then2, label %if.end378 79if.then2:                                         ; preds = %if.end80  store i32 1, ptr %retval, align 481  br label %return82 83if.end3:                                          ; preds = %if.end84  store i32 0, ptr %retval, align 485  br label %return86 87return:                                           ; preds = %if.end3, %if.then2, %if.then88  %0 = load i32, ptr %retval, align 489  ret i32 %090}91 92; TEST singleton SCC93;94; double *srec0(double *a) {95;   srec0(a);96;   return 0;97; }98;99define ptr @srec0(ptr %a) #0 {100; CHECK: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable101; CHECK-LABEL: define noalias noundef align 4294967296 ptr @srec0102; CHECK-SAME: (ptr nofree readnone captures(none) [[A:%.*]]) #[[ATTR1:[0-9]+]] {103; CHECK-NEXT:  entry:104; CHECK-NEXT:    ret ptr null105;106entry:107  %call = call ptr @srec0(ptr %a)108  ret ptr null109}110 111; TEST singleton SCC with lots of nested recursive calls112;113; int* srec16(int* a) {114;   return srec16(srec16(srec16(srec16(115;          srec16(srec16(srec16(srec16(116;          srec16(srec16(srec16(srec16(117;          srec16(srec16(srec16(srec16(118;                        a119;          ))))))))))))))));120; }121;122; Other arguments are possible here due to the no-return behavior.123;124define ptr @srec16(ptr %a) #0 {125; CHECK: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable126; CHECK-LABEL: define noalias nonnull align 4294967296 dereferenceable(4294967295) ptr @srec16127; CHECK-SAME: (ptr nofree readnone captures(none) [[A:%.*]]) #[[ATTR1]] {128; CHECK-NEXT:  entry:129; CHECK-NEXT:    ret ptr undef130;131entry:132  %call = call ptr @srec16(ptr %a)133  %call1 = call ptr @srec16(ptr %call)134  %call2 = call ptr @srec16(ptr %call1)135  %call3 = call ptr @srec16(ptr %call2)136  %call4 = call ptr @srec16(ptr %call3)137  %call5 = call ptr @srec16(ptr %call4)138  %call6 = call ptr @srec16(ptr %call5)139  %call7 = call ptr @srec16(ptr %call6)140  %call8 = call ptr @srec16(ptr %call7)141  %call9 = call ptr @srec16(ptr %call8)142  %call10 = call ptr @srec16(ptr %call9)143  %call11 = call ptr @srec16(ptr %call10)144  %call12 = call ptr @srec16(ptr %call11)145  %call13 = call ptr @srec16(ptr %call12)146  %call14 = call ptr @srec16(ptr %call13)147  %call15 = call ptr @srec16(ptr %call14)148  ret ptr %call15149}150 151; TEST SCC with various calls, casts, and comparisons agains NULL152;153; float *scc_A(int *a) {154;   return (float*)(a ? (int*)scc_A((int*)scc_B((double*)scc_C((short*)a))) : a);155; }156;157; long *scc_B(double *a) {158;   return (long*)(a ? scc_C((short*)scc_B((double*)scc_A((int*)a))) : a);159; }160;161; void *scc_C(short *a) {162;   return scc_A((int*)(scc_A(a) ? scc_B((double*)a) : scc_C(a)));163; }164define ptr @scc_A(ptr dereferenceable_or_null(4) %a) {165; CHECK: Function Attrs: nofree nosync nounwind memory(none)166; CHECK-LABEL: define noundef dereferenceable_or_null(4) ptr @scc_A167; CHECK-SAME: (ptr nofree noundef readnone returned dereferenceable_or_null(4) [[A:%.*]]) #[[ATTR2:[0-9]+]] {168; CHECK-NEXT:  entry:169; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp ne ptr [[A]], null170; CHECK-NEXT:    br i1 [[TOBOOL]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]171; CHECK:       cond.true:172; CHECK-NEXT:    [[CALL:%.*]] = call dereferenceable_or_null(4) ptr @scc_C(ptr noalias nofree noundef nonnull readnone dereferenceable(4) [[A]]) #[[ATTR2]]173; CHECK-NEXT:    [[CALL1:%.*]] = call dereferenceable_or_null(8) ptr @scc_B(ptr noalias nofree noundef readnone dereferenceable_or_null(8) [[A]]) #[[ATTR2]]174; CHECK-NEXT:    [[CALL2:%.*]] = call ptr @scc_A(ptr noalias nofree noundef readnone dereferenceable_or_null(8) [[A]]) #[[ATTR2]]175; CHECK-NEXT:    br label [[COND_END:%.*]]176; CHECK:       cond.false:177; CHECK-NEXT:    br label [[COND_END]]178; CHECK:       cond.end:179; CHECK-NEXT:    [[COND:%.*]] = phi ptr [ [[A]], [[COND_TRUE]] ], [ [[A]], [[COND_FALSE]] ]180; CHECK-NEXT:    ret ptr [[A]]181;182entry:183  %tobool = icmp ne ptr %a, null184  br i1 %tobool, label %cond.true, label %cond.false185 186cond.true:                                        ; preds = %entry187  %call = call ptr @scc_C(ptr %a)188  %call1 = call ptr @scc_B(ptr %call)189  %call2 = call ptr @scc_A(ptr %call1)190  br label %cond.end191 192cond.false:                                       ; preds = %entry193  br label %cond.end194 195cond.end:                                         ; preds = %cond.false, %cond.true196  %cond = phi ptr [ %call2, %cond.true ], [ %a, %cond.false ]197  ret ptr %cond198}199 200; FIXME: the call1 below to scc_B should return dereferenceable_or_null(8) (as the callee does). Something prevented that deduction and needs to be investigated.201define ptr @scc_B(ptr dereferenceable_or_null(8) %a) {202; CHECK: Function Attrs: nofree nosync nounwind memory(none)203; CHECK-LABEL: define noundef dereferenceable_or_null(8) ptr @scc_B204; CHECK-SAME: (ptr nofree noundef readnone returned dereferenceable_or_null(8) [[A:%.*]]) #[[ATTR2]] {205; CHECK-NEXT:  entry:206; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp ne ptr [[A]], null207; CHECK-NEXT:    br i1 [[TOBOOL]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]208; CHECK:       cond.true:209; CHECK-NEXT:    [[CALL:%.*]] = call dereferenceable_or_null(4) ptr @scc_A(ptr noalias nofree noundef nonnull readnone dereferenceable(8) [[A]]) #[[ATTR2]]210; CHECK-NEXT:    [[CALL1:%.*]] = call dereferenceable_or_null(8) ptr @scc_B(ptr noalias nofree noundef readnone dereferenceable_or_null(8) [[A]]) #[[ATTR2]]211; CHECK-NEXT:    [[CALL2:%.*]] = call ptr @scc_C(ptr noalias nofree noundef readnone dereferenceable_or_null(8) [[A]]) #[[ATTR2]]212; CHECK-NEXT:    br label [[COND_END:%.*]]213; CHECK:       cond.false:214; CHECK-NEXT:    br label [[COND_END]]215; CHECK:       cond.end:216; CHECK-NEXT:    [[COND:%.*]] = phi ptr [ [[A]], [[COND_TRUE]] ], [ [[A]], [[COND_FALSE]] ]217; CHECK-NEXT:    ret ptr [[A]]218;219entry:220  %tobool = icmp ne ptr %a, null221  br i1 %tobool, label %cond.true, label %cond.false222 223cond.true:                                        ; preds = %entry224  %call = call ptr @scc_A(ptr %a)225  %call1 = call ptr @scc_B(ptr %call)226  %call2 = call ptr @scc_C(ptr %call1)227  br label %cond.end228 229cond.false:                                       ; preds = %entry230  br label %cond.end231 232cond.end:                                         ; preds = %cond.false, %cond.true233  %cond = phi ptr [ %call2, %cond.true ], [ %a, %cond.false ]234  ret ptr %cond235}236 237define ptr @scc_C(ptr dereferenceable_or_null(2) %a) {238; CHECK: Function Attrs: nofree nosync nounwind memory(none)239; CHECK-LABEL: define noundef dereferenceable_or_null(4) ptr @scc_C240; CHECK-SAME: (ptr nofree noundef readnone returned dereferenceable_or_null(4) [[A:%.*]]) #[[ATTR2]] {241; CHECK-NEXT:  entry:242; CHECK-NEXT:    [[CALL:%.*]] = call ptr @scc_A(ptr noalias nofree noundef readnone dereferenceable_or_null(4) [[A]]) #[[ATTR2]]243; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp ne ptr [[A]], null244; CHECK-NEXT:    br i1 [[TOBOOL]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]245; CHECK:       cond.true:246; CHECK-NEXT:    [[CALL1:%.*]] = call ptr @scc_B(ptr noalias nofree noundef readnone dereferenceable_or_null(8) [[A]]) #[[ATTR2]]247; CHECK-NEXT:    br label [[COND_END:%.*]]248; CHECK:       cond.false:249; CHECK-NEXT:    [[CALL2:%.*]] = call ptr @scc_C(ptr noalias nofree noundef readnone dereferenceable_or_null(4) [[A]]) #[[ATTR2]]250; CHECK-NEXT:    br label [[COND_END]]251; CHECK:       cond.end:252; CHECK-NEXT:    [[COND:%.*]] = phi ptr [ [[A]], [[COND_TRUE]] ], [ [[A]], [[COND_FALSE]] ]253; CHECK-NEXT:    [[CALL3:%.*]] = call ptr @scc_A(ptr noalias nofree noundef readnone dereferenceable_or_null(4) [[A]]) #[[ATTR2]]254; CHECK-NEXT:    ret ptr [[A]]255;256entry:257  %call = call ptr @scc_A(ptr %a)258  %tobool = icmp ne ptr %call, null259  br i1 %tobool, label %cond.true, label %cond.false260 261cond.true:                                        ; preds = %entry262  %call1 = call ptr @scc_B(ptr %a)263  br label %cond.end264 265cond.false:                                       ; preds = %entry266  %call2 = call ptr @scc_C(ptr %a)267  br label %cond.end268 269cond.end:                                         ; preds = %cond.false, %cond.true270  %cond = phi ptr [ %call1, %cond.true ], [ %call2, %cond.false ]271  %call3 = call ptr @scc_A(ptr %cond)272  ret ptr %call3273}274 275 276; TEST call to external function, marked no-capture277;278; void external_no_capture(int /* no-capture */ *p);279; void test_external_no_capture(int *p) {280;   external_no_capture(p);281; }282;283declare void @external_no_capture(ptr nocapture)284 285define void @test_external_no_capture(ptr %p) #0 {286; CHECK: Function Attrs: noinline nounwind uwtable287; CHECK-LABEL: define void @test_external_no_capture288; CHECK-SAME: (ptr captures(none) [[P:%.*]]) #[[ATTR3:[0-9]+]] {289; CHECK-NEXT:  entry:290; CHECK-NEXT:    call void @external_no_capture(ptr captures(none) [[P]])291; CHECK-NEXT:    ret void292;293entry:294  call void @external_no_capture(ptr %p)295  ret void296}297 298; TEST call to external var-args function, marked no-capture299;300; void test_var_arg_call(char *p, int a) {301;   printf(p, a);302; }303;304define void @test_var_arg_call(ptr %p, i32 %a) #0 {305; CHECK: Function Attrs: noinline nounwind uwtable306; CHECK-LABEL: define void @test_var_arg_call307; CHECK-SAME: (ptr captures(none) [[P:%.*]], i32 [[A:%.*]]) #[[ATTR3]] {308; CHECK-NEXT:  entry:309; CHECK-NEXT:    [[CALL:%.*]] = call i32 (ptr, ...) @printf(ptr captures(none) [[P]], i32 [[A]])310; CHECK-NEXT:    ret void311;312entry:313  %call = call i32 (ptr, ...) @printf(ptr %p, i32 %a)314  ret void315}316 317declare i32 @printf(ptr nocapture, ...)318 319 320; TEST "captured" only through return321;322; long *not_captured_but_returned_0(long *a) {323;   *a1 = 0;324;   return a;325; }326;327; There should *not* be a no-capture attribute on %a328define ptr @not_captured_but_returned_0(ptr %a) #0 {329; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(argmem: write) uwtable330; CHECK-LABEL: define noundef nonnull align 8 dereferenceable(8) ptr @not_captured_but_returned_0331; CHECK-SAME: (ptr nofree noundef nonnull returned writeonly align 8 dereferenceable(8) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR4:[0-9]+]] {332; CHECK-NEXT:  entry:333; CHECK-NEXT:    store i64 0, ptr [[A]], align 8334; CHECK-NEXT:    ret ptr [[A]]335;336entry:337  store i64 0, ptr %a, align 8338  ret ptr %a339}340 341; TEST "captured" only through return342;343; long *not_captured_but_returned_1(long *a) {344;   *(a+1) = 1;345;   return a + 1;346; }347;348; There should *not* be a no-capture attribute on %a349define ptr @not_captured_but_returned_1(ptr %a) #0 {350; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(argmem: write) uwtable351; CHECK-LABEL: define noundef nonnull align 8 dereferenceable(8) ptr @not_captured_but_returned_1352; CHECK-SAME: (ptr nofree nonnull writeonly align 8 dereferenceable(16) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR4]] {353; CHECK-NEXT:  entry:354; CHECK-NEXT:    [[ADD_PTR:%.*]] = getelementptr inbounds i64, ptr [[A]], i64 1355; CHECK-NEXT:    store i64 1, ptr [[ADD_PTR]], align 8356; CHECK-NEXT:    ret ptr [[ADD_PTR]]357;358entry:359  %add.ptr = getelementptr inbounds i64, ptr %a, i64 1360  store i64 1, ptr %add.ptr, align 8361  ret ptr %add.ptr362}363 364; TEST calls to "captured" only through return functions365;366; void test_not_captured_but_returned_calls(long *a) {367;   not_captured_but_returned_0(a);368;   not_captured_but_returned_1(a);369; }370;371define void @test_not_captured_but_returned_calls(ptr %a) #0 {372; TUNIT: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(argmem: write) uwtable373; TUNIT-LABEL: define void @test_not_captured_but_returned_calls374; TUNIT-SAME: (ptr nofree writeonly align 8 captures(none) [[A:%.*]]) #[[ATTR4]] {375; TUNIT-NEXT:  entry:376; TUNIT-NEXT:    [[CALL:%.*]] = call ptr @not_captured_but_returned_0(ptr nofree noundef writeonly align 8 "no-capture-maybe-returned" [[A]]) #[[ATTR12:[0-9]+]]377; TUNIT-NEXT:    [[CALL1:%.*]] = call ptr @not_captured_but_returned_1(ptr nofree writeonly align 8 "no-capture-maybe-returned" [[A]]) #[[ATTR12]]378; TUNIT-NEXT:    ret void379;380; CGSCC: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(argmem: write) uwtable381; CGSCC-LABEL: define void @test_not_captured_but_returned_calls382; CGSCC-SAME: (ptr nofree noundef nonnull writeonly align 8 dereferenceable(16) [[A:%.*]]) #[[ATTR5:[0-9]+]] {383; CGSCC-NEXT:  entry:384; CGSCC-NEXT:    [[CALL:%.*]] = call ptr @not_captured_but_returned_0(ptr nofree noundef nonnull writeonly align 8 dereferenceable(16) [[A]]) #[[ATTR14:[0-9]+]]385; CGSCC-NEXT:    [[CALL1:%.*]] = call ptr @not_captured_but_returned_1(ptr nofree noundef nonnull writeonly align 8 dereferenceable(16) [[A]]) #[[ATTR14]]386; CGSCC-NEXT:    ret void387;388entry:389  %call = call ptr @not_captured_but_returned_0(ptr %a)390  %call1 = call ptr @not_captured_but_returned_1(ptr %a)391  ret void392}393 394; TEST "captured" only through transitive return395;396; long* negative_test_not_captured_but_returned_call_0a(long *a) {397;   return not_captured_but_returned_0(a);398; }399;400; There should *not* be a no-capture attribute on %a401define ptr @negative_test_not_captured_but_returned_call_0a(ptr %a) #0 {402; TUNIT: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(argmem: write) uwtable403; TUNIT-LABEL: define align 8 ptr @negative_test_not_captured_but_returned_call_0a404; TUNIT-SAME: (ptr nofree returned writeonly align 8 "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR4]] {405; TUNIT-NEXT:  entry:406; TUNIT-NEXT:    [[CALL:%.*]] = call ptr @not_captured_but_returned_0(ptr nofree noundef writeonly align 8 "no-capture-maybe-returned" [[A]]) #[[ATTR12]]407; TUNIT-NEXT:    ret ptr [[A]]408;409; CGSCC: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(argmem: write) uwtable410; CGSCC-LABEL: define noundef nonnull align 8 dereferenceable(8) ptr @negative_test_not_captured_but_returned_call_0a411; CGSCC-SAME: (ptr nofree noundef nonnull writeonly align 8 dereferenceable(8) [[A:%.*]]) #[[ATTR5]] {412; CGSCC-NEXT:  entry:413; CGSCC-NEXT:    [[CALL:%.*]] = call noundef nonnull align 8 dereferenceable(8) ptr @not_captured_but_returned_0(ptr nofree noundef nonnull writeonly align 8 dereferenceable(8) [[A]]) #[[ATTR14]]414; CGSCC-NEXT:    ret ptr [[CALL]]415;416entry:417  %call = call ptr @not_captured_but_returned_0(ptr %a)418  ret ptr %call419}420 421; TEST captured through write422;423; void negative_test_not_captured_but_returned_call_0b(long *a) {424;   *a = (long)not_captured_but_returned_0(a);425; }426;427; There should *not* be a no-capture attribute on %a428define void @negative_test_not_captured_but_returned_call_0b(ptr %a) #0 {429; TUNIT: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(argmem: write) uwtable430; TUNIT-LABEL: define void @negative_test_not_captured_but_returned_call_0b431; TUNIT-SAME: (ptr nofree writeonly align 8 [[A:%.*]]) #[[ATTR4]] {432; TUNIT-NEXT:  entry:433; TUNIT-NEXT:    [[CALL:%.*]] = call ptr @not_captured_but_returned_0(ptr nofree noundef writeonly align 8 "no-capture-maybe-returned" [[A]]) #[[ATTR12]]434; TUNIT-NEXT:    [[TMP0:%.*]] = ptrtoint ptr [[A]] to i64435; TUNIT-NEXT:    store i64 [[TMP0]], ptr [[A]], align 8436; TUNIT-NEXT:    ret void437;438; CGSCC: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(argmem: write) uwtable439; CGSCC-LABEL: define void @negative_test_not_captured_but_returned_call_0b440; CGSCC-SAME: (ptr nofree noundef nonnull writeonly align 8 dereferenceable(8) [[A:%.*]]) #[[ATTR5]] {441; CGSCC-NEXT:  entry:442; CGSCC-NEXT:    [[CALL:%.*]] = call ptr @not_captured_but_returned_0(ptr nofree noundef nonnull writeonly align 8 dereferenceable(8) [[A]]) #[[ATTR14]]443; CGSCC-NEXT:    [[TMP0:%.*]] = ptrtoint ptr [[CALL]] to i64444; CGSCC-NEXT:    store i64 [[TMP0]], ptr [[A]], align 8445; CGSCC-NEXT:    ret void446;447entry:448  %call = call ptr @not_captured_but_returned_0(ptr %a)449  %0 = ptrtoint ptr %call to i64450  store i64 %0, ptr %a, align 8451  ret void452}453 454; TEST "captured" only through transitive return455;456; long* negative_test_not_captured_but_returned_call_1a(long *a) {457;   return not_captured_but_returned_1(a);458; }459;460; There should *not* be a no-capture attribute on %a461define ptr @negative_test_not_captured_but_returned_call_1a(ptr %a) #0 {462; TUNIT: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(argmem: write) uwtable463; TUNIT-LABEL: define noundef nonnull align 8 dereferenceable(8) ptr @negative_test_not_captured_but_returned_call_1a464; TUNIT-SAME: (ptr nofree writeonly align 8 "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR4]] {465; TUNIT-NEXT:  entry:466; TUNIT-NEXT:    [[CALL:%.*]] = call noundef nonnull align 8 dereferenceable(8) ptr @not_captured_but_returned_1(ptr nofree writeonly align 8 "no-capture-maybe-returned" [[A]]) #[[ATTR12]]467; TUNIT-NEXT:    ret ptr [[CALL]]468;469; CGSCC: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(argmem: write) uwtable470; CGSCC-LABEL: define noundef nonnull align 8 dereferenceable(8) ptr @negative_test_not_captured_but_returned_call_1a471; CGSCC-SAME: (ptr nofree noundef nonnull writeonly align 8 dereferenceable(16) [[A:%.*]]) #[[ATTR5]] {472; CGSCC-NEXT:  entry:473; CGSCC-NEXT:    [[CALL:%.*]] = call noundef nonnull align 8 dereferenceable(8) ptr @not_captured_but_returned_1(ptr nofree noundef nonnull writeonly align 8 dereferenceable(16) [[A]]) #[[ATTR14]]474; CGSCC-NEXT:    ret ptr [[CALL]]475;476entry:477  %call = call ptr @not_captured_but_returned_1(ptr %a)478  ret ptr %call479}480 481; TEST captured through write482;483; void negative_test_not_captured_but_returned_call_1b(long *a) {484;   *a = (long)not_captured_but_returned_1(a);485; }486;487; There should *not* be a no-capture attribute on %a488define void @negative_test_not_captured_but_returned_call_1b(ptr %a) #0 {489; TUNIT: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(write) uwtable490; TUNIT-LABEL: define void @negative_test_not_captured_but_returned_call_1b491; TUNIT-SAME: (ptr nofree writeonly align 8 [[A:%.*]]) #[[ATTR5:[0-9]+]] {492; TUNIT-NEXT:  entry:493; TUNIT-NEXT:    [[CALL:%.*]] = call align 8 ptr @not_captured_but_returned_1(ptr nofree writeonly align 8 "no-capture-maybe-returned" [[A]]) #[[ATTR12]]494; TUNIT-NEXT:    [[TMP0:%.*]] = ptrtoint ptr [[CALL]] to i64495; TUNIT-NEXT:    store i64 [[TMP0]], ptr [[CALL]], align 8496; TUNIT-NEXT:    ret void497;498; CGSCC: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(write) uwtable499; CGSCC-LABEL: define void @negative_test_not_captured_but_returned_call_1b500; CGSCC-SAME: (ptr nofree noundef nonnull writeonly align 8 dereferenceable(16) [[A:%.*]]) #[[ATTR6:[0-9]+]] {501; CGSCC-NEXT:  entry:502; CGSCC-NEXT:    [[CALL:%.*]] = call align 8 ptr @not_captured_but_returned_1(ptr nofree noundef nonnull writeonly align 8 dereferenceable(16) [[A]]) #[[ATTR14]]503; CGSCC-NEXT:    [[TMP0:%.*]] = ptrtoint ptr [[CALL]] to i64504; CGSCC-NEXT:    store i64 [[TMP0]], ptr [[CALL]], align 8505; CGSCC-NEXT:    ret void506;507entry:508  %call = call ptr @not_captured_but_returned_1(ptr %a)509  %0 = ptrtoint ptr %call to i64510  store i64 %0, ptr %call, align 8511  ret void512}513 514; TEST return argument or unknown call result515;516; int* ret_arg_or_unknown(int* b) {517;   if (b == 0)518;     return b;519;   return unknown();520; }521;522; Verify we do *not* assume b is returned or not captured.523;524 525define ptr @ret_arg_or_unknown(ptr %b) #0 {526; CHECK: Function Attrs: noinline nounwind uwtable527; CHECK-LABEL: define ptr @ret_arg_or_unknown528; CHECK-SAME: (ptr [[B:%.*]]) #[[ATTR3]] {529; CHECK-NEXT:  entry:530; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[B]], null531; CHECK-NEXT:    br i1 [[CMP]], label [[RET_ARG:%.*]], label [[RET_UNKNOWN:%.*]]532; CHECK:       ret_arg:533; CHECK-NEXT:    ret ptr [[B]]534; CHECK:       ret_unknown:535; CHECK-NEXT:    [[CALL:%.*]] = call ptr @unknown()536; CHECK-NEXT:    ret ptr [[CALL]]537;538entry:539  %cmp = icmp eq ptr %b, null540  br i1 %cmp, label %ret_arg, label %ret_unknown541 542ret_arg:543  ret ptr %b544 545ret_unknown:546  %call = call ptr @unknown()547  ret ptr %call548}549 550define ptr @ret_arg_or_unknown_through_phi(ptr %b) #0 {551; CHECK: Function Attrs: noinline nounwind uwtable552; CHECK-LABEL: define ptr @ret_arg_or_unknown_through_phi553; CHECK-SAME: (ptr [[B:%.*]]) #[[ATTR3]] {554; CHECK-NEXT:  entry:555; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[B]], null556; CHECK-NEXT:    br i1 [[CMP]], label [[RET_ARG:%.*]], label [[RET_UNKNOWN:%.*]]557; CHECK:       ret_arg:558; CHECK-NEXT:    br label [[R:%.*]]559; CHECK:       ret_unknown:560; CHECK-NEXT:    [[CALL:%.*]] = call ptr @unknown()561; CHECK-NEXT:    br label [[R]]562; CHECK:       r:563; CHECK-NEXT:    [[PHI:%.*]] = phi ptr [ [[B]], [[RET_ARG]] ], [ [[CALL]], [[RET_UNKNOWN]] ]564; CHECK-NEXT:    ret ptr [[PHI]]565;566entry:567  %cmp = icmp eq ptr %b, null568  br i1 %cmp, label %ret_arg, label %ret_unknown569 570ret_arg:571  br label %r572 573ret_unknown:574  %call = call ptr @unknown()575  br label %r576 577r:578  %phi = phi ptr [ %b, %ret_arg ], [ %call, %ret_unknown ]579  ret ptr %phi580}581 582 583; TEST not captured by readonly external function584;585declare ptr @readonly_unknown(ptr, ptr) readonly586 587define void @not_captured_by_readonly_call(ptr %b) #0 {588; TUNIT: Function Attrs: noinline nosync nounwind memory(read) uwtable589; TUNIT-LABEL: define void @not_captured_by_readonly_call590; TUNIT-SAME: (ptr readonly captures(none) [[B:%.*]]) #[[ATTR7:[0-9]+]] {591; TUNIT-NEXT:  entry:592; TUNIT-NEXT:    [[CALL:%.*]] = call ptr @readonly_unknown(ptr readonly [[B]], ptr readonly [[B]]) #[[ATTR13:[0-9]+]]593; TUNIT-NEXT:    ret void594;595; CGSCC: Function Attrs: noinline nosync nounwind memory(read) uwtable596; CGSCC-LABEL: define void @not_captured_by_readonly_call597; CGSCC-SAME: (ptr readonly captures(none) [[B:%.*]]) #[[ATTR8:[0-9]+]] {598; CGSCC-NEXT:  entry:599; CGSCC-NEXT:    [[CALL:%.*]] = call ptr @readonly_unknown(ptr readonly [[B]], ptr readonly [[B]]) #[[ATTR15:[0-9]+]]600; CGSCC-NEXT:    ret void601;602entry:603  %call = call ptr @readonly_unknown(ptr %b, ptr %b)604  ret void605}606 607 608; TEST not captured by readonly external function if return chain is known609;610; Make sure the returned flag on %r is strong enough to justify nocapture on %b but **not** on %r.611;612define ptr @not_captured_by_readonly_call_not_returned_either1(ptr %b, ptr returned %r) {613; TUNIT: Function Attrs: nosync nounwind memory(read)614; TUNIT-LABEL: define ptr @not_captured_by_readonly_call_not_returned_either1615; TUNIT-SAME: (ptr readonly captures(none) [[B:%.*]], ptr readonly returned [[R:%.*]]) #[[ATTR8:[0-9]+]] {616; TUNIT-NEXT:  entry:617; TUNIT-NEXT:    [[CALL:%.*]] = call ptr @readonly_unknown(ptr readonly [[B]], ptr readonly [[R]]) #[[ATTR8]]618; TUNIT-NEXT:    ret ptr [[CALL]]619;620; CGSCC: Function Attrs: nosync nounwind memory(read)621; CGSCC-LABEL: define ptr @not_captured_by_readonly_call_not_returned_either1622; CGSCC-SAME: (ptr readonly captures(none) [[B:%.*]], ptr readonly returned [[R:%.*]]) #[[ATTR9:[0-9]+]] {623; CGSCC-NEXT:  entry:624; CGSCC-NEXT:    [[CALL:%.*]] = call ptr @readonly_unknown(ptr readonly [[B]], ptr readonly [[R]]) #[[ATTR9]]625; CGSCC-NEXT:    ret ptr [[CALL]]626;627entry:628  %call = call ptr @readonly_unknown(ptr %b, ptr %r) nounwind629  ret ptr %call630}631 632declare ptr @readonly_unknown_r1a(ptr, ptr returned) readonly633define ptr @not_captured_by_readonly_call_not_returned_either2(ptr %b, ptr %r) {634; TUNIT: Function Attrs: nosync nounwind memory(read)635; TUNIT-LABEL: define ptr @not_captured_by_readonly_call_not_returned_either2636; TUNIT-SAME: (ptr readonly [[B:%.*]], ptr readonly [[R:%.*]]) #[[ATTR8]] {637; TUNIT-NEXT:  entry:638; TUNIT-NEXT:    [[CALL:%.*]] = call ptr @readonly_unknown_r1a(ptr readonly [[B]], ptr readonly [[R]]) #[[ATTR8]]639; TUNIT-NEXT:    ret ptr [[CALL]]640;641; CGSCC: Function Attrs: nosync nounwind memory(read)642; CGSCC-LABEL: define ptr @not_captured_by_readonly_call_not_returned_either2643; CGSCC-SAME: (ptr readonly [[B:%.*]], ptr readonly [[R:%.*]]) #[[ATTR9]] {644; CGSCC-NEXT:  entry:645; CGSCC-NEXT:    [[CALL:%.*]] = call ptr @readonly_unknown_r1a(ptr readonly [[B]], ptr readonly [[R]]) #[[ATTR9]]646; CGSCC-NEXT:    ret ptr [[CALL]]647;648entry:649  %call = call ptr @readonly_unknown_r1a(ptr %b, ptr %r) nounwind650  ret ptr %call651}652 653declare ptr @readonly_unknown_r1b(ptr, ptr returned) readonly nounwind654define ptr @not_captured_by_readonly_call_not_returned_either3(ptr %b, ptr %r) {655; TUNIT: Function Attrs: nosync nounwind memory(read)656; TUNIT-LABEL: define ptr @not_captured_by_readonly_call_not_returned_either3657; TUNIT-SAME: (ptr readonly captures(none) [[B:%.*]], ptr readonly [[R:%.*]]) #[[ATTR8]] {658; TUNIT-NEXT:  entry:659; TUNIT-NEXT:    [[CALL:%.*]] = call ptr @readonly_unknown_r1b(ptr readonly captures(none) [[B]], ptr readonly [[R]]) #[[ATTR8]]660; TUNIT-NEXT:    ret ptr [[CALL]]661;662; CGSCC: Function Attrs: nosync nounwind memory(read)663; CGSCC-LABEL: define ptr @not_captured_by_readonly_call_not_returned_either3664; CGSCC-SAME: (ptr readonly captures(none) [[B:%.*]], ptr readonly [[R:%.*]]) #[[ATTR9]] {665; CGSCC-NEXT:  entry:666; CGSCC-NEXT:    [[CALL:%.*]] = call ptr @readonly_unknown_r1b(ptr readonly captures(none) [[B]], ptr readonly [[R]]) #[[ATTR9]]667; CGSCC-NEXT:    ret ptr [[CALL]]668;669entry:670  %call = call ptr @readonly_unknown_r1b(ptr %b, ptr %r)671  ret ptr %call672}673 674define ptr @not_captured_by_readonly_call_not_returned_either4(ptr %b, ptr %r) nounwind {675; TUNIT: Function Attrs: nosync nounwind memory(read)676; TUNIT-LABEL: define ptr @not_captured_by_readonly_call_not_returned_either4677; TUNIT-SAME: (ptr readonly [[B:%.*]], ptr readonly [[R:%.*]]) #[[ATTR8]] {678; TUNIT-NEXT:  entry:679; TUNIT-NEXT:    [[CALL:%.*]] = call ptr @readonly_unknown_r1a(ptr readonly [[B]], ptr readonly [[R]]) #[[ATTR13]]680; TUNIT-NEXT:    ret ptr [[CALL]]681;682; CGSCC: Function Attrs: nosync nounwind memory(read)683; CGSCC-LABEL: define ptr @not_captured_by_readonly_call_not_returned_either4684; CGSCC-SAME: (ptr readonly [[B:%.*]], ptr readonly [[R:%.*]]) #[[ATTR9]] {685; CGSCC-NEXT:  entry:686; CGSCC-NEXT:    [[CALL:%.*]] = call ptr @readonly_unknown_r1a(ptr readonly [[B]], ptr readonly [[R]]) #[[ATTR15]]687; CGSCC-NEXT:    ret ptr [[CALL]]688;689entry:690  %call = call ptr @readonly_unknown_r1a(ptr %b, ptr %r)691  ret ptr %call692}693 694 695declare ptr @unknown_i32p(ptr)696define void @nocapture_is_not_subsumed_1(ptr nocapture %b) {697; CHECK-LABEL: define void @nocapture_is_not_subsumed_1698; CHECK-SAME: (ptr captures(none) [[B:%.*]]) {699; CHECK-NEXT:  entry:700; CHECK-NEXT:    [[CALL:%.*]] = call ptr @unknown_i32p(ptr [[B]])701; CHECK-NEXT:    store i32 0, ptr [[CALL]], align 4702; CHECK-NEXT:    ret void703;704entry:705  %call = call ptr @unknown_i32p(ptr %b)706  store i32 0, ptr %call707  ret void708}709 710declare ptr @readonly_i32p(ptr) readonly711define void @nocapture_is_not_subsumed_2(ptr nocapture %b) {712; TUNIT: Function Attrs: nosync713; TUNIT-LABEL: define void @nocapture_is_not_subsumed_2714; TUNIT-SAME: (ptr captures(none) [[B:%.*]]) #[[ATTR10:[0-9]+]] {715; TUNIT-NEXT:  entry:716; TUNIT-NEXT:    [[CALL:%.*]] = call ptr @readonly_i32p(ptr readonly [[B]]) #[[ATTR13]]717; TUNIT-NEXT:    store i32 0, ptr [[CALL]], align 4718; TUNIT-NEXT:    ret void719;720; CGSCC: Function Attrs: nosync721; CGSCC-LABEL: define void @nocapture_is_not_subsumed_2722; CGSCC-SAME: (ptr captures(none) [[B:%.*]]) #[[ATTR11:[0-9]+]] {723; CGSCC-NEXT:  entry:724; CGSCC-NEXT:    [[CALL:%.*]] = call ptr @readonly_i32p(ptr readonly [[B]]) #[[ATTR15]]725; CGSCC-NEXT:    store i32 0, ptr [[CALL]], align 4726; CGSCC-NEXT:    ret void727;728entry:729  %call = call ptr @readonly_i32p(ptr %b)730  store i32 0, ptr %call731  ret void732}733 734; Make sure %p is not not marked nocapture (Bug #64613).735; Version a failed with the lightweight attributor, b with the full one.736define ptr @b64613_a(ptr noundef %p) {737; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)738; TUNIT-LABEL: define noundef ptr @b64613_a739; TUNIT-SAME: (ptr nofree noundef readnone returned "no-capture-maybe-returned" [[P:%.*]]) #[[ATTR11:[0-9]+]] {740; TUNIT-NEXT:    [[P_ADDR:%.*]] = alloca ptr, align 1741; TUNIT-NEXT:    store ptr [[P]], ptr [[P_ADDR]], align 1742; TUNIT-NEXT:    ret ptr [[P]]743;744; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)745; CGSCC-LABEL: define noundef ptr @b64613_a746; CGSCC-SAME: (ptr nofree noundef readnone returned "no-capture-maybe-returned" [[P:%.*]]) #[[ATTR12:[0-9]+]] {747; CGSCC-NEXT:    [[P_ADDR:%.*]] = alloca ptr, align 1748; CGSCC-NEXT:    store ptr [[P]], ptr [[P_ADDR]], align 1749; CGSCC-NEXT:    ret ptr [[P]]750;751  %p.addr = alloca ptr, align 1752  store ptr %p, ptr %p.addr, align 1753  %r = load ptr, ptr %p.addr, align 1754  ret ptr %r755}756define ptr @b64613_b(ptr noundef %p, i32 %i) {757; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)758; TUNIT-LABEL: define ptr @b64613_b759; TUNIT-SAME: (ptr nofree noundef [[P:%.*]], i32 [[I:%.*]]) #[[ATTR11]] {760; TUNIT-NEXT:    [[P_ADDR:%.*]] = alloca <2 x ptr>, align 1761; TUNIT-NEXT:    [[G:%.*]] = getelementptr i8, ptr [[P_ADDR]], i32 [[I]]762; TUNIT-NEXT:    store ptr [[P]], ptr [[G]], align 1763; TUNIT-NEXT:    [[R:%.*]] = load ptr, ptr [[P_ADDR]], align 1764; TUNIT-NEXT:    ret ptr [[R]]765;766; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)767; CGSCC-LABEL: define ptr @b64613_b768; CGSCC-SAME: (ptr nofree noundef [[P:%.*]], i32 [[I:%.*]]) #[[ATTR12]] {769; CGSCC-NEXT:    [[P_ADDR:%.*]] = alloca <2 x ptr>, align 1770; CGSCC-NEXT:    [[G:%.*]] = getelementptr i8, ptr [[P_ADDR]], i32 [[I]]771; CGSCC-NEXT:    store ptr [[P]], ptr [[G]], align 1772; CGSCC-NEXT:    [[R:%.*]] = load ptr, ptr [[P_ADDR]], align 1773; CGSCC-NEXT:    ret ptr [[R]]774;775  %p.addr = alloca <2 x ptr>, align 1776  %g = getelementptr i8, ptr %p.addr, i32 %i777  store ptr %p, ptr %g, align 1778  %r = load ptr, ptr %p.addr, align 1779  ret ptr %r780}781define void @b64613_positive(ptr noundef %p, i32 %i) {782; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)783; TUNIT-LABEL: define void @b64613_positive784; TUNIT-SAME: (ptr nofree noundef captures(none) [[P:%.*]], i32 [[I:%.*]]) #[[ATTR11]] {785; TUNIT-NEXT:    [[P_ADDR:%.*]] = alloca <2 x ptr>, align 1786; TUNIT-NEXT:    [[G:%.*]] = getelementptr i8, ptr [[P_ADDR]], i32 [[I]]787; TUNIT-NEXT:    store ptr [[P]], ptr [[G]], align 1788; TUNIT-NEXT:    ret void789;790; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)791; CGSCC-LABEL: define void @b64613_positive792; CGSCC-SAME: (ptr nofree noundef captures(none) [[P:%.*]], i32 [[I:%.*]]) #[[ATTR13:[0-9]+]] {793; CGSCC-NEXT:    [[P_ADDR:%.*]] = alloca <2 x ptr>, align 1794; CGSCC-NEXT:    [[G:%.*]] = getelementptr i8, ptr [[P_ADDR]], i32 [[I]]795; CGSCC-NEXT:    store ptr [[P]], ptr [[G]], align 1796; CGSCC-NEXT:    ret void797;798  %p.addr = alloca <2 x ptr>, align 1799  %g = getelementptr i8, ptr %p.addr, i32 %i800  store ptr %p, ptr %g, align 1801  %r = load ptr, ptr %p.addr, align 1802  %q = call ptr @b64613_b(ptr %r, i32 %i)803  ret void804}805 806attributes #0 = { noinline nounwind uwtable }807;.808; TUNIT: attributes #[[ATTR0]] = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable }809; TUNIT: attributes #[[ATTR1]] = { mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable }810; TUNIT: attributes #[[ATTR2]] = { nofree nosync nounwind memory(none) }811; TUNIT: attributes #[[ATTR3]] = { noinline nounwind uwtable }812; TUNIT: attributes #[[ATTR4]] = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(argmem: write) uwtable }813; TUNIT: attributes #[[ATTR5]] = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(write) uwtable }814; TUNIT: attributes #[[ATTR6:[0-9]+]] = { memory(read) }815; TUNIT: attributes #[[ATTR7]] = { noinline nosync nounwind memory(read) uwtable }816; TUNIT: attributes #[[ATTR8]] = { nosync nounwind memory(read) }817; TUNIT: attributes #[[ATTR9:[0-9]+]] = { nounwind memory(read) }818; TUNIT: attributes #[[ATTR10]] = { nosync }819; TUNIT: attributes #[[ATTR11]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }820; TUNIT: attributes #[[ATTR12]] = { nofree nosync nounwind willreturn memory(write) }821; TUNIT: attributes #[[ATTR13]] = { nosync memory(read) }822;.823; CGSCC: attributes #[[ATTR0]] = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable }824; CGSCC: attributes #[[ATTR1]] = { mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable }825; CGSCC: attributes #[[ATTR2]] = { nofree nosync nounwind memory(none) }826; CGSCC: attributes #[[ATTR3]] = { noinline nounwind uwtable }827; CGSCC: attributes #[[ATTR4]] = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(argmem: write) uwtable }828; CGSCC: attributes #[[ATTR5]] = { mustprogress nofree noinline nosync nounwind willreturn memory(argmem: write) uwtable }829; CGSCC: attributes #[[ATTR6]] = { mustprogress nofree noinline nosync nounwind willreturn memory(write) uwtable }830; CGSCC: attributes #[[ATTR7:[0-9]+]] = { memory(read) }831; CGSCC: attributes #[[ATTR8]] = { noinline nosync nounwind memory(read) uwtable }832; CGSCC: attributes #[[ATTR9]] = { nosync nounwind memory(read) }833; CGSCC: attributes #[[ATTR10:[0-9]+]] = { nounwind memory(read) }834; CGSCC: attributes #[[ATTR11]] = { nosync }835; CGSCC: attributes #[[ATTR12]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }836; CGSCC: attributes #[[ATTR13]] = { mustprogress nofree nosync nounwind willreturn memory(none) }837; CGSCC: attributes #[[ATTR14]] = { nofree nounwind willreturn memory(write) }838; CGSCC: attributes #[[ATTR15]] = { nosync memory(read) }839;.840