This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[trans-mem] optimize transaction local malloc/alloca memory
- From: Aldy Hernandez <aldyh at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org, rth at redhat dot com
- Date: Fri, 4 Dec 2009 10:26:45 -0400
- Subject: [trans-mem] optimize transaction local malloc/alloca memory
Howdy!
There is no need to instrument malloc/alloca memory being dereferenced
in a transaction if it can be proven that the memory was allocated
inside the transaction and cannot escape.
There is no instrumenting to do because for alloca, a transaction
restart will reset the stack pointer and we'll just reallocate again.
For malloc, a transaction restart will free the memory, and we'll also
reallocate again.
OK for branch?
* trans-mem.c (transaction_local_dynamic_memory_p): New.
(requires_barrier): Call transaction_local_dynamic_memory_p.
Index: testsuite/gcc.dg/tm/memopt-10.c
===================================================================
--- testsuite/gcc.dg/tm/memopt-10.c (revision 0)
+++ testsuite/gcc.dg/tm/memopt-10.c (revision 0)
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-options "-fgnu-tm -O -fdump-tree-tmmark" } */
+
+extern int something(void) __attribute__((transaction_safe));
+extern void *malloc (__SIZE_TYPE__) __attribute__((malloc,transaction_safe));
+
+int f()
+{
+ int *p;
+
+ p = malloc (sizeof (*p) * 100);
+
+ __transaction {
+ /* Instrument store, since memory pointed to by P is not
+ transaction local. */
+ p[5] = 123;
+
+ if (something())
+ __transaction_cancel;
+ }
+ return p[5];
+}
+
+/* { dg-final { scan-tree-dump-times "ITM_WU" 1 "tmmark" } } */
+/* { dg-final { cleanup-tree-dump "tmmark" } } */
Index: testsuite/gcc.dg/tm/memopt-8.c
===================================================================
--- testsuite/gcc.dg/tm/memopt-8.c (revision 0)
+++ testsuite/gcc.dg/tm/memopt-8.c (revision 0)
@@ -0,0 +1,26 @@
+/* { dg-do compile } */
+/* { dg-options "-fgnu-tm -O -fdump-tree-tmmark" } */
+
+extern int something(void) __attribute__((transaction_safe));
+extern int escape(int *) __attribute__((transaction_safe));
+extern void *malloc (__SIZE_TYPE__) __attribute__((malloc,transaction_safe));
+
+int f()
+{
+ int *p;
+
+ __transaction {
+ p = malloc (sizeof (*p) * 100);
+ escape (p);
+
+ /* This should be instrumented because P escapes. */
+ p[5] = 123;
+
+ if (something())
+ __transaction_cancel;
+ }
+ return p[5];
+}
+
+/* { dg-final { scan-tree-dump-times "ITM_WU" 1 "tmmark" } } */
+/* { dg-final { cleanup-tree-dump "tmmark" } } */
Index: testsuite/gcc.dg/tm/memopt-9.c
===================================================================
--- testsuite/gcc.dg/tm/memopt-9.c (revision 0)
+++ testsuite/gcc.dg/tm/memopt-9.c (revision 0)
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+/* { dg-options "-fgnu-tm -O -fdump-tree-tmmark" } */
+
+extern int something(void) __attribute__((transaction_safe));
+extern void *malloc (__SIZE_TYPE__) __attribute__((malloc,transaction_safe));
+
+struct large { int foo[500]; };
+
+int f()
+{
+ int *p;
+ struct large *lp;
+
+ __transaction {
+ p = malloc (sizeof (*p) * 100);
+ lp = malloc (sizeof (*lp) * 100);
+
+ /* No instrumentation necessary; P and LP are transaction local. */
+ p[5] = 123;
+ lp->foo[66] = 123;
+
+ if (something())
+ __transaction_cancel;
+ }
+ return p[5];
+}
+
+/* { dg-final { scan-tree-dump-times "ITM_WU" 0 "tmmark" } } */
+/* { dg-final { cleanup-tree-dump "tmmark" } } */
Index: trans-mem.c
===================================================================
--- trans-mem.c (revision 154874)
+++ trans-mem.c (working copy)
@@ -1130,6 +1130,76 @@ static tree lower_sequence_tm (gimple_st
static tree lower_sequence_no_tm (gimple_stmt_iterator *, bool *,
struct walk_stmt_info *);
+/* Given an address that is being dereferenced, return TRUE if we can
+ prove that the memory being dereferenced is a malloced type memory
+ local to the transaction, which therefore requires no
+ instrumentation.
+
+ ENTRY_BLOCK is the entry block to the transaction containing the
+ dereference of X. */
+static bool
+transaction_local_dynamic_memory_p (basic_block entry_block, tree x)
+{
+ gimple stmt = NULL;
+ enum tree_code code;
+
+ if (!entry_block)
+ return false;
+
+ /* Search back through the DEF chain to find the original definition
+ of this address. */
+ while (TREE_CODE (x) == SSA_NAME)
+ {
+ if (ptr_deref_may_alias_global_p (x))
+ {
+ /* Pointed to address escapes. This is not thread-private. */
+ return false;
+ }
+
+ stmt = SSA_NAME_DEF_STMT (x);
+
+ /* Bail if the malloc call is outside the transaction. We only
+ care about transaction local mallocs. There are no edges
+ into a transaction from without, so a simple dominance test
+ will do. */
+ if (!dominated_by_p (CDI_DOMINATORS, gimple_bb (stmt), entry_block))
+ return false;
+
+ if (is_gimple_assign (stmt))
+ {
+ code = gimple_assign_rhs_code (stmt);
+ /* x = foo ==> foo */
+ if (code == SSA_NAME)
+ x = gimple_assign_rhs1 (stmt);
+ /* x = foo + n ==> foo */
+ else if (code == POINTER_PLUS_EXPR)
+ x = gimple_assign_rhs1 (stmt);
+ /* x = (cast*) foo ==> foo */
+ else if (code == VIEW_CONVERT_EXPR || code == NOP_EXPR)
+ x = gimple_assign_rhs1 (stmt);
+ else
+ return false;
+ }
+ else
+ break;
+ }
+ if (stmt && is_gimple_call (stmt))
+ {
+ tree fn = gimple_call_fndecl (stmt);
+
+ if (DECL_BUILT_IN_CLASS (fn) == BUILT_IN_NORMAL
+ && (DECL_FUNCTION_CODE (fn) == BUILT_IN_MALLOC
+ || DECL_FUNCTION_CODE (fn) == BUILT_IN_ALLOCA))
+ {
+ /* No logging to do. For alloca stack pointer gets reset by
+ the retry and we reallocate. For malloc, a transaction
+ restart frees the memory and we reallocate. */
+ return true;
+ }
+ }
+ return false;
+}
+
/* Determine whether X has to be instrumented using a read
or write barrier.
@@ -1149,6 +1219,8 @@ requires_barrier (basic_block entry_bloc
switch (TREE_CODE (x))
{
case INDIRECT_REF:
+ if (transaction_local_dynamic_memory_p (entry_block, TREE_OPERAND (x, 0)))
+ return false;
return true;
case ALIGN_INDIRECT_REF: