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