This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[trans-mem] implement transaction expressions for C
- From: Aldy Hernandez <aldyh at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org, rth at redhat dot com
- Date: Wed, 12 May 2010 17:06:39 -0400
- Subject: [trans-mem] implement transaction expressions for C
Howdy.
The patch below implements transaction expressions as per the language
specs. For example:
x = __transaction (york);
On x86-64, we'd generate something like this.
call _ITM_beginTransaction
movl $york, %edi
call _ITM_RU4
movl %eax, %ebx
call _ITM_commitTransaction
movl %ebx, x(%rip)
The read of [york] is evaluated inside a transaction, and when we're
sure we've read, then we copy the value into [x].
I would've liked to reimplement c_parser_transaction() to handle
statements and expressions, but we have to parse through the TM
attributes before we know it's either an expression or a statement. All
in all, it seemed like it was cleaner to duplicate some of the existing
code for transaction statements.
Tested on x86-64 Linux. OK for branch?
p.s. I'll work on the C++ parser next.
* tree.h: Add documentation for TRANSACTION_EXPR_OUTER AND
TRANSACTION_EXPR_RELAXED.
* gimplify.c (voidify_wrapper_expr): Handle TRANSACTION_EXPR.
(gimplify_transaction): Call and handle voidify_wrapper_expr.
* tree.def (TRANSACTION_EXPR): Change into an expression.
* c-parser.c (c_parser_unary_expression): Handle RID_TRANSACTION.
(c_parser_transaction_expression): New.
Index: tree.h
===================================================================
--- tree.h (revision 159008)
+++ tree.h (working copy)
@@ -458,6 +458,9 @@ struct GTY(()) tree_common {
CALL_CANNOT_INLINE_P in
CALL_EXPR
+ TRANSACTION_EXPR_OUTER in
+ TRANSACTION_EXPR
+
public_flag:
TREE_OVERFLOW in
@@ -485,6 +488,9 @@ struct GTY(()) tree_common {
OMP_CLAUSE_PRIVATE_DEBUG in
OMP_CLAUSE_PRIVATE
+ TRANSACTION_EXPR_RELAXED in
+ TRANSACTION_EXPR
+
private_flag:
TREE_PRIVATE in
Index: testsuite/c-c++-common/tm/trxn-expr.c
===================================================================
--- testsuite/c-c++-common/tm/trxn-expr.c (revision 0)
+++ testsuite/c-c++-common/tm/trxn-expr.c (revision 0)
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-fgnu-tm -fdump-tree-tmmark" } */
+
+int y, x, york;
+
+void foobar(void)
+{
+ x = y + __transaction (york);
+}
+
+/* { dg-final { scan-tree-dump-times "_ITM_RU.*york" 1 "tmmark" } } */
+/* { dg-final { scan-tree-dump-times "_ITM_RU" 1 "tmmark" } } */
+/* { dg-final { cleanup-tree-dump "tmmark" } } */
Index: gimplify.c
===================================================================
--- gimplify.c (revision 158830)
+++ gimplify.c (working copy)
@@ -1024,6 +1024,12 @@ voidify_wrapper_expr (tree wrapper, tree
}
break;
+ case TRANSACTION_EXPR:
+ TREE_SIDE_EFFECTS (*p) = 1;
+ TREE_TYPE (*p) = void_type_node;
+ p = &TRANSACTION_EXPR_BODY (*p);
+ break;
+
default:
goto out;
}
@@ -6373,19 +6379,20 @@ gimplify_omp_atomic (tree *expr_p, gimpl
return GS_ALL_DONE;
}
-/* Gimplify the contents of a TRANSACTION_EXPR statement. This involves
- gimplification of the body, and adding some EH bits. */
+/* Gimplify a TRANSACTION_EXPR. This involves gimplification of the
+ body, and adding some EH bits. */
static enum gimplify_status
gimplify_transaction (tree *expr_p, gimple_seq *pre_p)
{
- tree expr = *expr_p;
+ tree expr = *expr_p, temp;
gimple g;
gimple_seq body = NULL;
struct gimplify_ctx gctx;
int subcode = 0;
push_gimplify_context (&gctx);
+ temp = voidify_wrapper_expr (*expr_p, NULL);
g = gimplify_and_return_first (TRANSACTION_EXPR_BODY (expr), &body);
if (g && gimple_code (g) == GIMPLE_BIND)
@@ -6401,8 +6408,14 @@ gimplify_transaction (tree *expr_p, gimp
gimple_transaction_set_subcode (g, subcode);
gimplify_seq_add_stmt (pre_p, g);
- *expr_p = NULL_TREE;
+ if (temp)
+ {
+ *expr_p = temp;
+ return GS_OK;
+ }
+
+ *expr_p = NULL_TREE;
return GS_ALL_DONE;
}
Index: tree.def
===================================================================
--- tree.def (revision 158824)
+++ tree.def (working copy)
@@ -1047,8 +1047,8 @@ DEFTREECODE (OMP_ATOMIC, "omp_atomic", t
DEFTREECODE (OMP_CLAUSE, "omp_clause", tcc_exceptional, 0)
/* TRANSACTION_EXPR tree code.
- Operand 0: BODY: contains body of the transaction.*/
-DEFTREECODE (TRANSACTION_EXPR, "transaction_expr", tcc_statement, 1)
+ Operand 0: BODY: contains body of the transaction. */
+DEFTREECODE (TRANSACTION_EXPR, "transaction_expr", tcc_expression, 1)
/* Reduction operations.
Operations that take a vector of elements and "reduce" it to a scalar
Index: c-parser.c
===================================================================
--- c-parser.c (revision 158824)
+++ c-parser.c (working copy)
@@ -941,6 +941,7 @@ static struct c_expr c_parser_postfix_ex
location_t loc,
struct c_expr);
static tree c_parser_transaction (c_parser *);
+static struct c_expr c_parser_transaction_expression (c_parser *);
static tree c_parser_transaction_cancel (c_parser *);
static struct c_expr c_parser_expression (c_parser *);
static struct c_expr c_parser_expression_conv (c_parser *);
@@ -5106,6 +5107,11 @@ c_parser_cast_expression (c_parser *pars
unary-operator: one of
__extension__ __real__ __imag__
+ Transactional Memory:
+
+ unary-expression:
+ transaction-expression
+
In addition, the GNU syntax treats ++ and -- as unary operators, so
they may be applied to cast expressions with errors for non-lvalues
given later. */
@@ -5213,6 +5219,8 @@ c_parser_unary_expression (c_parser *par
op = c_parser_cast_expression (parser, NULL);
op = default_function_array_conversion (exp_loc, op);
return parser_build_unary_op (op_loc, IMAGPART_EXPR, op);
+ case RID_TRANSACTION:
+ return c_parser_transaction_expression (parser);
default:
return c_parser_postfix_expression (parser);
}
@@ -8821,6 +8829,62 @@ c_parser_transaction (c_parser *parser)
return stmt;
}
+/* Parse a __transaction expression (GCC Extension).
+
+ transaction-expression:
+ __transaction attributes[opt] ( expression )
+
+ Note that the only valid attributes are: "atomic" and "relaxed".
+*/
+
+static struct c_expr
+c_parser_transaction_expression (c_parser *parser)
+{
+ struct c_expr ret;
+ unsigned int old_in = parser->in_transaction;
+ unsigned int this_in = 1;
+ location_t loc = c_parser_peek_token (parser)->location;
+ tree attrs;
+
+ gcc_assert (c_parser_next_token_is_keyword (parser, RID_TRANSACTION));
+ c_parser_consume_token (parser);
+
+ attrs = c_parser_transaction_attributes (parser);
+ if (attrs)
+ {
+ this_in |= parse_tm_stmt_attr (attrs, (TM_STMT_ATTR_ATOMIC
+ | TM_STMT_ATTR_RELAXED));
+ /* The [[ atomic ]] attribute is the same as no attribute. */
+ this_in &= ~TM_STMT_ATTR_ATOMIC;
+ }
+
+ parser->in_transaction = this_in;
+ if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+ {
+ tree expr = c_parser_expression (parser).value;
+ ret.original_type = TREE_TYPE (expr);
+ ret.value = build1 (TRANSACTION_EXPR, ret.original_type, expr);
+ if (this_in & TM_STMT_ATTR_RELAXED)
+ TRANSACTION_EXPR_RELAXED (ret.value) = 1;
+ SET_EXPR_LOCATION (ret.value, loc);
+ ret.original_code = TRANSACTION_EXPR;
+ }
+ else
+ {
+ c_parser_error (parser, "expected %<(%>");
+ ret.value = error_mark_node;
+ ret.original_code = ERROR_MARK;
+ ret.original_type = NULL;
+ }
+ parser->in_transaction = old_in;
+
+ if (!flag_tm)
+ error_at (loc, "%<__transaction%> without "
+ "transactional memory support enabled");
+
+ return ret;
+}
+
/* Parse a __transaction_cancel statement (GCC Extension).
transaction-cancel-statement: