浏览代码

gcc: Support arbitrary C expressions in the `register' pragma.

* configure.ac: Look for Bison.

* gcc-plugin/src/Makefile.am (starpu_la_SOURCES): Add `c-expr.y'.
  (AM_CPPFLAGS): Add `-DYYERROR_VERBOSE=1'.

* gcc-plugin/src/c-expr.y: New file.

* gcc-plugin/src/starpu-gcc-config.h.in (HAVE_DECL_BUILD_ARRAY_REF): New
  macro.

* gcc-plugin/src/starpu.c (read_pragma_pointer_variable): Remove.
  (read_pragma_expressions): New function.
  (handle_pragma_register, handle_pragma_acquire,
  handle_pragma_unregister): Use it and adjust accordingly.

* gcc-plugin/tests/acquire-errors.c: Adjust error messages.
* gcc-plugin/tests/unregister-errors.c: Likewise.
* gcc-plugin/tests/register-errors.c: Likewise, and add tests with
  complex expressions.
* gcc-plugin/tests/register.c (bar): New function.
  (main): Add tests with complex expressions.

* m4/gcc.m4 (STARPU_GCC_PLUGIN_SUPPORT): Look for the declaration of
  `build_array_ref'.
Ludovic Courtès 14 年之前
父节点
当前提交
d2d32792dd

+ 1 - 0
.gitignore

@@ -185,3 +185,4 @@ starpu.log
 /gcc-plugin/tests/unregister
 /gcc-plugin/tests/lib-user
 /gcc-plugin/examples/matrix-mult
+/gcc-plugin/src/c-expr.c

+ 4 - 0
configure.ac

@@ -1094,6 +1094,10 @@ if test "x$enable_gcc_plugin" = "xyes"; then
 
    build_gcc_plugin="yes"
 
+   # Bison is used to generate the C expression parser.  The generated
+   # parser is part of the distribution, though.
+   AC_PROG_YACC
+
    # GNU Guile 1.8/2.0 is used to run the test suite.
    AC_PATH_PROG([GUILE], [guile])
    if test "x$GUILE" != "x"; then

+ 2 - 2
gcc-plugin/src/Makefile.am

@@ -17,7 +17,7 @@
 # requires a name prefixed by `lib'.
 pkglib_LTLIBRARIES = starpu.la
 
-starpu_la_SOURCES = starpu.c
+starpu_la_SOURCES = starpu.c c-expr.y
 
-AM_CPPFLAGS = -I$(GCC_PLUGIN_INCLUDE_DIR) -Wall
+AM_CPPFLAGS = -I$(GCC_PLUGIN_INCLUDE_DIR) -Wall -DYYERROR_VERBOSE=1
 AM_LDFLAGS = -module

+ 224 - 0
gcc-plugin/src/c-expr.y

@@ -0,0 +1,224 @@
+/* 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/>.  */
+
+/* Parser for simple C expressions in pragmas.  */
+
+%define api.pure
+%parse-param { location_t loc }
+%parse-param { const char *pragma }
+%parse-param { tree *seq }
+%debug
+
+%{
+  #include <starpu-gcc-config.h>
+
+  #include <gcc-plugin.h>
+  #include <plugin.h>
+  #include <tree.h>
+  #include <c-common.h>
+  #include <c-pragma.h>
+  #include <cpplib.h>
+
+  #if !HAVE_DECL_BUILD_ARRAY_REF
+  /* This declaration is missing in GCC 4.6.1.  */
+  extern tree build_array_ref (location_t loc, tree array, tree index);
+  #endif
+
+
+  #define YYSTYPE tree
+  #define YYLTYPE location_t
+
+  static void
+  yyerror (location_t loc, const char *pragma, tree *seq,
+	   char const *message)
+  {
+    error_at (loc, "parse error in pragma %qs: %s", pragma, message);
+  }
+
+  /* Return SOMETHING if it's a VAR_DECL, an identifier bound to a VAR_DECL,
+     or another object; raise an error otherwise.  */
+
+  static tree
+  ensure_bound (location_t loc, tree something)
+  {
+    gcc_assert (something != NULL_TREE);
+
+    if (DECL_P (something))
+      return something;
+    else if (TREE_CODE (something) == IDENTIFIER_NODE)
+      {
+	tree var = lookup_name (something);
+	if (var == NULL_TREE)
+	  {
+	    error_at (loc, "unbound variable %qE", something);
+	    return error_mark_node;
+	  }
+	else
+	  return var;
+      }
+
+    return something;
+  }
+
+  static tree
+  build_component_ref (location_t loc, tree what, tree field)
+  {
+    sorry ("struct field access not implemented yet"); /* XXX */
+    return error_mark_node;
+  }
+%}
+
+%code {
+  /* Mapping of libcpp token names to Bison-generated token names.  This is
+     not ideal but Bison cannot be told to use the `enum cpp_ttype'
+     values.  */
+  static const int cpplib_bison_token_map[] =
+    {
+      [CPP_NAME] = YCPP_NAME,
+      [CPP_NUMBER] = YCPP_NUM,
+      [CPP_AND] = YCPP_AND,
+      [CPP_OPEN_SQUARE] = YCPP_OPEN_SQUARE,
+      [CPP_CLOSE_SQUARE] = YCPP_CLOSE_SQUARE,
+      [CPP_OPEN_PAREN] = YCPP_OPEN_PAREN,
+      [CPP_CLOSE_PAREN] = YCPP_CLOSE_PAREN,
+      [CPP_PLUS] = YCPP_PLUS,
+      [CPP_MINUS] = YCPP_MINUS,
+      [CPP_MULT] = YCPP_MULT,
+      [CPP_DIV] = YCPP_DIV,
+      [CPP_DOT] = YCPP_DOT,
+      [CPP_DEREF] = YCPP_DEREF
+    };
+
+  static int
+  yylex (YYSTYPE *lvalp)
+  {
+    int ret;
+
+    ret = pragma_lex (lvalp);
+    if (ret < sizeof cpplib_bison_token_map / sizeof cpplib_bison_token_map[0])
+      ret = cpplib_bison_token_map[ret];
+    else
+      ret = -1;
+
+    return ret;
+  }
+}
+
+%token YCPP_NAME "identifier"
+%token YCPP_NUM "integer"
+%token YCPP_AND "&"
+%token YCPP_OPEN_SQUARE "["
+%token YCPP_CLOSE_SQUARE "]"
+%token YCPP_OPEN_PAREN "("
+%token YCPP_CLOSE_PAREN ")"
+%token YCPP_PLUS "+"
+%token YCPP_MINUS "-"
+%token YCPP_MULT "*"
+%token YCPP_DIV "/"
+%token YCPP_DOT "."
+%token YCPP_DEREF "->"
+
+%% /* Grammar rules.  */
+
+ /* Always return a TREE_LIST rather than a raw chain, because the elements
+    of that list may be already chained for other purposes---e.g., PARM_DECLs
+    of a function are chained together.  */
+
+sequence: expression {
+          gcc_assert (*seq == NULL_TREE);
+	  *seq = tree_cons (NULL_TREE, $1, NULL_TREE);
+	  $$ = *seq;
+      }
+      | expression sequence {
+	  gcc_assert ($2 == *seq);
+	  *seq = tree_cons (NULL_TREE, $1, $2);
+	  $$ = *seq;
+      }
+;
+
+expression: identifier | binary_expression | unary_expression;
+
+/* XXX: `ensure_bound' below leads to errors raised even for non-significant
+   arguments---e.g., junk after pragma.  */
+identifier: YCPP_NAME  { $$ = ensure_bound (loc, $1); }
+;
+
+binary_expression: multiplicative_expression
+     | additive_expression
+;
+
+multiplicative_expression: multiplicative_expression YCPP_MULT cast_expression {
+       $$ = build_binary_op (UNKNOWN_LOCATION, MULT_EXPR, $1, $3, 0);
+     }
+     | multiplicative_expression YCPP_DIV cast_expression {
+       $$ = build_binary_op (UNKNOWN_LOCATION, TRUNC_DIV_EXPR, $1, $3, 0);
+     }
+     | cast_expression
+;
+
+additive_expression: multiplicative_expression
+     | additive_expression YCPP_PLUS multiplicative_expression {
+       $$ = build_binary_op (UNKNOWN_LOCATION, PLUS_EXPR, $1, $3, 0);
+     }
+     | additive_expression YCPP_MINUS multiplicative_expression {
+       $$ = build_binary_op (UNKNOWN_LOCATION, MINUS_EXPR, $1, $3, 0);
+     }
+;
+
+cast_expression: unary_expression
+		 /* XXX: No support for '(' TYPE-NAME ')' UNARY-EXPRESSION.  */
+;
+
+unary_expression:
+       primary_expression
+     | postfix_expression
+     | YCPP_AND cast_expression {
+       $$ = build_addr (ensure_bound (loc, $2), current_function_decl);
+     }
+;
+
+postfix_expression:
+       primary_expression
+     | postfix_expression YCPP_OPEN_SQUARE expression YCPP_CLOSE_SQUARE {
+#if 1
+	 /* Build the array ref with proper error checking.  */
+	 $$ = build_array_ref (loc, ensure_bound (loc, $1),
+			       ensure_bound (loc, $3));
+#else /* TIMTOWTDI */
+	 $$ = build_indirect_ref (loc,
+	       build_binary_op (loc, PLUS_EXPR, ensure_bound (loc, $1), ensure_bound (loc, $3), 0),
+		RO_ARRAY_INDEXING);
+#endif
+     }
+     | postfix_expression YCPP_DOT identifier {
+        $$ = build_component_ref (loc, ensure_bound (loc, $1), $2);
+     }
+     | postfix_expression YCPP_DEREF identifier {
+        $$ = build_component_ref (loc,
+               build_indirect_ref (loc, ensure_bound (loc, $1), RO_ARRAY_INDEXING),
+               $2);
+     }
+;
+
+primary_expression: identifier
+     | constant
+     | YCPP_OPEN_PAREN expression YCPP_CLOSE_PAREN { $$ = $2; }
+;
+
+constant: YCPP_NUM { $$ = $1; }
+;
+
+%%

