瀏覽代碼

gcc: Add support for `#pragma starpu register VAR [COUNT]'.

* gcc-plugin/src/starpu.c (handle_pragma_register): New function.
  (register_pragmas): Register the `register' pragma.

* gcc-plugin/tests/Makefile.am (check_PROGRAMS): Add `register'.

* gcc-plugin/tests/lib.h (struct data_register_arguments): New struct.
  (data_register_calls, expected_register_arguments): New variables.
  (starpu_vector_data_register): New function.

* gcc-plugin/tests/register.c: New file.
Ludovic Courtès 14 年之前
父節點
當前提交
aef51b4c19
共有 5 個文件被更改,包括 240 次插入0 次删除
  1. 3 0
      .gitignore
  2. 125 0
      gcc-plugin/src/starpu.c
  3. 1 0
      gcc-plugin/tests/Makefile.am
  4. 35 0
      gcc-plugin/tests/lib.h
  5. 76 0
      gcc-plugin/tests/register.c

+ 3 - 0
.gitignore

@@ -175,3 +175,6 @@ starpu.log
 /doc/starpu.tp
 /doc/starpu.tps
 /doc/starpu.vr
+/gcc-plugin/tests/register
+/tests/datawizard/acquire_cb_insert
+/tools/starpu_perfmodel_plot

+ 125 - 0
gcc-plugin/src/starpu.c

@@ -288,6 +288,129 @@ handle_pragma_wait (struct cpp_reader *reader)
   add_stmt (build_call_expr (fndecl, 0));
 }
 
+/* Process `#pragma starpu register VAR [COUNT]' and emit the corresponding
+   `starpu_vector_data_register' call.
+
+   FIXME: Currently processing happens before macro expansion, even though
+   the docstring of `cpp_get_token' says otherwise.  */
+
+static void
+handle_pragma_register (struct cpp_reader *reader)
+{
+  const cpp_token *token;
+
+  token = cpp_peek_token (reader, 0);
+  if (token->type == CPP_PRAGMA_EOL)
+    error_at (token->src_loc, "unterminated %<starpu register%> pragma");
+
+  token = cpp_get_token (reader);
+  if (token->type != CPP_NAME)
+    error_at (token->src_loc, "identifier expected");
+
+  /* Get the variable name.  */
+  tree var_name = get_identifier ((char *) cpp_token_as_text (reader, token));
+
+  tree var = lookup_name (var_name);
+  if (var == NULL_TREE || !DECL_P (var))
+    error_at (token->src_loc, "unbound variable %qE", var_name);
+
+  gcc_assert (POINTER_TYPE_P (TREE_TYPE (var))
+	      || TREE_CODE (TREE_TYPE (var)) == ARRAY_TYPE);
+
+  if (TREE_CODE (TREE_TYPE (var)) == ARRAY_TYPE
+      && !DECL_EXTERNAL (var)
+      && !TREE_STATIC (var)
+      && !MAIN_NAME_P (DECL_NAME (current_function_decl)))
+    warning_at (token->src_loc, 0, "using an on-stack array as a task input "
+		"considered unsafe");
+
+  /* Determine the number of elements in the vector.  */
+  tree count = NULL_TREE;
+
+  if (TREE_CODE (TREE_TYPE (var)) == ARRAY_TYPE)
+    {
+      tree domain = TYPE_DOMAIN (TREE_TYPE (var));
+
+      if (domain != NULL_TREE)
+	{
+	  count = build_binary_op (token->src_loc, MINUS_EXPR,
+				   TYPE_MAX_VALUE (domain),
+				   TYPE_MIN_VALUE (domain),
+				   false);
+	  count = build_binary_op (token->src_loc, PLUS_EXPR,
+				   count,
+				   build_int_cstu (integer_type_node, 1),
+				   false);
+	  count = fold_convert (size_type_node, count);
+	}
+    }
+
+  token = cpp_peek_token (reader, 0);
+  if (token->type == CPP_PRAGMA_EOL)
+    {
+      /* End of line reached: don't consume TOKEN and check whether the array
+	 size was determined.  */
+      if (count == NULL_TREE)
+	error_at (token->src_loc, "cannot determine size of array %qE",
+		  var_name);
+    }
+  else if (token->type == CPP_NUMBER)
+    {
+      /* TOKEN is a number, consume it.  */
+      token = cpp_get_token (reader);
+
+      unsigned int flags = cpp_classify_number (reader, token);
+      if ((flags & CPP_N_CATEGORY) != CPP_N_INTEGER)
+	error_at (token->src_loc, "invalid integer");
+
+      cpp_num value = cpp_interpret_integer (reader, token, CPP_N_UNSIGNED);
+      tree count_arg = build_int_cst_wide (size_type_node, value.low, value.high);
+
+      if (count != NULL_TREE)
+	{
+	  /* The number of elements of this array was already determined.  */
+	  inform (token->src_loc,
+		  "element count can be omitted for bounded array %qE",
+		  var_name);
+
+	  if (!tree_int_cst_equal (count, count_arg))
+	    error_at (token->src_loc,
+		      "specified element count differs from actual size of array %qE",
+		      var_name);
+	}
+      else
+	count = count_arg;
+
+      if (cpp_peek_token (reader, 0)->type != CPP_PRAGMA_EOL)
+	error_at (token->src_loc, "junk after %<starpu register%> pragma");
+    }
+  else
+    error_at (token->src_loc, "integer expected");
+
+  /* If VAR is an array, take its address.  */
+  tree pointer =
+    POINTER_TYPE_P (TREE_TYPE (var))
+    ? var
+    : build_addr (var, current_function_decl);
+
+  /* Introduce a local variable to hold the handle.  */
+  tree handle_var = create_tmp_var (ptr_type_node, ".handle");
+
+  tree register_fn =
+    lookup_name (get_identifier ("starpu_vector_data_register"));
+
+  /* Build `starpu_vector_data_register (&HANDLE_VAR, 0, POINTER,
+                                         COUNT, sizeof *POINTER)'  */
+  tree call =
+    build_call_expr (register_fn, 5,
+		     build_addr (handle_var, current_function_decl),
+		     build_zero_cst (uintptr_type_node), /* home node */
+		     pointer, count,
+		     size_in_bytes (TREE_TYPE (TREE_TYPE (var))));
+
+  add_stmt (call);
+}
+
 static void
 register_pragmas (void *gcc_data, void *user_data)
 {
@@ -295,6 +418,8 @@ register_pragmas (void *gcc_data, void *user_data)
 		     handle_pragma_hello);
   c_register_pragma (STARPU_PRAGMA_NAME_SPACE, "wait",
 		     handle_pragma_wait);
