365 changes: 355 additions & 10 deletions llvm/lib/Transforms/IPO/Attributor.cpp

Large diffs are not rendered by default.

30 changes: 15 additions & 15 deletions llvm/test/Transforms/FunctionAttrs/align.ll
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
; RUN: opt -attributor -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=6 -S < %s | FileCheck %s --check-prefix=ATTRIBUTOR
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=6 -S < %s | FileCheck %s --check-prefix=ATTRIBUTOR

target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"

Expand All @@ -7,26 +7,26 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"


; TEST 1
; ATTRIBUTOR: define align 8 i32* @test1(i32* returned align 8 %0)
; ATTRIBUTOR: define align 8 i32* @test1(i32* 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* returned %0)
; ATTRIBUTOR: define i32* @test2(i32* returned "no-capture-maybe-returned" %0)
define i32* @test2(i32* %0) #0 {
ret i32* %0
}

; TEST 3
; ATTRIBUTOR: define align 4 i32* @test3(i32* align 8 %0, i32* align 4 %1, i1 %2)
; ATTRIBUTOR: define align 4 i32* @test3(i32* align 8 "no-capture-maybe-returned" %0, i32* 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* align 32 %0, i32* align 32 %1, i1 %2)
; ATTRIBUTOR: define align 32 i32* @test4(i32* align 32 "no-capture-maybe-returned" %0, i32* 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
Expand Down Expand Up @@ -83,7 +83,7 @@ define i32* @test6_2() #0 {

; Function Attrs: nounwind readnone ssp uwtable
define internal i8* @f1(i8* readnone %0) local_unnamed_addr #0 {
; ATTRIBUTOR: define internal nonnull align 8 dereferenceable(1) i8* @f1(i8* nonnull readnone align 8 dereferenceable(1) %0)
; ATTRIBUTOR: define internal nonnull align 8 dereferenceable(1) i8* @f1(i8* nonnull readnone align 8 dereferenceable(1) "no-capture-maybe-returned" %0)
%2 = icmp eq i8* %0, null
br i1 %2, label %3, label %5

Expand All @@ -101,13 +101,13 @@ define internal i8* @f1(i8* readnone %0) local_unnamed_addr #0 {

; Function Attrs: nounwind readnone ssp uwtable
define internal i8* @f2(i8* readnone %0) local_unnamed_addr #0 {
; ATTRIBUTOR: define internal nonnull align 8 dereferenceable(1) i8* @f2(i8* nonnull readnone align 8 dereferenceable(1) %0)
; ATTRIBUTOR: define internal nonnull align 8 dereferenceable(1) i8* @f2(i8* nonnull readnone align 8 dereferenceable(1) "no-capture-maybe-returned" %0)
%2 = icmp eq i8* %0, null
br i1 %2, label %5, label %3

; <label>:3: ; preds = %1

; ATTRIBUTOR: %4 = tail call i8* @f1(i8* nonnull align 8 dereferenceable(1) %0)
; ATTRIBUTOR: %4 = tail call i8* @f1(i8* nonnull align 8 dereferenceable(1) "no-capture-maybe-returned" %0)
%4 = tail call i8* @f1(i8* nonnull %0)
br label %7

Expand All @@ -123,7 +123,7 @@ define internal i8* @f2(i8* readnone %0) local_unnamed_addr #0 {

; Function Attrs: nounwind readnone ssp uwtable
define internal i8* @f3(i8* readnone %0) local_unnamed_addr #0 {
; ATTRIBUTOR: define internal nonnull align 8 dereferenceable(1) i8* @f3(i8* nonnull readnone align 16 dereferenceable(1) %0)
; ATTRIBUTOR: define internal nonnull align 8 dereferenceable(1) i8* @f3(i8* nocapture nonnull readnone align 16 dereferenceable(1) %0)
%2 = icmp eq i8* %0, null
br i1 %2, label %3, label %5

Expand All @@ -139,7 +139,7 @@ define internal i8* @f3(i8* readnone %0) local_unnamed_addr #0 {

; TEST 7
; Better than IR information
; ATTRIBUTOR: define align 32 i32* @test7(i32* returned align 32 %p)
; ATTRIBUTOR: define align 32 i32* @test7(i32* returned align 32 "no-capture-maybe-returned" %p)
define align 4 i32* @test7(i32* align 32 %p) #0 {
tail call i8* @f1(i8* align 8 dereferenceable(1) @a1)
ret i32* %p
Expand All @@ -162,7 +162,7 @@ define void @test8_helper() {
}

define internal void @test8(i32* %a, i32* %b, i32* %c) {
; ATTRIBUTOR: define internal void @test8(i32* align 4 %a, i32* align 4 %b, i32* %c)
; ATTRIBUTOR: define internal void @test8(i32* nocapture align 4 %a, i32* nocapture align 4 %b, i32* nocapture %c)
ret void
}

Expand All @@ -174,8 +174,8 @@ define void @test9_traversal(i1 %c, i32* align 4 %B, i32* align 8 %C) {
}

; FIXME: This will work with an upcoming patch (D66618 or similar)
; define align 32 i32* @test10a(i32* align 32 %p)
; ATTRIBUTOR: define i32* @test10a(i32* align 32 %p)
; define align 32 i32* @test10a(i32* align 32 "no-capture-maybe-returned" %p)
; ATTRIBUTOR: define i32* @test10a(i32* align 32 "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
Expand All @@ -202,8 +202,8 @@ e:
}

; FIXME: This will work with an upcoming patch (D66618 or similar)
; define align 32 i32* @test10b(i32* align 32 %p)
; ATTRIBUTOR: define i32* @test10b(i32* align 32 %p)
; define align 32 i32* @test10b(i32* align 32 "no-capture-maybe-returned" %p)
; ATTRIBUTOR: define i32* @test10b(i32* align 32 "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
Expand Down
27 changes: 12 additions & 15 deletions llvm/test/Transforms/FunctionAttrs/arg_nocapture.ll
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
; RUN: opt -functionattrs -attributor -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=8 -S < %s | FileCheck %s
; RUN: opt -functionattrs -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=8 -S < %s | FileCheck %s
;
; Test cases specifically designed for the "no-capture" argument attribute.
; We use FIXME's to indicate problems and missing attributes.
Expand Down Expand Up @@ -112,15 +112,12 @@ entry:

; TEST SCC with various calls, casts, and comparisons agains NULL
;
; FIXME: no-capture missing for %a
; CHECK: define float* @scc_A(i32* readnone returned %a)
; CHECK: define dereferenceable_or_null(4) float* @scc_A(i32* readnone returned dereferenceable_or_null(4) "no-capture-maybe-returned" %a)
;
; FIXME: no-capture missing for %a
; CHECK: define i64* @scc_B(double* readnone returned %a)
; CHECK: define dereferenceable_or_null(8) i64* @scc_B(double* readnone returned dereferenceable_or_null(8) "no-capture-maybe-returned" %a)
;
; FIXME: readnone missing for %s
; FIXME: no-capture missing for %a
; CHECK: define i8* @scc_C(i16* returned %a)
; CHECK: define dereferenceable_or_null(2) i8* @scc_C(i16* returned dereferenceable_or_null(2) "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);
Expand All @@ -133,7 +130,7 @@ entry:
; void *scc_C(short *a) {
; return scc_A((int*)(scc_A(a) ? scc_B((double*)a) : scc_C(a)));
; }
define float* @scc_A(i32* %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
Expand All @@ -157,7 +154,7 @@ cond.end: ; preds = %cond.false, %cond.t
ret float* %4
}

define i64* @scc_B(double* %a) {
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
Expand All @@ -181,7 +178,7 @@ cond.end: ; preds = %cond.false, %cond.t
ret i64* %4
}

define i8* @scc_C(i16* %a) {
define i8* @scc_C(i16* dereferenceable_or_null(2) %a) {
entry:
%bc = bitcast i16* %a to i32*
%call = call float* @scc_A(i32* %bc)
Expand Down Expand Up @@ -248,7 +245,7 @@ declare i32 @printf(i8* nocapture, ...)
; }
;
; There should *not* be a no-capture attribute on %a
; CHECK: define i64* @not_captured_but_returned_0(i64* returned %a)
; CHECK: define i64* @not_captured_but_returned_0(i64* returned "no-capture-maybe-returned" %a)
define i64* @not_captured_but_returned_0(i64* %a) #0 {
entry:
store i64 0, i64* %a, align 8
Expand All @@ -263,7 +260,7 @@ entry:
; }
;
; There should *not* be a no-capture attribute on %a
; CHECK: define nonnull i64* @not_captured_but_returned_1(i64* %a)
; CHECK: define nonnull i64* @not_captured_but_returned_1(i64* "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
Expand All @@ -279,7 +276,7 @@ entry:
; }
;
; FIXME: no-capture missing for %a
; CHECK: define void @test_not_captured_but_returned_calls(i64* %a)
; CHECK: define void @test_not_captured_but_returned_calls(i64* nocapture %a)
define void @test_not_captured_but_returned_calls(i64* %a) #0 {
entry:
%call = call i64* @not_captured_but_returned_0(i64* %a)
Expand All @@ -294,7 +291,7 @@ entry:
; }
;
; There should *not* be a no-capture attribute on %a
; CHECK: define i64* @negative_test_not_captured_but_returned_call_0a(i64* returned %a)
; CHECK: define i64* @negative_test_not_captured_but_returned_call_0a(i64* returned "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)
Expand Down Expand Up @@ -324,7 +321,7 @@ entry:
; }
;
; There should *not* be a no-capture attribute on %a
; CHECK: define nonnull i64* @negative_test_not_captured_but_returned_call_1a(i64* %a)
; CHECK: define nonnull i64* @negative_test_not_captured_but_returned_call_1a(i64* "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)
Expand Down
26 changes: 13 additions & 13 deletions llvm/test/Transforms/FunctionAttrs/arg_returned.ll
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
; RUN: opt -functionattrs -S < %s | FileCheck %s --check-prefix=FNATTR
; RUN: opt -attributor -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=9 -S < %s | FileCheck %s --check-prefix=ATTRIBUTOR
; RUN: opt -attributor -attributor-disable=false -functionattrs -S < %s | FileCheck %s --check-prefix=BOTH
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=9 -S < %s | FileCheck %s --check-prefix=ATTRIBUTOR
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -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.
Expand Down Expand Up @@ -160,7 +160,7 @@ return: ; preds = %cond.end, %if.then3
; TEST SCC test returning a pointer value argument
;
; BOTH: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
; BOTH-NEXT: define double* @ptr_sink_r0(double* readnone returned %r)
; BOTH-NEXT: define double* @ptr_sink_r0(double* readnone returned "no-capture-maybe-returned" %r)
; BOTH: Function Attrs: nofree noinline nosync nounwind readnone uwtable
; BOTH-NEXT: define double* @ptr_scc_r1(double* %a, double* readnone returned %r, double* nocapture readnone %b)
; BOTH: Function Attrs: nofree noinline nosync nounwind readnone uwtable
Expand All @@ -171,9 +171,9 @@ return: ; preds = %cond.end, %if.then3
; FNATTR: define double* @ptr_scc_r2(double* readnone %a, double* readnone %b, double* readnone %r)
;
; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
; ATTRIBUTOR-NEXT: define double* @ptr_sink_r0(double* returned %r)
; ATTRIBUTOR-NEXT: define double* @ptr_sink_r0(double* returned "no-capture-maybe-returned" %r)
; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
; ATTRIBUTOR-NEXT: define double* @ptr_scc_r1(double* %a, double* returned %r, double* %b)
; ATTRIBUTOR-NEXT: define double* @ptr_scc_r1(double* %a, double* returned %r, double* nocapture %b)
; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
; ATTRIBUTOR-NEXT: define double* @ptr_scc_r2(double* %a, double* %b, double* returned %r)
;
Expand Down Expand Up @@ -261,7 +261,7 @@ return: ; preds = %cond.end, %if.then3
;
; FNATTR: define i32* @rt0(i32* readonly %a)
; BOTH: Function Attrs: nofree noinline noreturn nosync nounwind readonly uwtable
; BOTH-NEXT: define noalias nonnull align 536870912 dereferenceable(4294967295) i32* @rt0(i32* readonly %a)
; BOTH-NEXT: define noalias nonnull align 536870912 dereferenceable(4294967295) i32* @rt0(i32* nocapture readonly %a)
define i32* @rt0(i32* %a) #0 {
entry:
%v = load i32, i32* %a, align 4
Expand Down Expand Up @@ -294,7 +294,7 @@ entry:
; FNATTR: define i32* @rt2_helper(i32* %a)
; FNATTR: define i32* @rt2(i32* readnone %a, i32* readnone %b)
; BOTH: define i32* @rt2_helper(i32* returned %a)
; BOTH: define i32* @rt2(i32* readnone %a, i32* readnone %b)
; BOTH: define i32* @rt2(i32* readnone %a, i32* readnone "no-capture-maybe-returned" %b)
define i32* @rt2_helper(i32* %a) #0 {
entry:
%call = call i32* @rt2(i32* %a, i32* %a)
Expand All @@ -319,8 +319,8 @@ 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* %a, i32* returned %b)
; BOTH: define i32* @rt3(i32* readnone %a, i32* readnone returned %b)
; BOTH: define i32* @rt3_helper(i32* %a, i32* returned "no-capture-maybe-returned" %b)
; BOTH: define i32* @rt3(i32* readnone %a, i32* 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)
Expand Down Expand Up @@ -353,9 +353,9 @@ if.end:
; BOTH: declare void @unknown_fn(i32* (i32*)*)
;
; BOTH: Function Attrs: noinline nounwind uwtable
; BOTH-NEXT: define i32* @calls_unknown_fn(i32* readnone returned %r)
; 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* returned %r)
; ATTRIBUTOR: define i32* @calls_unknown_fn(i32* returned "no-capture-maybe-returned" %r)
declare void @unknown_fn(i32* (i32*)*) #0

define i32* @calls_unknown_fn(i32* %r) #0 {
Expand Down Expand Up @@ -502,12 +502,12 @@ if.end: ; preds = %if.then, %entry
; }
;
; BOTH: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
; BOTH-NEXT: define double* @bitcast(i32* readnone returned %b)
; BOTH-NEXT: define double* @bitcast(i32* readnone returned "no-capture-maybe-returned" %b)
;
; FNATTR: define double* @bitcast(i32* readnone %b)
;
; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
; ATTRIBUTOR-NEXT: define double* @bitcast(i32* returned %b)
; ATTRIBUTOR-NEXT: define double* @bitcast(i32* returned "no-capture-maybe-returned" %b)
define double* @bitcast(i32* %b) #0 {
entry:
%bc0 = bitcast i32* %b to double*
Expand Down
14 changes: 7 additions & 7 deletions llvm/test/Transforms/FunctionAttrs/dereferenceable.ll
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
; RUN: opt -attributor --attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=4 -S < %s | FileCheck %s --check-prefixes=ATTRIBUTOR
; RUN: opt -attributor -attributor-manifest-internal --attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=4 -S < %s | FileCheck %s --check-prefixes=ATTRIBUTOR


