Hi! This patch adds support for OpenMP 3.1 atomics to C++ FE. Tested on x86_64-linux, committed to gomp-3_1-branch.
2011-04-27 Jakub Jelinek <ja...@redhat.com> * parser.c (cp_parser_omp_atomic): Handle parsing OpenMP 3.1 atomics. Adjust finish_omp_atomic caller. * cp-tree.h (finish_omp_atomic): Adjust prototype. * semantics.c (finish_omp_atomic): Add OPCODE, V and LHS1 arguments. Handle OpenMP 3.1 atomics. * pt.c (tsubst_expr) <case OMP_ATOMIC>: Handle OpenMP 3.1 atomics. * testsuite/libgomp.c++/atomic-2.C: New test. * testsuite/libgomp.c++/atomic-3.C: New test. * testsuite/libgomp.c++/atomic-4.C: New test. * testsuite/libgomp.c++/atomic-5.C: New test. --- gcc/cp/parser.c.jj 2011-03-03 20:00:38.000000000 +0100 +++ gcc/cp/parser.c 2011-04-26 18:55:38.000000000 +0200 @@ -24041,34 +24041,132 @@ cp_parser_omp_structured_block (cp_parse binop: +, *, -, /, &, ^, |, <<, >> - where x is an lvalue expression with scalar type. */ + where x is an lvalue expression with scalar type. + + OpenMP 3.1: + # pragma omp atomic read new-line + read-stmt + + # pragma omp atomic write new-line + write-stmt + + # pragma omp atomic update new-line + expression-stmt + + # pragma omp atomic capture new-line + capture-stmt + + # pragma omp atomic capture new-line + capture-block + + read-stmt: + v = x + write-stmt: + x = expr + capture-stmt: + v = x binop= expr | v = x++ | v = ++x | v = x-- | v = --x + capture-block: + { v = x; x binop= expr; } | { x binop= expr; v = x; } + + where x and v are lvalue expressions with scalar type. */ static void cp_parser_omp_atomic (cp_parser *parser, cp_token *pragma_tok) { - tree lhs, rhs; - enum tree_code code; + tree lhs = NULL_TREE, rhs = NULL_TREE, v = NULL_TREE, lhs1 = NULL_TREE; + tree orig_lhs; + enum tree_code code = OMP_ATOMIC, opcode = NOP_EXPR; + bool structured_block = false; + + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + const char *p = IDENTIFIER_POINTER (id); + if (!strcmp (p, "read")) + code = OMP_ATOMIC_READ; + else if (!strcmp (p, "write")) + code = NOP_EXPR; + else if (!strcmp (p, "update")) + code = OMP_ATOMIC; + else if (!strcmp (p, "capture")) + code = OMP_ATOMIC_CAPTURE_NEW; + else + p = NULL; + if (p) + cp_lexer_consume_token (parser->lexer); + } cp_parser_require_pragma_eol (parser, pragma_tok); + switch (code) + { + case OMP_ATOMIC_READ: + case NOP_EXPR: /* atomic write */ + v = cp_parser_unary_expression (parser, /*address_p=*/false, + /*cast_p=*/false, NULL); + if (v == error_mark_node) + goto saw_error; + if (!cp_parser_require (parser, CPP_EQ, RT_EQ)) + goto saw_error; + lhs = cp_parser_unary_expression (parser, /*address_p=*/false, + /*cast_p=*/false, NULL); + if (lhs == error_mark_node) + goto saw_error; + if (code == NOP_EXPR) + { + /* atomic write is represented by OMP_ATOMIC with NOP_EXPR + opcode. */ + code = OMP_ATOMIC; + rhs = lhs; + lhs = v; + v = NULL_TREE; + } + goto done; + case OMP_ATOMIC_CAPTURE_NEW: + if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) + { + cp_lexer_consume_token (parser->lexer); + structured_block = true; + } + else + { + v = cp_parser_unary_expression (parser, /*address_p=*/false, + /*cast_p=*/false, NULL); + if (v == error_mark_node) + goto saw_error; + if (!cp_parser_require (parser, CPP_EQ, RT_EQ)) + goto saw_error; + } + default: + break; + } + +restart: lhs = cp_parser_unary_expression (parser, /*address_p=*/false, /*cast_p=*/false, NULL); + orig_lhs = lhs; switch (TREE_CODE (lhs)) { case ERROR_MARK: goto saw_error; - case PREINCREMENT_EXPR: case POSTINCREMENT_EXPR: + if (code == OMP_ATOMIC_CAPTURE_NEW) + code = OMP_ATOMIC_CAPTURE_OLD; + /* FALLTHROUGH */ + case PREINCREMENT_EXPR: lhs = TREE_OPERAND (lhs, 0); - code = PLUS_EXPR; + opcode = PLUS_EXPR; rhs = integer_one_node; break; - case PREDECREMENT_EXPR: case POSTDECREMENT_EXPR: + if (code == OMP_ATOMIC_CAPTURE_NEW) + code = OMP_ATOMIC_CAPTURE_OLD; + /* FALLTHROUGH */ + case PREDECREMENT_EXPR: lhs = TREE_OPERAND (lhs, 0); - code = MINUS_EXPR; + opcode = MINUS_EXPR; rhs = integer_one_node; break; @@ -24086,48 +24184,67 @@ cp_parser_omp_atomic (cp_parser *parser, case MODIFY_EXPR: if (TREE_CODE (lhs) == MODIFY_EXPR && TREE_CODE (TREE_TYPE (TREE_OPERAND (lhs, 0))) == BOOLEAN_TYPE) - { - /* Undo effects of boolean_increment. */ - if (integer_onep (TREE_OPERAND (lhs, 1))) - { - /* This is pre or post increment. */ - rhs = TREE_OPERAND (lhs, 1); - lhs = TREE_OPERAND (lhs, 0); - code = NOP_EXPR; - break; - } - } + { + /* Undo effects of boolean_increment. */ + if (integer_onep (TREE_OPERAND (lhs, 1))) + { + /* This is pre or post increment. */ + rhs = TREE_OPERAND (lhs, 1); + lhs = TREE_OPERAND (lhs, 0); + opcode = NOP_EXPR; + if (code == OMP_ATOMIC_CAPTURE_NEW + && TREE_CODE (orig_lhs) == COMPOUND_EXPR) + code = OMP_ATOMIC_CAPTURE_OLD; + break; + } + } /* FALLTHRU */ default: switch (cp_lexer_peek_token (parser->lexer)->type) { case CPP_MULT_EQ: - code = MULT_EXPR; + opcode = MULT_EXPR; break; case CPP_DIV_EQ: - code = TRUNC_DIV_EXPR; + opcode = TRUNC_DIV_EXPR; break; case CPP_PLUS_EQ: - code = PLUS_EXPR; + opcode = PLUS_EXPR; break; case CPP_MINUS_EQ: - code = MINUS_EXPR; + opcode = MINUS_EXPR; break; case CPP_LSHIFT_EQ: - code = LSHIFT_EXPR; + opcode = LSHIFT_EXPR; break; case CPP_RSHIFT_EQ: - code = RSHIFT_EXPR; + opcode = RSHIFT_EXPR; break; case CPP_AND_EQ: - code = BIT_AND_EXPR; + opcode = BIT_AND_EXPR; break; case CPP_OR_EQ: - code = BIT_IOR_EXPR; + opcode = BIT_IOR_EXPR; break; case CPP_XOR_EQ: - code = BIT_XOR_EXPR; + opcode = BIT_XOR_EXPR; break; + case CPP_EQ: + if (structured_block && code == OMP_ATOMIC_CAPTURE_NEW) + { + code = OMP_ATOMIC_CAPTURE_OLD; + v = lhs; + lhs = NULL_TREE; + cp_lexer_consume_token (parser->lexer); + lhs1 = cp_parser_unary_expression (parser, /*address_p=*/false, + /*cast_p=*/false, NULL); + if (lhs1 == error_mark_node) + goto saw_error; + if (!cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON)) + goto saw_error; + goto restart; + } + /* FALLTHROUGH */ default: cp_parser_error (parser, "invalid operator for %<#pragma omp atomic%>"); @@ -24140,8 +24257,30 @@ cp_parser_omp_atomic (cp_parser *parser, goto saw_error; break; } - finish_omp_atomic (code, lhs, rhs); - cp_parser_consume_semicolon_at_end_of_statement (parser); + if (structured_block && code == OMP_ATOMIC_CAPTURE_NEW) + { + if (!cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON)) + goto saw_error; + v = cp_parser_unary_expression (parser, /*address_p=*/false, + /*cast_p=*/false, NULL); + if (v == error_mark_node) + goto saw_error; + if (!cp_parser_require (parser, CPP_EQ, RT_EQ)) + goto saw_error; + lhs1 = cp_parser_unary_expression (parser, /*address_p=*/false, + /*cast_p=*/false, NULL); + if (lhs1 == error_mark_node) + goto saw_error; + } + if (structured_block) + { + cp_parser_consume_semicolon_at_end_of_statement (parser); + cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE); + } +done: + finish_omp_atomic (code, opcode, lhs, rhs, v, lhs1); + if (!structured_block) + cp_parser_consume_semicolon_at_end_of_statement (parser); return; saw_error: --- gcc/cp/cp-tree.h.jj 2011-02-24 14:18:07.000000000 +0100 +++ gcc/cp/cp-tree.h 2011-04-21 16:20:08.000000000 +0200 @@ -5333,7 +5333,8 @@ extern tree begin_omp_task (void); extern tree finish_omp_task (tree, tree); extern tree finish_omp_for (location_t, tree, tree, tree, tree, tree, tree, tree); -extern void finish_omp_atomic (enum tree_code, tree, tree); +extern void finish_omp_atomic (enum tree_code, enum tree_code, + tree, tree, tree, tree); extern void finish_omp_barrier (void); extern void finish_omp_flush (void); extern void finish_omp_taskwait (void); --- gcc/cp/semantics.c.jj 2011-04-20 18:31:25.000000000 +0200 +++ gcc/cp/semantics.c 2011-04-27 09:47:52.000000000 +0200 @@ -4581,15 +4581,20 @@ finish_omp_for (location_t locus, tree d } void -finish_omp_atomic (enum tree_code code, tree lhs, tree rhs) +finish_omp_atomic (enum tree_code code, enum tree_code opcode, tree lhs, + tree rhs, tree v, tree lhs1) { tree orig_lhs; tree orig_rhs; + tree orig_v; + tree orig_lhs1; bool dependent_p; tree stmt; orig_lhs = lhs; orig_rhs = rhs; + orig_v = v; + orig_lhs1 = lhs1; dependent_p = false; stmt = NULL_TREE; @@ -4598,23 +4603,48 @@ finish_omp_atomic (enum tree_code code, if (processing_template_decl) { dependent_p = (type_dependent_expression_p (lhs) - || type_dependent_expression_p (rhs)); + || (rhs && type_dependent_expression_p (rhs)) + || (v && type_dependent_expression_p (v)) + || (lhs1 && type_dependent_expression_p (lhs1))); if (!dependent_p) { lhs = build_non_dependent_expr (lhs); - rhs = build_non_dependent_expr (rhs); + if (rhs) + rhs = build_non_dependent_expr (rhs); + if (v) + v = build_non_dependent_expr (v); + if (lhs1) + lhs1 = build_non_dependent_expr (lhs1); } } if (!dependent_p) { - stmt = c_finish_omp_atomic (input_location, OMP_ATOMIC, code, lhs, rhs, - NULL_TREE, NULL_TREE); + stmt = c_finish_omp_atomic (input_location, code, opcode, lhs, rhs, + v, lhs1); if (stmt == error_mark_node) return; } if (processing_template_decl) - stmt = build2 (OMP_ATOMIC, void_type_node, integer_zero_node, - build2 (code, void_type_node, orig_lhs, orig_rhs)); + { + if (code == OMP_ATOMIC_READ) + { + stmt = build_min_nt (OMP_ATOMIC_READ, orig_lhs); + stmt = build2 (MODIFY_EXPR, void_type_node, orig_v, stmt); + } + else + { + if (opcode == NOP_EXPR) + stmt = build2 (MODIFY_EXPR, void_type_node, orig_lhs, orig_rhs); + else + stmt = build2 (opcode, void_type_node, orig_lhs, orig_rhs); + if (code != OMP_ATOMIC) + { + stmt = build_min_nt (code, orig_lhs1, stmt); + stmt = build2 (MODIFY_EXPR, void_type_node, orig_v, stmt); + } + } + stmt = build2 (OMP_ATOMIC, void_type_node, integer_zero_node, stmt); + } add_stmt (stmt); } --- gcc/cp/pt.c.jj 2011-02-24 14:18:07.000000000 +0100 +++ gcc/cp/pt.c 2011-04-27 09:52:25.000000000 +0200 @@ -12397,12 +12397,43 @@ tsubst_expr (tree t, tree args, tsubst_f case OMP_ATOMIC: gcc_assert (OMP_ATOMIC_DEPENDENT_P (t)); - { - tree op1 = TREE_OPERAND (t, 1); - tree lhs = RECUR (TREE_OPERAND (op1, 0)); - tree rhs = RECUR (TREE_OPERAND (op1, 1)); - finish_omp_atomic (TREE_CODE (op1), lhs, rhs); - } + if (TREE_CODE (TREE_OPERAND (t, 1)) != MODIFY_EXPR) + { + tree op1 = TREE_OPERAND (t, 1); + tree lhs = RECUR (TREE_OPERAND (op1, 0)); + tree rhs = RECUR (TREE_OPERAND (op1, 1)); + finish_omp_atomic (OMP_ATOMIC, TREE_CODE (op1), lhs, rhs, + NULL_TREE, NULL_TREE); + } + else + { + tree op1 = TREE_OPERAND (t, 1); + tree v = NULL_TREE, lhs, rhs = NULL_TREE, lhs1 = NULL_TREE; + enum tree_code code = TREE_CODE (TREE_OPERAND (op1, 1)); + enum tree_code opcode = NOP_EXPR; + if (code == OMP_ATOMIC_READ) + { + v = RECUR (TREE_OPERAND (op1, 0)); + lhs = RECUR (TREE_OPERAND (TREE_OPERAND (op1, 1), 0)); + } + else if (code == OMP_ATOMIC_CAPTURE_OLD + || code == OMP_ATOMIC_CAPTURE_NEW) + { + tree op11 = TREE_OPERAND (TREE_OPERAND (op1, 1), 1); + v = RECUR (TREE_OPERAND (op1, 0)); + lhs1 = RECUR (TREE_OPERAND (TREE_OPERAND (op1, 1), 0)); + lhs = RECUR (TREE_OPERAND (op11, 0)); + rhs = RECUR (TREE_OPERAND (op11, 1)); + opcode = TREE_CODE (op11); + } + else + { + code = OMP_ATOMIC; + lhs = RECUR (TREE_OPERAND (op1, 0)); + rhs = RECUR (TREE_OPERAND (op1, 1)); + } + finish_omp_atomic (code, opcode, lhs, rhs, v, lhs1); + } break; case EXPR_PACK_EXPANSION: --- libgomp/testsuite/libgomp.c++/atomic-5.C.jj 2011-04-27 09:55:44.000000000 +0200 +++ libgomp/testsuite/libgomp.c++/atomic-5.C 2011-04-27 09:56:50.000000000 +0200 @@ -0,0 +1,47 @@ +// { dg-do run } + +extern "C" void abort (void); + +template <typename T> +void +foo (void) +{ + extern T v, x1, x2, x3, x4, x5, x6; + #pragma omp atomic capture + v = ++x1; + if (!v) + abort (); + #pragma omp atomic capture + v = x2++; + if (v) + abort (); + #pragma omp atomic read + v = x3; + if (!v) + abort (); + #pragma omp atomic read + v = x4; + if (!v) + abort (); + #pragma omp atomic capture + { v = x5; x5 |= 1; } + if (v) + abort (); + #pragma omp atomic capture + { x6 |= 1; v = x6; } + if (!v) + abort (); +} + +bool v, x1, x2, x3, x4, x5, x6; + +int +main () +{ + #pragma omp atomic write + x3 = true; + #pragma omp atomic write + x4 = true; + foo <bool> (); + return 0; +} --- libgomp/testsuite/libgomp.c++/atomic-4.C.jj 2011-04-26 19:03:11.000000000 +0200 +++ libgomp/testsuite/libgomp.c++/atomic-4.C 2011-04-26 19:05:45.000000000 +0200 @@ -0,0 +1,122 @@ +// { dg-do run } + +extern "C" void abort (void); +template <typename T, typename T2> +int +foo (void) +{ + extern T x; + extern T2 y; + T v; + T2 f; + #pragma omp atomic read + v = x; + if (v != 6) + abort (); + #pragma omp atomic write + x = 17; + #pragma omp atomic read + v = x; + if (v != 17) + abort (); + #pragma omp atomic update + x++; + #pragma omp atomic read + v = x; + if (v != 18) + abort (); + #pragma omp atomic capture + v = x++; + if (v != 18) + abort (); + #pragma omp atomic read + v = x; + if (v != 19) + abort (); + #pragma omp atomic capture + v = ++x; + if (v != 20) + abort (); + #pragma omp atomic read + v = x; + if (v != 20) + abort (); + #pragma omp atomic capture + { v = x; x *= 3; } + if (v != 20) + abort (); + #pragma omp atomic read + v = x; + if (v != 60) + abort (); + #pragma omp atomic capture + { + x |= 2; + v = x; + } + if (v != 62) + abort (); + #pragma omp atomic read + v = x; + if (v != 62) + abort (); + #pragma omp atomic write + y = 17.5f; + #pragma omp atomic read + f = y; + if (f != 17.5) + abort (); + #pragma omp atomic update + y *= 2.0f; + #pragma omp atomic read + f = y; + if (y != 35.0) + abort (); + #pragma omp atomic capture + f = y *= 2.0f; + if (f != 70.0) + abort (); + #pragma omp atomic capture + f = y++; + if (f != 70.0) + abort (); + #pragma omp atomic read + f = y; + if (f != 71.0) + abort (); + #pragma omp atomic capture + f = --y; + if (f != 70.0) + abort (); + #pragma omp atomic read + f = y; + if (f != 70.0) + abort (); + #pragma omp atomic capture + { f = y; y /= 2.0f; } + if (f != 70.0) + abort (); + #pragma omp atomic read + f = y; + if (f != 35.0) + abort (); + #pragma omp atomic capture + { y /= 2.0f; f = y; } + if (f != 17.5) + abort (); + #pragma omp atomic read + f = y; + if (f != 17.5) + abort (); + return 0; +} + +int x = 6; +float y; + +int +main () +{ + foo <int, float> (); + return 0; +} --- libgomp/testsuite/libgomp.c++/atomic-3.C.jj 2011-04-26 18:51:34.000000000 +0200 +++ libgomp/testsuite/libgomp.c++/atomic-3.C 2011-04-27 09:57:02.000000000 +0200 @@ -0,0 +1,44 @@ +// { dg-do run } + +extern "C" void abort (void); +bool v, x1, x2, x3, x4, x5, x6; + +void +foo (void) +{ + #pragma omp atomic capture + v = ++x1; + if (!v) + abort (); + #pragma omp atomic capture + v = x2++; + if (v) + abort (); + #pragma omp atomic read + v = x3; + if (!v) + abort (); + #pragma omp atomic read + v = x4; + if (!v) + abort (); + #pragma omp atomic capture + { v = x5; x5 |= 1; } + if (v) + abort (); + #pragma omp atomic capture + { x6 |= 1; v = x6; } + if (!v) + abort (); +} + +int +main () +{ + #pragma omp atomic write + x3 = true; + #pragma omp atomic write + x4 = true; + foo (); + return 0; +} --- libgomp/testsuite/libgomp.c++/atomic-2.C.jj 2011-04-26 18:51:29.000000000 +0200 +++ libgomp/testsuite/libgomp.c++/atomic-2.C 2011-04-26 18:53:21.000000000 +0200 @@ -0,0 +1,112 @@ +// { dg-do run } + +extern "C" void abort (void); +int x = 6; +float y; + +int +main (void) +{ + int v; + float f; + #pragma omp atomic read + v = x; + if (v != 6) + abort (); + #pragma omp atomic write + x = 17; + #pragma omp atomic read + v = x; + if (v != 17) + abort (); + #pragma omp atomic update + x++; + #pragma omp atomic read + v = x; + if (v != 18) + abort (); + #pragma omp atomic capture + v = x++; + if (v != 18) + abort (); + #pragma omp atomic read + v = x; + if (v != 19) + abort (); + #pragma omp atomic capture + v = ++x; + if (v != 20) + abort (); + #pragma omp atomic read + v = x; + if (v != 20) + abort (); + #pragma omp atomic capture + { v = x; x *= 3; } + if (v != 20) + abort (); + #pragma omp atomic read + v = x; + if (v != 60) + abort (); + #pragma omp atomic capture + { + x |= 2; + v = x; + } + if (v != 62) + abort (); + #pragma omp atomic read + v = x; + if (v != 62) + abort (); + #pragma omp atomic write + y = 17.5f; + #pragma omp atomic read + f = y; + if (f != 17.5) + abort (); + #pragma omp atomic update + y *= 2.0f; + #pragma omp atomic read + f = y; + if (y != 35.0) + abort (); + #pragma omp atomic capture + f = y *= 2.0f; + if (f != 70.0) + abort (); + #pragma omp atomic capture + f = y++; + if (f != 70.0) + abort (); + #pragma omp atomic read + f = y; + if (f != 71.0) + abort (); + #pragma omp atomic capture + f = --y; + if (f != 70.0) + abort (); + #pragma omp atomic read + f = y; + if (f != 70.0) + abort (); + #pragma omp atomic capture + { f = y; y /= 2.0f; } + if (f != 70.0) + abort (); + #pragma omp atomic read + f = y; + if (f != 35.0) + abort (); + #pragma omp atomic capture + { y /= 2.0f; f = y; } + if (f != 17.5) + abort (); + #pragma omp atomic read + f = y; + if (f != 17.5) + abort (); + return 0; +} Jakub