+ 2 - 0
gcc-plugin/src/starpu-gcc-config.h.in

@@ -21,3 +21,5 @@
 #undef HAVE_DECL_BUILD_CALL_EXPR_LOC_ARRAY
 
 #undef HAVE_DECL_BUILD_CALL_EXPR_LOC_VEC
+
+#undef HAVE_DECL_BUILD_ARRAY_REF

+ 113 - 89
gcc-plugin/src/starpu.c

@@ -355,40 +355,24 @@ handle_pragma_wait (struct cpp_reader *reader)
   add_stmt (build_call_expr (fndecl, 0));
 }
 
-/* Parse a pointer variable for PRAGMA, raising the appropriate error if
-   needed.  Return the pointer variable on success, NULL_TREE otherwise.  */
+/* The minimal C expression parser.  */
+
+extern int yyparse (location_t, const char *, tree *);
+extern int yydebug;
+
+/* Parse expressions from the CPP reader for PRAGMA, which is located at LOC.
+   Return a TREE_LIST of C expressions.  */
 
 static tree
-read_pragma_pointer_variable (const char *pragma, location_t loc)
+read_pragma_expressions (const char *pragma, location_t loc)
 {
-  tree token, var = NULL_TREE;
-  enum cpp_ttype type;
-
-  type = pragma_lex (&token);
-  if (type == CPP_EOF)
-    error_at (loc, "unterminated %<starpu %s%> pragma", pragma);
-  else if (type != CPP_NAME)
-    error_at (loc, "identifier expected");
-  else
-    {
-      /* Get the variable name.  */
-      tree var_name = token;
-      tree decl = lookup_name (var_name);
-
-      if (decl == NULL_TREE || !DECL_P (decl))
-	error_at (loc, "unbound variable %qE", var_name);
-      else if (!POINTER_TYPE_P (TREE_TYPE (decl))
-	       && TREE_CODE (TREE_TYPE (decl)) != ARRAY_TYPE)
-	error_at (loc, "%qE is neither a pointer nor an array", var_name);
-      else
-	{
-	  var = decl;
-	  TREE_USED (var) = true;
-	  DECL_READ_P (var) = true;
-	}
-    }
+  tree expr = NULL_TREE;
+
+  if (yyparse (loc, pragma, &expr))
+    /* Parse error or memory exhaustion.  */
+    expr = NULL_TREE;
 
-  return var;
+  return expr;
 }
 
 /* Process `#pragma starpu register VAR [COUNT]' and emit the corresponding
@@ -397,19 +381,38 @@ read_pragma_pointer_variable (const char *pragma, location_t loc)
 static void
 handle_pragma_register (struct cpp_reader *reader)
 {
-  tree token, var;
+  tree args, ptr, count_arg;
   location_t loc;
-  enum cpp_ttype type;
 
   loc = cpp_peek_token (reader, 0)->src_loc;
 
-  var = read_pragma_pointer_variable ("register", loc);
-  if (var == NULL_TREE)
+  args = read_pragma_expressions ("register", loc);
+  debug_tree (args);
+  if (args == NULL_TREE)
+    /* Parse error, presumably already handled by the parser.  */
+    return;
+
+  /* First argument should be a pointer expression.  */
+  ptr = TREE_VALUE (args);
+  args = TREE_CHAIN (args);
+
+  if (ptr == error_mark_node)
     return;
 
