浏览代码

gcc: Diagnose problematic argument types in OpenCL task implementations.

* gcc-plugin/src/starpu.c (validate_opencl_argument_type): Add
  compatibility checks for standard OpenCL types that may differ from
  their C counterpart.

* gcc-plugin/tests/Makefile.am (gcc_tests): Rename `opencl-size_t
* gcc-plugin/tests/opencl-size_t.c: Rename to...
* gcc-plugin/tests/opencl-types.c: ... this.
  (my_long_task, my_long_task_cpu, my_long_task_opencl,
  my_long_ptr_task, my_long_ptr_task_cpu, my_long_ptr_task_opencl,
  my_uchar_task, my_uchar_task_cpu, my_uchar_task_opencl, my_cool_task,
  my_cool_task_cpu, my_cool_task_opencl): New functions.

* gcc-plugin/tests/mocks.h (cl_char, cl_uchar, cl_short, cl_ushort,
  cl_int, cl_uint, cl_long, cl_ulong, cl_half, cl_float, cl_double): New
  typedefs.

* gcc-plugin/tests/base.c: Use `unsigned char' instead of `char' as task
  argument types.

* gcc-plugin/tests/pointers.c: Use `long' instead of `long long' as task
  argument types.
Ludovic Courtès 13 年之前
父节点
当前提交
a2e85ea945

+ 73 - 6
gcc-plugin/src/starpu.c

@@ -30,6 +30,7 @@ int plugin_is_GPL_compatible;
 #include <cpplib.h>
 #include <tree.h>
 #include <tree-iterator.h>
+#include <langhooks.h>
 
 #ifdef HAVE_C_FAMILY_C_COMMON_H
 # include <c-family/c-common.h>
@@ -1001,15 +1002,81 @@ handle_task_attribute (tree *node, tree name, tree args,
 static void
 validate_opencl_argument_type (location_t loc, const_tree type)
 {
-  if (INTEGRAL_TYPE_P (type))
+  /* When TYPE is a pointer type, get to the base element type.  */
+  for (; POINTER_TYPE_P (type); type = TREE_TYPE (type));
+
+  if (!RECORD_OR_UNION_TYPE_P (type) && !VOID_TYPE_P (type))
     {
       tree decl = TYPE_NAME (type);
 
-      if (DECL_P (decl)
-	  && DECL_IN_SYSTEM_HEADER (decl)
-	  && DECL_NAME (decl) == get_identifier ("size_t"))
-	/* Check for the use of a literal `size_t'.  */
-	error_at (loc, "%<size_t%> is not a valid OpenCL type");
+      if (DECL_P (decl))
+	{
+	  static const struct { const char *c; const char *cl; }
+	  type_map[] =
+	    {
+	      { "char", "cl_char" },
+	      { "unsigned char", "cl_uchar" },
+	      { "short", "cl_short" },
+	      { "unsigned short", "cl_ushort" },
+	      { "int", "cl_int" },
+	      { "unsigned int", "cl_uint" },
+	      { "long int", "cl_long" },
+	      { "long unsigned int", "cl_ulong" },
+	      { "float", "cl_float" },
+	      { "double", "cl_double" },
+	      { NULL, NULL }
+	    };
+
+	  const char *c_name = IDENTIFIER_POINTER (DECL_NAME (decl));
+	  const char *cl_name =
+	    ({
+	      size_t i;
+	      for (i = 0; type_map[i].c != NULL; i++)
+		{
+		  if (strcmp (type_map[i].c, c_name) == 0)
+		    break;
+		}
+	      type_map[i].cl;
+	    });
+
+	  if (cl_name != NULL)
+	    {
+	      tree cl_type = lookup_name (get_identifier (cl_name));
+
+	      if (cl_type != NULL_TREE)
+		{
+		  if (DECL_P (cl_type))
+		    cl_type = TREE_TYPE (cl_type);
+
+		  if (!lang_hooks.types_compatible_p ((tree) type, cl_type))
+		    {
+		      tree st, sclt;
+
+		      st = c_common_signed_type ((tree) type);
+		      sclt = c_common_signed_type (cl_type);
+
+		      if (st == sclt)
+			warning_at (loc, 0, "C type %qE differs in signedness "
+				    "from the same-named OpenCL type",
+				    DECL_NAME (decl));
+		      else
+			/* TYPE should be avoided because the it differs from
+			   CL_TYPE, and thus cannot be used safely in
+			   `clSetKernelArg'.  */
+			warning_at (loc, 0, "C type %qE differs from the "
+				    "same-named OpenCL type",
+				    DECL_NAME (decl));
+		    }
+		}
+
+	      /* Otherwise we can't conclude.  It could be that <CL/cl.h>
+		 wasn't included in the program, for instance.  */
+	    }
+	  else
+	    /* Recommend against use of `size_t', etc.  */
+	    warning_at (loc, 0, "%qE does not correspond to a known "
+			"OpenCL type", DECL_NAME (decl));
+	}
     }
 }
 

+ 1 - 1
gcc-plugin/tests/Makefile.am

@@ -36,7 +36,7 @@ gcc_tests =					\
   heap-allocated-errors.c			\
   verbose.c					\
   debug-tree.c					\
-  opencl-size_t.c				\
+  opencl-types.c				\
   shutdown-errors.c
 
 dist_noinst_HEADERS = mocks.h

+ 7 - 7
gcc-plugin/tests/base.c

@@ -1,5 +1,5 @@
 /* GCC-StarPU
-   Copyright (C) 2011 Institut National de Recherche en Informatique et Automatique
+   Copyright (C) 2011, 2012 Institut National de Recherche en Informatique et Automatique
 
    GCC-StarPU is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -21,21 +21,21 @@
 
 /* The task under test.  */
 
-static void my_scalar_task (int x, char y, int z) __attribute__ ((task));
+static void my_scalar_task (int x, unsigned char y, int z) __attribute__ ((task));
 
-static void my_scalar_task_cpu (int, char, int)
+static void my_scalar_task_cpu (int, unsigned char, int)
   __attribute__ ((task_implementation ("cpu", my_scalar_task)));
-static void my_scalar_task_opencl (int, char, int)
+static void my_scalar_task_opencl (int, unsigned char, int)
   __attribute__ ((task_implementation ("opencl", my_scalar_task)));
 
 static void
-my_scalar_task_cpu (int x, char y, int z)
+my_scalar_task_cpu (int x, unsigned char y, int z)
 {
   printf ("%s: x = %i, y = %i, z = %i\n", __func__, x, (int) y, z);
 }
 
 static void
-my_scalar_task_opencl (int x, char y, int z)
+my_scalar_task_opencl (int x, unsigned char y, int z)
 {
   printf ("%s: x = %i, y = %i, z = %i\n", __func__, x, (int) y, z);
 }
@@ -84,7 +84,7 @@ main (int argc, char *argv[])
 #pragma starpu hello
 
   int x = 42, z = 99;
-  char y = 77;
+  unsigned char y = 77;
   long y_as_long_int = 77;
 
   struct insert_task_argument expected[] =

+ 24 - 0
gcc-plugin/tests/mocks.h

@@ -28,9 +28,33 @@
 
 #include <stdlib.h>
 #include <stdarg.h>
+#include <stdint.h>
 #include <string.h>
 #include <assert.h>
 #include <common/uthash.h>
+#include <stdint.h>
+
+
+/* Typedefs as found in <CL/cl_platform.h>.  */
+
+typedef int8_t         cl_char;
+typedef uint8_t        cl_uchar;
+typedef int16_t        cl_short;
+typedef uint16_t       cl_ushort;
+typedef int32_t        cl_int;
+typedef uint32_t       cl_uint;
+#ifdef BREAK_CL_LONG
+/* Make `cl_long' different from `long' for test purposes.  */
+typedef int16_t        cl_long;
+typedef uint16_t       cl_ulong;
+#else
+typedef int64_t        cl_long;
+typedef uint64_t       cl_ulong;
+#endif
+
+typedef uint16_t       cl_half;
+typedef float          cl_float;
+typedef double         cl_double;
 
 
 /* Stub used for testing purposes.  */

+ 0 - 39
gcc-plugin/tests/opencl-size_t.c

@@ -1,39 +0,0 @@
-/* GCC-StarPU
-   Copyright (C) 2012 Institut National de Recherche en Informatique et Automatique
-
-   GCC-StarPU is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   GCC-StarPU is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with GCC-StarPU.  If not, see <http://www.gnu.org/licenses/>.  */
-
-/* Make sure use of `size_t' as a task argument type is flagged.  */
-
-#undef NDEBUG
-
-#include <mocks.h>
-#include <unistd.h>
-
-static void my_task (size_t size, int x[size]) __attribute__ ((task));
-
-static void my_task_cpu (size_t size, int x[size])
-  __attribute__ ((task_implementation ("cpu", my_task)));
-static void my_task_opencl (size_t size, int x[size]) /* (error "not a valid OpenCL type") */
-  __attribute__ ((task_implementation ("opencl", my_task)));
-
-static void
-my_task_cpu (size_t size, int x[size])
-{
-}
-
-static void
-my_task_opencl (size_t size, int x[size])
-{
-}

+ 127 - 0
gcc-plugin/tests/opencl-types.c

@@ -0,0 +1,127 @@
+/* GCC-StarPU
+   Copyright (C) 2012 Institut National de Recherche en Informatique et Automatique
+
+   GCC-StarPU is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   GCC-StarPU is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GCC-StarPU.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* Make sure use of `size_t' as a task argument type is flagged.  */
+
+/* (instructions compile) */
+
+#undef NDEBUG
+
+/* Please gimme a broken `cl_long'!  */
+#define BREAK_CL_LONG
+
+#include <mocks.h>
+#include <unistd.h>
+
+
+/* Make sure `size_t' is flagged.  */
+
+static void my_task (size_t size, int x[size])
+  __attribute__ ((task));
+
+static void my_task_cpu (size_t size, int x[size])
+  __attribute__ ((task_implementation ("cpu", my_task)));
+static void my_task_opencl (size_t size, int x[size]) /* (warning "size_t.*not.*known OpenCL type") */
+  __attribute__ ((task_implementation ("opencl", my_task)));
+
+static void
+my_task_cpu (size_t size, int x[size])
+{
+}
+
+static void
+my_task_opencl (size_t size, int x[size])
+{
+}
+
+
+/* Make sure types that have the same name in C and OpenCL but are actually
+   different are flagged.  We assume `sizeof (long) == 4' here.  */
+
+static void my_long_task (unsigned long size, int x[size])
+  __attribute__ ((task));
+
+static void my_long_task_cpu (unsigned long size, int x[size])
+  __attribute__ ((task_implementation ("cpu", my_long_task)));
+static void my_long_task_opencl (unsigned long size,  /* (warning "differs from the same-named OpenCL type") */
+				 int x[size])
+  __attribute__ ((task_implementation ("opencl", my_long_task)));
+
+static void
+my_long_task_cpu (unsigned long size, int x[size])
+{
+}
+
+static void
+my_long_task_opencl (unsigned long size, int x[size])
+{
+}
+
+
+/* Same with a pointer-to-long.  */
+
+static void my_long_ptr_task (unsigned long *p)
+  __attribute__ ((task));
+
+static void my_long_ptr_task_cpu (unsigned long *p)
+  __attribute__ ((task_implementation ("cpu", my_long_ptr_task)));
+static void my_long_ptr_task_opencl (unsigned long *p) /* (warning "differs from the same-named OpenCL type") */
+  __attribute__ ((task_implementation ("opencl", my_long_ptr_task)));
+
+static void
+my_long_ptr_task_cpu (unsigned long *p)
+{
+}
+
+static void
+my_long_ptr_task_opencl (unsigned long *p)
+{
+}
+
+
+/* Same with an array of unsigned chars.  */
+
+static void my_uchar_task (char c[])
+  __attribute__ ((task));
+
+static void my_uchar_task_cpu (char c[])
+  __attribute__ ((task_implementation ("cpu", my_uchar_task)));
+static void my_uchar_task_opencl (char c[]) /* (warning "differs in signedness from the same-named OpenCL type") */
+  __attribute__ ((task_implementation ("opencl", my_uchar_task)));
+
+static void
+my_uchar_task_cpu (char c[])
+{
+}
+
+static void
+my_uchar_task_opencl (char c[])
+{
+}
+
+
+/* No OpenCL, no problems.  */
+
+static void my_cool_task (size_t size, long long x[size])
+  __attribute__ ((task));
+
+static void my_cool_task_cpu (size_t size, long long x[size])
+  __attribute__ ((task_implementation ("cpu", my_cool_task)));
+
+static void
+my_cool_task_cpu (size_t size, long long x[size])
+{
+}

+ 12 - 12
gcc-plugin/tests/pointers.c

@@ -21,42 +21,42 @@
 
 /* The tasks under test.  */
 
-static void my_pointer_task (const int *x, long long *y) __attribute__ ((task));
+static void my_pointer_task (const int *x, long *y) __attribute__ ((task));
 
-static void my_pointer_task_cpu (const int *, long long *)
+static void my_pointer_task_cpu (const int *, long *)
   __attribute__ ((task_implementation ("cpu", my_pointer_task)));
-static void my_pointer_task_opencl (const int *, long long *)
+static void my_pointer_task_opencl (const int *, long *)
   __attribute__ ((task_implementation ("opencl", my_pointer_task)));
 
 static void
-my_pointer_task_cpu (const int *x, long long *y)
+my_pointer_task_cpu (const int *x, long *y)
 {
   printf ("%s: x = %p, y = %p\n", __func__, x, y);
 }
 
 static void
-my_pointer_task_opencl (const int *x, long long *y)
+my_pointer_task_opencl (const int *x, long *y)
 {
   printf ("%s: x = %p, y = %p\n", __func__, x, y);
 }
 
 
 
-static void my_mixed_task (int *x, char z, const long long *y)
+static void my_mixed_task (int *x, unsigned char z, const long *y)
   __attribute__ ((task));
-static void my_mixed_task_cpu (int *, char, const long long *)
+static void my_mixed_task_cpu (int *, unsigned char, const long *)
   __attribute__ ((task_implementation ("cpu", my_mixed_task)));
-static void my_mixed_task_opencl (int *, char, const long long *)
+static void my_mixed_task_opencl (int *, unsigned char, const long *)
   __attribute__ ((task_implementation ("opencl", my_mixed_task)));
 
 static void
-my_mixed_task_cpu (int *x, char z, const long long *y)
+my_mixed_task_cpu (int *x, unsigned char z, const long *y)
 {
   printf ("%s: x = %p, y = %p, z = %i\n", __func__, x, y, (int) z);
 }
 
 static void
-my_mixed_task_opencl (int *x, char z, const long long *y)
+my_mixed_task_opencl (int *x, unsigned char z, const long *y)
 {
   printf ("%s: x = %p, y = %p, z = %i\n", __func__, x, y, (int) z);
 }
@@ -68,9 +68,9 @@ main (int argc, char *argv[])
 {
 #pragma starpu initialize
 
-  static const char z = 0x77;
+  static const unsigned char z = 0x77;
   int x[] = { 42 };
-  long long *y;
+  long *y;
 
   y = malloc (sizeof *y);
   *y = 77;