Переглянути джерело

gcc: Have codelet wrappers handle pointer arguments.

* gcc-plugin/src/starpu.c (array_ref): New function.
  (build_codelet_wrapper_definition)[build_scalar_var_chain]: Rename
  to...
  [build_var_chain]: ... this.  Add `type_list' and `seed' parameters.
  [build_body]: Handle pointer arguments.
  Change VARS to hold the complete list of scalar and pointer arguments.

* gcc-plugin/tests/Makefile.am (check_PROGRAMS): Add `pointer-tasks'.
  (pointer_tasks_LDADD): New variable.

* gcc-plugin/tests/pointer-tasks.c: New file.
Ludovic Courtès 14 роки тому
батько
коміт
8f98cf700a

+ 76 - 8
gcc-plugin/src/starpu.c

@@ -102,6 +102,30 @@ build_call_expr_loc_vec (location_t loc, tree fndecl, VEC(tree,gc) *vec)
 
 /* Helpers.  */
 
+
+/* Build a reference to the INDEXth element of ARRAY.  `build_array_ref' is
+   not exported, so we roll our own.  */
+
+static tree
+array_ref (tree array, size_t index)
+{
+  gcc_assert (POINTER_TYPE_P (TREE_TYPE (array)));
+
+  tree pointer_plus_offset =
+    index > 0
+    ? build_binary_op (UNKNOWN_LOCATION, PLUS_EXPR,
+		       array,
+		       build_int_cstu (integer_type_node, index),
+		       0)
+    : array;
+
+  gcc_assert (POINTER_TYPE_P (TREE_TYPE (pointer_plus_offset)));
+
+  return build_indirect_ref (UNKNOWN_LOCATION,
+			     pointer_plus_offset,
+			     RO_ARRAY_INDEXING);
+}
+
 /* Like `build_constructor_from_list', but sort VALS according to their
    offset in struct TYPE.  Inspired by `gnat_build_constructor'.  */
 
@@ -136,6 +160,8 @@ build_constructor_from_unsorted_list (tree type, tree vals)
   return build_constructor (type, v);
 }
 
+
+
 /* Debugging helpers.  */
 
 static tree build_printf (const char *, ...)
@@ -549,20 +575,21 @@ build_codelet_wrapper_definition (tree task_impl)
   loc = DECL_SOURCE_LOCATION (task_impl);
   task_decl = task_implementation_task (task_impl);
 
