diff options
author | Akira Hatanaka <ahatanaka@apple.com> | 2017-09-20 06:22:51 +0000 |
---|---|---|
committer | Akira Hatanaka <ahatanaka@apple.com> | 2017-09-20 06:22:51 +0000 |
commit | fc587e6a570796ca321aa981866359c3ae13e21e (patch) | |
tree | f99180094d880f13e2267ac280df889296bae3db /clang/test | |
parent | c8aea66627095ecff057958e06c43b4225b5bf95 (diff) | |
download | bcm5719-llvm-fc587e6a570796ca321aa981866359c3ae13e21e.tar.gz bcm5719-llvm-fc587e6a570796ca321aa981866359c3ae13e21e.zip |
Add support for attribute 'noescape'.
The attribute informs the compiler that the annotated pointer parameter
of a function cannot escape and enables IRGen to attach attribute
'nocapture' to parameters that are annotated with the attribute. That is
the only optimization that currently takes advantage of 'noescape', but
there are other optimizations that will be added later that improves
IRGen for ObjC blocks.
rdar://problem/19886775
Differential Revision: https://reviews.llvm.org/D32520
llvm-svn: 313720
Diffstat (limited to 'clang/test')
-rw-r--r-- | clang/test/CodeGenCXX/noescape.cpp | 67 | ||||
-rw-r--r-- | clang/test/CodeGenObjC/noescape.m | 71 | ||||
-rw-r--r-- | clang/test/Misc/ast-dump-attr.cpp | 8 | ||||
-rw-r--r-- | clang/test/Misc/pragma-attribute-supported-attributes-list.test | 3 | ||||
-rw-r--r-- | clang/test/Sema/noescape.c | 25 | ||||
-rw-r--r-- | clang/test/SemaObjCXX/noescape.mm | 90 |
6 files changed, 263 insertions, 1 deletions
diff --git a/clang/test/CodeGenCXX/noescape.cpp b/clang/test/CodeGenCXX/noescape.cpp new file mode 100644 index 00000000000..e8abd41f547 --- /dev/null +++ b/clang/test/CodeGenCXX/noescape.cpp @@ -0,0 +1,67 @@ +// RUN: %clang_cc1 -std=c++11 -emit-llvm -o - %s | FileCheck %s + +struct S { + int a[4]; + S(int *, int * __attribute__((noescape))); + S &operator=(int * __attribute__((noescape))); + void m0(int *, int * __attribute__((noescape))); + virtual void vm1(int *, int * __attribute__((noescape))); +}; + +// CHECK: define void @_ZN1SC2EPiS0_(%struct.S* {{.*}}, {{.*}}, {{.*}} nocapture) +// CHECK: define void @_ZN1SC1EPiS0_(%struct.S* {{.*}}, {{.*}}, {{.*}} nocapture) {{.*}} { +// CHECK: call void @_ZN1SC2EPiS0_(%struct.S* {{.*}}, {{.*}}, {{.*}} nocapture {{.*}}) + +S::S(int *, int * __attribute__((noescape))) {} + +// CHECK: define {{.*}} %struct.S* @_ZN1SaSEPi(%struct.S* {{.*}}, {{.*}} nocapture) +S &S::operator=(int * __attribute__((noescape))) { return *this; } + +// CHECK: define void @_ZN1S2m0EPiS0_(%struct.S* {{.*}}, {{.*}} nocapture) +void S::m0(int *, int * __attribute__((noescape))) {} + +// CHECK: define void @_ZN1S3vm1EPiS0_(%struct.S* {{.*}}, {{.*}} nocapture) +void S::vm1(int *, int * __attribute__((noescape))) {} + +// CHECK-LABEL: define void @_Z5test0P1SPiS1_( +// CHECK: call void @_ZN1SC1EPiS0_(%struct.S* {{.*}}, {{.*}}, {{.*}} nocapture {{.*}}) +// CHECK: call {{.*}} %struct.S* @_ZN1SaSEPi(%struct.S* {{.*}}, {{.*}} nocapture {{.*}}) +// CHECK: call void @_ZN1S2m0EPiS0_(%struct.S* {{.*}}, {{.*}}, {{.*}} nocapture {{.*}}) +// CHECK: call void {{.*}}(%struct.S* {{.*}}, {{.*}}, {{.*}} nocapture {{.*}}) +void test0(S *s, int *p0, int *p1) { + S t(p0, p1); + t = p1; + s->m0(p0, p1); + s->vm1(p0, p1); +} + +namespace std { + typedef decltype(sizeof(0)) size_t; +} + +// CHECK: define {{.*}} @_ZnwmPv({{.*}}, {{.*}} nocapture {{.*}}) +void *operator new(std::size_t, void * __attribute__((noescape)) p) { + return p; +} + +// CHECK-LABEL: define i8* @_Z5test1Pv( +// CHECK : %call = call {{.*}} @_ZnwmPv({{.*}}, {{.*}} nocapture {{.*}}) +void *test1(void *p0) { + return ::operator new(16, p0); +} + +// CHECK-LABEL: define void @_Z5test2PiS_( +// CHECK: call void @"_ZZ5test2PiS_ENK3$_0clES_S_"({{.*}}, {{.*}}, {{.*}} nocapture {{.*}}) +// CHECK: define internal void @"_ZZ5test2PiS_ENK3$_0clES_S_"({{.*}}, {{.*}}, {{.*}} nocapture) +void test2(int *p0, int *p1) { + auto t = [](int *, int * __attribute__((noescape))){}; + t(p0, p1); +} + +// CHECK-LABEL: define void @_Z5test3PFvU8noescapePiES_( +// CHECK: call void {{.*}}(i32* nocapture {{.*}}) +typedef void (*NoEscapeFunc)(__attribute__((noescape)) int *); + +void test3(NoEscapeFunc f, int *p) { + f(p); +} diff --git a/clang/test/CodeGenObjC/noescape.m b/clang/test/CodeGenObjC/noescape.m new file mode 100644 index 00000000000..8ea2aa94e00 --- /dev/null +++ b/clang/test/CodeGenObjC/noescape.m @@ -0,0 +1,71 @@ +// RUN: %clang_cc1 -fblocks -emit-llvm -o - %s | FileCheck %s + +typedef void (^BlockTy)(void); + +union U { + int *i; + long long *ll; +} __attribute__((transparent_union)); + +void noescapeFunc0(id, __attribute__((noescape)) BlockTy); +void noescapeFunc1(__attribute__((noescape)) int *); +void noescapeFunc2(__attribute__((noescape)) id); +void noescapeFunc3(__attribute__((noescape)) union U); + +// CHECK-LABEL: define void @test0( +// CHECK: call void @noescapeFunc0({{.*}}, {{.*}} nocapture {{.*}}) +// CHECK: declare void @noescapeFunc0(i8*, {{.*}} nocapture) +void test0(BlockTy b) { + noescapeFunc0(0, b); +} + +// CHECK-LABEL: define void @test1( +// CHECK: call void @noescapeFunc1({{.*}} nocapture {{.*}}) +// CHECK: declare void @noescapeFunc1({{.*}} nocapture) +void test1(int *i) { + noescapeFunc1(i); +} + +// CHECK-LABEL: define void @test2( +// CHECK: call void @noescapeFunc2({{.*}} nocapture {{.*}}) +// CHECK: declare void @noescapeFunc2({{.*}} nocapture) +void test2(id i) { + noescapeFunc2(i); +} + +// CHECK-LABEL: define void @test3( +// CHECK: call void @noescapeFunc3({{.*}} nocapture {{.*}}) +// CHECK: declare void @noescapeFunc3({{.*}} nocapture) +void test3(union U u) { + noescapeFunc3(u); +} + +// CHECK: define internal void @"\01-[C0 m0:]"({{.*}}, {{.*}}, {{.*}} nocapture {{.*}}) + +// CHECK-LABEL: define void @test4( +// CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i32*)*)(i8* {{.*}}, i8* {{.*}}, i32* nocapture {{.*}}) + +@interface C0 +-(void) m0:(int*)__attribute__((noescape)) p0; +@end + +@implementation C0 +-(void) m0:(int*)__attribute__((noescape)) p0 { +} +@end + +void test4(C0 *c0, int *p) { + [c0 m0:p]; +} + +// CHECK-LABEL: define void @test5( +// CHECK: call void {{.*}}(i8* bitcast ({ i8**, i32, i32, i8*, {{.*}} }* @{{.*}} to i8*), i32* nocapture {{.*}}) +// CHECK: call void {{.*}}(i8* {{.*}}, i32* nocapture {{.*}}) +// CHECK: define internal void @{{.*}}(i8* {{.*}}, i32* nocapture {{.*}}) + +typedef void (^BlockTy2)(__attribute__((noescape)) int *); + +void test5(BlockTy2 b, int *p) { + ^(int *__attribute__((noescape)) p0){}(p); + b(p); +} diff --git a/clang/test/Misc/ast-dump-attr.cpp b/clang/test/Misc/ast-dump-attr.cpp index 07f91605e71..bf942959a85 100644 --- a/clang/test/Misc/ast-dump-attr.cpp +++ b/clang/test/Misc/ast-dump-attr.cpp @@ -180,6 +180,14 @@ __attribute__((external_source_symbol(generated_declaration, defined_in="module" // CHECK: FunctionDecl{{.*}} TestExternalSourceSymbolAttr5 // CHECK-NEXT: ExternalSourceSymbolAttr{{.*}} "Swift" "module" GeneratedDeclaration +namespace TestNoEscape { + void noescapeFunc(int *p0, __attribute__((noescape)) int *p1) {} + // CHECK: `-FunctionDecl{{.*}} noescapeFunc 'void (int *, __attribute__((noescape)) int *)' + // CHECK-NEXT: ParmVarDecl + // CHECK-NEXT: ParmVarDecl + // CHECK-NEXT: NoEscapeAttr +} + namespace TestSuppress { [[gsl::suppress("at-namespace")]]; // CHECK: NamespaceDecl{{.*}} TestSuppress diff --git a/clang/test/Misc/pragma-attribute-supported-attributes-list.test b/clang/test/Misc/pragma-attribute-supported-attributes-list.test index 16c1f67c1bc..7529a2425d3 100644 --- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test +++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test @@ -2,7 +2,7 @@ // The number of supported attributes should never go down! -// CHECK: #pragma clang attribute supports 64 attributes: +// CHECK: #pragma clang attribute supports 65 attributes: // CHECK-NEXT: AMDGPUFlatWorkGroupSize (SubjectMatchRule_function) // CHECK-NEXT: AMDGPUNumSGPR (SubjectMatchRule_function) // CHECK-NEXT: AMDGPUNumVGPR (SubjectMatchRule_function) @@ -35,6 +35,7 @@ // CHECK-NEXT: MipsShortCall (SubjectMatchRule_function) // CHECK-NEXT: NoDebug (SubjectMatchRule_hasType_functionType, SubjectMatchRule_objc_method, SubjectMatchRule_variable_not_is_parameter) // CHECK-NEXT: NoDuplicate (SubjectMatchRule_function) +// CHECK-NEXT: NoEscape (SubjectMatchRule_variable_is_parameter) // CHECK-NEXT: NoMicroMips (SubjectMatchRule_function) // CHECK-NEXT: NoSanitize (SubjectMatchRule_function, SubjectMatchRule_objc_method, SubjectMatchRule_variable_is_global) // CHECK-NEXT: NoSanitizeSpecific (SubjectMatchRule_function, SubjectMatchRule_variable_is_global) diff --git a/clang/test/Sema/noescape.c b/clang/test/Sema/noescape.c new file mode 100644 index 00000000000..39f3f6f542a --- /dev/null +++ b/clang/test/Sema/noescape.c @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +void escapefunc(int *); +void noescapefunc(__attribute__((noescape)) int *); +void (*escapefuncptr)(int *); +void (*noescapefuncptr)(__attribute__((noescape)) int *); + +void func_ne(__attribute__((noescape)) int *, int *); +void func_en(int *, __attribute__((noescape)) int *); + +void (*funcptr_ee)(int *, int *); +void (*funcptr_nn)(__attribute__((noescape)) int *, __attribute__((noescape)) int *); + +void test0(int c) { + escapefuncptr = &escapefunc; + escapefuncptr = &noescapefunc; + noescapefuncptr = &escapefunc; // expected-warning {{incompatible function pointer types assigning to 'void (*)(__attribute__((noescape)) int *)' from 'void (*)(int *)'}} + noescapefuncptr = &noescapefunc; + + escapefuncptr = c ? &escapefunc : &noescapefunc; + noescapefuncptr = c ? &escapefunc : &noescapefunc; // expected-warning {{incompatible function pointer types assigning to 'void (*)(__attribute__((noescape)) int *)' from 'void (*)(int *)'}} + + funcptr_ee = c ? &func_ne : &func_en; + funcptr_nn = c ? &func_ne : &func_en; // expected-warning {{incompatible function pointer types assigning to 'void (*)(__attribute__((noescape)) int *, __attribute__((noescape)) int *)' from 'void (*)(int *, int *)'}} +} diff --git a/clang/test/SemaObjCXX/noescape.mm b/clang/test/SemaObjCXX/noescape.mm new file mode 100644 index 00000000000..6c5d9897aaf --- /dev/null +++ b/clang/test/SemaObjCXX/noescape.mm @@ -0,0 +1,90 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -fblocks -std=c++11 %s +// RUN: %clang_cc1 -fsyntax-only -verify -fblocks -std=c++1z %s + +typedef void (^BlockTy)(); + +struct S { + int i; + void m(); +}; + +void noescapeFunc0(id, __attribute__((noescape)) BlockTy); +void noescapeFunc1(id, [[clang::noescape]] BlockTy); +void noescapeFunc2(__attribute__((noescape)) int *); // expected-note {{previous declaration is here}} +void noescapeFunc3(__attribute__((noescape)) id); +void noescapeFunc4(__attribute__((noescape)) int &); +void noescapeFunc2(int *); // expected-error {{conflicting types for 'noescapeFunc2'}} + +void invalidFunc0(int __attribute__((noescape))); // expected-warning {{'noescape' attribute only applies to pointer arguments}} +void invalidFunc1(int __attribute__((noescape(0)))); // expected-error {{'noescape' attribute takes no arguments}} +void invalidFunc2(int0 *__attribute__((noescape))); // expected-error {{use of undeclared identifier 'int0'; did you mean 'int'?}} +void invalidFunc3(__attribute__((noescape)) int (S::*Ty)); // expected-warning {{'noescape' attribute only applies to pointer arguments}} +void invalidFunc4(__attribute__((noescape)) void (S::*Ty)()); // expected-warning {{'noescape' attribute only applies to pointer arguments}} +int __attribute__((noescape)) g; // expected-warning {{'noescape' attribute only applies to parameters}} + +struct S1 { + virtual void m0(int *__attribute__((noescape))); // expected-note {{parameter of overridden method is annotated with __attribute__((noescape))}} +}; + +struct S2 : S1 { + void m0(int *__attribute__((noescape))) override; +}; + +struct S3 : S1 { + void m0(int *) override; // expected-warning {{parameter of overriding method should be annotated with __attribute__((noescape))}} +}; + +__attribute__((objc_root_class)) +@interface C0 +-(void) m0:(int*)__attribute__((noescape)) p; // expected-note {{parameter of overridden method is annotated with __attribute__((noescape))}} +@end + +@implementation C0 +-(void) m0:(int*)__attribute__((noescape)) p {} +@end + +@interface C1 : C0 +-(void) m0:(int*)__attribute__((noescape)) p; +@end + +@implementation C1 : C0 +-(void) m0:(int*)__attribute__((noescape)) p {} +@end + +@interface C2 : C0 +-(void) m0:(int*) p; // expected-warning {{parameter of overriding method should be annotated with __attribute__((noescape))}} +@end + +@implementation C2 : C0 +-(void) m0:(int*) p {} +@end + +void func0(int *); +void (*fnptr0)(int *); +void (*fnptr1)(__attribute__((noescape)) int *); +template<void (*fn)(int*)> struct S4 {}; +template<void (*fn)(int* __attribute__((noescape)))> struct S5 {}; + +#if __cplusplus < 201406 + // expected-note@-4 {{template parameter is declared here}} + // expected-note@-4 {{template parameter is declared here}} +#endif + +void test0() { + fnptr0 = &func0; + fnptr0 = &noescapeFunc2; + fnptr1 = &func0; // expected-error {{assigning to 'void (*)(__attribute__((noescape)) int *)' from incompatible type 'void (*)(int *)'}} + fnptr1 = &noescapeFunc2; + S4<&func0> e0; + S4<&noescapeFunc2> e1; + S5<&func0> ne0; + +#if __cplusplus < 201406 + // expected-error@-4 {{non-type template argument of type 'void (*)(__attribute__((noescape)) int *)' cannot be converted to a value of type 'void (*)(int *)'}} + // expected-error@-4 {{non-type template argument of type 'void (*)(int *)' cannot be converted to a value of type 'void (*)(__attribute__((noescape)) int *)'}} +#else + // expected-error@-6 {{value of type 'void (*)(int *)' is not implicitly convertible to 'void (*)(__attribute__((noescape)) int *)'}} +#endif + + S5<&noescapeFunc2> ne1; +} |