-  if (TREE_CODE (TREE_TYPE (var)) == ARRAY_TYPE
-      && !DECL_EXTERNAL (var)
-      && !TREE_STATIC (var)
+  if (!POINTER_TYPE_P (TREE_TYPE (ptr))
+      && TREE_CODE (TREE_TYPE (ptr)) != ARRAY_TYPE)
+    {
+      error_at (loc, "%qE is neither a pointer nor an array", ptr);
+      return;
+    }
+
+  TREE_USED (ptr) = true;
+  if (DECL_P (ptr))
+    DECL_READ_P (ptr) = true;
+
+  if (TREE_CODE (TREE_TYPE (ptr)) == ARRAY_TYPE
+      && !DECL_EXTERNAL (ptr)
+      && !TREE_STATIC (ptr)
       && !MAIN_NAME_P (DECL_NAME (current_function_decl)))
     warning_at (loc, 0, "using an on-stack array as a task input "
 		"considered unsafe");
@@ -417,9 +420,9 @@ handle_pragma_register (struct cpp_reader *reader)
   /* Determine the number of elements in the vector.  */
   tree count = NULL_TREE;
 
-  if (TREE_CODE (TREE_TYPE (var)) == ARRAY_TYPE)
+  if (TREE_CODE (TREE_TYPE (ptr)) == ARRAY_TYPE)
     {
-      tree domain = TYPE_DOMAIN (TREE_TYPE (var));
+      tree domain = TYPE_DOMAIN (TREE_TYPE (ptr));
 
       if (domain != NULL_TREE)
 	{
@@ -435,52 +438,44 @@ handle_pragma_register (struct cpp_reader *reader)
 	}
     }
 
+  /* Second argument is optional but should be an integer.  */
+  count_arg = (args == NULL_TREE) ? NULL_TREE : TREE_VALUE (args);
+  if (args != NULL_TREE)
+    {
+      args = TREE_CHAIN (args);
+      TREE_CHAIN (count_arg) = NULL_TREE;
+    }
 
-  type = pragma_lex (&token);
-  if (type == CPP_EOF)
+  if (count_arg == NULL_TREE)
     {
-      /* End of line reached: don't consume TOKEN and check whether the array
-	 size was determined.  */
+      /* End of line reached: check whether the array size was
+	 determined.  */
       if (count == NULL_TREE)
 	{
-	  error_at (loc, "cannot determine size of array %qE", DECL_NAME (var));
+	  error_at (loc, "cannot determine size of array %qE", ptr);
 	  return;
 	}
     }
+  else if (count_arg == error_mark_node)
+    /* COUNT_ARG could not be parsed and an error was already reported.  */
+    return;
+  else if (!INTEGRAL_TYPE_P (TREE_TYPE (count_arg)))
+    {
+      error_at (loc, "%qE is not an integer", count_arg);
+      return;
+    }
   else
     {
-      /* TOKEN may be a number or a integer variable.  */
-
-      tree count_arg;
-
-      if (TREE_CODE (token) == IDENTIFIER_NODE)
-	{
-	  count_arg = lookup_name (token);
-	  if (count_arg == NULL_TREE)
-	    {
-	      error_at (loc, "unbound variable %qE", token);
-	      return;
-	    }
-	  else if (!INTEGRAL_TYPE_P (TREE_TYPE (count_arg)))
-	    {
-	      error_at (loc, "integer expected");
-	      return;
-	    }
-
-	  TREE_USED (count_arg) = true;
-	  DECL_READ_P (count_arg) = true;
-	}
-      else if (TREE_CODE (token) != INTEGER_CST)
-	error_at (loc, "integer expected");
-      else
-	count_arg = token;
+      TREE_USED (count_arg) = true;
+      if (DECL_P (count_arg))
+	DECL_READ_P (count_arg) = true;
 
       if (count != NULL_TREE)
 	{
 	  /* The number of elements of this array was already determined.  */
 	  inform (loc,
 		  "element count can be omitted for bounded array %qE",
-		  DECL_NAME (var));
+		  ptr);
 
 	  if (count_arg != NULL_TREE)
 	    {
@@ -489,7 +484,7 @@ handle_pragma_register (struct cpp_reader *reader)
 		  if (!tree_int_cst_equal (count, count_arg))
 		    error_at (loc, "specified element count differs "
 			      "from actual size of array %qE",
-			      DECL_NAME (var));
+			      ptr);
 		}
 	      else
 		/* Using a variable to determine the array size whereas the
@@ -501,19 +496,24 @@ handle_pragma_register (struct cpp_reader *reader)
 	}
       else
 	count = count_arg;
-
-      if (pragma_lex (&token) != CPP_EOF)
-	error_at (loc, "junk after %<starpu register%> pragma");
     }
 
-  /* If VAR is an array, take its address.  */
+  /* Any remaining args?  */
+  if (args != NULL_TREE)
+    error_at (loc, "junk after %<starpu register%> pragma");
+
+  /* If PTR is an array, take its address.  */
   tree pointer =
-    POINTER_TYPE_P (TREE_TYPE (var))
-    ? var
-    : build_addr (var, current_function_decl);
+    POINTER_TYPE_P (TREE_TYPE (ptr))
+    ? ptr
+    : build_addr (ptr, current_function_decl);
 
   /* Introduce a local variable to hold the handle.  */
-  tree handle_var = create_tmp_var (ptr_type_node, ".handle");
+  tree handle_var = build_decl (loc, VAR_DECL, create_tmp_var_name (".handle"),
+				ptr_type_node);
+  DECL_CONTEXT (handle_var) = current_function_decl;
+  DECL_ARTIFICIAL (handle_var) = true;
+  DECL_INITIAL (handle_var) = NULL_TREE;
 
   tree register_fn =
     lookup_name (get_identifier ("starpu_vector_data_register"));
@@ -525,9 +525,13 @@ handle_pragma_register (struct cpp_reader *reader)
 		     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))));
+		     size_in_bytes (TREE_TYPE (TREE_TYPE (ptr))));
 
-  add_stmt (call);
+  tree bind;
+  bind = build3 (BIND_EXPR, void_type_node, handle_var, call,
+		 NULL_TREE);
+
+  add_stmt (bind);
 }
 
 /* Process `#pragma starpu acquire VAR' and emit the corresponding
@@ -539,16 +543,26 @@ handle_pragma_acquire (struct cpp_reader *reader)
   static tree acquire_fn;
   LOOKUP_STARPU_FUNCTION (acquire_fn, "starpu_data_acquire");
 
-  tree token, var;
+  tree args, var;
   location_t loc;
 
   loc = cpp_peek_token (reader, 0)->src_loc;
 
-  var = read_pragma_pointer_variable ("acquire", loc);
-  if (var == NULL_TREE)
+  args = read_pragma_expressions ("acquire", loc);
+  if (args == NULL_TREE)
     return;
 
-  if (pragma_lex (&token) != CPP_EOF)
+  var = TREE_VALUE (args);
+
+  if (var == error_mark_node)
+    return;
+  else if (TREE_CODE (TREE_TYPE (var)) != POINTER_TYPE
+	   && TREE_CODE (TREE_TYPE (var)) != ARRAY_TYPE)
+    {
+      error_at (loc, "%qE is neither a pointer nor an array", var);
+      return;
+    }
+  else if (TREE_CHAIN (var) != NULL_TREE)
     error_at (loc, "junk after %<starpu acquire%> pragma");
 
   /* If VAR is an array, take its address.  */
@@ -573,16 +587,26 @@ handle_pragma_unregister (struct cpp_reader *reader)
   static tree unregister_fn;
   LOOKUP_STARPU_FUNCTION (unregister_fn, "starpu_data_unregister");
 
-  tree token, var;
+  tree args, var;
   location_t loc;
 
   loc = cpp_peek_token (reader, 0)->src_loc;
 
-  var = read_pragma_pointer_variable ("unregister", loc);
-  if (var == NULL_TREE)
+  args = read_pragma_expressions ("unregister", loc);
+  if (args == NULL_TREE)
     return;
 
-  if (pragma_lex (&token) != CPP_EOF)
+  var = TREE_VALUE (args);
+
+  if (var == error_mark_node)
+    return;
+  else if (TREE_CODE (TREE_TYPE (var)) != POINTER_TYPE
+	   && TREE_CODE (TREE_TYPE (var)) != ARRAY_TYPE)
+    {
+      error_at (loc, "%qE is neither a pointer nor an array", var);
+      return;
+    }
+  else if (TREE_CHAIN (args) != NULL_TREE)
     error_at (loc, "junk after %<starpu unregister%> pragma");
 
   /* If VAR is an array, take its address.  */

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

@@ -28,8 +28,8 @@ main (int argc, char *argv[])
 
 #pragma starpu register x
 
-#pragma starpu acquire /* (error "unterminated") */
-#pragma starpu acquire 123 /* (error "identifier expected") */
+#pragma starpu acquire /* (error "parse error") */
+#pragma starpu acquire 123 /* (error "neither a pointer nor an array") */
 #pragma starpu acquire does_not_exit /* (error "unbound variable") */
 
 #pragma starpu acquire argc /* (error "neither a pointer nor an array") */

+ 8 - 2
gcc-plugin/tests/register-errors.c

@@ -23,9 +23,9 @@ main (int argc, char *argv[])
 {
 #pragma starpu initialize
 
-#pragma starpu register /* (error "unterminated") */
+#pragma starpu register /* (error "parse error") */
 
-#pragma starpu register argv 234 junk right here /* (error "junk after") */
+#pragma starpu register argv 234 junk here /* (error "junk after") *//* (error "unbound") *//* (error "unbound") */
 
   static int x[123] __attribute__ ((unused));
 #pragma starpu register x 234 /* (note "can be omitted") *//* (error "differs from actual size") */
@@ -37,9 +37,15 @@ main (int argc, char *argv[])
 #pragma starpu register argv does_not_exit /* (error "unbound variable") */
 
 #pragma starpu register argv /* (error "cannot determine size") */
+#pragma starpu register &argv[2] /* (error "cannot determine size") */
+#pragma starpu register &x[2] /* (error "cannot determine size") */
 
 #pragma starpu register argc /* (error "neither a pointer nor an array") */
 
+#pragma starpu register argv[2][3] 3 /* (error "neither a pointer nor an array") */
+
+#pragma starpu register argv[does_not_exist] 3 /* (error "unbound variable") */
+
   char **p = argv;
   size_t ps = argc;
 #pragma starpu register p ps  /* No unused variable warning, please! */

+ 39 - 1
gcc-plugin/tests/register.c

@@ -31,6 +31,15 @@ foo (void)
 #pragma starpu register x /* (warning "considered unsafe") */
 }
 
