Browse Source

gcc: Support interleaved declarations & definitions of task implementations.

* gcc-plugin/src/starpu.c (unpack_fn): New variable.
  (handle_task_attribute): Look up `starpu_unpack_cl_args'.
  (handle_task_implementation_attribute): Check the `where' argument
  here.
  (task_implementation_target_to_int): New function.
  (task_implementation_where): Use it.
  (build_codelet_wrapper_definition): Use the global `unpack_fn' instead
  of the local `unpack_fndecl'.
  (codelet_type): Cache the result.
  (define_codelet): Rename to...
  (declare_codelet): ... this.  Declare the codelet without defining
  it.  Remove call to `define_codelet_wrappers'.
  (handle_pre_genericize): Use `declare_codelet' instead
  `define_codelet'.
  (lower_starpu): Define the codelet wrappers and codelet here.

* gcc-plugin/tests/base.c (my_other_task, my_other_task_cpu,
  my_other_task_opencl): New functions.
  (main): Invoke `my_other_task'.

* gcc-plugin/tests/task-errors.c (my_task_nowhere): Move warning from
  definition to declaration.
Ludovic Courtès 13 years ago
parent
commit
886913ffe3
3 changed files with 118 additions and 66 deletions
  1. 79 63
      gcc-plugin/src/starpu.c
  2. 37 1
      gcc-plugin/tests/base.c
  3. 2 2
      gcc-plugin/tests/task-errors.c

+ 79 - 63
gcc-plugin/src/starpu.c

@@ -79,6 +79,9 @@ static const char task_implementation_wrapper_attribute_name[] =
 static const char codelet_struct_name[] = "starpu_codelet";
 static const char task_struct_name[] = "starpu_task";
 
+/* Cached function declarations.  */
+static tree unpack_fn;
+
 
 /* Forward declarations.  */
 
@@ -89,6 +92,8 @@ static tree build_pointer_lookup (tree pointer);
 static bool task_p (const_tree decl);
 static bool task_implementation_p (const_tree decl);
 
+static int task_implementation_target_to_int (const_tree target);
+
 
 /* Lookup the StarPU function NAME in the global scope and store the result
    in VAR (this can't be done from `lower_starpu'.)  */
@@ -715,6 +720,9 @@ handle_task_attribute (tree *node, tree name, tree args,
       pushdecl (cl);
     }
 
+  /* Lookup & cache function declarations for later reuse.  */
+  LOOKUP_STARPU_FUNCTION (unpack_fn, "starpu_unpack_cl_args");
+
   return NULL_TREE;
 }
 
@@ -777,6 +785,12 @@ handle_task_implementation_attribute (tree *node, tree name, tree args,
 
       TREE_USED (fn) = TREE_USED (task_decl);
 
+      /* Check the `where' argument to raise a warning if needed.  */
+      if (task_implementation_target_to_int (where) == 0)
+	warning_at (loc, 0,
+		    "unsupported target %E; task implementation won't be used",
+		    where);
+
       /* Keep the attribute.  */
       *no_add_attrs = false;
     }
@@ -844,13 +858,36 @@ task_pointer_parameter_types (const_tree task_decl)
   return filter (is_pointer, TYPE_ARG_TYPES (TREE_TYPE (task_decl)));
 }
 
+/* Return the StarPU integer constant corresponding to string TARGET.  */
+
+static int
+task_implementation_target_to_int (const_tree target)
+{
+  gcc_assert (TREE_CODE (target) == STRING_CST);
+
+  int where_int;
+
+  if (!strncmp (TREE_STRING_POINTER (target), "cpu",
+		TREE_STRING_LENGTH (target)))
+    where_int = STARPU_CPU;
+  else if (!strncmp (TREE_STRING_POINTER (target), "opencl",
+		     TREE_STRING_LENGTH (target)))
+    where_int = STARPU_OPENCL;
+  else if (!strncmp (TREE_STRING_POINTER (target), "cuda",
+		     TREE_STRING_LENGTH (target)))
+    where_int = STARPU_CUDA;
+  else
+    where_int = 0;
+
+  return where_int;
+}
+
 /* Return a value indicating where TASK_IMPL should execute (`STARPU_CPU',
    `STARPU_CUDA', etc.).  */
 
 static int
