jdoerfert updated this revision to Diff 192962.
jdoerfert added a comment.

Closed a side-channel through "integers"


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D59922/new/

https://reviews.llvm.org/D59922

Files:
  clang/test/CodeGenObjC/os_log.m
  clang/test/CodeGenOpenCL/as_type.cl
  llvm/include/llvm/Transforms/IPO/Attributor.h
  llvm/lib/Transforms/IPO/Attributor.cpp
  llvm/test/Transforms/FunctionAttrs/2009-01-02-LocalStores.ll
  llvm/test/Transforms/FunctionAttrs/SCC1.ll
  llvm/test/Transforms/FunctionAttrs/arg_nocapture.ll
  llvm/test/Transforms/FunctionAttrs/arg_returned.ll
  llvm/test/Transforms/FunctionAttrs/incompatible_fn_attrs.ll
  llvm/test/Transforms/FunctionAttrs/nocapture.ll
  llvm/test/Transforms/FunctionAttrs/readattrs.ll

Index: llvm/test/Transforms/FunctionAttrs/readattrs.ll
===================================================================
--- llvm/test/Transforms/FunctionAttrs/readattrs.ll
+++ llvm/test/Transforms/FunctionAttrs/readattrs.ll
@@ -12,7 +12,7 @@
   ret void
 }
 
-; CHECK: define i8* @test2(i8* readnone returned %p)
+; CHECK: define i8* @test2(i8* readnone returned "no-capture-maybe-returned" %p)
 define i8* @test2(i8* %p) {
   store i32 0, i32* @x
   ret i8* %p
@@ -54,13 +54,13 @@
   ret void
 }
 
-; CHECK: define i32* @test8_1(i32* readnone returned %p)
+; CHECK: define i32* @test8_1(i32* readnone returned "no-capture-maybe-returned" %p)
 define i32* @test8_1(i32* %p) {
 entry:
   ret i32* %p
 }
 
-; CHECK: define void @test8_2(i32* %p)
+; CHECK: define void @test8_2(i32* nocapture %p)
 define void @test8_2(i32* %p) {
 entry:
   %call = call i32* @test8_1(i32* %p)
Index: llvm/test/Transforms/FunctionAttrs/nocapture.ll
===================================================================
--- llvm/test/Transforms/FunctionAttrs/nocapture.ll
+++ llvm/test/Transforms/FunctionAttrs/nocapture.ll
@@ -3,7 +3,7 @@
 
 @g = global i32* null		; <i32**> [#uses=1]
 
-; CHECK: define i32* @c1(i32* readnone returned %q)
+; CHECK: define i32* @c1(i32* readnone returned "no-capture-maybe-returned" %q)
 define i32* @c1(i32* %q) {
 	ret i32* %q
 }
@@ -134,7 +134,7 @@
 	ret void
 }
 
-; CHECK: define void @test1_1(i8* nocapture readnone %x1_1, i8* %y1_1)
+; CHECK: define void @test1_1(i8* nocapture %x1_1, i8* nocapture %y1_1)
 ; 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)
@@ -142,7 +142,7 @@
   ret void
 }
 
-; CHECK: define i8* @test1_2(i8* nocapture readnone %x1_2, i8* returned %y1_2)
+; CHECK: define i8* @test1_2(i8* nocapture %x1_2, i8* returned "no-capture-maybe-returned" %y1_2)
 define i8* @test1_2(i8* %x1_2, i8* %y1_2) {
   call void @test1_1(i8* %x1_2, i8* %y1_2)
   store i32* null, i32** @g
@@ -156,21 +156,21 @@
   ret void
 }
 
-; CHECK: define void @test3(i8* nocapture readnone %x3, i8* nocapture readnone %y3, i8* nocapture readnone %z3)
+; CHECK: define void @test3(i8* nocapture %x3, i8* nocapture readnone %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)
+; CHECK: define void @test4_1(i8* nocapture readnone %x4_1)
 define void @test4_1(i8* %x4_1) {
   call i8* @test4_2(i8* %x4_1, i8* %x4_1, i8* %x4_1)
   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)
+; CHECK: define i8* @test4_2(i8* nocapture readnone %x4_2, i8* readnone returned "no-capture-maybe-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)
   store i32* null, i32** @g
Index: llvm/test/Transforms/FunctionAttrs/incompatible_fn_attrs.ll
===================================================================
--- llvm/test/Transforms/FunctionAttrs/incompatible_fn_attrs.ll
+++ llvm/test/Transforms/FunctionAttrs/incompatible_fn_attrs.ll
@@ -6,21 +6,21 @@
 
 ; Function Attrs: argmemonly
 define i32* @given_argmem_infer_readnone(i32* %p) #0 {
-; CHECK: define i32* @given_argmem_infer_readnone(i32* readnone returned %p) #0 {
+; CHECK: define i32* @given_argmem_infer_readnone(i32* readnone returned "no-capture-maybe-returned" %p) #0 {
 entry:
   ret i32* %p
 }
 
 ; Function Attrs: inaccessiblememonly
 define i32* @given_inaccessible_infer_readnone(i32* %p) #1 {
-; CHECK: define i32* @given_inaccessible_infer_readnone(i32* readnone returned %p) #0 {
+; CHECK: define i32* @given_inaccessible_infer_readnone(i32* readnone returned "no-capture-maybe-returned" %p) #0 {
 entry:
   ret i32* %p
 }
 
 ; Function Attrs: inaccessiblemem_or_argmemonly
 define i32* @given_inaccessible_or_argmem_infer_readnone(i32* %p) #2 {
-; CHECK: define i32* @given_inaccessible_or_argmem_infer_readnone(i32* readnone returned %p) #0 {
+; CHECK: define i32* @given_inaccessible_or_argmem_infer_readnone(i32* readnone returned "no-capture-maybe-returned" %p) #0 {
 entry:
   ret i32* %p
 }
Index: llvm/test/Transforms/FunctionAttrs/arg_returned.ll
===================================================================
--- llvm/test/Transforms/FunctionAttrs/arg_returned.ll
+++ llvm/test/Transforms/FunctionAttrs/arg_returned.ll
@@ -172,7 +172,7 @@
 
 ; TEST 2
 ;
-; BOTH: define dso_local double* @ptr_sink_r0(double* readnone returned %r) [[NoInlineNoRecurseNoUnwindReadnoneUwtable]]
+; BOTH: define dso_local double* @ptr_sink_r0(double* readnone returned "no-capture-maybe-returned" %r) [[NoInlineNoRecurseNoUnwindReadnoneUwtable]]
 ; BOTH: define dso_local double* @ptr_scc_r1(double* %a, double* readnone returned %r, double* nocapture readnone %b) [[NoInlineNoUnwindReadnoneUwtable]]
 ; BOTH: define dso_local double* @ptr_scc_r2(double* readnone %a, double* readnone %b, double* readnone returned %r) [[NoInlineNoUnwindReadnoneUwtable]]
 ;
@@ -180,8 +180,8 @@
 ; FNATTR: define dso_local double* @ptr_scc_r1(double* %a, double* readnone %r, double* nocapture readnone %b) [[NoInlineNoUnwindReadnoneUwtable]]
 ; FNATTR: define dso_local double* @ptr_scc_r2(double* readnone %a, double* readnone %b, double* readnone %r) [[NoInlineNoUnwindReadnoneUwtable]]
 ;
-; ATTRIBUTOR: define dso_local double* @ptr_sink_r0(double* returned %r) [[NoInlineNoRecurseNoUnwindReadnoneUwtable]]
-; ATTRIBUTOR: define dso_local double* @ptr_scc_r1(double* %a, double* returned %r, double* %b) [[NoInlineNoUnwindReadnoneUwtable]]
+; ATTRIBUTOR: define dso_local double* @ptr_sink_r0(double* returned "no-capture-maybe-returned" %r) [[NoInlineNoRecurseNoUnwindReadnoneUwtable]]
+; ATTRIBUTOR: define dso_local double* @ptr_scc_r1(double* %a, double* returned %r, double* nocapture %b) [[NoInlineNoUnwindReadnoneUwtable]]
 ; ATTRIBUTOR: define dso_local double* @ptr_scc_r2(double* %a, double* %b, double* returned %r) [[NoInlineNoUnwindReadnoneUwtable]]
 ;
 ; double* ptr_scc_r1(double* a, double* b, double* r);