+static void
+bar (float *p, int s)
+{
+  expected_register_arguments.pointer = p;
+  expected_register_arguments.elements = s;
+  expected_register_arguments.element_size = sizeof *p;
+#pragma starpu register p s
+}
+
 int
 main (int argc, char *argv[])
 {
@@ -39,6 +48,7 @@ main (int argc, char *argv[])
   int x[123];
   double *y;
   static char z[345];
+  static float m[7][42];
   short w[] = { 1, 2, 3 };
   size_t y_size = 234;
 
@@ -84,8 +94,36 @@ main (int argc, char *argv[])
 #undef N
 
   foo ();
+  bar ((float *) argv, argc);
+
+  expected_register_arguments.pointer = argv;
+  expected_register_arguments.elements = argc;
+  expected_register_arguments.element_size = sizeof argv[0];
+
+  int chbouib = argc;
+#pragma starpu register argv chbouib
+
+  expected_register_arguments.pointer = &argv[2];
+  expected_register_arguments.elements = 3;
+  expected_register_arguments.element_size = sizeof argv[0];
+#pragma starpu register &argv[2] 3
+
+  expected_register_arguments.pointer = &argv[argc + 3 / 2];
+  expected_register_arguments.elements = argc * 4;
+  expected_register_arguments.element_size = sizeof argv[0];
+#pragma starpu register &argv[argc + 3 / 2] (argc * 4)
+
+  expected_register_arguments.pointer = &y[y_size / 2];
+  expected_register_arguments.elements = (y_size / 2 - 7);
+  expected_register_arguments.element_size = sizeof y[0];
+#pragma starpu register &y[y_size / 2] (y_size / 2 - 7)
+
+  expected_register_arguments.pointer = m[6];
+  expected_register_arguments.elements = 42;
+  expected_register_arguments.element_size = sizeof m[0][0];
+#pragma starpu register m[6]
 
-  assert (data_register_calls == 8);
+  assert (data_register_calls == 14);
 
   free (y);
 

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

@@ -28,8 +28,8 @@ main (int argc, char *argv[])
 
 #pragma starpu register x
 
-#pragma starpu unregister /* (error "unterminated") */
-#pragma starpu unregister 123 /* (error "identifier expected") */
+#pragma starpu unregister /* (error "parse error") */
+#pragma starpu unregister 123 /* (error "neither a pointer nor an array") */
 #pragma starpu unregister does_not_exit /* (error "unbound variable") */
 
 #pragma starpu unregister argc /* (error "neither a pointer nor an array") */

+ 2 - 1
m4/gcc.m4

@@ -52,7 +52,8 @@ AC_DEFUN([STARPU_GCC_PLUGIN_SUPPORT], [
     dnl   build_call_expr_loc_array -- not in GCC 4.5.x; appears in 4.6
     dnl   build_call_expr_loc_vec   -- likewise
     _STARPU_WITH_GCC_PLUGIN_API([
-      AC_CHECK_DECLS([build_call_expr_loc_array, build_call_expr_loc_vec],
+      AC_CHECK_DECLS([build_call_expr_loc_array, build_call_expr_loc_vec,
+                      build_array_ref],
         [], [], [#include <gcc-plugin.h>
 	         #include <tree.h>])
     ])