-  tree build_scalar_var_chain (tree wrapper_decl)
+  tree build_var_chain (tree type_list, const char *seed, tree wrapper_decl)
   {
     tree types, prev, vars = NULL_TREE;
 
-    for (types = task_scalar_parameter_types (task_decl), prev = NULL_TREE;
+    for (types = type_list, prev = NULL_TREE;
 	 types != NULL_TREE;
 	 types = TREE_CHAIN (types))
       {
 	tree var;
 
 	var = build_decl (loc, VAR_DECL,
-			  create_tmp_var_name ("scalar_arg"),
+			  create_tmp_var_name (seed),
 			  TREE_VALUE (types));
 	DECL_CONTEXT (var) = wrapper_decl;
+	DECL_ARTIFICIAL (var) = true;
 
 	if (prev != NULL_TREE)
 	  TREE_CHAIN (prev) = var;
@@ -587,16 +614,52 @@ build_codelet_wrapper_definition (tree task_impl)
     gcc_assert (unpack_fndecl != NULL_TREE
     		&& TREE_CODE (unpack_fndecl) == FUNCTION_DECL);
 
+    /* Build `var0 = STARPU_VECTOR_GET_PTR (buffers[0]); ...'.  */
+
+    size_t index = 0;
+    for (v = vars; v != NULL_TREE; v = TREE_CHAIN (v))
+      {
+	if (POINTER_TYPE_P (TREE_TYPE (v)))
+	  {
+	    /* Compute `void *VDESC = buffers[0];'.  */
+	    tree vdesc = array_ref (DECL_ARGUMENTS (wrapper_decl), index);
+
+	    /* Below we assume (1) that pointer arguments are registered as
+	       StarPU vector handles, and (2) that the `ptr' field is at
+	       offset 0 of `starpu_vector_interface_s'.  The latter allows us
+	       to use a simple pointer dereference instead of expanding
+	       `STARPU_VECTOR_GET_PTR'.  */
+	    assert (offsetof (struct starpu_vector_interface_s, ptr) == 0);
+
+	    /* Compute `type *PTR = *(type **) VDESC;'.  */
+	    tree ptr = build1 (INDIRECT_REF,
+			       build_pointer_type (TREE_TYPE (v)),
+			       vdesc);
+
+	    append_to_statement_list (build2 (MODIFY_EXPR, TREE_TYPE (v),
+					      v, ptr),
+				      &stmts);
+
+	    index++;
+	  }
+      }
+
     /* Build `starpu_unpack_cl_args (cl_args, &var1, &var2, ...)'.  */
 
     args = NULL;
     VEC_safe_push (tree, gc, args, TREE_CHAIN (DECL_ARGUMENTS (wrapper_decl)));
     for (v = vars; v != NULL_TREE; v = TREE_CHAIN (v))
-      VEC_safe_push (tree, gc, args, build_addr (v, wrapper_decl));
+      {
+	if (!POINTER_TYPE_P (TREE_TYPE (v)))
+	  VEC_safe_push (tree, gc, args, build_addr (v, wrapper_decl));
+      }
 
-    call = build_call_expr_loc_vec (UNKNOWN_LOCATION, unpack_fndecl, args);
-    TREE_SIDE_EFFECTS (call) = 1;
-    append_to_statement_list (call, &stmts);
+    if (VEC_length (tree, args) > 1)
+      {
+	call = build_call_expr_loc_vec (UNKNOWN_LOCATION, unpack_fndecl, args);
+	TREE_SIDE_EFFECTS (call) = 1;
+	append_to_statement_list (call, &stmts);
+      }
 
     /* Build `my_task_impl (var1, var2, ...)'.  */
 
@@ -646,7 +709,12 @@ build_codelet_wrapper_definition (tree task_impl)
   decl = build_decl (loc, FUNCTION_DECL, wrapper_name,
 		     build_codelet_wrapper_type ());
 
-  vars = build_scalar_var_chain (decl);
+  /* FIXME: This won't work if scalar and pointer params are
+     interspersed.  */
+  vars = chainon (build_var_chain (task_scalar_parameter_types (task_decl),
+				   "scalar_arg", decl),
+		  build_var_chain (task_pointer_parameter_types (task_decl),
+				   "pointer_arg", decl));
 
   DECL_CONTEXT (decl) = NULL_TREE;
   DECL_ARGUMENTS (decl) = build_parameters (decl);

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

@@ -19,9 +19,11 @@ TESTS = $(check_PROGRAMS)
 check_PROGRAMS =				\
   base						\
   pointers					\
-  scalar-tasks
+  scalar-tasks					\
+  pointer-tasks
 
 scalar_tasks_LDADD = $(top_builddir)/src/libstarpu.la
+pointer_tasks_LDADD = $(top_builddir)/src/libstarpu.la
 
 dist_noinst_HEADERS = lib.h
 

+ 81 - 0
gcc-plugin/tests/pointer-tasks.c

@@ -0,0 +1,81 @@
+/* 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 <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+
+/* The task under test.  */
+
+static void my_pointer_task (int *x, long long *y) __attribute__ ((task));
+
+static void my_pointer_task_cpu (int *x, long long *y)
+  __attribute__ ((task_implementation ("cpu", my_pointer_task), noinline));
+
+static int implementations_called;
+
+/* The input arguments.  */
+static int pointer_arg1[] = { 42, 1, 2, 3, 4, 5 };
+static long long *pointer_arg2;
+
+static void
+my_pointer_task_cpu (int *x, long long *y)
+{
+  implementations_called |= STARPU_CPU;
+  assert (x == pointer_arg1);
+  assert (y == pointer_arg2);
+}
+
+
+
+int
+main (int argc, char *argv[])
+{
+#define COUNT 100
+  pointer_arg2 = malloc (COUNT * sizeof *pointer_arg2);
+  memset (pointer_arg2, 0x77, COUNT * sizeof *pointer_arg2);
+
+  /* FIXME: Eventually remove calls to libstarpu and use pragmas or generated
+     code.  */
+
+  starpu_init (NULL);
+
+  /* Register POINTER_ARG1 and POINTER_ARG2
+     FIXME: Use a pragma when available.  */
+  starpu_data_handle handle;
+  starpu_vector_data_register (&handle, 0, (uintptr_t) pointer_arg1,
+			       sizeof pointer_arg1 / sizeof pointer_arg1[0],
+			       sizeof pointer_arg1[0]);
+  starpu_vector_data_register (&handle, 0, (uintptr_t) pointer_arg2,
+			       COUNT, sizeof *pointer_arg2);
+
+  /* Invoke the task, which should make sure it gets called with
+     EXPECTED.  */
+  my_pointer_task (pointer_arg1, pointer_arg2);
+
+#pragma starpu wait
+
+  assert (implementations_called == STARPU_CPU);
+
+  starpu_shutdown ();
+
+  free (pointer_arg2);
+
+  return EXIT_SUCCESS;
+}