@@ -268,7 +268,7 @@
 ;
 ; FEW_IT:  define dso_local i32* @ret0(i32* %a)
 ; FNATTR:  define dso_local i32* @ret0(i32* readonly %a) [[NoInlineNoUnwindUwtable:#[0-9]*]]
-; BOTH:    define dso_local i32* @ret0(i32* readonly returned %a) [[NoInlineNoReturnNoUnwindReadonlyUwtable:#[0-9]*]]
+; BOTH:    define dso_local i32* @ret0(i32* readonly returned "no-capture-maybe-returned" %a) [[NoInlineNoReturnNoUnwindReadonlyUwtable:#[0-9]*]]
 define dso_local i32* @ret0(i32* %a) #0 {
 entry:
   %v = load i32, i32* %a, align 4
@@ -307,9 +307,9 @@
 ;
 ; BOTH: declare void @unknown_fn(i32* (i32*)*) [[NoInlineNoUnwindUwtable:#[0-9]*]]
 ;
-; BOTH:       define dso_local i32* @calls_unknown_fn(i32* readnone returned %r) [[NoInlineNoUnwindUwtable]]
+; BOTH:       define dso_local i32* @calls_unknown_fn(i32* readnone returned "no-capture-maybe-returned" %r) [[NoInlineNoUnwindUwtable]]
 ; FNATTR:     define dso_local i32* @calls_unknown_fn(i32* readnone %r) [[NoInlineNoUnwindUwtable:#[0-9]*]]
-; ATTRIBUTOR: define dso_local i32* @calls_unknown_fn(i32* returned %r) [[NoInlineNoUnwindUwtable:#[0-9]*]]
+; ATTRIBUTOR: define dso_local i32* @calls_unknown_fn(i32* returned "no-capture-maybe-returned" %r) [[NoInlineNoUnwindUwtable:#[0-9]*]]
 ;
 declare void @unknown_fn(i32* (i32*)*) #0
 
@@ -417,8 +417,8 @@
 ; }
 ;
 ; FNATTR:     define dso_local double* @bitcast(i32* readnone %b) [[NoInlineNoRecurseNoUnwindReadnoneUwtable]]
-; ATTRIBUTOR: define dso_local double* @bitcast(i32* returned %b) [[NoInlineNoUnwindUwtable]]
-; BOTH:       define dso_local double* @bitcast(i32* readnone returned %b) [[NoInlineNoRecurseNoUnwindReadnoneUwtable]]
+; ATTRIBUTOR: define dso_local double* @bitcast(i32* returned "no-capture-maybe-returned" %b) [[NoInlineNoUnwindUwtable]]
+; BOTH:       define dso_local double* @bitcast(i32* readnone returned "no-capture-maybe-returned" %b) [[NoInlineNoRecurseNoUnwindReadnoneUwtable]]
 ;
 define dso_local double* @bitcast(i32* %b) #0 {
 entry:
@@ -437,8 +437,8 @@
 ; }
 ;
 ; FNATTR:     define dso_local double* @bitcasts_select_and_phi(i32* readnone %b) [[NoInlineNoRecurseNoUnwindReadnoneUwtable]]
-; ATTRIBUTOR: define dso_local double* @bitcasts_select_and_phi(i32* returned %b) [[NoInlineNoUnwindUwtable]]
-; BOTH:       define dso_local double* @bitcasts_select_and_phi(i32* readnone returned %b) [[NoInlineNoRecurseNoUnwindReadnoneUwtable]]
+; ATTRIBUTOR: define dso_local double* @bitcasts_select_and_phi(i32* returned "no-capture-maybe-returned" %b) [[NoInlineNoUnwindUwtable]]
+; BOTH:       define dso_local double* @bitcasts_select_and_phi(i32* readnone returned "no-capture-maybe-returned" %b) [[NoInlineNoRecurseNoUnwindReadnoneUwtable]]
 ;
 define dso_local double* @bitcasts_select_and_phi(i32* %b) #0 {
 entry:
@@ -472,8 +472,8 @@
 ; }
 ;
 ; FNATTR:     define dso_local double* @ret_arg_arg_undef(i32* readnone %b) [[NoInlineNoRecurseNoUnwindReadnoneUwtable]]
-; ATTRIBUTOR: define dso_local double* @ret_arg_arg_undef(i32* returned %b) [[NoInlineNoUnwindUwtable]]
-; BOTH:       define dso_local double* @ret_arg_arg_undef(i32* readnone returned %b) [[NoInlineNoRecurseNoUnwindReadnoneUwtable]]
+; ATTRIBUTOR: define dso_local double* @ret_arg_arg_undef(i32* returned "no-capture-maybe-returned" %b) [[NoInlineNoUnwindUwtable]]
+; BOTH:       define dso_local double* @ret_arg_arg_undef(i32* readnone returned "no-capture-maybe-returned" %b) [[NoInlineNoRecurseNoUnwindReadnoneUwtable]]
 ;
 define dso_local double* @ret_arg_arg_undef(i32* %b) #0 {
 entry:
@@ -507,8 +507,8 @@
 ; }
 ;
 ; FNATTR:     define dso_local double* @ret_undef_arg_arg(i32* readnone %b) [[NoInlineNoRecurseNoUnwindReadnoneUwtable]]
-; ATTRIBUTOR: define dso_local double* @ret_undef_arg_arg(i32* returned %b) [[NoInlineNoUnwindUwtable]]
-; BOTH:       define dso_local double* @ret_undef_arg_arg(i32* readnone returned %b) [[NoInlineNoRecurseNoUnwindReadnoneUwtable]]
+; ATTRIBUTOR: define dso_local double* @ret_undef_arg_arg(i32* returned "no-capture-maybe-returned" %b) [[NoInlineNoUnwindUwtable]]
+; BOTH:       define dso_local double* @ret_undef_arg_arg(i32* readnone returned "no-capture-maybe-returned" %b) [[NoInlineNoRecurseNoUnwindReadnoneUwtable]]
 ;
 define dso_local double* @ret_undef_arg_arg(i32* %b) #0 {
 entry:
@@ -542,8 +542,8 @@
 ; }
 ;
 ; FNATTR:     define dso_local double* @ret_undef_arg_undef(i32* readnone %b) [[NoInlineNoRecurseNoUnwindReadnoneUwtable]]
-; ATTRIBUTOR: define dso_local double* @ret_undef_arg_undef(i32* returned %b) [[NoInlineNoUnwindUwtable]]
-; BOTH:       define dso_local double* @ret_undef_arg_undef(i32* readnone returned %b) [[NoInlineNoRecurseNoUnwindReadnoneUwtable]]
+; ATTRIBUTOR: define dso_local double* @ret_undef_arg_undef(i32* returned "no-capture-maybe-returned" %b) [[NoInlineNoUnwindUwtable]]
+; BOTH:       define dso_local double* @ret_undef_arg_undef(i32* readnone returned "no-capture-maybe-returned" %b) [[NoInlineNoRecurseNoUnwindReadnoneUwtable]]
 ;
 define dso_local double* @ret_undef_arg_undef(i32* %b) #0 {
 entry:
@@ -569,7 +569,7 @@
 ; int* ret_arg_or_unknown(int* b) {
 ;   if (b == 0)
 ;     return b;
-;   return unknown();
+;   return unknown(b);
 ; }
 ;
 ; Verify we do not assume b is returned>
Index: llvm/test/Transforms/FunctionAttrs/arg_nocapture.ll
===================================================================
--- llvm/test/Transforms/FunctionAttrs/arg_nocapture.ll
+++ llvm/test/Transforms/FunctionAttrs/arg_nocapture.ll
@@ -29,8 +29,7 @@
 ;   return p == 0;
 ; }
 ;
-; FIXME: no-capture missing for %p
-; CHECK: define dso_local i32 @is_null_return(i32* readnone %p)
+; CHECK: define dso_local i32 @is_null_return(i32* nocapture readnone %p)
 ;
 define dso_local i32 @is_null_return(i32* %p) #0 {
 entry:
@@ -49,8 +48,7 @@
 ;   return 0;
 ; }
 ;
-; FIXME: no-capture missing for %p
-; CHECK: define dso_local i32 @is_null_control(i32* readnone %p)
+; CHECK: define dso_local i32 @is_null_control(i32* nocapture readnone %p)
 ;
 define dso_local i32 @is_null_control(i32* %p) #0 {
 entry:
@@ -127,15 +125,12 @@
 
 ; TEST 5:
 ;
-; FIXME: no-capture missing for %a
-; CHECK: define dso_local float* @scc_A(i32* readnone returned %a)
+; CHECK: define dso_local float* @scc_A(i32* readnone returned "no-capture-maybe-returned" %a)
 ;
-; FIXME: no-capture missing for %a
-; CHECK: define dso_local i64* @scc_B(double* readnone returned %a)
+; CHECK: define dso_local i64* @scc_B(double* readnone returned "no-capture-maybe-returned" %a)
 ;
 ; FIXME: readnone missing for %s
-; FIXME: no-capture missing for %a
-; CHECK: define dso_local i8* @scc_C(i16* returned %a)
+; CHECK: define dso_local i8* @scc_C(i16* returned "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);
@@ -264,7 +259,7 @@
 ; }
 ;
 ; There should *not* be a no-capture attribute on %a
-; CHECK: define dso_local i64* @not_captured_but_returned_0(i64* returned %a)
+; CHECK: define dso_local i64* @not_captured_but_returned_0(i64* returned "no-capture-maybe-returned" %a)
 ;
 define dso_local i64* @not_captured_but_returned_0(i64* %a) #0 {
 entry:
@@ -280,7 +275,7 @@
 ; }
 ;
 ; There should *not* be a no-capture attribute on %a
-; CHECK: define dso_local nonnull i64* @not_captured_but_returned_1(i64* %a)
+; CHECK: define dso_local nonnull i64* @not_captured_but_returned_1(i64* "no-capture-maybe-returned" %a)
 ;
 define dso_local i64* @not_captured_but_returned_1(i64* %a) #0 {
 entry:
@@ -296,8 +291,7 @@
 ;   not_captured_but_returned_1(a);
 ; }
 ;
-; FIXME: no-capture missing for %a
-; CHECK: define dso_local void @test_not_captured_but_returned_calls(i64* %a)
+; CHECK: define dso_local void @test_not_captured_but_returned_calls(i64* nocapture %a)
 ;
 define dso_local void @test_not_captured_but_returned_calls(i64* %a) #0 {
 entry:
@@ -313,7 +307,7 @@
 ; }
 ;
 ; There should *not* be a no-capture attribute on %a
-; CHECK: define dso_local i64* @negative_test_not_captured_but_returned_call_0a(i64* returned %a)
+; CHECK: define dso_local i64* @negative_test_not_captured_but_returned_call_0a(i64* returned "no-capture-maybe-returned" %a)
 ;
 define dso_local i64* @negative_test_not_captured_but_returned_call_0a(i64* %a) #0 {
 entry:
@@ -345,7 +339,7 @@
 ; }
 ;
 ; There should *not* be a no-capture attribute on %a
-; CHECK: define dso_local nonnull i64* @negative_test_not_captured_but_returned_call_1a(i64* %a)
+; CHECK: define dso_local nonnull i64* @negative_test_not_captured_but_returned_call_1a(i64* "no-capture-maybe-returned" %a)
 ;
 define dso_local i64* @negative_test_not_captured_but_returned_call_1a(i64* %a) #0 {
 entry:
@@ -378,10 +372,14 @@
 ;   return unknown();
 ; }
 ;
-; Verify we do *not* assume b is returned or not captured.
+; Verify we do not assume b is returned>
 ;
-; CHECK:     define dso_local i32* @ret_arg_or_unknown(i32* readnone %b)
-; CHECK:     define dso_local i32* @ret_arg_or_unknown_through_phi(i32* readnone %b)
+; FNATTR:     define dso_local i32* @ret_arg_or_unknown(i32* %b)
+; FNATTR:     define dso_local i32* @ret_arg_or_unknown_through_phi(i32* %b)
+; ATTRIBUTOR: define dso_local i32* @ret_arg_or_unknown(i32* "no-capture-maybe-returned" %b)
+; ATTRIBUTOR: define dso_local i32* @ret_arg_or_unknown_through_phi(i32* "no-capture-maybe-returned" %b)
+; BOTH:       define dso_local i32* @ret_arg_or_unknown(i32* "no-capture-maybe-returned" %b)
+; BOTH:       define dso_local i32* @ret_arg_or_unknown_through_phi(i32* "no-capture-maybe-returned" %b)
 ;
 declare dso_local i32* @unknown()
 
@@ -418,7 +416,8 @@
 
 ; TEST 16:
 ;
-; CHECK: define dso_local void @not_captured_by_readonly_call(i32* nocapture %b)
+; ATTRIBUTOR: define dso_local i32* @readonly(i32* "no-capture-maybe-returned")
+; ATTRIBUTOR: define dso_local void @not_captured_by_readonly_call(i32* nocapture %b)
 ;
 declare dso_local i32* @readonly_unknown(i32*, i32*) readonly
 
@@ -434,13 +433,13 @@
 ; Make sure the returned flag on %r is strong enough to justify nocapture on %b but **not** on %r.
 ;
 ; FIXME: The "returned" information is not propagated to the fullest extend causing us to miss "nocapture" on %b in the following:
-; CHECK: define dso_local i32* @not_captured_by_readonly_call_not_returned_either1(i32* readonly %b, i32* readonly returned %r)
+; ATTRIBUTOR: define dso_local i32* @not_captured_by_readonly_call_not_returned_either1(i32* "no-capture-maybe-returned" %b, i32* returned "no-capture-maybe-returned" %r) #0 {
 ;
-; CHECK: define dso_local i32* @not_captured_by_readonly_call_not_returned_either2(i32* readonly %b, i32* readonly returned %r)
-; CHECK: define dso_local i32* @not_captured_by_readonly_call_not_returned_either3(i32* readonly %b, i32* readonly returned %r)
+; ATTRIBUTOR: define dso_local i32* @not_captured_by_readonly_call_not_returned_either2(i32* nocapture %b, i32* returned "no-capture-maybe-returned" %r) #0 {
+; ATTRIBUTOR: define dso_local i32* @not_captured_by_readonly_call_not_returned_either3(i32* nocapture %b, i32* returned "no-capture-maybe-returned" %r) #0 {
 ;
 ; FIXME: The "nounwind" information is not derived to the fullest extend causing us to miss "nocapture" on %b in the following:
-; CHECK: define dso_local i32* @not_captured_by_readonly_call_not_returned_either4(i32* readonly %b, i32* readonly returned %r)
+; ATTRIBUTOR: define dso_local i32* @not_captured_by_readonly_call_not_returned_either4(i32* "no-capture-maybe-returned" %b, i32* returned "no-capture-maybe-returned" %r) #0 {
 ;
 define dso_local i32* @not_captured_by_readonly_call_not_returned_either1(i32* %b, i32* returned %r) #0 {
 entry:
Index: llvm/test/Transforms/FunctionAttrs/SCC1.ll
===================================================================
--- llvm/test/Transforms/FunctionAttrs/SCC1.ll
+++ llvm/test/Transforms/FunctionAttrs/SCC1.ll
@@ -35,7 +35,8 @@
 ;   1 functionattrs - Number of functions marked as norecurse
 ;   6 functionattrs - Number of functions marked argmemonly
 ;   6 functionattrs - Number of functions marked as nounwind
-;  16 functionattrs - Number of arguments marked nocapture
+;  10 functionattrs - Number of arguments marked nocapture
+;   6 functionattrs - Number of arguments marked nocapture-maybe-returned
 ;   4 functionattrs - Number of arguments marked readnone
 ;   6 functionattrs - Number of arguments marked writeonly
 ;   6 functionattrs - Number of arguments marked readonly
@@ -45,7 +46,7 @@
 ;
 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
 
-; CHECK: define dso_local i32* @external_ret2_nrw(i32* %n0, i32* %r0, i32* returned %w0) #[[NOUNWIND:[0-9]*]]
+; CHECK: define dso_local i32* @external_ret2_nrw(i32* nocapture %n0, i32* nocapture %r0, i32* returned "no-capture-maybe-returned" %w0) #[[NOUNWIND:[0-9]*]]
 define dso_local i32* @external_ret2_nrw(i32* %n0, i32* %r0, i32* %w0) {
 entry:
   %call = call i32* @internal_ret0_nw(i32* %n0, i32* %w0)
@@ -55,7 +56,7 @@
   ret i32* %call3
 }
 
-; CHECK: define internal i32* @internal_ret0_nw(i32* returned %n0, i32* %w0) #[[NOUNWIND]]
+; CHECK: define internal i32* @internal_ret0_nw(i32* returned "no-capture-maybe-returned" %n0, i32* nocapture %w0) #[[NOUNWIND]]
 define internal i32* @internal_ret0_nw(i32* %n0, i32* %w0) {
 entry:
   %r0 = alloca i32, align 4
@@ -83,7 +84,7 @@
   ret i32* %retval.0
 }
 
-; CHECK: define internal i32* @internal_ret1_rrw(i32* %r0, i32* returned %r1, i32* %w0) #[[NOUNWIND]]
+; CHECK: define internal i32* @internal_ret1_rrw(i32* nocapture %r0, i32* returned "no-capture-maybe-returned" %r1, i32* nocapture %w0) #[[NOUNWIND]]
 define internal i32* @internal_ret1_rrw(i32* %r0, i32* %r1, i32* %w0) {
 entry:
   %0 = load i32, i32* %r0, align 4
@@ -114,7 +115,7 @@
   ret i32* %retval.0
 }
 
-; CHECK: define dso_local i32* @external_sink_ret2_nrw(i32* readnone %n0, i32* nocapture readonly %r0, i32* returned %w0) #[[NOREC_NOUNWIND:[0-9]*]]
+; CHECK: define dso_local i32* @external_sink_ret2_nrw(i32* nocapture readnone %n0, i32* nocapture readonly %r0, i32* returned "no-capture-maybe-returned" %w0) #[[NOREC_NOUNWIND:[0-9]*]]
 define dso_local i32* @external_sink_ret2_nrw(i32* %n0, i32* %r0, i32* %w0) {
 entry:
   %tobool = icmp ne i32* %n0, null
@@ -132,7 +133,7 @@
   ret i32* %w0
 }
 
-; CHECK: define internal i32* @internal_ret1_rw(i32* %r0, i32* returned %w0) #[[NOUNWIND]]
+; CHECK: define internal i32* @internal_ret1_rw(i32* nocapture %r0, i32* returned "no-capture-maybe-returned" %w0) #[[NOUNWIND]]
 define internal i32* @internal_ret1_rw(i32* %r0, i32* %w0) {
 entry:
   %0 = load i32, i32* %r0, align 4
@@ -157,7 +158,7 @@
   ret i32* %retval.0
 }
 
-; CHECK: define dso_local i32* @external_source_ret2_nrw(i32* %n0, i32* %r0, i32* returned %w0) #[[NOUNWIND]]
+; CHECK: define dso_local i32* @external_source_ret2_nrw(i32* nocapture %n0, i32* nocapture %r0, i32* returned "no-capture-maybe-returned" %w0) #[[NOUNWIND]]
 define dso_local 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)
Index: llvm/test/Transforms/FunctionAttrs/2009-01-02-LocalStores.ll
===================================================================
--- llvm/test/Transforms/FunctionAttrs/2009-01-02-LocalStores.ll
+++ llvm/test/Transforms/FunctionAttrs/2009-01-02-LocalStores.ll
@@ -15,7 +15,7 @@
 	ret i32* %tmp
 }
 
