diff options
Diffstat (limited to 'llvm/test/Transforms/FunctionAttrs')
24 files changed, 115 insertions, 5236 deletions
diff --git a/llvm/test/Transforms/FunctionAttrs/align.ll b/llvm/test/Transforms/FunctionAttrs/align.ll deleted file mode 100644 index a5bf91915ba..00000000000 --- a/llvm/test/Transforms/FunctionAttrs/align.ll +++ /dev/null @@ -1,400 +0,0 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=5 -S < %s | FileCheck %s --check-prefix=ATTRIBUTOR - -target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" - -; Test cases specifically designed for "align" attribute. -; We use FIXME's to indicate problems and missing attributes. - - -; TEST 1 -; ATTRIBUTOR: define align 8 i32* @test1(i32* nofree readnone returned align 8 "no-capture-maybe-returned" %0) -define i32* @test1(i32* align 8 %0) #0 { - ret i32* %0 -} - -; TEST 2 -; ATTRIBUTOR: define i32* @test2(i32* nofree readnone returned "no-capture-maybe-returned" %0) -define i32* @test2(i32* %0) #0 { - ret i32* %0 -} - -; TEST 3 -; ATTRIBUTOR: define align 4 i32* @test3(i32* nofree readnone align 8 "no-capture-maybe-returned" %0, i32* nofree readnone align 4 "no-capture-maybe-returned" %1, i1 %2) -define i32* @test3(i32* align 8 %0, i32* align 4 %1, i1 %2) #0 { - %ret = select i1 %2, i32* %0, i32* %1 - ret i32* %ret -} - -; TEST 4 -; ATTRIBUTOR: define align 32 i32* @test4(i32* nofree readnone align 32 "no-capture-maybe-returned" %0, i32* nofree readnone align 32 "no-capture-maybe-returned" %1, i1 %2) -define i32* @test4(i32* align 32 %0, i32* align 32 %1, i1 %2) #0 { - %ret = select i1 %2, i32* %0, i32* %1 - ret i32* %ret -} - -; TEST 5 -declare i32* @unknown() -declare align 8 i32* @align8() - - -; ATTRIBUTOR: define align 8 i32* @test5_1() -define i32* @test5_1() { - %ret = tail call align 8 i32* @unknown() - ret i32* %ret -} - -; ATTRIBUTOR: define align 8 i32* @test5_2() -define i32* @test5_2() { - %ret = tail call i32* @align8() - ret i32* %ret -} - -; TEST 6 -; SCC -; ATTRIBUTOR: define noalias nonnull align 536870912 dereferenceable(4294967295) i32* @test6_1() -define i32* @test6_1() #0 { - %ret = tail call i32* @test6_2() - ret i32* %ret -} - -; ATTRIBUTOR: define noalias nonnull align 536870912 dereferenceable(4294967295) i32* @test6_2() -define i32* @test6_2() #0 { - %ret = tail call i32* @test6_1() - ret i32* %ret -} - - -; char a1 __attribute__((aligned(8))); -; char a2 __attribute__((aligned(16))); -; -; char* f1(char* a ){ -; return a?a:f2(&a1); -; } -; char* f2(char* a){ -; return a?f1(a):f3(&a2); -; } -; -; char* f3(char* a){ -; return a?&a1: f1(&a2); -; } - -@a1 = common global i8 0, align 8 -@a2 = common global i8 0, align 16 - -; Function Attrs: nounwind readnone ssp uwtable -define internal i8* @f1(i8* readnone %0) local_unnamed_addr #0 { - %2 = icmp eq i8* %0, null - br i1 %2, label %3, label %5 - -; <label>:3: ; preds = %1 - %4 = tail call i8* @f2(i8* nonnull @a1) - %l = load i8, i8* %4 - br label %5 - -; <label>:5: ; preds = %1, %3 - %6 = phi i8* [ %4, %3 ], [ %0, %1 ] - ret i8* %6 -} - -; Function Attrs: nounwind readnone ssp uwtable -define internal i8* @f2(i8* readnone %0) local_unnamed_addr #0 { - %2 = icmp eq i8* %0, null - br i1 %2, label %5, label %3 - -; <label>:3: ; preds = %1 - - %4 = tail call i8* @f1(i8* nonnull %0) - br label %7 - -; <label>:5: ; preds = %1 - %6 = tail call i8* @f3(i8* nonnull @a2) - br label %7 - -; <label>:7: ; preds = %5, %3 - %8 = phi i8* [ %4, %3 ], [ %6, %5 ] - ret i8* %8 -} - -; Function Attrs: nounwind readnone ssp uwtable -define internal i8* @f3(i8* readnone %0) local_unnamed_addr #0 { - %2 = icmp eq i8* %0, null - br i1 %2, label %3, label %5 - -; <label>:3: ; preds = %1 - %4 = tail call i8* @f1(i8* nonnull @a2) - br label %5 - -; <label>:5: ; preds = %1, %3 - %6 = phi i8* [ %4, %3 ], [ @a1, %1 ] - ret i8* %6 -} - -; TEST 7 -; Better than IR information -define align 4 i32* @test7(i32* align 32 %p) #0 { -; ATTRIBUTOR-LABEL: define {{[^@]+}}@test7 -; ATTRIBUTOR-SAME: (i32* nofree readnone returned align 32 "no-capture-maybe-returned" [[P:%.*]]) -; ATTRIBUTOR-NEXT: ret i32* [[P:%.*]] -; - tail call i8* @f1(i8* align 8 dereferenceable(1) @a1) - ret i32* %p -} - -; TEST 7b -; Function Attrs: nounwind readnone ssp uwtable -define internal i8* @f1b(i8* readnone %0) local_unnamed_addr #0 { -; -; ATTRIBUTOR-LABEL: define {{[^@]+}}@f1b -; ATTRIBUTOR-SAME: (i8* nofree nonnull readnone align 8 dereferenceable(1) "no-capture-maybe-returned" [[TMP0:%.*]]) local_unnamed_addr -; ATTRIBUTOR-NEXT: [[TMP2:%.*]] = icmp eq i8* [[TMP0:%.*]], null -; ATTRIBUTOR-NEXT: br i1 [[TMP2]], label [[TMP3:%.*]], label [[TMP5:%.*]] -; ATTRIBUTOR: 3: -; ATTRIBUTOR-NEXT: [[TMP4:%.*]] = tail call align 8 i8* @f2b(i8* nofree nonnull align 8 dereferenceable(1) @a1) -; ATTRIBUTOR-NEXT: [[L:%.*]] = load i8, i8* [[TMP4]], align 8 -; ATTRIBUTOR-NEXT: store i8 [[L]], i8* @a1, align 8 -; ATTRIBUTOR-NEXT: br label [[TMP5]] -; ATTRIBUTOR: 5: -; ATTRIBUTOR-NEXT: [[TMP6:%.*]] = phi i8* [ [[TMP4]], [[TMP3]] ], [ [[TMP0]], [[TMP1:%.*]] ] -; ATTRIBUTOR-NEXT: ret i8* [[TMP6]] -; - %2 = icmp eq i8* %0, null - br i1 %2, label %3, label %5 - -; <label>:3: ; preds = %1 - %4 = tail call i8* @f2b(i8* nonnull @a1) - %l = load i8, i8* %4 - store i8 %l, i8* @a1 - br label %5 - -; <label>:5: ; preds = %1, %3 - %6 = phi i8* [ %4, %3 ], [ %0, %1 ] - ret i8* %6 -} - -; Function Attrs: nounwind readnone ssp uwtable -define internal i8* @f2b(i8* readnone %0) local_unnamed_addr #0 { -; -; ATTRIBUTOR-LABEL: define {{[^@]+}}@f2b -; ATTRIBUTOR-SAME: (i8* nofree nonnull readnone align 8 dereferenceable(1) "no-capture-maybe-returned" [[TMP0:%.*]]) local_unnamed_addr -; ATTRIBUTOR-NEXT: [[TMP2:%.*]] = icmp eq i8* @a1, null -; ATTRIBUTOR-NEXT: br i1 [[TMP2]], label [[TMP5:%.*]], label [[TMP3:%.*]] -; ATTRIBUTOR: 3: -; ATTRIBUTOR-NEXT: [[TMP4:%.*]] = tail call i8* @f1b(i8* nofree nonnull align 8 dereferenceable(1) "no-capture-maybe-returned" @a1) -; ATTRIBUTOR-NEXT: br label [[TMP7:%.*]] -; ATTRIBUTOR: 5: -; ATTRIBUTOR-NEXT: [[TMP6:%.*]] = tail call i8* @f3b(i8* nofree nonnull align 16 dereferenceable(1) @a2) -; ATTRIBUTOR-NEXT: br label [[TMP7]] -; ATTRIBUTOR: 7: -; ATTRIBUTOR-NEXT: [[TMP8:%.*]] = phi i8* [ [[TMP4]], [[TMP3]] ], [ [[TMP6]], [[TMP5]] ] -; ATTRIBUTOR-NEXT: ret i8* [[TMP8]] -; - %2 = icmp eq i8* %0, null - br i1 %2, label %5, label %3 - -; <label>:3: ; preds = %1 - - %4 = tail call i8* @f1b(i8* nonnull %0) - br label %7 - -; <label>:5: ; preds = %1 - %6 = tail call i8* @f3b(i8* nonnull @a2) - br label %7 - -; <label>:7: ; preds = %5, %3 - %8 = phi i8* [ %4, %3 ], [ %6, %5 ] - ret i8* %8 -} - -; Function Attrs: nounwind readnone ssp uwtable -define internal i8* @f3b(i8* readnone %0) local_unnamed_addr #0 { -; -; ATTRIBUTOR-LABEL: define {{[^@]+}}@f3b -; ATTRIBUTOR-SAME: (i8* nocapture nofree nonnull readnone align 16 dereferenceable(1) [[TMP0:%.*]]) local_unnamed_addr -; ATTRIBUTOR-NEXT: [[TMP2:%.*]] = icmp eq i8* @a2, null -; ATTRIBUTOR-NEXT: br i1 [[TMP2]], label [[TMP3:%.*]], label [[TMP5:%.*]] -; ATTRIBUTOR: 3: -; ATTRIBUTOR-NEXT: [[TMP4:%.*]] = tail call i8* @f1b(i8* nofree nonnull align 16 dereferenceable(1) @a2) -; ATTRIBUTOR-NEXT: br label [[TMP5]] -; ATTRIBUTOR: 5: -; ATTRIBUTOR-NEXT: [[TMP6:%.*]] = phi i8* [ [[TMP4]], [[TMP3]] ], [ @a1, [[TMP1:%.*]] ] -; ATTRIBUTOR-NEXT: ret i8* [[TMP6]] -; - %2 = icmp eq i8* %0, null - br i1 %2, label %3, label %5 - -; <label>:3: ; preds = %1 - %4 = tail call i8* @f1b(i8* nonnull @a2) - br label %5 - -; <label>:5: ; preds = %1, %3 - %6 = phi i8* [ %4, %3 ], [ @a1, %1 ] - ret i8* %6 -} - -define align 4 i32* @test7b(i32* align 32 %p) #0 { -; ATTRIBUTOR-LABEL: define {{[^@]+}}@test7b -; ATTRIBUTOR-SAME: (i32* nofree readnone returned align 32 "no-capture-maybe-returned" [[P:%.*]]) -; ATTRIBUTOR-NEXT: [[TMP1:%.*]] = tail call i8* @f1b(i8* nofree nonnull align 8 dereferenceable(1) @a1) -; ATTRIBUTOR-NEXT: ret i32* [[P:%.*]] -; - tail call i8* @f1b(i8* align 8 dereferenceable(1) @a1) - ret i32* %p -} - - -; TEST 8 -define void @test8_helper() { - %ptr0 = tail call i32* @unknown() - %ptr1 = tail call align 4 i32* @unknown() - %ptr2 = tail call align 8 i32* @unknown() - - tail call void @test8(i32* %ptr1, i32* %ptr1, i32* %ptr0) -; ATTRIBUTOR: tail call void @test8(i32* align 4 %ptr1, i32* align 4 %ptr1, i32* %ptr0) - tail call void @test8(i32* %ptr2, i32* %ptr1, i32* %ptr1) -; ATTRIBUTOR: tail call void @test8(i32* align 8 %ptr2, i32* align 4 %ptr1, i32* align 4 %ptr1) - tail call void @test8(i32* %ptr2, i32* %ptr1, i32* %ptr1) -; ATTRIBUTOR: tail call void @test8(i32* align 8 %ptr2, i32* align 4 %ptr1, i32* align 4 %ptr1) - ret void -} - -declare void @user_i32_ptr(i32*) readnone nounwind -define internal void @test8(i32* %a, i32* %b, i32* %c) { -; ATTRIBUTOR: define internal void @test8(i32* nocapture readnone align 4 %a, i32* nocapture readnone align 4 %b, i32* nocapture readnone %c) - call void @user_i32_ptr(i32* %a) - call void @user_i32_ptr(i32* %b) - call void @user_i32_ptr(i32* %c) - ret void -} - -declare void @test9_helper(i32* %A) -define void @test9_traversal(i1 %c, i32* align 4 %B, i32* align 8 %C) { - %sel = select i1 %c, i32* %B, i32* %C - call void @test9_helper(i32* %sel) - ret void -} - -; FIXME: This will work with an upcoming patch (D66618 or similar) -; define align 32 i32* @test10a(i32* align 32 "no-capture-maybe-returned" %p) -; ATTRIBUTOR: define i32* @test10a(i32* nofree nonnull align 32 dereferenceable(4) "no-capture-maybe-returned" %p) -define i32* @test10a(i32* align 32 %p) { -; ATTRIBUTOR: %l = load i32, i32* %p, align 32 - %l = load i32, i32* %p - %c = icmp eq i32 %l, 0 - br i1 %c, label %t, label %f -t: - %r = call i32* @test10a(i32* %p) -; FIXME: This will work with an upcoming patch (D66618 or similar) -; store i32 1, i32* %r, align 32 -; ATTRIBUTOR: store i32 1, i32* %r - store i32 1, i32* %r - %g0 = getelementptr i32, i32* %p, i32 8 - br label %e -f: - %g1 = getelementptr i32, i32* %p, i32 8 -; FIXME: This will work with an upcoming patch (D66618 or similar) -; store i32 -1, i32* %g1, align 32 -; ATTRIBUTOR: store i32 -1, i32* %g1 - store i32 -1, i32* %g1 - br label %e -e: - %phi = phi i32* [%g0, %t], [%g1, %f] - ret i32* %phi -} - -; FIXME: This will work with an upcoming patch (D66618 or similar) -; define align 32 i32* @test10b(i32* align 32 "no-capture-maybe-returned" %p) -; ATTRIBUTOR: define i32* @test10b(i32* nofree nonnull align 32 dereferenceable(4) "no-capture-maybe-returned" %p) -define i32* @test10b(i32* align 32 %p) { -; ATTRIBUTOR: %l = load i32, i32* %p, align 32 - %l = load i32, i32* %p - %c = icmp eq i32 %l, 0 - br i1 %c, label %t, label %f -t: - %r = call i32* @test10b(i32* %p) -; FIXME: This will work with an upcoming patch (D66618 or similar) -; store i32 1, i32* %r, align 32 -; ATTRIBUTOR: store i32 1, i32* %r - store i32 1, i32* %r - %g0 = getelementptr i32, i32* %p, i32 8 - br label %e -f: - %g1 = getelementptr i32, i32* %p, i32 -8 -; FIXME: This will work with an upcoming patch (D66618 or similar) -; store i32 -1, i32* %g1, align 32 -; ATTRIBUTOR: store i32 -1, i32* %g1 - store i32 -1, i32* %g1 - br label %e -e: - %phi = phi i32* [%g0, %t], [%g1, %f] - ret i32* %phi -} - - -; ATTRIBUTOR: define i64 @test11(i32* nocapture nofree nonnull readonly align 8 dereferenceable(8) %p) -define i64 @test11(i32* %p) { - %p-cast = bitcast i32* %p to i64* - %ret = load i64, i64* %p-cast, align 8 - ret i64 %ret -} - -; TEST 12 -; Test for deduction using must-be-executed-context and GEP instruction - -; FXIME: %p should have nonnull -; ATTRIBUTOR: define i64 @test12-1(i32* nocapture nofree readonly align 16 %p) -define i64 @test12-1(i32* align 4 %p) { - %p-cast = bitcast i32* %p to i64* - %arrayidx0 = getelementptr i64, i64* %p-cast, i64 1 - %arrayidx1 = getelementptr i64, i64* %arrayidx0, i64 3 - %ret = load i64, i64* %arrayidx1, align 16 - ret i64 %ret -} - -; ATTRIBUTOR: define i64 @test12-2(i32* nocapture nofree nonnull readonly align 16 dereferenceable(8) %p) -define i64 @test12-2(i32* align 4 %p) { - %p-cast = bitcast i32* %p to i64* - %arrayidx0 = getelementptr i64, i64* %p-cast, i64 0 - %ret = load i64, i64* %arrayidx0, align 16 - ret i64 %ret -} - -; FXIME: %p should have nonnull -; ATTRIBUTOR: define void @test12-3(i32* nocapture nofree writeonly align 16 %p) -define void @test12-3(i32* align 4 %p) { - %p-cast = bitcast i32* %p to i64* - %arrayidx0 = getelementptr i64, i64* %p-cast, i64 1 - %arrayidx1 = getelementptr i64, i64* %arrayidx0, i64 3 - store i64 0, i64* %arrayidx1, align 16 - ret void -} - -; ATTRIBUTOR: define void @test12-4(i32* nocapture nofree nonnull writeonly align 16 dereferenceable(8) %p) -define void @test12-4(i32* align 4 %p) { - %p-cast = bitcast i32* %p to i64* - %arrayidx0 = getelementptr i64, i64* %p-cast, i64 0 - store i64 0, i64* %arrayidx0, align 16 - ret void -} - -declare void @use(i64*) willreturn nounwind - -; ATTRIBUTOR: define void @test12-5(i32* align 16 %p) -define void @test12-5(i32* align 4 %p) { - %p-cast = bitcast i32* %p to i64* - %arrayidx0 = getelementptr i64, i64* %p-cast, i64 1 - %arrayidx1 = getelementptr i64, i64* %arrayidx0, i64 3 - tail call void @use(i64* align 16 %arrayidx1) - ret void -} - -; ATTRIBUTOR: define void @test12-6(i32* align 16 %p) -define void @test12-6(i32* align 4 %p) { - %p-cast = bitcast i32* %p to i64* - %arrayidx0 = getelementptr i64, i64* %p-cast, i64 0 - tail call void @use(i64* align 16 %arrayidx0) - ret void -} - -attributes #0 = { nounwind uwtable noinline } -attributes #1 = { uwtable noinline } diff --git a/llvm/test/Transforms/FunctionAttrs/arg_nocapture.ll b/llvm/test/Transforms/FunctionAttrs/arg_nocapture.ll deleted file mode 100644 index 79075268ed4..00000000000 --- a/llvm/test/Transforms/FunctionAttrs/arg_nocapture.ll +++ /dev/null @@ -1,471 +0,0 @@ -; RUN: opt -functionattrs -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=6 -S < %s | FileCheck %s -; -; Test cases specifically designed for the "no-capture" argument attribute. -; We use FIXME's to indicate problems and missing attributes. -; -target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" - -; TEST comparison against NULL -; -; int is_null_return(int *p) { -; return p == 0; -; } -; -; FIXME: no-capture missing for %p -; CHECK: define i32 @is_null_return(i32* nofree readnone %p) -define i32 @is_null_return(i32* %p) #0 { -entry: - %cmp = icmp eq i32* %p, null - %conv = zext i1 %cmp to i32 - ret i32 %conv -} - -; TEST comparison against NULL in control flow -; -; int is_null_control(int *p) { -; if (p == 0) -; return 1; -; if (0 == p) -; return 1; -; return 0; -; } -; -; FIXME: no-capture missing for %p -; CHECK: define i32 @is_null_control(i32* nofree readnone %p) -define i32 @is_null_control(i32* %p) #0 { -entry: - %retval = alloca i32, align 4 - %cmp = icmp eq i32* %p, null - br i1 %cmp, label %if.then, label %if.end - -if.then: ; preds = %entry - store i32 1, i32* %retval, align 4 - br label %return - -if.end: ; preds = %entry - %cmp1 = icmp eq i32* null, %p - br i1 %cmp1, label %if.then2, label %if.end3 - -if.then2: ; preds = %if.end - store i32 1, i32* %retval, align 4 - br label %return - -if.end3: ; preds = %if.end - store i32 0, i32* %retval, align 4 - br label %return - -return: ; preds = %if.end3, %if.then2, %if.then - %0 = load i32, i32* %retval, align 4 - ret i32 %0 -} - -; TEST singleton SCC -; -; double *srec0(double *a) { -; srec0(a); -; return 0; -; } -; -; CHECK: define noalias nonnull align 536870912 dereferenceable(4294967295) double* @srec0(double* nocapture nofree readnone %a) -define double* @srec0(double* %a) #0 { -entry: - %call = call double* @srec0(double* %a) - ret double* null -} - -; TEST singleton SCC with lots of nested recursive calls -; -; int* srec16(int* a) { -; return srec16(srec16(srec16(srec16( -; srec16(srec16(srec16(srec16( -; srec16(srec16(srec16(srec16( -; srec16(srec16(srec16(srec16( -; a -; )))))))))))))))); -; } -; -; Other arguments are possible here due to the no-return behavior. -; -; CHECK: define noalias nonnull align 536870912 dereferenceable(4294967295) i32* @srec16(i32* nocapture nofree readnone %a) -define i32* @srec16(i32* %a) #0 { -entry: - %call = call i32* @srec16(i32* %a) -; CHECK-NOT: %call -; CHECK: unreachable - %call1 = call i32* @srec16(i32* %call) - %call2 = call i32* @srec16(i32* %call1) - %call3 = call i32* @srec16(i32* %call2) - %call4 = call i32* @srec16(i32* %call3) - %call5 = call i32* @srec16(i32* %call4) - %call6 = call i32* @srec16(i32* %call5) - %call7 = call i32* @srec16(i32* %call6) - %call8 = call i32* @srec16(i32* %call7) - %call9 = call i32* @srec16(i32* %call8) - %call10 = call i32* @srec16(i32* %call9) - %call11 = call i32* @srec16(i32* %call10) - %call12 = call i32* @srec16(i32* %call11) - %call13 = call i32* @srec16(i32* %call12) - %call14 = call i32* @srec16(i32* %call13) - %call15 = call i32* @srec16(i32* %call14) - ret i32* %call15 -} - -; TEST SCC with various calls, casts, and comparisons agains NULL -; -; CHECK: define dereferenceable_or_null(4) float* @scc_A(i32* nofree readnone returned dereferenceable_or_null(4) "no-capture-maybe-returned" %a) -; -; CHECK: define dereferenceable_or_null(8) i64* @scc_B(double* nofree readnone returned dereferenceable_or_null(8) "no-capture-maybe-returned" %a) -; -; CHECK: define dereferenceable_or_null(4) i8* @scc_C(i16* nofree readnone returned dereferenceable_or_null(4) "no-capture-maybe-returned" %a) -; -; float *scc_A(int *a) { -; return (float*)(a ? (int*)scc_A((int*)scc_B((double*)scc_C((short*)a))) : a); -; } -; -; long *scc_B(double *a) { -; return (long*)(a ? scc_C((short*)scc_B((double*)scc_A((int*)a))) : a); -; } -; -; void *scc_C(short *a) { -; return scc_A((int*)(scc_A(a) ? scc_B((double*)a) : scc_C(a))); -; } -define float* @scc_A(i32* dereferenceable_or_null(4) %a) { -entry: - %tobool = icmp ne i32* %a, null - br i1 %tobool, label %cond.true, label %cond.false - -cond.true: ; preds = %entry - %0 = bitcast i32* %a to i16* - %call = call i8* @scc_C(i16* %0) - %1 = bitcast i8* %call to double* - %call1 = call i64* @scc_B(double* %1) - %2 = bitcast i64* %call1 to i32* - %call2 = call float* @scc_A(i32* %2) - %3 = bitcast float* %call2 to i32* - br label %cond.end - -cond.false: ; preds = %entry - br label %cond.end - -cond.end: ; preds = %cond.false, %cond.true - %cond = phi i32* [ %3, %cond.true ], [ %a, %cond.false ] - %4 = bitcast i32* %cond to float* - ret float* %4 -} - -define i64* @scc_B(double* dereferenceable_or_null(8) %a) { -entry: - %tobool = icmp ne double* %a, null - br i1 %tobool, label %cond.true, label %cond.false - -cond.true: ; preds = %entry - %0 = bitcast double* %a to i32* - %call = call float* @scc_A(i32* %0) - %1 = bitcast float* %call to double* - %call1 = call i64* @scc_B(double* %1) - %2 = bitcast i64* %call1 to i16* - %call2 = call i8* @scc_C(i16* %2) - br label %cond.end - -cond.false: ; preds = %entry - %3 = bitcast double* %a to i8* - br label %cond.end - -cond.end: ; preds = %cond.false, %cond.true - %cond = phi i8* [ %call2, %cond.true ], [ %3, %cond.false ] - %4 = bitcast i8* %cond to i64* - ret i64* %4 -} - -define i8* @scc_C(i16* dereferenceable_or_null(2) %a) { -entry: - %bc = bitcast i16* %a to i32* - %call = call float* @scc_A(i32* %bc) - %bc2 = bitcast float* %call to i8* - %tobool = icmp ne i8* %bc2, null - br i1 %tobool, label %cond.true, label %cond.false - -cond.true: ; preds = %entry - %0 = bitcast i16* %a to double* - %call1 = call i64* @scc_B(double* %0) - %1 = bitcast i64* %call1 to i8* - br label %cond.end - -cond.false: ; preds = %entry - %call2 = call i8* @scc_C(i16* %a) - br label %cond.end - -cond.end: ; preds = %cond.false, %cond.true - %cond = phi i8* [ %1, %cond.true ], [ %call2, %cond.false ] - %2 = bitcast i8* %cond to i32* - %call3 = call float* @scc_A(i32* %2) - %3 = bitcast float* %call3 to i8* - ret i8* %3 -} - - -; TEST call to external function, marked no-capture -; -; void external_no_capture(int /* no-capture */ *p); -; void test_external_no_capture(int *p) { -; external_no_capture(p); -; } -; -; CHECK: define void @test_external_no_capture(i32* nocapture %p) -declare void @external_no_capture(i32* nocapture) - -define void @test_external_no_capture(i32* %p) #0 { -entry: - call void @external_no_capture(i32* %p) - ret void -} - -; TEST call to external var-args function, marked no-capture -; -; void test_var_arg_call(char *p, int a) { -; printf(p, a); -; } -; -; CHECK: define void @test_var_arg_call(i8* nocapture %p, i32 %a) -define void @test_var_arg_call(i8* %p, i32 %a) #0 { -entry: - %call = call i32 (i8*, ...) @printf(i8* %p, i32 %a) - ret void -} - -declare i32 @printf(i8* nocapture, ...) - - -; TEST "captured" only through return -; -; long *not_captured_but_returned_0(long *a) { -; *a1 = 0; -; return a; -; } -; -; There should *not* be a no-capture attribute on %a -; CHECK: define nonnull align 8 dereferenceable(8) i64* @not_captured_but_returned_0(i64* nofree nonnull returned writeonly align 8 dereferenceable(8) "no-capture-maybe-returned" %a) - -define i64* @not_captured_but_returned_0(i64* %a) #0 { -entry: - store i64 0, i64* %a, align 8 - ret i64* %a -} - -; TEST "captured" only through return -; -; long *not_captured_but_returned_1(long *a) { -; *(a+1) = 1; -; return a + 1; -; } -; -; There should *not* be a no-capture attribute on %a -; CHECK: define nonnull align 8 dereferenceable(8) i64* @not_captured_but_returned_1(i64* nofree nonnull writeonly align 8 dereferenceable(16) "no-capture-maybe-returned" %a) -define i64* @not_captured_but_returned_1(i64* %a) #0 { -entry: - %add.ptr = getelementptr inbounds i64, i64* %a, i64 1 - store i64 1, i64* %add.ptr, align 8 - ret i64* %add.ptr -} - -; TEST calls to "captured" only through return functions -; -; void test_not_captured_but_returned_calls(long *a) { -; not_captured_but_returned_0(a); -; not_captured_but_returned_1(a); -; } -; -; CHECK: define void @test_not_captured_but_returned_calls(i64* nocapture nofree writeonly %a) -define void @test_not_captured_but_returned_calls(i64* %a) #0 { -entry: - %call = call i64* @not_captured_but_returned_0(i64* %a) - %call1 = call i64* @not_captured_but_returned_1(i64* %a) - ret void -} - -; TEST "captured" only through transitive return -; -; long* negative_test_not_captured_but_returned_call_0a(long *a) { -; return not_captured_but_returned_0(a); -; } -; -; There should *not* be a no-capture attribute on %a -; CHECK: define i64* @negative_test_not_captured_but_returned_call_0a(i64* nofree returned writeonly "no-capture-maybe-returned" %a) -define i64* @negative_test_not_captured_but_returned_call_0a(i64* %a) #0 { -entry: - %call = call i64* @not_captured_but_returned_0(i64* %a) - ret i64* %call -} - -; TEST captured through write -; -; void negative_test_not_captured_but_returned_call_0b(long *a) { -; *a = (long)not_captured_but_returned_0(a); -; } -; -; There should *not* be a no-capture attribute on %a -; CHECK: define void @negative_test_not_captured_but_returned_call_0b(i64* nofree writeonly %a) -define void @negative_test_not_captured_but_returned_call_0b(i64* %a) #0 { -entry: - %call = call i64* @not_captured_but_returned_0(i64* %a) - %0 = ptrtoint i64* %call to i64 - store i64 %0, i64* %a, align 8 - ret void -} - -; TEST "captured" only through transitive return -; -; long* negative_test_not_captured_but_returned_call_1a(long *a) { -; return not_captured_but_returned_1(a); -; } -; -; There should *not* be a no-capture attribute on %a -; CHECK: define nonnull align 8 dereferenceable(8) i64* @negative_test_not_captured_but_returned_call_1a(i64* nofree writeonly "no-capture-maybe-returned" %a) -define i64* @negative_test_not_captured_but_returned_call_1a(i64* %a) #0 { -entry: - %call = call i64* @not_captured_but_returned_1(i64* %a) - ret i64* %call -} - -; TEST captured through write -; -; void negative_test_not_captured_but_returned_call_1b(long *a) { -; *a = (long)not_captured_but_returned_1(a); -; } -; -; There should *not* be a no-capture attribute on %a -; CHECK: define void @negative_test_not_captured_but_returned_call_1b(i64* nofree writeonly %a) -define void @negative_test_not_captured_but_returned_call_1b(i64* %a) #0 { -entry: - %call = call i64* @not_captured_but_returned_1(i64* %a) - %0 = ptrtoint i64* %call to i64 - store i64 %0, i64* %call, align 8 - ret void -} - -; TEST return argument or unknown call result -; -; int* ret_arg_or_unknown(int* b) { -; if (b == 0) -; return b; -; return unknown(); -; } -; -; Verify we do *not* assume b is returned or not captured. -; -; CHECK: define i32* @ret_arg_or_unknown(i32* readnone %b) -; CHECK: define i32* @ret_arg_or_unknown_through_phi(i32* readnone %b) - -declare i32* @unknown() - -define i32* @ret_arg_or_unknown(i32* %b) #0 { -entry: - %cmp = icmp eq i32* %b, null - br i1 %cmp, label %ret_arg, label %ret_unknown - -ret_arg: - ret i32* %b - -ret_unknown: - %call = call i32* @unknown() - ret i32* %call -} - -define i32* @ret_arg_or_unknown_through_phi(i32* %b) #0 { -entry: - %cmp = icmp eq i32* %b, null - br i1 %cmp, label %ret_arg, label %ret_unknown - -ret_arg: - br label %r - -ret_unknown: - %call = call i32* @unknown() - br label %r - -r: - %phi = phi i32* [ %b, %ret_arg ], [ %call, %ret_unknown ] - ret i32* %phi -} - - -; TEST not captured by readonly external function -; -; CHECK: define void @not_captured_by_readonly_call(i32* nocapture readonly %b) -declare i32* @readonly_unknown(i32*, i32*) readonly - -define void @not_captured_by_readonly_call(i32* %b) #0 { -entry: - %call = call i32* @readonly_unknown(i32* %b, i32* %b) - ret void -} - - -; TEST not captured by readonly external function if return chain is known -; -; Make sure the returned flag on %r is strong enough to justify nocapture on %b but **not** on %r. -; -; CHECK: define i32* @not_captured_by_readonly_call_not_returned_either1(i32* nocapture readonly %b, i32* readonly returned %r) -; -; CHECK: define i32* @not_captured_by_readonly_call_not_returned_either2(i32* nocapture readonly %b, i32* readonly returned %r) -; CHECK: define i32* @not_captured_by_readonly_call_not_returned_either3(i32* nocapture readonly %b, i32* readonly returned %r) -; -; CHECK: define i32* @not_captured_by_readonly_call_not_returned_either4(i32* nocapture readonly %b, i32* readonly returned %r) -define i32* @not_captured_by_readonly_call_not_returned_either1(i32* %b, i32* returned %r) { -entry: - %call = call i32* @readonly_unknown(i32* %b, i32* %r) nounwind - ret i32* %call -} - -declare i32* @readonly_unknown_r1a(i32*, i32* returned) readonly -define i32* @not_captured_by_readonly_call_not_returned_either2(i32* %b, i32* %r) { -entry: - %call = call i32* @readonly_unknown_r1a(i32* %b, i32* %r) nounwind - ret i32* %call -} - -declare i32* @readonly_unknown_r1b(i32*, i32* returned) readonly nounwind -define i32* @not_captured_by_readonly_call_not_returned_either3(i32* %b, i32* %r) { -entry: - %call = call i32* @readonly_unknown_r1b(i32* %b, i32* %r) - ret i32* %call -} - -define i32* @not_captured_by_readonly_call_not_returned_either4(i32* %b, i32* %r) nounwind { -entry: - %call = call i32* @readonly_unknown_r1a(i32* %b, i32* %r) - ret i32* %call -} - - -declare i32* @unknown_i32p(i32*) -define void @nocapture_is_not_subsumed_1(i32* nocapture %b) { -; CHECK-LABEL: define {{[^@]+}}@nocapture_is_not_subsumed_1 -; CHECK-SAME: (i32* nocapture [[B:%.*]]) -; CHECK-NEXT: entry: -; CHECK-NEXT: [[CALL:%.*]] = call i32* @unknown_i32p(i32* [[B:%.*]]) -; CHECK-NEXT: store i32 0, i32* [[CALL]] -; CHECK-NEXT: ret void -; -entry: - %call = call i32* @unknown_i32p(i32* %b) - store i32 0, i32* %call - ret void -} - -declare i32* @readonly_i32p(i32*) readonly -define void @nocapture_is_not_subsumed_2(i32* nocapture %b) { -; CHECK-LABEL: define {{[^@]+}}@nocapture_is_not_subsumed_2 -; CHECK-SAME: (i32* nocapture nofree [[B:%.*]]) -; CHECK-NEXT: entry: -; CHECK-NEXT: [[CALL:%.*]] = call i32* @readonly_i32p(i32* readonly [[B:%.*]]) -; CHECK-NEXT: store i32 0, i32* [[CALL]] -; CHECK-NEXT: ret void -; -entry: - %call = call i32* @readonly_i32p(i32* %b) - store i32 0, i32* %call - ret void -} - -attributes #0 = { noinline nounwind uwtable } diff --git a/llvm/test/Transforms/FunctionAttrs/arg_returned.ll b/llvm/test/Transforms/FunctionAttrs/arg_returned.ll index 5572c0124a0..0adf91cd9aa 100644 --- a/llvm/test/Transforms/FunctionAttrs/arg_returned.ll +++ b/llvm/test/Transforms/FunctionAttrs/arg_returned.ll @@ -1,6 +1,4 @@ ; RUN: opt -functionattrs -S < %s | FileCheck %s --check-prefix=FNATTR -; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=5 -S < %s | FileCheck %s --check-prefix=ATTRIBUTOR -; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -functionattrs -S < %s | FileCheck %s --check-prefix=BOTH ; ; Test cases specifically designed for the "returned" argument attribute. ; We use FIXME's to indicate problems and missing attributes. @@ -8,24 +6,12 @@ ; TEST SCC test returning an integer value argument ; -; BOTH: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable -; BOTH-NEXT: define i32 @sink_r0(i32 returned %r) -; BOTH: Function Attrs: nofree noinline nosync nounwind readnone uwtable -; BOTH-NEXT: define i32 @scc_r1(i32 %a, i32 returned %r, i32 %b) -; BOTH: Function Attrs: nofree noinline nosync nounwind readnone uwtable -; BOTH-NEXT: define i32 @scc_r2(i32 %a, i32 %b, i32 returned %r) -; BOTH: Function Attrs: nofree noinline nosync nounwind readnone uwtable -; BOTH-NEXT: define i32 @scc_rX(i32 %a, i32 %b, i32 %r) ; ; FNATTR: define i32 @sink_r0(i32 returned %r) ; FNATTR: define i32 @scc_r1(i32 %a, i32 %r, i32 %b) ; FNATTR: define i32 @scc_r2(i32 %a, i32 %b, i32 %r) ; FNATTR: define i32 @scc_rX(i32 %a, i32 %b, i32 %r) ; -; ATTRIBUTOR: define i32 @sink_r0(i32 returned %r) -; ATTRIBUTOR: define i32 @scc_r1(i32 %a, i32 returned %r, i32 %b) -; ATTRIBUTOR: define i32 @scc_r2(i32 %a, i32 %b, i32 returned %r) -; ATTRIBUTOR: define i32 @scc_rX(i32 %a, i32 %b, i32 %r) ; ; int scc_r1(int a, int b, int r); ; int scc_r2(int a, int b, int r); @@ -163,12 +149,6 @@ return: ; preds = %cond.end, %if.then3 ; FNATTR: define double* @ptr_scc_r1(double* %a, double* readnone %r, double* nocapture readnone %b) ; FNATTR: define double* @ptr_scc_r2(double* readnone %a, double* readnone %b, double* readnone %r) ; -; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable -; ATTRIBUTOR-NEXT: define double* @ptr_sink_r0(double* nofree readnone returned "no-capture-maybe-returned" %r) -; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable -; ATTRIBUTOR-NEXT: define double* @ptr_scc_r1(double* nofree readnone %a, double* nofree readnone returned %r, double* nocapture nofree readnone %b) -; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable -; ATTRIBUTOR-NEXT: define double* @ptr_scc_r2(double* nofree readnone %a, double* nofree readnone %b, double* nofree readnone returned %r) ; ; double* ptr_scc_r1(double* a, double* b, double* r); ; double* ptr_scc_r2(double* a, double* b, double* r); @@ -253,8 +233,6 @@ return: ; preds = %cond.end, %if.then3 ; } ; ; FNATTR: define i32* @rt0(i32* readonly %a) -; BOTH: Function Attrs: nofree noinline norecurse noreturn nosync nounwind readonly uwtable -; BOTH-NEXT: define noalias nonnull align 536870912 dereferenceable(4294967295) i32* @rt0(i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) %a) define i32* @rt0(i32* %a) #0 { entry: %v = load i32, i32* %a, align 4 @@ -271,8 +249,6 @@ entry: ; } ; ; FNATTR: define noalias i32* @rt1(i32* nocapture readonly %a) -; BOTH: Function Attrs: nofree noinline norecurse noreturn nosync nounwind readonly uwtable -; BOTH-NEXT: define noalias nonnull align 536870912 dereferenceable(4294967295) i32* @rt1(i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) %a) define i32* @rt1(i32* %a) #0 { entry: %v = load i32, i32* %a, align 4 @@ -286,8 +262,6 @@ entry: ; ; FNATTR: define i32* @rt2_helper(i32* %a) ; FNATTR: define i32* @rt2(i32* readnone %a, i32* readnone %b) -; BOTH: define i32* @rt2_helper(i32* nofree readnone returned %a) -; BOTH: define i32* @rt2(i32* nofree readnone %a, i32* nofree readnone "no-capture-maybe-returned" %b) define i32* @rt2_helper(i32* %a) #0 { entry: %call = call i32* @rt2(i32* %a, i32* %a) @@ -312,8 +286,6 @@ if.end: ; ; FNATTR: define i32* @rt3_helper(i32* %a, i32* %b) ; FNATTR: define i32* @rt3(i32* readnone %a, i32* readnone %b) -; BOTH: define i32* @rt3_helper(i32* nofree readnone %a, i32* nofree readnone returned "no-capture-maybe-returned" %b) -; BOTH: define i32* @rt3(i32* nofree readnone %a, i32* nofree readnone returned "no-capture-maybe-returned" %b) define i32* @rt3_helper(i32* %a, i32* %b) #0 { entry: %call = call i32* @rt3(i32* %a, i32* %b) @@ -343,12 +315,8 @@ if.end: ; return r; ; } ; -; BOTH: declare void @unknown_fn(i32* (i32*)*) ; -; BOTH: Function Attrs: noinline nounwind uwtable -; BOTH-NEXT: define i32* @calls_unknown_fn(i32* readnone returned "no-capture-maybe-returned" %r) ; FNATTR: define i32* @calls_unknown_fn(i32* readnone returned %r) -; ATTRIBUTOR: define i32* @calls_unknown_fn(i32* readnone returned "no-capture-maybe-returned" %r) declare void @unknown_fn(i32* (i32*)*) #0 define i32* @calls_unknown_fn(i32* %r) #0 { @@ -357,41 +325,6 @@ define i32* @calls_unknown_fn(i32* %r) #0 { } -; TEST call to a function that might be redifined at link time -; -; int *maybe_redefined_fn(int *r) { -; return r; -; } -; -; int *calls_maybe_redefined_fn(int *r) { -; maybe_redefined_fn(r); -; return r; -; } -; -; Verify the maybe-redefined function is not annotated: -; -; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable -; ATTRIBUTOR: define linkonce_odr i32* @maybe_redefined_fn(i32* %r) -; -; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable -; ATTRIBUTOR: define i32* @calls_maybe_redefined_fn(i32* returned %r) -; -; BOTH: Function Attrs: noinline nounwind uwtable -; BOTH-NEXT: define linkonce_odr i32* @maybe_redefined_fn(i32* %r) -; -; BOTH: Function Attrs: noinline nounwind uwtable -; BOTH-NEXT: define i32* @calls_maybe_redefined_fn(i32* returned %r) -define linkonce_odr i32* @maybe_redefined_fn(i32* %r) #0 { -entry: - ret i32* %r -} - -define i32* @calls_maybe_redefined_fn(i32* %r) #0 { -entry: - %call = call i32* @maybe_redefined_fn(i32* %r) - ret i32* %r -} - ; TEST return call to a function that might be redifined at link time ; ; int *maybe_redefined_fn2(int *r) { @@ -404,13 +337,8 @@ entry: ; ; Verify the maybe-redefined function is not annotated: ; -; BOTH: Function Attrs: noinline nounwind uwtable -; BOTH-NEXT: define linkonce_odr i32* @maybe_redefined_fn2(i32* %r) -; BOTH: Function Attrs: noinline nounwind uwtable -; BOTH-NEXT: define i32* @calls_maybe_redefined_fn2(i32* %r) ; ; FNATTR: define i32* @calls_maybe_redefined_fn2(i32* %r) -; ATTRIBUTOR: define i32* @calls_maybe_redefined_fn2(i32* %r) define linkonce_odr i32* @maybe_redefined_fn2(i32* %r) #0 { entry: ret i32* %r @@ -432,12 +360,8 @@ entry: ; return b == 0? b : x; ; } ; -; BOTH: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable -; BOTH-NEXT: define double @select_and_phi(double returned %b) ; ; FNATTR: define double @select_and_phi(double %b) -; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable -; ATTRIBUTOR-NEXT: define double @select_and_phi(double returned %b) define double @select_and_phi(double %b) #0 { entry: %cmp = fcmp ogt double %b, 0.000000e+00 @@ -463,13 +387,9 @@ if.end: ; preds = %if.then, %entry ; return b == 0? b : x; ; } ; -; BOTH: Function Attrs: nofree noinline nosync nounwind readnone uwtable -; BOTH-NEXT: define double @recursion_select_and_phi(i32 %a, double returned %b) ; ; FNATTR: define double @recursion_select_and_phi(i32 %a, double %b) ; -; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable -; ATTRIBUTOR-NEXT: define double @recursion_select_and_phi(i32 %a, double returned %b) define double @recursion_select_and_phi(i32 %a, double %b) #0 { entry: %dec = add nsw i32 %a, -1 @@ -494,13 +414,9 @@ if.end: ; preds = %if.then, %entry ; return (double*)b; ; } ; -; BOTH: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable -; BOTH-NEXT: define double* @bitcast(i32* nofree readnone returned "no-capture-maybe-returned" %b) ; ; FNATTR: define double* @bitcast(i32* readnone %b) ; -; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable -; ATTRIBUTOR-NEXT: define double* @bitcast(i32* nofree readnone returned "no-capture-maybe-returned" %b) define double* @bitcast(i32* %b) #0 { entry: %bc0 = bitcast i32* %b to double* @@ -517,13 +433,9 @@ entry: ; return b != 0 ? b : x; ; } ; -; BOTH: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable -; BOTH-NEXT: define double* @bitcasts_select_and_phi(i32* nofree readnone returned %b) ; ; FNATTR: define double* @bitcasts_select_and_phi(i32* readnone %b) ; -; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable -; ATTRIBUTOR-NEXT: define double* @bitcasts_select_and_phi(i32* nofree readnone returned %b) define double* @bitcasts_select_and_phi(i32* %b) #0 { entry: %bc0 = bitcast i32* %b to double* @@ -555,13 +467,9 @@ if.end: ; preds = %if.then, %entry ; /* return undef */ ; } ; -; BOTH: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable -; BOTH-NEXT: define double* @ret_arg_arg_undef(i32* nofree readnone returned %b) ; ; FNATTR: define double* @ret_arg_arg_undef(i32* readnone %b) ; -; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable -; ATTRIBUTOR-NEXT: define double* @ret_arg_arg_undef(i32* nofree readnone returned %b) define double* @ret_arg_arg_undef(i32* %b) #0 { entry: %bc0 = bitcast i32* %b to double* @@ -593,13 +501,9 @@ ret_undef: ; /* return undef */ ; } ; -; BOTH: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable -; BOTH-NEXT: define double* @ret_undef_arg_arg(i32* nofree readnone returned %b) ; ; FNATTR: define double* @ret_undef_arg_arg(i32* readnone %b) ; -; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable -; ATTRIBUTOR-NEXT: define double* @ret_undef_arg_arg(i32* nofree readnone returned %b) define double* @ret_undef_arg_arg(i32* %b) #0 { entry: %bc0 = bitcast i32* %b to double* @@ -631,11 +535,8 @@ ret_arg1: ; /* return undef */ ; } ; -; BOTH: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable -; BOTH-NEXT: define double* @ret_undef_arg_undef(i32* nofree readnone returned %b) ; ; FNATTR: define double* @ret_undef_arg_undef(i32* readnone %b) -; ATTRIBUTOR: define double* @ret_undef_arg_undef(i32* nofree readnone returned %b) define double* @ret_undef_arg_undef(i32* %b) #0 { entry: %bc0 = bitcast i32* %b to double* @@ -667,10 +568,6 @@ ret_undef1: ; ; FNATTR: define i32* @ret_arg_or_unknown(i32* %b) ; FNATTR: define i32* @ret_arg_or_unknown_through_phi(i32* %b) -; ATTRIBUTOR: define i32* @ret_arg_or_unknown(i32* %b) -; ATTRIBUTOR: define i32* @ret_arg_or_unknown_through_phi(i32* %b) -; BOTH: define i32* @ret_arg_or_unknown(i32* %b) -; BOTH: define i32* @ret_arg_or_unknown_through_phi(i32* %b) declare i32* @unknown(i32*) define i32* @ret_arg_or_unknown(i32* %b) #0 { @@ -709,14 +606,6 @@ r: ; FNATTR: define i32 @deadblockcall2(i32 %A) ; FNATTR: define i32 @deadblockphi1(i32 %A) ; FNATTR: define i32 @deadblockphi2(i32 %A) -; ATTRIBUTOR: define i32 @deadblockcall1(i32 returned %A) -; ATTRIBUTOR: define i32 @deadblockcall2(i32 returned %A) -; ATTRIBUTOR: define i32 @deadblockphi1(i32 returned %A) -; ATTRIBUTOR: define i32 @deadblockphi2(i32 returned %A) -; BOTH: define i32 @deadblockcall1(i32 returned %A) -; BOTH: define i32 @deadblockcall2(i32 returned %A) -; BOTH: define i32 @deadblockphi1(i32 returned %A) -; BOTH: define i32 @deadblockphi2(i32 returned %A) define i32 @deadblockcall1(i32 %A) #0 { entry: ret i32 %A @@ -789,51 +678,4 @@ r: ret i32 %PHI2 } -define weak_odr i32 @non_exact_0() { - ret i32 0 -} -define weak_odr i32 @non_exact_1(i32 %a) { - ret i32 %a -} -define weak_odr i32 @non_exact_2(i32 returned %a) { - ret i32 %a -} -define weak_odr i32* @non_exact_3(i32* align 32 returned %a) { - ret i32* %a -} -define i32 @exact(i32* %a) { - %c0 = call i32 @non_exact_0() - %c1 = call i32 @non_exact_1(i32 1) - %c2 = call i32 @non_exact_2(i32 2) - %c3 = call i32* @non_exact_3(i32* %a) -; We can use the information of the weak function non_exact_3 because it was -; given to us and not derived (the alignment of the returned argument). -; ATTRIBUTOR: %c4 = load i32, i32* %c3, align 32 - %c4 = load i32, i32* %c3 -; FIXME: %c2 and %c3 should be replaced but not %c0 or %c1! -; ATTRIBUTOR: %add1 = add i32 %c0, %c1 -; ATTRIBUTOR: %add2 = add i32 %add1, %c2 -; ATTRIBUTOR: %add3 = add i32 %add2, %c4 - %add1 = add i32 %c0, %c1 - %add2 = add i32 %add1, %c2 - %add3 = add i32 %add2, %c4 - ret i32 %add3 -} - -@G = external global i8 -define i32* @ret_const() #0 { - %bc = bitcast i8* @G to i32* - ret i32* %bc -} -define i32* @use_const() #0 { - %c = call i32* @ret_const() - ; ATTRIBUTOR: ret i32* bitcast (i8* @G to i32*) - ret i32* %c -} -define i32* @dont_use_const() #0 { - %c = musttail call i32* @ret_const() - ; ATTRIBUTOR: ret i32* %c - ret i32* %c -} - attributes #0 = { noinline nounwind uwtable } diff --git a/llvm/test/Transforms/FunctionAttrs/callbacks.ll b/llvm/test/Transforms/FunctionAttrs/callbacks.ll deleted file mode 100644 index f79d81c3969..00000000000 --- a/llvm/test/Transforms/FunctionAttrs/callbacks.ll +++ /dev/null @@ -1,65 +0,0 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; FIXME: Add -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations below. -; This flag was removed because max iterations is 2 in most cases, but in windows it is 1. -; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-annotate-decl-cs < %s | FileCheck %s -; ModuleID = 'callback_simple.c' -target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" - -; Test 0 -; -; Make sure we propagate information from the caller to the callback callee but -; only for arguments that are mapped through the callback metadata. Here, the -; first two arguments of the call and the callback callee do not correspond to -; each other but argument 3-5 of the transitive call site in the caller match -; arguments 2-4 of the callback callee. Here we should see information and value -; transfer in both directions. -; FIXME: The callee -> call site direction is not working yet. - -define void @t0_caller(i32* %a) { -; CHECK-LABEL: @t0_caller( -; CHECK-NEXT: entry: -; CHECK-NEXT: [[B:%.*]] = alloca i32, align 32 -; CHECK-NEXT: [[C:%.*]] = alloca i32*, align 64 -; CHECK-NEXT: [[PTR:%.*]] = alloca i32, align 128 -; CHECK-NEXT: [[TMP0:%.*]] = bitcast i32* [[B]] to i8* -; CHECK-NEXT: store i32 42, i32* [[B]], align 32 -; CHECK-NEXT: store i32* [[B]], i32** [[C]], align 64 -; CHECK-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t0_callback_broker(i32* noalias null, i32* nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* nonnull bitcast (void (i32*, i32*, i32*, i64, i32**)* @t0_callback_callee to void (i32*, i32*, ...)*), i32* [[A:%.*]], i64 99, i32** nonnull align 64 dereferenceable(8) [[C]]) -; CHECK-NEXT: ret void -; -entry: - %b = alloca i32, align 32 - %c = alloca i32*, align 64 - %ptr = alloca i32, align 128 - %0 = bitcast i32* %b to i8* - store i32 42, i32* %b, align 4 - store i32* %b, i32** %c, align 8 - call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t0_callback_broker(i32* null, i32* %ptr, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i32*, i64, i32**)* @t0_callback_callee to void (i32*, i32*, ...)*), i32* %a, i64 99, i32** %c) - ret void -} - -; Note that the first two arguments are provided by the callback_broker according to the callback in !1 below! -; The others are annotated with alignment information, amongst others, or even replaced by the constants passed to the call. -define internal void @t0_callback_callee(i32* %is_not_null, i32* %ptr, i32* %a, i64 %b, i32** %c) { -; CHECK-LABEL: @t0_callback_callee( -; CHECK-NEXT: entry: -; CHECK-NEXT: [[PTR_VAL:%.*]] = load i32, i32* [[PTR:%.*]], align 8 -; CHECK-NEXT: store i32 [[PTR_VAL]], i32* [[IS_NOT_NULL:%.*]] -; CHECK-NEXT: [[TMP0:%.*]] = load i32*, i32** [[C:%.*]], align 64 -; CHECK-NEXT: tail call void @t0_check(i32* align 256 [[A:%.*]], i64 99, i32* [[TMP0]]) -; CHECK-NEXT: ret void -; -entry: - %ptr_val = load i32, i32* %ptr, align 8 - store i32 %ptr_val, i32* %is_not_null - %0 = load i32*, i32** %c, align 8 - tail call void @t0_check(i32* %a, i64 %b, i32* %0) - ret void -} - -declare void @t0_check(i32* align 256, i64, i32*) - -declare !callback !0 void @t0_callback_broker(i32*, i32*, void (i32*, i32*, ...)*, ...) - -!0 = !{!1} -!1 = !{i64 2, i64 -1, i64 -1, i1 true} diff --git a/llvm/test/Transforms/FunctionAttrs/dereferenceable.ll b/llvm/test/Transforms/FunctionAttrs/dereferenceable.ll deleted file mode 100644 index 951b5047747..00000000000 --- a/llvm/test/Transforms/FunctionAttrs/dereferenceable.ll +++ /dev/null @@ -1,209 +0,0 @@ -; RUN: opt -attributor -attributor-manifest-internal --attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefix=ATTRIBUTOR - - -declare void @deref_phi_user(i32* %a); - -; TEST 1 -; take mininimum of return values -; -define i32* @test1(i32* dereferenceable(4) %0, double* dereferenceable(8) %1, i1 zeroext %2) local_unnamed_addr { -; ATTRIBUTOR: define nonnull dereferenceable(4) i32* @test1(i32* nofree nonnull readnone dereferenceable(4) "no-capture-maybe-returned" %0, double* nofree nonnull readnone dereferenceable(8) "no-capture-maybe-returned" %1, i1 zeroext %2) - %4 = bitcast double* %1 to i32* - %5 = select i1 %2, i32* %0, i32* %4 - ret i32* %5 -} - -; TEST 2 -define i32* @test2(i32* dereferenceable_or_null(4) %0, double* dereferenceable(8) %1, i1 zeroext %2) local_unnamed_addr { -; ATTRIBUTOR: define dereferenceable_or_null(4) i32* @test2(i32* nofree readnone dereferenceable_or_null(4) "no-capture-maybe-returned" %0, double* nofree nonnull readnone dereferenceable(8) "no-capture-maybe-returned" %1, i1 zeroext %2) - %4 = bitcast double* %1 to i32* - %5 = select i1 %2, i32* %0, i32* %4 - ret i32* %5 -} - -; TEST 3 -; GEP inbounds -define i32* @test3_1(i32* dereferenceable(8) %0) local_unnamed_addr { -; ATTRIBUTOR: define nonnull dereferenceable(4) i32* @test3_1(i32* nofree nonnull readnone dereferenceable(8) "no-capture-maybe-returned" %0) - %ret = getelementptr inbounds i32, i32* %0, i64 1 - ret i32* %ret -} - -define i32* @test3_2(i32* dereferenceable_or_null(32) %0) local_unnamed_addr { -; ATTRIBUTOR: define nonnull dereferenceable(16) i32* @test3_2(i32* nofree nonnull readnone dereferenceable(32) "no-capture-maybe-returned" %0) - %ret = getelementptr inbounds i32, i32* %0, i64 4 - ret i32* %ret -} - -define i32* @test3_3(i32* dereferenceable(8) %0, i32* dereferenceable(16) %1, i1 %2) local_unnamed_addr { -; ATTRIBUTOR: define nonnull dereferenceable(4) i32* @test3_3(i32* nofree nonnull readnone dereferenceable(8) "no-capture-maybe-returned" %0, i32* nofree nonnull readnone dereferenceable(16) "no-capture-maybe-returned" %1, i1 %2) local_unnamed_addr - %ret1 = getelementptr inbounds i32, i32* %0, i64 1 - %ret2 = getelementptr inbounds i32, i32* %1, i64 2 - %ret = select i1 %2, i32* %ret1, i32* %ret2 - ret i32* %ret -} - -; TEST 4 -; Better than known in IR. - -define dereferenceable(4) i32* @test4(i32* dereferenceable(8) %0) local_unnamed_addr { -; ATTRIBUTOR: define nonnull dereferenceable(8) i32* @test4(i32* nofree nonnull readnone returned dereferenceable(8) "no-capture-maybe-returned" %0) - ret i32* %0 -} - -; TEST 5 -; loop in which dereferenceabily "grows" -define void @deref_phi_growing(i32* dereferenceable(4000) %a) { -entry: - br label %for.cond - -for.cond: ; preds = %for.inc, %entry - %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ] - %a.addr.0 = phi i32* [ %a, %entry ], [ %incdec.ptr, %for.inc ] -; ATTRIBUTOR: call void @deref_phi_user(i32* nonnull dereferenceable(4000) %a.addr.0) - call void @deref_phi_user(i32* %a.addr.0) - %tmp = load i32, i32* %a.addr.0, align 4 - %cmp = icmp slt i32 %i.0, %tmp - br i1 %cmp, label %for.body, label %for.cond.cleanup - -for.cond.cleanup: ; preds = %for.cond - br label %for.end - -for.body: ; preds = %for.cond - br label %for.inc - -for.inc: ; preds = %for.body - %incdec.ptr = getelementptr inbounds i32, i32* %a.addr.0, i64 -1 - %inc = add nuw nsw i32 %i.0, 1 - br label %for.cond - -for.end: ; preds = %for.cond.cleanup - ret void -} - -; TEST 6 -; loop in which dereferenceabily "shrinks" -define void @deref_phi_shrinking(i32* dereferenceable(4000) %a) { -entry: - br label %for.cond - -for.cond: ; preds = %for.inc, %entry - %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ] - %a.addr.0 = phi i32* [ %a, %entry ], [ %incdec.ptr, %for.inc ] -; ATTRIBUTOR: call void @deref_phi_user(i32* nonnull %a.addr.0) - call void @deref_phi_user(i32* %a.addr.0) - %tmp = load i32, i32* %a.addr.0, align 4 - %cmp = icmp slt i32 %i.0, %tmp - br i1 %cmp, label %for.body, label %for.cond.cleanup - -for.cond.cleanup: ; preds = %for.cond - br label %for.end - -for.body: ; preds = %for.cond - br label %for.inc - -for.inc: ; preds = %for.body - %incdec.ptr = getelementptr inbounds i32, i32* %a.addr.0, i64 1 - %inc = add nuw nsw i32 %i.0, 1 - br label %for.cond - -for.end: ; preds = %for.cond.cleanup - ret void -} - -; TEST 7 -; share known infomation in must-be-executed-context -declare i32* @unkown_ptr() willreturn nounwind -declare i32 @unkown_f(i32*) willreturn nounwind -define i32* @f7_0(i32* %ptr) { -; ATTRIBUTOR: define nonnull dereferenceable(8) i32* @f7_0(i32* nonnull returned dereferenceable(8) %ptr) - %T = tail call i32 @unkown_f(i32* dereferenceable(8) %ptr) - ret i32* %ptr -} - -; ATTRIBUTOR: define void @f7_1(i32* nonnull dereferenceable(4) %ptr, i1 %c) -define void @f7_1(i32* %ptr, i1 %c) { - -; ATTRIBUTOR: %A = tail call i32 @unkown_f(i32* nonnull dereferenceable(4) %ptr) - %A = tail call i32 @unkown_f(i32* %ptr) - - %ptr.0 = load i32, i32* %ptr - ; deref 4 hold - -; FIXME: this should be %B = tail call i32 @unkown_f(i32* nonnull dereferenceable(4) %ptr) -; ATTRIBUTOR: %B = tail call i32 @unkown_f(i32* nonnull dereferenceable(4) %ptr) - %B = tail call i32 @unkown_f(i32* dereferenceable(1) %ptr) - - br i1%c, label %if.true, label %if.false -if.true: -; ATTRIBUTOR: %C = tail call i32 @unkown_f(i32* nonnull dereferenceable(8) %ptr) - %C = tail call i32 @unkown_f(i32* %ptr) - -; ATTRIBUTOR: %D = tail call i32 @unkown_f(i32* nonnull dereferenceable(8) %ptr) - %D = tail call i32 @unkown_f(i32* dereferenceable(8) %ptr) - -; FIXME: This should be tail call i32 @unkown_f(i32* nonnull dereferenceable(8) %ptr) -; Making must-be-executed-context backward exploration will fix this. -; ATTRIBUTOR: %E = tail call i32 @unkown_f(i32* nonnull dereferenceable(4) %ptr) - %E = tail call i32 @unkown_f(i32* %ptr) - - ret void - -if.false: - ret void -} - -; ATTRIBUTOR: define void @f7_2(i1 %c) -define void @f7_2(i1 %c) { - - %ptr = tail call i32* @unkown_ptr() - -; ATTRIBUTOR: %A = tail call i32 @unkown_f(i32* nonnull dereferenceable(4) %ptr) - %A = tail call i32 @unkown_f(i32* %ptr) - - %arg_a.0 = load i32, i32* %ptr - ; deref 4 hold - -; ATTRIBUTOR: %B = tail call i32 @unkown_f(i32* nonnull dereferenceable(4) %ptr) - %B = tail call i32 @unkown_f(i32* dereferenceable(1) %ptr) - - br i1%c, label %if.true, label %if.false -if.true: - -; ATTRIBUTOR: %C = tail call i32 @unkown_f(i32* nonnull dereferenceable(8) %ptr) - %C = tail call i32 @unkown_f(i32* %ptr) - -; ATTRIBUTOR: %D = tail call i32 @unkown_f(i32* nonnull dereferenceable(8) %ptr) - %D = tail call i32 @unkown_f(i32* dereferenceable(8) %ptr) - - %E = tail call i32 @unkown_f(i32* %ptr) -; FIXME: This should be @unkown_f(i32* nonnull dereferenceable(8) %ptr) -; Making must-be-executed-context backward exploration will fix this. -; ATTRIBUTOR: %E = tail call i32 @unkown_f(i32* nonnull dereferenceable(4) %ptr) - - ret void - -if.false: - ret void -} - -define i32* @f7_3() { -; ATTRIBUTOR: define nonnull align 16 dereferenceable(4) i32* @f7_3() - %ptr = tail call i32* @unkown_ptr() - store i32 10, i32* %ptr, align 16 - ret i32* %ptr -} - -define i32* @test_for_minus_index(i32* %p) { -; FIXME: This should have a return dereferenceable(8) but we need to make sure it will work in loops as well. -; ATTRIBUTOR: define nonnull i32* @test_for_minus_index(i32* nofree nonnull writeonly "no-capture-maybe-returned" %p) - %q = getelementptr inbounds i32, i32* %p, i32 -2 - store i32 1, i32* %q - ret i32* %q -} - -define void @deref_or_null_and_nonnull(i32* dereferenceable_or_null(100) %0) { -; ATTRIBUTOR: define void @deref_or_null_and_nonnull(i32* nocapture nofree nonnull writeonly dereferenceable(100) %0) - store i32 1, i32* %0 - ret void -} diff --git a/llvm/test/Transforms/FunctionAttrs/fn_noreturn.ll b/llvm/test/Transforms/FunctionAttrs/fn_noreturn.ll deleted file mode 100644 index 2b15e0780df..00000000000 --- a/llvm/test/Transforms/FunctionAttrs/fn_noreturn.ll +++ /dev/null @@ -1,149 +0,0 @@ -; RUN: opt -functionattrs -attributor -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s -; -; Test cases specifically designed for the "no-return" function attribute. -; We use FIXME's to indicate problems and missing attributes. - -target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" - - -; TEST 1, singleton SCC void return type -; -; void srec0() { -; return srec0(); -; } -; -; CHECK: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable -; CHECK: define void @srec0() -; -define void @srec0() #0 { -entry: - call void @srec0() - ret void -} - - -; TEST 2: singleton SCC int return type with a lot of recursive calls -; -; int srec16(int a) { -; return srec16(srec16(srec16(srec16(srec16(srec16(srec16(srec16(srec16(srec16(srec16(srec16(srec16(srec16(srec16(srec16(a)))))))))))))))); -; } -; -; CHECK: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable -; CHECK: define i32 @srec16(i32 %a) -; -define i32 @srec16(i32 %a) #0 { -entry: - %call = call i32 @srec16(i32 %a) - %call1 = call i32 @srec16(i32 %call) - %call2 = call i32 @srec16(i32 %call1) - %call3 = call i32 @srec16(i32 %call2) - %call4 = call i32 @srec16(i32 %call3) - %call5 = call i32 @srec16(i32 %call4) - %call6 = call i32 @srec16(i32 %call5) - %call7 = call i32 @srec16(i32 %call6) - %call8 = call i32 @srec16(i32 %call7) - %call9 = call i32 @srec16(i32 %call8) - %call10 = call i32 @srec16(i32 %call9) - %call11 = call i32 @srec16(i32 %call10) - %call12 = call i32 @srec16(i32 %call11) - %call13 = call i32 @srec16(i32 %call12) - %call14 = call i32 @srec16(i32 %call13) - %call15 = call i32 @srec16(i32 %call14) - br label %exit - -exit: - ret i32 %call15 -} - - -; TEST 3: endless loop, no return instruction -; -; int endless_loop(int a) { -; while (1); -; } -; -; CHECK: Function Attrs: nofree noinline norecurse noreturn nosync nounwind readnone uwtable -; CHECK: define i32 @endless_loop(i32 %a) -; -define i32 @endless_loop(i32 %a) #0 { -entry: - br label %while.body - -while.body: ; preds = %entry, %while.body - br label %while.body -} - - -; TEST 4: endless loop, dead return instruction -; -; int endless_loop(int a) { -; while (1); -; return a; -; } -; -; FIXME: no-return missing (D65243 should fix this) -; CHECK: Function Attrs: nofree noinline norecurse noreturn nosync nounwind readnone uwtable -; CHECK: define i32 @dead_return(i32 returned %a) -; -define i32 @dead_return(i32 %a) #0 { -entry: - br label %while.body - -while.body: ; preds = %entry, %while.body - br label %while.body - -return: ; No predecessors! - ret i32 %a -} - - -; TEST 5: all paths contain a no-return function call -; -; int multiple_noreturn_calls(int a) { -; return a == 0 ? endless_loop(a) : srec16(a); -; } -; -; CHECK: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable -; CHECK: define i32 @multiple_noreturn_calls(i32 %a) -; -define i32 @multiple_noreturn_calls(i32 %a) #0 { -entry: - %cmp = icmp eq i32 %a, 0 - br i1 %cmp, label %cond.true, label %cond.false - -cond.true: ; preds = %entry - %call = call i32 @endless_loop(i32 %a) - br label %cond.end - -cond.false: ; preds = %entry - %call1 = call i32 @srec16(i32 %a) - br label %cond.end - -cond.end: ; preds = %cond.false, %cond.true - %cond = phi i32 [ %call, %cond.true ], [ %call1, %cond.false ] - ret i32 %cond -} - - -; TEST 6a: willreturn means *not* no-return or UB -; FIXME: we should derive "UB" as an argument and report it to the user on request. - -; CHECK: Function Attrs: nofree norecurse noreturn nosync nounwind readnone willreturn -; CHECK-NEXT: define i32 @endless_loop_but_willreturn -define i32 @endless_loop_but_willreturn() willreturn { -entry: - br label %while.body - -while.body: ; preds = %entry, %while.body - br label %while.body -} - -; TEST 6b: willreturn means *not* no-return or UB -; CHECK: Function Attrs: nofree norecurse noreturn nosync nounwind readnone willreturn -; CHECK-NEXT: define i32 @UB_and_willreturn -define i32 @UB_and_willreturn() willreturn { -entry: - unreachable -} - -attributes #0 = { noinline nounwind uwtable } diff --git a/llvm/test/Transforms/FunctionAttrs/heap_to_stack.ll b/llvm/test/Transforms/FunctionAttrs/heap_to_stack.ll deleted file mode 100644 index 1f7be75ef16..00000000000 --- a/llvm/test/Transforms/FunctionAttrs/heap_to_stack.ll +++ /dev/null @@ -1,376 +0,0 @@ -; RUN: opt -passes=attributor --attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s - -declare noalias i8* @malloc(i64) - -declare void @nocapture_func_frees_pointer(i8* nocapture) - -declare void @func_throws(...) - -declare void @sync_func(i8* %p) - -declare void @sync_will_return(i8* %p) willreturn nounwind - -declare void @no_sync_func(i8* nocapture %p) nofree nosync willreturn - -declare void @nofree_func(i8* nocapture %p) nofree nosync willreturn - -declare void @foo(i32* %p) - -declare void @foo_nounw(i32* %p) nounwind nofree - -declare i32 @no_return_call() noreturn - -declare void @free(i8* nocapture) - -declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) nounwind - -; CHECK: @nofree_arg_only(i8* nocapture nofree %p1, i8* nocapture %p2) -define void @nofree_arg_only(i8* %p1, i8* %p2) { - tail call void @free(i8* %p2) - tail call void @nofree_func(i8* %p1) - ret void -} - -; TEST 1 - negative, pointer freed in another function. - -define void @test1() { - %1 = tail call noalias i8* @malloc(i64 4) - ; CHECK: @malloc(i64 4) - ; CHECK-NEXT: @nocapture_func_frees_pointer(i8* noalias nocapture %1) - tail call void @nocapture_func_frees_pointer(i8* %1) - tail call void (...) @func_throws() - tail call void @free(i8* %1) - ret void -} - -; TEST 2 - negative, call to a sync function. - -define void @test2() { - %1 = tail call noalias i8* @malloc(i64 4) - ; CHECK: @malloc(i64 4) - ; CHECK-NEXT: @sync_func(i8* %1) - tail call void @sync_func(i8* %1) - tail call void @free(i8* %1) - ret void -} - -; TEST 3 - 1 malloc, 1 free - -define void @test3() { - %1 = tail call noalias i8* @malloc(i64 4) - ; CHECK: %1 = alloca i8, i64 4 - ; CHECK-NEXT: @no_sync_func(i8* noalias nocapture nofree %1) - tail call void @no_sync_func(i8* %1) - ; CHECK-NOT: @free(i8* %1) - tail call void @free(i8* %1) - ret void -} - -define void @test3a(i8* %p) { - %1 = tail call noalias i8* @malloc(i64 4) - ; CHECK: %1 = alloca i8, i64 4 - ; CHECK-NEXT: tail call void @nofree_arg_only - tail call void @nofree_arg_only(i8* %1, i8* %p) - ; CHECK-NOT: @free(i8* %1) - tail call void @free(i8* %1) - ret void -} - -declare noalias i8* @calloc(i64, i64) - -define void @test0() { - %1 = tail call noalias i8* @calloc(i64 2, i64 4) - ; CHECK: %1 = alloca i8, i64 8 - ; CHECK-NEXT: %calloc_bc = bitcast i8* %1 to i8* - ; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* %calloc_bc, i8 0, i64 8, i1 false) - ; CHECK-NEXT: @no_sync_func(i8* noalias nocapture nofree %1) - tail call void @no_sync_func(i8* %1) - ; CHECK-NOT: @free(i8* %1) - tail call void @free(i8* %1) - ret void -} - -; TEST 4 -define void @test4() { - %1 = tail call noalias i8* @malloc(i64 4) - ; CHECK: %1 = alloca i8, i64 4 - ; CHECK-NEXT: @nofree_func(i8* noalias nocapture nofree %1) - tail call void @nofree_func(i8* %1) - ret void -} - -; TEST 5 - not all exit paths have a call to free, but all uses of malloc -; are in nofree functions and are not captured - -define void @test5(i32, i8* %p) { - %2 = tail call noalias i8* @malloc(i64 4) - ; CHECK: %2 = alloca i8, i64 4 - ; CHECK-NEXT: icmp eq i32 %0, 0 - %3 = icmp eq i32 %0, 0 - br i1 %3, label %5, label %4 - -4: ; preds = %1 - tail call void @nofree_func(i8* %2) - br label %6 - -5: ; preds = %1 - tail call void @nofree_arg_only(i8* %2, i8* %p) - tail call void @free(i8* %2) - ; CHECK-NOT: @free(i8* %2) - br label %6 - -6: ; preds = %5, %4 - ret void -} - -; TEST 6 - all exit paths have a call to free - -define void @test6(i32) { - %2 = tail call noalias i8* @malloc(i64 4) - ; CHECK: %2 = alloca i8, i64 4 - ; CHECK-NEXT: icmp eq i32 %0, 0 - %3 = icmp eq i32 %0, 0 - br i1 %3, label %5, label %4 - -4: ; preds = %1 - tail call void @nofree_func(i8* %2) - tail call void @free(i8* %2) - ; CHECK-NOT: @free(i8* %2) - br label %6 - -5: ; preds = %1 - tail call void @free(i8* %2) - ; CHECK-NOT: @free(i8* %2) - br label %6 - -6: ; preds = %5, %4 - ret void -} - -; TEST 7 - free is dead. - -define void @test7() { - %1 = tail call noalias i8* @malloc(i64 4) - ; CHECK: alloca i8, i64 4 - ; CHECK-NEXT: tail call i32 @no_return_call() - tail call i32 @no_return_call() - ; CHECK-NOT: @free(i8* %1) - tail call void @free(i8* %1) - ret void -} - -; TEST 8 - Negative: bitcast pointer used in capture function - -define void @test8() { - %1 = tail call noalias i8* @malloc(i64 4) - ; CHECK: %1 = tail call noalias i8* @malloc(i64 4) - ; CHECK-NEXT: @no_sync_func(i8* nocapture nofree %1) - tail call void @no_sync_func(i8* %1) - %2 = bitcast i8* %1 to i32* - store i32 10, i32* %2 - %3 = load i32, i32* %2 - tail call void @foo(i32* %2) - ; CHECK: @free(i8* %1) - tail call void @free(i8* %1) - ret void -} - -; TEST 9 - FIXME: malloc should be converted. -define void @test9() { - %1 = tail call noalias i8* @malloc(i64 4) - ; CHECK: %1 = tail call noalias i8* @malloc(i64 4) - ; CHECK-NEXT: @no_sync_func(i8* nocapture nofree %1) - tail call void @no_sync_func(i8* %1) - %2 = bitcast i8* %1 to i32* - store i32 10, i32* %2 - %3 = load i32, i32* %2 - tail call void @foo_nounw(i32* %2) - ; CHECK: @free(i8* %1) - tail call void @free(i8* %1) - ret void -} - -; TEST 10 - 1 malloc, 1 free - -define i32 @test10() { - %1 = tail call noalias i8* @malloc(i64 4) - ; CHECK: %1 = alloca i8, i64 4 - ; CHECK-NEXT: @no_sync_func(i8* noalias nocapture nofree %1) - tail call void @no_sync_func(i8* %1) - %2 = bitcast i8* %1 to i32* - store i32 10, i32* %2 - %3 = load i32, i32* %2 - ; CHECK-NOT: @free(i8* %1) - tail call void @free(i8* %1) - ret i32 %3 -} - -define i32 @test_lifetime() { - %1 = tail call noalias i8* @malloc(i64 4) - ; CHECK: %1 = alloca i8, i64 4 - ; CHECK-NEXT: @no_sync_func(i8* noalias nocapture nofree %1) - tail call void @no_sync_func(i8* %1) - call void @llvm.lifetime.start.p0i8(i64 4, i8* %1) - %2 = bitcast i8* %1 to i32* - store i32 10, i32* %2 - %3 = load i32, i32* %2 - ; CHECK-NOT: @free(i8* %1) - tail call void @free(i8* %1) - ret i32 %3 -} - -; TEST 11 - -define void @test11() { - %1 = tail call noalias i8* @malloc(i64 4) - ; CHECK: test11 - ; CHECK-NEXT: alloc - ; CHECK-NEXT: @sync_will_return(i8* %1) - tail call void @sync_will_return(i8* %1) - tail call void @free(i8* %1) - ret void -} - -; TEST 12 -define i32 @irreducible_cfg(i32 %0) { - ; CHECK: alloca i8, i64 4 - ; CHECK-NEXT: %3 = bitcast - %2 = call noalias i8* @malloc(i64 4) - %3 = bitcast i8* %2 to i32* - store i32 10, i32* %3, align 4 - %4 = icmp eq i32 %0, 1 - br i1 %4, label %5, label %7 - -5: ; preds = %1 - %6 = add nsw i32 %0, 5 - br label %13 - -7: ; preds = %1 - br label %8 - -8: ; preds = %13, %7 - %.0 = phi i32 [ %14, %13 ], [ 1, %7 ] - %9 = load i32, i32* %3, align 4 - %10 = add nsw i32 %9, -1 - store i32 %10, i32* %3, align 4 - %11 = icmp ne i32 %9, 0 - br i1 %11, label %12, label %15 - -12: ; preds = %8 - br label %13 - -13: ; preds = %12, %5 - %.1 = phi i32 [ %6, %5 ], [ %.0, %12 ] - %14 = add nsw i32 %.1, 1 - br label %8 - -15: ; preds = %8 - %16 = load i32, i32* %3, align 4 - %17 = bitcast i32* %3 to i8* - call void @free(i8* %17) - %18 = load i32, i32* %3, align 4 - ret i32 %18 -} - - -define i32 @malloc_in_loop(i32 %0) { - %2 = alloca i32, align 4 - %3 = alloca i32*, align 8 - store i32 %0, i32* %2, align 4 - br label %4 - -4: ; preds = %8, %1 - %5 = load i32, i32* %2, align 4 - %6 = add nsw i32 %5, -1 - store i32 %6, i32* %2, align 4 - %7 = icmp sgt i32 %6, 0 - br i1 %7, label %8, label %11 - -8: ; preds = %4 - %9 = call noalias i8* @malloc(i64 4) - ; CHECK: alloca i8, i64 4 - %10 = bitcast i8* %9 to i32* - store i32 1, i32* %10, align 8 - br label %4 - -11: ; preds = %4 - ret i32 5 -} - -; Malloc/Calloc too large -define i32 @test13() { - %1 = tail call noalias i8* @malloc(i64 256) - ; CHECK: %1 = tail call noalias i8* @malloc(i64 256) - ; CHECK-NEXT: @no_sync_func(i8* noalias nofree %1) - tail call void @no_sync_func(i8* %1) - %2 = bitcast i8* %1 to i32* - store i32 10, i32* %2 - %3 = load i32, i32* %2 - tail call void @free(i8* %1) - ; CHECK: tail call void @free(i8* noalias %1) - ret i32 %3 -} - -define void @test14() { - %1 = tail call noalias i8* @calloc(i64 64, i64 4) - ; CHECK: %1 = tail call noalias i8* @calloc(i64 64, i64 4) - ; CHECK-NEXT: @no_sync_func(i8* noalias nofree %1) - tail call void @no_sync_func(i8* %1) - tail call void @free(i8* %1) - ; CHECK: tail call void @free(i8* noalias %1) - ret void -} - -define void @test15(i64 %S) { - ; CHECK: %1 = tail call noalias i8* @malloc(i64 %S) - %1 = tail call noalias i8* @malloc(i64 %S) - ; CHECK-NEXT: @no_sync_func(i8* noalias nofree %1) - tail call void @no_sync_func(i8* %1) - ; CHECK-NEXT: @free(i8* noalias %1) - tail call void @free(i8* %1) - ret void -} - -define void @test16a(i8 %v, i8** %P) { - ; CHECK: %1 = alloca - %1 = tail call noalias i8* @malloc(i64 4) - ; CHECK-NEXT: store i8 %v, i8* %1 - store i8 %v, i8* %1 - ; CHECK-NEXT: @no_sync_func(i8* noalias nocapture nofree %1) - tail call void @no_sync_func(i8* %1) - ; CHECK-NOT: @free(i8* %1) - tail call void @free(i8* %1) - ret void -} - -define void @test16b(i8 %v, i8** %P) { - ; CHECK: %1 = tail call noalias i8* @malloc(i64 4) - %1 = tail call noalias i8* @malloc(i64 4) - ; CHECK-NEXT: store i8* %1, i8** %P - store i8* %1, i8** %P - ; CHECK-NEXT: @no_sync_func(i8* nocapture nofree %1) - tail call void @no_sync_func(i8* %1) - ; CHECK-NEXT: @free(i8* %1) - tail call void @free(i8* %1) - ret void -} - -define void @test16c(i8 %v, i8** %P) { - ; CHECK: %1 = alloca - %1 = tail call noalias i8* @malloc(i64 4) - ; CHECK-NEXT: store i8* %1, i8** %P - store i8* %1, i8** %P - ; CHECK-NEXT: @no_sync_func(i8* nocapture nofree %1) - tail call void @no_sync_func(i8* %1) nounwind - ; CHECK-NOT: @free - tail call void @free(i8* %1) - ret void -} - -define void @test16d(i8 %v, i8** %P) { - ; CHECK: %1 = tail call noalias i8* @malloc(i64 4) - %1 = tail call noalias i8* @malloc(i64 4) - ; CHECK-NEXT: store i8* %1, i8** %P - store i8* %1, i8** %P - ret void -} diff --git a/llvm/test/Transforms/FunctionAttrs/internal-noalias.ll b/llvm/test/Transforms/FunctionAttrs/internal-noalias.ll deleted file mode 100644 index fd6e17bc77f..00000000000 --- a/llvm/test/Transforms/FunctionAttrs/internal-noalias.ll +++ /dev/null @@ -1,48 +0,0 @@ -; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=5 < %s | FileCheck %s - -define dso_local i32 @visible(i32* noalias %A, i32* noalias %B) #0 { -entry: - %call1 = call i32 @noalias_args(i32* %A, i32* %B) - %call2 = call i32 @noalias_args_argmem(i32* %A, i32* %B) - %add = add nsw i32 %call1, %call2 - ret i32 %add -} - -; CHECK: define private i32 @noalias_args(i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) %A, i32* noalias nocapture nofree nonnull readonly align 4 dereferenceable(4) %B) - -define private i32 @noalias_args(i32* %A, i32* %B) #0 { -entry: - %0 = load i32, i32* %A, align 4 - %1 = load i32, i32* %B, align 4 - %add = add nsw i32 %0, %1 - %call = call i32 @noalias_args_argmem(i32* %A, i32* %B) - %add2 = add nsw i32 %add, %call - ret i32 %add2 -} - - -; FIXME: Should be something like this. -; define internal i32 @noalias_args_argmem(i32* noalias nocapture readonly %A, i32* noalias nocapture readonly %B) -; CHECK: define internal i32 @noalias_args_argmem(i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) %A, i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) %B) - -; -define internal i32 @noalias_args_argmem(i32* %A, i32* %B) #1 { -entry: - %0 = load i32, i32* %A, align 4 - %1 = load i32, i32* %B, align 4 - %add = add nsw i32 %0, %1 - ret i32 %add -} - -define dso_local i32 @visible_local(i32* %A) #0 { -entry: - %B = alloca i32, align 4 - store i32 5, i32* %B, align 4 - %call1 = call i32 @noalias_args(i32* %A, i32* nonnull %B) - %call2 = call i32 @noalias_args_argmem(i32* %A, i32* nonnull %B) - %add = add nsw i32 %call1, %call2 - ret i32 %add -} - -attributes #0 = { noinline nounwind uwtable willreturn } -attributes #1 = { argmemonly noinline nounwind uwtable willreturn} diff --git a/llvm/test/Transforms/FunctionAttrs/liveness.ll b/llvm/test/Transforms/FunctionAttrs/liveness.ll deleted file mode 100644 index 4fea57ff921..00000000000 --- a/llvm/test/Transforms/FunctionAttrs/liveness.ll +++ /dev/null @@ -1,857 +0,0 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes -; RUN: opt -attributor --attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=4 -S < %s | FileCheck %s -; UTC_ARGS: --turn off - -; CHECK: @dead_with_blockaddress_users.l = constant [2 x i8*] [i8* inttoptr (i32 1 to i8*), i8* inttoptr (i32 1 to i8*)] -@dead_with_blockaddress_users.l = constant [2 x i8*] [i8* blockaddress(@dead_with_blockaddress_users, %lab0), i8* blockaddress(@dead_with_blockaddress_users, %end)] - -declare void @no_return_call() nofree noreturn nounwind readnone - -declare void @normal_call() readnone - -declare i32 @foo() - -declare i32 @foo_nounwind() nounwind - -declare i32 @foo_noreturn_nounwind() noreturn nounwind - -declare i32 @foo_noreturn() noreturn - -declare i32 @bar() nosync readnone - -; This internal function has no live call sites, so all its BBs are considered dead, -; and nothing should be deduced for it. - -; CHECK-NOT: define internal i32 @dead_internal_func(i32 %0) -define internal i32 @dead_internal_func(i32 %0) { - %2 = icmp slt i32 %0, 1 - br i1 %2, label %3, label %5 - -; <label>:3: ; preds = %5, %1 - %4 = phi i32 [ 1, %1 ], [ %8, %5 ] - ret i32 %4 - -; <label>:5: ; preds = %1, %5 - %6 = phi i32 [ %9, %5 ], [ 1, %1 ] - %7 = phi i32 [ %8, %5 ], [ 1, %1 ] - %8 = mul nsw i32 %6, %7 - %9 = add nuw nsw i32 %6, 1 - %10 = icmp eq i32 %6, %0 - br i1 %10, label %3, label %5 -} - -; CHECK: Function Attrs: nofree norecurse nounwind uwtable willreturn -define i32 @volatile_load(i32*) norecurse nounwind uwtable { - %2 = load volatile i32, i32* %0, align 4 - ret i32 %2 -} - -; CHECK-NOT: internal_load -define internal i32 @internal_load(i32*) norecurse nounwind uwtable { - %2 = load i32, i32* %0, align 4 - ret i32 %2 -} -; TEST 1: Only first block is live. - -; CHECK: Function Attrs: nofree noreturn nosync nounwind -; CHECK-NEXT: define i32 @first_block_no_return(i32 %a, i32* nocapture nofree nonnull readonly %ptr1, i32* nocapture nofree readnone %ptr2) -define i32 @first_block_no_return(i32 %a, i32* nonnull %ptr1, i32* %ptr2) #0 { -entry: - call i32 @internal_load(i32* %ptr1) - call void @no_return_call() - ; CHECK: call void @no_return_call() - ; CHECK-NEXT: unreachable - call i32 @dead_internal_func(i32 10) - %cmp = icmp eq i32 %a, 0 - br i1 %cmp, label %cond.true, label %cond.false - -cond.true: ; preds = %entry - call i32 @internal_load(i32* %ptr2) - %load = call i32 @volatile_load(i32* %ptr1) - call void @normal_call() - %call = call i32 @foo() - br label %cond.end - -cond.false: ; preds = %entry - call void @normal_call() - %call1 = call i32 @bar() - br label %cond.end - -cond.end: ; preds = %cond.false, %cond.true - %cond = phi i32 [ %call, %cond.true ], [ %call1, %cond.false ] - ret i32 %cond -} - -; TEST 2: cond.true is dead, but cond.end is not, since cond.false is live - -; This is just an example. For example we can put a sync call in a -; dead block and check if it is deduced. - -; CHECK: Function Attrs: nosync -; CHECK-NEXT: define i32 @dead_block_present(i32 %a, i32* nocapture nofree readnone %ptr1) -define i32 @dead_block_present(i32 %a, i32* %ptr1) #0 { -entry: - %cmp = icmp eq i32 %a, 0 - br i1 %cmp, label %cond.true, label %cond.false - -cond.true: ; preds = %entry - call void @no_return_call() - ; CHECK: call void @no_return_call() - ; CHECK-NEXT: unreachable - %call = call i32 @volatile_load(i32* %ptr1) - br label %cond.end - -cond.false: ; preds = %entry - call void @normal_call() - %call1 = call i32 @bar() - br label %cond.end - -cond.end: ; preds = %cond.false, %cond.true -; CHECK: cond.end: -; CHECK-NEXT: ret i32 %call1 - %cond = phi i32 [ %call, %cond.true ], [ %call1, %cond.false ] - ret i32 %cond -} - -; TEST 3: both cond.true and cond.false are dead, therfore cond.end is dead as well. - -define i32 @all_dead(i32 %a) #0 { -entry: - %cmp = icmp eq i32 %a, 0 - br i1 %cmp, label %cond.true, label %cond.false - -cond.true: ; preds = %entry - call void @no_return_call() - ; CHECK: call void @no_return_call() - ; CHECK-NEXT: unreachable - call i32 @dead_internal_func(i32 10) - ; CHECK-NOT: call - %call = call i32 @foo() - br label %cond.end - -cond.false: ; preds = %entry - call void @no_return_call() - ; CHECK: call void @no_return_call() - ; CHECK-NEXT: unreachable - call i32 @dead_internal_func(i32 10) - %call1 = call i32 @bar() - br label %cond.end - -cond.end: ; preds = %cond.false, %cond.true - %cond = phi i32 [ %call, %cond.true ], [ %call1, %cond.false ] - ret i32 %cond -} - -declare i32 @__gxx_personality_v0(...) - -; TEST 4: All blocks are live. - -; CHECK: define i32 @all_live(i32 %a) -define i32 @all_live(i32 %a) #0 { -entry: - %cmp = icmp eq i32 %a, 0 - br i1 %cmp, label %cond.true, label %cond.false - -cond.true: ; preds = %entry - call void @normal_call() - %call = call i32 @foo_noreturn() - br label %cond.end - -cond.false: ; preds = %entry - call void @normal_call() - %call1 = call i32 @bar() - br label %cond.end - -cond.end: ; preds = %cond.false, %cond.true - %cond = phi i32 [ %call, %cond.true ], [ %call1, %cond.false ] - ret i32 %cond -} - -; TEST 5.1 noreturn invoke instruction with a unreachable normal successor block. - -; CHECK: define i32 @invoke_noreturn(i32 %a) -define i32 @invoke_noreturn(i32 %a) personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { -entry: - %cmp = icmp eq i32 %a, 0 - br i1 %cmp, label %cond.true, label %cond.false - -cond.true: ; preds = %entry - call void @normal_call() - %call = invoke i32 @foo_noreturn() to label %continue - unwind label %cleanup - ; CHECK: %call = invoke i32 @foo_noreturn() - ; CHECK-NEXT: to label %continue unwind label %cleanup - -cond.false: ; preds = %entry - call void @normal_call() - %call1 = call i32 @bar() - br label %cond.end - -cond.end: ; preds = %cond.false, %continue - %cond = phi i32 [ %call, %continue ], [ %call1, %cond.false ] - ret i32 %cond - -continue: - ; CHECK: continue: - ; CHECK-NEXT: unreachable - br label %cond.end - -cleanup: - %res = landingpad { i8*, i32 } - catch i8* null - ret i32 0 -} - -; TEST 5.2 noreturn invoke instruction replaced by a call and an unreachable instruction -; put after it. - -; CHECK: define i32 @invoke_noreturn_nounwind(i32 %a) -define i32 @invoke_noreturn_nounwind(i32 %a) personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { -entry: - %cmp = icmp eq i32 %a, 0 - br i1 %cmp, label %cond.true, label %cond.false - -cond.true: ; preds = %entry - call void @normal_call() - %call = invoke i32 @foo_noreturn_nounwind() to label %continue - unwind label %cleanup - ; CHECK: call void @normal_call() - ; CHECK-NEXT: call i32 @foo_noreturn_nounwind() - ; CHECK-NEXT: unreachable - - ; CHECK-NOT: @foo_noreturn_nounwind() - -cond.false: ; preds = %entry - call void @normal_call() - %call1 = call i32 @bar() - br label %cond.end - -cond.end: ; preds = %cond.false, %continue - %cond = phi i32 [ %call, %continue ], [ %call1, %cond.false ] - ret i32 %cond - -continue: - br label %cond.end - -cleanup: - %res = landingpad { i8*, i32 } - catch i8* null - ret i32 0 -} - -; TEST 5.3 unounwind invoke instruction replaced by a call and a branch instruction put after it. -define i32 @invoke_nounwind(i32 %a) personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { -; CHECK-LABEL: define {{[^@]+}}@invoke_nounwind -; CHECK: cond.true: -; CHECK-NEXT: call void @normal_call() -; CHECK-NEXT: [[CALL:%.*]] = call i32 @foo_nounwind() -; CHECK-NEXT: br label [[CONTINUE:%.*]] -; CHECK: continue: -; CHECK-NEXT: br label [[COND_END:%.*]] -; -entry: - %cmp = icmp eq i32 %a, 0 - br i1 %cmp, label %cond.true, label %cond.false - -cond.true: ; preds = %entry - call void @normal_call() - %call = invoke i32 @foo_nounwind() to label %continue - unwind label %cleanup - -cond.false: ; preds = %entry - call void @normal_call() - %call1 = call i32 @bar() - br label %cond.end - -cond.end: ; preds = %cond.false, %continue - %cond = phi i32 [ %call, %continue ], [ %call1, %cond.false ] - ret i32 %cond - -continue: - br label %cond.end - -cleanup: - %res = landingpad { i8*, i32 } - catch i8* null - ret i32 0 -} - -; UTC_ARGS: --turn off - -; TEST 6: Undefined behvior, taken from LangRef. -; FIXME: Should be able to detect undefined behavior. - -; CHECK: define void @ub(i32* nocapture nofree writeonly %0) -define void @ub(i32* %0) { - %poison = sub nuw i32 0, 1 ; Results in a poison value. - %still_poison = and i32 %poison, 0 ; 0, but also poison. - %poison_yet_again = getelementptr i32, i32* %0, i32 %still_poison - store i32 0, i32* %poison_yet_again ; Undefined behavior due to store to poison. - ret void -} - -define void @inf_loop() #0 { -entry: - br label %while.body - -while.body: ; preds = %entry, %while.body - br label %while.body -} - -; TEST 7: Infinite loop. -; FIXME: Detect infloops, and mark affected blocks dead. - -define i32 @test5(i32, i32) #0 { - %3 = icmp sgt i32 %0, %1 - br i1 %3, label %cond.if, label %cond.elseif - -cond.if: ; preds = %2 - %4 = tail call i32 @bar() - br label %cond.end - -cond.elseif: ; preds = %2 - call void @inf_loop() - %5 = icmp slt i32 %0, %1 - br i1 %5, label %cond.end, label %cond.else - -cond.else: ; preds = %cond.elseif - %6 = tail call i32 @foo() - br label %cond.end - -cond.end: ; preds = %cond.if, %cond.else, %cond.elseif - %7 = phi i32 [ %1, %cond.elseif ], [ 0, %cond.else ], [ 0, %cond.if ] - ret i32 %7 -} - -define void @rec() #0 { -entry: - call void @rec() - ret void -} - -; TEST 8: Recursion -; FIXME: everything after first block should be marked dead -; and unreachable should be put after call to @rec(). - -define i32 @test6(i32, i32) #0 { - call void @rec() - %3 = icmp sgt i32 %0, %1 - br i1 %3, label %cond.if, label %cond.elseif - -cond.if: ; preds = %2 - %4 = tail call i32 @bar() - br label %cond.end - -cond.elseif: ; preds = %2 - call void @rec() - %5 = icmp slt i32 %0, %1 - br i1 %5, label %cond.end, label %cond.else - -cond.else: ; preds = %cond.elseif - %6 = tail call i32 @foo() - br label %cond.end - -cond.end: ; preds = %cond.if, %cond.else, %cond.elseif - %7 = phi i32 [ %1, %cond.elseif ], [ 0, %cond.else ], [ 0, %cond.if ] - ret i32 %7 -} -; TEST 9: Recursion -; FIXME: contains recursive call to itself in cond.elseif block - -define i32 @test7(i32, i32) #0 { - %3 = icmp sgt i32 %0, %1 - br i1 %3, label %cond.if, label %cond.elseif - -cond.if: ; preds = %2 - %4 = tail call i32 @bar() - br label %cond.end - -cond.elseif: ; preds = %2 - %5 = tail call i32 @test7(i32 %0, i32 %1) - %6 = icmp slt i32 %0, %1 - br i1 %6, label %cond.end, label %cond.else - -cond.else: ; preds = %cond.elseif - %7 = tail call i32 @foo() - br label %cond.end - -cond.end: ; preds = %cond.if, %cond.else, %cond.elseif - %8 = phi i32 [ %1, %cond.elseif ], [ 0, %cond.else ], [ 0, %cond.if ] - ret i32 %8 -} - -; SCC test -; -; char a1 __attribute__((aligned(8))); -; char a2 __attribute__((aligned(16))); -; -; char* f1(char* a ){ -; return a?a:f2(&a1); -; } -; char* f2(char* a){ -; return a?f1(a):f3(&a2); -; } -; -; char* f3(char* a){ -; return a?&a1: f1(&a2); -; } - -@a1 = common global i8 0, align 8 -@a2 = common global i8 0, align 16 - -define internal i8* @f1(i8* readnone %0) local_unnamed_addr #0 { -; ATTRIBUTOR: define internal i8* @f1(i8* readnone %0) - %2 = icmp eq i8* %0, null - br i1 %2, label %3, label %5 - -; <label>:3: ; preds = %1 -; ATTRIBUTOR: %4 = tail call i8* undef(i8* nonnull align 8 @a1) - %4 = tail call i8* @f2(i8* nonnull @a1) - br label %5 - -; <label>:5: ; preds = %1, %3 - %6 = phi i8* [ %4, %3 ], [ %0, %1 ] - ret i8* %6 -} - -define internal i8* @f2(i8* readnone %0) local_unnamed_addr #0 { -; ATTRIBUTOR: define internal i8* @f2(i8* readnone %0) - %2 = icmp eq i8* %0, null - br i1 %2, label %5, label %3 - -; <label>:3: ; preds = %1 - -; ATTRIBUTOR: %4 = tail call i8* undef(i8* nonnull align 8 %0) - %4 = tail call i8* @f1(i8* nonnull %0) - br label %7 - -; <label>:5: ; preds = %1 -; ATTRIBUTOR: %6 = tail call i8* undef(i8* nonnull align 16 @a2) - %6 = tail call i8* @f3(i8* nonnull @a2) - br label %7 - -; <label>:7: ; preds = %5, %3 - %8 = phi i8* [ %4, %3 ], [ %6, %5 ] - ret i8* %8 -} - -define internal i8* @f3(i8* readnone %0) local_unnamed_addr #0 { -; ATTRIBUTOR: define internal i8* @f3(i8* readnone %0) - %2 = icmp eq i8* %0, null - br i1 %2, label %3, label %5 - -; <label>:3: ; preds = %1 -; ATTRIBUTOR: %4 = tail call i8* undef(i8* nonnull align 16 @a2) - %4 = tail call i8* @f1(i8* nonnull @a2) - br label %5 - -; <label>:5: ; preds = %1, %3 - %6 = phi i8* [ %4, %3 ], [ @a1, %1 ] - ret i8* %6 -} - -define void @test_unreachable() { -; CHECK: define void @test_unreachable() -; CHECK-NEXT: call void @test_unreachable() -; CHECK-NEXT: unreachable -; CHECK-NEXT: } - call void @test_unreachable() - unreachable -} - -define linkonce_odr void @non_exact1() { - call void @non_dead_a0() - call void @non_dead_a1() - call void @non_dead_a2() - call void @non_dead_a3() - call void @non_dead_a4() - call void @non_dead_a5() - call void @non_dead_a6() - call void @non_dead_a7() - call void @non_dead_a8() - call void @non_dead_a9() - call void @non_dead_a10() - call void @non_dead_a11() - call void @non_dead_a12() - call void @non_dead_a13() - call void @non_dead_a14() - call void @non_dead_a15() - call void @middle() - ret void -} -define internal void @middle() { -bb0: - call void @non_dead_b0() - call void @non_dead_b1() - call void @non_dead_b2() - call void @non_dead_b3() -br label %bb1 -bb1: - call void @non_dead_b4() - call void @non_dead_b5() - call void @non_dead_b6() - call void @non_dead_b7() -br label %bb2 -bb2: - call void @non_dead_b8() - call void @non_dead_b9() - call void @non_dead_b10() - call void @non_dead_b11() -br label %bb3 -bb3: - call void @non_dead_b12() - call void @non_dead_b13() - call void @non_dead_b14() - call void @non_dead_b15() -br label %bb4 -bb4: - call void @non_exact2() - ret void -} -define linkonce_odr void @non_exact2() { - call void @non_dead_c0() - call void @non_dead_c1() - call void @non_dead_c2() - call void @non_dead_c3() - call void @non_dead_c4() - call void @non_dead_c5() - call void @non_dead_c6() - call void @non_dead_c7() - call void @non_dead_c8() - call void @non_dead_c9() - call void @non_dead_c10() - call void @non_dead_c11() - call void @non_dead_c12() - call void @non_dead_c13() - call void @non_dead_c14() - call void @non_dead_c15() - call void @non_exact3() - ret void -} -define linkonce_odr void @non_exact3() { - call void @non_dead_d0() - call void @non_dead_d1() - call void @non_dead_d2() - call void @non_dead_d3() - call void @non_dead_d4() - call void @non_dead_d5() - call void @non_dead_d6() - call void @non_dead_d7() - call void @non_dead_d8() - call void @non_dead_d9() - call void @non_dead_d10() - call void @non_dead_d11() - call void @non_dead_d12() - call void @non_dead_d13() - call void @non_dead_d14() - call void @non_dead_d15() - %nr = call i32 @foo_noreturn() - call void @dead_e1() - ret void -} -; CHECK: define linkonce_odr void @non_exact3() { -; CHECK-NEXT: call void @non_dead_d0() -; CHECK-NEXT: call void @non_dead_d1() -; CHECK-NEXT: call void @non_dead_d2() -; CHECK-NEXT: call void @non_dead_d3() -; CHECK-NEXT: call void @non_dead_d4() -; CHECK-NEXT: call void @non_dead_d5() -; CHECK-NEXT: call void @non_dead_d6() -; CHECK-NEXT: call void @non_dead_d7() -; CHECK-NEXT: call void @non_dead_d8() -; CHECK-NEXT: call void @non_dead_d9() -; CHECK-NEXT: call void @non_dead_d10() -; CHECK-NEXT: call void @non_dead_d11() -; CHECK-NEXT: call void @non_dead_d12() -; CHECK-NEXT: call void @non_dead_d13() -; CHECK-NEXT: call void @non_dead_d14() -; CHECK-NEXT: call void @non_dead_d15() -; CHECK-NEXT: %nr = call i32 @foo_noreturn() -; CHECK-NEXT: unreachable - -define internal void @non_dead_a0() { ret void } -define internal void @non_dead_a1() { ret void } -define internal void @non_dead_a2() { ret void } -define internal void @non_dead_a3() { ret void } -define internal void @non_dead_a4() { ret void } -define internal void @non_dead_a5() { ret void } -define internal void @non_dead_a6() { ret void } -define internal void @non_dead_a7() { ret void } -define internal void @non_dead_a8() { ret void } -define internal void @non_dead_a9() { ret void } -define internal void @non_dead_a10() { ret void } -define internal void @non_dead_a11() { ret void } -define internal void @non_dead_a12() { ret void } -define internal void @non_dead_a13() { ret void } -define internal void @non_dead_a14() { ret void } -define internal void @non_dead_a15() { ret void } -define internal void @non_dead_b0() { ret void } -define internal void @non_dead_b1() { ret void } -define internal void @non_dead_b2() { ret void } -define internal void @non_dead_b3() { ret void } -define internal void @non_dead_b4() { ret void } -define internal void @non_dead_b5() { ret void } -define internal void @non_dead_b6() { ret void } -define internal void @non_dead_b7() { ret void } -define internal void @non_dead_b8() { ret void } -define internal void @non_dead_b9() { ret void } -define internal void @non_dead_b10() { ret void } -define internal void @non_dead_b11() { ret void } -define internal void @non_dead_b12() { ret void } -define internal void @non_dead_b13() { ret void } -define internal void @non_dead_b14() { ret void } -define internal void @non_dead_b15() { ret void } -define internal void @non_dead_c0() { ret void } -define internal void @non_dead_c1() { ret void } -define internal void @non_dead_c2() { ret void } -define internal void @non_dead_c3() { ret void } -define internal void @non_dead_c4() { ret void } -define internal void @non_dead_c5() { ret void } -define internal void @non_dead_c6() { ret void } -define internal void @non_dead_c7() { ret void } -define internal void @non_dead_c8() { ret void } -define internal void @non_dead_c9() { ret void } -define internal void @non_dead_c10() { ret void } -define internal void @non_dead_c11() { ret void } -define internal void @non_dead_c12() { ret void } -define internal void @non_dead_c13() { ret void } -define internal void @non_dead_c14() { ret void } -define internal void @non_dead_c15() { ret void } -define internal void @non_dead_d0() { ret void } -define internal void @non_dead_d1() { ret void } -define internal void @non_dead_d2() { ret void } -define internal void @non_dead_d3() { ret void } -define internal void @non_dead_d4() { ret void } -define internal void @non_dead_d5() { ret void } -define internal void @non_dead_d6() { ret void } -define internal void @non_dead_d7() { ret void } -define internal void @non_dead_d8() { ret void } -define internal void @non_dead_d9() { ret void } -define internal void @non_dead_d10() { ret void } -define internal void @non_dead_d11() { ret void } -define internal void @non_dead_d12() { ret void } -define internal void @non_dead_d13() { ret void } -define internal void @non_dead_d14() { ret void } -define internal void @non_dead_d15() { ret void } -define internal void @dead_e0() { call void @dead_e1() ret void } -define internal void @dead_e1() { call void @dead_e2() ret void } -define internal void @dead_e2() { ret void } - -; CHECK: define internal void @non_dead_a0() -; CHECK: define internal void @non_dead_a1() -; CHECK: define internal void @non_dead_a2() -; CHECK: define internal void @non_dead_a3() -; CHECK: define internal void @non_dead_a4() -; CHECK: define internal void @non_dead_a5() -; CHECK: define internal void @non_dead_a6() -; CHECK: define internal void @non_dead_a7() -; CHECK: define internal void @non_dead_a8() -; CHECK: define internal void @non_dead_a9() -; CHECK: define internal void @non_dead_a10() -; CHECK: define internal void @non_dead_a11() -; CHECK: define internal void @non_dead_a12() -; CHECK: define internal void @non_dead_a13() -; CHECK: define internal void @non_dead_a14() -; CHECK: define internal void @non_dead_a15() -; CHECK: define internal void @non_dead_b0() -; CHECK: define internal void @non_dead_b1() -; CHECK: define internal void @non_dead_b2() -; CHECK: define internal void @non_dead_b3() -; CHECK: define internal void @non_dead_b4() -; CHECK: define internal void @non_dead_b5() -; CHECK: define internal void @non_dead_b6() -; CHECK: define internal void @non_dead_b7() -; CHECK: define internal void @non_dead_b8() -; CHECK: define internal void @non_dead_b9() -; CHECK: define internal void @non_dead_b10() -; CHECK: define internal void @non_dead_b11() -; CHECK: define internal void @non_dead_b12() -; CHECK: define internal void @non_dead_b13() -; CHECK: define internal void @non_dead_b14() -; CHECK: define internal void @non_dead_b15() -; CHECK: define internal void @non_dead_c0() -; CHECK: define internal void @non_dead_c1() -; CHECK: define internal void @non_dead_c2() -; CHECK: define internal void @non_dead_c3() -; CHECK: define internal void @non_dead_c4() -; CHECK: define internal void @non_dead_c5() -; CHECK: define internal void @non_dead_c6() -; CHECK: define internal void @non_dead_c7() -; CHECK: define internal void @non_dead_c8() -; CHECK: define internal void @non_dead_c9() -; CHECK: define internal void @non_dead_c10() -; CHECK: define internal void @non_dead_c11() -; CHECK: define internal void @non_dead_c12() -; CHECK: define internal void @non_dead_c13() -; CHECK: define internal void @non_dead_c14() -; CHECK: define internal void @non_dead_c15() -; CHECK: define internal void @non_dead_d0() -; CHECK: define internal void @non_dead_d1() -; CHECK: define internal void @non_dead_d2() -; CHECK: define internal void @non_dead_d3() -; CHECK: define internal void @non_dead_d4() -; CHECK: define internal void @non_dead_d5() -; CHECK: define internal void @non_dead_d6() -; CHECK: define internal void @non_dead_d7() -; CHECK: define internal void @non_dead_d8() -; CHECK: define internal void @non_dead_d9() -; CHECK: define internal void @non_dead_d10() -; CHECK: define internal void @non_dead_d11() -; CHECK: define internal void @non_dead_d12() -; CHECK: define internal void @non_dead_d13() -; CHECK: define internal void @non_dead_d14() -; Verify we actually deduce information for these functions. -; CHECK: Function Attrs: nofree nosync nounwind readnone willreturn -; CHECK-NEXT: define internal void @non_dead_d15() -; CHECK-NOT: define internal void @dead_e - - -declare void @blowup() noreturn -define void @live_with_dead_entry() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { -; CHECK: define void @live_with_dead_entry( -; CHECK-NEXT: entry: -; CHECK-NEXT: invoke void @blowup() -; CHECK-NEXT: to label %live_with_dead_entry.dead unwind label %lpad -; CHECK: lpad: ; preds = %entry -; CHECK-NEXT: %0 = landingpad { i8*, i32 } -; CHECK-NEXT: catch i8* null -; CHECK-NEXT: br label %live_with_dead_entry -; CHECK: live_with_dead_entry.dead: ; preds = %entry -; CHECK-NEXT: unreachable -; CHECK: live_with_dead_entry: ; preds = %lpad -; CHECK-NEXT: ret void -entry: - invoke void @blowup() to label %live_with_dead_entry unwind label %lpad -lpad: - %0 = landingpad { i8*, i32 } catch i8* null - br label %live_with_dead_entry -live_with_dead_entry: - ret void -} - -define void @live_with_dead_entry_lp() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { -; CHECK: define void @live_with_dead_entry_lp( -; CHECK-NEXT: entry: -; CHECK-NEXT: invoke void @blowup() -; CHECK-NEXT: to label %live_with_dead_entry.dead unwind label %lp1 -; CHECK: lp1: ; preds = %entry -; CHECK-NEXT: %lp = landingpad { i8*, i32 } -; CHECK-NEXT: catch i8* null -; CHECK-NEXT: invoke void @blowup() -; CHECK-NEXT: to label %live_with_dead_entry.dead1 unwind label %lp2 -; CHECK: lp2: ; preds = %lp1 -; CHECK-NEXT: %0 = landingpad { i8*, i32 } -; CHECK-NEXT: catch i8* null -; CHECK-NEXT: br label %live_with_dead_entry -; CHECK: live_with_dead_entry.dead: -; CHECK-NEXT: unreachable -; CHECK: live_with_dead_entry.dead1: -; CHECK-NEXT: unreachable -; CHECK: live_with_dead_entry: ; preds = %lp2 -; CHECK-NEXT: ret void -entry: - invoke void @blowup() to label %live_with_dead_entry unwind label %lp1 -lp1: - %lp = landingpad { i8*, i32 } catch i8* null - invoke void @blowup() to label %live_with_dead_entry unwind label %lp2 -lp2: - %0 = landingpad { i8*, i32 } catch i8* null - br label %live_with_dead_entry -live_with_dead_entry: - ret void -} - -; CHECK: define internal void @useless_arg_sink(i32* nocapture nofree readnone %a) -define internal void @useless_arg_sink(i32* %a) { - ret void -} - -; CHECK: define internal void @useless_arg_almost_sink(i32* nocapture nofree readnone %a) -define internal void @useless_arg_almost_sink(i32* %a) { -; CHECK: call void @useless_arg_sink(i32* nofree undef) - call void @useless_arg_sink(i32* %a) - ret void -} - -; Check we do not annotate the function interface of this weak function. -; CHECK: define weak_odr void @useless_arg_ext(i32* %a) -define weak_odr void @useless_arg_ext(i32* %a) { -; CHECK: call void @useless_arg_almost_sink(i32* nofree undef) - call void @useless_arg_almost_sink(i32* %a) - ret void -} - -; CHECK: define internal void @useless_arg_ext_int(i32* %a) -define internal void @useless_arg_ext_int(i32* %a) { -; CHECK: call void @useless_arg_ext(i32* %a) - call void @useless_arg_ext(i32* %a) - ret void -} - -define void @useless_arg_ext_int_ext(i32* %a) { -; CHECK: call void @useless_arg_ext_int(i32* %a) - call void @useless_arg_ext_int(i32* %a) - ret void -} - -; UTC_ARGS: --turn on - -; FIXME: We should fold terminators. - -define internal i32 @switch_default(i64 %i) nounwind { -; CHECK-LABEL: define {{[^@]+}}@switch_default -; CHECK-SAME: (i64 [[I:%.*]]) -; CHECK-NEXT: entry: -; CHECK-NEXT: switch i64 0, label [[SW_DEFAULT:%.*]] [ -; CHECK-NEXT: i64 3, label [[RETURN:%.*]] -; CHECK-NEXT: i64 10, label [[RETURN]] -; CHECK-NEXT: ] -; CHECK: sw.default: -; CHECK-NEXT: ret i32 123 -; CHECK: return: -; CHECK-NEXT: unreachable -; -entry: - switch i64 %i, label %sw.default [ - i64 3, label %return - i64 10, label %return - ] - -sw.default: - ret i32 123 - -return: - ret i32 0 -} - -define i32 @switch_default_caller() { -; CHECK-LABEL: define {{[^@]+}}@switch_default_caller() -; CHECK-NEXT: [[CALL2:%.*]] = tail call i32 @switch_default(i64 0) -; CHECK-NEXT: ret i32 123 -; - %call2 = tail call i32 @switch_default(i64 0) - ret i32 %call2 -} -; UTC_ARGS: --turn off - -; Allow blockaddress users -; CHECK-NOT @dead_with_blockaddress_users -define internal void @dead_with_blockaddress_users(i32* nocapture %pc) nounwind readonly { -entry: - br label %indirectgoto - -lab0: ; preds = %indirectgoto - %indvar.next = add i32 %indvar, 1 ; <i32> [#uses=1] - br label %indirectgoto - -end: ; preds = %indirectgoto - ret void - -indirectgoto: ; preds = %lab0, %entry - %indvar = phi i32 [ %indvar.next, %lab0 ], [ 0, %entry ] ; <i32> [#uses=2] - %pc.addr.0 = getelementptr i32, i32* %pc, i32 %indvar ; <i32*> [#uses=1] - %tmp1.pn = load i32, i32* %pc.addr.0 ; <i32> [#uses=1] - %indirect.goto.dest.in = getelementptr inbounds [2 x i8*], [2 x i8*]* @dead_with_blockaddress_users.l, i32 0, i32 %tmp1.pn ; <i8**> [#uses=1] - %indirect.goto.dest = load i8*, i8** %indirect.goto.dest.in ; <i8*> [#uses=1] - indirectbr i8* %indirect.goto.dest, [label %lab0, label %end] -} diff --git a/llvm/test/Transforms/FunctionAttrs/misc.ll b/llvm/test/Transforms/FunctionAttrs/misc.ll deleted file mode 100644 index 7b9e25809d9..00000000000 --- a/llvm/test/Transforms/FunctionAttrs/misc.ll +++ /dev/null @@ -1,105 +0,0 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes -; RUN: opt -S -attributor -attributor-disable=false < %s | FileCheck %s --check-prefixes=ALL,CHECK -; RUN: opt -S -aa-pipeline='basic-aa' -passes=attributor -attributor-disable=false -attributor-annotate-decl-cs < %s | FileCheck %s --check-prefixes=ALL,DECL_CS -; -; Mostly check we do not crash on these uses - -define internal void @internal(void (i8*)* %fp) { -; CHECK-LABEL: define {{[^@]+}}@internal -; CHECK-SAME: (void (i8*)* [[FP:%.*]]) -; CHECK-NEXT: entry: -; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 -; CHECK-NEXT: [[TMP:%.*]] = bitcast i32* [[A]] to i8* -; CHECK-NEXT: call void @foo(i32* nocapture nofree nonnull align 4 dereferenceable(4) undef) -; CHECK-NEXT: call void [[FP:%.*]](i8* bitcast (void (i32*)* @foo to i8*)) -; CHECK-NEXT: call void @callback1(void (i32*)* nonnull @foo) -; CHECK-NEXT: call void @callback2(void (i8*)* bitcast (void (i32*)* @foo to void (i8*)*)) -; CHECK-NEXT: call void @callback2(void (i8*)* [[FP]]) -; CHECK-NEXT: [[TMP1:%.*]] = bitcast i32* [[A]] to i8* -; CHECK-NEXT: call void [[FP]](i8* [[TMP1]]) -; CHECK-NEXT: ret void -; -; DECL_CS-LABEL: define {{[^@]+}}@internal -; DECL_CS-SAME: (void (i8*)* [[FP:%.*]]) -; DECL_CS-NEXT: entry: -; DECL_CS-NEXT: [[A:%.*]] = alloca i32, align 4 -; DECL_CS-NEXT: [[TMP:%.*]] = bitcast i32* [[A]] to i8* -; DECL_CS-NEXT: call void @foo(i32* nocapture nofree nonnull align 4 dereferenceable(4) undef) -; DECL_CS-NEXT: call void [[FP]](i8* bitcast (void (i32*)* @foo to i8*)) -; DECL_CS-NEXT: call void @callback1(void (i32*)* nonnull @foo) -; DECL_CS-NEXT: call void @callback2(void (i8*)* nonnull bitcast (void (i32*)* @foo to void (i8*)*)) -; DECL_CS-NEXT: call void @callback2(void (i8*)* [[FP]]) -; DECL_CS-NEXT: [[TMP1:%.*]] = bitcast i32* [[A]] to i8* -; DECL_CS-NEXT: call void [[FP]](i8* [[TMP1]]) -; DECL_CS-NEXT: ret void -; -entry: - %a = alloca i32, align 4 - %tmp = bitcast i32* %a to i8* - call void @foo(i32* nonnull %a) - call void %fp(i8* bitcast (void (i32*)* @foo to i8*)) - call void @callback1(void (i32*)* nonnull @foo) - call void @callback2(void (i8*)* bitcast (void (i32*)* @foo to void (i8*)*)) - call void @callback2(void (i8*)* %fp) - %tmp1 = bitcast i32* %a to i8* - call void %fp(i8* %tmp1) - ret void -} - -define void @external(void (i8*)* %fp) { -; CHECK-LABEL: define {{[^@]+}}@external -; CHECK-SAME: (void (i8*)* [[FP:%.*]]) -; CHECK-NEXT: entry: -; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 -; CHECK-NEXT: [[TMP:%.*]] = bitcast i32* [[A]] to i8* -; CHECK-NEXT: call void @foo(i32* nocapture nofree nonnull align 4 dereferenceable(4) undef) -; CHECK-NEXT: call void @callback1(void (i32*)* nonnull @foo) -; CHECK-NEXT: call void @callback2(void (i8*)* bitcast (void (i32*)* @foo to void (i8*)*)) -; CHECK-NEXT: call void @callback2(void (i8*)* [[FP]]) -; CHECK-NEXT: call void [[FP]](i8* bitcast (void (i32*)* @foo to i8*)) -; CHECK-NEXT: [[TMP1:%.*]] = bitcast i32* [[A]] to i8* -; CHECK-NEXT: call void [[FP]](i8* [[TMP1]]) -; CHECK-NEXT: call void @internal(void (i8*)* [[FP]]) -; CHECK-NEXT: ret void -; -; DECL_CS-LABEL: define {{[^@]+}}@external -; DECL_CS-SAME: (void (i8*)* [[FP:%.*]]) -; DECL_CS-NEXT: entry: -; DECL_CS-NEXT: [[A:%.*]] = alloca i32, align 4 -; DECL_CS-NEXT: [[TMP:%.*]] = bitcast i32* [[A]] to i8* -; DECL_CS-NEXT: call void @foo(i32* nocapture nofree nonnull align 4 dereferenceable(4) undef) -; DECL_CS-NEXT: call void @callback1(void (i32*)* nonnull @foo) -; DECL_CS-NEXT: call void @callback2(void (i8*)* nonnull bitcast (void (i32*)* @foo to void (i8*)*)) -; DECL_CS-NEXT: call void @callback2(void (i8*)* [[FP]]) -; DECL_CS-NEXT: call void [[FP]](i8* bitcast (void (i32*)* @foo to i8*)) -; DECL_CS-NEXT: [[TMP1:%.*]] = bitcast i32* [[A]] to i8* -; DECL_CS-NEXT: call void [[FP]](i8* [[TMP1]]) -; DECL_CS-NEXT: call void @internal(void (i8*)* [[FP]]) -; DECL_CS-NEXT: ret void -; -entry: - %a = alloca i32, align 4 - %tmp = bitcast i32* %a to i8* - call void @foo(i32* nonnull %a) - call void @callback1(void (i32*)* nonnull @foo) - call void @callback2(void (i8*)* bitcast (void (i32*)* @foo to void (i8*)*)) - call void @callback2(void (i8*)* %fp) - call void %fp(i8* bitcast (void (i32*)* @foo to i8*)) - %tmp1 = bitcast i32* %a to i8* - call void %fp(i8* %tmp1) - call void @internal(void (i8*)* %fp) - ret void -} - -define internal void @foo(i32* %a) { -; CHECK-LABEL: define {{[^@]+}}@foo -; CHECK-SAME: (i32* nocapture nofree readnone [[A:%.*]]) -; CHECK-NEXT: entry: -; CHECK-NEXT: ret void -; -entry: - ret void -} - -declare void @callback1(void (i32*)*) -declare void @callback2(void (i8*)*) diff --git a/llvm/test/Transforms/FunctionAttrs/new_attributes.ll b/llvm/test/Transforms/FunctionAttrs/new_attributes.ll deleted file mode 100644 index 6e87cffeb02..00000000000 --- a/llvm/test/Transforms/FunctionAttrs/new_attributes.ll +++ /dev/null @@ -1,43 +0,0 @@ -; RUN: opt < %s -attributor -attributor-annotate-decl-cs -attributor-disable=false -attributor-max-iterations=0 -S | FileCheck %s -; RUN: opt < %s -attributor -attributor-annotate-decl-cs -attributor-disable=false -attributor-max-iterations=1 -S | FileCheck %s -; RUN: opt < %s -attributor -attributor-annotate-decl-cs -attributor-disable=false -attributor-max-iterations=2 -S | FileCheck %s -; RUN: opt < %s -attributor -attributor-annotate-decl-cs -attributor-disable=false -attributor-max-iterations=3 -S | FileCheck %s -; RUN: opt < %s -attributor -attributor-annotate-decl-cs -attributor-disable=false -attributor-max-iterations=4 -S | FileCheck %s -; RUN: opt < %s -attributor -attributor-annotate-decl-cs -attributor-disable=false -attributor-max-iterations=2147483647 -S | FileCheck %s - -; CHECK-NOT: Function -; CHECK: declare i32 @foo1() -; CHECK-NOT: Function -; CHECK: declare i32 @foo2() -; CHECK-NOT: Function -; CHECK: declare i32 @foo3() -declare i32 @foo1() -declare i32 @foo2() -declare i32 @foo3() - -; CHECK-NOT: Function -; CHECK: define internal i32 @bar() { -; CHECK-NEXT: %1 = call i32 @foo1() -; CHECK-NEXT: %2 = call i32 @foo2() -; CHECK-NEXT: %3 = call i32 @foo3() -; CHECK-NEXT: ret i32 undef -; CHECK-NEXT: } -define internal i32 @bar() { - %1 = call i32 @foo1() - %2 = call i32 @foo2() - %3 = call i32 @foo3() - ret i32 1 -} - -; CHECK-NOT: Function -; CHECK: define i32 @baz() { -; CHECK-NEXT: %1 = call i32 @bar() -; CHECK-NEXT: ret i32 0 -; CHECK-NEXT: } -define i32 @baz() { - %1 = call i32 @bar() - ret i32 0 -} - -; We should never derive anything here -; CHECK-NOT: attributes diff --git a/llvm/test/Transforms/FunctionAttrs/noalias_returned.ll b/llvm/test/Transforms/FunctionAttrs/noalias_returned.ll deleted file mode 100644 index 587727dc311..00000000000 --- a/llvm/test/Transforms/FunctionAttrs/noalias_returned.ll +++ /dev/null @@ -1,270 +0,0 @@ -; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=3 < %s | FileCheck %s - -; TEST 1 - negative. - -; void *G; -; void *foo(){ -; void *V = malloc(4); -; G = V; -; return V; -; } - -@G = external global i8* - -; CHECK: define i8* @foo() -define i8* @foo() { - %1 = tail call noalias i8* @malloc(i64 4) - store i8* %1, i8** @G, align 8 - ret i8* %1 -} - -declare noalias i8* @malloc(i64) - -; TEST 2 -; call noalias function in return instruction. - -; CHECK: define noalias i8* @return_noalias() -define i8* @return_noalias(){ - %1 = tail call noalias i8* @malloc(i64 4) - ret i8* %1 -} - -define void @nocapture(i8* %a){ - ret void -} - -; CHECK: define noalias i8* @return_noalias_looks_like_capture() -define i8* @return_noalias_looks_like_capture(){ - %1 = tail call noalias i8* @malloc(i64 4) - call void @nocapture(i8* %1) - ret i8* %1 -} - -declare i8* @alias() - -; TEST 3 -; CHECK: define i8* @call_alias() -; CHECK-NOT: noalias -define i8* @call_alias(){ - %1 = tail call i8* @alias() - ret i8* %1 -} - -; TEST 4 -; void *baz(); -; void *foo(int a); -; -; void *bar() { -; foo(0); -; return baz(); -; } -; -; void *foo(int a) { -; if (a) -; bar(); -; return malloc(4); -; } - -; CHECK: define i8* @bar() -define i8* @bar() nounwind uwtable { - %1 = tail call i8* (...) @baz() - ret i8* %1 -} - -; CHECK: define noalias i8* @foo1(i32 %0) -define i8* @foo1(i32 %0) nounwind uwtable { - %2 = icmp eq i32 %0, 0 - br i1 %2, label %5, label %3 - -3: ; preds = %1 - %4 = tail call i8* (...) @baz() - br label %5 - -5: ; preds = %1, %3 - %6 = tail call noalias i8* @malloc(i64 4) - ret i8* %6 -} - -declare i8* @baz(...) nounwind uwtable - -; TEST 5 - -; Returning global pointer. Should not be noalias. -; CHECK: define nonnull align 8 dereferenceable(8) i8** @getter() -define i8** @getter() { - ret i8** @G -} - -; Returning global pointer. Should not be noalias. -; CHECK: define nonnull align 8 dereferenceable(8) i8** @calle1() -define i8** @calle1(){ - %1 = call i8** @getter() - ret i8** %1 -} - -; TEST 6 -declare noalias i8* @strdup(i8* nocapture) nounwind - -; CHECK: define noalias i8* @test6() -define i8* @test6() nounwind uwtable ssp { - %x = alloca [2 x i8], align 1 - %arrayidx = getelementptr inbounds [2 x i8], [2 x i8]* %x, i64 0, i64 0 - store i8 97, i8* %arrayidx, align 1 - %arrayidx1 = getelementptr inbounds [2 x i8], [2 x i8]* %x, i64 0, i64 1 - store i8 0, i8* %arrayidx1, align 1 - %call = call noalias i8* @strdup(i8* %arrayidx) nounwind - ret i8* %call -} - -; TEST 7 - -; CHECK: define noalias i8* @test7() -define i8* @test7() nounwind { -entry: - %A = call noalias i8* @malloc(i64 4) nounwind - %tobool = icmp eq i8* %A, null - br i1 %tobool, label %return, label %if.end - -if.end: - store i8 7, i8* %A - br label %return - -return: - %retval.0 = phi i8* [ %A, %if.end ], [ null, %entry ] - ret i8* %retval.0 -} - -; TEST 8 - -; CHECK: define noalias i8* @test8(i32* %0) -define i8* @test8(i32* %0) nounwind uwtable { - %2 = tail call noalias i8* @malloc(i64 4) - %3 = icmp ne i32* %0, null - br i1 %3, label %4, label %5 - -4: ; preds = %1 - store i8 10, i8* %2 - br label %5 - -5: ; preds = %1, %4 - ret i8* %2 -} - -; TEST 9 -; Simple Argument Test -define internal void @test9(i8* %a, i8* %b) { -; CHECK: define internal void @test9(i8* noalias nocapture nofree readnone %a, i8* nocapture nofree readnone %b) - ret void -} -define void @test9_helper(i8* %a, i8* %b) { - tail call void @test9(i8* noalias %a, i8* %b) - tail call void @test9(i8* noalias %b, i8* noalias %a) - ret void -} - - -; TEST 10 -; Simple CallSite Test - -declare void @test10_helper_1(i8* %a) -define void @test10_helper_2(i8* noalias %a) { -; CHECK: tail call void @test10_helper_1(i8* %a) - tail call void @test10_helper_1(i8* %a) - ret void -} -define void @test10(i8* noalias %a) { -; CHECK: define void @test10(i8* noalias %a) -; FIXME: missing noalias -; CHECK-NEXT: tail call void @test10_helper_1(i8* %a) - tail call void @test10_helper_1(i8* %a) - -; CHECK-NEXT: tail call void @test10_helper_2(i8* noalias %a) - tail call void @test10_helper_2(i8* %a) - ret void -} - -; TEST 11 -; CallSite Test - -declare void @test11_helper(i8* %a, i8 *%b) -define void @test11(i8* noalias %a) { -; CHECK: define void @test11(i8* noalias %a) -; CHECK-NEXT: tail call void @test11_helper(i8* %a, i8* %a) - tail call void @test11_helper(i8* %a, i8* %a) - ret void -} - - -; TEST 12 -; CallSite Argument -declare void @use_nocapture(i8* nocapture) -declare void @use(i8*) -define void @test12_1() { -; CHECK-LABEL: @test12_1( -; CHECK-NEXT: [[A:%.*]] = alloca i8, align 4 -; CHECK-NEXT: [[B:%.*]] = tail call noalias i8* @malloc(i64 4) -; CHECK-NEXT: tail call void @use_nocapture(i8* noalias nonnull align 4 dereferenceable(1) [[A]]) -; CHECK-NEXT: tail call void @use_nocapture(i8* noalias nonnull align 4 dereferenceable(1) [[A]]) -; CHECK-NEXT: tail call void @use_nocapture(i8* noalias nocapture [[B]]) -; CHECK-NEXT: tail call void @use_nocapture(i8* noalias nocapture [[B]]) -; CHECK-NEXT: ret void -; - %A = alloca i8, align 4 - %B = tail call noalias i8* @malloc(i64 4) - tail call void @use_nocapture(i8* %A) - tail call void @use_nocapture(i8* %A) - tail call void @use_nocapture(i8* %B) - tail call void @use_nocapture(i8* %B) - ret void -} - -define void @test12_2(){ -; CHECK-LABEL: @test12_2( -; CHECK-NEXT: [[A:%.*]] = tail call noalias i8* @malloc(i64 4) -; FIXME: This should be @use_nocapture(i8* noalias [[A]]) -; CHECK-NEXT: tail call void @use_nocapture(i8* nocapture [[A]]) -; FIXME: This should be @use_nocapture(i8* noalias nocapture [[A]]) -; CHECK-NEXT: tail call void @use_nocapture(i8* nocapture [[A]]) -; CHECK-NEXT: tail call void @use(i8* [[A]]) -; CHECK-NEXT: tail call void @use_nocapture(i8* nocapture [[A]]) -; CHECK-NEXT: ret void -; - %A = tail call noalias i8* @malloc(i64 4) - tail call void @use_nocapture(i8* %A) - tail call void @use_nocapture(i8* %A) - tail call void @use(i8* %A) - tail call void @use_nocapture(i8* %A) - ret void -} - -declare void @two_args(i8* nocapture , i8* nocapture) -define void @test12_3(){ -; CHECK-LABEL: @test12_3( - %A = tail call noalias i8* @malloc(i64 4) -; CHECK: tail call void @two_args(i8* nocapture %A, i8* nocapture %A) - tail call void @two_args(i8* %A, i8* %A) - ret void -} - -define void @test12_4(){ -; CHECK-LABEL: @test12_4( - %A = tail call noalias i8* @malloc(i64 4) - %B = tail call noalias i8* @malloc(i64 4) - %A_0 = getelementptr i8, i8* %A, i64 0 - %A_1 = getelementptr i8, i8* %A, i64 1 - %B_0 = getelementptr i8, i8* %B, i64 0 - -; CHECK: tail call void @two_args(i8* noalias nocapture %A, i8* noalias nocapture %B) - tail call void @two_args(i8* %A, i8* %B) - -; CHECK: tail call void @two_args(i8* nocapture %A, i8* nocapture %A_0) - tail call void @two_args(i8* %A, i8* %A_0) - -; CHECK: tail call void @two_args(i8* nocapture %A, i8* nocapture %A_1) - tail call void @two_args(i8* %A, i8* %A_1) - -; FIXME: This should be @two_args(i8* noalias nocapture %A_0, i8* noalias nocapture %B_0) -; CHECK: tail call void @two_args(i8* nocapture %A_0, i8* nocapture %B_0) - tail call void @two_args(i8* %A_0, i8* %B_0) - ret void -} diff --git a/llvm/test/Transforms/FunctionAttrs/nocapture.ll b/llvm/test/Transforms/FunctionAttrs/nocapture.ll index a78af104167..25759cffe13 100644 --- a/llvm/test/Transforms/FunctionAttrs/nocapture.ll +++ b/llvm/test/Transforms/FunctionAttrs/nocapture.ll @@ -1,18 +1,14 @@ -; RUN: opt -functionattrs -S < %s | FileCheck %s --check-prefixes=FNATTR,EITHER -; RUN: opt -passes=function-attrs -S < %s | FileCheck %s --check-prefixes=FNATTR,EITHER -; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -S -attributor-annotate-decl-cs < %s | FileCheck %s --check-prefixes=ATTRIBUTOR,EITHER -; RUN: opt -passes=attributor -attributor-manifest-internal -attributor-disable=false -S -attributor-annotate-decl-cs < %s | FileCheck %s --check-prefixes=ATTRIBUTOR,EITHER +; RUN: opt -functionattrs -S < %s | FileCheck %s --check-prefixes=FNATTR +; RUN: opt -passes=function-attrs -S < %s | FileCheck %s --check-prefixes=FNATTR @g = global i32* null ; <i32**> [#uses=1] ; FNATTR: define i32* @c1(i32* readnone returned %q) -; ATTRIBUTOR: define i32* @c1(i32* nofree readnone returned "no-capture-maybe-returned" %q) define i32* @c1(i32* %q) { ret i32* %q } ; FNATTR: define void @c2(i32* %q) -; ATTRIBUTOR: define void @c2(i32* nofree writeonly %q) ; It would also be acceptable to mark %q as readnone. Update @c3 too. define void @c2(i32* %q) { store i32* %q, i32** @g @@ -20,14 +16,12 @@ define void @c2(i32* %q) { } ; FNATTR: define void @c3(i32* %q) -; ATTRIBUTOR: define void @c3(i32* nofree writeonly %q) define void @c3(i32* %q) { call void @c2(i32* %q) ret void } ; FNATTR: define i1 @c4(i32* %q, i32 %bitno) -; ATTRIBUTOR: define i1 @c4(i32* nofree readnone %q, i32 %bitno) define i1 @c4(i32* %q, i32 %bitno) { %tmp = ptrtoint i32* %q to i32 %tmp2 = lshr i32 %tmp, %bitno @@ -41,7 +35,6 @@ l1: ; c4b is c4 but without the escaping part ; FNATTR: define i1 @c4b(i32* %q, i32 %bitno) -; ATTRIBUTOR: define i1 @c4b(i32* nocapture nofree readnone %q, i32 %bitno) define i1 @c4b(i32* %q, i32 %bitno) { %tmp = ptrtoint i32* %q to i32 %tmp2 = lshr i32 %tmp, %bitno @@ -56,7 +49,6 @@ l1: @lookup_table = global [2 x i1] [ i1 0, i1 1 ] ; FNATTR: define i1 @c5(i32* %q, i32 %bitno) -; ATTRIBUTOR: define i1 @c5(i32* nofree readonly %q, i32 %bitno) define i1 @c5(i32* %q, i32 %bitno) { %tmp = ptrtoint i32* %q to i32 %tmp2 = lshr i32 %tmp, %bitno @@ -69,7 +61,7 @@ define i1 @c5(i32* %q, i32 %bitno) { declare void @throw_if_bit_set(i8*, i8) readonly -; EITHER: define i1 @c6(i8* readonly %q, i8 %bit) +; FNATTR: define i1 @c6(i8* readonly %q, i8 %bit) define i1 @c6(i8* %q, i8 %bit) personality i32 (...)* @__gxx_personality_v0 { invoke void @throw_if_bit_set(i8* %q, i8 %bit) to label %ret0 unwind label %ret1 @@ -92,7 +84,6 @@ define i1* @lookup_bit(i32* %q, i32 %bitno) readnone nounwind { } ; FNATTR: define i1 @c7(i32* readonly %q, i32 %bitno) -; ATTRIBUTOR: define i1 @c7(i32* nofree readonly %q, i32 %bitno) define i1 @c7(i32* %q, i32 %bitno) { %ptr = call i1* @lookup_bit(i32* %q, i32 %bitno) %val = load i1, i1* %ptr @@ -101,7 +92,6 @@ define i1 @c7(i32* %q, i32 %bitno) { ; FNATTR: define i32 @nc1(i32* %q, i32* nocapture %p, i1 %b) -; ATTRIBUTOR: define i32 @nc1(i32* nofree %q, i32* nocapture nofree %p, i1 %b) define i32 @nc1(i32* %q, i32* %p, i1 %b) { e: br label %l @@ -117,7 +107,6 @@ l: } ; FNATTR: define i32 @nc1_addrspace(i32* %q, i32 addrspace(1)* nocapture %p, i1 %b) -; ATTRIBUTOR: define i32 @nc1_addrspace(i32* nofree %q, i32 addrspace(1)* nocapture nofree %p, i1 %b) define i32 @nc1_addrspace(i32* %q, i32 addrspace(1)* %p, i1 %b) { e: br label %l @@ -133,7 +122,6 @@ l: } ; FNATTR: define void @nc2(i32* nocapture %p, i32* %q) -; ATTRIBUTOR: define void @nc2(i32* nocapture nofree %p, i32* nofree %q) define void @nc2(i32* %p, i32* %q) { %1 = call i32 @nc1(i32* %q, i32* %p, i1 0) ; <i32> [#uses=0] ret void @@ -141,21 +129,19 @@ define void @nc2(i32* %p, i32* %q) { ; FNATTR: define void @nc3(void ()* nocapture %p) -; ATTRIBUTOR: define void @nc3(void ()* nocapture nofree nonnull %p) define void @nc3(void ()* %p) { call void %p() ret void } declare void @external(i8*) readonly nounwind -; EITHER: define void @nc4(i8* nocapture readonly %p) +; FNATTR: define void @nc4(i8* nocapture readonly %p) define void @nc4(i8* %p) { call void @external(i8* %p) ret void } ; FNATTR: define void @nc5(void (i8*)* nocapture %f, i8* nocapture %p) -; ATTRIBUTOR: define void @nc5(void (i8*)* nocapture nofree nonnull %f, i8* nocapture %p) define void @nc5(void (i8*)* %f, i8* %p) { call void %f(i8* %p) readonly nounwind call void %f(i8* nocapture %p) @@ -163,7 +149,6 @@ define void @nc5(void (i8*)* %f, i8* %p) { } ; FNATTR: define void @test1_1(i8* nocapture readnone %x1_1, i8* %y1_1, i1 %c) -; ATTRIBUTOR: define void @test1_1(i8* nocapture nofree readnone %x1_1, i8* nocapture nofree readnone %y1_1, i1 %c) ; It would be acceptable to add readnone to %y1_1 and %y1_2. define void @test1_1(i8* %x1_1, i8* %y1_1, i1 %c) { call i8* @test1_2(i8* %x1_1, i8* %y1_1, i1 %c) @@ -172,7 +157,6 @@ define void @test1_1(i8* %x1_1, i8* %y1_1, i1 %c) { } ; FNATTR: define i8* @test1_2(i8* nocapture readnone %x1_2, i8* returned %y1_2, i1 %c) -; ATTRIBUTOR: define i8* @test1_2(i8* nocapture nofree readnone %x1_2, i8* nofree readnone returned "no-capture-maybe-returned" %y1_2, i1 %c) define i8* @test1_2(i8* %x1_2, i8* %y1_2, i1 %c) { br i1 %c, label %t, label %f t: @@ -184,7 +168,6 @@ f: } ; FNATTR: define void @test2(i8* nocapture readnone %x2) -; ATTRIBUTOR: define void @test2(i8* nocapture nofree readnone %x2) define void @test2(i8* %x2) { call void @test2(i8* %x2) store i32* null, i32** @g @@ -192,7 +175,6 @@ define void @test2(i8* %x2) { } ; FNATTR: define void @test3(i8* nocapture readnone %x3, i8* nocapture readnone %y3, i8* nocapture readnone %z3) -; ATTRIBUTOR: define void @test3(i8* nocapture nofree readnone %x3, i8* nocapture nofree readnone %y3, i8* nocapture nofree readnone %z3) define void @test3(i8* %x3, i8* %y3, i8* %z3) { call void @test3(i8* %z3, i8* %y3, i8* %x3) store i32* null, i32** @g @@ -200,7 +182,6 @@ define void @test3(i8* %x3, i8* %y3, i8* %z3) { } ; FNATTR: define void @test4_1(i8* %x4_1, i1 %c) -; ATTRIBUTOR: define void @test4_1(i8* nocapture nofree readnone %x4_1, i1 %c) define void @test4_1(i8* %x4_1, i1 %c) { call i8* @test4_2(i8* %x4_1, i8* %x4_1, i8* %x4_1, i1 %c) store i32* null, i32** @g @@ -208,7 +189,6 @@ define void @test4_1(i8* %x4_1, i1 %c) { } ; FNATTR: define i8* @test4_2(i8* nocapture readnone %x4_2, i8* readnone returned %y4_2, i8* nocapture readnone %z4_2, i1 %c) -; ATTRIBUTOR: define i8* @test4_2(i8* nocapture nofree readnone %x4_2, i8* nofree readnone returned "no-capture-maybe-returned" %y4_2, i8* nocapture nofree readnone %z4_2, i1 %c) define i8* @test4_2(i8* %x4_2, i8* %y4_2, i8* %z4_2, i1 %c) { br i1 %c, label %t, label %f t: @@ -221,7 +201,7 @@ f: declare i8* @test5_1(i8* %x5_1) -; EITHER: define void @test5_2(i8* %x5_2) +; FNATTR: define void @test5_2(i8* %x5_2) define void @test5_2(i8* %x5_2) { call i8* @test5_1(i8* %x5_2) store i32* null, i32** @g @@ -230,7 +210,7 @@ define void @test5_2(i8* %x5_2) { declare void @test6_1(i8* %x6_1, i8* nocapture %y6_1, ...) -; EITHER: define void @test6_2(i8* %x6_2, i8* nocapture %y6_2, i8* %z6_2) +; FNATTR: define void @test6_2(i8* %x6_2, i8* nocapture %y6_2, i8* %z6_2) define void @test6_2(i8* %x6_2, i8* %y6_2, i8* %z6_2) { call void (i8*, i8*, ...) @test6_1(i8* %x6_2, i8* %y6_2, i8* %z6_2) store i32* null, i32** @g @@ -238,28 +218,24 @@ define void @test6_2(i8* %x6_2, i8* %y6_2, i8* %z6_2) { } ; FNATTR: define void @test_cmpxchg(i32* nocapture %p) -; ATTRIBUTOR: define void @test_cmpxchg(i32* nocapture nofree nonnull dereferenceable(4) %p) define void @test_cmpxchg(i32* %p) { cmpxchg i32* %p, i32 0, i32 1 acquire monotonic ret void } ; FNATTR: define void @test_cmpxchg_ptr(i32** nocapture %p, i32* %q) -; ATTRIBUTOR: define void @test_cmpxchg_ptr(i32** nocapture nofree nonnull dereferenceable(8) %p, i32* nofree %q) define void @test_cmpxchg_ptr(i32** %p, i32* %q) { cmpxchg i32** %p, i32* null, i32* %q acquire monotonic ret void } ; FNATTR: define void @test_atomicrmw(i32* nocapture %p) -; ATTRIBUTOR: define void @test_atomicrmw(i32* nocapture nofree nonnull dereferenceable(4) %p) define void @test_atomicrmw(i32* %p) { atomicrmw add i32* %p, i32 1 seq_cst ret void } ; FNATTR: define void @test_volatile(i32* %x) -; ATTRIBUTOR: define void @test_volatile(i32* nofree align 4 %x) define void @test_volatile(i32* %x) { entry: %gep = getelementptr i32, i32* %x, i64 1 @@ -267,7 +243,7 @@ entry: ret void } -; EITHER: nocaptureLaunder(i8* nocapture %p) +; FNATTR: nocaptureLaunder(i8* nocapture %p) define void @nocaptureLaunder(i8* %p) { entry: %b = call i8* @llvm.launder.invariant.group.p0i8(i8* %p) @@ -276,7 +252,7 @@ entry: } @g2 = global i8* null -; EITHER: define void @captureLaunder(i8* %p) +; FNATTR: define void @captureLaunder(i8* %p) define void @captureLaunder(i8* %p) { %b = call i8* @llvm.launder.invariant.group.p0i8(i8* %p) store i8* %b, i8** @g2 @@ -284,7 +260,6 @@ define void @captureLaunder(i8* %p) { } ; FNATTR: @nocaptureStrip(i8* nocapture %p) -; ATTRIBUTOR: @nocaptureStrip(i8* nocapture writeonly %p) define void @nocaptureStrip(i8* %p) { entry: %b = call i8* @llvm.strip.invariant.group.p0i8(i8* %p) @@ -294,7 +269,6 @@ entry: @g3 = global i8* null ; FNATTR: define void @captureStrip(i8* %p) -; ATTRIBUTOR: define void @captureStrip(i8* writeonly %p) define void @captureStrip(i8* %p) { %b = call i8* @llvm.strip.invariant.group.p0i8(i8* %p) store i8* %b, i8** @g3 @@ -302,21 +276,18 @@ define void @captureStrip(i8* %p) { } ; FNATTR: define i1 @captureICmp(i32* readnone %x) -; ATTRIBUTOR: define i1 @captureICmp(i32* nofree readnone %x) define i1 @captureICmp(i32* %x) { %1 = icmp eq i32* %x, null ret i1 %1 } ; FNATTR: define i1 @captureICmpRev(i32* readnone %x) -; ATTRIBUTOR: define i1 @captureICmpRev(i32* nofree readnone %x) define i1 @captureICmpRev(i32* %x) { %1 = icmp eq i32* null, %x ret i1 %1 } ; FNATTR: define i1 @nocaptureInboundsGEPICmp(i32* nocapture readnone %x) -; ATTRIBUTOR: define i1 @nocaptureInboundsGEPICmp(i32* nocapture nofree nonnull readnone %x) define i1 @nocaptureInboundsGEPICmp(i32* %x) { %1 = getelementptr inbounds i32, i32* %x, i32 5 %2 = bitcast i32* %1 to i8* @@ -325,7 +296,6 @@ define i1 @nocaptureInboundsGEPICmp(i32* %x) { } ; FNATTR: define i1 @nocaptureInboundsGEPICmpRev(i32* nocapture readnone %x) -; ATTRIBUTOR: define i1 @nocaptureInboundsGEPICmpRev(i32* nocapture nofree nonnull readnone %x) define i1 @nocaptureInboundsGEPICmpRev(i32* %x) { %1 = getelementptr inbounds i32, i32* %x, i32 5 %2 = bitcast i32* %1 to i8* @@ -334,7 +304,6 @@ define i1 @nocaptureInboundsGEPICmpRev(i32* %x) { } ; FNATTR: define i1 @nocaptureDereferenceableOrNullICmp(i32* nocapture readnone dereferenceable_or_null(4) %x) -; ATTRIBUTOR: define i1 @nocaptureDereferenceableOrNullICmp(i32* nocapture nofree readnone dereferenceable_or_null(4) %x) define i1 @nocaptureDereferenceableOrNullICmp(i32* dereferenceable_or_null(4) %x) { %1 = bitcast i32* %x to i8* %2 = icmp eq i8* %1, null @@ -342,36 +311,11 @@ define i1 @nocaptureDereferenceableOrNullICmp(i32* dereferenceable_or_null(4) %x } ; FNATTR: define i1 @captureDereferenceableOrNullICmp(i32* readnone dereferenceable_or_null(4) %x) -; ATTRIBUTOR: define i1 @captureDereferenceableOrNullICmp(i32* nofree readnone dereferenceable_or_null(4) %x) define i1 @captureDereferenceableOrNullICmp(i32* dereferenceable_or_null(4) %x) "null-pointer-is-valid"="true" { %1 = bitcast i32* %x to i8* %2 = icmp eq i8* %1, null ret i1 %2 } -declare void @unknown(i8*) -define void @test_callsite() { -entry: -; We know that 'null' in AS 0 does not alias anything and cannot be captured. Though the latter is not qurried -> derived atm. -; ATTRIBUTOR: call void @unknown(i8* noalias null) - call void @unknown(i8* null) - ret void -} - -declare i8* @unknownpi8pi8(i8*,i8* returned) -define i8* @test_returned1(i8* %A, i8* returned %B) nounwind readonly { -; ATTRIBUTOR: define i8* @test_returned1(i8* nocapture readonly %A, i8* readonly returned %B) -entry: - %p = call i8* @unknownpi8pi8(i8* %A, i8* %B) - ret i8* %p -} - -define i8* @test_returned2(i8* %A, i8* %B) { -; ATTRIBUTOR: define i8* @test_returned2(i8* nocapture readonly %A, i8* readonly returned %B) -entry: - %p = call i8* @unknownpi8pi8(i8* %A, i8* %B) nounwind readonly - ret i8* %p -} - declare i8* @llvm.launder.invariant.group.p0i8(i8*) declare i8* @llvm.strip.invariant.group.p0i8(i8*) diff --git a/llvm/test/Transforms/FunctionAttrs/nofree-attributor.ll b/llvm/test/Transforms/FunctionAttrs/nofree-attributor.ll index 1c007ee11b4..8ac037e5cd8 100644 --- a/llvm/test/Transforms/FunctionAttrs/nofree-attributor.ll +++ b/llvm/test/Transforms/FunctionAttrs/nofree-attributor.ll @@ -1,5 +1,4 @@ ; RUN: opt -functionattrs --disable-nofree-inference=false -S < %s | FileCheck %s --check-prefix=FNATTR -; RUN: opt -attributor --attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefix=ATTRIBUTOR target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" @@ -15,8 +14,6 @@ declare void @_ZdaPv(i8*) local_unnamed_addr #2 ; TEST 1 (positive case) ; FNATTR: Function Attrs: noinline norecurse nounwind readnone uwtable ; FNATTR-NEXT: define void @only_return() -; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable -; ATTRIBUTOR-NEXT: define void @only_return() define void @only_return() #0 { ret void } @@ -30,9 +27,6 @@ define void @only_return() #0 { ; FNATTR: Function Attrs: noinline nounwind uwtable ; FNATTR-NEXT: define void @only_free(i8* nocapture %0) local_unnamed_addr -; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable -; ATTRIBUTOR-NOT: nofree -; ATTRIBUTOR-NEXT: define void @only_free(i8* nocapture %0) local_unnamed_addr #1 define void @only_free(i8* nocapture %0) local_unnamed_addr #0 { tail call void @free(i8* %0) #1 ret void @@ -52,9 +46,6 @@ define void @only_free(i8* nocapture %0) local_unnamed_addr #0 { ; FNATTR: Function Attrs: noinline nounwind uwtable ; FNATTR-NEXT: define void @free_in_scc1(i8* nocapture %0) local_unnamed_addr -; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable -; ATTRIBUTOR-NOT: nofree -; ATTRIBUTOR-NEXT :define void @free_in_scc1(i8* nocapture %0) local_unnamed_addr define void @free_in_scc1(i8* nocapture %0) local_unnamed_addr #0 { tail call void @free_in_scc2(i8* %0) #1 ret void @@ -63,9 +54,6 @@ define void @free_in_scc1(i8* nocapture %0) local_unnamed_addr #0 { ; FNATTR: Function Attrs: noinline nounwind uwtable ; FNATTR-NEXT: define void @free_in_scc2(i8* nocapture %0) local_unnamed_addr -; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable -; ATTRIBUTOR-NOT: nofree -; ATTRIBUTOR: define void @free_in_scc2(i8* nocapture %0) local_unnamed_addr define void @free_in_scc2(i8* nocapture %0) local_unnamed_addr #0 { %cmp = icmp eq i8* %0, null br i1 %cmp, label %rec, label %call @@ -92,8 +80,6 @@ end: ; FNATTR: Function Attrs: noinline nounwind readnone uwtable ; FNATTR-NEXT: define void @mutual_recursion1() -; ATTRIBUTOR: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable -; ATTRIBUTOR-NEXT: define void @mutual_recursion1() define void @mutual_recursion1() #0 { call void @mutual_recursion2() ret void @@ -101,8 +87,6 @@ define void @mutual_recursion1() #0 { ; FNATTR: Function Attrs: noinline nounwind readnone uwtable ; FNATTR-NEXT: define void @mutual_recursion2() -; ATTRIBUTOR: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable -; ATTRIBUTOR-NEXT: define void @mutual_recursion2() define void @mutual_recursion2() #0 { call void @mutual_recursion1() ret void @@ -117,9 +101,6 @@ define void @mutual_recursion2() #0 { ; FNATTR: Function Attrs: noinline nounwind uwtable ; FNATTR-NEXT: define void @_Z9delete_opPc(i8* %0) local_unnamed_addr -; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable -; ATTRIBUTOR-NOT: nofree -; ATTRIBUTOR-NEXT: define void @_Z9delete_opPc(i8* %0) local_unnamed_addr #1 define void @_Z9delete_opPc(i8* %0) local_unnamed_addr #0 { %2 = icmp eq i8* %0, null br i1 %2, label %4, label %3 @@ -137,9 +118,6 @@ define void @_Z9delete_opPc(i8* %0) local_unnamed_addr #0 { ; Call realloc ; FNATTR: Function Attrs: noinline nounwind uwtable ; FNATTR-NEXT: define noalias i8* @call_realloc(i8* nocapture %0, i64 %1) local_unnamed_addr -; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable -; ATTRIBUTOR-NOT: nofree -; ATTRIBUTOR-NEXT: define noalias i8* @call_realloc(i8* nocapture %0, i64 %1) local_unnamed_addr define noalias i8* @call_realloc(i8* nocapture %0, i64 %1) local_unnamed_addr #0 { %ret = tail call i8* @realloc(i8* %0, i64 %1) #2 ret i8* %ret @@ -152,14 +130,10 @@ define noalias i8* @call_realloc(i8* nocapture %0, i64 %1) local_unnamed_addr #0 ; FNATTR: Function Attrs: nofree noinline nounwind readnone uwtable ; FNATTR-NEXT: declare void @nofree_function() -; ATTRIBUTOR: Function Attrs: nofree noinline nounwind readnone uwtable -; ATTRIBUTOR-NEXT: declare void @nofree_function() declare void @nofree_function() nofree readnone #0 ; FNATTR: Function Attrs: noinline nounwind readnone uwtable ; FNATTR-NEXT: define void @call_nofree_function() -; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable -; ATTRIBUTOR-NEXT: define void @call_nofree_function() define void @call_nofree_function() #0 { tail call void @nofree_function() ret void @@ -169,16 +143,11 @@ define void @call_nofree_function() #0 { ; Call function declaration without "nofree" -; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable -; ATTRIBUTOR-NEXT: declare void @maybe_free() declare void @maybe_free() #0 ; FNATTR: Function Attrs: noinline nounwind uwtable ; FNATTR: define void @call_maybe_free() -; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable -; ATTRIBUTOR-NOT: nofree -; ATTRIBUTOR-NEXT: define void @call_maybe_free() define void @call_maybe_free() #0 { tail call void @maybe_free() ret void @@ -190,9 +159,6 @@ define void @call_maybe_free() #0 { ; FNATTR: Function Attrs: noinline nounwind uwtable ; FNATTR-NEXT: define void @call_both() -; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable -; ATTRIBUTOR-NOT: nofree -; ATTRIBUTOR-NEXT: define void @call_both() define void @call_both() #0 { tail call void @maybe_free() tail call void @nofree_function() @@ -204,15 +170,11 @@ define void @call_both() #0 { ; Call intrinsic function ; FNATTRS: Function Attrs: noinline readnone speculatable ; FNATTRS-NEXT: declare float @llvm.floor.f32(float %0) -; ATTRIBUTOR: Function Attrs: nounwind readnone speculatable -; ATTRIBUTOR-NEXT: declare float @llvm.floor.f32(float) declare float @llvm.floor.f32(float) ; FNATTRS: Function Attrs: noinline nounwind uwtable ; FNATTRS-NEXT: define void @call_floor(float %a) ; FIXME: missing nofree -; ATTRIBUTOR: Function Attrs: noinline nosync nounwind readnone uwtable -; ATTRIBUTOR-NEXT: define void @call_floor(float %a) define void @call_floor(float %a) #0 { tail call float @llvm.floor.f32(float %a) @@ -224,8 +186,6 @@ define void @call_floor(float %a) #0 { ; FNATTRS: Function Attrs: noinline nounwind uwtable ; FNATTRS-NEXT: define void @f1() -; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable -; ATTRIBUTOR-NEXT: define void @f1() define void @f1() #0 { tail call void @nofree_function() ret void @@ -233,40 +193,11 @@ define void @f1() #0 { ; FNATTRS: Function Attrs: noinline nounwind uwtable ; FNATTRS-NEXT: define void @f2() -; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable -; ATTRIBUTOR-NEXT: define void @f2() define void @f2() #0 { tail call void @f1() ret void } -; TEST 12 NoFree argument - positive. -; ATTRIBUTOR: define double @test12(double* nocapture nofree nonnull readonly align 8 dereferenceable(8) %a) -define double @test12(double* nocapture readonly %a) { -entry: - %0 = load double, double* %a, align 8 - %call = tail call double @cos(double %0) #2 - ret double %call -} - -declare double @cos(double) nobuiltin nounwind nofree - -; FIXME: %a should be nofree. -; TEST 13 NoFree argument - positive. -; ATTRIBUTOR: define noalias i32* @test13(i64* nocapture nonnull readonly align 8 dereferenceable(8) %a) -define noalias i32* @test13(i64* nocapture readonly %a) { -entry: - %0 = load i64, i64* %a, align 8 - %call = tail call noalias i8* @malloc(i64 %0) #2 - %1 = bitcast i8* %call to i32* - ret i32* %1 -} - -; ATTRIBUTOR: define void @test14(i8* nocapture %0, i8* nocapture nofree readnone %1) -define void @test14(i8* nocapture %0, i8* nocapture %1) { - tail call void @free(i8* %0) #1 - ret void -} declare noalias i8* @malloc(i64) diff --git a/llvm/test/Transforms/FunctionAttrs/nonnull.ll b/llvm/test/Transforms/FunctionAttrs/nonnull.ll index 42923cee770..128a2bdbe50 100644 --- a/llvm/test/Transforms/FunctionAttrs/nonnull.ll +++ b/llvm/test/Transforms/FunctionAttrs/nonnull.ll @@ -1,8 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt -S -functionattrs -enable-nonnull-arg-prop %s | FileCheck %s --check-prefixes=BOTH,FNATTR,OLD -; RUN: opt -S -passes=function-attrs -enable-nonnull-arg-prop %s | FileCheck %s --check-prefixes=BOTH,FNATTR,OLD -; RUN: opt -attributor --attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=5 -S < %s | FileCheck %s --check-prefixes=BOTH,OLD,ATTRIBUTOR,ATTRIBUTOR_OPM -; RUN: opt -passes=attributor --attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=5 -S < %s | FileCheck %s --check-prefixes=BOTH,ATTRIBUTOR,ATTRIBUTOR_NPM +; RUN: opt -S -functionattrs -enable-nonnull-arg-prop %s | FileCheck %s --check-prefixes=FNATTR +; RUN: opt -S -passes=function-attrs -enable-nonnull-arg-prop %s | FileCheck %s --check-prefixes=FNATTR target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" @@ -10,14 +8,14 @@ declare nonnull i8* @ret_nonnull() ; Return a pointer trivially nonnull (call return attribute) define i8* @test1() { -; BOTH: define nonnull i8* @test1 +; FNATTR: define nonnull i8* @test1 %ret = call i8* @ret_nonnull() ret i8* %ret } ; Return a pointer trivially nonnull (argument attribute) define i8* @test2(i8* nonnull %p) { -; BOTH: define nonnull i8* @test2 +; FNATTR: define nonnull i8* @test2 ret i8* %p } @@ -25,7 +23,6 @@ define i8* @test2(i8* nonnull %p) { ; can we still mark the other one which is trivially nonnull define i8* @scc_binder(i1 %c) { ; FNATTR: define i8* @scc_binder -; ATTRIBUTOR: define noalias i8* @scc_binder br i1 %c, label %rec, label %end rec: call i8* @test3(i1 %c) @@ -35,7 +32,7 @@ end: } define i8* @test3(i1 %c) { -; BOTH: define nonnull i8* @test3 +; FNATTR: define nonnull i8* @test3 call i8* @scc_binder(i1 %c) %ret = call i8* @ret_nonnull() ret i8* %ret @@ -46,14 +43,12 @@ define i8* @test3(i1 %c) { ; just never return period.) define i8* @test4_helper() { ; FNATTR: define noalias nonnull i8* @test4_helper -; ATTRIBUTOR: define noalias nonnull align 536870912 dereferenceable(4294967295) i8* @test4_helper %ret = call i8* @test4() ret i8* %ret } define i8* @test4() { ; FNATTR: define noalias nonnull i8* @test4 -; ATTRIBUTOR: define noalias nonnull align 536870912 dereferenceable(4294967295) i8* @test4 %ret = call i8* @test4_helper() ret i8* %ret } @@ -62,7 +57,6 @@ define i8* @test4() { ; make sure we haven't marked them as nonnull. define i8* @test5_helper(i1 %c) { ; FNATTR: define noalias i8* @test5_helper -; ATTRIBUTOR: define noalias i8* @test5_helper br i1 %c, label %rec, label %end rec: %ret = call i8* @test5(i1 %c) @@ -73,14 +67,11 @@ end: define i8* @test5(i1 %c) { ; FNATTR: define noalias i8* @test5 -; ATTRIBUTOR: define noalias i8* @test5 %ret = call i8* @test5_helper(i1 %c) ret i8* %ret } ; Local analysis, but going through a self recursive phi -; ATTRIBUTOR: Function Attrs: noreturn -; ATTRIBUTOR: define noalias nonnull align 536870912 dereferenceable(4294967295) i8* @test6a() define i8* @test6a() { entry: %ret = call i8* @ret_nonnull() @@ -92,7 +83,6 @@ exit: ret i8* %phi } -; ATTRIBUTOR: define nonnull i8* @test6b(i1 %c) define i8* @test6b(i1 %c) { entry: %ret = call i8* @ret_nonnull() @@ -104,19 +94,19 @@ exit: ret i8* %phi } -; BOTH: define i8* @test7 +; FNATTR: define i8* @test7 define i8* @test7(i8* %a) { %b = getelementptr inbounds i8, i8* %a, i64 0 ret i8* %b } -; BOTH: define nonnull i8* @test8 +; FNATTR: define nonnull i8* @test8 define i8* @test8(i8* %a) { %b = getelementptr inbounds i8, i8* %a, i64 1 ret i8* %b } -; BOTH: define i8* @test9 +; FNATTR: define i8* @test9 define i8* @test9(i8* %a, i64 %n) { %b = getelementptr inbounds i8, i8* %a, i64 %n ret i8* %b @@ -125,7 +115,6 @@ define i8* @test9(i8* %a, i64 %n) { declare void @llvm.assume(i1) ; FNATTR: define i8* @test10 ; FIXME: missing nonnull -; ATTRIBUTOR: define i8* @test10 define i8* @test10(i8* %a, i64 %n) { %cmp = icmp ne i64 %n, 0 call void @llvm.assume(i1 %cmp) @@ -139,7 +128,6 @@ define i8* @test10(i8* %a, i64 %n) { ; } ; FNATTR: define i8* @test11 ; FIXME: missing nonnull -; ATTRIBUTOR: define i8* @test11 define i8* @test11(i8*) local_unnamed_addr { %2 = icmp eq i8* %0, null br i1 %2, label %3, label %5 @@ -157,8 +145,6 @@ define i8* @test11(i8*) local_unnamed_addr { ; Simple CallSite Test declare void @test12_helper(i8*) define void @test12(i8* nonnull %a) { -; ATTRIBUTOR: define void @test12(i8* nonnull %a) -; ATTRIBUTOR-NEXT: tail call void @test12_helper(i8* nonnull %a) tail call void @test12_helper(i8* %a) ret void } @@ -174,7 +160,6 @@ define void @test13_helper() { ret void } define internal void @test13(i8* %a, i8* %b, i8* %c) { -; ATTRIBUTOR: define internal void @test13(i8* nocapture nofree nonnull readnone %a, i8* nocapture nofree readnone %b, i8* nocapture nofree readnone %c) ret void } @@ -194,7 +179,6 @@ declare nonnull i8* @nonnull() define internal i32* @f1(i32* %arg) { ; FIXME: missing nonnull It should be nonnull @f1(i32* nonnull readonly %arg) -; ATTRIBUTOR: define internal nonnull i32* @f1(i32* nofree readonly %arg) bb: %tmp = icmp eq i32* %arg, null @@ -207,14 +191,12 @@ bb1: ; preds = %bb bb4: ; preds = %bb1 %tmp5 = getelementptr inbounds i32, i32* %arg, i64 1 -; ATTRIBUTOR: %tmp5b = tail call nonnull i32* @f3(i32* nofree nonnull %tmp5) %tmp5b = tail call i32* @f3(i32* %tmp5) %tmp5c = getelementptr inbounds i32, i32* %tmp5b, i64 -1 br label %bb9 bb6: ; preds = %bb1 ; FIXME: missing nonnull. It should be @f2(i32* nonnull %arg) -; ATTRIBUTOR: %tmp7 = tail call nonnull i32* @f2(i32* nofree %arg) %tmp7 = tail call i32* @f2(i32* %arg) ret i32* %tmp7 @@ -225,28 +207,23 @@ bb9: ; preds = %bb4, %bb define internal i32* @f2(i32* %arg) { ; FIXME: missing nonnull. It should be nonnull @f2(i32* nonnull %arg) -; ATTRIBUTOR: define internal nonnull i32* @f2(i32* nofree readonly %arg) bb: ; FIXME: missing nonnull. It should be @f1(i32* nonnull readonly %arg) -; ATTRIBUTOR: %tmp = tail call nonnull i32* @f1(i32* nofree %arg) %tmp = tail call i32* @f1(i32* %arg) ret i32* %tmp } define dso_local noalias i32* @f3(i32* %arg) { ; FIXME: missing nonnull. It should be nonnull @f3(i32* nonnull readonly %arg) -; ATTRIBUTOR: define dso_local noalias nonnull i32* @f3(i32* nofree readonly %arg) bb: ; FIXME: missing nonnull. It should be @f1(i32* nonnull readonly %arg) -; ATTRIBUTOR: %tmp = call nonnull i32* @f1(i32* nofree %arg) %tmp = call i32* @f1(i32* %arg) ret i32* %tmp } ; TEST 15 define void @f15(i8* %arg) { -; ATTRIBUTOR: tail call void @use1(i8* nonnull dereferenceable(4) %arg) tail call void @use1(i8* dereferenceable(4) %arg) ret void @@ -264,7 +241,6 @@ declare void @fun3(i8*, i8*, i8*) #1 ; We can say that %a is nonnull but %b is not. define void @f16(i8* %a, i8 * %b, i8 %c) { ; FIXME: missing nonnull on %a -; ATTRIBUTOR: define void @f16(i8* %a, i8* %b, i8 %c) %cmp = icmp eq i8 %c, 0 br i1 %cmp, label %if.then, label %if.else if.then: @@ -282,7 +258,6 @@ if.else: ; fun1(nonnull %a) ; We can say that %a is nonnull define void @f17(i8* %a, i8 %c) { -; ATTRIBUTOR: define void @f17(i8* nonnull %a, i8 %c) %cmp = icmp eq i8 %c, 0 br i1 %cmp, label %if.then, label %if.else if.then: @@ -307,7 +282,6 @@ cont: ; fun1(nonnull %a) define void @f18(i8* %a, i8* %b, i8 %c) { -; ATTRIBUTOR: define void @f18(i8* nonnull %a, i8* %b, i8 %c) %cmp1 = icmp eq i8 %c, 0 br i1 %cmp1, label %if.then, label %if.else if.then: @@ -334,7 +308,6 @@ cont2: define void @f19(i8* %a, i8* %b, i8 %c) { ; FIXME: missing nonnull on %b -; ATTRIBUTOR: define void @f19(i8* %a, i8* %b, i8 %c) br label %loop.header loop.header: %cmp2 = icmp eq i8 %c, 0 @@ -363,11 +336,10 @@ declare i8 @use1safecall(i8* %x) readonly nounwind ; readonly+nounwind guarantee ; Can't extend non-null to parent for any argument because the 2nd call is not guaranteed to execute. define void @parent1(i8* %a, i8* %b, i8* %c) { -; BOTH-LABEL: @parent1(i8* %a, i8* %b, i8* %c) -; BOTH-NEXT: call void @use3(i8* %c, i8* %a, i8* %b) +; FNATTR-LABEL: @parent1(i8* %a, i8* %b, i8* %c) +; FNATTR-NEXT: call void @use3(i8* %c, i8* %a, i8* %b) ; FNATTR-NEXT: call void @use3nonnull(i8* %b, i8* %c, i8* %a) -; ATTRIBUTOR-NEXT: call void @use3nonnull(i8* nonnull %b, i8* nonnull %c, i8* nonnull %a) -; BOTH-NEXT: ret void +; FNATTR-NEXT: ret void call void @use3(i8* %c, i8* %a, i8* %b) call void @use3nonnull(i8* %b, i8* %c, i8* %a) ret void @@ -380,11 +352,8 @@ define void @parent2(i8* %a, i8* %b, i8* %c) { ; FNATTR-NEXT: call void @use3nonnull(i8* %b, i8* %c, i8* %a) ; FNATTR-NEXT: call void @use3(i8* %c, i8* %a, i8* %b) -; ATTRIBUTOR-LABEL: @parent2(i8* nonnull %a, i8* nonnull %b, i8* nonnull %c) -; ATTRIBUTOR-NEXT: call void @use3nonnull(i8* nonnull %b, i8* nonnull %c, i8* nonnull %a) -; ATTRIBUTOR-NEXT: call void @use3(i8* nonnull %c, i8* nonnull %a, i8* nonnull %b) -; BOTH-NEXT: ret void +; FNATTR-NEXT: ret void call void @use3nonnull(i8* %b, i8* %c, i8* %a) call void @use3(i8* %c, i8* %a, i8* %b) ret void @@ -397,11 +366,8 @@ define void @parent3(i8* %a, i8* %b, i8* %c) { ; FNATTR-NEXT: call void @use1nonnull(i8* %a) ; FNATTR-NEXT: call void @use3(i8* %c, i8* %b, i8* %a) -; ATTRIBUTOR-LABEL: @parent3(i8* nonnull %a, i8* %b, i8* %c) -; ATTRIBUTOR-NEXT: call void @use1nonnull(i8* nonnull %a) -; ATTRIBUTOR-NEXT: call void @use3(i8* %c, i8* %b, i8* nonnull %a) -; BOTH-NEXT: ret void +; FNATTR-NEXT: ret void call void @use1nonnull(i8* %a) call void @use3(i8* %c, i8* %b, i8* %a) @@ -416,12 +382,8 @@ define void @parent4(i8* %a, i8* %b, i8* %c) { ; CHECK-NEXT: call void @use2(i8* %a, i8* %c) ; CHECK-NEXT: call void @use1(i8* %b) -; ATTRIBUTOR-LABEL: @parent4(i8* %a, i8* nonnull %b, i8* nonnull %c) -; ATTRIBUTOR-NEXT: call void @use2nonnull(i8* nonnull %c, i8* nonnull %b) -; ATTRIBUTOR-NEXT: call void @use2(i8* %a, i8* nonnull %c) -; ATTRIBUTOR-NEXT: call void @use1(i8* nonnull %b) -; BOTH: ret void +; FNATTR: ret void call void @use2nonnull(i8* %c, i8* %b) call void @use2(i8* %a, i8* %c) @@ -434,14 +396,13 @@ define void @parent4(i8* %a, i8* %b, i8* %c) { ; because it would incorrectly propagate the wrong information to its callers. define void @parent5(i8* %a, i1 %a_is_notnull) { -; BOTH: @parent5(i8* %a, i1 %a_is_notnull) -; BOTH-NEXT: br i1 %a_is_notnull, label %t, label %f -; BOTH: t: +; FNATTR: @parent5(i8* %a, i1 %a_is_notnull) +; FNATTR-NEXT: br i1 %a_is_notnull, label %t, label %f +; FNATTR: t: ; FNATTR-NEXT: call void @use1nonnull(i8* %a) -; ATTRIBUTOR-NEXT: call void @use1nonnull(i8* nonnull %a) -; BOTH-NEXT: ret void -; BOTH: f: -; BOTH-NEXT: ret void +; FNATTR-NEXT: ret void +; FNATTR: f: +; FNATTR-NEXT: ret void br i1 %a_is_notnull, label %t, label %f t: @@ -456,11 +417,9 @@ f: define i8 @parent6(i8* %a, i8* %b) { ; FNATTR-LABEL: @parent6(i8* nonnull %a, i8* %b) -; ATTRIBUTOR-LABEL: @parent6(i8* nonnull %a, i8* %b) -; BOTH-NEXT: [[C:%.*]] = load volatile i8, i8* %b +; FNATTR-NEXT: [[C:%.*]] = load volatile i8, i8* %b ; FNATTR-NEXT: call void @use1nonnull(i8* %a) -; ATTRIBUTOR-NEXT: call void @use1nonnull(i8* nonnull %a) -; BOTH-NEXT: ret i8 [[C]] +; FNATTR-NEXT: ret i8 [[C]] %c = load volatile i8, i8* %b call void @use1nonnull(i8* %a) @@ -475,11 +434,8 @@ define i8 @parent7(i8* %a) { ; FNATTR-NEXT: call void @use1nonnull(i8* %a) -; ATTRIBUTOR-LABEL: @parent7(i8* nonnull %a) -; ATTRIBUTOR-NEXT: [[RET:%.*]] = call i8 @use1safecall(i8* nonnull %a) -; ATTRIBUTOR-NEXT: call void @use1nonnull(i8* nonnull %a) -; BOTH-NEXT: ret i8 [[RET]] +; FNATTR-NEXT: ret i8 [[RET]] %ret = call i8 @use1safecall(i8* %a) call void @use1nonnull(i8* %a) @@ -492,18 +448,16 @@ declare i32 @esfp(...) define i1 @parent8(i8* %a, i8* %bogus1, i8* %b) personality i8* bitcast (i32 (...)* @esfp to i8*){ ; FNATTR-LABEL: @parent8(i8* nonnull %a, i8* nocapture readnone %bogus1, i8* nonnull %b) -; ATTRIBUTOR-LABEL: @parent8(i8* nonnull %a, i8* nocapture nofree readnone %bogus1, i8* nonnull %b) -; BOTH-NEXT: entry: +; FNATTR-NEXT: entry: ; FNATTR-NEXT: invoke void @use2nonnull(i8* %a, i8* %b) -; ATTRIBUTOR-NEXT: invoke void @use2nonnull(i8* nonnull %a, i8* nonnull %b) -; BOTH-NEXT: to label %cont unwind label %exc -; BOTH: cont: -; BOTH-NEXT: [[NULL_CHECK:%.*]] = icmp eq i8* %b, null -; BOTH-NEXT: ret i1 [[NULL_CHECK]] -; BOTH: exc: -; BOTH-NEXT: [[LP:%.*]] = landingpad { i8*, i32 } -; BOTH-NEXT: filter [0 x i8*] zeroinitializer -; BOTH-NEXT: unreachable +; FNATTR-NEXT: to label %cont unwind label %exc +; FNATTR: cont: +; FNATTR-NEXT: [[NULL_CHECK:%.*]] = icmp eq i8* %b, null +; FNATTR-NEXT: ret i1 [[NULL_CHECK]] +; FNATTR: exc: +; FNATTR-NEXT: [[LP:%.*]] = landingpad { i8*, i32 } +; FNATTR-NEXT: filter [0 x i8*] zeroinitializer +; FNATTR-NEXT: unreachable entry: invoke void @use2nonnull(i8* %a, i8* %b) @@ -519,7 +473,7 @@ exc: unreachable } -; BOTH: define nonnull i32* @gep1( +; FNATTR: define nonnull i32* @gep1( define i32* @gep1(i32* %p) { %q = getelementptr inbounds i32, i32* %p, i32 1 ret i32* %q @@ -527,12 +481,12 @@ define i32* @gep1(i32* %p) { define i32* @gep1_no_null_opt(i32* %p) #0 { ; Should't be able to derive nonnull based on gep. -; BOTH: define i32* @gep1_no_null_opt( +; FNATTR: define i32* @gep1_no_null_opt( %q = getelementptr inbounds i32, i32* %p, i32 1 ret i32* %q } -; BOTH: define i32 addrspace(3)* @gep2( +; FNATTR: define i32 addrspace(3)* @gep2( define i32 addrspace(3)* @gep2(i32 addrspace(3)* %p) { %q = getelementptr inbounds i32, i32 addrspace(3)* %p, i32 1 ret i32 addrspace(3)* %q @@ -540,12 +494,11 @@ define i32 addrspace(3)* @gep2(i32 addrspace(3)* %p) { ; FNATTR: define i32 addrspace(3)* @as(i32 addrspace(3)* readnone returned dereferenceable(4) %p) ; FIXME: We should propagate dereferenceable here but *not* nonnull -; ATTRIBUTOR: define dereferenceable_or_null(4) i32 addrspace(3)* @as(i32 addrspace(3)* nofree readnone returned dereferenceable(4) dereferenceable_or_null(4) %p) define i32 addrspace(3)* @as(i32 addrspace(3)* dereferenceable(4) %p) { ret i32 addrspace(3)* %p } -; BOTH: define internal nonnull i32* @g2() +; FNATTR: define internal nonnull i32* @g2() define internal i32* @g2() { ret i32* inttoptr (i64 4 to i32*) } @@ -556,33 +509,28 @@ define i32* @g1() { } declare void @use_i32_ptr(i32*) readnone nounwind -; ATTRIBUTOR: define internal void @called_by_weak(i32* nocapture nonnull readnone %a) define internal void @called_by_weak(i32* %a) { call void @use_i32_ptr(i32* %a) ret void } ; Check we do not annotate the function interface of this weak function. -; ATTRIBUTOR: define weak_odr void @weak_caller(i32* nonnull %a) define weak_odr void @weak_caller(i32* nonnull %a) { call void @called_by_weak(i32* %a) ret void } ; Expect nonnull -; ATTRIBUTOR: define internal void @control(i32* nocapture nonnull readnone align 16 dereferenceable(8) %a) define internal void @control(i32* dereferenceable(4) %a) { call void @use_i32_ptr(i32* %a) ret void } ; Avoid nonnull as we do not touch naked functions -; ATTRIBUTOR: define internal void @naked(i32* dereferenceable(4) %a) define internal void @naked(i32* dereferenceable(4) %a) naked { call void @use_i32_ptr(i32* %a) ret void } ; Avoid nonnull as we do not touch optnone -; ATTRIBUTOR: define internal void @optnone(i32* dereferenceable(4) %a) define internal void @optnone(i32* dereferenceable(4) %a) optnone noinline { call void @use_i32_ptr(i32* %a) ret void @@ -618,20 +566,6 @@ define i32 @nonnull_exec_ctx_1(i32* %a, i32 %b) { ; FNATTR-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], [[B]] ; FNATTR-NEXT: br i1 [[TMP9]], label [[EX]], label [[HD]] ; -; ATTRIBUTOR-LABEL: define {{[^@]+}}@nonnull_exec_ctx_1 -; ATTRIBUTOR-SAME: (i32* [[A:%.*]], i32 [[B:%.*]]) -; ATTRIBUTOR-NEXT: en: -; ATTRIBUTOR-NEXT: [[TMP3:%.*]] = icmp eq i32 [[B:%.*]], 0 -; ATTRIBUTOR-NEXT: br i1 [[TMP3]], label [[EX:%.*]], label [[HD:%.*]] -; ATTRIBUTOR: ex: -; ATTRIBUTOR-NEXT: [[TMP5:%.*]] = tail call i32 @g(i32* nonnull [[A:%.*]]) -; ATTRIBUTOR-NEXT: ret i32 [[TMP5]] -; ATTRIBUTOR: hd: -; ATTRIBUTOR-NEXT: [[TMP7:%.*]] = phi i32 [ [[TMP8:%.*]], [[HD]] ], [ 0, [[EN:%.*]] ] -; ATTRIBUTOR-NEXT: tail call void @h(i32* [[A]]) -; ATTRIBUTOR-NEXT: [[TMP8]] = add nuw i32 [[TMP7]], 1 -; ATTRIBUTOR-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], [[B]] -; ATTRIBUTOR-NEXT: br i1 [[TMP9]], label [[EX]], label [[HD]] ; en: %tmp3 = icmp eq i32 %b, 0 @@ -667,22 +601,6 @@ define i32 @nonnull_exec_ctx_1b(i32* %a, i32 %b) { ; FNATTR-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], [[B]] ; FNATTR-NEXT: br i1 [[TMP9]], label [[EX]], label [[HD]] ; -; ATTRIBUTOR-LABEL: define {{[^@]+}}@nonnull_exec_ctx_1b -; ATTRIBUTOR-SAME: (i32* [[A:%.*]], i32 [[B:%.*]]) -; ATTRIBUTOR-NEXT: en: -; ATTRIBUTOR-NEXT: [[TMP3:%.*]] = icmp eq i32 [[B:%.*]], 0 -; ATTRIBUTOR-NEXT: br i1 [[TMP3]], label [[EX:%.*]], label [[HD:%.*]] -; ATTRIBUTOR: ex: -; ATTRIBUTOR-NEXT: [[TMP5:%.*]] = tail call i32 @g(i32* nonnull [[A:%.*]]) -; ATTRIBUTOR-NEXT: ret i32 [[TMP5]] -; ATTRIBUTOR: hd: -; ATTRIBUTOR-NEXT: [[TMP7:%.*]] = phi i32 [ [[TMP8:%.*]], [[HD2:%.*]] ], [ 0, [[EN:%.*]] ] -; ATTRIBUTOR-NEXT: tail call void @h(i32* [[A]]) -; ATTRIBUTOR-NEXT: br label [[HD2]] -; ATTRIBUTOR: hd2: -; ATTRIBUTOR-NEXT: [[TMP8]] = add nuw i32 [[TMP7]], 1 -; ATTRIBUTOR-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], [[B]] -; ATTRIBUTOR-NEXT: br i1 [[TMP9]], label [[EX]], label [[HD]] ; en: %tmp3 = icmp eq i32 %b, 0 @@ -719,20 +637,6 @@ define i32 @nonnull_exec_ctx_2(i32* %a, i32 %b) willreturn nounwind { ; FNATTR-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], [[B]] ; FNATTR-NEXT: br i1 [[TMP9]], label [[EX]], label [[HD]] ; -; ATTRIBUTOR-LABEL: define {{[^@]+}}@nonnull_exec_ctx_2 -; ATTRIBUTOR-SAME: (i32* [[A:%.*]], i32 [[B:%.*]]) -; ATTRIBUTOR-NEXT: en: -; ATTRIBUTOR-NEXT: [[TMP3:%.*]] = icmp eq i32 [[B:%.*]], 0 -; ATTRIBUTOR-NEXT: br i1 [[TMP3]], label [[EX:%.*]], label [[HD:%.*]] -; ATTRIBUTOR: ex: -; ATTRIBUTOR-NEXT: [[TMP5:%.*]] = tail call i32 @g(i32* nonnull [[A:%.*]]) -; ATTRIBUTOR-NEXT: ret i32 [[TMP5]] -; ATTRIBUTOR: hd: -; ATTRIBUTOR-NEXT: [[TMP7:%.*]] = phi i32 [ [[TMP8:%.*]], [[HD]] ], [ 0, [[EN:%.*]] ] -; ATTRIBUTOR-NEXT: tail call void @h(i32* nonnull [[A]]) -; ATTRIBUTOR-NEXT: [[TMP8]] = add nuw i32 [[TMP7]], 1 -; ATTRIBUTOR-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], [[B]] -; ATTRIBUTOR-NEXT: br i1 [[TMP9]], label [[EX]], label [[HD]] ; en: %tmp3 = icmp eq i32 %b, 0 @@ -768,22 +672,6 @@ define i32 @nonnull_exec_ctx_2b(i32* %a, i32 %b) willreturn nounwind { ; FNATTR-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], [[B]] ; FNATTR-NEXT: br i1 [[TMP9]], label [[EX]], label [[HD]] ; -; ATTRIBUTOR-LABEL: define {{[^@]+}}@nonnull_exec_ctx_2b -; ATTRIBUTOR-SAME: (i32* [[A:%.*]], i32 [[B:%.*]]) -; ATTRIBUTOR-NEXT: en: -; ATTRIBUTOR-NEXT: [[TMP3:%.*]] = icmp eq i32 [[B:%.*]], 0 -; ATTRIBUTOR-NEXT: br i1 [[TMP3]], label [[EX:%.*]], label [[HD:%.*]] -; ATTRIBUTOR: ex: -; ATTRIBUTOR-NEXT: [[TMP5:%.*]] = tail call i32 @g(i32* nonnull [[A:%.*]]) -; ATTRIBUTOR-NEXT: ret i32 [[TMP5]] -; ATTRIBUTOR: hd: -; ATTRIBUTOR-NEXT: [[TMP7:%.*]] = phi i32 [ [[TMP8:%.*]], [[HD2:%.*]] ], [ 0, [[EN:%.*]] ] -; ATTRIBUTOR-NEXT: tail call void @h(i32* nonnull [[A]]) -; ATTRIBUTOR-NEXT: br label [[HD2]] -; ATTRIBUTOR: hd2: -; ATTRIBUTOR-NEXT: [[TMP8]] = add nuw i32 [[TMP7]], 1 -; ATTRIBUTOR-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], [[B]] -; ATTRIBUTOR-NEXT: br i1 [[TMP9]], label [[EX]], label [[HD]] ; en: %tmp3 = icmp eq i32 %b, 0 @@ -809,21 +697,21 @@ declare void @sink(i32*) ; FIXME: the sink argument should be marked nonnull as in @PR43833_simple. define void @PR43833(i32* %0, i32 %1) { -; BOTH-LABEL: @PR43833( -; BOTH-NEXT: [[TMP3:%.*]] = icmp sgt i32 [[TMP1:%.*]], 1 -; BOTH-NEXT: br i1 [[TMP3]], label [[TMP4:%.*]], label [[TMP7:%.*]] -; BOTH: 4: -; BOTH-NEXT: [[TMP5:%.*]] = zext i32 [[TMP1]] to i64 -; BOTH-NEXT: [[TMP6:%.*]] = getelementptr inbounds i32, i32* [[TMP0:%.*]], i64 [[TMP5]] -; BOTH-NEXT: br label [[TMP8:%.*]] -; BOTH: 7: -; BOTH-NEXT: ret void -; BOTH: 8: -; BOTH-NEXT: [[TMP9:%.*]] = phi i32 [ 1, [[TMP4]] ], [ [[TMP10:%.*]], [[TMP8]] ] -; BOTH-NEXT: tail call void @sink(i32* [[TMP6]]) -; BOTH-NEXT: [[TMP10]] = add nuw nsw i32 [[TMP9]], 1 -; BOTH-NEXT: [[TMP11:%.*]] = icmp eq i32 [[TMP10]], [[TMP1]] -; BOTH-NEXT: br i1 [[TMP11]], label [[TMP7]], label [[TMP8]] +; FNATTR-LABEL: @PR43833( +; FNATTR-NEXT: [[TMP3:%.*]] = icmp sgt i32 [[TMP1:%.*]], 1 +; FNATTR-NEXT: br i1 [[TMP3]], label [[TMP4:%.*]], label [[TMP7:%.*]] +; FNATTR: 4: +; FNATTR-NEXT: [[TMP5:%.*]] = zext i32 [[TMP1]] to i64 +; FNATTR-NEXT: [[TMP6:%.*]] = getelementptr inbounds i32, i32* [[TMP0:%.*]], i64 [[TMP5]] +; FNATTR-NEXT: br label [[TMP8:%.*]] +; FNATTR: 7: +; FNATTR-NEXT: ret void +; FNATTR: 8: +; FNATTR-NEXT: [[TMP9:%.*]] = phi i32 [ 1, [[TMP4]] ], [ [[TMP10:%.*]], [[TMP8]] ] +; FNATTR-NEXT: tail call void @sink(i32* [[TMP6]]) +; FNATTR-NEXT: [[TMP10]] = add nuw nsw i32 [[TMP9]], 1 +; FNATTR-NEXT: [[TMP11:%.*]] = icmp eq i32 [[TMP10]], [[TMP1]] +; FNATTR-NEXT: br i1 [[TMP11]], label [[TMP7]], label [[TMP8]] ; %3 = icmp sgt i32 %1, 1 br i1 %3, label %4, label %7 @@ -846,37 +734,22 @@ define void @PR43833(i32* %0, i32 %1) { ; Adjusted from PR43833 define void @PR43833_simple(i32* %0, i32 %1) { -; OLD-LABEL: @PR43833_simple( -; OLD-NEXT: [[TMP3:%.*]] = icmp ne i32 [[TMP1:%.*]], 0 -; OLD-NEXT: br i1 [[TMP3]], label [[TMP4:%.*]], label [[TMP7:%.*]] -; OLD: 4: -; OLD-NEXT: [[TMP5:%.*]] = zext i32 [[TMP1]] to i64 -; OLD-NEXT: [[TMP6:%.*]] = getelementptr inbounds i32, i32* [[TMP0:%.*]], i64 [[TMP5]] -; OLD-NEXT: br label [[TMP8:%.*]] -; OLD: 7: -; OLD-NEXT: ret void -; OLD: 8: -; OLD-NEXT: [[TMP9:%.*]] = phi i32 [ 1, [[TMP4]] ], [ [[TMP10:%.*]], [[TMP8]] ] -; OLD-NEXT: tail call void @sink(i32* [[TMP6]]) -; OLD-NEXT: [[TMP10]] = add nuw nsw i32 [[TMP9]], 1 -; OLD-NEXT: [[TMP11:%.*]] = icmp eq i32 [[TMP10]], [[TMP1]] -; OLD-NEXT: br i1 [[TMP11]], label [[TMP7]], label [[TMP8]] +; FNATTR-LABEL: @PR43833_simple( +; FNATTR-NEXT: [[TMP3:%.*]] = icmp ne i32 [[TMP1:%.*]], 0 +; FNATTR-NEXT: br i1 [[TMP3]], label [[TMP4:%.*]], label [[TMP7:%.*]] +; FNATTR: 4: +; FNATTR-NEXT: [[TMP5:%.*]] = zext i32 [[TMP1]] to i64 +; FNATTR-NEXT: [[TMP6:%.*]] = getelementptr inbounds i32, i32* [[TMP0:%.*]], i64 [[TMP5]] +; FNATTR-NEXT: br label [[TMP8:%.*]] +; FNATTR: 7: +; FNATTR-NEXT: ret void +; FNATTR: 8: +; FNATTR-NEXT: [[TMP9:%.*]] = phi i32 [ 1, [[TMP4]] ], [ [[TMP10:%.*]], [[TMP8]] ] +; FNATTR-NEXT: tail call void @sink(i32* [[TMP6]]) +; FNATTR-NEXT: [[TMP10]] = add nuw nsw i32 [[TMP9]], 1 +; FNATTR-NEXT: [[TMP11:%.*]] = icmp eq i32 [[TMP10]], [[TMP1]] +; FNATTR-NEXT: br i1 [[TMP11]], label [[TMP7]], label [[TMP8]] ; -; ATTRIBUTOR_NPM-LABEL: @PR43833_simple( -; ATTRIBUTOR_NPM-NEXT: [[TMP3:%.*]] = icmp ne i32 [[TMP1:%.*]], 0 -; ATTRIBUTOR_NPM-NEXT: br i1 [[TMP3]], label [[TMP4:%.*]], label [[TMP7:%.*]] -; ATTRIBUTOR_NPM: 4: -; ATTRIBUTOR_NPM-NEXT: [[TMP5:%.*]] = zext i32 [[TMP1]] to i64 -; ATTRIBUTOR_NPM-NEXT: [[TMP6:%.*]] = getelementptr inbounds i32, i32* [[TMP0:%.*]], i64 [[TMP5]] -; ATTRIBUTOR_NPM-NEXT: br label [[TMP8:%.*]] -; ATTRIBUTOR_NPM: 7: -; ATTRIBUTOR_NPM-NEXT: ret void -; ATTRIBUTOR_NPM: 8: -; ATTRIBUTOR_NPM-NEXT: [[TMP9:%.*]] = phi i32 [ 1, [[TMP4]] ], [ [[TMP10:%.*]], [[TMP8]] ] -; ATTRIBUTOR_NPM-NEXT: tail call void @sink(i32* [[TMP6]]) -; ATTRIBUTOR_NPM-NEXT: [[TMP10]] = add nuw nsw i32 [[TMP9]], 1 -; ATTRIBUTOR_NPM-NEXT: [[TMP11:%.*]] = icmp eq i32 [[TMP10]], [[TMP1]] -; ATTRIBUTOR_NPM-NEXT: br i1 [[TMP11]], label [[TMP7]], label [[TMP8]] ; %3 = icmp ne i32 %1, 0 br i1 %3, label %4, label %7 diff --git a/llvm/test/Transforms/FunctionAttrs/norecurse.ll b/llvm/test/Transforms/FunctionAttrs/norecurse.ll index de5d35d6342..b780bb7b718 100644 --- a/llvm/test/Transforms/FunctionAttrs/norecurse.ll +++ b/llvm/test/Transforms/FunctionAttrs/norecurse.ll @@ -1,88 +1,83 @@ -; RUN: opt < %s -basicaa -functionattrs -rpo-functionattrs -S | FileCheck %s --check-prefixes=CHECK,BOTH -; RUN: opt < %s -aa-pipeline=basic-aa -passes='cgscc(function-attrs),rpo-functionattrs' -S | FileCheck %s --check-prefixes=CHECK,BOTH -; RUN: opt -passes=attributor --attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=ATTRIBUTOR,BOTH +; RUN: opt < %s -basicaa -functionattrs -rpo-functionattrs -S | FileCheck %s +; RUN: opt < %s -aa-pipeline=basic-aa -passes='cgscc(function-attrs),rpo-functionattrs' -S | FileCheck %s ; CHECK: Function Attrs ; CHECK-SAME: norecurse nounwind readnone -; ATTRIBUTOR: Function Attrs: nofree norecurse nosync nounwind readnone willreturn -; BOTH-NEXT: define i32 @leaf() +; CHECK-NEXT: define i32 @leaf() define i32 @leaf() { ret i32 1 } -; BOTH: Function Attrs -; BOTH-SAME: readnone -; BOTH-NOT: norecurse -; BOTH-NEXT: define i32 @self_rec() +; CHECK: Function Attrs +; CHECK-SAME: readnone +; CHECK-NOT: norecurse +; CHECK-NEXT: define i32 @self_rec() define i32 @self_rec() { %a = call i32 @self_rec() ret i32 4 } -; BOTH: Function Attrs -; BOTH-SAME: readnone -; BOTH-NOT: norecurse -; BOTH-NEXT: define i32 @indirect_rec() +; CHECK: Function Attrs +; CHECK-SAME: readnone +; CHECK-NOT: norecurse +; CHECK-NEXT: define i32 @indirect_rec() define i32 @indirect_rec() { %a = call i32 @indirect_rec2() ret i32 %a } -; BOTH: Function Attrs -; BOTH-SAME: readnone -; BOTH-NOT: norecurse -; BOTH-NEXT: define i32 @indirect_rec2() +; CHECK: Function Attrs +; CHECK-SAME: readnone +; CHECK-NOT: norecurse +; CHECK-NEXT: define i32 @indirect_rec2() define i32 @indirect_rec2() { %a = call i32 @indirect_rec() ret i32 %a } -; BOTH: Function Attrs -; BOTH-SAME: readnone -; BOTH-NOT: norecurse -; BOTH-NEXT: define i32 @extern() +; CHECK: Function Attrs +; CHECK-SAME: readnone +; CHECK-NOT: norecurse +; CHECK-NEXT: define i32 @extern() define i32 @extern() { %a = call i32 @k() ret i32 %a } -; BOTH: Function Attrs -; BOTH-NEXT: declare i32 @k() +; CHECK: Function Attrs +; CHECK-NEXT: declare i32 @k() declare i32 @k() readnone -; BOTH: Function Attrs +; CHECK: Function Attrs ; CHECK-SAME: nounwind -; BOTH-NOT: norecurse +; CHECK-NOT: norecurse ; CHECK-NEXT: define void @intrinsic(i8* nocapture %dest, i8* nocapture readonly %src, i32 %len) -; ATTRIBUTOR-NEXT: define void @intrinsic(i8* nocapture writeonly %dest, i8* nocapture readonly %src, i32 %len) define void @intrinsic(i8* %dest, i8* %src, i32 %len) { call void @llvm.memcpy.p0i8.p0i8.i32(i8* %dest, i8* %src, i32 %len, i1 false) ret void } -; BOTH: Function Attrs -; BOTH-NEXT: declare void @llvm.memcpy.p0i8.p0i8.i32 +; CHECK: Function Attrs +; CHECK-NEXT: declare void @llvm.memcpy.p0i8.p0i8.i32 declare void @llvm.memcpy.p0i8.p0i8.i32(i8*, i8*, i32, i1) -; BOTH: Function Attrs +; CHECK: Function Attrs ; CHECK-SAME: norecurse readnone ; FIXME: missing "norecurse" -; ATTRIBUTOR-SAME: nosync readnone ; CHECK-NEXT: define internal i32 @called_by_norecurse() define internal i32 @called_by_norecurse() { %a = call i32 @k() ret i32 %a } -; BOTH: Function Attrs -; BOTH-NEXT: define void @m() +; CHECK: Function Attrs +; CHECK-NEXT: define void @m() define void @m() norecurse { %a = call i32 @called_by_norecurse() ret void } -; BOTH: Function Attrs +; CHECK: Function Attrs ; CHECK-SAME: norecurse readnone ; FIXME: missing "norecurse" -; ATTRIBUTOR-SAME: nosync ; CHECK-NEXT: define internal i32 @called_by_norecurse_indirectly() define internal i32 @called_by_norecurse_indirectly() { %a = call i32 @k() @@ -96,61 +91,3 @@ define void @p() norecurse { call void @o() ret void } - -; ATTRIBUTOR: Function Attrs: nofree nosync nounwind -; ATTRIBUTOR-NEXT: define void @f(i32 %x) -define void @f(i32 %x) { -entry: - %x.addr = alloca i32, align 4 - store i32 %x, i32* %x.addr, align 4 - %0 = load i32, i32* %x.addr, align 4 - %tobool = icmp ne i32 %0, 0 - br i1 %tobool, label %if.then, label %if.end - -if.then: - call void @g() norecurse - br label %if.end - -if.end: - ret void -} - -; BOTH: define void @g() -define void @g() norecurse { -entry: - call void @f(i32 0) - ret void -} - -; ATTRIBUTOR-NOT: Function Attrs -; ATTRIBUTOR: define linkonce_odr i32 @leaf_redefinable() -define linkonce_odr i32 @leaf_redefinable() { - ret i32 1 -} - -; Call through a function pointer -; ATTRIBUTOR-NOT: Function Attrs -; ATTRIBUTOR: define i32 @eval_func1(i32 (i32)* nocapture nofree nonnull %0, i32 %1) -define i32 @eval_func1(i32 (i32)* , i32) local_unnamed_addr { - %3 = tail call i32 %0(i32 %1) #2 - ret i32 %3 -} - -; ATTRIBUTOR-NOT: Function Attrs -; ATTRIBUTOR: define i32 @eval_func2(i32 (i32)* nocapture nofree %0, i32 %1) -define i32 @eval_func2(i32 (i32)* , i32) local_unnamed_addr "null-pointer-is-valid"="true"{ - %3 = tail call i32 %0(i32 %1) #2 - ret i32 %3 -} - -declare void @unknown() -; Call an unknown function in a dead block. -; ATTRIBUTOR: Function Attrs: nofree norecurse nosync nounwind readnone willreturn -; ATTRIBUTOR: define i32 @call_unknown_in_dead_block() -define i32 @call_unknown_in_dead_block() local_unnamed_addr { - ret i32 0 -Dead: - tail call void @unknown() - ret i32 1 -} - diff --git a/llvm/test/Transforms/FunctionAttrs/noreturn_async.ll b/llvm/test/Transforms/FunctionAttrs/noreturn_async.ll deleted file mode 100644 index 3d2dd9f47da..00000000000 --- a/llvm/test/Transforms/FunctionAttrs/noreturn_async.ll +++ /dev/null @@ -1,142 +0,0 @@ -; RUN: opt -functionattrs -attributor -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s -; -; This file is the same as noreturn_sync.ll but with a personality which -; indicates that the exception handler *can* catch asynchronous exceptions. As -; a consequence, invokes to noreturn and nounwind functions are not translated -; to calls followed by an unreachable but the unwind edge is considered live. -; -; https://reviews.llvm.org/D59978#inline-586873 -; -; Make sure we handle invoke of a noreturn function correctly. -; -; This test is also a reminder of how we handle (=ignore) stackoverflow exception handling. -; -target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" -target triple = "x86_64-pc-windows-msvc19.16.27032" - -@"??_C@_0BG@CMNEKHOP@Exception?5NOT?5caught?6?$AA@" = linkonce_odr dso_local unnamed_addr constant [22 x i8] c"Exception NOT caught\0A\00", align 1 -@"??_C@_0BC@NKPAGFFJ@Exception?5caught?6?$AA@" = linkonce_odr dso_local unnamed_addr constant [18 x i8] c"Exception caught\0A\00", align 1 -@"??_C@_0BK@JHJLGDKL@Done?5execution?5result?$DN?$CFi?6?$AA@" = linkonce_odr dso_local unnamed_addr constant [26 x i8] c"Done execution result=%i\0A\00", align 1 -@"?_OptionsStorage@?1??__local_stdio_printf_options@@9@4_KA" = linkonce_odr dso_local global i64 0, align 8 - - -define dso_local void @"?overflow@@YAXXZ"() { -entry: -; CHECK: Function Attrs: nofree noreturn nosync nounwind -; CHECK-NEXT: define -; CHECK-NEXT: entry: -; CHECK-NEXT: call void @"?overflow@@YAXXZ"() -; CHECK-NEXT: unreachable - call void @"?overflow@@YAXXZ"() - %call3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @"??_C@_0BC@NKPAGFFJ@Exception?5caught?6?$AA@", i64 0, i64 0)) - ret void -} - - -; CHECK-NOT: nounwind -; CHECK-NOT: noreturn -; CHECK: define -; CHECK-SAME: @"?catchoverflow@@YAHXZ"() -define dso_local i32 @"?catchoverflow@@YAHXZ"() personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) { -entry: - %retval = alloca i32, align 4 - %__exception_code = alloca i32, align 4 -; CHECK: invoke void @"?overflow@@YAXXZ"() -; CHECK: to label %invoke.cont unwind label %catch.dispatch - invoke void @"?overflow@@YAXXZ"() - to label %invoke.cont unwind label %catch.dispatch - -invoke.cont: ; preds = %entry -; CHECK: invoke.cont: -; CHECK-NEXT: unreachable - br label %invoke.cont1 - -catch.dispatch: ; preds = %invoke.cont, %entry - %0 = catchswitch within none [label %__except] unwind to caller - -__except: ; preds = %catch.dispatch - %1 = catchpad within %0 [i8* null] - catchret from %1 to label %__except2 - -__except2: ; preds = %__except - %2 = call i32 @llvm.eh.exceptioncode(token %1) - store i32 1, i32* %retval, align 4 - br label %return - -invoke.cont1: ; preds = %invoke.cont - store i32 0, i32* %retval, align 4 - br label %return - -__try.cont: ; No predecessors! - store i32 2, i32* %retval, align 4 - br label %return - -return: ; preds = %__try.cont, %__except2, %invoke.cont1 - %3 = load i32, i32* %retval, align 4 - ret i32 %3 -} - - -define dso_local void @"?overflow@@YAXXZ_may_throw"() { -entry: -; CHECK: Function Attrs: noreturn -; CHECK-NOT: nounwind -; CHECK-NEXT: define -; CHECK-NEXT: entry: -; CHECK-NEXT: %call3 = call i32 (i8*, ...) @printf(i8* nonnull dereferenceable(18) getelementptr inbounds ([18 x i8], [18 x i8]* @"??_C@_0BC@NKPAGFFJ@Exception?5caught?6?$AA@", i64 0, i64 0)) -; CHECK-NEXT: call void @"?overflow@@YAXXZ_may_throw"() -; CHECK-NEXT: unreachable - %call3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @"??_C@_0BC@NKPAGFFJ@Exception?5caught?6?$AA@", i64 0, i64 0)) - call void @"?overflow@@YAXXZ_may_throw"() - ret void -} - - -; CHECK-NOT: nounwind -; CHECK-NOT: noreturn -; CHECK: define -; CHECK-SAME: @"?catchoverflow@@YAHXZ_may_throw"() -define dso_local i32 @"?catchoverflow@@YAHXZ_may_throw"() personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) { -entry: - %retval = alloca i32, align 4 - %__exception_code = alloca i32, align 4 -; CHECK: invoke void @"?overflow@@YAXXZ_may_throw"() -; CHECK: to label %invoke.cont unwind label %catch.dispatch - invoke void @"?overflow@@YAXXZ_may_throw"() - to label %invoke.cont unwind label %catch.dispatch - -invoke.cont: ; preds = %entry -; CHECK: invoke.cont: -; CHECK-NEXT: unreachable - br label %invoke.cont1 - -catch.dispatch: ; preds = %invoke.cont, %entry - %0 = catchswitch within none [label %__except] unwind to caller - -__except: ; preds = %catch.dispatch - %1 = catchpad within %0 [i8* null] - catchret from %1 to label %__except2 - -__except2: ; preds = %__except - %2 = call i32 @llvm.eh.exceptioncode(token %1) - store i32 1, i32* %retval, align 4 - br label %return - -invoke.cont1: ; preds = %invoke.cont - store i32 0, i32* %retval, align 4 - br label %return - -__try.cont: ; No predecessors! - store i32 2, i32* %retval, align 4 - br label %return - -return: ; preds = %__try.cont, %__except2, %invoke.cont1 - %3 = load i32, i32* %retval, align 4 - ret i32 %3 -} - -declare dso_local i32 @__C_specific_handler(...) - -declare dso_local i32 @printf(i8* %_Format, ...) - -declare i32 @llvm.eh.exceptioncode(token) diff --git a/llvm/test/Transforms/FunctionAttrs/noreturn_sync.ll b/llvm/test/Transforms/FunctionAttrs/noreturn_sync.ll deleted file mode 100644 index b5a70e76271..00000000000 --- a/llvm/test/Transforms/FunctionAttrs/noreturn_sync.ll +++ /dev/null @@ -1,138 +0,0 @@ -; RUN: opt -functionattrs -attributor -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s -; -; This file is the same as noreturn_async.ll but with a personality which -; indicates that the exception handler *cannot* catch asynchronous exceptions. -; As a consequence, invokes to noreturn and nounwind functions are translated -; to calls followed by an unreachable. -; -; https://reviews.llvm.org/D59978#inline-586873 -; -; Make sure we handle invoke of a noreturn function correctly. -; -; This test is also a reminder of how we handle (=ignore) stackoverflow exception handling. -; -target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" -target triple = "x86_64-pc-linux-gnu" - -@"??_C@_0BG@CMNEKHOP@Exception?5NOT?5caught?6?$AA@" = linkonce_odr dso_local unnamed_addr constant [22 x i8] c"Exception NOT caught\0A\00", align 1 -@"??_C@_0BC@NKPAGFFJ@Exception?5caught?6?$AA@" = linkonce_odr dso_local unnamed_addr constant [18 x i8] c"Exception caught\0A\00", align 1 -@"??_C@_0BK@JHJLGDKL@Done?5execution?5result?$DN?$CFi?6?$AA@" = linkonce_odr dso_local unnamed_addr constant [26 x i8] c"Done execution result=%i\0A\00", align 1 -@"?_OptionsStorage@?1??__local_stdio_printf_options@@9@4_KA" = linkonce_odr dso_local global i64 0, align 8 - - -define dso_local void @"?overflow@@YAXXZ"() { -entry: -; CHECK: Function Attrs: nofree noreturn nosync nounwind -; CHECK-NEXT: define -; CHECK-NEXT: entry: -; CHECK-NEXT: call void @"?overflow@@YAXXZ"() -; CHECK-NEXT: unreachable - call void @"?overflow@@YAXXZ"() - %call3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @"??_C@_0BC@NKPAGFFJ@Exception?5caught?6?$AA@", i64 0, i64 0)) - ret void -} - - -; CHECK: Function Attrs: nofree noreturn nosync nounwind -; CHECK-NEXT: @"?catchoverflow@@YAHXZ"() -define dso_local i32 @"?catchoverflow@@YAHXZ"() personality i8* bitcast (i32 (...)* @__gcc_personality_v0 to i8*) { -entry: - %retval = alloca i32, align 4 - %__exception_code = alloca i32, align 4 - invoke void @"?overflow@@YAXXZ"() - to label %invoke.cont unwind label %catch.dispatch -; CHECK: call void @"?overflow@@YAXXZ"() -; CHECK-NEXT: unreachable - -invoke.cont: ; preds = %entry - br label %invoke.cont1 - -catch.dispatch: ; preds = %invoke.cont, %entry - %0 = catchswitch within none [label %__except] unwind to caller - -__except: ; preds = %catch.dispatch - %1 = catchpad within %0 [i8* null] - catchret from %1 to label %__except2 - -__except2: ; preds = %__except - %2 = call i32 @llvm.eh.exceptioncode(token %1) - store i32 1, i32* %retval, align 4 - br label %return - -invoke.cont1: ; preds = %invoke.cont - store i32 0, i32* %retval, align 4 - br label %return - -__try.cont: ; No predecessors! - store i32 2, i32* %retval, align 4 - br label %return - -return: ; preds = %__try.cont, %__except2, %invoke.cont1 - %3 = load i32, i32* %retval, align 4 - ret i32 %3 -} - - -define dso_local void @"?overflow@@YAXXZ_may_throw"() { -entry: -; CHECK: Function Attrs: noreturn -; CHECK-NOT: nounwind -; CHECK-NEXT: define -; CHECK-NEXT: entry: -; CHECK-NEXT: %call3 = call i32 (i8*, ...) @printf(i8* nonnull dereferenceable(18) getelementptr inbounds ([18 x i8], [18 x i8]* @"??_C@_0BC@NKPAGFFJ@Exception?5caught?6?$AA@", i64 0, i64 0)) -; CHECK-NEXT: call void @"?overflow@@YAXXZ_may_throw"() -; CHECK-NEXT: unreachable - %call3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @"??_C@_0BC@NKPAGFFJ@Exception?5caught?6?$AA@", i64 0, i64 0)) - call void @"?overflow@@YAXXZ_may_throw"() - ret void -} - - -; CHECK-NOT: nounwind -; CHECK-NOT: noreturn -; CHECK: define -; CHECK-SAME: @"?catchoverflow@@YAHXZ_may_throw"() -define dso_local i32 @"?catchoverflow@@YAHXZ_may_throw"() personality i8* bitcast (i32 (...)* @__gcc_personality_v0 to i8*) { -entry: - %retval = alloca i32, align 4 - %__exception_code = alloca i32, align 4 -; CHECK: invoke void @"?overflow@@YAXXZ_may_throw"() -; CHECK: to label %invoke.cont unwind label %catch.dispatch - invoke void @"?overflow@@YAXXZ_may_throw"() - to label %invoke.cont unwind label %catch.dispatch - -invoke.cont: ; preds = %entry -; CHECK: invoke.cont: -; CHECK-NEXT: unreachable - br label %invoke.cont1 - -catch.dispatch: ; preds = %invoke.cont, %entry - %0 = catchswitch within none [label %__except] unwind to caller - -__except: ; preds = %catch.dispatch - %1 = catchpad within %0 [i8* null] - catchret from %1 to label %__except2 - -__except2: ; preds = %__except - %2 = call i32 @llvm.eh.exceptioncode(token %1) - store i32 1, i32* %retval, align 4 - br label %return - -invoke.cont1: ; preds = %invoke.cont - store i32 0, i32* %retval, align 4 - br label %return - -__try.cont: ; No predecessors! - store i32 2, i32* %retval, align 4 - br label %return - -return: ; preds = %__try.cont, %__except2, %invoke.cont1 - %3 = load i32, i32* %retval, align 4 - ret i32 %3 -} - -declare dso_local i32 @__gcc_personality_v0(...) - -declare dso_local i32 @printf(i8* %_Format, ...) - -declare i32 @llvm.eh.exceptioncode(token) diff --git a/llvm/test/Transforms/FunctionAttrs/nosync.ll b/llvm/test/Transforms/FunctionAttrs/nosync.ll deleted file mode 100644 index abb40cf2669..00000000000 --- a/llvm/test/Transforms/FunctionAttrs/nosync.ll +++ /dev/null @@ -1,356 +0,0 @@ -; RUN: opt -functionattrs -S < %s | FileCheck %s --check-prefix=FNATTR -; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefix=ATTRIBUTOR -target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" - -; Test cases designed for the nosync function attribute. -; FIXME's are used to indicate problems and missing attributes. - -; struct RT { -; char A; -; int B[10][20]; -; char C; -; }; -; struct ST { -; int X; -; double Y; -; struct RT Z; -; }; -; -; int *foo(struct ST *s) { -; return &s[1].Z.B[5][13]; -; } - -; TEST 1 -; non-convergent and readnone implies nosync -%struct.RT = type { i8, [10 x [20 x i32]], i8 } -%struct.ST = type { i32, double, %struct.RT } - -; FNATTR: Function Attrs: norecurse nounwind optsize readnone ssp uwtable -; FNATTR-NEXT: define nonnull i32* @foo(%struct.ST* readnone %s) -; ATTRIBUTOR: Function Attrs: nofree nosync nounwind optsize readnone ssp uwtable -; ATTRIBUTOR-NEXT: define nonnull i32* @foo(%struct.ST* nofree nonnull readnone "no-capture-maybe-returned" %s) -define i32* @foo(%struct.ST* %s) nounwind uwtable readnone optsize ssp { -entry: - %arrayidx = getelementptr inbounds %struct.ST, %struct.ST* %s, i64 1, i32 2, i32 1, i64 5, i64 13 - ret i32* %arrayidx -} - -; TEST 2 -; atomic load with monotonic ordering -; int load_monotonic(_Atomic int *num) { -; int n = atomic_load_explicit(num, memory_order_relaxed); -; return n; -; } - -; FNATTR: Function Attrs: nofree norecurse nounwind uwtable -; FNATTR-NEXT: define i32 @load_monotonic(i32* nocapture readonly %0) -; ATTRIBUTOR: Function Attrs: nofree norecurse nosync nounwind uwtable -; ATTRIBUTOR-NEXT: define i32 @load_monotonic(i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) %0) -define i32 @load_monotonic(i32* nocapture readonly %0) norecurse nounwind uwtable { - %2 = load atomic i32, i32* %0 monotonic, align 4 - ret i32 %2 -} - - -; TEST 3 -; atomic store with monotonic ordering. -; void store_monotonic(_Atomic int *num) { -; atomic_load_explicit(num, memory_order_relaxed); -; } - -; FNATTR: Function Attrs: nofree norecurse nounwind uwtable -; FNATTR-NEXT: define void @store_monotonic(i32* nocapture %0) -; ATTRIBUTOR: Function Attrs: nofree norecurse nosync nounwind uwtable -; ATTRIBUTOR-NEXT: define void @store_monotonic(i32* nocapture nofree nonnull writeonly align 4 dereferenceable(4) %0) -define void @store_monotonic(i32* nocapture %0) norecurse nounwind uwtable { - store atomic i32 10, i32* %0 monotonic, align 4 - ret void -} - -; TEST 4 - negative, should not deduce nosync -; atomic load with acquire ordering. -; int load_acquire(_Atomic int *num) { -; int n = atomic_load_explicit(num, memory_order_acquire); -; return n; -; } - -; FNATTR: Function Attrs: nofree norecurse nounwind uwtable -; FNATTR-NEXT: define i32 @load_acquire(i32* nocapture readonly %0) -; ATTRIBUTOR: Function Attrs: nofree norecurse nounwind uwtable -; ATTRIBUTOR-NOT: nosync -; ATTRIBUTOR-NEXT: define i32 @load_acquire(i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) %0) -define i32 @load_acquire(i32* nocapture readonly %0) norecurse nounwind uwtable { - %2 = load atomic i32, i32* %0 acquire, align 4 - ret i32 %2 -} - -; TEST 5 - negative, should not deduce nosync -; atomic load with release ordering -; void load_release(_Atomic int *num) { -; atomic_store_explicit(num, 10, memory_order_release); -; } - -; FNATTR: Function Attrs: nofree norecurse nounwind uwtable -; FNATTR-NEXT: define void @load_release(i32* nocapture %0) -; ATTRIBUTOR: Function Attrs: nofree norecurse nounwind uwtable -; ATTRIBUTOR-NOT: nosync -; ATTRIBUTOR-NEXT: define void @load_release(i32* nocapture nofree writeonly align 4 %0) -define void @load_release(i32* nocapture %0) norecurse nounwind uwtable { - store atomic volatile i32 10, i32* %0 release, align 4 - ret void -} - -; TEST 6 - negative volatile, relaxed atomic - -; FNATTR: Function Attrs: nofree norecurse nounwind uwtable -; FNATTR-NEXT: define void @load_volatile_release(i32* nocapture %0) -; ATTRIBUTOR: Function Attrs: nofree norecurse nounwind uwtable -; ATTRIBUTOR-NOT: nosync -; ATTRIBUTOR-NEXT: define void @load_volatile_release(i32* nocapture nofree writeonly align 4 %0) -define void @load_volatile_release(i32* nocapture %0) norecurse nounwind uwtable { - store atomic volatile i32 10, i32* %0 release, align 4 - ret void -} - -; TEST 7 - negative, should not deduce nosync -; volatile store. -; void volatile_store(volatile int *num) { -; *num = 14; -; } - -; FNATTR: Function Attrs: nofree norecurse nounwind uwtable -; FNATTR-NEXT: define void @volatile_store(i32* %0) -; ATTRIBUTOR: Function Attrs: nofree norecurse nounwind uwtable -; ATTRIBUTOR-NOT: nosync -; ATTRIBUTOR-NEXT: define void @volatile_store(i32* nofree align 4 %0) -define void @volatile_store(i32* %0) norecurse nounwind uwtable { - store volatile i32 14, i32* %0, align 4 - ret void -} - -; TEST 8 - negative, should not deduce nosync -; volatile load. -; int volatile_load(volatile int *num) { -; int n = *num; -; return n; -; } - -; FNATTR: Function Attrs: nofree norecurse nounwind uwtable -; FNATTR-NEXT: define i32 @volatile_load(i32* %0) -; ATTRIBUTOR: Function Attrs: nofree norecurse nounwind uwtable -; ATTRIBUTOR-NOT: nosync -; ATTRIBUTOR-NEXT: define i32 @volatile_load(i32* nofree align 4 %0) -define i32 @volatile_load(i32* %0) norecurse nounwind uwtable { - %2 = load volatile i32, i32* %0, align 4 - ret i32 %2 -} - -; TEST 9 - -; FNATTR: Function Attrs: noinline nosync nounwind uwtable -; FNATTR-NEXT: declare void @nosync_function() -; ATTRIBUTOR: Function Attrs: noinline nosync nounwind uwtable -; ATTRIBUTOR-NEXT: declare void @nosync_function() -declare void @nosync_function() noinline nounwind uwtable nosync - -; FNATTR: Function Attrs: noinline nounwind uwtable -; FNATTR-NEXT: define void @call_nosync_function() -; ATTRIBUTOR: Function Attrs: noinline nosync nounwind uwtable -; ATTRIBUTOR-next: define void @call_nosync_function() -define void @call_nosync_function() nounwind uwtable noinline { - tail call void @nosync_function() noinline nounwind uwtable - ret void -} - -; TEST 10 - negative, should not deduce nosync - -; FNATTR: Function Attrs: noinline nounwind uwtable -; FNATTR-NEXT: declare void @might_sync() -; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable -; ATTRIBUTOR-NEXT: declare void @might_sync() -declare void @might_sync() noinline nounwind uwtable - -; FNATTR: Function Attrs: noinline nounwind uwtable -; FNATTR-NEXT: define void @call_might_sync() -; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable -; ATTRIBUTOR-NOT: nosync -; ATTRIBUTOR-NEXT: define void @call_might_sync() -define void @call_might_sync() nounwind uwtable noinline { - tail call void @might_sync() noinline nounwind uwtable - ret void -} - -; TEST 11 - positive, should deduce nosync -; volatile operation in same scc but dead. Call volatile_load defined in TEST 8. - -; FNATTR: Function Attrs: nofree noinline nounwind uwtable -; FNATTR-NEXT: define i32 @scc1(i32* %0) -; ATTRIBUTOR: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable -; ATTRIBUTOR-NEXT: define i32 @scc1(i32* nocapture nofree readnone %0) -define i32 @scc1(i32* %0) noinline nounwind uwtable { - tail call void @scc2(i32* %0); - %val = tail call i32 @volatile_load(i32* %0); - ret i32 %val; -} - -; FNATTR: Function Attrs: nofree noinline nounwind uwtable -; FNATTR-NEXT: define void @scc2(i32* %0) -; ATTRIBUTOR: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable -; ATTRIBUTOR-NEXT: define void @scc2(i32* nocapture nofree readnone %0) -define void @scc2(i32* %0) noinline nounwind uwtable { - tail call i32 @scc1(i32* %0); - ret void; -} - -; TEST 12 - fences, negative -; -; void foo1(int *a, std::atomic<bool> flag){ -; *a = 100; -; atomic_thread_fence(std::memory_order_release); -; flag.store(true, std::memory_order_relaxed); -; } -; -; void bar(int *a, std::atomic<bool> flag){ -; while(!flag.load(std::memory_order_relaxed)) -; ; -; -; atomic_thread_fence(std::memory_order_acquire); -; int b = *a; -; } - -%"struct.std::atomic" = type { %"struct.std::__atomic_base" } -%"struct.std::__atomic_base" = type { i8 } - -; FNATTR: Function Attrs: nofree norecurse nounwind -; FNATTR-NEXT: define void @foo1(i32* nocapture %0, %"struct.std::atomic"* nocapture %1) -; ATTRIBUTOR-NOT: nosync -; ATTRIBUTOR: define void @foo1(i32* nocapture nofree nonnull writeonly align 4 dereferenceable(4) %0, %"struct.std::atomic"* nocapture nofree nonnull writeonly dereferenceable(1) %1) - -define void @foo1(i32* %0, %"struct.std::atomic"* %1) { - store i32 100, i32* %0, align 4 - fence release - %3 = getelementptr inbounds %"struct.std::atomic", %"struct.std::atomic"* %1, i64 0, i32 0, i32 0 - store atomic i8 1, i8* %3 monotonic, align 1 - ret void -} - -; FNATTR: Function Attrs: nofree norecurse nounwind -; FNATTR-NEXT: define void @bar(i32* nocapture readnone %0, %"struct.std::atomic"* nocapture readonly %1) -; ATTRIBUTOR-NOT: nosync -; ATTRIBUTOR: define void @bar(i32* nocapture nofree readnone %0, %"struct.std::atomic"* nocapture nofree nonnull readonly dereferenceable(1) %1) -define void @bar(i32* %0, %"struct.std::atomic"* %1) { - %3 = getelementptr inbounds %"struct.std::atomic", %"struct.std::atomic"* %1, i64 0, i32 0, i32 0 - br label %4 - -4: ; preds = %4, %2 - %5 = load atomic i8, i8* %3 monotonic, align 1 - %6 = and i8 %5, 1 - %7 = icmp eq i8 %6, 0 - br i1 %7, label %4, label %8 - -8: ; preds = %4 - fence acquire - ret void -} - -; TEST 13 - Fence syncscope("singlethread") seq_cst -; FNATTR: Function Attrs: nofree norecurse nounwind -; FNATTR-NEXT: define void @foo1_singlethread(i32* nocapture %0, %"struct.std::atomic"* nocapture %1) -; ATTRIBUTOR: Function Attrs: nofree nosync nounwind willreturn -; ATTRIBUTOR: define void @foo1_singlethread(i32* nocapture nofree nonnull writeonly align 4 dereferenceable(4) %0, %"struct.std::atomic"* nocapture nofree nonnull writeonly dereferenceable(1) %1) - -define void @foo1_singlethread(i32* %0, %"struct.std::atomic"* %1) { - store i32 100, i32* %0, align 4 - fence syncscope("singlethread") release - %3 = getelementptr inbounds %"struct.std::atomic", %"struct.std::atomic"* %1, i64 0, i32 0, i32 0 - store atomic i8 1, i8* %3 monotonic, align 1 - ret void -} - -; FNATTR: Function Attrs: nofree norecurse nounwind -; FNATTR-NEXT: define void @bar_singlethread(i32* nocapture readnone %0, %"struct.std::atomic"* nocapture readonly %1) -; ATTRIBUTOR: Function Attrs: nofree nosync nounwind -; ATTRIBUTOR: define void @bar_singlethread(i32* nocapture nofree readnone %0, %"struct.std::atomic"* nocapture nofree nonnull readonly dereferenceable(1) %1) -define void @bar_singlethread(i32* %0, %"struct.std::atomic"* %1) { - %3 = getelementptr inbounds %"struct.std::atomic", %"struct.std::atomic"* %1, i64 0, i32 0, i32 0 - br label %4 - -4: ; preds = %4, %2 - %5 = load atomic i8, i8* %3 monotonic, align 1 - %6 = and i8 %5, 1 - %7 = icmp eq i8 %6, 0 - br i1 %7, label %4, label %8 - -8: ; preds = %4 - fence syncscope("singlethread") acquire - ret void -} - -declare void @llvm.memcpy(i8* %dest, i8* %src, i32 %len, i1 %isvolatile) -declare void @llvm.memset(i8* %dest, i8 %val, i32 %len, i1 %isvolatile) - -; TEST 14 - negative, checking volatile intrinsics. - -; It is odd to add nocapture but a result of the llvm.memcpy nocapture. -; -; ATTRIBUTOR: Function Attrs: nounwind -; ATTRIBUTOR-NOT: nosync -; ATTRIBUTOR-NEXT: define i32 @memcpy_volatile(i8* nocapture writeonly %ptr1, i8* nocapture readonly %ptr2) -define i32 @memcpy_volatile(i8* %ptr1, i8* %ptr2) { - call void @llvm.memcpy(i8* %ptr1, i8* %ptr2, i32 8, i1 1) - ret i32 4 -} - -; TEST 15 - positive, non-volatile intrinsic. - -; It is odd to add nocapture but a result of the llvm.memset nocapture. -; -; ATTRIBUTOR: Function Attrs: nosync -; ATTRIBUTOR-NEXT: define i32 @memset_non_volatile(i8* nocapture writeonly %ptr1, i8 %val) -define i32 @memset_non_volatile(i8* %ptr1, i8 %val) { - call void @llvm.memset(i8* %ptr1, i8 %val, i32 8, i1 0) - ret i32 4 -} - -; TEST 16 - negative, inline assembly. - -; ATTRIBUTOR: define i32 @inline_asm_test(i32 %x) -define i32 @inline_asm_test(i32 %x) { - call i32 asm "bswap $0", "=r,r"(i32 %x) - ret i32 4 -} - -declare void @readnone_test() convergent readnone - -; ATTRIBUTOR: define void @convergent_readnone() -; TEST 17 - negative. Convergent -define void @convergent_readnone(){ - call void @readnone_test() - ret void -} - -; ATTRIBUTOR: Function Attrs: nounwind -; ATTRIBUTOR-NEXT: declare void @llvm.x86.sse2.clflush(i8*) -declare void @llvm.x86.sse2.clflush(i8*) -@a = common global i32 0, align 4 - -; TEST 18 - negative. Synchronizing intrinsic - -; ATTRIBUTOR: Function Attrs: nounwind -; ATTRIBUTOR-NOT: nosync -; ATTRIBUTOR-NEXT: define void @i_totally_sync() -define void @i_totally_sync() { - tail call void @llvm.x86.sse2.clflush(i8* bitcast (i32* @a to i8*)) - ret void -} - -declare float @llvm.cos(float %val) readnone - -; TEST 19 - positive, readnone & non-convergent intrinsic. - -; ATTRIBUTOR: Function Attrs: nosync nounwind -; ATTRIBUTOR-NEXT: define i32 @cos_test(float %x) -define i32 @cos_test(float %x) { - call float @llvm.cos(float %x) - ret i32 4 -} diff --git a/llvm/test/Transforms/FunctionAttrs/nounwind.ll b/llvm/test/Transforms/FunctionAttrs/nounwind.ll index ed7576c970b..6d5e3a2ea5b 100644 --- a/llvm/test/Transforms/FunctionAttrs/nounwind.ll +++ b/llvm/test/Transforms/FunctionAttrs/nounwind.ll @@ -1,11 +1,8 @@ ; RUN: opt < %s -functionattrs -S | FileCheck %s -; RUN: opt < %s -attributor -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=3 -S | FileCheck %s --check-prefix=ATTRIBUTOR ; TEST 1 ; CHECK: Function Attrs: norecurse nounwind readnone ; CHECK-NEXT: define i32 @foo1() -; ATTRIBUTOR: Function Attrs: nofree nosync nounwind -; ATTRIBUTOR-NEXT: define i32 @foo1() define i32 @foo1() { ret i32 1 } @@ -13,8 +10,6 @@ define i32 @foo1() { ; TEST 2 ; CHECK: Function Attrs: nounwind readnone ; CHECK-NEXT: define i32 @scc1_foo() -; ATTRIBUTOR: Function Attrs: nofree noreturn nosync nounwind -; ATTRIBUTOR-NEXT: define i32 @scc1_foo() define i32 @scc1_foo() { %1 = call i32 @scc1_bar() ret i32 1 @@ -24,8 +19,6 @@ define i32 @scc1_foo() { ; TEST 3 ; CHECK: Function Attrs: nounwind readnone ; CHECK-NEXT: define i32 @scc1_bar() -; ATTRIBUTOR: Function Attrs: nofree noreturn nosync nounwind -; ATTRIBUTOR-NEXT: define i32 @scc1_bar() define i32 @scc1_bar() { %1 = call i32 @scc1_foo() ret i32 1 @@ -36,7 +29,6 @@ declare i32 @non_nounwind() ; TEST 4 ; CHECK: define void @call_non_nounwind() { -; ATTRIBUTOR: define void @call_non_nounwind() { define void @call_non_nounwind(){ tail call i32 @non_nounwind() ret void @@ -51,7 +43,6 @@ define void @call_non_nounwind(){ ; } ; CHECK: define i32 @maybe_throw(i1 zeroext %0) -; ATTRIBUTOR: define i32 @maybe_throw(i1 zeroext %0) define i32 @maybe_throw(i1 zeroext %0) { br i1 %0, label %2, label %3 @@ -75,7 +66,6 @@ declare void @__cxa_rethrow() ; } ; CHECK: define i32 @catch_thing() -; ATTRIBUTOR: define i32 @catch_thing() define i32 @catch_thing() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { invoke void @__cxa_rethrow() #1 to label %1 unwind label %2 @@ -93,9 +83,6 @@ define i32 @catch_thing() personality i8* bitcast (i32 (...)* @__gxx_personality } define i32 @catch_thing_user() { -; ATTRIBUTOR: define i32 @catch_thing_user -; ATTRIBUTOR-NEXT: %catch_thing_call = call -; ATTRIBUTOR-NEXT: ret i32 -1 %catch_thing_call = call i32 @catch_thing() ret i32 %catch_thing_call } diff --git a/llvm/test/Transforms/FunctionAttrs/read_write_returned_arguments_scc.ll b/llvm/test/Transforms/FunctionAttrs/read_write_returned_arguments_scc.ll deleted file mode 100644 index 72d062b7616..00000000000 --- a/llvm/test/Transforms/FunctionAttrs/read_write_returned_arguments_scc.ll +++ /dev/null @@ -1,165 +0,0 @@ -; RUN: opt -functionattrs -enable-nonnull-arg-prop -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=6 -S < %s | FileCheck %s -; -; This is an evolved example to stress test SCC parameter attribute propagation. -; The SCC in this test is made up of the following six function, three of which -; are internal and three externally visible: -; -; static int *internal_ret0_nw(int *n0, int *w0); -; static int *internal_ret1_rw(int *r0, int *w0); -; static int *internal_ret1_rrw(int *r0, int *r1, int *w0); -; int *external_ret2_nrw(int *n0, int *r0, int *w0); -; int *external_sink_ret2_nrw(int *n0, int *r0, int *w0); -; int *external_source_ret2_nrw(int *n0, int *r0, int *w0); -; -; The top four functions call each other while the "sink" function will not -; call anything and the "source" function will not be called in this module. -; The names of the functions define the returned parameter (X for "_retX_"), -; as well as how the parameters are (transitively) used (n = readnone, -; r = readonly, w = writeonly). -; -; What we should see is something along the lines of: -; 1 - Number of functions marked as norecurse -; 6 - Number of functions marked argmemonly -; 6 - Number of functions marked as nounwind -; 16 - Number of arguments marked nocapture -; 4 - Number of arguments marked readnone -; 6 - Number of arguments marked writeonly -; 6 - Number of arguments marked readonly -; 6 - Number of arguments marked returned -; -target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" - -; CHECK: Function Attrs: nofree nosync nounwind -; CHECK-NEXT: define i32* @external_ret2_nrw(i32* nofree %n0, i32* nofree %r0, i32* nofree returned %w0) -define i32* @external_ret2_nrw(i32* %n0, i32* %r0, i32* %w0) { -entry: - %call = call i32* @internal_ret0_nw(i32* %n0, i32* %w0) - %call1 = call i32* @internal_ret1_rrw(i32* %r0, i32* %r0, i32* %w0) - %call2 = call i32* @external_sink_ret2_nrw(i32* %n0, i32* %r0, i32* %w0) - %call3 = call i32* @internal_ret1_rw(i32* %r0, i32* %w0) - ret i32* %call3 -} - -; CHECK: Function Attrs: nofree nosync nounwind -; CHECK-NEXT: define internal i32* @internal_ret0_nw(i32* nofree returned %n0, i32* nofree %w0) -define internal i32* @internal_ret0_nw(i32* %n0, i32* %w0) { -entry: - %r0 = alloca i32, align 4 - %r1 = alloca i32, align 4 - %tobool = icmp ne i32* %n0, null - br i1 %tobool, label %if.end, label %if.then - -if.then: ; preds = %entry - br label %return - -if.end: ; preds = %entry - store i32 3, i32* %r0, align 4 - store i32 5, i32* %r1, align 4 - store i32 1, i32* %w0, align 4 - %call = call i32* @internal_ret1_rrw(i32* %r0, i32* %r1, i32* %w0) - %call1 = call i32* @external_ret2_nrw(i32* %n0, i32* %r0, i32* %w0) - %call2 = call i32* @external_ret2_nrw(i32* %n0, i32* %r1, i32* %w0) - %call3 = call i32* @external_sink_ret2_nrw(i32* %n0, i32* %r0, i32* %w0) - %call4 = call i32* @external_sink_ret2_nrw(i32* %n0, i32* %r1, i32* %w0) - %call5 = call i32* @internal_ret0_nw(i32* %n0, i32* %w0) - br label %return - -return: ; preds = %if.end, %if.then - %retval.0 = phi i32* [ %call5, %if.end ], [ %n0, %if.then ] - ret i32* %retval.0 -} - -; CHECK: Function Attrs: nofree nosync nounwind -; CHECK-NEXT: define internal i32* @internal_ret1_rrw(i32* nofree nonnull align 4 dereferenceable(4) %r0, i32* nofree returned %r1, i32* nofree %w0) -define internal i32* @internal_ret1_rrw(i32* %r0, i32* %r1, i32* %w0) { -entry: - %0 = load i32, i32* %r0, align 4 - %tobool = icmp ne i32 %0, 0 - br i1 %tobool, label %if.end, label %if.then - -if.then: ; preds = %entry - br label %return - -if.end: ; preds = %entry - %call = call i32* @internal_ret1_rw(i32* %r0, i32* %w0) - %1 = load i32, i32* %r0, align 4 - %2 = load i32, i32* %r1, align 4 - %add = add nsw i32 %1, %2 - store i32 %add, i32* %w0, align 4 - %call1 = call i32* @internal_ret1_rw(i32* %r1, i32* %w0) - %call2 = call i32* @internal_ret0_nw(i32* %r0, i32* %w0) - %call3 = call i32* @internal_ret0_nw(i32* %w0, i32* %w0) - %call4 = call i32* @external_ret2_nrw(i32* %r0, i32* %r1, i32* %w0) - %call5 = call i32* @external_ret2_nrw(i32* %r1, i32* %r0, i32* %w0) - %call6 = call i32* @external_sink_ret2_nrw(i32* %r0, i32* %r1, i32* %w0) - %call7 = call i32* @external_sink_ret2_nrw(i32* %r1, i32* %r0, i32* %w0) - %call8 = call i32* @internal_ret0_nw(i32* %r1, i32* %w0) - br label %return - -return: ; preds = %if.end, %if.then - %retval.0 = phi i32* [ %call8, %if.end ], [ %r1, %if.then ] - ret i32* %retval.0 -} - -; CHECK: Function Attrs: nofree norecurse nosync nounwind -; CHECK-NEXT: define i32* @external_sink_ret2_nrw(i32* nofree readnone %n0, i32* nocapture nofree readonly %r0, i32* nofree returned writeonly "no-capture-maybe-returned" %w0) -define i32* @external_sink_ret2_nrw(i32* %n0, i32* %r0, i32* %w0) { -entry: - %tobool = icmp ne i32* %n0, null - br i1 %tobool, label %if.end, label %if.then - -if.then: ; preds = %entry - br label %return - -if.end: ; preds = %entry - %0 = load i32, i32* %r0, align 4 - store i32 %0, i32* %w0, align 4 - br label %return - -return: ; preds = %if.end, %if.then - ret i32* %w0 -} - -; CHECK: Function Attrs: nofree nosync nounwind -; CHECK-NEXT: define internal i32* @internal_ret1_rw(i32* nofree nonnull align 4 dereferenceable(4) %r0, i32* nofree returned %w0) -define internal i32* @internal_ret1_rw(i32* %r0, i32* %w0) { -entry: - %0 = load i32, i32* %r0, align 4 - %tobool = icmp ne i32 %0, 0 - br i1 %tobool, label %if.end, label %if.then - -if.then: ; preds = %entry - br label %return - -if.end: ; preds = %entry - %call = call i32* @internal_ret1_rrw(i32* %r0, i32* %r0, i32* %w0) - %1 = load i32, i32* %r0, align 4 - store i32 %1, i32* %w0, align 4 - %call1 = call i32* @internal_ret0_nw(i32* %r0, i32* %w0) - %call2 = call i32* @internal_ret0_nw(i32* %w0, i32* %w0) - %call3 = call i32* @external_sink_ret2_nrw(i32* %r0, i32* %r0, i32* %w0) - %call4 = call i32* @external_ret2_nrw(i32* %r0, i32* %r0, i32* %w0) - br label %return - -return: ; preds = %if.end, %if.then - %retval.0 = phi i32* [ %call4, %if.end ], [ %w0, %if.then ] - ret i32* %retval.0 -} - -; CHECK: Function Attrs: nofree nosync nounwind -; CHECK-NEXT: define i32* @external_source_ret2_nrw(i32* nofree %n0, i32* nofree %r0, i32* nofree returned %w0) -define i32* @external_source_ret2_nrw(i32* %n0, i32* %r0, i32* %w0) { -entry: - %call = call i32* @external_sink_ret2_nrw(i32* %n0, i32* %r0, i32* %w0) - %call1 = call i32* @external_ret2_nrw(i32* %n0, i32* %r0, i32* %w0) - ret i32* %call1 -} - -; Verify that we see only expected attribute sets, the above lines only check -; for a subset relation. -; -; CHECK-NOT: attributes # -; CHECK: attributes #{{.*}} = { nofree nosync nounwind } -; CHECK: attributes #{{.*}} = { nofree norecurse nosync nounwind } -; CHECK: attributes #{{.*}} = { nosync } -; CHECK-NOT: attributes # diff --git a/llvm/test/Transforms/FunctionAttrs/readattrs.ll b/llvm/test/Transforms/FunctionAttrs/readattrs.ll index dc1fbf652f9..b11b3edcebf 100644 --- a/llvm/test/Transforms/FunctionAttrs/readattrs.ll +++ b/llvm/test/Transforms/FunctionAttrs/readattrs.ll @@ -1,7 +1,5 @@ -; RUN: opt < %s -functionattrs -S | FileCheck %s --check-prefixes=CHECK,FNATTR -; RUN: opt < %s -aa-pipeline=basic-aa -passes='cgscc(function-attrs)' -S | FileCheck %s --check-prefixes=CHECK,FNATTR -; RUN: opt < %s -attributor -attributor-disable=false -S -attributor-annotate-decl-cs | FileCheck %s --check-prefixes=CHECK,ATTRIBUTOR -; RUN: opt < %s -aa-pipeline=basic-aa -passes='attributor' -attributor-disable=false -S -attributor-annotate-decl-cs | FileCheck %s --check-prefixes=CHECK,ATTRIBUTOR +; RUN: opt < %s -functionattrs -S | FileCheck %s +; RUN: opt < %s -aa-pipeline=basic-aa -passes='cgscc(function-attrs)' -S | FileCheck %s @x = global i32 0 @@ -9,23 +7,20 @@ declare void @test1_1(i8* %x1_1, i8* readonly %y1_1, ...) ; NOTE: readonly for %y1_2 would be OK here but not for the similar situation in test13. ; -; FNATTR: define void @test1_2(i8* %x1_2, i8* readonly %y1_2, i8* %z1_2) -; ATTRIBUTOR: define void @test1_2(i8* %x1_2, i8* %y1_2, i8* %z1_2) +; CHECK: define void @test1_2(i8* %x1_2, i8* readonly %y1_2, i8* %z1_2) define void @test1_2(i8* %x1_2, i8* %y1_2, i8* %z1_2) { call void (i8*, i8*, ...) @test1_1(i8* %x1_2, i8* %y1_2, i8* %z1_2) store i32 0, i32* @x ret void } -; FNATTR: define i8* @test2(i8* readnone returned %p) -; ATTRIBUTOR: define i8* @test2(i8* nofree readnone returned %p) +; CHECK: define i8* @test2(i8* readnone returned %p) define i8* @test2(i8* %p) { store i32 0, i32* @x ret i8* %p } -; FNATTR: define i1 @test3(i8* readnone %p, i8* readnone %q) -; ATTRIBUTOR: define i1 @test3(i8* nofree readnone %p, i8* nofree readnone %q) +; CHECK: define i1 @test3(i8* readnone %p, i8* readnone %q) define i1 @test3(i8* %p, i8* %q) { %A = icmp ult i8* %p, %q ret i1 %A @@ -39,8 +34,7 @@ define void @test4_2(i8* %p) { ret void } -; FNATTR: define void @test5(i8** nocapture %p, i8* %q) -; ATTRIBUTOR: define void @test5(i8** nocapture nofree nonnull writeonly dereferenceable(8) %p, i8* nofree writeonly %q) +; CHECK: define void @test5(i8** nocapture %p, i8* %q) ; Missed optz'n: we could make %q readnone, but don't break test6! define void @test5(i8** %p, i8* %q) { store i8* %q, i8** %p @@ -48,8 +42,7 @@ define void @test5(i8** %p, i8* %q) { } declare void @test6_1() -; FNATTR: define void @test6_2(i8** nocapture %p, i8* %q) -; ATTRIBUTOR: define void @test6_2(i8** nocapture nonnull writeonly dereferenceable(8) %p, i8* %q) +; CHECK: define void @test6_2(i8** nocapture %p, i8* %q) ; This is not a missed optz'n. define void @test6_2(i8** %p, i8* %q) { store i8* %q, i8** %p @@ -57,22 +50,19 @@ define void @test6_2(i8** %p, i8* %q) { ret void } -; FNATTR: define void @test7_1(i32* inalloca nocapture %a) -; ATTRIBUTOR: define void @test7_1(i32* inalloca nocapture nofree writeonly %a) +; CHECK: define void @test7_1(i32* inalloca nocapture %a) ; inalloca parameters are always considered written define void @test7_1(i32* inalloca %a) { ret void } -; FNATTR: define i32* @test8_1(i32* readnone returned %p) -; ATTRIBUTOR: define i32* @test8_1(i32* nofree readnone returned %p) +; CHECK: define i32* @test8_1(i32* readnone returned %p) define i32* @test8_1(i32* %p) { entry: ret i32* %p } -; FNATTR: define void @test8_2(i32* %p) -; ATTRIBUTOR: define void @test8_2(i32* nocapture nofree writeonly %p) +; CHECK: define void @test8_2(i32* %p) define void @test8_2(i32* %p) { entry: %call = call i32* @test8_1(i32* %p) @@ -136,11 +126,9 @@ declare void @escape_readonly_ptr(i8** %addr, i8* readonly %ptr) ; ; FIXME: This test currently exposes a bug in functionattrs! ; -; FNATTR: define void @unsound_readnone(i8* nocapture readnone %ignored, i8* readnone %escaped_then_written) -; FNATTR: define void @unsound_readonly(i8* nocapture readnone %ignored, i8* readonly %escaped_then_written) +; CHECK: define void @unsound_readnone(i8* nocapture readnone %ignored, i8* readnone %escaped_then_written) +; CHECK: define void @unsound_readonly(i8* nocapture readnone %ignored, i8* readonly %escaped_then_written) ; -; ATTRIBUTOR: define void @unsound_readnone(i8* nocapture nofree readnone %ignored, i8* %escaped_then_written) -; ATTRIBUTOR: define void @unsound_readonly(i8* nocapture nofree readnone %ignored, i8* %escaped_then_written) define void @unsound_readnone(i8* %ignored, i8* %escaped_then_written) { %addr = alloca i8* call void @escape_readnone_ptr(i8** %addr, i8* %escaped_then_written) diff --git a/llvm/test/Transforms/FunctionAttrs/value-simplify.ll b/llvm/test/Transforms/FunctionAttrs/value-simplify.ll deleted file mode 100644 index 4e765cc233f..00000000000 --- a/llvm/test/Transforms/FunctionAttrs/value-simplify.ll +++ /dev/null @@ -1,276 +0,0 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes -; RUN: opt -attributor --attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s -; TODO: Add max-iteration check - -; Disable update test checks and enable it where required. -; UTC_ARGS: --turn off - -; ModuleID = 'value-simplify.ll' -source_filename = "value-simplify.ll" -target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" -declare void @f(i32) - -; Test1: Replace argument with constant -define internal void @test1(i32 %a) { -; CHECK: tail call void @f(i32 1) - tail call void @f(i32 %a) - ret void -} - -define void @test1_helper() { - tail call void @test1(i32 1) - ret void -} - -; TEST 2 : Simplify return value -define i32 @return0() { - ret i32 0 -} - -define i32 @return1() { - ret i32 1 -} - -; CHECK: define i32 @test2_1(i1 %c) -define i32 @test2_1(i1 %c) { - br i1 %c, label %if.true, label %if.false -if.true: - %call = tail call i32 @return0() - -; FIXME: %ret0 should be replaced with i32 1. -; CHECK: %ret0 = add i32 0, 1 - %ret0 = add i32 %call, 1 - br label %end -if.false: - %ret1 = tail call i32 @return1() - br label %end -end: - -; FIXME: %ret should be replaced with i32 1. -; CHECK: %ret = phi i32 [ %ret0, %if.true ], [ 1, %if.false ] - %ret = phi i32 [ %ret0, %if.true ], [ %ret1, %if.false ] - -; FIXME: ret i32 1 -; CHECK: ret i32 %ret - ret i32 %ret -} - - - -; CHECK: define i32 @test2_2(i1 %c) -define i32 @test2_2(i1 %c) { -; FIXME: %ret should be replaced with i32 1. - %ret = tail call i32 @test2_1(i1 %c) -; FIXME: ret i32 1 -; CHECK: ret i32 %ret - ret i32 %ret -} - -declare void @use(i32) -; CHECK: define void @test3(i1 %c) -define void @test3(i1 %c) { - br i1 %c, label %if.true, label %if.false -if.true: - br label %end -if.false: - %ret1 = tail call i32 @return1() - br label %end -end: - -; CHECK: %r = phi i32 [ 1, %if.true ], [ 1, %if.false ] - %r = phi i32 [ 1, %if.true ], [ %ret1, %if.false ] - -; CHECK: tail call void @use(i32 1) - tail call void @use(i32 %r) - ret void -} - -define void @test-select-phi(i1 %c) { - %select-same = select i1 %c, i32 1, i32 1 - ; CHECK: tail call void @use(i32 1) - tail call void @use(i32 %select-same) - - %select-not-same = select i1 %c, i32 1, i32 0 - ; CHECK: tail call void @use(i32 %select-not-same) - tail call void @use(i32 %select-not-same) - br i1 %c, label %if-true, label %if-false -if-true: - br label %end -if-false: - br label %end -end: - %phi-same = phi i32 [ 1, %if-true ], [ 1, %if-false ] - %phi-not-same = phi i32 [ 0, %if-true ], [ 1, %if-false ] - %phi-same-prop = phi i32 [ 1, %if-true ], [ %select-same, %if-false ] - %phi-same-undef = phi i32 [ 1, %if-true ], [ undef, %if-false ] - %select-not-same-undef = select i1 %c, i32 %phi-not-same, i32 undef - - - ; CHECK: tail call void @use(i32 1) - tail call void @use(i32 %phi-same) - - ; CHECK: tail call void @use(i32 %phi-not-same) - tail call void @use(i32 %phi-not-same) - - ; CHECK: tail call void @use(i32 1) - tail call void @use(i32 %phi-same-prop) - - ; CHECK: tail call void @use(i32 1) - tail call void @use(i32 %phi-same-undef) - - ; CHECK: tail call void @use(i32 %select-not-same-undef) - tail call void @use(i32 %select-not-same-undef) - - ret void - -} - -define i32 @ipccp1(i32 %a) { -; CHECK-LABEL: define {{[^@]+}}@ipccp1 -; CHECK-SAME: (i32 returned [[A:%.*]]) #0 -; CHECK-NEXT: br i1 true, label [[T:%.*]], label [[F:%.*]] -; CHECK: t: -; CHECK-NEXT: ret i32 [[A:%.*]] -; CHECK: f: -; CHECK-NEXT: unreachable -; - br i1 true, label %t, label %f -t: - ret i32 %a -f: - %r = call i32 @ipccp1(i32 5) - ret i32 %r -} - -define internal i1 @ipccp2i(i1 %a) { -; CHECK-LABEL: define {{[^@]+}}@ipccp2i -; CHECK-SAME: (i1 returned [[A:%.*]]) #0 -; CHECK-NEXT: br i1 true, label [[T:%.*]], label [[F:%.*]] -; CHECK: t: -; CHECK-NEXT: ret i1 true -; CHECK: f: -; CHECK-NEXT: unreachable -; - br i1 %a, label %t, label %f -t: - ret i1 %a -f: - %r = call i1 @ipccp2i(i1 false) - ret i1 %r -} - -define i1 @ipccp2() { -; CHECK-LABEL: define {{[^@]+}}@ipccp2() #1 -; CHECK-NEXT: [[R:%.*]] = call i1 @ipccp2i(i1 true) #0 -; CHECK-NEXT: ret i1 [[R]] -; - %r = call i1 @ipccp2i(i1 true) - ret i1 %r -} - -define internal i32 @ipccp3i(i32 %a) { -; CHECK-LABEL: define {{[^@]+}}@ipccp3i -; CHECK-SAME: (i32 [[A:%.*]]) #1 -; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[A:%.*]], 7 -; CHECK-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]] -; CHECK: t: -; CHECK-NEXT: ret i32 [[A]] -; CHECK: f: -; CHECK-NEXT: [[R:%.*]] = call i32 @ipccp3i(i32 5) #1 -; CHECK-NEXT: ret i32 [[R]] -; - %c = icmp eq i32 %a, 7 - br i1 %c, label %t, label %f -t: - ret i32 %a -f: - %r = call i32 @ipccp3i(i32 5) - ret i32 %r -} - -define i32 @ipccp3() { -; CHECK-LABEL: define {{[^@]+}}@ipccp3() #1 -; CHECK-NEXT: [[R:%.*]] = call i32 @ipccp3i(i32 7) #1 -; CHECK-NEXT: ret i32 [[R]] -; - %r = call i32 @ipccp3i(i32 7) - ret i32 %r -} - -; UTC_ARGS: --turn on - -; Do not touch complicated arguments (for now) -%struct.X = type { i8* } -define internal i32* @test_inalloca(i32* inalloca %a) { -; CHECK-LABEL: define {{[^@]+}}@test_inalloca -; CHECK-SAME: (i32* inalloca noalias nofree returned writeonly [[A:%.*]]) -; CHECK-NEXT: ret i32* [[A]] -; - ret i32* %a -} -define i32* @complicated_args_inalloca() { -; CHECK-LABEL: define {{[^@]+}}@complicated_args_inalloca() -; CHECK-NEXT: [[CALL:%.*]] = call i32* @test_inalloca(i32* noalias nofree null) -; CHECK-NEXT: ret i32* [[CALL]] -; - %call = call i32* @test_inalloca(i32* null) - ret i32* %call -} - -define internal void @test_sret(%struct.X* sret %a, %struct.X** %b) { -; CHECK-LABEL: define {{[^@]+}}@test_sret -; CHECK-SAME: (%struct.X* nofree sret writeonly [[A:%.*]], %struct.X** nocapture nofree nonnull writeonly dereferenceable(8) [[B:%.*]]) -; CHECK-NEXT: store %struct.X* [[A]], %struct.X** [[B]] -; CHECK-NEXT: ret void -; - store %struct.X* %a, %struct.X** %b - ret void -} -define void @complicated_args_sret(%struct.X** %b) { -; CHECK-LABEL: define {{[^@]+}}@complicated_args_sret -; CHECK-SAME: (%struct.X** nocapture nofree writeonly [[B:%.*]]) -; CHECK-NEXT: call void @test_sret(%struct.X* nofree null, %struct.X** nocapture nofree writeonly [[B]]) -; CHECK-NEXT: ret void -; - call void @test_sret(%struct.X* null, %struct.X** %b) - ret void -} - -define internal %struct.X* @test_nest(%struct.X* nest %a) { -; CHECK-LABEL: define {{[^@]+}}@test_nest -; CHECK-SAME: (%struct.X* nest noalias nofree readnone returned [[A:%.*]]) -; CHECK-NEXT: ret %struct.X* [[A]] -; - ret %struct.X* %a -} -define %struct.X* @complicated_args_nest() { -; CHECK-LABEL: define {{[^@]+}}@complicated_args_nest() -; CHECK-NEXT: [[CALL:%.*]] = call %struct.X* @test_nest(%struct.X* noalias nofree null) -; CHECK-NEXT: ret %struct.X* [[CALL]] -; - %call = call %struct.X* @test_nest(%struct.X* null) - ret %struct.X* %call -} - -@S = external global %struct.X -define internal void @test_byval(%struct.X* byval %a) { -; CHECK-LABEL: define {{[^@]+}}@test_byval -; CHECK-SAME: (%struct.X* nocapture nofree nonnull writeonly byval align 8 dereferenceable(8) [[A:%.*]]) -; CHECK-NEXT: [[G0:%.*]] = getelementptr [[STRUCT_X:%.*]], %struct.X* [[A]], i32 0, i32 0 -; CHECK-NEXT: store i8* null, i8** [[G0]], align 8 -; CHECK-NEXT: ret void -; - %g0 = getelementptr %struct.X, %struct.X* %a, i32 0, i32 0 - store i8* null, i8** %g0 - ret void -} -define void @complicated_args_byval() { -; CHECK-LABEL: define {{[^@]+}}@complicated_args_byval() -; CHECK-NEXT: call void @test_byval(%struct.X* nofree nonnull align 8 dereferenceable(8) @S) -; CHECK-NEXT: ret void -; - call void @test_byval(%struct.X* @S) - ret void -} - -; UTC_ARGS: --turn off diff --git a/llvm/test/Transforms/FunctionAttrs/willreturn.ll b/llvm/test/Transforms/FunctionAttrs/willreturn.ll deleted file mode 100644 index 8f7e46837c1..00000000000 --- a/llvm/test/Transforms/FunctionAttrs/willreturn.ll +++ /dev/null @@ -1,553 +0,0 @@ -; RUN: opt -functionattrs -S < %s | FileCheck %s --check-prefix=FNATTR -; RUN: opt -passes=attributor --attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefix=ATTRIBUTOR - - -target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" - -; Test cases specifically designed for the "willreturn" function attribute. -; We use FIXME's to indicate problems and missing attributes. - - -; TEST 1 (positive case) -; FNATTR: Function Attrs: noinline norecurse nounwind readnone uwtable -; FNATTR-NEXT: define void @only_return() -; ATTRIBUTOR: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable willreturn -; ATTRIBUTOR-NEXT: define void @only_return() -define void @only_return() #0 { - ret void -} - - -; TEST 2 (positive & negative case) -; 2.1 (positive case) -; recursive function which will halt -; int fib(int n){ -; return n<=1? n : fib(n-1) + fib(n-2); -; } - -; FNATTR: Function Attrs: noinline nounwind readnone uwtable -; FNATTR-NEXT: define i32 @fib(i32 %0) -; FIXME: missing willreturn -; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable -; ATTRIBUTOR-NEXT: define i32 @fib(i32 %0) local_unnamed_addr -define i32 @fib(i32 %0) local_unnamed_addr #0 { - %2 = icmp slt i32 %0, 2 - br i1 %2, label %9, label %3 - -; <label>:3: ; preds = %1 - %4 = add nsw i32 %0, -1 - %5 = tail call i32 @fib(i32 %4) - %6 = add nsw i32 %0, -2 - %7 = tail call i32 @fib(i32 %6) - %8 = add nsw i32 %7, %5 - ret i32 %8 - -; <label>:9: ; preds = %1 - ret i32 %0 -} - -; 2.2 (negative case) -; recursive function which doesn't stop for some input. -; int fact_maybe_not_halt(int n) { -; if (n==0) { -; return 1; -; } -; return fact_maybe_not_halt( n > 0 ? n-1 : n) * n; -; } -; fact_maybe_not(-1) doesn't stop. - -; FNATTR: Function Attrs: noinline norecurse nounwind readnone uwtable -; FNATTR-NOT: willreturn -; FNATTR-NEXT: define i32 @fact_maybe_not_halt(i32 %0) local_unnamed_addr -; ATTRIBUTOR: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable -; ATTRIBUTOR-NOT: willreturn -; ATTRIBUTOR-NEXT: define i32 @fact_maybe_not_halt(i32 %0) local_unnamed_addr -define i32 @fact_maybe_not_halt(i32 %0) local_unnamed_addr #0 { - %2 = icmp eq i32 %0, 0 - br i1 %2, label %11, label %3 - -; <label>:3: ; preds = %1, %3 - %4 = phi i32 [ %8, %3 ], [ %0, %1 ] - %5 = phi i32 [ %9, %3 ], [ 1, %1 ] - %6 = icmp sgt i32 %4, 0 - %7 = sext i1 %6 to i32 - %8 = add nsw i32 %4, %7 - %9 = mul nsw i32 %4, %5 - %10 = icmp eq i32 %8, 0 - br i1 %10, label %11, label %3 - -; <label>:11: ; preds = %3, %1 - %12 = phi i32 [ 1, %1 ], [ %9, %3 ] - ret i32 %12 -} - - -; TEST 3 (positive case) -; loop -; int fact_loop(int n ){ -; int ans = 1; -; for(int i = 1;i<=n;i++){ -; ans *= i; -; } -; return ans; -; } - -; FIXME: missing willreturn -; FNATTR: Function Attrs: noinline norecurse nounwind readnone uwtable -; FNATTR-NEXT: define i32 @fact_loop(i32 %0) -; ATTRIBUTOR: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable -; ATTRIBUTOR-NEXT: define i32 @fact_loop(i32 %0) local_unnamed_addr -define i32 @fact_loop(i32 %0) local_unnamed_addr #0 { - %2 = icmp slt i32 %0, 1 - br i1 %2, label %3, label %5 - -; <label>:3: ; preds = %5, %1 - %4 = phi i32 [ 1, %1 ], [ %8, %5 ] - ret i32 %4 - -; <label>:5: ; preds = %1, %5 - %6 = phi i32 [ %9, %5 ], [ 1, %1 ] - %7 = phi i32 [ %8, %5 ], [ 1, %1 ] - %8 = mul nsw i32 %6, %7 - %9 = add nuw nsw i32 %6, 1 - %10 = icmp eq i32 %6, %0 - br i1 %10, label %3, label %5 -} - -; TEST 4 (negative case) -; mutual recursion -; void mutual_recursion1(){ -; mutual_recursion2(); -; } -; void mutual_recursion2(){ -; mutual_recursion1(); -; } - -; FNATTR: Function Attrs: noinline nounwind readnone uwtable -; FNATTR-NOT: willreturn -; FNATTR-NEXT: define void @mutual_recursion1(i1 %c) -; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable -; ATTRIBUTOR-NOT: willreturn -; ATTRIBUTOR-NEXT: define void @mutual_recursion1(i1 %c) -define void @mutual_recursion1(i1 %c) #0 { - br i1 %c, label %rec, label %end -rec: - call void @mutual_recursion2(i1 %c) - br label %end -end: - ret void -} - - -; FNATTR: Function Attrs: noinline nounwind readnone uwtable -; FNATTR-NOT: willreturn -; FNATTR-NEXT: define void @mutual_recursion2(i1 %c) -; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable -; ATTRIBUTOR-NOT: willreturn -; ATTRIBUTOR-NEXT: define void @mutual_recursion2(i1 %c) -define void @mutual_recursion2(i1 %c) #0 { - call void @mutual_recursion1(i1 %c) - ret void -} - - -; TEST 5 (negative case) -; call exit/abort (has noreturn attribute) -; FNATTR: Function Attrs: noreturn -; FNATTR-NEXT: declare void @exit(i32) local_unnamed_addr -; ATTRIBUTOR: Function Attrs: noreturn -; ATTRIBUTOR-NEXT: declare void @exit(i32) local_unnamed_add -declare void @exit(i32 %0) local_unnamed_addr noreturn - -; FNATTR: Function Attrs: noinline nounwind uwtable -; FNATTR-NOT: willreturn -; FNATTR-NEXT: define void @only_exit() -; ATTRIBUTOR: Function Attrs: noinline noreturn nounwind uwtable -; ATTRIBUTOR-NOT: willreturn -; ATTRIBUTOR-NEXT: define void @only_exit() local_unnamed_addr -define void @only_exit() local_unnamed_addr #0 { - tail call void @exit(i32 0) - unreachable -} - -; conditional exit -; void conditional_exit(int cond, int *p){ -; if(cond){ -; exit(0); -; } -; if(*p){ -; exit(1); -; } -; return; -; } -; FNATTR: Function Attrs: noinline nounwind uwtable -; FNATTR-NOT: willreturn -; FNATTR-NEXT: define void @conditional_exit(i32 %0, i32* nocapture readonly %1) local_unnamed_addr -; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable -; ATTRIBUTOR-NOT: willreturn -; ATTRIBUTOR-NEXT: define void @conditional_exit(i32 %0, i32* nocapture readonly %1) local_unnamed_addr -define void @conditional_exit(i32 %0, i32* nocapture readonly %1) local_unnamed_addr #0 { - %3 = icmp eq i32 %0, 0 - br i1 %3, label %5, label %4 - -; <label>:4: ; preds = %2 - tail call void @exit(i32 0) - unreachable - -; <label>:5: ; preds = %2 - %6 = load i32, i32* %1, align 4 - %7 = icmp eq i32 %6, 0 - br i1 %7, label %9, label %8 - -; <label>:8: ; preds = %5 - tail call void @exit(i32 1) - unreachable - -; <label>:9: ; preds = %5 - ret void -} - -; TEST 6 (positive case) -; Call intrinsic function -; FIXME: missing willreturn -; FNATTRS: Function Attrs: noinline readnone speculatable -; FNATTRS-NEXT: declare float @llvm.floor.f32(float %0) -; ATTRIBUTOR: Function Attrs: nounwind readnone speculatable -; ATTRIBUTOR-NEXT: declare float @llvm.floor.f32(float) -declare float @llvm.floor.f32(float) - -; FNATTRS: Function Attrs: noinline nounwind readnone uwtable -; FNATTRS-NEXT: define void @call_floor(float %a) -; FIXME: missing willreturn -; ATTRIBUTOR: Function Attrs: noinline nosync nounwind readnone uwtable -; ATTRIBUTOR-NEXT: define void @call_floor(float %a) -define void @call_floor(float %a) #0 { - tail call float @llvm.floor.f32(float %a) - ret void -} - - -; TEST 7 (negative case) -; Call function declaration without willreturn - -; FNATTR: Function Attrs: noinline nounwind uwtable -; FNATTR-NOT: willreturn -; FNATTR-NEXT: declare void @maybe_noreturn() -; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable -; ATTRIBUTOR-NOT: willreturn -; ATTRIBUTOR-NEXT: declare void @maybe_noreturn() -declare void @maybe_noreturn() #0 - -; FNATTR: Function Attrs: noinline nounwind uwtable -; FNATTR-NOT: willreturn -; FNATTR-NEXT: define void @call_maybe_noreturn() -; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable -; ATTRIBUTOR-NOT: willreturn -; ATTRIBUTOR-NEXT: define void @call_maybe_noreturn() -define void @call_maybe_noreturn() #0 { - tail call void @maybe_noreturn() - ret void -} - - -; TEST 8 (positive case) -; Check propagation. - -; FNATTR: Function Attrs: norecurse willreturn -; FNATTR-NEXT: declare void @will_return() -; ATTRIBUTOR: Function Attrs: norecurse willreturn -; ATTRIBUTOR-NEXT: declare void @will_return() -declare void @will_return() willreturn norecurse - -; FNATTR: Function Attrs: noinline norecurse nounwind uwtable -; FNATTR-NEXT: define void @f1() -; ATTRIBUTOR: Function Attrs: noinline norecurse nounwind uwtable willreturn -; ATTRIBUTOR-NEXT: define void @f1() -define void @f1() #0 { - tail call void @will_return() - ret void -} - -; FNATTR: Function Attrs: noinline norecurse nounwind uwtable -; FNATTR-NEXT: define void @f2() -; ATTRIBUTOR: Function Attrs: noinline norecurse nounwind uwtable willreturn -; ATTRIBUTOR-NEXT: define void @f2() -define void @f2() #0 { - tail call void @f1() - ret void -} - - -; TEST 9 (negative case) -; call willreturn function in endless loop. - -; FNATTR: Function Attrs: noinline norecurse nounwind uwtable -; FNATTR-NOT: willreturn -; FNATTR-NEXT: define void @call_will_return_but_has_loop() -; ATTRIBUTOR: Function Attrs: noinline norecurse noreturn nounwind uwtable -; ATTRIBUTOR-NOT: willreturn -; ATTRIBUTOR-NEXT: define void @call_will_return_but_has_loop() -define void @call_will_return_but_has_loop() #0 { - br label %label1 -label1: - tail call void @will_return() - br label %label2 -label2: - br label %label1 -} - - -; TEST 10 (positive case) -; invoke a function with willreturn - -; FNATTR: Function Attrs: noinline uwtable willreturn -; FNATTR-NEXT: declare i1 @maybe_raise_exception() -; ATTRIBUTOR: Function Attrs: noinline uwtable willreturn -; ATTRIBUTOR-NEXT: declare i1 @maybe_raise_exception() -declare i1 @maybe_raise_exception() #1 willreturn - -; FNATTR: Function Attrs: nounwind -; FNATTR-NEXT: define void @invoke_test() -; ATTRIBUTOR: Function Attrs: nounwind willreturn -; ATTRIBUTOR-NEXT: define void @invoke_test() -define void @invoke_test() personality i32 (...)* @__gxx_personality_v0 { - invoke i1 @maybe_raise_exception() - to label %N unwind label %F - N: - ret void - F: - %val = landingpad { i8*, i32 } - catch i8* null - ret void -} - -declare i32 @__gxx_personality_v0(...) - - -; TEST 11 (positive case) -; counstant trip count -; int loop_constant_trip_count(int*p){ -; int ans = 0; -; for(int i = 0;i<10;i++){ -; ans += p[i]; -; } -; return ans; -; } - -; FIXME: missing willreturn -; FNATTR: Function Attrs: noinline norecurse nounwind readonly uwtable -; FNATTR-NEXT: define i32 @loop_constant_trip_count(i32* nocapture readonly %0) -; ATTRIBUTOR: Function Attrs: nofree noinline norecurse nosync nounwind readonly uwtable -; ATTRIBUTOR-NEXT: define i32 @loop_constant_trip_count(i32* nocapture nofree readonly %0) -define i32 @loop_constant_trip_count(i32* nocapture readonly %0) #0 { - br label %3 - -; <label>:2: ; preds = %3 - ret i32 %8 - -; <label>:3: ; preds = %3, %1 - %4 = phi i64 [ 0, %1 ], [ %9, %3 ] - %5 = phi i32 [ 0, %1 ], [ %8, %3 ] - %6 = getelementptr inbounds i32, i32* %0, i64 %4 - %7 = load i32, i32* %6, align 4 - %8 = add nsw i32 %7, %5 - %9 = add nuw nsw i64 %4, 1 - %10 = icmp eq i64 %9, 10 - br i1 %10, label %2, label %3 -} - - -; TEST 12 (negative case) -; unbounded trip count - -; int loop_trip_count_unbound(unsigned s,unsigned e, int *p, int offset){ -; int ans = 0; -; for(unsigned i = s;i != e;i+=offset){ -; ans += p[i]; -; } -; return ans; -; } -; FNATTR: Function Attrs: noinline norecurse nounwind readonly uwtable -; FNATTR-NOT: willreturn -; FNATTR-NEXT: define i32 @loop_trip_count_unbound(i32 %0, i32 %1, i32* nocapture readonly %2, i32 %3) local_unnamed_addr -; ATTRIBUTOR: Function Attrs: nofree noinline norecurse nosync nounwind readonly uwtable -; ATTRIBUTOR-NOT: willreturn -; ATTRIBUTOR-NEXT: define i32 @loop_trip_count_unbound(i32 %0, i32 %1, i32* nocapture nofree readonly %2, i32 %3) local_unnamed_addr -define i32 @loop_trip_count_unbound(i32 %0, i32 %1, i32* nocapture readonly %2, i32 %3) local_unnamed_addr #0 { - %5 = icmp eq i32 %0, %1 - br i1 %5, label %6, label %8 - -; <label>:6: ; preds = %8, %4 - %7 = phi i32 [ 0, %4 ], [ %14, %8 ] - ret i32 %7 - -; <label>:8: ; preds = %4, %8 - %9 = phi i32 [ %15, %8 ], [ %0, %4 ] - %10 = phi i32 [ %14, %8 ], [ 0, %4 ] - %11 = zext i32 %9 to i64 - %12 = getelementptr inbounds i32, i32* %2, i64 %11 - %13 = load i32, i32* %12, align 4 - %14 = add nsw i32 %13, %10 - %15 = add i32 %9, %3 - %16 = icmp eq i32 %15, %1 - br i1 %16, label %6, label %8 -} - - -; TEST 13 (positive case) -; Function Attrs: norecurse nounwind readonly uwtable -; int loop_trip_dec(int n, int *p){ -; int ans = 0; -; for(;n >= 0;n--){ -; ans += p[n]; -; } -; return ans; -; } - - -; FIXME: missing willreturn -; FNATTR: Function Attrs: noinline norecurse nounwind readonly uwtable -; FNATTR-NEXT: define i32 @loop_trip_dec(i32 %0, i32* nocapture readonly %1) -; ATTRIBUTOR: Function Attrs: nofree noinline norecurse nosync nounwind readonly uwtable -; ATTRIBUTOR-NEXT: define i32 @loop_trip_dec(i32 %0, i32* nocapture nofree readonly %1) local_unnamed_addr - -define i32 @loop_trip_dec(i32 %0, i32* nocapture readonly %1) local_unnamed_addr #0 { - %3 = icmp sgt i32 %0, -1 - br i1 %3, label %4, label %14 - -; <label>:4: ; preds = %2 - %5 = sext i32 %0 to i64 - br label %6 - -; <label>:6: ; preds = %4, %6 - %7 = phi i64 [ %5, %4 ], [ %12, %6 ] - %8 = phi i32 [ 0, %4 ], [ %11, %6 ] - %9 = getelementptr inbounds i32, i32* %1, i64 %7 - %10 = load i32, i32* %9, align 4 - %11 = add nsw i32 %10, %8 - %12 = add nsw i64 %7, -1 - %13 = icmp sgt i64 %7, 0 - br i1 %13, label %6, label %14 - -; <label>:14: ; preds = %6, %2 - %15 = phi i32 [ 0, %2 ], [ %11, %6 ] - ret i32 %15 -} - -; TEST 14 (positive case) -; multiple return - -; FNATTR: Function Attrs: noinline norecurse nounwind readnone uwtable -; FNATTR-NEXT: define i32 @multiple_return(i32 %a) -; ATTRIBUTOR: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable willreturn -; ATTRIBUTOR-NEXT: define i32 @multiple_return(i32 %a) -define i32 @multiple_return(i32 %a) #0 { - %b = icmp eq i32 %a, 0 - br i1 %b, label %t, label %f - -t: - ret i32 1 -f: - ret i32 0 -} - -; TEST 15 (positive & negative case) -; unreachable exit - -; 15.1 (positive case) -; FNATTR: Function Attrs: noinline nounwind uwtable -; FNATTR-NEXT: define void @unreachable_exit_positive1() -; ATTRIBUTOR: Function Attrs: noinline norecurse nounwind uwtable willreturn -; ATTRIBUTOR-NEXT: define void @unreachable_exit_positive1() -define void @unreachable_exit_positive1() #0 { - tail call void @will_return() - ret void - -unreachable_label: - tail call void @exit(i32 0) - unreachable -} - -; FIXME: missing willreturn -; FNATTR: Function Attrs: noinline nounwind uwtable -; FNATTR-NEXT: define i32 @unreachable_exit_positive2(i32 %0) -; ATTRIBUTOR: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable -; ATTRIBUTOR-NEXT: define i32 @unreachable_exit_positive2(i32 %0) -define i32 @unreachable_exit_positive2(i32) local_unnamed_addr #0 { - %2 = icmp slt i32 %0, 1 - br i1 %2, label %3, label %5 - -; <label>:3: ; preds = %5, %1 - %4 = phi i32 [ 1, %1 ], [ %8, %5 ] - ret i32 %4 - -; <label>:5: ; preds = %1, %5 - %6 = phi i32 [ %9, %5 ], [ 1, %1 ] - %7 = phi i32 [ %8, %5 ], [ 1, %1 ] - %8 = mul nsw i32 %6, %7 - %9 = add nuw nsw i32 %6, 1 - %10 = icmp eq i32 %6, %0 - br i1 %10, label %3, label %5 - -unreachable_label: - tail call void @exit(i32 0) - unreachable -} - - -;15.2 - -; FNATTR: Function Attrs: noinline nounwind uwtable -; FNATTR-NOT: willreturn -; FNATTR-NEXT: define void @unreachable_exit_negative1() -; ATTRIBUTOR: Function Attrs: noinline noreturn nounwind uwtable -; ATTRIBUTOR-NOT: willreturn -; ATTRIBUTOR-NEXT: define void @unreachable_exit_negative1() -define void @unreachable_exit_negative1() #0 { - tail call void @exit(i32 0) - ret void - -unreachable_label: - tail call void @exit(i32 0) - unreachable -} - -; FNATTR: Function Attrs: noinline nounwind uwtable -; FNATTR-NOT: willreturn -; FNATTR-NEXT: define void @unreachable_exit_negative2() -; ATTRIBUTOR: Function Attrs: nofree noinline norecurse noreturn nosync nounwind readnone uwtable -; ATTRIBUTOR-NOT: willreturn -; ATTRIBUTOR-NEXT: define void @unreachable_exit_negative2() -define void @unreachable_exit_negative2() #0 { - - br label %L1 -L1: - br label %L2 -L2: - br label %L1 - -unreachable_label: - tail call void @exit(i32 0) - unreachable -} - -; FNATTR: Function Attrs: noreturn nounwind -; FNATTR-NEXT: declare void @llvm.eh.sjlj.longjmp(i8*) -; ATTRIBUTOR: Function Attrs: noreturn nounwind -; ATTRIBUTOR-NEXT: declare void @llvm.eh.sjlj.longjmp(i8*) -declare void @llvm.eh.sjlj.longjmp(i8*) - -; FNATTR: Function Attrs: noinline nounwind uwtable -; FNATTR-NOT: willreturn -; FNATTR-NEXT: define void @call_longjmp(i8* nocapture readnone %0) local_unnamed_addr #3 { -; ATTRIBUTOR: Function Attrs: noinline noreturn nounwind uwtable -; ATTRIBUTOR-NOT: willreturn -; ATTRIBUTOR-NEXT: define void @call_longjmp(i8* nocapture readnone %0) local_unnamed_addr -define void @call_longjmp(i8* nocapture readnone %0) local_unnamed_addr #0 { - tail call void @llvm.eh.sjlj.longjmp(i8* %0) - ret void -} - - -attributes #0 = { nounwind uwtable noinline } -attributes #1 = { uwtable noinline } |

