浏览代码

gcc: Add an `output' type attribute for output task parameters.

* gcc-plugin/src/starpu.c (output_attribute_name): New variable.
  (handle_output_attribute, output_parameter_p): New functions.
  (register_task_attributes): Register the `output' type attribute.
  (build_task_body): Handle `output'-qualified parameters.

* gcc-plugin/tests/output-pointer-errors.c,
  gcc-plugin/tests/output-pointer.c: New files.

* gcc-plugin/tests/Makefile.am (gcc_tests): Add `output-pointer.c' and
  `output-pointer-errors.c'.

* doc/chapters/c-extensions.texi (Defining Tasks): Document the `output'
  type attribute.
Ludovic Courtès 13 年之前
父节点
当前提交
21e2721cce

+ 1 - 0
.gitignore

@@ -187,3 +187,4 @@ starpu.log
 /gcc-plugin/examples/matrix-mult
 /gcc-plugin/src/c-expr.c
 /gcc-plugin/tests/heap-allocated
+/gcc-plugin/tests/output-pointer

+ 11 - 4
doc/chapters/c-extensions.texi

@@ -78,11 +78,14 @@ Scalar arguments to the task are passed by value and copied to the
 target device if need be---technically, they are passed as the
 @code{cl_arg} buffer (@pxref{Codelets and Tasks, @code{cl_arg}}).
 
+@cindex @code{output} type attribute
 Pointer arguments are assumed to be registered data buffers---the
 @code{buffers} argument of a task (@pxref{Codelets and Tasks,
 @code{buffers}}); @code{const}-qualified pointer arguments are viewed as
 read-only buffers (@code{STARPU_R}), and non-@code{const}-qualified
-buffers are assumed to be used read-write (@code{STARPU_RW}).
+buffers are assumed to be used read-write (@code{STARPU_RW}).  In
+addition, the @code{output} type attribute can be as a type qualifier
+for output pointer or array parameters (@code{STARPU_W}).
 
 @item task_implementation (@var{target}, @var{task})
 @cindex @code{task_implementation} attribute
@@ -96,17 +99,21 @@ Declare the given function as an implementation of @var{task} to run on
 Here is an example:
 
 @example