-; CHECK: define i32* @c(i32* readnone returned %r)
+; CHECK: define i32* @c(i32* readnone returned "no-capture-maybe-returned" %r)
 @g = global i32 0
 define i32* @c(i32 *%r) {
 	%a = icmp eq i32* %r, null
Index: llvm/lib/Transforms/IPO/Attributor.cpp
===================================================================
--- llvm/lib/Transforms/IPO/Attributor.cpp
+++ llvm/lib/Transforms/IPO/Attributor.cpp
@@ -20,6 +20,7 @@
 #include "llvm/ADT/Statistic.h"
 #include "llvm/Analysis/CallGraph.h"
 #include "llvm/Analysis/CallGraphSCCPass.h"
+#include "llvm/Analysis/CaptureTracking.h"
 #include "llvm/Analysis/GlobalsModRef.h"
 #include "llvm/IR/Argument.h"
 #include "llvm/IR/Attributes.h"
@@ -52,6 +53,9 @@
 
 STATISTIC(NumFnNoReturn, "Number of functions marked noreturn");
 
+STATISTIC(NumFnArgumentNoCapture,
+          "Number of function arguments marked no-capture");
+
 // TODO: Determine a good default value.
 static cl::opt<unsigned>
     MaxFixpointIterations("attributor-max-iterations", cl::Hidden,
@@ -103,7 +107,6 @@
   /// Return the assumed (integer) state.
   BaseTy getAssumed() const { return Assumed; }
 
-protected:
   /// Copy the bits set in \p BitsEncoding from \p From to \p To.
   static void copyBits(BaseTy &To, const BaseTy From, BaseTy BitsEncoding) {
     BaseTy UnaffectedBits = To & (~BitsEncoding);
@@ -133,6 +136,7 @@
     return (Source & BitsEncoding) == BitsEncoding;
   }
 
+protected:
   /// The known state encoding in an integer of type BaseTy.
   BaseTy Known;
 
@@ -155,6 +159,9 @@
   case Attribute::Returned:
     NumFnArgumentReturned++;
     return;
+  case Attribute::NoCapture:
+    NumFnArgumentNoCapture++;
+    return;
   case Attribute::NoReturn:
     NumFnNoReturn++;
     return;
@@ -257,7 +264,6 @@
   llvm_unreachable("Expected enum or string attribute!");
 }
 
-
 ChangeStatus AbstractAttribute::update(Attributor &A) {
   ChangeStatus Changed = ChangeStatus::UNCHANGED;
   if (getState().isAtFixpoint())
@@ -783,6 +789,396 @@
   }
 };
 
+/// ----------------------- Variable Capturing ---------------------------------
+
+/// A class to hold the state of for no-capture attributes.
+struct AANoCaptureImpl : public AANoCapture, IntegerState<char, 0, 7> {
+
+  /// State encoding bits. A set bit in the state means the property holds.
+  /// NO_CAPTURE is the best possible state, 0 the worst possible state.
+  enum {
+    NOT_CAPTURED_IN_MEM = 1 << 0,
+    NOT_CAPTURED_IN_INT = 1 << 1,
+    NOT_COMMUNICATED_BACK = 1 << 2,
+
+    /// If we do not capture the value in memory or through integers we can only
+    /// communicate it back as a derived pointer.
+    NO_CAPTURE_MAYBE_RETURNED = NOT_CAPTURED_IN_MEM | NOT_CAPTURED_IN_INT,
+
+    /// If we do not capture the value in memory, through integers, or as a
+    /// derived pointer we know it is not captured.
+    NO_CAPTURE =
+        NOT_CAPTURED_IN_MEM | NOT_CAPTURED_IN_INT | NOT_COMMUNICATED_BACK,
+  };
+
+  /// Constructor that takes the value this attribute is associated with (\p V)
+  /// as well as the function this attribute is related to.
+  AANoCaptureImpl(Value &V) : AANoCapture(V) {
+    assert(getAssumed() == NO_CAPTURE);
+  }
+
+  /// See AbstractAttribute::initialize(...).
+  void initialize(Attributor &A) override {
+    Value &V = *getAssociatedValue();
+
+    // If the value in questions is unused it is not captured.
+    if (V.getNumUses() == 0) {
+      indicateFixpoint(/* Optimistic */ true);
+      return;
+    }
+
+    // Check what state the enclosing function can actually capture state.
+    Function &F = getAnchorScope();
+    determineFunctionCaptureCapabilities(F, Known);
+  }
+
+  /// See AANoCapture::isKnownNoCapture().
+  bool isKnownNoCapture() const override { return getKnown() == NO_CAPTURE; }
+
+  /// See AANoCapture::isAssumedNoCapture(...).
+  bool isAssumedNoCapture() const override {
+    return testBits(getAssumed(), NO_CAPTURE);
+  }
+
+  /// See AANoCapture::isKnownNoCaptureMaybeReturned(...).
+  bool isKnownNoCaptureMaybeReturned() const override {
+    return testBits(getKnown(), NO_CAPTURE_MAYBE_RETURNED);
+  }
+
+  /// See AANoCapture::isAssumedNoCaptureMaybeReturned(...).
+  bool isAssumedNoCaptureMaybeReturned() const override {
+    return testBits(getAssumed(), NO_CAPTURE_MAYBE_RETURNED);
+  }
+
+  /// see AbstractAttribute::isAssumedNoCaptureMaybeReturned(...).
+  virtual void
+  getDeducedAttributes(SmallVectorImpl<Attribute> &Attrs) const override {
+    if (!isAssumedNoCaptureMaybeReturned())
+      return;
+
+    LLVMContext &Ctx = AnchoredVal.getContext();
+    if (isAssumedNoCapture())
+      Attrs.emplace_back(Attribute::get(Ctx, Attribute::NoCapture));
+    else
+      Attrs.emplace_back(Attribute::get(Ctx, "no-capture-maybe-returned"));
+  }
+
+  /// Set the NOT_CAPTURED_IN_MEM and NOT_COMMUNICATED_BACK bits in \p Known
+  /// depending on the ability of the function \p F to capture state in memory
+  /// and through "returning/throwing", respectively.
+  static void determineFunctionCaptureCapabilities(Function &F,
+                                                   decltype(Known) &Known) {
+    // If we know we cannot communicate or write to memory, we do not care about
+    // ptr2int anymore.
+    if (F.onlyReadsMemory() && F.doesNotThrow() &&
+        F.getReturnType()->isVoidTy()) {
+      setBits(Known, NO_CAPTURE);
+      return;
+    }
+
+    // A function cannot capture state in memory if it only reads memory.
+    if (F.onlyReadsMemory())
+      setBits(Known, NOT_CAPTURED_IN_MEM);
+
+    // A function cannot communicate state back if it does not through
+    // exceptions and doesn not return values.
+    if (F.doesNotThrow() && F.getReturnType()->isVoidTy())
+      setBits(Known, NOT_COMMUNICATED_BACK);
+  }
+
+  /// See AbstractAttribute::getState()
+  ///{
+  AbstractState &getState() override { return *this; }
+  const AbstractState &getState() const override { return *this; }
+  ///}
+
+  /// See AbstractState::getAsStr().
+  const std::string getAsStr() const override {
+    if (isKnownNoCapture())
+      return "known not-captured";
+    if (isAssumedNoCapture())
+      return "assumed not-captured";
+    if (isKnownNoCaptureMaybeReturned())
+      return "known not-captured-maybe-returned";
+    if (isAssumedNoCaptureMaybeReturned())
+      return "assumed not-captured-maybe-returned";
+    return "assumed-captured";
+  }
+};
+
+/// Attributor-aware capture tracker.
+struct AACaptureUseTracker final : public CaptureTracker {
+
+  /// Create a capture tracker that can lookup in-flight abstract attributes
+  /// through the attributor \p A.
+  ///
+  /// If a use leads to a potential capture, \p CapturedInMemory is set and the
+  /// search is stopped. If a use leads to a return instruction,
+  /// \p CommunicatedBack is set to true and \p CapturedInMemory is not changed.
+  /// If a use leads to a ptr2int which may capute the value,
+  /// \p CapturedInInteger is set. If a use is found that is currently assumed
+  /// "no-capture-maybe-returned", the user is added to the \p PotentialCopies
+  /// set. All values in \p PotentialCopies are later tracked aswell. For every
+  /// explored use we decrement \p RemainingUsesToExplore. Once it reaches 0,
+  /// the search is stopped with \p CapturedInMemory and \p CapturedInInteger
+  /// conservatively set to true.
+  AACaptureUseTracker(Attributor &A, AbstractAttribute &QueryingAA,
+                      bool &CapturedInMemory, bool &CapturedInInteger,
+                      bool &CommunicatedBack,
+                      SmallVectorImpl<Value *> &PotentialCopies,
+                      unsigned &RemainingUsesToExplore)
+      : A(A), QueryingAA(QueryingAA), CapturedInMemory(CapturedInMemory),
+        CapturedInInteger(CapturedInInteger),
+        CommunicatedBack(CommunicatedBack), PotentialCopies(PotentialCopies),
+        RemainingUsesToExplore(RemainingUsesToExplore) {}
+
+  /// Determine if \p V maybe captured. *Also updated CapturedInMemory or
+  /// CapturedInInteger!*
+  bool valueMayBeCaptured(const Value *V) {
+    if (V->getType()->isPointerTy()) {
+      PointerMayBeCaptured(V, this);
+    } else {
+      for (const Use &U : V->uses()) {
+        if (!captured(&U))
+          continue;
+        CapturedInInteger = true;
+      }
+      if (isa<InvokeInst>(V))
+        CapturedInInteger = true;
+    }
+
+    return CapturedInMemory | CapturedInInteger;
+  }
+
+  /// See CaptureTracker::tooManyUses().
+  void tooManyUses() override { CapturedInMemory = CapturedInInteger = true; }
+
+  /// See CaptureTracker::captured(...).
+  bool captured(const Use *U) override {
+    LLVM_DEBUG(errs() << "Check use: " << *U->get() << " in " << *U->getUser()
+                      << "\n");
+
+    // Because we may reuse the tracker multiple times we keep track of the
+    // number of explored uses ourselves as well.
+    if (RemainingUsesToExplore-- == 0) {
+      LLVM_DEBUG(errs() << " - too many uses to explore\n");
+      return shouldContinueTraversal(false);
+    }
+
+    // Deal with ptr2int by following uses.
+    if (isa<PtrToIntInst>(U->getUser())) {
+      LLVM_DEBUG(errs() << " - delegate to ptr2int users!\n");
+      return valueMayBeCaptured(U->getUser());
+    }
+
+    // Explicitly catch return instructions.
+    if (isa<ReturnInst>(U->getUser()))
+      return shouldContinueTraversal(true, /* Maybe handed back */ true);
+
+    // Special case for comparisons agains null. We consider them as
+    // non-capturing.
+    // TODO: This should only be valid if 0 is not a valid address.
+    if (ICmpInst *ICmp = dyn_cast<ICmpInst>(U->getUser())) {
+      unsigned Idx = (ICmp->getOperand(0) == U->get());
+      if (isa<Constant>(ICmp->getOperand(Idx)))
+        if (cast<Constant>(ICmp->getOperand(Idx))->isNullValue())
+          return shouldContinueTraversal(true);
+      return shouldContinueTraversal(false);
+    }
+
+    // For now we only use special logic for call sites. However, the tracker
+    // itself knows about a lot of other non-capturing cases already.
+    CallSite CS(U->getUser());
+    if (!CS || !CS.isArgOperand(U))
+      return shouldContinueTraversal(false);
+
+    unsigned ArgNo = CS.getArgumentNo(U);
+    // TODO: This might be checked in the tracker already.
+    if (CS.paramHasAttr(ArgNo, Attribute::NoCapture))
+      return shouldContinueTraversal(true);
+
+    // If we do not know the called function we have to assume the use captures.
+    if (!CS.getCalledFunction())
+      return shouldContinueTraversal(false);
+
+    // If the called function cannot capture state, nothing is captured.
+    Function &F = *CS.getCalledFunction();
+
+    // Check what we know about the callee already from the IR. If that suffices
+    // to justify no-caputre(-in-memory) we take it. Note that a similar
+    // reasoning is applied for assumed capture capabilities but implicitly
+    // through the recursive use of a AANoCapture attribute below.
+    char KnownCaptureInfo = 0;
+    AANoCaptureImpl::determineFunctionCaptureCapabilities(F, KnownCaptureInfo);
+    if (AANoCaptureImpl::testBits(KnownCaptureInfo,
+                                  AANoCaptureImpl::NO_CAPTURE))
+      return shouldContinueTraversal(true);
+    if (AANoCaptureImpl::testBits(KnownCaptureInfo,
+                                  AANoCaptureImpl::NO_CAPTURE_MAYBE_RETURNED)) {
+      addPotentialCopyIfNecessary(U, CS);
+      return shouldContinueTraversal(true);
+    }
+
+    // Exclude var-arg arguments.
+    if (F.arg_size() > ArgNo) {
+      // If we have a abstract no-capture attribute for the argument we can use
+      // it to justify a non-capture attribute here. This allows recursion!
+      auto *ArgNoCaptureAA = A.getAAFor<AANoCapture>(QueryingAA, F, ArgNo);
+      if (ArgNoCaptureAA) {
+        if (ArgNoCaptureAA->isAssumedNoCapture())
+          return shouldContinueTraversal(true);
+        if (ArgNoCaptureAA->isAssumedNoCaptureMaybeReturned()) {
+          addPotentialCopyIfNecessary(U, CS);
+          return shouldContinueTraversal(true);
+        }
+      }
+
+      // Check for an existing attribute to justify no-capture for this use.
+      if (F.getAttributes().hasParamAttr(ArgNo, "no-capture-maybe-returned")) {
+        addPotentialCopyIfNecessary(U, CS);
+        return shouldContinueTraversal(true);
+      }
+    }
+
+    // Lastly, we could not find a reason no-capture can be assumed so we don't.
+    return shouldContinueTraversal(false);
+  }
+
+  /// Register \p CS as potential copy if the returned/thrown value might be
+  /// derived from the use value \p U.
+  void addPotentialCopyIfNecessary(const Use *U, CallSite CS) {
+    Function *F = CS.getCalledFunction();
+
+    // If "returned" is present in the IR we use it.
+    if (Value *RetArgOp = CS.getReturnedArgOperand()) {
+      if (RetArgOp == U->get())
+        PotentialCopies.push_back(CS.getInstruction());
+      return;
+    }
+
+    // If this is a var-args argument we have to be conservative.
+    unsigned ArgNo = CS.getArgumentNo(U);
+    if (!F || F->arg_size() <= ArgNo) {
+      PotentialCopies.push_back(CS.getInstruction());
+      return;
+    }
+
+    // Use the returned values abstract attribute to determine if the
+    // assocated argument might be returned or not.
+    const AAReturnedValues *RVAA = A.getAAFor<AAReturnedValues>(QueryingAA, *F);
+    if (RVAA && RVAA->getState().isValidState())
+      if (!RVAA->maybeReturned(F->arg_begin() + ArgNo))
+        return;
+
+    // By default we look at the call site users as well.
+    PotentialCopies.push_back(CS.getInstruction());
+  }
+
+  /// See CaptureTracker::shouldExplore(...).
+  bool shouldExplore(const Use *U) override { return true; }
+
+  /// Update the state according to \p ShouldContinue and return the appropriate
+  /// value for use in the CaptureTracker::captured() interface.
+  /// The \p MaybeCommunicated flag indicate if the use allows the value to be
+  /// "returned/thrown" out of the current scope.
+  bool shouldContinueTraversal(bool ShouldContinue,
+                               bool MaybeCommunicated = false) {
+    LLVM_DEBUG(dbgs() << " - " << (ShouldContinue ? "won't" : "might")
+                      << " capture"
+                      << (MaybeCommunicated ? ", but maybe communicated back\n"
+                                            : "\n"));
+    CapturedInMemory = !ShouldContinue;
+    CommunicatedBack |= MaybeCommunicated;
+    return CapturedInMemory | CapturedInInteger;
+  }
+
+private:
+  /// The attributor providing in-flight abstract attributes.
+  Attributor &A;
+
+  /// The abstract attribute currently updated.
+  AbstractAttribute &QueryingAA;
+
+  /// Flag indicating if capturing through memory is possible.
+  bool &CapturedInMemory;
+
+  /// Flag indicating if capturing through integers is possible.
+  bool &CapturedInInteger;
+
+  /// Flag indicating if capturing through communication (return/throw) is
+  /// possible.
+  bool &CommunicatedBack;
+
+  /// Set of potential copies of the tracked value.
+  SmallVectorImpl<Value *> &PotentialCopies;
+
+  /// Global counter to limit the number of explored uses.
+  unsigned &RemainingUsesToExplore;
+};
+
+/// An AA to represent the no-capture argument attribute.
+struct AANoCaptureArgument final : public AANoCaptureImpl {
+
+  /// See AANoCaptureImpl::AANoCaptureImpl(...).
+  AANoCaptureArgument(Argument &Arg) : AANoCaptureImpl(Arg) {
+    if (Arg.hasAttribute(Attribute::NoCapture))
+      indicateFixpoint(/* Optimistic */ true);
+  }
+
+  /// See AbstractAttribute::updateImpl(Attributor &A).
+  virtual ChangeStatus updateImpl(Attributor &A) override;
+
+  /// See AbstractAttribute::getManifestPosition().
+  virtual ManifestPosition getManifestPosition() const override {
+    return MP_ARGUMENT;
+  }
+};
+
+ChangeStatus AANoCaptureArgument::updateImpl(Attributor &A) {
+  // The current assumed state used to determine a change.
+  auto AssumedState = getAssumed();
+
+  // TODO: Once we have memory behavior attributes we should use them here
+  // similar to the reasoning in
+  // AANoCaptureImpl::determineFunctionCaptureCapabilities(...).
+
+  bool CapturedInInteger = false;
+  bool CapturedInMemory = false;
+  bool CommunicatedBack = false;
+  SmallVector<Value *, 4> PotentialCopies;
+  unsigned RemainingUsesToExplore = DefaultMaxUsesToExplore;
+
+  // Use the CaptureTracker interface and logic with the specialized tracker,
+  // defined in AACaptureUseTracker, that can look at in-flight abstract
+  // attributes and directly updates the assumed state.
+  AACaptureUseTracker Tracker(A, *this, CapturedInMemory, CapturedInInteger,
+                              CommunicatedBack, PotentialCopies,
+                              RemainingUsesToExplore);
+
+  // Check all potential copies of the associated value until we can assume none
+  // will be captured or we have to assume at least one might be.
+  unsigned Idx = 0;
+  PotentialCopies.push_back(getAssociatedValue());
+  while (!CapturedInMemory && !CapturedInInteger &&
+         Idx < PotentialCopies.size())
+    Tracker.valueMayBeCaptured(PotentialCopies[Idx++]);
+
+  // We cannot derive useful information if the value may have escaped into
+  // memory or an integer (we couldn't track furthr).
+  if (CapturedInMemory | CapturedInInteger) {
+    indicateFixpoint(/* Optimistic */ false);
+    return ChangeStatus::CHANGED;
+  }
+
+  // If the uses indicate that value might be communicated back, have to give up
+  // on the "not-communicated-back" bit.
+  if (CommunicatedBack)
+    setBits(unsetBits(Assumed, NOT_COMMUNICATED_BACK), Known);
+
+  return (AssumedState == getAssumed()) ? ChangeStatus::UNCHANGED
+                                        : ChangeStatus::CHANGED;
+}
+
 /// ----------------------------------------------------------------------------
 ///                               Attributor
 /// ----------------------------------------------------------------------------
