This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[trans-mem] thread-private malloc optimizations


In the previous patch I attacked transaction local malloc optimizations,
which are new memories created within a transaction.  This is a subset
of the more general thread-private malloc optimizations.  As rth
explained, thread-private memory is memory that is created in a function
but whose address does not escape it, and is thus invisible to other
threads.

Here I implement the more general case of thread-private malloc optimizations.

This should be it for malloc type optimizations, although perhaps... we
could be more aggressive with some phi nodes if we previously calculated
logging information on any of its components.  Hmmmm, I'll think about
this.

OK for branch?

	* trans-mem.c (transaction_invariant_address_p): Exclude self.
	Look inside INDIRECT_REF.
	(transaction_local_new_memory_p): Handle thread-private memory
	that is not transaction local.
	(requires_barrier): Pass additional argument.

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,28 @@
+/* { 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 {
+    /* p[5] is thread private, but not transaction local since the
+       malloc is outside of the transaction.  We can use the logging
+       functions for this.  */
+    p[5] = 123;
+
+    if (something())
+      __transaction_cancel;
+  }
+  return p[5];
+}
+
+/* { dg-final { scan-tree-dump-times "ITM_LU" 1 "tmmark" } } */
+/* { dg-final { scan-tree-dump-times "ITM_WU" 0 "tmmark" } } */
+/* { dg-final { scan-tree-dump-times "tm_save" 0 "tmmark" } } */
+/* { dg-final { cleanup-tree-dump "tmmark" } } */
Index: testsuite/gcc.dg/tm/memopt-11.c
===================================================================
--- testsuite/gcc.dg/tm/memopt-11.c	(revision 0)
+++ testsuite/gcc.dg/tm/memopt-11.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));
+
+int f()
+{
+  int *p;
+
+  p = malloc (sizeof (*p) * 100);
+  foo(p[5]);
+
+  __transaction {
+    /* p[5] is thread private, however the SSA_NAME that holds the
+       address dominates the entire transaction (transaction
+       invariant) so we can use a save/restore pair.  */
+    p[5] = 123;
+
+    if (something())
+      __transaction_cancel;
+  }
+  return p[5];
+}
+
+/* { dg-final { scan-tree-dump-times "ITM_LU" 0 "tmmark" } } */
+/* { dg-final { scan-tree-dump-times "ITM_WU" 0 "tmmark" } } */
+/* { dg-final { scan-tree-dump-times "tm_save" 1 "tmmark" } } */
+/* { dg-final { cleanup-tree-dump "tmmark" } } */
Index: trans-mem.c
===================================================================
--- trans-mem.c	(revision 155051)
+++ trans-mem.c	(working copy)
@@ -832,10 +832,15 @@ tm_log_delete (void)
 static bool
 transaction_invariant_address_p (const_tree mem, basic_block region_entry_block)
 {
-  if (TREE_CODE (mem) == SSA_NAME)
-    return dominated_by_p (CDI_DOMINATORS,
-			   region_entry_block,
-			   gimple_bb (SSA_NAME_DEF_STMT (mem)));
+  if (TREE_CODE (mem) == INDIRECT_REF
+      && TREE_CODE (TREE_OPERAND (mem, 0)) == SSA_NAME)
+    {
+      basic_block def_bb;
+
+      def_bb = gimple_bb (SSA_NAME_DEF_STMT (TREE_OPERAND (mem, 0)));
+      return def_bb != region_entry_block
+	&& dominated_by_p (CDI_DOMINATORS, region_entry_block, def_bb);
+    }
 
   mem = strip_invariant_refs (mem);
   return mem && (CONSTANT_CLASS_P (mem) || decl_address_invariant_p (mem));
@@ -1145,20 +1150,28 @@ 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 non aliased new chunk
-   of memory local to the transaction (malloc, alloca, etc), which
-   therefore requires no instrumentation.
+/* Given an address X that is being dereferenced, return TRUE if we
+   can prove that the memory being dereferenced is a non aliased new
+   chunk of memory local to the transaction (malloc, alloca, etc),
+   which therefore requires no instrumentation.
+
+   ORIG_MEM is the original memory reference.
+
+   ORIG_STMT is the statement the memory reference is in.
 
    ENTRY_BLOCK is the entry block to the transaction containing the
    dereference of X.  */
 static bool
-transaction_local_new_memory_p (basic_block entry_block, tree x)
+transaction_local_new_memory_p (basic_block entry_block, tree x,
+				tree orig_mem, gimple orig_stmt)
 {
   gimple stmt = NULL;
   enum tree_code code;
   void **slot;
   tm_new_mem_map_t elt, *elt_p;
+  bool transaction_local_p = true;
+  bool retval = false;
+  tree val = x;
 
   if (!entry_block)
     return false;
@@ -1172,13 +1185,6 @@ transaction_local_new_memory_p (basic_bl
   elt_p = (tm_new_mem_map_t *) *slot;
   if (elt_p)
     return elt_p->local_new_memory_p;
-  else
-    {
-      elt_p = XNEW (tm_new_mem_map_t);
-      elt_p->val = x;
-      elt_p->local_new_memory_p = false;
-      *slot = elt_p;
-    }
 
   /* Search back through the DEF chain to find the original definition
      of this address.  */
@@ -1187,7 +1193,7 @@ transaction_local_new_memory_p (basic_bl
       if (ptr_deref_may_alias_global_p (x))
 	{
 	  /* Pointed to address escapes.  This is not thread-private.  */
-	  return false;
+	  goto new_memory_ret;
 	}
 
       stmt = SSA_NAME_DEF_STMT (x);
@@ -1196,8 +1202,9 @@ transaction_local_new_memory_p (basic_bl
 	 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 (transaction_local_p
+	  && !dominated_by_p (CDI_DOMINATORS, gimple_bb (stmt), entry_block))
+	transaction_local_p = false;
 
       if (is_gimple_assign (stmt))
 	{
@@ -1212,7 +1219,7 @@ transaction_local_new_memory_p (basic_bl
 	  else if (code == VIEW_CONVERT_EXPR || code == NOP_EXPR)
 	    x = gimple_assign_rhs1 (stmt);
 	  else
-	    return false;
+	    goto new_memory_ret;
 	}
       else
 	break;
@@ -1221,14 +1228,31 @@ transaction_local_new_memory_p (basic_bl
 
   if (stmt && is_gimple_call (stmt) && gimple_call_flags (stmt) & ECF_MALLOC)
     {
-      /* No logging to do.  For alloca, the stack pointer gets reset
-	 by the retry and we reallocate.  For malloc, a transaction
-	 restart frees the memory and we reallocate.  Similarly for
-	 user-defined malloc type routines, which should release the
-	 memory on a transaction restart.  */
-      return elt_p->local_new_memory_p = true;
+      retval = true;
+      if (transaction_local_p)
+	{
+	  /* No logging to do.  For alloca, the stack pointer gets
+	     reset by the retry and we reallocate.  For malloc, a
+	     transaction restart frees the memory and we reallocate.
+	     Similarly for user-defined malloc type routines, which
+	     should release the memory on a transaction restart.  */
+	}
+      else
+	{
+	  /* Thread-private chunk, use the log if requested.  */
+	  if (orig_stmt)
+	    tm_log_add (entry_block, orig_mem, orig_stmt);
+	  else
+	    return true;	/* Don't cache just yet.  */
+	}
     }
-  return false;
+
+ new_memory_ret:
+  elt_p = XNEW (tm_new_mem_map_t);
+  elt_p->val = val;
+  elt_p->local_new_memory_p = retval;
+  *slot = elt_p;
+  return retval;
 }
 
 /* Determine whether X has to be instrumented using a read
@@ -1250,7 +1274,11 @@ requires_barrier (basic_block entry_bloc
   switch (TREE_CODE (x))
     {
     case INDIRECT_REF:
-      if (transaction_local_new_memory_p (entry_block, TREE_OPERAND (x, 0)))
+      if (transaction_local_new_memory_p
+	  (entry_block, TREE_OPERAND (x, 0),
+	   /* ?? Should we pass `orig', or the INDIRECT_REF X.  ?? */
+	   orig,
+	   stmt))
 	return false;
       return true;
 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]