diff --git a/gcc/testsuite/gcc.dg/tm/pr56572.c b/gcc/testsuite/gcc.dg/tm/pr56572.c
new file mode 100644
index 0000000..0b43569
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tm/pr56572.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-fgnu-tm -fdump-ipa-tmipa -O2" } */
+
+/* Test that nested unnecessary transactions are properly folded.  */
+
+int a;
+
+static inline void f() {
+  __transaction_atomic {
+    ++a;
+  }
+}
+
+void g() {
+  __transaction_atomic {
+    f();
+  }
+}
+
+/* { dg-final { scan-ipa-dump-times "__transaction_atomic" 1 "tmipa" } } */
+/* { dg-final { cleanup-ipa-dump "tmipa" } } */
diff --git a/gcc/trans-mem.c b/gcc/trans-mem.c
index ba34488..5e9e2ab 100644
--- a/gcc/trans-mem.c
+++ b/gcc/trans-mem.c
@@ -2956,6 +2956,120 @@ propagate_tm_flags_out (struct tm_region *region)
   propagate_tm_flags_out (region->next);
 }
 
+/* Callback for expand_regions.
+
+   Given a transaction in REGION, remove the GIMPLE_TRANSACTION and
+   its corresponding BUILT_IN_TM_COMMIT*.  The tm_region itself is
+   removed by the caller.  */
+
+static void *
+remove_transaction (struct tm_region *region, void *data ATTRIBUTE_UNUSED)
+{
+  // Remove the transaction.
+  if (dump_file)
+    fprintf (dump_file, "Folding unnecessary inner transaction in BB%d\n",
+	     gimple_bb (region->transaction_stmt)->index);
+  gimple_stmt_iterator gsi = gsi_for_stmt (region->transaction_stmt);
+  gsi_remove (&gsi, true);
+
+  // Find the corresponding BUILT_IN_TM_COMMIT* and remove it as well.
+  if (region->exit_blocks)
+    {
+      bitmap_iterator bi;
+      unsigned i;
+
+      EXECUTE_IF_SET_IN_BITMAP (region->exit_blocks, 0, i, bi)
+	{
+	  gimple_stmt_iterator gsi
+	    = gsi_last_bb (BASIC_BLOCK_FOR_FN (cfun, i));
+	  gimple stmt = gsi_stmt (gsi);
+	  if (gimple_code (stmt) != GIMPLE_CALL)
+	    continue;
+	  tree fndecl = gimple_call_fndecl (stmt);
+	  if (fndecl
+	      && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
+	      && (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_TM_COMMIT
+		  || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_TM_COMMIT_EH))
+	    {
+	      tree vdef = gimple_vdef (stmt);
+	      tree vuse = gimple_vuse (stmt);
+	      if (vdef && vuse)
+		replace_uses_by (vdef, vuse);
+	      gsi_remove (&gsi, true);
+	    }
+	}
+    }
+  return NULL;
+}
+
+/* A helper function for flatten_nested_transactions.
+
+   Go through all the transactional regions, starting at TOP, and
+   remove any nested transactions that are redundant, removing both
+   the start/end of a transaction as well as removing the region
+   from the tm_region list.
+
+   OUTER is TOP's outer transaction and is set to null if TOP is the
+   outermost transaction.
+
+   Returns FALSE if the region passed in TOP should be removed from
+   the list of regions by the caller.  */
+static bool
+flatten_nested_transactions_1 (struct tm_region *top, struct tm_region *outer)
+{
+  /* We could fold this traversal into ipa_tm_scan_calls_transaction,
+     and only traverse all_tm_regions once, but the nested
+     transactions we handle below would complicate things.  Besides,
+     there aren't liable to be many TM regions in a function to make
+     this extra iteration so unprofitable.
+
+     ?? We could even only call flatten_nested_transactions from
+     within ipa_tm_scan_calls_transaction only if we have any inner
+     transactions.  Hmmm, probably not worth it.  */
+  struct tm_region *prev = NULL;
+  for (struct tm_region *region = top; region; region = region->next)
+    {
+      if (region->inner
+	  && !flatten_nested_transactions_1 (region->inner, region))
+	region->inner = NULL;
+
+      /* An inner transactions which has no explicit aborts can be
+	 folded into its outer transaction.  */
+      unsigned int sub = gimple_transaction_subcode (region->transaction_stmt);
+      if (outer && !(sub & GTMA_HAVE_ABORT))
+	{
+	  expand_regions (region, remove_transaction, NULL, false);
+
+	  /* Remove region from the list if its anything but the first
+	     item, otherwise make the caller remove the first
+	     item.  */
+	  if (prev == NULL)
+	    return false;
+	  else
+	    prev->next = region->next;
+	}
+      prev = region;
+    }
+  return true;
+}
+
+/* Go through all the transactional regions and remove any nested
+   transactions that are redundant.  This is done by removing the
+   GIMPLE_TRANSACTION + BUILT_IN_TM_COMMIT* pairs and by removing the
+   transaction region from the all_tm_regions list.
+
+   Note: We already did this in the tmlower pass (lower_transaction),
+   but inlining may have added more nested transactions that are now
+   candidates for removal.  */
+
+static void
+flatten_nested_transactions ()
+{
+  if (!flatten_nested_transactions_1 (all_tm_regions, NULL))
+    all_tm_regions = NULL;
+}
+
+
 /* Entry point to the MARK phase of TM expansion.  Here we replace
    transactional memory statements with calls to builtins, and function
    calls with their transactional clones (if available).  But we don't
@@ -5358,6 +5472,8 @@ ipa_tm_execute (void)
 	  {
 	    d = get_cg_data (&node, true);
 
+	    flatten_nested_transactions ();
+
 	    /* Scan for calls that are in each transaction, and
 	       generate the uninstrumented code path.  */
 	    ipa_tm_scan_calls_transaction (d, &tm_callees);
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index 96a4805..6c6ef41 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -3972,7 +3972,7 @@ init_inline_once (void)
   eni_size_weights.target_builtin_call_cost = 1;
   eni_size_weights.div_mod_cost = 1;
   eni_size_weights.omp_cost = 40;
-  eni_size_weights.tm_cost = 10;
+  eni_size_weights.tm_cost = 2;
   eni_size_weights.time_based = false;
   eni_size_weights.return_cost = 1;
 