@@ -975,6 +1371,16 @@
   // Every function might be "no-return".
   registerAA(*new AANoReturnFunction(F));
 
+  // For each argument we check if we can derive attributes.
+  for (Argument &Arg : F.args()) {
+
+    // So far only pointer arguments are interesting. However, "returned"
+    // is also derived but as a "function return attribute" (see above).
+    if (Arg.getType()->isPointerTy()) {
+      registerAA(*new AANoCaptureArgument(Arg));
+    }
+  }
+
   // Walk all instructions to find more attribute opportunities and also
   // interesting instructions that might be querried by abstract attributes
   // during their initialziation or update.
Index: llvm/include/llvm/Transforms/IPO/Attributor.h
===================================================================
--- llvm/include/llvm/Transforms/IPO/Attributor.h
+++ llvm/include/llvm/Transforms/IPO/Attributor.h
@@ -266,6 +266,35 @@
   static constexpr Attribute::AttrKind ID = Attribute::Returned;
 };
 
+/// An abstract interface for all nocapture attributes.
+struct AANoCapture : public AbstractAttribute {
+
+  /// See AbstractAttribute::AbstractAttribute(...).
+  AANoCapture(Value &V) : AbstractAttribute(V) {}
+
+  /// Return true if we know that the underlying value is not captured in its
+  /// respective scope.
+  virtual bool isKnownNoCapture() const = 0;
+
+  /// Return true if we assume that the underlying value is not captured in its
+  /// respective scope.
+  virtual bool isAssumedNoCapture() const = 0;
+
+  /// Return true if we know that the underlying value is not captured in its
+  /// respective scope but we allow it to escape through a "return".
+  virtual bool isKnownNoCaptureMaybeReturned() const = 0;
+
+  /// Return true if we assume that the underlying value is not captured in its
+  /// respective scope but we allow it to escape through a "return".
+  virtual bool isAssumedNoCaptureMaybeReturned() const = 0;
+
+  /// See AbstractState::getAttrKind().
+  Attribute::AttrKind getAttrKind() const override { return ID; }
+
+  /// The identifier used by the Attributor for this class of attributes.
+  static constexpr Attribute::AttrKind ID = Attribute::NoCapture;
+};
+
 /// ----------------------------------------------------------------------------
 ///                       Pass (Manager) Boilerplate
 /// ----------------------------------------------------------------------------
