Forráskód Böngészése

gcc: Gracefully handle errors with `task' and `task_implementation'.

* gcc-plugin/src/starpu.c (handle_task_attribute,
  handle_task_implementation_attribute): Turn assertions into graceful
  error handling.
  (task_implementation_where): Warn once when TASK_IMPL has an
  unsupported target.

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

* gcc-plugin/tests/task-errors.c: New file.
Ludovic Courtès 14 éve
szülő
commit
a10cd72526
3 módosított fájl, 160 hozzáadás és 53 törlés
  1. 86 53
      gcc-plugin/src/starpu.c
  2. 1 0
      gcc-plugin/tests/Makefile.am
  3. 73 0
      gcc-plugin/tests/task-errors.c

+ 86 - 53
gcc-plugin/src/starpu.c

@@ -441,35 +441,40 @@ handle_task_attribute (tree *node, tree name, tree args,
   tree fn;
 
   fn = *node;
-  gcc_assert (TREE_CODE (fn) == FUNCTION_DECL);
 
-  /* This is a function declaration for something local to this
-     translation unit, so add the `task' attribute to FN.  */
-  *no_add_attrs = false;
+  if (TREE_CODE (fn) != FUNCTION_DECL)
+    error_at (DECL_SOURCE_LOCATION (fn),
+	      "%<task%> attribute only applies to functions");
+  else
+    {
+      /* This is a function declaration for something local to this
+	 translation unit, so add the `task' attribute to FN.  */
+      *no_add_attrs = false;
 
-  /* Add an empty `task_implementation_list' attribute.  */
-  DECL_ATTRIBUTES (fn) =
-    tree_cons (get_identifier (task_implementation_list_attribute_name),
-	       NULL_TREE,
-	       NULL_TREE);
+      /* Add an empty `task_implementation_list' attribute.  */
+      DECL_ATTRIBUTES (fn) =
+	tree_cons (get_identifier (task_implementation_list_attribute_name),
+		   NULL_TREE,
+		   NULL_TREE);
 
-  if (!TREE_PUBLIC (fn))
-    {
-      /* Set a dummy body to avoid "used but never defined" warnings when FN
-	 has file scope.  */
-      DECL_SAVED_TREE (fn) = build_printf ("hello from the task!");
-      DECL_INITIAL (fn) = build_block (NULL_TREE, NULL_TREE, fn, NULL_TREE);
-    }
+      if (!TREE_PUBLIC (fn))
+	{
+	  /* Set a dummy body to avoid "used but never defined" warnings when
+	     FN has file scope.  */
+	  DECL_SAVED_TREE (fn) = build_printf ("hello from the task!");
+	  DECL_INITIAL (fn) = build_block (NULL_TREE, NULL_TREE, fn, NULL_TREE);
+	}
 
-  /* Push a declaration for the corresponding `starpu_codelet' object and add
-     it as an attribute of FN.  */
-  tree cl = build_codelet_declaration (fn);
-  DECL_ATTRIBUTES (fn) =
-    tree_cons (get_identifier (task_codelet_attribute_name), cl,
-	       DECL_ATTRIBUTES (fn));
-  pushdecl (cl);
+      /* Push a declaration for the corresponding `starpu_codelet' object and
+	 add it as an attribute of FN.  */
+      tree cl = build_codelet_declaration (fn);
+      DECL_ATTRIBUTES (fn) =
+	tree_cons (get_identifier (task_codelet_attribute_name), cl,
+		   DECL_ATTRIBUTES (fn));
+      pushdecl (cl);
 
-  TREE_USED (fn) = true;
+      TREE_USED (fn) = true;
+    }
 
   /* Lookup the useful StarPU functions in the global scope (this can't be
      done from `lower_starpu'.)
@@ -498,48 +503,57 @@ static tree
 handle_task_implementation_attribute (tree *node, tree name, tree args,
 				      int flags, bool *no_add_attrs)
 {
+  location_t loc;
   tree fn, where, task_decl;
 
-  /* FIXME: Use error nodes instead of `gcc_assert'.  */
-
   /* FIXME:TODO: To change the order to (TASK, WHERE):
 	  tree cleanup_id = TREE_VALUE (TREE_VALUE (attr));
 	  tree cleanup_decl = lookup_name (cleanup_id);
   */
 
-
   fn = *node;
-  gcc_assert (TREE_CODE (fn) == FUNCTION_DECL);
-
   where = TREE_VALUE (args);
-  gcc_assert (TREE_CODE (where) == STRING_CST);
-
   task_decl = TREE_VALUE (TREE_CHAIN (args));
-  gcc_assert (TREE_CODE (task_decl) == FUNCTION_DECL);
-  gcc_assert (lookup_attribute (task_attribute_name,
-				DECL_ATTRIBUTES (task_decl)));
-  gcc_assert (TYPE_CANONICAL (TREE_TYPE (fn))
-	      == TYPE_CANONICAL (TREE_TYPE (task_decl))
-	      && TYPE_CANONICAL (TREE_TYPE (fn)) != NULL_TREE);
 
-  /* Add FN to the list of implementations of TASK_DECL.  */
+  loc = DECL_SOURCE_LOCATION (fn);
+
+  if (TREE_CODE (fn) != FUNCTION_DECL)
+    error_at (loc,
+	      "%<task_implementation%> attribute only applies to functions");
+  else if (TREE_CODE (where) != STRING_CST)
+    error_at (loc, "string constant expected "
+	      "as the first %<task_implementation%> argument");
+  else if (TREE_CODE (task_decl) != FUNCTION_DECL)
+    error_at (loc, "%qE is not a function", task_decl);
+  else if (lookup_attribute (task_attribute_name,
+			DECL_ATTRIBUTES (task_decl)) == NULL_TREE)
+    error_at (loc, "function %qE lacks the %<task%> attribute",
+	      DECL_NAME (task_decl));
+  else if (TYPE_CANONICAL (TREE_TYPE (fn))
+	   != TYPE_CANONICAL (TREE_TYPE (task_decl)))
+    error_at (loc, "type differs from that of task %qE",
+	      DECL_NAME (task_decl));
+  else
+    {
+      /* Add FN to the list of implementations of TASK_DECL.  */
 
-  tree attr, impls;
+      tree attr, impls;
 
-  attr = lookup_attribute (task_implementation_list_attribute_name,
-			   DECL_ATTRIBUTES (task_decl));
-  impls = tree_cons (NULL_TREE, fn, TREE_VALUE (attr));
+      attr = lookup_attribute (task_implementation_list_attribute_name,
+			       DECL_ATTRIBUTES (task_decl));
+      impls = tree_cons (NULL_TREE, fn, TREE_VALUE (attr));
 
-  DECL_ATTRIBUTES (task_decl) =
-    tree_cons (get_identifier (task_implementation_list_attribute_name),
-	       impls,
-	       remove_attribute (task_implementation_list_attribute_name,
-				 DECL_ATTRIBUTES (task_decl)));
+      DECL_ATTRIBUTES (task_decl) =
+	tree_cons (get_identifier (task_implementation_list_attribute_name),
+		   impls,
+		   remove_attribute (task_implementation_list_attribute_name,
+				     DECL_ATTRIBUTES (task_decl)));
 
-  TREE_USED (fn) = true;
+      TREE_USED (fn) = true;
 
-  /* Keep the attribute.  */
-  *no_add_attrs = false;
+      /* Keep the attribute.  */
+      *no_add_attrs = false;
+    }
 
   return NULL_TREE;
 }