-static void matmul (const float *A, const float *B, float *C,
+#define __output  __attribute__ ((output))
+
+static void matmul (const float *A, const float *B,
+                    __output float *C,
                     size_t nx, size_t ny, size_t nz)
   __attribute__ ((task));
 
-static void matmul_cpu (const float *A, const float *B, float *C,
+static void matmul_cpu (const float *A, const float *B,
+                        __output float *C,
                         size_t nx, size_t ny, size_t nz)
   __attribute__ ((task_implementation ("cpu", matmul)));
 
 
 static void
-matmul_cpu (const float *A, const float *B, float *C,
+matmul_cpu (const float *A, const float *B, __output float *C,
             size_t nx, size_t ny, size_t nz)
 @{
   size_t i, j, k;

+ 46 - 3
gcc-plugin/src/starpu.c

@@ -67,6 +67,7 @@ static const char plugin_name[] = "starpu";
 /* Names of public attributes.  */
 static const char task_attribute_name[] = "task";
 static const char task_implementation_attribute_name[] = "task_implementation";
+static const char output_attribute_name[] = "output";
 static const char heap_allocated_attribute_name[] = "heap_allocated";
 
 /* Names of attributes used internally.  */
@@ -864,6 +865,26 @@ handle_heap_allocated_attribute (tree *node, tree name, tree args,
   return NULL_TREE;
 }
 
+/* Handle the `output' attribute on type *NODE, which should be the type of a
+   PARM_DECL of a task or task implementation.  */
+
+static tree
+handle_output_attribute (tree *node, tree name, tree args,
+			 int flags, bool *no_add_attrs)
+{
+  tree type = *node;
+
+  gcc_assert (TYPE_P (type));
+
+  if (!POINTER_TYPE_P (type) && TREE_CODE (type) != ARRAY_TYPE)
+    error ("%<output%> attribute not allowed for non-pointer types");
+  else
+    /* Keep the attribute.  */
+    *no_add_attrs = false;
+
+  return NULL_TREE;
+}
+
 
 /* Return the declaration of the `struct starpu_codelet' variable associated with
    TASK_DECL.  */
@@ -1003,6 +1024,16 @@ task_implementation_wrapper (const_tree task_impl)
   return TREE_VALUE (attr);
 }
 
+/* Return true if DECL is a parameter whose type is `output'-qualified.  */
+
+static bool
+output_parameter_p (const_tree decl)
+{
+  return (TREE_CODE (decl) == PARM_DECL &&
+	  lookup_attribute (output_attribute_name,
+			    TYPE_ATTRIBUTES (TREE_TYPE (decl))) != NULL_TREE);
+}
+
 
 static void
 register_task_attributes (void *gcc_data, void *user_data)
@@ -1025,9 +1056,20 @@ register_task_attributes (void *gcc_data, void *user_data)
       handle_heap_allocated_attribute
     };
 
+  static const struct attribute_spec output_attr =
+    {
+      output_attribute_name, 0, 0, true, true, false,
+      handle_output_attribute,
+#if 0 /* FIXME: Check whether the `affects_type_identity' field is
+	 present.  */
+      true /* affects type identity */
+#endif
+    };
+
   register_attribute (&task_attr);
   register_attribute (&task_implementation_attr);
   register_attribute (&heap_allocated_attr);
+  register_attribute (&output_attr);
 }
 
 
@@ -1601,11 +1643,12 @@ build_task_body (const_tree task_decl)
 	     `STARPU_RW, ptr' or similar.  */
 
 	  /* If TYPE points to a const-qualified type, then mark the data as
-	     read-only; otherwise default to read-write.
-	     FIXME: Add an attribute to specify write-only.  */
+	     read-only; if is has the `output' attribute, then mark it as
+	     write-only; otherwise default to read-write.  */
 	  int mode =
 	    (TYPE_QUALS (TREE_TYPE (type)) & TYPE_QUAL_CONST)
-	    ? STARPU_R : STARPU_RW;
+	    ? STARPU_R
+	    : (output_parameter_p (p) ? STARPU_W : STARPU_RW);
 
 	  VEC_safe_push (tree, gc, args,
 			 build_int_cst (integer_type_node, mode));

+ 2 - 0
gcc-plugin/tests/Makefile.am

@@ -17,6 +17,8 @@
 gcc_tests =					\
   base.c					\
   pointers.c					\
+  output-pointer.c				\
+  output-pointer-errors.c			\
   register.c					\
   register-errors.c				\
   acquire.c					\

+ 25 - 0
gcc-plugin/tests/output-pointer-errors.c

@@ -0,0 +1,25 @@
+/* GCC-StarPU
+   Copyright (C) 2011 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/>.  */
+
+#define __output __attribute__ ((output))
+
+/* XXX: Currently, since `output' is a type attribute, we have no way to
+   restrict its use to PARM_DECLs of tasks.  */
+
+void f (__output int x)				  /* (error "not allowed") */
+  __attribute__ ((task));
+
+__output void g (int x);			  /* (error "not allowed") */

+ 97 - 0
gcc-plugin/tests/output-pointer.c

@@ -0,0 +1,97 @@
+/* GCC-StarPU
+   Copyright (C) 2011 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/>.  */
+
+#undef NDEBUG
+
+#include <mocks.h>
+
+#define __output __attribute__ ((output))
+
+/* The tasks under test.  */
+
+static void my_pointer_task (size_t size, __output int *x)
+  __attribute__ ((task));
+
+static void my_pointer_task_cpu (size_t size, __output int *x)
+  __attribute__ ((task_implementation ("cpu", my_pointer_task)));
+static void my_pointer_task_opencl (size_t size, __output int *x)
+  __attribute__ ((task_implementation ("opencl", my_pointer_task)));
+
+static void
+my_pointer_task_cpu (size_t size, __output int *x)
+{
+  printf ("%s: x = %p, size = %zi\n", __func__, x, size);
+}
+
+static void
+my_pointer_task_opencl (size_t size, int *x)
+{
+  printf ("%s: x = %p, size = %zi\n", __func__, x, size);
+}
+
+
+
+static void my_array_task (size_t size, __output int x[size])
+  __attribute__ ((task));
+
+static void my_array_task_cpu (size_t size, __output int x[size])
+  __attribute__ ((task_implementation ("cpu", my_array_task)));
+static void my_array_task_opencl (size_t size, __output int x[size])
+  __attribute__ ((task_implementation ("opencl", my_array_task)));
+
+static void
+my_array_task_cpu (size_t size, __output int x[size])
+{
+  printf ("%s: x = %p, size = %zi\n", __func__, x, size);
+}
+
+static void
+my_array_task_opencl (size_t size, __output int x[size])
+{
+  printf ("%s: x = %p, size = %zi\n", __func__, x, size);
+}
+
+
+
+int
+main (int argc, char *argv[])
+{
+#pragma starpu initialize
+
+  size_t size = 42;
+  int x[size];
+
+  struct insert_task_argument expected[] =
+    {
+      { STARPU_VALUE, &size, sizeof size },
+      { STARPU_W, x },
+      { 0, 0, 0 }
+    };
+
+  expected_insert_task_arguments = expected;
+
+  /* Invoke the task, which makes sure it gets called with EXPECTED.  */
+  my_pointer_task (size, x);
+
+  assert (tasks_submitted == 1);
+
+  /* Again.  */
+  my_array_task (size, x);
+
+  assert (tasks_submitted == 2);
+
+  return EXIT_SUCCESS;
+}