===================================================================
@@ -5390,12 +5390,16 @@ extern tree build_personality_function (
extern tree build_tm_abort_call (location_t, bool);
extern bool is_tm_safe (tree);
extern bool is_tm_pure (tree);
-extern bool is_tm_callable (tree);
-extern bool is_tm_irrevocable (tree);
extern bool is_tm_may_cancel_outer (tree);
extern void record_tm_replacement (tree, tree);
extern void tm_malloc_replacement (tree);
+static inline bool
+is_tm_safe_or_pure (tree x)
+{
+ return is_tm_safe (x) || is_tm_pure (x);
+}
+
/* In tree-inline.c. */
void init_inline_once (void);
===================================================================
@@ -12,7 +12,7 @@ class HashTree
{
public:
__attribute__((transaction_safe))
- void *operator new(long unsigned int);
+ void *operator new(__SIZE_TYPE__);
__attribute__((transaction_safe))
int add_element();
private:
===================================================================
@@ -14,7 +14,7 @@ class HashTree
{
public:
__attribute__((transaction_safe))
- void *operator new(long unsigned int);
+ void *operator new(__SIZE_TYPE__);
__attribute__((transaction_safe))
int add_element();
private:
===================================================================
@@ -0,0 +1,30 @@
+// { dg-do compile }
+// { dg-options "-fgnu-tm -O1" }
+
+__attribute__((transaction_pure))
+inline int atomic_exchange_and_add(int dv )
+{
+ int r;
+ __asm__ ("" : "=r"(r));
+ return r;
+}
+
+class sp_counted_base
+{
+public:
+ __attribute__((transaction_safe))
+ void release()
+ {
+ if( atomic_exchange_and_add(-1 ) == 1 )
+ {
+ }
+ }
+};
+
+sp_counted_base *base;
+
+void here(){
+ __transaction[[atomic]] {
+ base->release();
+ }
+}
===================================================================
@@ -0,0 +1,30 @@
+// { dg-do compile }
+// { dg-options "-fgnu-tm -O0" }
+
+__attribute__((transaction_pure))
+inline int atomic_exchange_and_add(int dv )
+{
+ int r;
+ __asm__ ("" : "=r"(r));
+ return r;
+}
+
+class sp_counted_base
+{
+public:
+ __attribute__((transaction_safe))
+ void release()
+ {
+ if( atomic_exchange_and_add(-1 ) == 1 )
+ {
+ }
+ }
+};
+
+sp_counted_base *base;
+
+void here(){
+ __transaction[[atomic]] {
+ base->release();
+ }
+}
===================================================================
@@ -0,0 +1,69 @@
+// { dg-do compile }
+// { dg-options "-fgnu-tm -O0" }
+
+__attribute__((transaction_safe))
+void* operator new (__SIZE_TYPE__);
+
+__attribute__((transaction_pure))
+inline int atomic_exchange_and_add( int * pw, int dv )
+{
+ int r;
+ __asm__ ("" : "=r"(r));
+ return r;
+}
+
+class sp_counted_base
+{
+protected:
+ int use_count_; // #shared
+public:
+ __attribute__((transaction_safe))
+ virtual void dispose() = 0; // nothrow
+
+ __attribute__((transaction_safe))
+ void release() // nothrow
+ {
+ if( atomic_exchange_and_add( &use_count_, -1 ) == 1 )
+ {
+ dispose();
+ }
+ }
+};
+
+class sp_counted_base_x86 : public sp_counted_base
+{
+public:
+ void dispose()
+ {
+ release();
+ }
+};
+
+class shared_count
+{
+private:
+ sp_counted_base * pi_;
+public:
+ int j;
+ __attribute__((transaction_safe))
+ shared_count(): pi_(new sp_counted_base_x86()), j(0)
+ {
+ }
+ __attribute__((transaction_safe))
+ ~shared_count() // nothrow
+ {
+ if( pi_ != 0 ) pi_->release();
+ }
+};
+
+volatile int i = 1;
+shared_count * c;
+int main()
+{
+ if ( i == 0) {
+ __transaction [[atomic]] {
+ shared_count sc;
+ }
+ }
+ return 0;
+}
===================================================================
@@ -0,0 +1,69 @@
+// { dg-do compile }
+// { dg-options "-fgnu-tm -O1" }
+
+__attribute__((transaction_safe))
+void* operator new (__SIZE_TYPE__);
+
+__attribute__((transaction_pure))
+inline int atomic_exchange_and_add( int * pw, int dv )
+{
+ int r;
+ __asm__ ("" : "=r"(r));
+ return r;
+}
+
+class sp_counted_base
+{
+protected:
+ int use_count_; // #shared
+public:
+ __attribute__((transaction_safe))
+ virtual void dispose() = 0; // nothrow
+
+ __attribute__((transaction_safe))
+ void release() // nothrow
+ {
+ if( atomic_exchange_and_add( &use_count_, -1 ) == 1 )
+ {
+ dispose();
+ }
+ }
+};
+
+class sp_counted_base_x86 : public sp_counted_base
+{
+public:
+ void dispose()
+ {
+ release();
+ }
+};
+
+class shared_count
+{
+private:
+ sp_counted_base * pi_;
+public:
+ int j;
+ __attribute__((transaction_safe))
+ shared_count(): pi_(new sp_counted_base_x86()), j(0)
+ {
+ }
+ __attribute__((transaction_safe))
+ ~shared_count() // nothrow
+ {
+ if( pi_ != 0 ) pi_->release();
+ }
+};
+
+volatile int i = 1;
+shared_count * c;
+int main()
+{
+ if ( i == 0) {
+ __transaction [[atomic]] {
+ shared_count sc;
+ }
+ }
+ return 0;
+}
===================================================================
@@ -184,7 +184,7 @@ is_tm_pure (tree x)
/* Return true if X has been marked TM_IRREVOCABLE. */
-bool
+static bool
is_tm_irrevocable (tree x)
{
tree attrs = get_attrs_for (x);
@@ -247,7 +247,7 @@ is_tm_pure_call (gimple call)
/* Return true if X has been marked TM_CALLABLE. */
-bool
+static bool
is_tm_callable (tree x)
{
tree attrs = get_attrs_for (x);
@@ -587,7 +587,7 @@ diagnose_tm_1 (gimple_stmt_iterator *gsi
replacement = NULL_TREE;
}
- if (is_tm_safe (fn) || is_tm_pure (fn))
+ if (is_tm_safe_or_pure (fn))
is_safe = true;
else if (is_tm_callable (fn) || is_tm_irrevocable (fn))
{
@@ -736,7 +736,7 @@ diagnose_tm_blocks (void)
/* If we saw something other than a call that makes this function
unsafe, remember it so that the IPA pass only needs to scan calls. */
- if (d.saw_unsafe && !is_tm_safe (current_function_decl))
+ if (d.saw_unsafe && !is_tm_safe_or_pure (current_function_decl))
cgraph_local_info (current_function_decl)->tm_may_enter_irr = 1;
return 0;
@@ -3495,8 +3495,7 @@ ipa_tm_note_irrevocable (struct cgraph_n
continue;
/* Even if we think we can go irrevocable, believe the user
above all. */
- if (is_tm_safe (e->caller->decl)
- || is_tm_pure (e->caller->decl))
+ if (is_tm_safe_or_pure (e->caller->decl))
continue;
if (gimple_call_in_transaction_p (e->call_stmt))
d->want_irr_scan_normal = true;
@@ -3792,9 +3791,9 @@ ipa_tm_mayenterirr_function (struct cgra
tree decl = node->decl;
/* Filter out all functions that are marked. */
- if (is_tm_safe (decl))
+ if (is_tm_safe_or_pure (decl))
return false;
- if (is_tm_pure (decl) || (flags_from_decl_or_type (decl) & ECF_CONST) != 0)
+ if ((flags_from_decl_or_type (decl) & ECF_CONST) != 0)
return false;
if (is_tm_irrevocable (decl))
return true;
@@ -4443,8 +4442,7 @@ ipa_tm_execute (void)
if (is_tm_irrevocable (node->decl))
ipa_tm_note_irrevocable (node, &worklist);
else if (a <= AVAIL_NOT_AVAILABLE
- && !is_tm_safe (node->decl)
- && !is_tm_pure (node->decl))
+ && !is_tm_safe_or_pure (node->decl))
ipa_tm_note_irrevocable (node, &worklist);
else if (a >= AVAIL_OVERWRITABLE)
{
@@ -4512,8 +4510,7 @@ ipa_tm_execute (void)
node->local.tm_may_enter_irr = true;
for (e = node->callers; e ; e = e->next_caller)
- if (!is_tm_safe (e->caller->decl)
- && !is_tm_pure (e->caller->decl)
+ if (!is_tm_safe_or_pure (e->caller->decl)
&& !e->caller->local.tm_may_enter_irr)
maybe_push_queue (e->caller, &worklist, &d->in_worklist);
}
===================================================================
@@ -72,6 +72,15 @@ static void set_block_abstract_flags (tr
bool
function_attribute_inlinable_p (const_tree fndecl)
{
+ /* TM pure functions should not get inlined if the outer function is
+ a TM safe function.
+
+ FIXME: In the meantime, prevent pure functions from being
+ inlined. */
+ if (flag_tm
+ && is_tm_pure (fndecl))
+ return false;
+
if (targetm.attribute_table)
{
const_tree a;