Hello,

Attached the cpp example.

While I was trying to understand the problem (segfault), I found this:
In special_function_p function (calls.c), ECF_TM_OPS flag is returned for all TM builtin call except BUILT_IN_TM_START.
Question: is it really intentional or missing?

Moreover since BUILT_IN_TM_START is doing a setjmp, I suppose it should add also the flag ECS_RETURNS_TWICE. If I add this, the generated code is a bit different (more things happen in the stack, which I suppose right).

BUILT_IN_TM_ABORT is kind of longjmp, it should then add ECF_NORETURN, right?.

Otherwise I have a strange bug with the attached cpp file when _ITM_commitTransaction is the last call of a function with optimization level>=2. This call is optimized as a tail call thus the epilogue is before the jmp. But in this specific case, if the _ITM_commitTransaction aborts and roll backs, it seems it creates a problem (corrupted stack) but I didn't figure out the real reason. To avoid this problem I have added ECF_RETURNS_TWICE for the transaction commit which avoid this tail call optimization but I am sure this is not the way to fix this.

Attached the patch for these problems.

Thanks for any help.

Patrick Marlier.
#include <stdlib.h>

namespace bench
{
    class LLNode
    {
    	LLNode* next;
    	int data;

    public:
        __attribute__((transaction_safe)) 
	LLNode(int val, LLNode* m_next)
        {
		data = val;
		next = m_next;
        }
        __attribute__((transaction_safe))
	  ~LLNode(){}
        __attribute__((transaction_safe))
	  int get_val()  {return data;}
        __attribute__((transaction_safe))
	  LLNode* get_next()  {return next;}
	__attribute__((transaction_safe))
	  void set_val(int val) {data = val;}
        __attribute__((transaction_safe))
	  void set_next(LLNode* n)  {next = n;}
        __attribute__((transaction_safe))
	  void *operator new(size_t size);
    };

    class LinkedList 
    {
      LLNode* head;
    public:
        LinkedList();
        void insert(int val);
    };
}

using bench::LinkedList;
using bench::LLNode;


__attribute__((transaction_safe))
void* LLNode::operator new(size_t size)
{
  return malloc(size);
}

LinkedList::LinkedList() : head(new LLNode(-1, NULL)) { }

void LinkedList::insert(int val)
{
  __transaction [[atomic]] {
    LLNode* prev = head;
    LLNode* curr = head->get_next();

    while (curr != NULL) {
      if (curr->get_val() >= val)
	break;
      prev = curr;
      curr = prev->get_next();
    }

    if (!curr || (curr->get_val() > val)){
      LLNode* tmp = new LLNode(val,curr);
      prev->set_next(tmp);
    }
  }  

//  asm volatile("nop");
}
 

Index: calls.c
===================================================================
--- calls.c	(revision 168989)
+++ calls.c	(working copy)
@@ -473,9 +473,17 @@
     {
       switch (DECL_FUNCTION_CODE (fndecl))
 	{
+
+	case BUILT_IN_TM_START:
+	  flags |= ECF_RETURNS_TWICE | ECF_TM_OPS;
+	  break;
+	case BUILT_IN_TM_ABORT:
+	  flags |= ECF_NORETURN | ECF_TM_OPS;
+	  break;
 	case BUILT_IN_TM_COMMIT:
 	case BUILT_IN_TM_COMMIT_EH:
-	case BUILT_IN_TM_ABORT:
+	  flags |= ECF_RETURNS_TWICE | ECF_TM_OPS;
+	  break;
 	case BUILT_IN_TM_IRREVOCABLE:
 	case BUILT_IN_TM_GETTMCLONE_IRR:
 	case BUILT_IN_TM_MEMCPY:

Reply via email to