declare void @deref_phi_user(i32* %a);
Expand All @@ -7,15 +7,15 @@ declare void @deref_phi_user(i32* %a);
; 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* nonnull dereferenceable(4) %0, double* nonnull dereferenceable(8) %1, i1 zeroext %2)
; ATTRIBUTOR: define nonnull dereferenceable(4) i32* @test1(i32* nonnull dereferenceable(4) "no-capture-maybe-returned" %0, double* nonnull 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* dereferenceable_or_null(4) %0, double* nonnull dereferenceable(8) %1, i1 zeroext %2)
; ATTRIBUTOR: define dereferenceable_or_null(4) i32* @test2(i32* dereferenceable_or_null(4) "no-capture-maybe-returned" %0, double* nonnull 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
Expand All @@ -24,20 +24,20 @@ define i32* @test2(i32* dereferenceable_or_null(4) %0, double* dereferenceable(8
; TEST 3
; GEP inbounds
define i32* @test3_1(i32* dereferenceable(8) %0) local_unnamed_addr {
; ATTRIBUTOR: define nonnull dereferenceable(4) i32* @test3_1(i32* nonnull dereferenceable(8) %0)
; ATTRIBUTOR: define nonnull dereferenceable(4) i32* @test3_1(i32* nonnull 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 {
; FIXME: Argument should be mark dereferenceable because of GEP `inbounds`.
; ATTRIBUTOR: define nonnull dereferenceable(16) i32* @test3_2(i32* dereferenceable_or_null(32) %0)
; ATTRIBUTOR: define nonnull dereferenceable(16) i32* @test3_2(i32* dereferenceable_or_null(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* nonnull dereferenceable(8) %0, i32* nonnull dereferenceable(16) %1, i1 %2) local_unnamed_addr
; ATTRIBUTOR: define nonnull dereferenceable(4) i32* @test3_3(i32* nonnull dereferenceable(8) "no-capture-maybe-returned" %0, i32* nonnull 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
Expand All @@ -48,7 +48,7 @@ define i32* @test3_3(i32* dereferenceable(8) %0, i32* dereferenceable(16) %1, i1
; 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* nonnull returned dereferenceable(8) %0)
; ATTRIBUTOR: define nonnull dereferenceable(8) i32* @test4(i32* nonnull returned dereferenceable(8) "no-capture-maybe-returned" %0)
ret i32* %0
}

Expand Down
4 changes: 2 additions & 2 deletions llvm/test/Transforms/FunctionAttrs/internal-noalias.ll
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ entry:

; FIXME: Should be something like this.
; define internal i32 @noalias_args(i32* nocapture readonly %A, i32* noalias nocapture readonly %B)
; CHECK: define internal i32 @noalias_args(i32* %A, i32* %B)
; CHECK: define internal i32 @noalias_args(i32* nocapture %A, i32* nocapture %B)

define internal i32 @noalias_args(i32* %A, i32* %B) #0 {
entry:
Expand All @@ -25,7 +25,7 @@ entry:

; 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* %A, i32* %B)
; CHECK: define internal i32 @noalias_args_argmem(i32* nocapture %A, i32* nocapture %B)
;
define internal i32 @noalias_args_argmem(i32* %A, i32* %B) #1 {
entry:
Expand Down
10 changes: 5 additions & 5 deletions llvm/test/Transforms/FunctionAttrs/liveness.ll
Original file line number Diff line number Diff line change
Expand Up @@ -40,19 +40,19 @@ define i32 @volatile_load(i32*) norecurse nounwind uwtable {
}

; CHECK: Function Attrs: nofree norecurse nosync nounwind uwtable willreturn
; CHECK-NEXT: define internal i32 @internal_load(i32* nonnull %0)
; CHECK-NEXT: define internal i32 @internal_load(i32* nocapture nonnull %0)
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* nonnull %ptr1, i32* %ptr2)
; CHECK-NEXT: define i32 @first_block_no_return(i32 %a, i32* nocapture nonnull %ptr1, i32* nocapture %ptr2)
define i32 @first_block_no_return(i32 %a, i32* nonnull %ptr1, i32* %ptr2) #0 {
entry:
call i32 @internal_load(i32* %ptr1)
; CHECK: call i32 @internal_load(i32* nonnull %ptr1)
; CHECK: call i32 @internal_load(i32* nocapture nonnull %ptr1)
call void @no_return_call()
; CHECK: call void @no_return_call()
; CHECK-NEXT: unreachable
Expand Down Expand Up @@ -85,7 +85,7 @@ cond.end: ; preds = %cond.false, %cond.t
; dead block and check if it is deduced.

; CHECK: Function Attrs: nosync
; CHECK-NEXT: define i32 @dead_block_present(i32 %a, i32* %ptr1)
; CHECK-NEXT: define i32 @dead_block_present(i32 %a, i32* nocapture %ptr1)
define i32 @dead_block_present(i32 %a, i32* %ptr1) #0 {
entry:
%cmp = icmp eq i32 %a, 0
Expand Down Expand Up @@ -240,7 +240,7 @@ cleanup:
; TEST 6: Undefined behvior, taken from LangRef.
; FIXME: Should be able to detect undefined behavior.

; CHECK: define void @ub(i32* %0)
; CHECK: define void @ub(i32* nocapture %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.
Expand Down
13 changes: 12 additions & 1 deletion llvm/test/Transforms/FunctionAttrs/noalias_returned.ll
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,17 @@ define i8* @return_noalias(){
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
Expand Down Expand Up @@ -142,7 +153,7 @@ define i8* @test8(i32* %0) nounwind uwtable {
; TEST 9
; Simple Argument Test
define internal void @test9(i8* %a, i8* %b) {
; CHECK: define internal void @test9(i8* noalias %a, i8* %b)
; CHECK: define internal void @test9(i8* noalias nocapture %a, i8* nocapture %b)
ret void
}
define void @test9_helper(i8* %a, i8* %b) {
Expand Down
116 changes: 71 additions & 45 deletions llvm/test/Transforms/FunctionAttrs/nocapture.ll
Original file line number Diff line number Diff line change
@@ -1,27 +1,30 @@
; RUN: opt < %s -functionattrs -S | FileCheck %s
; RUN: opt < %s -passes=function-attrs -S | FileCheck %s
; 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 < %s | FileCheck %s --check-prefixes=ATTRIBUTOR,EITHER
; RUN: opt -passes=attributor -attributor-manifest-internal -attributor-disable=false -S < %s | FileCheck %s --check-prefixes=ATTRIBUTOR,EITHER

@g = global i32* null ; <i32**> [#uses=1]

; CHECK: define i32* @c1(i32* readnone returned %q)
; FNATTR: define i32* @c1(i32* readnone returned %q)
; ATTRIBUTOR: define i32* @c1(i32* returned "no-capture-maybe-returned" %q)
define i32* @c1(i32* %q) {
ret i32* %q
}

; CHECK: define void @c2(i32* %q)
; EITHER: define void @c2(i32* %q)
; It would also be acceptable to mark %q as readnone. Update @c3 too.
define void @c2(i32* %q) {
store i32* %q, i32** @g
ret void
}

; CHECK: define void @c3(i32* %q)
; EITHER: define void @c3(i32* %q)
define void @c3(i32* %q) {
call void @c2(i32* %q)
ret void
}

; CHECK: define i1 @c4(i32* %q, i32 %bitno)
; EITHER: define i1 @c4(i32* %q, i32 %bitno)
define i1 @c4(i32* %q, i32 %bitno) {
%tmp = ptrtoint i32* %q to i32
%tmp2 = lshr i32 %tmp, %bitno
Expand All @@ -35,7 +38,7 @@ l1:

@lookup_table = global [2 x i1] [ i1 0, i1 1 ]

; CHECK: define i1 @c5(i32* %q, i32 %bitno)
; EITHER: define i1 @c5(i32* %q, i32 %bitno)
define i1 @c5(i32* %q, i32 %bitno) {
%tmp = ptrtoint i32* %q to i32
%tmp2 = lshr i32 %tmp, %bitno
Expand All @@ -48,7 +51,8 @@ define i1 @c5(i32* %q, i32 %bitno) {

declare void @throw_if_bit_set(i8*, i8) readonly

; CHECK: define i1 @c6(i8* readonly %q, i8 %bit)
; FNATTR: define i1 @c6(i8* readonly %q, i8 %bit)
; ATTRIBUTOR: define i1 @c6(i8* %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
Expand All @@ -70,15 +74,16 @@ define i1* @lookup_bit(i32* %q, i32 %bitno) readnone nounwind {
ret i1* %lookup
}

; CHECK: define i1 @c7(i32* readonly %q, i32 %bitno)
; FNATTR: define i1 @c7(i32* readonly %q, i32 %bitno)
; ATTRIBUTOR: define i1 @c7(i32* %q, i32 %bitno)
define i1 @c7(i32* %q, i32 %bitno) {
%ptr = call i1* @lookup_bit(i32* %q, i32 %bitno)
%val = load i1, i1* %ptr
ret i1 %val
}


; CHECK: define i32 @nc1(i32* %q, i32* nocapture %p, i1 %b)
; EITHER: define i32 @nc1(i32* %q, i32* nocapture %p, i1 %b)
define i32 @nc1(i32* %q, i32* %p, i1 %b) {
e:
br label %l
Expand All @@ -93,7 +98,7 @@ l:
ret i32 %val
}

; CHECK: define i32 @nc1_addrspace(i32* %q, i32 addrspace(1)* nocapture %p, i1 %b)
; EITHER: define i32 @nc1_addrspace(i32* %q, i32 addrspace(1)* nocapture %p, i1 %b)
define i32 @nc1_addrspace(i32* %q, i32 addrspace(1)* %p, i1 %b) {
e:
br label %l
Expand All @@ -108,78 +113,93 @@ l:
ret i32 %val
}

; CHECK: define void @nc2(i32* nocapture %p, i32* %q)
; EITHER: define void @nc2(i32* nocapture %p, i32* %q)
define void @nc2(i32* %p, i32* %q) {
%1 = call i32 @nc1(i32* %q, i32* %p, i1 0) ; <i32> [#uses=0]
ret void
}

; CHECK: define void @nc3(void ()* nocapture %p)
; EITHER: define void @nc3(void ()* nocapture %p)
define void @nc3(void ()* %p) {
call void %p()
ret void
}

declare void @external(i8*) readonly nounwind
; CHECK: define void @nc4(i8* nocapture readonly %p)
; FNATTR: define void @nc4(i8* nocapture readonly %p)
; ATTRIBUTOR: define void @nc4(i8* nocapture %p)
define void @nc4(i8* %p) {
call void @external(i8* %p)
ret void
}

; CHECK: define void @nc5(void (i8*)* nocapture %f, i8* nocapture %p)
; EITHER: define void @nc5(void (i8*)* nocapture %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)
ret void
}

; CHECK: define void @test1_1(i8* nocapture readnone %x1_1, i8* %y1_1)
; FNATTR: define void @test1_1(i8* nocapture readnone %x1_1, i8* %y1_1, i1 %c)
; ATTRIBUTOR: define void @test1_1(i8* nocapture %x1_1, i8* nocapture %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) {
call i8* @test1_2(i8* %x1_1, i8* %y1_1)
define void @test1_1(i8* %x1_1, i8* %y1_1, i1 %c) {
call i8* @test1_2(i8* %x1_1, i8* %y1_1, i1 %c)
store i32* null, i32** @g
ret void
}

; CHECK: define i8* @test1_2(i8* nocapture readnone %x1_2, i8* returned %y1_2)
define i8* @test1_2(i8* %x1_2, i8* %y1_2) {
call void @test1_1(i8* %x1_2, i8* %y1_2)
; FNATTR: define i8* @test1_2(i8* nocapture readnone %x1_2, i8* returned %y1_2, i1 %c)
; ATTRIBUTOR: define i8* @test1_2(i8* nocapture %x1_2, i8* 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:
call void @test1_1(i8* %x1_2, i8* %y1_2, i1 %c)
store i32* null, i32** @g
br label %f
f:
ret i8* %y1_2
}

; CHECK: define void @test2(i8* nocapture readnone %x2)
; FNATTR: define void @test2(i8* nocapture readnone %x2)
; ATTRIBUTOR: define void @test2(i8* nocapture %x2)
define void @test2(i8* %x2) {
call void @test2(i8* %x2)
store i32* null, i32** @g
ret void
}

; CHECK: define void @test3(i8* nocapture readnone %x3, i8* nocapture readnone %y3, i8* nocapture readnone %z3)
; FNATTR: define void @test3(i8* nocapture readnone %x3, i8* nocapture readnone %y3, i8* nocapture readnone %z3)
; ATTRIBUTOR: define void @test3(i8* nocapture %x3, i8* nocapture %y3, i8* nocapture %z3)
define void @test3(i8* %x3, i8* %y3, i8* %z3) {
call void @test3(i8* %z3, i8* %y3, i8* %x3)
store i32* null, i32** @g
ret void
}

; CHECK: define void @test4_1(i8* %x4_1)
define void @test4_1(i8* %x4_1) {
call i8* @test4_2(i8* %x4_1, i8* %x4_1, i8* %x4_1)
; FNATTR: define void @test4_1(i8* %x4_1, i1 %c)
; ATTRIBUTOR: define void @test4_1(i8* nocapture %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
ret void
}

; CHECK: define i8* @test4_2(i8* nocapture readnone %x4_2, i8* readnone returned %y4_2, i8* nocapture readnone %z4_2)
define i8* @test4_2(i8* %x4_2, i8* %y4_2, i8* %z4_2) {
call void @test4_1(i8* null)
; 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 %x4_2, i8* returned "no-capture-maybe-returned" %y4_2, i8* nocapture %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:
call void @test4_1(i8* null, i1 %c)
store i32* null, i32** @g
br label %f
f:
ret i8* %y4_2
}

declare i8* @test5_1(i8* %x5_1)

; CHECK: define void @test5_2(i8* %x5_2)
; EITHER: 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
Expand All @@ -188,40 +208,40 @@ define void @test5_2(i8* %x5_2) {

declare void @test6_1(i8* %x6_1, i8* nocapture %y6_1, ...)

; CHECK: define void @test6_2(i8* %x6_2, i8* nocapture %y6_2, i8* %z6_2)
; EITHER: 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
ret void
}

; CHECK: define void @test_cmpxchg(i32* nocapture %p)
; EITHER: define void @test_cmpxchg(i32* nocapture %p)
define void @test_cmpxchg(i32* %p) {
cmpxchg i32* %p, i32 0, i32 1 acquire monotonic
ret void
}

; CHECK: define void @test_cmpxchg_ptr(i32** nocapture %p, i32* %q)
; EITHER: define void @test_cmpxchg_ptr(i32** nocapture %p, i32* %q)
define void @test_cmpxchg_ptr(i32** %p, i32* %q) {
cmpxchg i32** %p, i32* null, i32* %q acquire monotonic
ret void
}

; CHECK: define void @test_atomicrmw(i32* nocapture %p)
; EITHER: define void @test_atomicrmw(i32* nocapture %p)
define void @test_atomicrmw(i32* %p) {
atomicrmw add i32* %p, i32 1 seq_cst
ret void
}

; CHECK: define void @test_volatile(i32* %x)
; EITHER: define void @test_volatile(i32* %x)
define void @test_volatile(i32* %x) {
entry:
%gep = getelementptr i32, i32* %x, i64 1
store volatile i32 0, i32* %gep, align 4
ret void
}

; CHECK: nocaptureLaunder(i8* nocapture %p)
; EITHER: nocaptureLaunder(i8* nocapture %p)
define void @nocaptureLaunder(i8* %p) {
entry:
%b = call i8* @llvm.launder.invariant.group.p0i8(i8* %p)
Expand All @@ -230,14 +250,14 @@ entry:
}

@g2 = global i8* null
; CHECK: define void @captureLaunder(i8* %p)
; EITHER: 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
ret void
}

; CHECK: @nocaptureStrip(i8* nocapture %p)
; EITHER: @nocaptureStrip(i8* nocapture %p)
define void @nocaptureStrip(i8* %p) {
entry:
%b = call i8* @llvm.strip.invariant.group.p0i8(i8* %p)
Expand All @@ -246,49 +266,55 @@ entry:
}

@g3 = global i8* null
; CHECK: define void @captureStrip(i8* %p)
; EITHER: define void @captureStrip(i8* %p)
define void @captureStrip(i8* %p) {
%b = call i8* @llvm.strip.invariant.group.p0i8(i8* %p)
store i8* %b, i8** @g3
ret void
}

; CHECK: define i1 @captureICmp(i32* readnone %x)
; FNATTR: define i1 @captureICmp(i32* readnone %x)
; ATTRIBUTOR: define i1 @captureICmp(i32* %x)
define i1 @captureICmp(i32* %x) {
%1 = icmp eq i32* %x, null
ret i1 %1
}

; CHECK: define i1 @captureICmpRev(i32* readnone %x)
; FNATTR: define i1 @captureICmpRev(i32* readnone %x)
; ATTRIBUTOR: define i1 @captureICmpRev(i32* %x)
define i1 @captureICmpRev(i32* %x) {
%1 = icmp eq i32* null, %x
ret i1 %1
}

; CHECK: define i1 @nocaptureInboundsGEPICmp(i32* nocapture readnone %x)
; FNATTR: define i1 @nocaptureInboundsGEPICmp(i32* nocapture readnone %x)
; ATTRIBUTOR: define i1 @nocaptureInboundsGEPICmp(i32* nocapture %x)
define i1 @nocaptureInboundsGEPICmp(i32* %x) {
%1 = getelementptr inbounds i32, i32* %x, i32 5
%2 = bitcast i32* %1 to i8*
%3 = icmp eq i8* %2, null
ret i1 %3
}

; CHECK: define i1 @nocaptureInboundsGEPICmpRev(i32* nocapture readnone %x)
; FNATTR: define i1 @nocaptureInboundsGEPICmpRev(i32* nocapture readnone %x)
; ATTRIBUTOR: define i1 @nocaptureInboundsGEPICmpRev(i32* nocapture %x)
define i1 @nocaptureInboundsGEPICmpRev(i32* %x) {
%1 = getelementptr inbounds i32, i32* %x, i32 5
%2 = bitcast i32* %1 to i8*
%3 = icmp eq i8* null, %2
ret i1 %3
}

; CHECK: define i1 @nocaptureDereferenceableOrNullICmp(i32* nocapture readnone dereferenceable_or_null(4) %x)
; FNATTR: define i1 @nocaptureDereferenceableOrNullICmp(i32* nocapture readnone dereferenceable_or_null(4) %x)
; ATTRIBUTOR: define i1 @nocaptureDereferenceableOrNullICmp(i32* nocapture 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
ret i1 %2
}

; CHECK: define i1 @captureDereferenceableOrNullICmp(i32* readnone dereferenceable_or_null(4) %x)
; FNATTR: define i1 @captureDereferenceableOrNullICmp(i32* readnone dereferenceable_or_null(4) %x)
; ATTRIBUTOR: define i1 @captureDereferenceableOrNullICmp(i32* 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
Expand Down
4 changes: 2 additions & 2 deletions llvm/test/Transforms/FunctionAttrs/nonnull.ll
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ define void @test13_helper() {
ret void
}
define internal void @test13(i8* %a, i8* %b, i8* %c) {
; ATTRIBUTOR: define internal void @test13(i8* nonnull %a, i8* %b, i8* %c)
; ATTRIBUTOR: define internal void @test13(i8* nocapture nonnull %a, i8* nocapture %b, i8* nocapture %c)
ret void
}

Expand Down Expand Up @@ -402,7 +402,7 @@ 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)
; FIXME : missing "nonnull", it should be @parent8(i8* nonnull %a, i8* %bogus1, i8* nonnull %b)
; ATTRIBUTOR-LABEL: @parent8(i8* %a, i8* %bogus1, i8* %b)
; ATTRIBUTOR-LABEL: @parent8(i8* %a, i8* nocapture %bogus1, i8* %b)
; BOTH-NEXT: entry:
; FNATTR-NEXT: invoke void @use2nonnull(i8* %a, i8* %b)
; ATTRIBUTOR-NEXT: invoke void @use2nonnull(i8* nonnull %a, i8* nonnull %b)
Expand Down
24 changes: 14 additions & 10 deletions llvm/test/Transforms/FunctionAttrs/nosync.ll
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
; RUN: opt -functionattrs -S < %s | FileCheck %s --check-prefix=FNATTR
; RUN: opt -attributor -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=4 -S < %s | FileCheck %s --check-prefix=ATTRIBUTOR
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=4 -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.
Expand Down Expand Up @@ -28,7 +28,7 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
; 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* %s)
; ATTRIBUTOR-NEXT: define nonnull i32* @foo(%struct.ST* "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
Expand Down Expand Up @@ -186,7 +186,7 @@ define void @call_might_sync() nounwind uwtable noinline {
; FNATTR: Function Attrs: nofree noinline nounwind uwtable
; FNATTR-NEXT: define i32 @scc1(i32* %0)
; ATTRIBUTOR: Function Attrs: nofree noinline noreturn nosync nounwind uwtable
; ATTRIBUTOR-NEXT: define i32 @scc1(i32* %0)
; ATTRIBUTOR-NEXT: define i32 @scc1(i32* nocapture %0)
define i32 @scc1(i32* %0) noinline nounwind uwtable {
tail call void @scc2(i32* %0);
%val = tail call i32 @volatile_load(i32* %0);
Expand All @@ -196,7 +196,7 @@ define i32 @scc1(i32* %0) noinline nounwind uwtable {
; FNATTR: Function Attrs: nofree noinline nounwind uwtable
; FNATTR-NEXT: define void @scc2(i32* %0)
; ATTRIBUTOR: Function Attrs: nofree noinline noreturn nosync nounwind uwtable
; ATTRIBUTOR-NEXT: define void @scc2(i32* %0)
; ATTRIBUTOR-NEXT: define void @scc2(i32* nocapture %0)
define void @scc2(i32* %0) noinline nounwind uwtable {
tail call i32 @scc1(i32* %0);
ret void;
Expand Down Expand Up @@ -224,7 +224,7 @@ define void @scc2(i32* %0) noinline nounwind uwtable {
; 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* %0, %"struct.std::atomic"* %1)
; ATTRIBUTOR: define void @foo1(i32* nocapture %0, %"struct.std::atomic"* nocapture %1)
define void @foo1(i32* %0, %"struct.std::atomic"* %1) {
store i32 100, i32* %0, align 4
fence release
Expand All @@ -236,7 +236,7 @@ define void @foo1(i32* %0, %"struct.std::atomic"* %1) {
; 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* %0, %"struct.std::atomic"* %1)
; ATTRIBUTOR: define void @bar(i32* nocapture %0, %"struct.std::atomic"* nocapture %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
Expand All @@ -256,7 +256,7 @@ define void @bar(i32* %0, %"struct.std::atomic"* %1) {
; 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
; ATTRIBUTOR: define void @foo1_singlethread(i32* %0, %"struct.std::atomic"* %1)
; ATTRIBUTOR: define void @foo1_singlethread(i32* nocapture %0, %"struct.std::atomic"* nocapture %1)
define void @foo1_singlethread(i32* %0, %"struct.std::atomic"* %1) {
store i32 100, i32* %0, align 4
fence syncscope("singlethread") release
Expand All @@ -268,7 +268,7 @@ define void @foo1_singlethread(i32* %0, %"struct.std::atomic"* %1) {
; 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
; ATTRIBUTOR: define void @bar_singlethread(i32* %0, %"struct.std::atomic"* %1)
; ATTRIBUTOR: define void @bar_singlethread(i32* nocapture %0, %"struct.std::atomic"* nocapture %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
Expand All @@ -289,18 +289,22 @@ 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* %ptr1, i8* %ptr2)
; ATTRIBUTOR-NEXT: define i32 @memcpy_volatile(i8* nocapture %ptr1, i8* nocapture %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* %ptr1, i8 %val)
; ATTRIBUTOR-NEXT: define i32 @memset_non_volatile(i8* nocapture %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
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
; RUN: opt -functionattrs -enable-nonnull-arg-prop -attributor -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=6 -S < %s | FileCheck %s
; RUN: opt -functionattrs -enable-nonnull-arg-prop -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -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
Expand Down Expand Up @@ -102,7 +102,7 @@ return: ; preds = %if.end, %if.then
}

; CHECK: Function Attrs: nofree norecurse nosync nounwind
; CHECK-NEXT: define i32* @external_sink_ret2_nrw(i32* readnone %n0, i32* nocapture readonly %r0, i32* returned %w0)
; CHECK-NEXT: define i32* @external_sink_ret2_nrw(i32* readnone %n0, i32* nocapture readonly %r0, i32* returned "no-capture-maybe-returned" %w0)
define i32* @external_sink_ret2_nrw(i32* %n0, i32* %r0, i32* %w0) {
entry:
%tobool = icmp ne i32* %n0, null
Expand Down