-task_implementation_where (tree task_impl)
+task_implementation_where (const_tree task_impl)
 {
-  int where_int;
   tree impl_attr, args, where;
 
   gcc_assert (TREE_CODE (task_impl) == FUNCTION_DECL);
@@ -862,39 +899,7 @@ task_implementation_where (tree task_impl)
   args = TREE_VALUE (impl_attr);
   where = TREE_VALUE (args);
 
-  if (!strncmp (TREE_STRING_POINTER (where), "cpu",
-		TREE_STRING_LENGTH (where)))
-    where_int = STARPU_CPU;
-  else if (!strncmp (TREE_STRING_POINTER (where), "opencl",
-		     TREE_STRING_LENGTH (where)))
-    where_int = STARPU_OPENCL;
-  else if (!strncmp (TREE_STRING_POINTER (where), "cuda",
-		     TREE_STRING_LENGTH (where)))
-    where_int = STARPU_CUDA;
-  else
-    {
-      static const char invalid_target_attribute_name[] = ".invalid_target";
-
-      if (lookup_attribute (invalid_target_attribute_name,
-			    DECL_ATTRIBUTES (task_impl)) == NULL_TREE)
-	{
-	  /* This is the first time we notice that WHERE is invalid.  Emit a
-	     warning and add a special attribute to TASK_IMPL to remember
-	     that we've already reported the problem.  */
-	  warning_at (DECL_SOURCE_LOCATION (task_impl), 0,
-		      "unsupported target %E; task implementation won't be used",
-		      where);
-
-	  DECL_ATTRIBUTES (task_impl) =
-	    tree_cons (get_identifier (invalid_target_attribute_name),
-		       NULL_TREE, DECL_ATTRIBUTES (task_impl));
-	}
-
-      /* TASK_IMPL won't be executed anywhere.  */
-      where_int = 0;
-    }
-
-  return where_int;
+  return task_implementation_target_to_int (where);
 }
 
 /* Return the task implemented by TASK_IMPL.  */
@@ -1023,13 +1028,9 @@ build_codelet_wrapper_definition (tree task_impl)
 
   tree build_body (tree wrapper_decl, tree vars)
   {
-    tree stmts = NULL, call, unpack_fndecl, v;
+    tree stmts = NULL, call, v;
     VEC(tree, gc) *args;
 
-    unpack_fndecl = lookup_name (get_identifier ("starpu_unpack_cl_args"));
-    gcc_assert (unpack_fndecl != NULL_TREE
-    		&& TREE_CODE (unpack_fndecl) == FUNCTION_DECL);
-
     /* Build `var0 = STARPU_VECTOR_GET_PTR (buffers[0]); ...'.  */
 
     size_t index = 0;
@@ -1072,7 +1073,7 @@ build_codelet_wrapper_definition (tree task_impl)
 
     if (VEC_length (tree, args) > 1)
       {
-	call = build_call_expr_loc_vec (UNKNOWN_LOCATION, unpack_fndecl, args);
+	call = build_call_expr_loc_vec (UNKNOWN_LOCATION, unpack_fn, args);
 	TREE_SIDE_EFFECTS (call) = 1;
 	append_to_statement_list (call, &stmts);
       }
@@ -1183,8 +1184,6 @@ define_codelet_wrappers (tree task)
       tree_cons (get_identifier (task_implementation_wrapper_attribute_name),
 		 wrapper_def,
 		 DECL_ATTRIBUTES (task_impl));
-
-    pushdecl (wrapper_def);
   }
 
   for_each (define, task_implementation_list (task));
@@ -1215,13 +1214,18 @@ build_codelet_identifier (tree task_decl)
 static tree
 codelet_type (void)
 {
-  tree type_decl;
+  /* XXX: Hack to allow the type declaration to be accessible at lower
+     time.  */
+  static tree type_decl = NULL_TREE;
 
-  /* Lookup the `starpu_codelet' struct type.  This should succeed since we
-     push <starpu.h> early on.  */
+  if (type_decl == NULL_TREE)
+    {
+      /* Lookup the `starpu_codelet' struct type.  This should succeed since
+	 we push <starpu.h> early on.  */
 
-  type_decl = lookup_name (get_identifier (codelet_struct_name));
-  gcc_assert (type_decl != NULL_TREE && TREE_CODE (type_decl) == TYPE_DECL);
+      type_decl = lookup_name (get_identifier (codelet_struct_name));
+      gcc_assert (type_decl != NULL_TREE && TREE_CODE (type_decl) == TYPE_DECL);
+    }
 
   return TREE_TYPE (type_decl);
 }
@@ -1373,24 +1377,18 @@ build_codelet_initializer (tree task_decl)
    pushed again.  */
 
 static tree
-define_codelet (tree task_decl)
+declare_codelet (tree task_decl)
 {
-  /* Generate a wrapper function for each implementation of TASK_DECL that
-     does all the packing/unpacking.  */
-  define_codelet_wrappers (task_decl);
-
   /* Retrieve the declaration of the `starpu_codelet' object.  */
-  tree cl_def;
-  cl_def = lookup_name (build_codelet_identifier (task_decl));
-  gcc_assert (cl_def != NULL_TREE && TREE_CODE (cl_def) == VAR_DECL);
+  tree cl_decl;
+  cl_decl = lookup_name (build_codelet_identifier (task_decl));
+  gcc_assert (cl_decl != NULL_TREE && TREE_CODE (cl_decl) == VAR_DECL);
 
   /* Turn the codelet declaration into a definition.  */
-  TREE_PUBLIC (cl_def) = TREE_PUBLIC (task_decl);
-  TREE_STATIC (cl_def) = true;
-  DECL_EXTERNAL (cl_def) = false;
-  DECL_INITIAL (cl_def) = build_codelet_initializer (task_decl);
+  TREE_TYPE (cl_decl) = codelet_type ();
+  TREE_PUBLIC (cl_decl) = TREE_PUBLIC (task_decl);
 
-  return cl_def;
+  return cl_decl;
 }
 
 
