Browse Source

gcc: Fix support for separate compilation.

* gcc-plugin/src/starpu.c (handle_task_attribute): Don't build FN's body
  here; remove check for an already existing body.
  (task_p, task_implementation_p): New functions.
  (maybe_define_codelet): Remove.
  (handle_pre_genericize): When FN is a task implementation, build the
  body, codelet, and codelet wrappers for its task, unless it already
  has a body.  Raise a "must not have a body" error when FN is a task.

* gcc-plugin/tests/Makefile.am (gcc_tests): Add `lib-user.c'.
  (EXTRA_DIST): Add `my-lib.h' and `my-lib.c'.

* gcc-plugin/tests/lib-user.c, gcc-plugin/tests/my-lib.c,
  gcc-plugin/tests/my-lib.h: New files.

* gcc-plugin/tests/task-errors.c: Adjust error message.
Ludovic Courtès 14 years ago
parent
commit
ea0a071b1f

+ 1 - 0
.gitignore

@@ -182,3 +182,4 @@ starpu.log
 /gcc-plugin/tests/register-errors
 /gcc-plugin/tests/acquire
 /gcc-plugin/tests/unregister
+/gcc-plugin/tests/lib-user

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

@@ -622,20 +622,6 @@ handle_task_attribute (tree *node, tree name, tree args,
 
   fn = *node;
 
-  tree build_parameter (const_tree lst)
-  {
-    tree param, type;
-
-    type = TREE_VALUE (lst);
-    param = build_decl (DECL_SOURCE_LOCATION (fn), PARM_DECL,
-			create_tmp_var_name ("parameter"),
-			type);
-    DECL_ARG_TYPE (param) = type;
-    DECL_CONTEXT (param) = fn;
-
-    return param;
-  }
-
   /* Get rid of the `task' attribute by default so that FN isn't further
      processed when it's erroneous.  */
   *no_add_attrs = true;
@@ -643,9 +629,6 @@ handle_task_attribute (tree *node, tree name, tree args,
   if (TREE_CODE (fn) != FUNCTION_DECL)
     error_at (DECL_SOURCE_LOCATION (fn),
 	      "%<task%> attribute only applies to functions");
-  else if (DECL_SAVED_TREE (fn) != NULL_TREE)
-    error_at (DECL_SOURCE_LOCATION (fn),
-	      "task %qE must not have a body", DECL_NAME (fn));
   else
     {
       /* This is a function declaration for something local to this
@@ -665,27 +648,6 @@ handle_task_attribute (tree *node, tree name, tree args,
 	tree_cons (get_identifier (task_codelet_attribute_name), cl,
 		   DECL_ATTRIBUTES (fn));
       pushdecl (cl);
-
-      /* Set the task's parameter list.  */
-      DECL_ARGUMENTS (fn) =
-	map (build_parameter,
-	     list_remove (void_type_p,
-			  TYPE_ARG_TYPES (TREE_TYPE (fn))));
-
-      /* Build its body.  */
-      DECL_SAVED_TREE (fn) = build_task_body (fn);
-      TREE_STATIC (fn) = true;
-      DECL_EXTERNAL (fn) = false;
-      DECL_INITIAL (fn) = build_block (NULL_TREE, NULL_TREE, fn, NULL_TREE);
-      DECL_RESULT (fn) =
-	build_decl (DECL_SOURCE_LOCATION (fn), RESULT_DECL,
-		    NULL_TREE, void_type_node);
-      DECL_CONTEXT (DECL_RESULT (fn)) = fn;
-
-      /* Compile FN's body.  */
-      rest_of_decl_compilation (fn, true, 0);
-      allocate_struct_function (fn, false);
-      cgraph_finalize_function (fn, false);
     }
 
   return NULL_TREE;
@@ -777,6 +739,26 @@ task_codelet_declaration (const_tree task_decl)
   return TREE_VALUE (cl_attr);
 }
 
+/* Return true if DECL is a task.  */
+
+static bool
+task_p (const_tree decl)
+{
+  return (TREE_CODE (decl) == FUNCTION_DECL &&
+	  lookup_attribute (task_attribute_name,
+			    DECL_ATTRIBUTES (decl)) != NULL_TREE);
+}
+
+/* Return true if DECL is a task implementation.  */
+
+static bool
+task_implementation_p (const_tree decl)
+{
+  return (TREE_CODE (decl) == FUNCTION_DECL &&
+	  lookup_attribute (task_implementation_attribute_name,
+			    DECL_ATTRIBUTES (decl)) != NULL_TREE);
+}
+
 /* Return the list of implementations of TASK_DECL.  */
 
 static tree
@@ -1351,30 +1333,65 @@ define_codelet (tree task_decl)
   return cl_def;
 }
 