@@ -588,7 +602,7 @@ task_pointer_parameter_types (const_tree task_decl)
    `STARPU_CUDA', etc.).  */
 
 static int
-task_implementation_where (const_tree task_impl)
+task_implementation_where (tree task_impl)
 {
   int where_int;
   tree impl_attr, args, where;
@@ -612,8 +626,27 @@ task_implementation_where (const_tree task_impl)
 		     TREE_STRING_LENGTH (where)))
     where_int = STARPU_CUDA;
   else
-    /* FIXME: Error out?  */
-    where_int = 0;
+    {
+      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 %qE; 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;
 }

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

@@ -19,6 +19,7 @@ gcc_tests =					\
   pointers.c					\
   register.c					\
   register-errors.c				\
+  task-errors.c					\
   scalar-tasks.c				\
   pointer-tasks.c
 

+ 73 - 0
gcc-plugin/tests/task-errors.c

@@ -0,0 +1,73 @@
+/* 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 error handling for the `task' and `task_implementation' attributes.  */
+
+static void my_task (int foo, char *bar) __attribute__ ((task));
+static void my_task_cpu (int foo, float *bar)    /* (error "type differs") */
+  __attribute__ ((task_implementation ("cpu", my_task)));
+
+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) /* (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") */
+  __attribute__ ((task_implementation ("cpu", my_task_nowhere)));
+
+static int foo /* (error "only applies to function") */
+  __attribute__ ((task_implementation ("cpu", my_task)));
+
+static int bar /* (error "only applies to function") */
+  __attribute__ ((task));
+
+static int not_a_task __attribute__ ((unused));
+
+static void my_task_almost (int foo, char *bar)    /* (error "not a function") */
+  __attribute__ ((task_implementation ("cpu", not_a_task)));
+
+static void my_task_wrong_task_arg (int foo, char *bar)   /* (error "not a function") */
+  __attribute__ ((task_implementation ("cpu", 123)));
+
+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_cpu (int foo, float *bar)
+{
+}
+
+static void
+my_task_opencl (long foo, char *bar)
+{
+}
+
+static void
+my_task_nowhere (int foo, char *bar)
+{
+}
+
+static void
+my_task_not_quite (int foo, char *bar)
+{
+}
+
+static void
+my_task_almost (int foo, char *bar)
+{
+}