Without this patch, transaction commits of different transactions get potentially merged, which breaks how we handle transactional regions. Patch provided by Richard Henderson.
OK for trunk?
commit 48d236d4c40fdb7111308fe88844068603e235eb Author: Torvald Riegel <trie...@redhat.com> Date: Thu Dec 8 11:57:05 2011 +0100 Prevent sharing of commit calls among transactions. gcc/ * tree-ssa-tail-merge.c (gimple_equal_p): Don't treat transaction commits as equal. gcc/testsuite/ * c-c++-common/tm/20111206.c: New test. diff --git a/gcc/testsuite/c-c++-common/tm/20111206.c b/gcc/testsuite/c-c++-common/tm/20111206.c new file mode 100644 index 0000000..74a5519 --- /dev/null +++ b/gcc/testsuite/c-c++-common/tm/20111206.c @@ -0,0 +1,53 @@ +/* { dg-do compile } */ +/* { dg-options "-fgnu-tm -O2" } */ +/* This test case triggered block sharing between the two transactions. */ + +void func1 (void) __attribute__ ((transaction_callable, used)); +long func2 (void) __attribute__ ((transaction_callable, used)); +unsigned long rand (void); + +void client_run (void) +{ + long types[100]; + long i; + + for (i = 0; i < 100; i++) + { + long action = rand (); + + switch (action) + { + case 0: + { + __transaction_relaxed + { + long bill = func2 (); + if (bill >= 0) + { + func1 (); + } + } + break; + } + + case 1: + { + long n; + __transaction_relaxed + { + for (n = 0; n < 100; n++) + { + long t = types[n]; + switch (t) + { + case 0: + func1 (); + break; + } + } + } + break; + } + } + } +} diff --git a/gcc/tree-ssa-tail-merge.c b/gcc/tree-ssa-tail-merge.c index a501b07..7452266 100644 --- a/gcc/tree-ssa-tail-merge.c +++ b/gcc/tree-ssa-tail-merge.c @@ -1051,6 +1051,14 @@ gimple_equal_p (same_succ same_succ, gimple s1, gimple s2) if (!gimple_call_same_target_p (s1, s2)) return false; + /* Eventually, we'll significantly complicate the CFG by adding + back edges to properly model the effects of transaction restart. + For the bulk of optimization this does not matter, but what we + cannot recover from is tail merging blocks between two separate + transactions. Avoid that by making commit not match. */ + if (gimple_call_builtin_p (s1, BUILT_IN_TM_COMMIT)) + return false; + equal = true; for (i = 0; i < gimple_call_num_args (s1); ++i) {