-/* Define the `starpu_codelet' structure for the task implemented by
-   IMPL_DECL if we're in the right compilation unit, i.e., is IMPL_DECL is a
-   "cpu" task implementation.  */
-
-static void
-maybe_define_codelet (tree impl_decl)
-{
-  if (task_implementation_where (impl_decl) == STARPU_CPU)
-    /* IMPL_DECL is a "cpu" implementation of some task, so define the
-       codelet structure in this compilation unit.  */
-    define_codelet (task_implementation_task (impl_decl));
-}
 
 static void
 handle_pre_genericize (void *gcc_data, void *user_data)
 {
-  tree fndecl = (tree) gcc_data;
+  tree fn = (tree) gcc_data;
+
+  gcc_assert (TREE_CODE (fn) == FUNCTION_DECL);
+
+  if (task_p (fn) && TREE_STATIC (fn))
+    /* The user defined a body for task FN, which is forbidden.  */
+    error_at (DECL_SOURCE_LOCATION (fn),
+	      "task %qE must not have a body", DECL_NAME (fn));
+  else if (task_implementation_p (fn))
+    {
+      tree task = task_implementation_task (fn);
 
-  gcc_assert (fndecl != NULL_TREE && TREE_CODE (fndecl) == FUNCTION_DECL);
-  gcc_assert (lookup_name (DECL_NAME (fndecl)) == fndecl);
+      if (!TREE_STATIC (task))
+	{
+	  /* TASK lacks a body.  Instantiate its codelet, its codelet
+	     wrappers, and its body in this compilation unit.  */
+
+	  tree build_parameter (const_tree lst)
+	  {
+	    tree param, type;
+
+	    type = TREE_VALUE (lst);
+	    param = build_decl (DECL_SOURCE_LOCATION (task), PARM_DECL,
+				create_tmp_var_name ("parameter"),
+				type);
+	    DECL_ARG_TYPE (param) = type;
+	    DECL_CONTEXT (param) = task;
 
-  if (lookup_attribute (task_implementation_attribute_name,
-			DECL_ATTRIBUTES (fndecl)))
-    maybe_define_codelet (fndecl);
+	    return param;
+	  }
+
+	  define_codelet (task);
+
+	  /* Set the task's parameter list.  */
+	  DECL_ARGUMENTS (task) =
+	    map (build_parameter,
+		 list_remove (void_type_p,
+			      TYPE_ARG_TYPES (TREE_TYPE (task))));
+
+	  /* Build its body.  */
+	  DECL_SAVED_TREE (task) = build_task_body (task);
+	  TREE_STATIC (task) = true;
+	  DECL_EXTERNAL (task) = false;
+	  DECL_INITIAL (task) = build_block (NULL_TREE, NULL_TREE, task, NULL_TREE);
+	  DECL_RESULT (task) =
+	    build_decl (DECL_SOURCE_LOCATION (task), RESULT_DECL,
+			NULL_TREE, void_type_node);
+	  DECL_CONTEXT (DECL_RESULT (task)) = task;
+
+	  /* Compile TASK's body.  */
+	  rest_of_decl_compilation (task, true, 0);
+	  allocate_struct_function (task, false);
+	  cgraph_finalize_function (task, false);
+	}
+    }
 }
 
 /* Build a "conversion" from a raw C pointer to its data handle.  The

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

@@ -27,6 +27,7 @@ gcc_tests =					\
   scalar-tasks.c				\
   pointer-tasks.c				\
   no-initialize.c				\
+  lib-user.c					\
   shutdown-errors.c
 
 dist_noinst_HEADERS = mocks.h
@@ -38,7 +39,8 @@ CLEANFILES = *.gimple				\
   scalar-tasks					\
   pointer-tasks
 
-EXTRA_DIST = ./run-test.in
+EXTRA_DIST = ./run-test.in			\
+  my-lib.h my-lib.c
 
 if HAVE_GUILE
 

+ 67 - 0
gcc-plugin/tests/lib-user.c

@@ -0,0 +1,67 @@
+/* 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/>.  */
+
+/* Test whether tasks defined in another compilation unit can actually be
+   used.  */
+
+/* (instructions run (dependencies "my-lib.c")) */
+
+#include <mocks.h>
+
+#include <my-lib.h>
+
+int
+main (int argc, char *argv[])
+{
+#pragma starpu initialize
+
+  static const char x[] = { 0, 1, 2, 3, 4, 5 };
+  float y[sizeof x];
+
+  static const char forty_two = 42;
+  static const int  sizeof_x = sizeof x;
+
+  struct insert_task_argument expected_pointer_task[] =
+    {
+      { STARPU_VALUE, &forty_two, sizeof forty_two },
+      { STARPU_R,  x },
+      { STARPU_RW, y },
+      { STARPU_VALUE, &sizeof_x, sizeof sizeof_x },
+      { 0, 0, 0 }
+    };
+
+  expected_insert_task_arguments = expected_pointer_task;
+
+  expected_register_arguments.pointer = (void *) x;
+  expected_register_arguments.elements = sizeof x / sizeof x[0];
+  expected_register_arguments.element_size = sizeof x[0];
+#pragma starpu register x
+
+  expected_register_arguments.pointer = y;
+  expected_register_arguments.elements = sizeof y / sizeof y[0];
+  expected_register_arguments.element_size = sizeof y[0];
+#pragma starpu register y
+
+  /* Invoke the task, which should make sure it gets called with
+     EXPECTED.  */
+  my_task (42, x, y, sizeof x);
+
+  assert (tasks_submitted == 1);
+
+#pragma starpu shutdown
+
+  return EXIT_SUCCESS;
+}