Index: clang/test/CodeGenOpenCL/as_type.cl
===================================================================
--- clang/test/CodeGenOpenCL/as_type.cl
+++ clang/test/CodeGenOpenCL/as_type.cl
@@ -67,7 +67,7 @@
   return __builtin_astype(x, int3);
 }
 
-//CHECK: define spir_func i32 addrspace(1)* @addr_cast(i32* readnone returned %[[x:.*]])
+//CHECK: define spir_func i32 addrspace(1)* @addr_cast(i32* readnone returned "no-capture-maybe-returned" %[[x:.*]])
 //CHECK: %[[cast:.*]] = addrspacecast i32* %[[x]] to i32 addrspace(1)*
 //CHECK: ret i32 addrspace(1)* %[[cast]]
 global int* addr_cast(int *x) {
@@ -81,7 +81,7 @@
   return __builtin_astype(x, global int*);
 }
 
-//CHECK: define spir_func i32 @ptr_to_int(i32* %[[x:.*]])
+//CHECK: define spir_func i32 @ptr_to_int(i32* "no-capture-maybe-returned" %[[x:.*]])
 //CHECK: %[[cast:.*]] = ptrtoint i32* %[[x]] to i32
 //CHECK: ret i32 %[[cast]]
 int ptr_to_int(int *x) {
Index: clang/test/CodeGenObjC/os_log.m
===================================================================
--- clang/test/CodeGenObjC/os_log.m
+++ clang/test/CodeGenObjC/os_log.m
@@ -14,7 +14,7 @@
 #ifdef __x86_64__
 // CHECK-LABEL: define i8* @test_builtin_os_log
 // CHECK-O0-LABEL: define i8* @test_builtin_os_log
-// CHECK: (i8* returned %[[BUF:.*]])
+// CHECK: (i8* returned "no-capture-maybe-returned" %[[BUF:.*]])
 // CHECK-O0: (i8* %[[BUF:.*]])
 void *test_builtin_os_log(void *buf) {
   return __builtin_os_log_format(buf, "capabilities: %@", GenString());
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to