@@ -1411,7 +1409,7 @@ handle_pre_genericize (void *gcc_data, void *user_data)
 
       if (!TREE_STATIC (task))
 	{
-	  /* TASK lacks a body.  Instantiate its codelet, its codelet
+	  /* TASK lacks a body.  Declare its codelet, intantiate its codelet
 	     wrappers, and its body in this compilation unit.  */
 
 	  tree build_parameter (const_tree lst)
@@ -1428,7 +1426,9 @@ handle_pre_genericize (void *gcc_data, void *user_data)
 	    return param;
 	  }
 
-	  define_codelet (task);
+	  /* Declare TASK's codelet.  It cannot be defined yet because the
+	     complete list of tasks isn't available at this point.  */
+	  declare_codelet (task);
 
 	  /* Set the task's parameter list.  */
 	  DECL_ARGUMENTS (task) =
@@ -1554,6 +1554,22 @@ lower_starpu (void)
   fndecl = current_function_decl;
   gcc_assert (TREE_CODE (fndecl) == FUNCTION_DECL);
 
+  if (task_p (fndecl))
+    {
+      /* Generate a `starpu_codelet' structure and a wrapper function for
+	 each implementation of TASK_DECL.  This cannot be done earlier
+	 because we need to have a complete list of task implementations.  */
+
+      define_codelet_wrappers (fndecl);
+
+      tree cl_def = task_codelet_declaration (fndecl);
+      DECL_INITIAL (cl_def) = build_codelet_initializer (fndecl);
+      TREE_STATIC (cl_def) = true;
+      DECL_EXTERNAL (cl_def) = false;
+
+      varpool_finalize_decl (cl_def);
+    }
+
   /* This pass should occur after `build_cgraph_edges'.  */
   cgraph = cgraph_get_node (fndecl);
   gcc_assert (cgraph != NULL);

+ 37 - 1
gcc-plugin/tests/base.c

@@ -41,6 +41,32 @@ my_scalar_task_opencl (int x, char y, int z)
 }
 
 
+/* Another task, where task implementation declarations are interleaved with
+   task definitions.  */
+
+static void my_other_task (int x) __attribute__ ((task));
+
+static void my_other_task_cpu (int)
+  __attribute__ ((task_implementation ("cpu", my_other_task)));
+
+static void
+my_other_task_cpu (int x)
+{
+  printf ("cpu\n");
+}
+
+static void my_other_task_opencl (int)
+  __attribute__ ((task_implementation ("opencl", my_other_task)));
+
+static void
+my_other_task_opencl (int x)
+{
+  printf ("opencl\n");
+}
+
+
+
+
 int
 main (int argc, char *argv[])
 {
@@ -83,7 +109,17 @@ main (int argc, char *argv[])
      should be introduced, and we should take its address.  */
   my_scalar_task (42, y_as_long_int, 99);
 
-  assert (tasks_submitted == 9);
+  struct insert_task_argument expected2[] =
+    {
+      { STARPU_VALUE, &x, sizeof x },
+      { 0, 0, 0 }
+    };
+
+  expected_insert_task_arguments = expected2;
+
+  my_other_task (42);
+
+  assert (tasks_submitted == 10);
 
 #pragma starpu shutdown
   assert (initialized == 0);

+ 2 - 2
gcc-plugin/tests/task-errors.c

@@ -23,7 +23,7 @@ static void my_task_cpu (int foo, float *bar)    /* (error "type differs") */
 static void my_task_opencl (long foo, char *bar) /* (error "type differs") */
   __attribute__ ((task_implementation ("opencl", my_task)));
 
-static void my_task_nowhere (int foo, char *bar)
+static void my_task_nowhere (int foo, char *bar) /* (warning "unsupported target") */
   __attribute__ ((task_implementation ("does-not-exist", my_task)));
 
 static void my_task_not_quite (int foo, char *bar) /* (error "lacks the 'task' attribute") */
@@ -64,7 +64,7 @@ my_task_opencl (long foo, char *bar)
 }
 
 static void
-my_task_nowhere (int foo, char *bar)  /* (warning "unsupported target") */
+my_task_nowhere (int foo, char *bar)
 {
 }