r186908 - Error on more illegal kernel argument types for OpenCL
Matt Arsenault
Matthew.Arsenault at amd.com
Mon Jul 22 18:23:37 PDT 2013
Author: arsenm
Date: Mon Jul 22 20:23:36 2013
New Revision: 186908
URL: http://llvm.org/viewvc/llvm-project?rev=186908&view=rev
Log:
Error on more illegal kernel argument types for OpenCL
bool, half, pointers and structs / unions containing any
of these are not allowed. Does not yet reject size_t and
related integer types that are also disallowed.
Added:
cfe/trunk/test/SemaOpenCL/invalid-kernel-parameters.cl
Modified:
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/test/SemaOpenCL/event_t.cl
cfe/trunk/test/SemaOpenCL/invalid-kernel.cl
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=186908&r1=186907&r2=186908&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Jul 22 20:23:36 2013
@@ -6452,16 +6452,22 @@ def err_invalid_astype_of_different_size
"invalid reinterpretation: sizes of %0 and %1 must match">;
def err_static_kernel : Error<
"kernel functions cannot be declared static">;
-def err_opencl_ptrptr_kernel_arg : Error<
- "kernel argument cannot be declared as a pointer to a pointer">;
+def err_opencl_ptrptr_kernel_param : Error<
+ "kernel parameter cannot be declared as a pointer to a pointer">;
def err_static_function_scope : Error<
"variables in function scope cannot be declared static">;
def err_opencl_bitfields : Error<
"bitfields are not supported in OpenCL">;
def err_opencl_vla : Error<
"variable length arrays are not supported in OpenCL">;
-def err_event_t_kernel_arg : Error<
- "the event_t type cannot be used to declare a kernel function argument">;
+def err_bad_kernel_param_type : Error<
+ "%0 cannot be used as the type of a kernel parameter">;
+def err_record_with_pointers_kernel_param : Error<
+ "%select{struct|union}0 kernel parameters may not contain pointers">;
+def note_within_field_of_type : Note<
+ "within field of type %0 declared here">;
+def note_illegal_field_declared_here : Note<
+ "field of illegal %select{type|pointer type}0 %1 declared here">;
def err_event_t_global_var : Error<
"the event_t type cannot be used to declare a program scope variable">;
def err_event_t_struct_field : Error<
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=186908&r1=186907&r2=186908&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Mon Jul 22 20:23:36 2013
@@ -1454,6 +1454,7 @@ public:
void MaybeSuggestAddingStaticToDecl(const FunctionDecl *D);
void ActOnStartFunctionDeclarator();
void ActOnEndFunctionDeclarator();
+
NamedDecl* ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
TypeSourceInfo *TInfo,
LookupResult &Previous,
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=186908&r1=186907&r2=186908&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Mon Jul 22 20:23:36 2013
@@ -6069,6 +6069,173 @@ void Sema::checkVoidParamDecl(ParmVarDec
}
}
+enum OpenCLParamType {
+ ValidKernelParam,
+ PtrPtrKernelParam,
+ PtrKernelParam,
+ InvalidKernelParam,
+ RecordKernelParam
+};
+
+static OpenCLParamType getOpenCLKernelParameterType(QualType PT) {
+ if (PT->isPointerType()) {
+ QualType PointeeType = PT->getPointeeType();
+ return PointeeType->isPointerType() ? PtrPtrKernelParam : PtrKernelParam;
+ }
+
+ // TODO: Forbid the other integer types (size_t, ptrdiff_t...) when they can
+ // be used as builtin types.
+
+ if (PT->isImageType())
+ return PtrKernelParam;
+
+ if (PT->isBooleanType())
+ return InvalidKernelParam;
+
+ if (PT->isEventT())
+ return InvalidKernelParam;
+
+ if (PT->isHalfType())
+ return InvalidKernelParam;
+
+ if (PT->isRecordType())
+ return RecordKernelParam;
+
+ return ValidKernelParam;
+}
+
+static void checkIsValidOpenCLKernelParameter(
+ Sema &S,
+ Declarator &D,
+ ParmVarDecl *Param,
+ llvm::SmallPtrSet<const Type *, 16> &ValidTypes) {
+ QualType PT = Param->getType();
+
+ // Cache the valid types we encounter to avoid rechecking structs that are
+ // used again
+ if (ValidTypes.count(PT.getTypePtr()))
+ return;
+
+ switch (getOpenCLKernelParameterType(PT)) {
+ case PtrPtrKernelParam:
+ // OpenCL v1.2 s6.9.a:
+ // A kernel function argument cannot be declared as a
+ // pointer to a pointer type.
+ S.Diag(Param->getLocation(), diag::err_opencl_ptrptr_kernel_param);
+ D.setInvalidType();
+ return;
+
+ // OpenCL v1.2 s6.9.k:
+ // Arguments to kernel functions in a program cannot be declared with the
+ // built-in scalar types bool, half, size_t, ptrdiff_t, intptr_t, and
+ // uintptr_t or a struct and/or union that contain fields declared to be
+ // one of these built-in scalar types.
+
+ case InvalidKernelParam:
+ // OpenCL v1.2 s6.8 n:
+ // A kernel function argument cannot be declared
+ // of event_t type.
+ S.Diag(Param->getLocation(), diag::err_bad_kernel_param_type) << PT;
+ D.setInvalidType();
+ return;
+
+ case PtrKernelParam:
+ case ValidKernelParam:
+ ValidTypes.insert(PT.getTypePtr());
+ return;
+
+ case RecordKernelParam:
+ break;
+ }
+
+ // Track nested structs we will inspect
+ SmallVector<const Decl *, 4> VisitStack;
+
+ // Track where we are in the nested structs. Items will migrate from
+ // VisitStack to HistoryStack as we do the DFS for bad field.
+ SmallVector<const FieldDecl *, 4> HistoryStack;
+ HistoryStack.push_back((const FieldDecl *) 0);
+
+ const RecordDecl *PD = PT->castAs<RecordType>()->getDecl();
+ VisitStack.push_back(PD);
+
+ assert(VisitStack.back() && "First decl null?");
+
+ do {
+ const Decl *Next = VisitStack.pop_back_val();
+ if (!Next) {
+ assert(!HistoryStack.empty());
+ // Found a marker, we have gone up a level
+ if (const FieldDecl *Hist = HistoryStack.pop_back_val())
+ ValidTypes.insert(Hist->getType().getTypePtr());
+
+ continue;
+ }
+
+ // Adds everything except the original parameter declaration (which is not a
+ // field itself) to the history stack.
+ const RecordDecl *RD;
+ if (const FieldDecl *Field = dyn_cast<FieldDecl>(Next)) {
+ HistoryStack.push_back(Field);
+ RD = Field->getType()->castAs<RecordType>()->getDecl();
+ } else {
+ RD = cast<RecordDecl>(Next);
+ }
+
+ // Add a null marker so we know when we've gone back up a level
+ VisitStack.push_back((const Decl *) 0);
+
+ for (RecordDecl::field_iterator I = RD->field_begin(),
+ E = RD->field_end(); I != E; ++I) {
+ const FieldDecl *FD = *I;
+ QualType QT = FD->getType();
+
+ if (ValidTypes.count(QT.getTypePtr()))
+ continue;
+
+ OpenCLParamType ParamType = getOpenCLKernelParameterType(QT);
+ if (ParamType == ValidKernelParam)
+ continue;
+
+ if (ParamType == RecordKernelParam) {
+ VisitStack.push_back(FD);
+ continue;
+ }
+
+ // OpenCL v1.2 s6.9.p:
+ // Arguments to kernel functions that are declared to be a struct or union
+ // do not allow OpenCL objects to be passed as elements of the struct or
+ // union.
+ if (ParamType == PtrKernelParam || ParamType == PtrPtrKernelParam) {
+ S.Diag(Param->getLocation(),
+ diag::err_record_with_pointers_kernel_param)
+ << PT->isUnionType()
+ << PT;
+ } else {
+ S.Diag(Param->getLocation(), diag::err_bad_kernel_param_type) << PT;
+ }
+
+ S.Diag(PD->getLocation(), diag::note_within_field_of_type)
+ << PD->getDeclName();
+
+ // We have an error, now let's go back up through history and show where
+ // the offending field came from
+ for (ArrayRef<const FieldDecl *>::const_iterator I = HistoryStack.begin() + 1,
+ E = HistoryStack.end(); I != E; ++I) {
+ const FieldDecl *OuterField = *I;
+ S.Diag(OuterField->getLocation(), diag::note_within_field_of_type)
+ << OuterField->getType();
+ }
+
+ S.Diag(FD->getLocation(), diag::note_illegal_field_declared_here)
+ << QT->isPointerType()
+ << QT;
+ D.setInvalidType();
+ return;
+ }
+ } while (!VisitStack.empty());
+}
+
NamedDecl*
Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
TypeSourceInfo *TInfo, LookupResult &Previous,
@@ -6803,27 +6970,12 @@ Sema::ActOnFunctionDeclarator(Scope *S,
diag::err_expected_kernel_void_return_type);
D.setInvalidType();
}
-
+
+ llvm::SmallPtrSet<const Type *, 16> ValidTypes;
for (FunctionDecl::param_iterator PI = NewFD->param_begin(),
PE = NewFD->param_end(); PI != PE; ++PI) {
ParmVarDecl *Param = *PI;
- QualType PT = Param->getType();
-
- // OpenCL v1.2 s6.9.a:
- // A kernel function argument cannot be declared as a
- // pointer to a pointer type.
- if (PT->isPointerType() && PT->getPointeeType()->isPointerType()) {
- Diag(Param->getLocation(), diag::err_opencl_ptrptr_kernel_arg);
- D.setInvalidType();
- }
-
- // OpenCL v1.2 s6.8 n:
- // A kernel function argument cannot be declared
- // of event_t type.
- if (PT->isEventT()) {
- Diag(Param->getLocation(), diag::err_event_t_kernel_arg);
- D.setInvalidType();
- }
+ checkIsValidOpenCLKernelParameter(*this, D, Param, ValidTypes);
}
}
Modified: cfe/trunk/test/SemaOpenCL/event_t.cl
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaOpenCL/event_t.cl?rev=186908&r1=186907&r2=186908&view=diff
==============================================================================
--- cfe/trunk/test/SemaOpenCL/event_t.cl (original)
+++ cfe/trunk/test/SemaOpenCL/event_t.cl Mon Jul 22 20:23:36 2013
@@ -8,10 +8,11 @@ constant struct evt_s {
void foo(event_t evt); // expected-note {{passing argument to parameter 'evt' here}}
-void kernel ker(event_t argevt) { // expected-error {{the event_t type cannot be used to declare a kernel function argument}}
+void kernel ker(event_t argevt) { // expected-error {{'event_t' cannot be used as the type of a kernel parameter}}
event_t e;
constant event_t const_evt; // expected-error {{the event_t type can only be used with __private address space qualifier}}
foo(e);
foo(0);
foo(5); // expected-error {{passing 'int' to parameter of incompatible type 'event_t'}}
}
+
Added: cfe/trunk/test/SemaOpenCL/invalid-kernel-parameters.cl
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaOpenCL/invalid-kernel-parameters.cl?rev=186908&view=auto
==============================================================================
--- cfe/trunk/test/SemaOpenCL/invalid-kernel-parameters.cl (added)
+++ cfe/trunk/test/SemaOpenCL/invalid-kernel-parameters.cl Mon Jul 22 20:23:36 2013
@@ -0,0 +1,132 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+#pragma OPENCL EXTENSION cl_khr_fp16 : enable
+
+
+// Disallowed: parameters with type
+// bool, half, size_t, ptrdiff_t, intptr_t, and uintptr_t
+// or a struct / union with any of these types in them
+
+// TODO: Ban int types, size_t, ptrdiff_t ...
+
+kernel void bool_arg(bool x) { } // expected-error{{'bool' cannot be used as the type of a kernel parameter}}
+
+kernel void half_arg(half x) { } // expected-error{{'half' cannot be used as the type of a kernel parameter}}
+
+typedef struct ContainsBool // expected-note{{within field of type 'ContainsBool' declared here}}
+{
+ bool x; // expected-note{{field of illegal type 'bool' declared here}}
+} ContainsBool;
+
+kernel void bool_in_struct_arg(ContainsBool x) { } // expected-error{{'ContainsBool' (aka 'struct ContainsBool') cannot be used as the type of a kernel parameter}}
+
+
+
+typedef struct FooImage2D // expected-note{{within field of type 'FooImage2D' declared here}}
+{
+ image2d_t imageField; // expected-note{{field of illegal type 'image2d_t' declared here}}
+} FooImage2D;
+
+kernel void image_in_struct_arg(FooImage2D arg) { } // expected-error{{struct kernel parameters may not contain pointers}}
+
+typedef struct Foo // expected-note{{within field of type 'Foo' declared here}}
+{
+ int* ptrField; // expected-note{{field of illegal pointer type 'int *' declared here}}
+} Foo;
+
+kernel void pointer_in_struct_arg(Foo arg) { } // expected-error{{struct kernel parameters may not contain pointers}}
+
+typedef union FooUnion // expected-note{{within field of type 'FooUnion' declared here}}
+{
+ int* ptrField; // expected-note{{field of illegal pointer type 'int *' declared here}}
+} FooUnion;
+
+kernel void pointer_in_union_arg(FooUnion arg) { }// expected-error{{union kernel parameters may not contain pointers}}
+
+typedef struct NestedPointer // expected-note 2 {{within field of type 'NestedPointer' declared here}}
+{
+ int x;
+ struct InnerNestedPointer
+ {
+ int* ptrField; // expected-note 3 {{field of illegal pointer type 'int *' declared here}}
+ } inner; // expected-note 3 {{within field of type 'struct InnerNestedPointer' declared here}}
+} NestedPointer;
+
+kernel void pointer_in_nested_struct_arg(NestedPointer arg) { }// expected-error{{struct kernel parameters may not contain pointers}}
+
+struct NestedPointerComplex // expected-note{{within field of type 'NestedPointerComplex' declared here}}
+{
+ int foo;
+ float bar;
+
+ struct InnerNestedPointerComplex
+ {
+ int innerFoo;
+ int* innerPtrField; // expected-note{{field of illegal pointer type 'int *' declared here}}
+ } inner; // expected-note{{within field of type 'struct InnerNestedPointerComplex' declared here}}
+
+ float y;
+ float z[4];
+};
+
+kernel void pointer_in_nested_struct_arg_complex(struct NestedPointerComplex arg) { }// expected-error{{struct kernel parameters may not contain pointers}}
+
+typedef struct NestedBool // expected-note 2 {{within field of type 'NestedBool' declared here}}
+{
+ int x;
+ struct InnerNestedBool
+ {
+ bool boolField; // expected-note 2 {{field of illegal type 'bool' declared here}}
+ } inner; // expected-note 2 {{within field of type 'struct InnerNestedBool' declared here}}
+} NestedBool;
+
+kernel void bool_in_nested_struct_arg(NestedBool arg) { } // expected-error{{'NestedBool' (aka 'struct NestedBool') cannot be used as the type of a kernel parameter}}
+
+// Warning emitted again for argument used in other kernel
+kernel void bool_in_nested_struct_arg_again(NestedBool arg) { } // expected-error{{'NestedBool' (aka 'struct NestedBool') cannot be used as the type of a kernel parameter}}
+
+
+// Check for note with a struct not defined inside the struct
+typedef struct NestedBool2Inner
+{
+ bool boolField; // expected-note{{field of illegal type 'bool' declared here}}
+} NestedBool2Inner;
+
+typedef struct NestedBool2 // expected-note{{within field of type 'NestedBool2' declared here}}
+{
+ int x;
+ NestedBool2Inner inner; // expected-note{{within field of type 'NestedBool2Inner' (aka 'struct NestedBool2Inner') declared here}}
+} NestedBool2;
+
+kernel void bool_in_nested_struct_2_arg(NestedBool2 arg) { } // expected-error{{'NestedBool2' (aka 'struct NestedBool2') cannot be used as the type of a kernel parameter}}
+
+
+struct InnerInner
+{
+ int* foo;
+ bool x;
+};
+
+struct Valid
+{
+ float c;
+ float d;
+};
+
+struct Inner
+{
+ struct Valid v;
+ struct InnerInner a;
+ struct Valid g;
+ struct InnerInner b;
+};
+
+struct AlsoUser // expected-note{{within field of type 'AlsoUser' declared here}}
+{
+ float x;
+ struct Valid valid1;
+ struct Valid valid2;
+ struct NestedPointer aaaa; // expected-note{{within field of type 'struct NestedPointer' declared here}}
+};
+
+kernel void pointer_in_nested_struct_arg_2(struct Valid valid, struct NestedPointer arg, struct AlsoUser also) { } // expected-error 2 {{struct kernel parameters may not contain pointers}}
Modified: cfe/trunk/test/SemaOpenCL/invalid-kernel.cl
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaOpenCL/invalid-kernel.cl?rev=186908&r1=186907&r2=186908&view=diff
==============================================================================
--- cfe/trunk/test/SemaOpenCL/invalid-kernel.cl (original)
+++ cfe/trunk/test/SemaOpenCL/invalid-kernel.cl Mon Jul 22 20:23:36 2013
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -verify %s
-kernel void no_ptrptr(global int **i) { } // expected-error{{kernel argument cannot be declared as a pointer to a pointer}}
+kernel void no_ptrptr(global int **i) { } // expected-error{{kernel parameter cannot be declared as a pointer to a pointer}}
kernel int bar() { // expected-error {{kernel must have void return type}}
return 6;
More information about the cfe-commits
mailing list