===================================================================
@@ -0,0 +1,65 @@
+// { dg-do compile }
+// { dg-options "-fgnu-tm -O2" }
+
+__attribute__((transaction_pure))
+void atomic_exchange_and_add()
+{
+ __asm__ __volatile__ ("");
+}
+
+template<class X> class sp_counted_impl_p
+{
+ public:
+ X * px_;
+
+ void weak_release()
+ {
+ atomic_exchange_and_add ();
+ }
+
+ __attribute__((transaction_safe))
+ void release()
+ {
+ weak_release();
+ }
+
+ sp_counted_impl_p( X * px ): px_( px )
+ {
+ }
+
+ __attribute__((transaction_safe))
+ virtual void dispose()
+ {
+ delete px_;
+ }
+};
+
+template<class Y> class shared_count
+{
+ private: sp_counted_impl_p<Y> * pi_;
+ public: shared_count(): pi_(0)
+ {
+ }
+ shared_count( Y * p )
+ {
+ pi_ = new sp_counted_impl_p<Y>( p );
+ }
+ ~shared_count()
+ {
+ pi_->release();
+ }
+};
+
+class Entity;
+
+class GradientInfo
+{
+ public:
+ GradientInfo();
+ shared_count<Entity> sources;
+};
+
+void get_grad()
+{
+ shared_count<GradientInfo>(new GradientInfo());
+}
===================================================================
@@ -540,6 +540,7 @@ tm_malloc_replacement (tree from)
#define DIAG_TM_OUTER 1
#define DIAG_TM_SAFE 2
#define DIAG_TM_RELAXED 4
+#define DIAG_TM_PURE 8
struct diagnose_tm
{
@@ -672,9 +673,6 @@ diagnose_tm_1 (gimple_stmt_iterator *gsi
break;
case GIMPLE_ASM:
- /* ??? We ought to come up with a way to add attributes to
- asm statements, and then add "transaction_safe" to it.
- Either that or get the language spec to resurrect __tm_waiver. */
if (d->block_flags & DIAG_TM_SAFE)
error_at (gimple_location (stmt),
"asm not allowed in atomic transaction");
@@ -682,7 +680,14 @@ diagnose_tm_1 (gimple_stmt_iterator *gsi
error_at (gimple_location (stmt),
"asm not allowed in %<transaction_safe%> function");
else
- d->saw_unsafe = true;
+ {
+ /* Mark the ASM as allowed if the function it appears in is
+ marked as TM pure. */
+ if (d->func_flags & DIAG_TM_PURE)
+ gimple_asm_set_tm_safe (stmt, true);
+ else
+ d->saw_unsafe = true;
+ }
break;
case GIMPLE_TRANSACTION:
@@ -758,6 +763,8 @@ diagnose_tm_blocks (void)
d.func_flags = DIAG_TM_OUTER | DIAG_TM_SAFE;
else if (is_tm_safe (current_function_decl))
d.func_flags = DIAG_TM_SAFE;
+ else if (is_tm_pure (current_function_decl))
+ d.func_flags = DIAG_TM_PURE;
d.summary_flags = d.func_flags;
memset (&wi, 0, sizeof (wi));
@@ -2322,7 +2329,9 @@ expand_block_tm (struct tm_region *regio
break;
case GIMPLE_ASM:
- gcc_unreachable ();
+ if (!gimple_asm_tm_safe (stmt))
+ gcc_unreachable ();
+ break;
default:
break;
===================================================================
@@ -101,6 +101,7 @@ enum gimple_rhs_class
enum gf_mask {
GF_ASM_INPUT = 1 << 0,
GF_ASM_VOLATILE = 1 << 1,
+ GF_ASM_TM_SAFE = 1 << 2,
GF_CALL_CANNOT_INLINE = 1 << 0,
GF_CALL_FROM_THUNK = 1 << 1,
GF_CALL_RETURN_SLOT_OPT = 1 << 2,
@@ -2901,6 +2902,30 @@ gimple_asm_input_p (const_gimple gs)
}
+/* If TM_SAFE_P is true, mark asm GS as a TM_ASM_TM_SAFE.
+ This is set for GIMPLE_ASM's that appear in a TM pure function. */
+
+static inline void
+gimple_asm_set_tm_safe (gimple gs, bool tm_safe_p)
+{
+ GIMPLE_CHECK (gs, GIMPLE_ASM);
+ if (tm_safe_p)
+ gs->gsbase.subcode |= GF_ASM_TM_SAFE;
+ else
+ gs->gsbase.subcode &= ~GF_ASM_TM_SAFE;
+}
+
+
+/* Return true if asm GS is a TM_ASM_TM_SAFE. */
+
+static inline bool
+gimple_asm_tm_safe (const_gimple gs)
+{
+ GIMPLE_CHECK (gs, GIMPLE_ASM);
+ return (gs->gsbase.subcode & GF_ASM_TM_SAFE) != 0;
+}
+
+
/* Return the types handled by GIMPLE_CATCH statement GS. */
static inline tree