+ 46 - 0
gcc-plugin/tests/my-lib.c

@@ -0,0 +1,46 @@
+/* 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/>.  */
+
+/* Example library of tasks.  */
+
+/* (instructions compile) */
+
+#include <my-lib.h>
+
+
+/* Task implementations: one is `static', one is global.  The codelet
+   wrapper, codelet, and task body should be instantiated in this file.  */
+
+static void my_task_opencl (char, const char *, float *, int)
+  __attribute__ ((task_implementation ("opencl", my_task)));
+
+void
+my_task_cpu (char a, const char *p, float *q, int b)
+{
+  int i;
+
+  for (i = 0; i < b; i++)
+    *q = *p + a;
+}
+
+static void
+my_task_opencl (char a, const char *p, float *q, int b)
+{
+  int i;
+
+  for (i = 0; i < b; i++)
+    *q = *p + a;
+}

+ 30 - 0
gcc-plugin/tests/my-lib.h

@@ -0,0 +1,30 @@
+/* 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/>.  */
+
+/* Example library of tasks.  */
+
+#ifndef MY_LIB_H
+#define MY_LIB_H
+
+extern void my_task (char, const char *, float *, int)
+  __attribute__ ((task));
+
+/* One of the implementations of MY_TASK.  Since it's `extern', this should
+   not trigger generation of the codelet, wrapper, etc.  */
+extern void my_task_cpu (char, const char *, float *, int)
+  __attribute__ ((task_implementation ("cpu", my_task)));
+
+#endif /* MY_LIB_H */

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

@@ -46,7 +46,7 @@ static void my_task_wrong_task_arg (int foo, char *bar)   /* (error "not a funct
 static void my_task_wrong_target_arg (int foo, char *bar) /* (error "string constant expected") */
   __attribute__ ((task_implementation (123, my_task)));
 
-static void my_task_with_a_body (int foo, char *bar) /* (note "previous definition") */
+static void my_task_with_a_body (int foo, char *bar)
   __attribute__ ((task, unused));
 
 
@@ -86,6 +86,6 @@ my_task_wrong_target_arg (int foo, char *bar)
 }
 
 static void
-my_task_with_a_body (int foo, char *bar)  /* (error "redefinition") *//* (warning "defined but not used") */
+my_task_with_a_body (int foo, char *bar)  /* (error "must not have a body") */
 {
 }