+  c_register_pragma (STARPU_PRAGMA_NAME_SPACE, "register",
+		     handle_pragma_register);
 }
 
 

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

@@ -19,6 +19,7 @@ TESTS = $(check_PROGRAMS)
 check_PROGRAMS =				\
   base						\
   pointers					\
+  register					\
   scalar-tasks					\
   pointer-tasks
 

+ 35 - 0
gcc-plugin/tests/lib.h

@@ -183,3 +183,38 @@ starpu_handle_get_local_ptr (starpu_data_handle handle)
 {
   return dummy_handle_to_pointer (handle);
 }
+
+
+/* Data registration.  */
+
+struct data_register_arguments
+{
+  /* A pointer to the vector being registered.  */
+  void *pointer;
+
+  /* Number of elements in the vector.  */
+  size_t elements;
+
+  /* Size of individual elements.  */
+  size_t element_size;
+};
+
+/* Number of `starpu_vector_data_register' calls.  */
+static unsigned int data_register_calls;
+
+/* Variable describing the expected `starpu_vector_data_register'
+   arguments.  */
+struct data_register_arguments expected_register_arguments;
+
+void
+starpu_vector_data_register (starpu_data_handle *handle,
+			     uint32_t home_node, uintptr_t ptr,
+			     uint32_t count, size_t elemsize)
+{
+  assert ((void *) ptr == expected_register_arguments.pointer);
+  assert (count == expected_register_arguments.elements);
+  assert (elemsize == expected_register_arguments.element_size);
+
+  data_register_calls++;
+  *handle = dummy_pointer_to_handle ((void *) ptr);
+}

+ 76 - 0
gcc-plugin/tests/register.c

@@ -0,0 +1,76 @@
+/* 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 `#pragma starpu register ...' generates the right code.  */
+
+#undef NDEBUG
+
+#include <lib.h>
+
+int
+main (int argc, char *argv[])
+{
+  int x[123];
+  double *y;
+  static char z[345];
+  short w[] = { 1, 2, 3 };
+
+  y = malloc (234 * sizeof *y);
+
+  expected_register_arguments.pointer = x;
+  expected_register_arguments.elements = 123;
+  expected_register_arguments.element_size = sizeof x[0];
+#pragma starpu register x 123
+
+  expected_register_arguments.pointer = y;
+  expected_register_arguments.elements = 234;
+  expected_register_arguments.element_size = sizeof *y;
+#pragma starpu register y 234
+
+  expected_register_arguments.pointer = z;
+  expected_register_arguments.elements = 345;
+  expected_register_arguments.element_size = sizeof z[0];
+#pragma starpu register z
+
+  expected_register_arguments.pointer = w;
+  expected_register_arguments.elements = 3;
+  expected_register_arguments.element_size = sizeof w[0];
+#pragma starpu register w
+
+  expected_register_arguments.pointer = argv;
+  expected_register_arguments.elements = 456;
+  expected_register_arguments.element_size = sizeof argv[0];
+#pragma starpu register argv 456
+
+  /* FIXME: Uncomment the example below when macros are suitably
+     expanded.  */
+#if 0
+#define ARGV argv
+#define N 456
+  expected_register_arguments.pointer = argv;
+  expected_register_arguments.elements = N;
+  expected_register_arguments.element_size = sizeof argv[0];
+#pragma starpu register ARGV N
+#undef ARGV
+#undef N
+#endif
+
+  assert (data_register_calls == 5);
+
+  free (y);
+
+  return EXIT_SUCCESS;
+}