浏览代码

gcc: Make `heap_allocated' arrays really have an array type.

* gcc-plugin/src/starpu.c (handle_heap_allocated_attribute): Make VAR
  keep its array type instead of pointer type, but fiddle with its size
  and alignment.  Mark the `starpu_malloc' call as side-effecting.  Call
  `starpu_free' instead of `_starpu_free_unref'.

* gcc-plugin/tests/heap-allocated.c (foo)[test_array_parm,
  test_array_static_parm, test_pointer_parm]: New nested functions.
  Use them and check pointer/array arithmetic.
  (main): Pass `foo' a large value.

* gcc-plugin/tests/mocks.h (_starpu_free_unref): Remove.
  (starpu_free): New function.
* include/starpu_data.h (_starpu_free_unref): Remove declaration.
* src/util/malloc.c (_starpu_free_unref): Remove.
Ludovic Courtès 13 年之前
父节点
当前提交
a0f073e426
共有 5 个文件被更改,包括 54 次插入21 次删除
  1. 12 6
      gcc-plugin/src/starpu.c
  2. 38 1
      gcc-plugin/tests/heap-allocated.c
  3. 4 3
      gcc-plugin/tests/mocks.h
  4. 0 4
      include/starpu_data.h
  5. 0 7
      src/util/malloc.c

+ 12 - 6
gcc-plugin/src/starpu.c

@@ -833,25 +833,31 @@ handle_heap_allocated_attribute (tree *node, tree name, tree args,
   else
     {
       tree array_type = TREE_TYPE (var);
-      tree pointer_type = build_pointer_type (array_type);
+      tree pointer_type = build_pointer_type (strip_array_types (array_type));
 
-      TREE_TYPE (var) = pointer_type;
+      /* We want VAR to feel like an array, but to really be a pointer.  So
+	 the hack consists in keeping its array type, but giving it the
+	 storage of a pointer.  (XXX) */
       DECL_SIZE (var) = TYPE_SIZE (pointer_type);
       DECL_SIZE_UNIT (var) = TYPE_SIZE_UNIT (pointer_type);
+      DECL_ALIGN (var) = TYPE_ALIGN (pointer_type);
+      DECL_USER_ALIGN (var) = false;
       DECL_MODE (var) = TYPE_MODE (pointer_type);
 
       tree malloc_fn = lookup_name (get_identifier ("starpu_malloc"));
       gcc_assert (malloc_fn != NULL_TREE);
 
-      add_stmt (build_call_expr (malloc_fn, 2,
-				 build_addr (var, current_function_decl),
-				 TYPE_SIZE_UNIT (array_type)));
+      tree alloc = build_call_expr (malloc_fn, 2,
+				    build_addr (var, current_function_decl),
+				    TYPE_SIZE_UNIT (array_type));
+      TREE_SIDE_EFFECTS (alloc) = true;
+      add_stmt (alloc);
 
       /* Add a destructor for VAR.
 	 TODO: Provide a way to disable this.  */
       DECL_ATTRIBUTES (var) =
 	tree_cons (get_identifier ("cleanup"),
-		   lookup_name (get_identifier ("_starpu_free_unref")),
+		   lookup_name (get_identifier ("starpu_free")),
 		   DECL_ATTRIBUTES (var));
     }
 

+ 38 - 1
gcc-plugin/tests/heap-allocated.c

@@ -21,12 +21,47 @@
 static void
 foo (size_t size)
 {
+  /* See ISO C99, Section 6.7.5.2 ("Array Declarators") and Section 6.7.6
+     ("Type names").  */
+
+  float *test_array_parm (float m[size][23], int x, int y)
+  {
+    return &m[x][y];
+  }
+
+  size_t minus_one = size - 1;
+  float *test_array_static_parm (float m[static minus_one][23], int x, int y)
+  {
+    return &m[x][y];
+  }
+
+  float *test_pointer_parm (float *m, int x, int y)
+  {
+    return &m[23 * x + y];
+  }
+
   expected_malloc_argument = size * 23 * sizeof (float);
 
+  /* The idea is that this code should be compilable both with and without
+     the attribute.  */
   float m[size][23] __attribute__ ((heap_allocated));
 
   assert (malloc_calls == 1);
 
+  /* Make sure "array arithmetic" works.  */
+  assert ((char *) &m[0][1] - (char *) &m[0][0] == sizeof m[0][0]);
+  assert ((char *) &m[1][0] - (char *) &m[0][22] == sizeof m[0][0]);
+
+  unsigned int x, y;
+  for (x = 0; x < size; x++)
+    for (y = 0; y < 23; y++)
+      {
+	assert (&m[x][y] == test_array_parm (m, x, y));
+	assert (&m[x][y] == test_array_static_parm (m, x, y));
+	assert (&m[x][y] == test_pointer_parm ((float *) m, x, y));
+	assert (&m[x][y] == test_pointer_parm ((float *) &m, x, y));
+      }
+
   /* Freed when going out of scope.  */
   expected_free_argument = m;
 }
@@ -36,7 +71,9 @@ main (int argc, char *argv[])
 {
 #pragma starpu initialize
 
-  foo (42 + argc);
+  /* Choose the size such that the process would most likely segfault if
+     `foo' tried to allocate this much data on the stack.  */
+  foo (100000);
 
   assert (free_calls == 1);
 

+ 4 - 3
gcc-plugin/tests/mocks.h

@@ -290,11 +290,12 @@ starpu_malloc (void **ptr, size_t size)
   return 0;
 }
 
-void
-_starpu_free_unref (void *ptr)
+int
+starpu_free (void *ptr)
 {
-  assert (* (void **) ptr == expected_free_argument);
+  assert (ptr == expected_free_argument);
   free_calls++;
+  return 0;
 }
 
 

+ 0 - 4
include/starpu_data.h

@@ -78,10 +78,6 @@ void starpu_data_release(starpu_data_handle_t handle);
 int starpu_malloc(void **A, size_t dim);
 int starpu_free(void *A);
 
-#ifdef STARPU_GCC_PLUGIN
-void _starpu_free_unref(void *p);
-#endif
-
 /* XXX These macros are provided to avoid breaking old codes. But consider
  * these function names as deprecated. */
 #define starpu_data_malloc_pinned_if_possible	starpu_malloc

+ 0 - 7
src/util/malloc.c

@@ -224,10 +224,3 @@ int starpu_free(void *A)
 
 	return 0;
 }
-
-/* Internal convenience function, used by code generated by the GCC
- * plug-in.  */
-void _starpu_free_unref(void *p)
-{
-	(void)starpu_free(* (void **)p);
-}