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: