From 1ccc44f517c1d62ba6a1accdf080f68ef924368b Mon Sep 17 00:00:00 2001 From: jakub Date: Wed, 20 Mar 2013 09:01:24 +0000 Subject: [PATCH 01/63] Branch for OpenMP 4.0 support development. See http://openmp.org/wp/2013/03/openmp-40-rc2/ for the standard draft. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gomp-4_0-branch@196809 138bc75d-0d04-0410-961f-82ee72b054a4 From 1cbedd40838d1362c735bcf5bae4573b1b6c7382 Mon Sep 17 00:00:00 2001 From: jakub Date: Wed, 20 Mar 2013 09:40:48 +0000 Subject: [PATCH 02/63] * c-parser.c (c_parser_omp_atomic): Adjust comment. Add another argument to c_finish_omp_atomic. * parser.c (cp_parser_binary_expression): Handle no_toplevel_fold_p even for binary operations other than comparison. (cp_parser_omp_atomic): Handle parsing OpenMP 4.0 atomics. * pt.c (tsubst_expr) : Handle atomic exchange. * semantics.c (finish_omp_atomic): Use cp_tree_equal to diagnose expression mismatches and to find out if c_finish_omp_atomic should be called with swapped set to true or false. * c-omp.c (c_finish_omp_atomic): Add swapped argument, if true, build the operation first with rhs, lhs arguments and use NOP_EXPR build_modify_expr. * c-common.h (c_finish_omp_atomic): Adjust prototype. * c-c++-common/gomp/atomic-15.c: Remove error test that is now valid in OpenMP 4.0. * testsuite/libgomp.c++/atomic-10.C: New test. * testsuite/libgomp.c++/atomic-11.C: New test. * testsuite/libgomp.c++/atomic-12.C: New test. * testsuite/libgomp.c++/atomic-13.C: New test. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gomp-4_0-branch@196815 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/c-family/ChangeLog.gomp | 12 ++ gcc/c-family/c-common.h | 2 +- gcc/c-family/c-omp.c | 10 +- gcc/c/ChangeLog.gomp | 10 + gcc/c/c-parser.c | 13 +- gcc/cp/ChangeLog.gomp | 15 ++ gcc/cp/parser.c | 204 +++++++++++++------- gcc/cp/pt.c | 2 + gcc/cp/semantics.c | 30 ++- gcc/testsuite/ChangeLog.gomp | 10 + gcc/testsuite/c-c++-common/gomp/atomic-15.c | 2 - libgomp/ChangeLog.gomp | 12 ++ libgomp/testsuite/libgomp.c++/atomic-10.C | 99 ++++++++++ libgomp/testsuite/libgomp.c++/atomic-11.C | 108 +++++++++++ libgomp/testsuite/libgomp.c++/atomic-12.C | 58 ++++++ libgomp/testsuite/libgomp.c++/atomic-13.C | 68 +++++++ 16 files changed, 581 insertions(+), 74 deletions(-) create mode 100644 gcc/c-family/ChangeLog.gomp create mode 100644 gcc/c/ChangeLog.gomp create mode 100644 gcc/cp/ChangeLog.gomp create mode 100644 gcc/testsuite/ChangeLog.gomp create mode 100644 libgomp/ChangeLog.gomp create mode 100644 libgomp/testsuite/libgomp.c++/atomic-10.C create mode 100644 libgomp/testsuite/libgomp.c++/atomic-11.C create mode 100644 libgomp/testsuite/libgomp.c++/atomic-12.C create mode 100644 libgomp/testsuite/libgomp.c++/atomic-13.C diff --git a/gcc/c-family/ChangeLog.gomp b/gcc/c-family/ChangeLog.gomp new file mode 100644 index 0000000000000..c31948f85ddb6 --- /dev/null +++ b/gcc/c-family/ChangeLog.gomp @@ -0,0 +1,12 @@ +2013-03-20 Jakub Jelinek + + * c-omp.c (c_finish_omp_atomic): Add swapped argument, if true, + build the operation first with rhs, lhs arguments and use NOP_EXPR + build_modify_expr. + * c-common.h (c_finish_omp_atomic): Adjust prototype. + +Copyright (C) 2013 Free Software Foundation, Inc. + +Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index 4014651b876d1..f5638bfac1486 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -1035,7 +1035,7 @@ extern tree c_finish_omp_critical (location_t, tree, tree); extern tree c_finish_omp_ordered (location_t, tree); extern void c_finish_omp_barrier (location_t); extern tree c_finish_omp_atomic (location_t, enum tree_code, enum tree_code, - tree, tree, tree, tree, tree); + tree, tree, tree, tree, tree, bool); extern void c_finish_omp_flush (location_t); extern void c_finish_omp_taskwait (location_t); extern void c_finish_omp_taskyield (location_t); diff --git a/gcc/c-family/c-omp.c b/gcc/c-family/c-omp.c index f05b60a403501..634923017eba3 100644 --- a/gcc/c-family/c-omp.c +++ b/gcc/c-family/c-omp.c @@ -122,7 +122,7 @@ c_finish_omp_taskyield (location_t loc) tree c_finish_omp_atomic (location_t loc, enum tree_code code, enum tree_code opcode, tree lhs, tree rhs, - tree v, tree lhs1, tree rhs1) + tree v, tree lhs1, tree rhs1, bool swapped) { tree x, type, addr; @@ -176,8 +176,12 @@ c_finish_omp_atomic (location_t loc, enum tree_code code, /* There are lots of warnings, errors, and conversions that need to happen in the course of interpreting a statement. Use the normal mechanisms to do this, and then take it apart again. */ - x = build_modify_expr (input_location, lhs, NULL_TREE, opcode, - input_location, rhs, NULL_TREE); + if (swapped) + { + rhs = build2_loc (loc, opcode, TREE_TYPE (lhs), rhs, lhs); + opcode = NOP_EXPR; + } + x = build_modify_expr (loc, lhs, NULL_TREE, opcode, loc, rhs, NULL_TREE); if (x == error_mark_node) return error_mark_node; gcc_assert (TREE_CODE (x) == MODIFY_EXPR); diff --git a/gcc/c/ChangeLog.gomp b/gcc/c/ChangeLog.gomp new file mode 100644 index 0000000000000..9941433abf05f --- /dev/null +++ b/gcc/c/ChangeLog.gomp @@ -0,0 +1,10 @@ +2013-03-20 Jakub Jelinek + + * c-parser.c (c_parser_omp_atomic): Adjust comment. + Add another argument to c_finish_omp_atomic. + +Copyright (C) 2013 Free Software Foundation, Inc. + +Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index 2ae46220ac14c..e9f07ee745dc8 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -9500,10 +9500,18 @@ c_parser_omp_structured_block (c_parser *parser) update-stmt: expression-stmt | x = x binop expr capture-stmt: - v = x binop= expr | v = x++ | v = ++x | v = x-- | v = --x + v = expression-stmt capture-block: { v = x; update-stmt; } | { update-stmt; v = x; } + OpenMP 4.0: + update-stmt: + expression-stmt | x = x binop expr | x = expr binop x + capture-stmt: + v = update-stmt + capture-block: + { v = x; update-stmt; } | { update-stmt; v = x; } | { v = x; x = expr; } + where x and v are lvalue expressions with scalar type. LOC is the location of the #pragma token. */ @@ -9826,7 +9834,8 @@ c_parser_omp_atomic (location_t loc, c_parser *parser) c_parser_require (parser, CPP_CLOSE_BRACE, "expected %<}%>"); } done: - stmt = c_finish_omp_atomic (loc, code, opcode, lhs, rhs, v, lhs1, rhs1); + stmt = c_finish_omp_atomic (loc, code, opcode, lhs, rhs, v, lhs1, rhs1, + false); if (stmt != error_mark_node) add_stmt (stmt); diff --git a/gcc/cp/ChangeLog.gomp b/gcc/cp/ChangeLog.gomp new file mode 100644 index 0000000000000..1b783e6eba471 --- /dev/null +++ b/gcc/cp/ChangeLog.gomp @@ -0,0 +1,15 @@ +2013-03-20 Jakub Jelinek + + * parser.c (cp_parser_binary_expression): Handle no_toplevel_fold_p + even for binary operations other than comparison. + (cp_parser_omp_atomic): Handle parsing OpenMP 4.0 atomics. + * pt.c (tsubst_expr) : Handle atomic exchange. + * semantics.c (finish_omp_atomic): Use cp_tree_equal to diagnose + expression mismatches and to find out if c_finish_omp_atomic + should be called with swapped set to true or false. + +Copyright (C) 2013 Free Software Foundation, Inc. + +Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 23fe3f302a0d6..514574e0d97dc 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -7509,9 +7509,11 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p, */ if (no_toplevel_fold_p && lookahead_prec <= current.prec - && sp == stack - && TREE_CODE_CLASS (current.tree_type) == tcc_comparison) - current.lhs = build2 (current.tree_type, boolean_type_node, + && sp == stack) + current.lhs = build2 (current.tree_type, + TREE_CODE_CLASS (current.tree_type) + == tcc_comparison + ? boolean_type_node : TREE_TYPE (current.lhs), current.lhs, rhs); else current.lhs = build_x_binary_op (current.loc, current.tree_type, @@ -26518,10 +26520,18 @@ cp_parser_omp_structured_block (cp_parser *parser) update-stmt: expression-stmt | x = x binop expr capture-stmt: - v = x binop= expr | v = x++ | v = ++x | v = x-- | v = --x + v = expression-stmt capture-block: { v = x; update-stmt; } | { update-stmt; v = x; } + OpenMP 4.0: + update-stmt: + expression-stmt | x = x binop expr | x = expr binop x + capture-stmt: + v = update-stmt + capture-block: + { v = x; update-stmt; } | { update-stmt; v = x; } | { v = x; x = expr; } + where x and v are lvalue expressions with scalar type. */ static void @@ -26688,75 +26698,139 @@ cp_parser_omp_atomic (cp_parser *parser, cp_token *pragma_tok) opcode = BIT_XOR_EXPR; break; case CPP_EQ: - if (structured_block || code == OMP_ATOMIC) + enum cp_parser_prec oprec; + cp_token *token; + cp_lexer_consume_token (parser->lexer); + cp_parser_parse_tentatively (parser); + rhs1 = cp_parser_simple_cast_expression (parser); + if (rhs1 == error_mark_node) { - enum cp_parser_prec oprec; - cp_token *token; - cp_lexer_consume_token (parser->lexer); - rhs1 = cp_parser_unary_expression (parser, /*address_p=*/false, - /*cast_p=*/false, NULL); - if (rhs1 == error_mark_node) - goto saw_error; - token = cp_lexer_peek_token (parser->lexer); - switch (token->type) + cp_parser_abort_tentative_parse (parser); + cp_parser_simple_cast_expression (parser); + goto saw_error; + } + token = cp_lexer_peek_token (parser->lexer); + if (token->type != CPP_SEMICOLON && !cp_tree_equal (lhs, rhs1)) + { + cp_parser_abort_tentative_parse (parser); + cp_parser_parse_tentatively (parser); + rhs = cp_parser_binary_expression (parser, false, true, + PREC_NOT_OPERATOR, NULL); + if (rhs == error_mark_node) { - case CPP_SEMICOLON: - if (code == OMP_ATOMIC_CAPTURE_NEW) + cp_parser_abort_tentative_parse (parser); + cp_parser_binary_expression (parser, false, true, + PREC_NOT_OPERATOR, NULL); + goto saw_error; + } + switch (TREE_CODE (rhs)) + { + case MULT_EXPR: + case TRUNC_DIV_EXPR: + case PLUS_EXPR: + case MINUS_EXPR: + case LSHIFT_EXPR: + case RSHIFT_EXPR: + case BIT_AND_EXPR: + case BIT_IOR_EXPR: + case BIT_XOR_EXPR: + if (cp_tree_equal (lhs, TREE_OPERAND (rhs, 1))) { - code = OMP_ATOMIC_CAPTURE_OLD; - v = lhs; - lhs = NULL_TREE; - lhs1 = rhs1; - rhs1 = NULL_TREE; - cp_lexer_consume_token (parser->lexer); - goto restart; + if (cp_parser_parse_definitely (parser)) + { + opcode = TREE_CODE (rhs); + rhs1 = TREE_OPERAND (rhs, 0); + rhs = TREE_OPERAND (rhs, 1); + goto stmt_done; + } + else + goto saw_error; } - cp_parser_error (parser, - "invalid form of %<#pragma omp atomic%>"); - goto saw_error; - case CPP_MULT: - opcode = MULT_EXPR; - break; - case CPP_DIV: - opcode = TRUNC_DIV_EXPR; - break; - case CPP_PLUS: - opcode = PLUS_EXPR; - break; - case CPP_MINUS: - opcode = MINUS_EXPR; - break; - case CPP_LSHIFT: - opcode = LSHIFT_EXPR; - break; - case CPP_RSHIFT: - opcode = RSHIFT_EXPR; - break; - case CPP_AND: - opcode = BIT_AND_EXPR; - break; - case CPP_OR: - opcode = BIT_IOR_EXPR; - break; - case CPP_XOR: - opcode = BIT_XOR_EXPR; break; default: - cp_parser_error (parser, - "invalid operator for %<#pragma omp atomic%>"); - goto saw_error; + break; } - oprec = TOKEN_PRECEDENCE (token); - gcc_assert (oprec != PREC_NOT_OPERATOR); - if (commutative_tree_code (opcode)) - oprec = (enum cp_parser_prec) (oprec - 1); - cp_lexer_consume_token (parser->lexer); - rhs = cp_parser_binary_expression (parser, false, false, - oprec, NULL); - if (rhs == error_mark_node) - goto saw_error; - goto stmt_done; + cp_parser_abort_tentative_parse (parser); + if (structured_block && code == OMP_ATOMIC_CAPTURE_OLD) + { + rhs = cp_parser_expression (parser, /*cast_p=*/false, NULL); + if (rhs == error_mark_node) + goto saw_error; + opcode = NOP_EXPR; + rhs1 = NULL_TREE; + goto stmt_done; + } + cp_parser_error (parser, + "invalid form of %<#pragma omp atomic%>"); + goto saw_error; } + if (!cp_parser_parse_definitely (parser)) + goto saw_error; + switch (token->type) + { + case CPP_SEMICOLON: + if (code == OMP_ATOMIC_CAPTURE_NEW) + { + code = OMP_ATOMIC_CAPTURE_OLD; + v = lhs; + lhs = NULL_TREE; + lhs1 = rhs1; + rhs1 = NULL_TREE; + cp_lexer_consume_token (parser->lexer); + goto restart; + } + else if (structured_block) + { + opcode = NOP_EXPR; + rhs = rhs1; + rhs1 = NULL_TREE; + goto stmt_done; + } + cp_parser_error (parser, + "invalid form of %<#pragma omp atomic%>"); + goto saw_error; + case CPP_MULT: + opcode = MULT_EXPR; + break; + case CPP_DIV: + opcode = TRUNC_DIV_EXPR; + break; + case CPP_PLUS: + opcode = PLUS_EXPR; + break; + case CPP_MINUS: + opcode = MINUS_EXPR; + break; + case CPP_LSHIFT: + opcode = LSHIFT_EXPR; + break; + case CPP_RSHIFT: + opcode = RSHIFT_EXPR; + break; + case CPP_AND: + opcode = BIT_AND_EXPR; + break; + case CPP_OR: + opcode = BIT_IOR_EXPR; + break; + case CPP_XOR: + opcode = BIT_XOR_EXPR; + break; + default: + cp_parser_error (parser, + "invalid operator for %<#pragma omp atomic%>"); + goto saw_error; + } + oprec = TOKEN_PRECEDENCE (token); + gcc_assert (oprec != PREC_NOT_OPERATOR); + if (commutative_tree_code (opcode)) + oprec = (enum cp_parser_prec) (oprec - 1); + cp_lexer_consume_token (parser->lexer); + rhs = cp_parser_binary_expression (parser, false, false, + oprec, NULL); + if (rhs == error_mark_node) + goto saw_error; + goto stmt_done; /* FALLTHROUGH */ default: cp_parser_error (parser, diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 427447913ecfb..0bace4b314561 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -13301,6 +13301,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, lhs = RECUR (TREE_OPERAND (op11, 0)); rhs = RECUR (TREE_OPERAND (op11, 1)); opcode = TREE_CODE (op11); + if (opcode == MODIFY_EXPR) + opcode = NOP_EXPR; } else { diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 5143e4bd5822b..ae9bd18c6ed21 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -5010,8 +5010,36 @@ finish_omp_atomic (enum tree_code code, enum tree_code opcode, tree lhs, } if (!dependent_p) { + bool swapped = false; + if (rhs1 && cp_tree_equal (lhs, rhs)) + { + tree tem = rhs; + rhs = rhs1; + rhs1 = tem; + swapped = !commutative_tree_code (opcode); + } + if (rhs1 && !cp_tree_equal (lhs, rhs1)) + { + if (code == OMP_ATOMIC) + error ("%<#pragma omp atomic update%> uses two different " + "expressions for memory"); + else + error ("%<#pragma omp atomic capture%> uses two different " + "expressions for memory"); + return; + } + if (lhs1 && !cp_tree_equal (lhs, lhs1)) + { + if (code == OMP_ATOMIC) + error ("%<#pragma omp atomic update%> uses two different " + "expressions for memory"); + else + error ("%<#pragma omp atomic capture%> uses two different " + "expressions for memory"); + return; + } stmt = c_finish_omp_atomic (input_location, code, opcode, lhs, rhs, - v, lhs1, rhs1); + v, lhs1, rhs1, swapped); if (stmt == error_mark_node) return; } diff --git a/gcc/testsuite/ChangeLog.gomp b/gcc/testsuite/ChangeLog.gomp new file mode 100644 index 0000000000000..466f81a56ab23 --- /dev/null +++ b/gcc/testsuite/ChangeLog.gomp @@ -0,0 +1,10 @@ +2013-03-20 Jakub Jelinek + + * c-c++-common/gomp/atomic-15.c: Remove error test that is now + valid in OpenMP 4.0. + +Copyright (C) 2013 Free Software Foundation, Inc. + +Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. diff --git a/gcc/testsuite/c-c++-common/gomp/atomic-15.c b/gcc/testsuite/c-c++-common/gomp/atomic-15.c index 13a9e0ce48a15..d77a858829b84 100644 --- a/gcc/testsuite/c-c++-common/gomp/atomic-15.c +++ b/gcc/testsuite/c-c++-common/gomp/atomic-15.c @@ -19,8 +19,6 @@ main () x = x / 7 * 2; /* { dg-error "expected" } */ #pragma omp atomic x = x / 7 / 2; /* { dg-error "expected" } */ - #pragma omp atomic capture - v = x = x | 6; /* { dg-error "invalid operator" } */ #pragma omp atomic capture { v = x; x = x * 7 + 6; } /* { dg-error "expected" } */ #pragma omp atomic capture diff --git a/libgomp/ChangeLog.gomp b/libgomp/ChangeLog.gomp new file mode 100644 index 0000000000000..a6eeb6bfed193 --- /dev/null +++ b/libgomp/ChangeLog.gomp @@ -0,0 +1,12 @@ +2013-03-20 Jakub Jelinek + + * testsuite/libgomp.c++/atomic-10.C: New test. + * testsuite/libgomp.c++/atomic-11.C: New test. + * testsuite/libgomp.c++/atomic-12.C: New test. + * testsuite/libgomp.c++/atomic-13.C: New test. + +Copyright (C) 2013 Free Software Foundation, Inc. + +Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. diff --git a/libgomp/testsuite/libgomp.c++/atomic-10.C b/libgomp/testsuite/libgomp.c++/atomic-10.C new file mode 100644 index 0000000000000..2145f28823329 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/atomic-10.C @@ -0,0 +1,99 @@ +// { dg-do run } + +extern "C" void abort (void); +int x = 6; + +int +main () +{ + int v, l = 2, s = 1; + #pragma omp atomic + x = -3 + x; + #pragma omp atomic read + v = x; + if (v != 3) + abort (); + #pragma omp atomic update + x = 3 * 2 * 1 + x; + #pragma omp atomic read + v = x; + if (v != 9) + abort (); + #pragma omp atomic capture + v = x = x | 16; + if (v != 25) + abort (); + #pragma omp atomic capture + v = x = x + 14 * 2 / 4; + if (v != 32) + abort (); + #pragma omp atomic capture + v = x = 5 | x; + if (v != 37) + abort (); + #pragma omp atomic capture + v = x = 40 + 12 - 2 - 7 - x; + if (v != 6) + abort (); + #pragma omp atomic read + v = x; + if (v != 6) + abort (); + #pragma omp atomic capture + { v = x; x = 3 + x; } + if (v != 6) + abort (); + #pragma omp atomic capture + { v = x; x = -1 * -1 * -1 * -1 - x; } + if (v != 9) + abort (); + #pragma omp atomic read + v = x; + if (v != -8) + abort (); + #pragma omp atomic capture + { x = 2 * 2 - x; v = x; } + if (v != 12) + abort (); + #pragma omp atomic capture + { x = 7 & x; v = x; } + if (v != 4) + abort (); + #pragma omp atomic capture + { v = x; x = 6; } + if (v != 4) + abort (); + #pragma omp atomic read + v = x; + if (v != 6) + abort (); + #pragma omp atomic capture + { v = x; x = 7 * 8 + 23; } + if (v != 6) + abort (); + #pragma omp atomic read + v = x; + if (v != 79) + abort (); + #pragma omp atomic capture + { v = x; x = 23 + 6 * 4; } + if (v != 79) + abort (); + #pragma omp atomic read + v = x; + if (v != 47) + abort (); + #pragma omp atomic capture + { v = x; x = l ? 17 : 12; } + if (v != 47) + abort (); + #pragma omp atomic capture + { v = x; x = l = s++ + 3; } + if (v != 17 || l != 4 || s != 2) + abort (); + #pragma omp atomic read + v = x; + if (v != 4) + abort (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/atomic-11.C b/libgomp/testsuite/libgomp.c++/atomic-11.C new file mode 100644 index 0000000000000..c7101e01408bb --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/atomic-11.C @@ -0,0 +1,108 @@ +// { dg-do run } + +extern "C" void abort (void); + +template +void +foo () +{ + extern T x; + T v, l = 2, s = 1; + #pragma omp atomic + x = -3 + x; + #pragma omp atomic read + v = x; + if (v != 3) + abort (); + #pragma omp atomic update + x = 3 * 2 * 1 + x; + #pragma omp atomic read + v = x; + if (v != 9) + abort (); + #pragma omp atomic capture + v = x = x | 16; + if (v != 25) + abort (); + #pragma omp atomic capture + v = x = x + 14 * 2 / 4; + if (v != 32) + abort (); + #pragma omp atomic capture + v = x = 5 | x; + if (v != 37) + abort (); + #pragma omp atomic capture + v = x = 40 + 12 - 2 - 7 - x; + if (v != 6) + abort (); + #pragma omp atomic read + v = x; + if (v != 6) + abort (); + #pragma omp atomic capture + { v = x; x = 3 + x; } + if (v != 6) + abort (); + #pragma omp atomic capture + { v = x; x = -1 * -1 * -1 * -1 - x; } + if (v != 9) + abort (); + #pragma omp atomic read + v = x; + if (v != -8) + abort (); + #pragma omp atomic capture + { x = 2 * 2 - x; v = x; } + if (v != 12) + abort (); + #pragma omp atomic capture + { x = 7 & x; v = x; } + if (v != 4) + abort (); + #pragma omp atomic capture + { v = x; x = 6; } + if (v != 4) + abort (); + #pragma omp atomic read + v = x; + if (v != 6) + abort (); + #pragma omp atomic capture + { v = x; x = 7 * 8 + 23; } + if (v != 6) + abort (); + #pragma omp atomic read + v = x; + if (v != 79) + abort (); + #pragma omp atomic capture + { v = x; x = 23 + 6 * 4; } + if (v != 79) + abort (); + #pragma omp atomic read + v = x; + if (v != 47) + abort (); + #pragma omp atomic capture + { v = x; x = l ? 17 : 12; } + if (v != 47) + abort (); + #pragma omp atomic capture + { v = x; x = l = s++ + 3; } + if (v != 17 || l != 4 || s != 2) + abort (); + #pragma omp atomic read + v = x; + if (v != 4) + abort (); +} + +int x = 6; + +int +main () +{ + foo (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/atomic-12.C b/libgomp/testsuite/libgomp.c++/atomic-12.C new file mode 100644 index 0000000000000..d1ae9d8c88ca0 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/atomic-12.C @@ -0,0 +1,58 @@ +// { dg-do run } + +extern "C" void abort (); +int x = 6, cnt; + +int +foo () +{ + return cnt++; +} + +int +main () +{ + int v, *p; + p = &x; + #pragma omp atomic update + p[foo (), 0] = 16 + 6 - p[foo (), 0]; + #pragma omp atomic read + v = x; + if (cnt != 2 || v != 16) + abort (); + #pragma omp atomic capture + v = p[foo () + foo (), 0] = p[foo () + foo (), 0] + 3; + if (cnt != 6 || v != 19) + abort (); + #pragma omp atomic capture + v = p[foo (), 0] = 12 * 1 / 2 + (foo (), 0) + p[foo (), 0]; + if (cnt != 9 || v != 25) + abort (); + #pragma omp atomic capture + { + v = p[foo () & 0]; p[foo () & 0] = (foo (), 1) * 9 - p[foo () & 0]; + } + if (cnt != 13 || v != 25) + abort (); + #pragma omp atomic read + v = x; + if (v != -16) + abort (); + #pragma omp atomic capture + { + p[0 & foo ()] = 16 - 2 + 3 + p[0 & foo ()]; v = p[0 & foo ()]; + } + if (cnt != 16 || v != 1) + abort (); + #pragma omp atomic capture + { + v = p[foo (), 0]; p[foo (), 0] = (foo (), 7) ? 13 : foo () + 6; + } + if (cnt != 19 || v != 1) + abort (); + #pragma omp atomic read + v = x; + if (v != 13) + abort (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/atomic-13.C b/libgomp/testsuite/libgomp.c++/atomic-13.C new file mode 100644 index 0000000000000..0569d1c6deb43 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/atomic-13.C @@ -0,0 +1,68 @@ +// { dg-do run } + +extern "C" void abort (); +int cnt; + +int +foo () +{ + return cnt++; +} + +template +void +bar () +{ + extern T x; + T v, *p; + p = &x; + #pragma omp atomic update + p[foo (), 0] = 16 + 6 - p[foo (), 0]; + #pragma omp atomic read + v = x; + if (cnt != 2 || v != 16) + abort (); + #pragma omp atomic capture + v = p[foo () + foo (), 0] = p[foo () + foo (), 0] + 3; + if (cnt != 6 || v != 19) + abort (); + #pragma omp atomic capture + v = p[foo (), 0] = 12 * 1 / 2 + (foo (), 0) + p[foo (), 0]; + if (cnt != 9 || v != 25) + abort (); + #pragma omp atomic capture + { + v = p[foo () & 0]; p[foo () & 0] = (foo (), 1) * 9 - p[foo () & 0]; + } + if (cnt != 13 || v != 25) + abort (); + #pragma omp atomic read + v = x; + if (v != -16) + abort (); + #pragma omp atomic capture + { + p[0 & foo ()] = 16 - 2 + 3 + p[0 & foo ()]; v = p[0 & foo ()]; + } + if (cnt != 16 || v != 1) + abort (); + #pragma omp atomic capture + { + v = p[foo (), 0]; p[foo (), 0] = (foo (), 7) ? 13 : foo () + 6; + } + if (cnt != 19 || v != 1) + abort (); + #pragma omp atomic read + v = x; + if (v != 13) + abort (); +} + +int x = 6; + +int +main () +{ + bar (); + return 0; +} From 3c9e69d6ac007d279c91b3649be73deb0ee45df6 Mon Sep 17 00:00:00 2001 From: jakub Date: Wed, 20 Mar 2013 09:43:19 +0000 Subject: [PATCH 03/63] * c-parser.c (c_parser_expr_no_commas): Add omp_atomic_lhs argument with default value, pass it down to c_parser_conditional_expression. (c_parser_conditional_expression): Add omp_atomic_lhs argument, pass it down to c_parser_binary_expression. Don't pass PREC_NONE to it. Adjust recursive call. (c_parser_binary_expression): Remove prec argument, add omp_atomic_lhs argument. Always start from PREC_NONE, if omp_atomic_lhs is non-NULL and one of the arguments of toplevel binop matches it, use build2 instead of parser_build_binary_op. (c_parser_omp_atomic): Handle OpenMP 4.0 atomics. (c_parser_omp_for_loop): Adjust c_parser_binary_expression caller. * c-tree.h (c_tree_equal): New prototype. * c-typeck.c (c_tree_equal): New function. * parser.c (cp_parser_omp_atomic): Never restart unless structured_block is true. * c-c++-common/gomp/atomic-15.c: Adjust for C diagnostics. * testsuite/libgomp.c/atomic-14.c: Add parens to make it valid. * testsuite/libgomp.c/atomic-15.c: New test. * testsuite/libgomp.c/atomic-16.c: New test. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gomp-4_0-branch@196816 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/c/ChangeLog.gomp | 14 ++ gcc/c/c-parser.c | 233 +++++++++++--------- gcc/c/c-tree.h | 1 + gcc/c/c-typeck.c | 202 +++++++++++++++++ gcc/cp/ChangeLog.gomp | 3 + gcc/cp/parser.c | 2 +- gcc/testsuite/ChangeLog.gomp | 2 + gcc/testsuite/c-c++-common/gomp/atomic-15.c | 32 +-- libgomp/ChangeLog.gomp | 4 + libgomp/testsuite/libgomp.c/atomic-14.c | 4 +- libgomp/testsuite/libgomp.c/atomic-15.c | 99 +++++++++ libgomp/testsuite/libgomp.c/atomic-16.c | 58 +++++ 12 files changed, 525 insertions(+), 129 deletions(-) create mode 100644 libgomp/testsuite/libgomp.c/atomic-15.c create mode 100644 libgomp/testsuite/libgomp.c/atomic-16.c diff --git a/gcc/c/ChangeLog.gomp b/gcc/c/ChangeLog.gomp index 9941433abf05f..75e2aebae0449 100644 --- a/gcc/c/ChangeLog.gomp +++ b/gcc/c/ChangeLog.gomp @@ -1,5 +1,19 @@ 2013-03-20 Jakub Jelinek + * c-parser.c (c_parser_expr_no_commas): Add omp_atomic_lhs argument + with default value, pass it down to c_parser_conditional_expression. + (c_parser_conditional_expression): Add omp_atomic_lhs argument, pass + it down to c_parser_binary_expression. Don't pass PREC_NONE to + it. Adjust recursive call. + (c_parser_binary_expression): Remove prec argument, add omp_atomic_lhs + argument. Always start from PREC_NONE, if omp_atomic_lhs is non-NULL + and one of the arguments of toplevel binop matches it, use build2 + instead of parser_build_binary_op. + (c_parser_omp_atomic): Handle OpenMP 4.0 atomics. + (c_parser_omp_for_loop): Adjust c_parser_binary_expression caller. + * c-tree.h (c_tree_equal): New prototype. + * c-typeck.c (c_tree_equal): New function. + * c-parser.c (c_parser_omp_atomic): Adjust comment. Add another argument to c_finish_omp_atomic. diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index e9f07ee745dc8..f1b39fda60396 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -1155,11 +1155,12 @@ static tree c_parser_asm_statement (c_parser *); static tree c_parser_asm_operands (c_parser *); static tree c_parser_asm_goto_operands (c_parser *); static tree c_parser_asm_clobbers (c_parser *); -static struct c_expr c_parser_expr_no_commas (c_parser *, struct c_expr *); +static struct c_expr c_parser_expr_no_commas (c_parser *, struct c_expr *, + tree = NULL_TREE); static struct c_expr c_parser_conditional_expression (c_parser *, - struct c_expr *); + struct c_expr *, tree); static struct c_expr c_parser_binary_expression (c_parser *, struct c_expr *, - enum c_parser_prec); + tree); static struct c_expr c_parser_cast_expression (c_parser *, struct c_expr *); static struct c_expr c_parser_unary_expression (c_parser *); static struct c_expr c_parser_sizeof_expression (c_parser *); @@ -5338,13 +5339,14 @@ c_parser_asm_goto_operands (c_parser *parser) error. */ static struct c_expr -c_parser_expr_no_commas (c_parser *parser, struct c_expr *after) +c_parser_expr_no_commas (c_parser *parser, struct c_expr *after, + tree omp_atomic_lhs) { struct c_expr lhs, rhs, ret; enum tree_code code; location_t op_location, exp_location; gcc_assert (!after || c_dialect_objc ()); - lhs = c_parser_conditional_expression (parser, after); + lhs = c_parser_conditional_expression (parser, after, omp_atomic_lhs); op_location = c_parser_peek_token (parser)->location; switch (c_parser_peek_token (parser)->type) { @@ -5417,14 +5419,15 @@ c_parser_expr_no_commas (c_parser *parser, struct c_expr *after) */ static struct c_expr -c_parser_conditional_expression (c_parser *parser, struct c_expr *after) +c_parser_conditional_expression (c_parser *parser, struct c_expr *after, + tree omp_atomic_lhs) { struct c_expr cond, exp1, exp2, ret; location_t cond_loc, colon_loc, middle_loc; gcc_assert (!after || c_dialect_objc ()); - cond = c_parser_binary_expression (parser, after, PREC_NONE); + cond = c_parser_binary_expression (parser, after, omp_atomic_lhs); if (c_parser_next_token_is_not (parser, CPP_QUERY)) return cond; @@ -5476,7 +5479,7 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after) } { location_t exp2_loc = c_parser_peek_token (parser)->location; - exp2 = c_parser_conditional_expression (parser, NULL); + exp2 = c_parser_conditional_expression (parser, NULL, NULL_TREE); exp2 = default_function_array_read_conversion (exp2_loc, exp2); } c_inhibit_evaluation_warnings -= cond.value == truthvalue_true_node; @@ -5563,7 +5566,7 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after) static struct c_expr c_parser_binary_expression (c_parser *parser, struct c_expr *after, - enum c_parser_prec prec) + tree omp_atomic_lhs) { /* A binary expression is parsed using operator-precedence parsing, with the operands being cast expressions. All the binary @@ -5621,16 +5624,30 @@ c_parser_binary_expression (c_parser *parser, struct c_expr *after, stack[sp].expr \ = default_function_array_read_conversion (stack[sp].loc, \ stack[sp].expr); \ - stack[sp - 1].expr = parser_build_binary_op (stack[sp].loc, \ - stack[sp].op, \ - stack[sp - 1].expr, \ - stack[sp].expr); \ + if (__builtin_expect (omp_atomic_lhs != NULL_TREE, 0) && sp == 1 \ + && c_parser_peek_token (parser)->type == CPP_SEMICOLON \ + && ((1 << stack[sp].prec) \ + & (1 << (PREC_BITOR | PREC_BITXOR | PREC_BITAND | PREC_SHIFT \ + | PREC_ADD | PREC_MULT))) \ + && stack[sp].op != TRUNC_MOD_EXPR \ + && stack[0].expr.value != error_mark_node \ + && stack[1].expr.value != error_mark_node \ + && (c_tree_equal (stack[0].expr.value, omp_atomic_lhs) \ + || c_tree_equal (stack[1].expr.value, omp_atomic_lhs))) \ + stack[0].expr.value \ + = build2 (stack[1].op, TREE_TYPE (stack[0].expr.value), \ + stack[0].expr.value, stack[1].expr.value); \ + else \ + stack[sp - 1].expr = parser_build_binary_op (stack[sp].loc, \ + stack[sp].op, \ + stack[sp - 1].expr, \ + stack[sp].expr); \ sp--; \ } while (0) gcc_assert (!after || c_dialect_objc ()); stack[0].loc = c_parser_peek_token (parser)->location; stack[0].expr = c_parser_cast_expression (parser, after); - stack[0].prec = prec; + stack[0].prec = PREC_NONE; sp = 0; while (true) { @@ -5719,11 +5736,7 @@ c_parser_binary_expression (c_parser *parser, struct c_expr *after, } binary_loc = c_parser_peek_token (parser)->location; while (oprec <= stack[sp].prec) - { - if (sp == 0) - goto out; - POP; - } + POP; c_parser_consume_token (parser); switch (ocode) { @@ -9521,10 +9534,12 @@ c_parser_omp_atomic (location_t loc, c_parser *parser) { tree lhs = NULL_TREE, rhs = NULL_TREE, v = NULL_TREE; tree lhs1 = NULL_TREE, rhs1 = NULL_TREE; - tree stmt, orig_lhs; + tree stmt, orig_lhs, unfolded_lhs = NULL_TREE, unfolded_lhs1 = NULL_TREE; enum tree_code code = OMP_ATOMIC, opcode = NOP_EXPR; - struct c_expr rhs_expr; + struct c_expr expr; + location_t eloc; bool structured_block = false; + bool swapped = false; if (c_parser_next_token_is (parser, CPP_NAME)) { @@ -9596,7 +9611,11 @@ c_parser_omp_atomic (location_t loc, c_parser *parser) /* For structured_block case we don't know yet whether old or new x should be captured. */ restart: - lhs = c_parser_unary_expression (parser).value; + eloc = c_parser_peek_token (parser)->location; + expr = c_parser_unary_expression (parser); + lhs = expr.value; + expr = default_function_array_conversion (eloc, expr); + unfolded_lhs = expr.value; lhs = c_fully_fold (lhs, false, NULL); orig_lhs = lhs; switch (TREE_CODE (lhs)) @@ -9623,6 +9642,7 @@ c_parser_omp_atomic (location_t loc, c_parser *parser) /* FALLTHROUGH */ case PREINCREMENT_EXPR: lhs = TREE_OPERAND (lhs, 0); + unfolded_lhs = NULL_TREE; opcode = PLUS_EXPR; rhs = integer_one_node; break; @@ -9633,6 +9653,7 @@ c_parser_omp_atomic (location_t loc, c_parser *parser) /* FALLTHROUGH */ case PREDECREMENT_EXPR: lhs = TREE_OPERAND (lhs, 0); + unfolded_lhs = NULL_TREE; opcode = MINUS_EXPR; rhs = integer_one_node; break; @@ -9658,6 +9679,7 @@ c_parser_omp_atomic (location_t loc, c_parser *parser) /* This is pre or post increment. */ rhs = TREE_OPERAND (lhs, 1); lhs = TREE_OPERAND (lhs, 0); + unfolded_lhs = NULL_TREE; opcode = NOP_EXPR; if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block @@ -9672,6 +9694,7 @@ c_parser_omp_atomic (location_t loc, c_parser *parser) /* This is pre or post decrement. */ rhs = TREE_OPERAND (lhs, 1); lhs = TREE_OPERAND (lhs, 0); + unfolded_lhs = NULL_TREE; opcode = NOP_EXPR; if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block @@ -9712,87 +9735,67 @@ c_parser_omp_atomic (location_t loc, c_parser *parser) opcode = BIT_XOR_EXPR; break; case CPP_EQ: - if (structured_block || code == OMP_ATOMIC) + c_parser_consume_token (parser); + eloc = c_parser_peek_token (parser)->location; + expr = c_parser_expr_no_commas (parser, NULL, unfolded_lhs); + rhs1 = expr.value; + switch (TREE_CODE (rhs1)) { - location_t aloc = c_parser_peek_token (parser)->location; - location_t rhs_loc; - enum c_parser_prec oprec = PREC_NONE; - - c_parser_consume_token (parser); - rhs1 = c_parser_unary_expression (parser).value; - rhs1 = c_fully_fold (rhs1, false, NULL); - if (rhs1 == error_mark_node) - goto saw_error; - switch (c_parser_peek_token (parser)->type) + case MULT_EXPR: + case TRUNC_DIV_EXPR: + case PLUS_EXPR: + case MINUS_EXPR: + case LSHIFT_EXPR: + case RSHIFT_EXPR: + case BIT_AND_EXPR: + case BIT_IOR_EXPR: + case BIT_XOR_EXPR: + if (c_tree_equal (TREE_OPERAND (rhs1, 0), unfolded_lhs)) { - case CPP_SEMICOLON: - if (code == OMP_ATOMIC_CAPTURE_NEW) - { - code = OMP_ATOMIC_CAPTURE_OLD; - v = lhs; - lhs = NULL_TREE; - lhs1 = rhs1; - rhs1 = NULL_TREE; - c_parser_consume_token (parser); - goto restart; - } - c_parser_error (parser, - "invalid form of %<#pragma omp atomic%>"); - goto saw_error; - case CPP_MULT: - opcode = MULT_EXPR; - oprec = PREC_MULT; - break; - case CPP_DIV: - opcode = TRUNC_DIV_EXPR; - oprec = PREC_MULT; - break; - case CPP_PLUS: - opcode = PLUS_EXPR; - oprec = PREC_ADD; - break; - case CPP_MINUS: - opcode = MINUS_EXPR; - oprec = PREC_ADD; - break; - case CPP_LSHIFT: - opcode = LSHIFT_EXPR; - oprec = PREC_SHIFT; - break; - case CPP_RSHIFT: - opcode = RSHIFT_EXPR; - oprec = PREC_SHIFT; - break; - case CPP_AND: - opcode = BIT_AND_EXPR; - oprec = PREC_BITAND; - break; - case CPP_OR: - opcode = BIT_IOR_EXPR; - oprec = PREC_BITOR; - break; - case CPP_XOR: - opcode = BIT_XOR_EXPR; - oprec = PREC_BITXOR; - break; - default: - c_parser_error (parser, - "invalid operator for %<#pragma omp atomic%>"); - goto saw_error; + opcode = TREE_CODE (rhs1); + rhs = c_fully_fold (TREE_OPERAND (rhs1, 1), false, NULL); + rhs1 = c_fully_fold (TREE_OPERAND (rhs1, 0), false, NULL); + goto stmt_done; + } + if (c_tree_equal (TREE_OPERAND (rhs1, 1), unfolded_lhs)) + { + opcode = TREE_CODE (rhs1); + rhs = c_fully_fold (TREE_OPERAND (rhs1, 0), false, NULL); + rhs1 = c_fully_fold (TREE_OPERAND (rhs1, 1), false, NULL); + swapped = !commutative_tree_code (opcode); + goto stmt_done; + } + break; + case ERROR_MARK: + goto saw_error; + default: + break; + } + if (c_parser_peek_token (parser)->type == CPP_SEMICOLON) + { + if (structured_block && code == OMP_ATOMIC_CAPTURE_NEW) + { + code = OMP_ATOMIC_CAPTURE_OLD; + v = lhs; + lhs = NULL_TREE; + expr = default_function_array_read_conversion (eloc, expr); + unfolded_lhs1 = expr.value; + lhs1 = c_fully_fold (unfolded_lhs1, false, NULL); + rhs1 = NULL_TREE; + c_parser_consume_token (parser); + goto restart; + } + if (structured_block) + { + opcode = NOP_EXPR; + expr = default_function_array_read_conversion (eloc, expr); + rhs = c_fully_fold (expr.value, false, NULL); + rhs1 = NULL_TREE; + goto stmt_done; } - loc = aloc; - c_parser_consume_token (parser); - rhs_loc = c_parser_peek_token (parser)->location; - if (commutative_tree_code (opcode)) - oprec = (enum c_parser_prec) (oprec - 1); - rhs_expr = c_parser_binary_expression (parser, NULL, oprec); - rhs_expr = default_function_array_read_conversion (rhs_loc, - rhs_expr); - rhs = rhs_expr.value; - rhs = c_fully_fold (rhs, false, NULL); - goto stmt_done; } - /* FALLTHROUGH */ + c_parser_error (parser, "invalid form of %<#pragma omp atomic%>"); + goto saw_error; default: c_parser_error (parser, "invalid operator for %<#pragma omp atomic%>"); @@ -9803,12 +9806,10 @@ c_parser_omp_atomic (location_t loc, c_parser *parser) c_finish_omp_atomic. */ loc = c_parser_peek_token (parser)->location; c_parser_consume_token (parser); - { - location_t rhs_loc = c_parser_peek_token (parser)->location; - rhs_expr = c_parser_expression (parser); - rhs_expr = default_function_array_read_conversion (rhs_loc, rhs_expr); - } - rhs = rhs_expr.value; + eloc = c_parser_peek_token (parser)->location; + expr = c_parser_expression (parser); + expr = default_function_array_read_conversion (eloc, expr); + rhs = expr.value; rhs = c_fully_fold (rhs, false, NULL); break; } @@ -9823,7 +9824,11 @@ c_parser_omp_atomic (location_t loc, c_parser *parser) goto saw_error; if (!c_parser_require (parser, CPP_EQ, "expected %<=%>")) goto saw_error; - lhs1 = c_parser_unary_expression (parser).value; + eloc = c_parser_peek_token (parser)->location; + expr = c_parser_unary_expression (parser); + lhs1 = expr.value; + expr = default_function_array_read_conversion (eloc, expr); + unfolded_lhs1 = expr.value; lhs1 = c_fully_fold (lhs1, false, NULL); if (lhs1 == error_mark_node) goto saw_error; @@ -9834,8 +9839,16 @@ c_parser_omp_atomic (location_t loc, c_parser *parser) c_parser_require (parser, CPP_CLOSE_BRACE, "expected %<}%>"); } done: - stmt = c_finish_omp_atomic (loc, code, opcode, lhs, rhs, v, lhs1, rhs1, - false); + if (unfolded_lhs && unfolded_lhs1 + && !c_tree_equal (unfolded_lhs, unfolded_lhs1)) + { + error ("%<#pragma omp atomic capture%> uses two different " + "expressions for memory"); + stmt = error_mark_node; + } + else + stmt = c_finish_omp_atomic (loc, code, opcode, lhs, rhs, v, lhs1, rhs1, + swapped); if (stmt != error_mark_node) add_stmt (stmt); @@ -10003,8 +10016,8 @@ c_parser_omp_for_loop (location_t loc, if (c_parser_next_token_is_not (parser, CPP_SEMICOLON)) { location_t cond_loc = c_parser_peek_token (parser)->location; - struct c_expr cond_expr = c_parser_binary_expression (parser, NULL, - PREC_NONE); + struct c_expr cond_expr + = c_parser_binary_expression (parser, NULL, NULL_TREE); cond = cond_expr.value; cond = c_objc_common_truthvalue_conversion (cond_loc, cond); diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index d1a871daa683c..c4210a53f67af 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -640,6 +640,7 @@ extern tree c_finish_omp_task (location_t, tree, tree); extern tree c_finish_omp_clauses (tree); extern tree c_build_va_arg (location_t, tree, tree); extern tree c_finish_transaction (location_t, tree, int); +extern bool c_tree_equal (tree, tree); /* Set to 0 at beginning of a function definition, set to 1 if a return statement that specifies a return value is seen. */ diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index ddb6d39774f95..789029401b3a1 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -10897,3 +10897,205 @@ c_build_va_arg (location_t loc, tree expr, tree type) "C++ requires promoted type, not enum type, in %"); return build_va_arg (loc, expr, type); } + +/* Return truthvalue of whether T1 is the same tree structure as T2. + Return 1 if they are the same. Return 0 if they are different. */ + +bool +c_tree_equal (tree t1, tree t2) +{ + enum tree_code code1, code2; + + if (t1 == t2) + return true; + if (!t1 || !t2) + return false; + + for (code1 = TREE_CODE (t1); + CONVERT_EXPR_CODE_P (code1) + || code1 == NON_LVALUE_EXPR; + code1 = TREE_CODE (t1)) + t1 = TREE_OPERAND (t1, 0); + for (code2 = TREE_CODE (t2); + CONVERT_EXPR_CODE_P (code2) + || code2 == NON_LVALUE_EXPR; + code2 = TREE_CODE (t2)) + t2 = TREE_OPERAND (t2, 0); + + /* They might have become equal now. */ + if (t1 == t2) + return true; + + if (code1 != code2) + return false; + + switch (code1) + { + case INTEGER_CST: + return TREE_INT_CST_LOW (t1) == TREE_INT_CST_LOW (t2) + && TREE_INT_CST_HIGH (t1) == TREE_INT_CST_HIGH (t2); + + case REAL_CST: + return REAL_VALUES_EQUAL (TREE_REAL_CST (t1), TREE_REAL_CST (t2)); + + case STRING_CST: + return TREE_STRING_LENGTH (t1) == TREE_STRING_LENGTH (t2) + && !memcmp (TREE_STRING_POINTER (t1), TREE_STRING_POINTER (t2), + TREE_STRING_LENGTH (t1)); + + case FIXED_CST: + return FIXED_VALUES_IDENTICAL (TREE_FIXED_CST (t1), + TREE_FIXED_CST (t2)); + + case COMPLEX_CST: + return c_tree_equal (TREE_REALPART (t1), TREE_REALPART (t2)) + && c_tree_equal (TREE_IMAGPART (t1), TREE_IMAGPART (t2)); + + case VECTOR_CST: + return operand_equal_p (t1, t2, OEP_ONLY_CONST); + + case CONSTRUCTOR: + /* We need to do this when determining whether or not two + non-type pointer to member function template arguments + are the same. */ + if (!comptypes (TREE_TYPE (t1), TREE_TYPE (t2)) + || CONSTRUCTOR_NELTS (t1) != CONSTRUCTOR_NELTS (t2)) + return false; + { + tree field, value; + unsigned int i; + FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (t1), i, field, value) + { + constructor_elt *elt2 = CONSTRUCTOR_ELT (t2, i); + if (!c_tree_equal (field, elt2->index) + || !c_tree_equal (value, elt2->value)) + return false; + } + } + return true; + + case TREE_LIST: + if (!c_tree_equal (TREE_PURPOSE (t1), TREE_PURPOSE (t2))) + return false; + if (!c_tree_equal (TREE_VALUE (t1), TREE_VALUE (t2))) + return false; + return c_tree_equal (TREE_CHAIN (t1), TREE_CHAIN (t2)); + + case SAVE_EXPR: + return c_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0)); + + case CALL_EXPR: + { + tree arg1, arg2; + call_expr_arg_iterator iter1, iter2; + if (!c_tree_equal (CALL_EXPR_FN (t1), CALL_EXPR_FN (t2))) + return false; + for (arg1 = first_call_expr_arg (t1, &iter1), + arg2 = first_call_expr_arg (t2, &iter2); + arg1 && arg2; + arg1 = next_call_expr_arg (&iter1), + arg2 = next_call_expr_arg (&iter2)) + if (!c_tree_equal (arg1, arg2)) + return false; + if (arg1 || arg2) + return false; + return true; + } + + case TARGET_EXPR: + { + tree o1 = TREE_OPERAND (t1, 0); + tree o2 = TREE_OPERAND (t2, 0); + + /* Special case: if either target is an unallocated VAR_DECL, + it means that it's going to be unified with whatever the + TARGET_EXPR is really supposed to initialize, so treat it + as being equivalent to anything. */ + if (TREE_CODE (o1) == VAR_DECL && DECL_NAME (o1) == NULL_TREE + && !DECL_RTL_SET_P (o1)) + /*Nop*/; + else if (TREE_CODE (o2) == VAR_DECL && DECL_NAME (o2) == NULL_TREE + && !DECL_RTL_SET_P (o2)) + /*Nop*/; + else if (!c_tree_equal (o1, o2)) + return false; + + return c_tree_equal (TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1)); + } + + case COMPONENT_REF: + if (TREE_OPERAND (t1, 1) != TREE_OPERAND (t2, 1)) + return false; + return c_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0)); + + case PARM_DECL: + case VAR_DECL: + case CONST_DECL: + case FIELD_DECL: + case FUNCTION_DECL: + case IDENTIFIER_NODE: + case SSA_NAME: + return false; + + case TREE_VEC: + { + unsigned ix; + if (TREE_VEC_LENGTH (t1) != TREE_VEC_LENGTH (t2)) + return false; + for (ix = TREE_VEC_LENGTH (t1); ix--;) + if (!c_tree_equal (TREE_VEC_ELT (t1, ix), + TREE_VEC_ELT (t2, ix))) + return false; + return true; + } + + default: + break; + } + + switch (TREE_CODE_CLASS (code1)) + { + case tcc_unary: + case tcc_binary: + case tcc_comparison: + case tcc_expression: + case tcc_vl_exp: + case tcc_reference: + case tcc_statement: + { + int i, n = TREE_OPERAND_LENGTH (t1); + + switch (code1) + { + case PREINCREMENT_EXPR: + case PREDECREMENT_EXPR: + case POSTINCREMENT_EXPR: + case POSTDECREMENT_EXPR: + n = 1; + break; + case ARRAY_REF: + n = 2; + break; + default: + break; + } + + if (TREE_CODE_CLASS (code1) == tcc_vl_exp + && n != TREE_OPERAND_LENGTH (t2)) + return false; + + for (i = 0; i < n; ++i) + if (!c_tree_equal (TREE_OPERAND (t1, i), TREE_OPERAND (t2, i))) + return false; + + return true; + } + + case tcc_type: + return comptypes (t1, t2); + default: + gcc_unreachable (); + } + /* We can get here with --disable-checking. */ + return false; +} diff --git a/gcc/cp/ChangeLog.gomp b/gcc/cp/ChangeLog.gomp index 1b783e6eba471..b679679370376 100644 --- a/gcc/cp/ChangeLog.gomp +++ b/gcc/cp/ChangeLog.gomp @@ -1,5 +1,8 @@ 2013-03-20 Jakub Jelinek + * parser.c (cp_parser_omp_atomic): Never restart unless + structured_block is true. + * parser.c (cp_parser_binary_expression): Handle no_toplevel_fold_p even for binary operations other than comparison. (cp_parser_omp_atomic): Handle parsing OpenMP 4.0 atomics. diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 514574e0d97dc..cf4242e2637a0 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -26769,7 +26769,7 @@ cp_parser_omp_atomic (cp_parser *parser, cp_token *pragma_tok) switch (token->type) { case CPP_SEMICOLON: - if (code == OMP_ATOMIC_CAPTURE_NEW) + if (structured_block && code == OMP_ATOMIC_CAPTURE_NEW) { code = OMP_ATOMIC_CAPTURE_OLD; v = lhs; diff --git a/gcc/testsuite/ChangeLog.gomp b/gcc/testsuite/ChangeLog.gomp index 466f81a56ab23..5791a4fe98afc 100644 --- a/gcc/testsuite/ChangeLog.gomp +++ b/gcc/testsuite/ChangeLog.gomp @@ -1,5 +1,7 @@ 2013-03-20 Jakub Jelinek + * c-c++-common/gomp/atomic-15.c: Adjust for C diagnostics. + * c-c++-common/gomp/atomic-15.c: Remove error test that is now valid in OpenMP 4.0. diff --git a/gcc/testsuite/c-c++-common/gomp/atomic-15.c b/gcc/testsuite/c-c++-common/gomp/atomic-15.c index d77a858829b84..5e669fa3543d8 100644 --- a/gcc/testsuite/c-c++-common/gomp/atomic-15.c +++ b/gcc/testsuite/c-c++-common/gomp/atomic-15.c @@ -8,37 +8,37 @@ main () { int v; #pragma omp atomic - x = x * 7 + 6; /* { dg-error "expected" } */ + x = x * 7 + 6; /* { dg-error "expected|invalid form of" } */ #pragma omp atomic - x = x * 7 ^ 6; /* { dg-error "expected" } */ + x = x * 7 ^ 6; /* { dg-error "expected|invalid form of" } */ #pragma omp atomic update - x = x - 8 + 6; /* { dg-error "expected" } */ + x = x - 8 + 6; /* { dg-error "expected|invalid form of" } */ #pragma omp atomic - x = x ^ 7 | 2; /* { dg-error "expected" } */ + x = x ^ 7 | 2; /* { dg-error "expected|invalid form of" } */ #pragma omp atomic - x = x / 7 * 2; /* { dg-error "expected" } */ + x = x / 7 * 2; /* { dg-error "expected|invalid form of" } */ #pragma omp atomic - x = x / 7 / 2; /* { dg-error "expected" } */ + x = x / 7 / 2; /* { dg-error "expected|invalid form of" } */ #pragma omp atomic capture - { v = x; x = x * 7 + 6; } /* { dg-error "expected" } */ + { v = x; x = x * 7 + 6; } /* { dg-error "expected" "" { target c++ } } */ #pragma omp atomic capture - { v = x; x = x * 7 ^ 6; } /* { dg-error "expected" } */ + { v = x; x = x * 7 ^ 6; } /* { dg-error "expected" "" { target c++ } } */ #pragma omp atomic capture - { v = x; x = x - 8 + 6; } /* { dg-error "expected" } */ + { v = x; x = x - 8 + 6; } /* { dg-error "expected" "" { target c++ } } */ #pragma omp atomic capture - { v = x; x = x ^ 7 | 2; } /* { dg-error "expected" } */ + { v = x; x = x ^ 7 | 2; } /* { dg-error "expected" "" { target c++ } } */ #pragma omp atomic capture - { v = x; x = x / 7 * 2; } /* { dg-error "expected" } */ + { v = x; x = x / 7 * 2; } /* { dg-error "expected" "" { target c++ } } */ #pragma omp atomic capture - { v = x; x = x / 7 / 2; } /* { dg-error "expected" } */ + { v = x; x = x / 7 / 2; } /* { dg-error "expected" "" { target c++ } } */ #pragma omp atomic capture - { x = x * 7 + 6; v = x; } /* { dg-error "expected" } */ + { x = x * 7 + 6; v = x; } /* { dg-error "expected|uses two different expressions for memory" } */ #pragma omp atomic capture - { x = x * 7 ^ 6; v = x; } /* { dg-error "expected" } */ + { x = x * 7 ^ 6; v = x; } /* { dg-error "expected|uses two different expressions for memory" } */ #pragma omp atomic capture - { x = x - 8 + 6; v = x; } /* { dg-error "expected" } */ + { x = x - 8 + 6; v = x; } /* { dg-error "expected|uses two different expressions for memory" } */ #pragma omp atomic capture - { x = x ^ 7 | 2; v = x; } /* { dg-error "expected" } */ + { x = x ^ 7 | 2; v = x; } /* { dg-error "expected|uses two different expressions for memory" } */ (void) v; return 0; } diff --git a/libgomp/ChangeLog.gomp b/libgomp/ChangeLog.gomp index a6eeb6bfed193..4b53d5b80ad59 100644 --- a/libgomp/ChangeLog.gomp +++ b/libgomp/ChangeLog.gomp @@ -1,5 +1,9 @@ 2013-03-20 Jakub Jelinek + * testsuite/libgomp.c/atomic-14.c: Add parens to make it valid. + * testsuite/libgomp.c/atomic-15.c: New test. + * testsuite/libgomp.c/atomic-16.c: New test. + * testsuite/libgomp.c++/atomic-10.C: New test. * testsuite/libgomp.c++/atomic-11.C: New test. * testsuite/libgomp.c++/atomic-12.C: New test. diff --git a/libgomp/testsuite/libgomp.c/atomic-14.c b/libgomp/testsuite/libgomp.c/atomic-14.c index 593665046c5c3..9046d80220d4c 100644 --- a/libgomp/testsuite/libgomp.c/atomic-14.c +++ b/libgomp/testsuite/libgomp.c/atomic-14.c @@ -16,7 +16,7 @@ main () #pragma omp atomic update x = x + 7; #pragma omp atomic - x = x + 7 + 6; + x = x + (7 + 6); #pragma omp atomic update x = x + 2 * 3; #pragma omp atomic @@ -65,7 +65,7 @@ main () if (v != -8) abort (); #pragma omp atomic - x = x * -4 / 2; + x = x * (-4 / 2); #pragma omp atomic read v = x; if (v != 16) diff --git a/libgomp/testsuite/libgomp.c/atomic-15.c b/libgomp/testsuite/libgomp.c/atomic-15.c new file mode 100644 index 0000000000000..58331f4a90bfd --- /dev/null +++ b/libgomp/testsuite/libgomp.c/atomic-15.c @@ -0,0 +1,99 @@ +// { dg-do run } + +extern void abort (void); +int x = 6; + +int +main () +{ + int v, l = 2, s = 1; + #pragma omp atomic + x = -3 + x; + #pragma omp atomic read + v = x; + if (v != 3) + abort (); + #pragma omp atomic update + x = 3 * 2 * 1 + x; + #pragma omp atomic read + v = x; + if (v != 9) + abort (); + #pragma omp atomic capture + v = x = x | 16; + if (v != 25) + abort (); + #pragma omp atomic capture + v = x = x + 14 * 2 / 4; + if (v != 32) + abort (); + #pragma omp atomic capture + v = x = 5 | x; + if (v != 37) + abort (); + #pragma omp atomic capture + v = x = 40 + 12 - 2 - 7 - x; + if (v != 6) + abort (); + #pragma omp atomic read + v = x; + if (v != 6) + abort (); + #pragma omp atomic capture + { v = x; x = 3 + x; } + if (v != 6) + abort (); + #pragma omp atomic capture + { v = x; x = -1 * -1 * -1 * -1 - x; } + if (v != 9) + abort (); + #pragma omp atomic read + v = x; + if (v != -8) + abort (); + #pragma omp atomic capture + { x = 2 * 2 - x; v = x; } + if (v != 12) + abort (); + #pragma omp atomic capture + { x = 7 & x; v = x; } + if (v != 4) + abort (); + #pragma omp atomic capture + { v = x; x = 6; } + if (v != 4) + abort (); + #pragma omp atomic read + v = x; + if (v != 6) + abort (); + #pragma omp atomic capture + { v = x; x = 7 * 8 + 23; } + if (v != 6) + abort (); + #pragma omp atomic read + v = x; + if (v != 79) + abort (); + #pragma omp atomic capture + { v = x; x = 23 + 6 * 4; } + if (v != 79) + abort (); + #pragma omp atomic read + v = x; + if (v != 47) + abort (); + #pragma omp atomic capture + { v = x; x = l ? 17 : 12; } + if (v != 47) + abort (); + #pragma omp atomic capture + { v = x; x = l = s++ + 3; } + if (v != 17 || l != 4 || s != 2) + abort (); + #pragma omp atomic read + v = x; + if (v != 4) + abort (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c/atomic-16.c b/libgomp/testsuite/libgomp.c/atomic-16.c new file mode 100644 index 0000000000000..d33f670ec1f5a --- /dev/null +++ b/libgomp/testsuite/libgomp.c/atomic-16.c @@ -0,0 +1,58 @@ +// { dg-do run } + +extern void abort (void); +int x = 6, cnt; + +int +foo (void) +{ + return cnt++; +} + +int +main () +{ + int v, *p; + p = &x; + #pragma omp atomic update + p[foo (), 0] = 16 + 6 - p[foo (), 0]; + #pragma omp atomic read + v = x; + if (cnt != 2 || v != 16) + abort (); + #pragma omp atomic capture + v = p[foo () + foo (), 0] = p[foo () + foo (), 0] + 3; + if (cnt != 6 || v != 19) + abort (); + #pragma omp atomic capture + v = p[foo (), 0] = 12 * 1 / 2 + (foo (), 0) + p[foo (), 0]; + if (cnt != 9 || v != 25) + abort (); + #pragma omp atomic capture + { + v = p[foo () & 0]; p[foo () & 0] = (foo (), 1) * 9 - p[foo () & 0]; + } + if (cnt != 13 || v != 25) + abort (); + #pragma omp atomic read + v = x; + if (v != -16) + abort (); + #pragma omp atomic capture + { + p[0 & foo ()] = 16 - 2 + 3 + p[0 & foo ()]; v = p[0 & foo ()]; + } + if (cnt != 16 || v != 1) + abort (); + #pragma omp atomic capture + { + v = p[foo (), 0]; p[foo (), 0] = (foo (), 7) ? 13 : foo () + 6; + } + if (cnt != 19 || v != 1) + abort (); + #pragma omp atomic read + v = x; + if (v != 13) + abort (); + return 0; +} From cf12b7f0a4ba583b64f39aa60a5419d6d097e785 Mon Sep 17 00:00:00 2001 From: burnus Date: Wed, 20 Mar 2013 10:07:05 +0000 Subject: [PATCH 04/63] 2013-03-20 Tobias Burnus * env.c (handle_omp_display_env): New function. (initialize_env): Use it. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gomp-4_0-branch@196817 138bc75d-0d04-0410-961f-82ee72b054a4 --- libgomp/ChangeLog.gomp | 5 ++ libgomp/env.c | 122 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 127 insertions(+) diff --git a/libgomp/ChangeLog.gomp b/libgomp/ChangeLog.gomp index 4b53d5b80ad59..10c25869216a8 100644 --- a/libgomp/ChangeLog.gomp +++ b/libgomp/ChangeLog.gomp @@ -1,3 +1,8 @@ +2013-03-20 Tobias Burnus + + * env.c (handle_omp_display_env): New function. + (initialize_env): Use it. + 2013-03-20 Jakub Jelinek * testsuite/libgomp.c/atomic-14.c: Add parens to make it valid. diff --git a/libgomp/env.c b/libgomp/env.c index 65cbba83e6c02..5cd11649d7725 100644 --- a/libgomp/env.c +++ b/libgomp/env.c @@ -29,6 +29,10 @@ #include "libgomp_f.h" #include #include +#include +#ifdef HAVE_INTTYPES_H +# include /* For PRIu64. */ +#endif #ifdef STRING_WITH_STRINGS # include # include @@ -565,6 +569,122 @@ parse_affinity (void) return false; } + +static void +handle_omp_display_env (bool proc_bind, unsigned long stacksize, + int wait_policy) +{ + const char *env; + bool display = false; + bool verbose = false; + int i; + + env = getenv ("OMP_DISPLAY_ENV"); + if (env == NULL) + return; + + while (isspace ((unsigned char) *env)) + ++env; + if (strncasecmp (env, "true", 4) == 0) + { + env += 4; + } + else if (strncasecmp (env, "false", 5) == 0) + { + display = false; + env += 5; + } + else if (strncasecmp (env, "verbose", 7) == 0) + { + display = true; + verbose = true; + env += 7; + } + else + env = "X"; + while (isspace ((unsigned char) *env)) + ++env; + if (*env != '\0') + gomp_error ("Invalid value for environment variable OMP_DISPLAY_ENV"); + + if (!display) + return; + + fputs ("\nOPENMP DISPLAY ENVIRONMENT BEGIN\n", stderr); + + fputs (" _OPENMP = '201107'\n", stderr); + fprintf (stderr, " OMP_DYNAMIC = '%s'\n", + gomp_global_icv.dyn_var ? "TRUE" : "FALSE"); + fprintf (stderr, " OMP_NESTED = '%s'\n", + gomp_global_icv.nest_var ? "TRUE" : "FALSE"); + + fprintf (stderr, " OMP_NUM_THREADS = '%lu", gomp_global_icv.nthreads_var); + for (i = 1; i < gomp_nthreads_var_list_len; i++) + fprintf (stderr, ",%lu", gomp_nthreads_var_list[i]); + fputs ("'\n", stderr); + + fprintf (stderr, " OMP_SCHEDULE = '"); + switch (gomp_global_icv.run_sched_var) + { + case GFS_RUNTIME: + fputs ("RUNTIME", stderr); + break; + case GFS_STATIC: + fputs ("STATIC", stderr); + break; + case GFS_DYNAMIC: + fputs ("DYNAMIC", stderr); + break; + case GFS_GUIDED: + fputs ("GUIDED", stderr); + break; + case GFS_AUTO: + fputs ("AUTO", stderr); + break; + } + fputs ("'\n", stderr); + + fprintf (stderr, " OMP_PROC_BIND = '%s'\n", + proc_bind ? "TRUE" : "FALSE"); + fprintf (stderr, " OMP_STACKSIZE = '%lu'\n", stacksize); + + /* GOMP's default value is actually neither active nor passive. */ + fprintf (stderr, " OMP_WAIT_POLICY = '%s'\n", + wait_policy > 0 ? "ACTIVE" : "PASSIVE"); + fprintf (stderr, " OMP_THREAD_LIMIT = '%lu'\n", + gomp_thread_limit_var); + fprintf (stderr, " OMP_MAX_ACTIVE_LEVELS = '%lu'\n", + gomp_max_active_levels_var); + +/* FIXME: Unimplemented OpenMP 4.0 environment variables. + fprintf (stderr, " OMP_PLACES = ''\n"); + fprintf (stderr, " OMP_CANCELLATION = ''\n"); + fprintf (stderr, " OMP_DEFAULT_DEVICE = ''\n"); */ + + if (verbose) + { + fputs (" GOMP_CPU_AFFINITY = '", stderr); + if (gomp_cpu_affinity_len) + { + fprintf (stderr, "%d", gomp_cpu_affinity[0]); + for (i = 1; i < gomp_cpu_affinity_len; i++) + fprintf (stderr, " %d", gomp_cpu_affinity[i]); + } + fputs ("'\n", stderr); + fprintf (stderr, " GOMP_STACKSIZE = '%lu'\n", stacksize); +#ifdef HAVE_INTTYPES_H + fprintf (stderr, " GOMP_SPINCOUNT = '%"PRIu64"'\n", + (uint64_t) gomp_spin_count_var); +#else + fprintf (stderr, " GOMP_SPINCOUNT = '%lu'\n", + (unsigned long) gomp_spin_count_var); +#endif + } + + fputs ("OPENMP DISPLAY ENVIRONMENT END\n", stderr); +} + + static void __attribute__((constructor)) initialize_env (void) { @@ -645,6 +765,8 @@ initialize_env (void) if (err != 0) gomp_error ("Stack size change failed: %s", strerror (err)); } + + handle_omp_display_env (bind_var, stacksize, wait_policy); } From 7bbcc3b9aa095845471a5f451e57742b0d0bada8 Mon Sep 17 00:00:00 2001 From: burnus Date: Wed, 20 Mar 2013 10:07:58 +0000 Subject: [PATCH 05/63] 2013-03-20 Tobias Burnus * libgomp.texi (Environment Variables): Minor cleanup, update section refs to OpenMP 4.0rc2. (OMP_DISPLAY_ENV, GOMP_SPINCOUNT): Document these environment variables. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gomp-4_0-branch@196818 138bc75d-0d04-0410-961f-82ee72b054a4 --- libgomp/ChangeLog.gomp | 7 ++++ libgomp/libgomp.texi | 86 ++++++++++++++++++++++++++++++++---------- 2 files changed, 74 insertions(+), 19 deletions(-) diff --git a/libgomp/ChangeLog.gomp b/libgomp/ChangeLog.gomp index 10c25869216a8..218b730b0b155 100644 --- a/libgomp/ChangeLog.gomp +++ b/libgomp/ChangeLog.gomp @@ -1,3 +1,10 @@ +2013-03-20 Tobias Burnus + + * libgomp.texi (Environment Variables): Minor cleanup, + update section refs to OpenMP 4.0rc2. + (OMP_DISPLAY_ENV, GOMP_SPINCOUNT): Document these + environment variables. + 2013-03-20 Tobias Burnus * env.c (handle_omp_display_env): New function. diff --git a/libgomp/libgomp.texi b/libgomp/libgomp.texi index 40c3830e59968..36431ab59b848 100644 --- a/libgomp/libgomp.texi +++ b/libgomp/libgomp.texi @@ -1083,12 +1083,9 @@ guaranteed not to change during the execution of the program. @node Environment Variables @chapter Environment Variables -The variables @env{OMP_DYNAMIC}, @env{OMP_MAX_ACTIVE_LEVELS}, -@env{OMP_NESTED}, @env{OMP_NUM_THREADS}, @env{OMP_SCHEDULE}, -@env{OMP_STACKSIZE},@env{OMP_THREAD_LIMIT} and @env{OMP_WAIT_POLICY} -are defined by section 4 of the OpenMP specifications in version 3.1, -while @env{GOMP_CPU_AFFINITY} and @env{GOMP_STACKSIZE} are GNU -extensions. +The environment variables which beginning with @env{OMP_} are defined by +section 4 of the OpenMP specification in version 4.0, while those +beginning with @env{GOMP_} are GNU extensions. @menu * OMP_DYNAMIC:: Dynamic adjustment of threads @@ -1099,9 +1096,11 @@ extensions. * OMP_SCHEDULE:: How threads are scheduled * OMP_THREAD_LIMIT:: Set the maximum number of threads * OMP_WAIT_POLICY:: How waiting threads are handled +* OMP_DISPLAY_ENV:: Show OpenMP version and environment variables * OMP_PROC_BIND:: Whether theads may be moved between CPUs * GOMP_CPU_AFFINITY:: Bind threads to specific CPUs * GOMP_STACKSIZE:: Set default thread stack size +* GOMP_SPINCOUNT:: Set the busy-wait spin count @end menu @@ -1119,7 +1118,7 @@ disabled by default. @ref{omp_set_dynamic} @item @emph{Reference}: -@uref{http://www.openmp.org/, OpenMP specifications v3.1}, section 4.3 +@uref{http://www.openmp.org/, OpenMP specifications v4.0}, section 4.3 @end table @@ -1137,7 +1136,7 @@ If undefined, the number of active levels is unlimited. @ref{omp_set_max_active_levels} @item @emph{Reference}: -@uref{http://www.openmp.org/, OpenMP specifications v3.1}, section 4.8 +@uref{http://www.openmp.org/, OpenMP specifications v4.0}, section 4.9 @end table @@ -1157,7 +1156,7 @@ regions are disabled by default. @ref{omp_set_nested} @item @emph{Reference}: -@uref{http://www.openmp.org/, OpenMP specifications v3.1}, section 4.5 +@uref{http://www.openmp.org/, OpenMP specifications v4.0}, section 4.6 @end table @@ -1177,7 +1176,7 @@ level. If undefined one thread per CPU is used. @ref{omp_set_num_threads} @item @emph{Reference}: -@uref{http://www.openmp.org/, OpenMP specifications v3.1}, section 4.2 +@uref{http://www.openmp.org/, OpenMP specifications v4.0}, section 4.2 @end table @@ -1198,7 +1197,7 @@ dynamic scheduling and a chunk size of 1 is used. @ref{omp_set_schedule} @item @emph{Reference}: -@uref{http://www.openmp.org/, OpenMP specifications v3.1}, sections 2.5.1 and 4.1 +@uref{http://www.openmp.org/, OpenMP specifications v4.0}, sections 2.7.1 and 4.1 @end table @@ -1218,7 +1217,7 @@ stack size is left unchanged. If undefined, the stack size is system dependent. @item @emph{Reference}: -@uref{http://www.openmp.org/, OpenMP specifications v3.1}, sections 4.6 +@uref{http://www.openmp.org/, OpenMP specifications v4.0}, section 4.7 @end table @@ -1237,7 +1236,7 @@ the number of threads is not limited. @ref{omp_get_thread_limit} @item @emph{Reference}: -@uref{http://www.openmp.org/, OpenMP specifications v3.1}, section 4.9 +@uref{http://www.openmp.org/, OpenMP specifications v4.0}, section 4.10 @end table @@ -1250,10 +1249,14 @@ the number of threads is not limited. Specifies whether waiting threads should be active or passive. If the value is @code{PASSIVE}, waiting threads should not consume CPU power while waiting; while the value is @code{ACTIVE} specifies that -they should. +they should. If undefined, threads wait actively for a short time +before waiting passively. + +@item @emph{See also}: +@ref{GOMP_SPINCOUNT} @item @emph{Reference}: -@uref{http://www.openmp.org/, OpenMP specifications v3.1}, sections 4.7 +@uref{http://www.openmp.org/, OpenMP specifications v4.0}, section 4.8 @end table @@ -1264,14 +1267,32 @@ they should. @table @asis @item @emph{Description}: Specifies whether threads may be moved between processors. If set to -@code{true}, OpenMP theads should not be moved, if set to @code{false} -they may be moved. +@code{TRUE}, OpenMP theads should not be moved, if set to @code{FALSE} +they may be moved. If undefined, threads may move between processors. @item @emph{See also}: @ref{GOMP_CPU_AFFINITY} @item @emph{Reference}: -@uref{http://www.openmp.org/, OpenMP specifications v3.1}, sections 4.4 +@uref{http://www.openmp.org/, OpenMP specifications v4.0}, section 4.4 +@end table + + + +@node OMP_DISPLAY_ENV +@section @env{OMP_DISPLAY_ENV} -- Show OpenMP version and environment variables +@cindex Environment Variable +@table @asis +@item @emph{Description}: +If set to @code{TRUE}, the OpenMP version number and the values +associated with the OpenMP environment variables are printed to @code{stderr}. +If set to @code{VERBOSE}, it additionally shows the value of the environment +variables which are GNU extensions. If undefined or set to @code{FALSE}, +this information will not be shown. + + +@item @emph{Reference}: +@uref{http://www.openmp.org/, OpenMP specifications v4.0}, section 4.12 @end table @@ -1298,7 +1319,7 @@ Fortran, may be used to query the setting of the @code{GOMP_CPU_AFFINITY} environment variable. A defined CPU affinity on startup cannot be changed or disabled during the runtime of the application. -If this environment variable is omitted, the host system will handle the +If this environment variable is omitted, the host system will handle the assignment of threads to CPUs. @item @emph{See also}: @@ -1331,6 +1352,33 @@ GCC Patches Mailinglist} +@node GOMP_SPINCOUNT +@section @env{GOMP_SPINCOUNT} -- Set the busy-wait spin count +@cindex Environment Variable +@cindex Implementation specific setting +@table @asis +@item @emph{Description}: +Determines how long a threads waits actively with consuming CPU power +before waiting passively without consuming CPU power. The value may be +either @code{INFINITE}, @code{INFINITY} to always wait actively or an +integer which gives the number of spins of the busy-wait loop. The +integer may optionally be followed by the following suffixes acting +as multiplication factors: @code{k} (kilo, thousand), @code{M} (mega, +million), @code{G} (giga, billion), or @code{T} (tera, trillion). +If undefined, 0 is used when @env{OMP_WAIT_POLICY} is @code{PASSIVE}, +300,000 is used when @env{OMP_WAIT_POLICY} is undefined and +30 billion is used when @env{OMP_WAIT_POLICY} is @code{ACTIVE}. +If there are more OpenMP threads than available CPUs, 1000 and 100 +spins are used for @env{OMP_WAIT_POLICY} being @code{ACTIVE} or +undefined, respectively; unless the @env{GOMP_SPINCOUNT} is lower +or @env{OMP_WAIT_POLICY} is @code{PASSIVE}. + +@item @emph{See also}: +@ref{OMP_WAIT_POLICY} +@end table + + + @c --------------------------------------------------------------------- @c The libgomp ABI @c --------------------------------------------------------------------- From db14f322c6e7706889d678a1394850099feadaef Mon Sep 17 00:00:00 2001 From: jakub Date: Wed, 27 Mar 2013 12:04:03 +0000 Subject: [PATCH 06/63] * gimple-pretty-print.c (dump_gimple_omp_for): Handle different GIMPLE_OMP_FOR kinds. * tree.def (OMP_SIMD, OMP_FOR_SIMD, OMP_DISTRIBUTE): New tree codes. * gimple.h (enum gf_mask): Add GF_OMP_FOR_KIND_MASK, GF_OMP_FOR_KIND_FOR, GF_OMP_FOR_KIND_SIMD, GF_OMP_FOR_KIND_FOR_SIMD and GF_OMP_FOR_KIND_DISTRIBUTE. (gimple_omp_for_kind, gimple_omp_for_set_kind): New inline functions. * gimplify.c (is_gimple_stmt, gimplify_omp_for, gimplify_expr): Handle OMP_SIMD, OMP_FOR_SIMD and OMP_DISTRIBUTE. * tree.c (omp_clause_num_ops, omp_clause_code_name, walk_tree_1): Handle new OpenMP 4.0 clauses. * tree-pretty-print.c (dump_omp_clause): Likewise. (dump_generic_node): Handle OMP_SIMD, OMP_FOR_SIMD and OMP_DISTRIBUTE. * tree.h (enum omp_clause_code): Add OMP_CLAUSE_LINEAR, OMP_CLAUSE_ALIGNED, OMP_CLAUSE_DEPEND, OMP_CLAUSE_FROM, OMP_CLAUSE_TO, OMP_CLAUSE_UNIFORM, OMP_CLAUSE_MAP, OMP_CLAUSE_DEVICE, OMP_CLAUSE_DIST_SCHEDULE, OMP_CLAUSE_INBRANCH, OMP_CLAUSE_NOTINBRANCH, OMP_CLAUSE_NUM_TEAMS, OMP_CLAUSE_PROC_BIND, OMP_CLAUSE_SAFELEN, OMP_CLAUSE_SIMDLEN, OMP_CLAUSE_FOR, OMP_CLAUSE_PARALLEL, OMP_CLAUSE_SECTIONS and OMP_CLAUSE_TASKGROUP. (OMP_LOOP_CHECK): Define. (OMP_FOR_BODY, OMP_FOR_CLAUSES, OMP_FOR_INIT, OMP_FOR_COND, OMP_FOR_INCR, OMP_FOR_PRE_BODY): Use OMP_LOOP_CHECK instead of OMP_FOR_CHECK. (OMP_CLAUSE_DECL): Extend check range up to OMP_CLAUSE_MAP. (OMP_CLAUSE_LINEAR_STEP, OMP_CLAUSE_ALIGNED_ALIGNMENT, OMP_CLAUSE_NUM_TEAMS_EXPR, OMP_CLAUSE_DEVICE_ID, OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR, OMP_CLAUSE_SAFELEN_EXPR, OMP_CLAUSE_SIMDLEN_EXPR): Define. (enum omp_clause_depend_kind, enum omp_clause_map_kind, enum omp_clause_proc_bind_kind): New enums. (OMP_CLAUSE_DEPEND_KIND, OMP_CLAUSE_MAP_KIND, OMP_CLAUSE_PROC_BIND_KIND): Define. (struct tree_omp_clause): Add subcode.depend_kind, subcode.map_kind and subcode.proc_bind_kind. (find_omp_clause): New prototype. * omp-builtins.def (BUILT_IN_GOMP_CANCEL, BUILT_IN_GOMP_CANCELLATION_POINT): New built-ins. * tree-flow.h (find_omp_clause): Remove prototype. c/ * c-parser.c (c_parser_omp_all_clauses): Change mask argument type from unsigned to omp_clause_mask. (c_parser_omp_for_loop): Adjust c_finish_omp_for caller. (OMP_FOR_CLAUSE_MASK, OMP_SECTIONS_CLAUSE_MASK, OMP_PARALLEL_CLAUSE_MASK, OMP_SINGLE_CLAUSE_MASK, OMP_TASK_CLAUSE_MASK): Use OMP_CLAUSE_MASK_1 instead of 1. (c_parser_omp_parallel): Use omp_clause_mask type instead of unsigned for mask, use OMP_CLAUSE_MASK_1 instead of 1 for masks. cp/ * cp-tree.h (OMP_FOR_GIMPLIFYING_P): Use OMP_LOOP_CHECK instead of OMP_FOR_CHECK. (finish_omp_for): Add enum tree_code second argument. (finish_omp_cancel, finish_omp_cancellation_point): New prototypes. * cp-gimplify.c (cp_gimplify_expr, cp_genericize_r): Handle OMP_SIMD, OMP_FOR_SIMD and OMP_DISTRIBUTE. * semantics.c (finish_omp_clauses): Handle new OpenMP 4.0 clauses. (finish_omp_for): Add code argument, pass it down to make_node or c_finish_omp_for. (finish_omp_cancel, finish_omp_cancellation_point): New functions. * parser.c (cp_parser_omp_clause_name): Add parsing of new OpenMP 4.0 clauses. (cp_parser_omp_var_list_no_open): Add COLON argument, if non-NULL, accept termination by colon instead of closing paren. (cp_parser_omp_var_list, cp_parser_omp_clause_reduction): Adjust callers. (cp_parser_omp_clause_branch, cp_parser_omp_clause_cancelkind, cp_parser_omp_clause_num_teams, cp_parser_omp_clause_aligned, cp_parser_omp_clause_linear, cp_parser_omp_clause_depend, cp_parser_omp_clause_map, cp_parser_omp_clause_device, cp_parser_omp_clause_dist_schedule, cp_parser_omp_clause_proc_bind): New functions. (cp_parser_omp_all_clauses): Change mask argument's type to omp_clause_mask from unsigned. Fix c_name for PRAGMA_OMP_CLAUSE_UNTIED. Handle new OpenMP 4.0 clauses. (cp_parser_omp_for_loop): Add code argument. Pass it down to finish_omp_for. (OMP_SIMD_CLAUSE_MASK): Define. (cp_parser_omp_simd): New function. (OMP_FOR_CLAUSE_MASK, OMP_SECTIONS_CLAUSE_MASK, OMP_PARALLEL_CLAUSE_MASK, OMP_SINGLE_CLAUSE_MASK, OMP_TASK_CLAUSE_MASK): Use OMP_CLAUSE_MASK_1 instead of 1. (cp_parser_omp_for): Handle parsing of #pragma omp for simd. (cp_parser_omp_parallel): Handle parsing of #pragma omp parallel for simd. Use omp_clause_mask type instead of unsigned for mask, use OMP_CLAUSE_MASK_1 instead of 1 for masks. (OMP_CANCEL_CLAUSE_MASK, OMP_CANCELLATION_POINT_CLAUSE_MASK): Define. (cp_parser_omp_cancel, cp_parser_omp_cancellation_point): New functions. (cp_parser_omp_construct): Handle PRAGMA_OMP_SIMD, PRAGMA_OMP_CANCEL and PRAGMA_OMP_CANCELLATION_POINT. (cp_parser_pragma): Handle PRAGMA_OMP_SIMD. * pt.c (tsubst_expr): Handle OMP_SIMD, OMP_FOR_SIMD and OMP_DISTRIBUTE. Pass down TREE_CODE to finish_omp_for. fortran/ * f95-lang.c (ATTR_NULL): Define. c-family/ * c-omp.c (c_finish_omp_for): Add code argument, pass it down to make_code. (c_split_parallel_clauses): Handle OMP_CLAUSE_SAFELEN, OMP_CLAUSE_ALIGNED and OMP_CLAUSE_LINEAR. * c-pragma.h (enum pragma_kind): Add PRAGMA_OMP_CANCEL, PRAGMA_OMP_CANCELLATION_POINT, PRAGMA_OMP_DECLARE_REDUCTION, PRAGMA_OMP_DECLARE_SIMD, PRAGMA_OMP_DECLARE_TARGET, PRAGMA_OMP_DISTRIBUTE, PRAGMA_OMP_END_DECLARE_TARGET, PRAGMA_OMP_FOR_SIMD, PRAGMA_OMP_PARALLEL_FOR_SIMD, PRAGMA_OMP_SIMD, PRAGMA_OMP_TARGET, PRAGMA_OMP_TARGET_DATA, PRAGMA_OMP_TARGET_UPDATE, PRAGMA_OMP_TASKGROUP and PRAGMA_OMP_TEAMS. (enum pragma_omp_clause): Add PRAGMA_OMP_CLAUSE_ALIGNED, PRAGMA_OMP_CLAUSE_DEPEND, PRAGMA_OMP_CLAUSE_DEVICE, PRAGMA_OMP_CLAUSE_DIST_SCHEDULE, PRAGMA_OMP_CLAUSE_FOR, PRAGMA_OMP_CLAUSE_FROM, PRAGMA_OMP_CLAUSE_INBRANCH, PRAGMA_OMP_CLAUSE_LINEAR, PRAGMA_OMP_CLAUSE_MAP, PRAGMA_OMP_CLAUSE_NOTINBRANCH, PRAGMA_OMP_CLAUSE_NUM_TEAMS, PRAGMA_OMP_CLAUSE_PARALLEL, PRAGMA_OMP_CLAUSE_PROC_BIND, PRAGMA_OMP_CLAUSE_SAFELEN, PRAGMA_OMP_CLAUSE_SECTIONS, PRAGMA_OMP_CLAUSE_SIMDLEN, PRAGMA_OMP_CLAUSE_TASKGROUP, PRAGMA_OMP_CLAUSE_TO and PRAGMA_OMP_CLAUSE_UNIFORM. * c-pragma.c (omp_pragmas): Add new OpenMP 4.0 constructs. * c-common.h (c_finish_omp_for): Add enum tree_code as second argument. (OMP_CLAUSE_MASK_1): Define. (omp_clause_mask): For HWI >= 64 new typedef for unsigned HOST_WIDE_INT, otherwise a class with needed ctors and operators. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gomp-4_0-branch@197161 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog.gomp | 47 +++ gcc/c-family/ChangeLog.gomp | 31 ++ gcc/c-family/c-common.h | 128 +++++- gcc/c-family/c-omp.c | 9 +- gcc/c-family/c-pragma.c | 8 + gcc/c-family/c-pragma.h | 42 +- gcc/c/ChangeLog.gomp | 11 + gcc/c/c-parser.c | 87 ++-- gcc/cp/ChangeLog.gomp | 48 +++ gcc/cp/cp-gimplify.c | 8 +- gcc/cp/cp-tree.h | 14 +- gcc/cp/parser.c | 818 +++++++++++++++++++++++++++++++++--- gcc/cp/pt.c | 7 +- gcc/cp/semantics.c | 285 ++++++++++++- gcc/fortran/ChangeLog.gomp | 9 + gcc/fortran/f95-lang.c | 3 +- gcc/gimple-pretty-print.c | 40 +- gcc/gimple.h | 26 ++ gcc/gimplify.c | 22 + gcc/omp-builtins.def | 4 + gcc/tree-flow.h | 1 - gcc/tree-pretty-print.c | 224 ++++++++-- gcc/tree.c | 65 ++- gcc/tree.def | 12 + gcc/tree.h | 140 +++++- 25 files changed, 1919 insertions(+), 170 deletions(-) create mode 100644 gcc/ChangeLog.gomp create mode 100644 gcc/fortran/ChangeLog.gomp diff --git a/gcc/ChangeLog.gomp b/gcc/ChangeLog.gomp new file mode 100644 index 0000000000000..e14fe71770065 --- /dev/null +++ b/gcc/ChangeLog.gomp @@ -0,0 +1,47 @@ +2013-03-27 Jakub Jelinek + + * gimple-pretty-print.c (dump_gimple_omp_for): Handle different + GIMPLE_OMP_FOR kinds. + * tree.def (OMP_SIMD, OMP_FOR_SIMD, OMP_DISTRIBUTE): New tree codes. + * gimple.h (enum gf_mask): Add GF_OMP_FOR_KIND_MASK, + GF_OMP_FOR_KIND_FOR, GF_OMP_FOR_KIND_SIMD, GF_OMP_FOR_KIND_FOR_SIMD + and GF_OMP_FOR_KIND_DISTRIBUTE. + (gimple_omp_for_kind, gimple_omp_for_set_kind): New inline functions. + * gimplify.c (is_gimple_stmt, gimplify_omp_for, gimplify_expr): Handle + OMP_SIMD, OMP_FOR_SIMD and OMP_DISTRIBUTE. + * tree.c (omp_clause_num_ops, omp_clause_code_name, walk_tree_1): + Handle new OpenMP 4.0 clauses. + * tree-pretty-print.c (dump_omp_clause): Likewise. + (dump_generic_node): Handle OMP_SIMD, OMP_FOR_SIMD and OMP_DISTRIBUTE. + * tree.h (enum omp_clause_code): Add OMP_CLAUSE_LINEAR, + OMP_CLAUSE_ALIGNED, OMP_CLAUSE_DEPEND, OMP_CLAUSE_FROM, OMP_CLAUSE_TO, + OMP_CLAUSE_UNIFORM, OMP_CLAUSE_MAP, OMP_CLAUSE_DEVICE, + OMP_CLAUSE_DIST_SCHEDULE, OMP_CLAUSE_INBRANCH, OMP_CLAUSE_NOTINBRANCH, + OMP_CLAUSE_NUM_TEAMS, OMP_CLAUSE_PROC_BIND, OMP_CLAUSE_SAFELEN, + OMP_CLAUSE_SIMDLEN, OMP_CLAUSE_FOR, OMP_CLAUSE_PARALLEL, + OMP_CLAUSE_SECTIONS and OMP_CLAUSE_TASKGROUP. + (OMP_LOOP_CHECK): Define. + (OMP_FOR_BODY, OMP_FOR_CLAUSES, OMP_FOR_INIT, OMP_FOR_COND, + OMP_FOR_INCR, OMP_FOR_PRE_BODY): Use OMP_LOOP_CHECK instead of + OMP_FOR_CHECK. + (OMP_CLAUSE_DECL): Extend check range up to OMP_CLAUSE_MAP. + (OMP_CLAUSE_LINEAR_STEP, OMP_CLAUSE_ALIGNED_ALIGNMENT, + OMP_CLAUSE_NUM_TEAMS_EXPR, OMP_CLAUSE_DEVICE_ID, + OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR, OMP_CLAUSE_SAFELEN_EXPR, + OMP_CLAUSE_SIMDLEN_EXPR): Define. + (enum omp_clause_depend_kind, enum omp_clause_map_kind, + enum omp_clause_proc_bind_kind): New enums. + (OMP_CLAUSE_DEPEND_KIND, OMP_CLAUSE_MAP_KIND, + OMP_CLAUSE_PROC_BIND_KIND): Define. + (struct tree_omp_clause): Add subcode.depend_kind, subcode.map_kind + and subcode.proc_bind_kind. + (find_omp_clause): New prototype. + * omp-builtins.def (BUILT_IN_GOMP_CANCEL, + BUILT_IN_GOMP_CANCELLATION_POINT): New built-ins. + * tree-flow.h (find_omp_clause): Remove prototype. + +Copyright (C) 2013 Free Software Foundation, Inc. + +Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. diff --git a/gcc/c-family/ChangeLog.gomp b/gcc/c-family/ChangeLog.gomp index c31948f85ddb6..73d9dda26720f 100644 --- a/gcc/c-family/ChangeLog.gomp +++ b/gcc/c-family/ChangeLog.gomp @@ -1,3 +1,34 @@ +2013-03-27 Jakub Jelinek + + * c-omp.c (c_finish_omp_for): Add code argument, pass it down to + make_code. + (c_split_parallel_clauses): Handle OMP_CLAUSE_SAFELEN, + OMP_CLAUSE_ALIGNED and OMP_CLAUSE_LINEAR. + * c-pragma.h (enum pragma_kind): Add PRAGMA_OMP_CANCEL, + PRAGMA_OMP_CANCELLATION_POINT, PRAGMA_OMP_DECLARE_REDUCTION, + PRAGMA_OMP_DECLARE_SIMD, PRAGMA_OMP_DECLARE_TARGET, + PRAGMA_OMP_DISTRIBUTE, PRAGMA_OMP_END_DECLARE_TARGET, + PRAGMA_OMP_FOR_SIMD, PRAGMA_OMP_PARALLEL_FOR_SIMD, PRAGMA_OMP_SIMD, + PRAGMA_OMP_TARGET, PRAGMA_OMP_TARGET_DATA, PRAGMA_OMP_TARGET_UPDATE, + PRAGMA_OMP_TASKGROUP and PRAGMA_OMP_TEAMS. + (enum pragma_omp_clause): Add PRAGMA_OMP_CLAUSE_ALIGNED, + PRAGMA_OMP_CLAUSE_DEPEND, PRAGMA_OMP_CLAUSE_DEVICE, + PRAGMA_OMP_CLAUSE_DIST_SCHEDULE, PRAGMA_OMP_CLAUSE_FOR, + PRAGMA_OMP_CLAUSE_FROM, PRAGMA_OMP_CLAUSE_INBRANCH, + PRAGMA_OMP_CLAUSE_LINEAR, PRAGMA_OMP_CLAUSE_MAP, + PRAGMA_OMP_CLAUSE_NOTINBRANCH, PRAGMA_OMP_CLAUSE_NUM_TEAMS, + PRAGMA_OMP_CLAUSE_PARALLEL, PRAGMA_OMP_CLAUSE_PROC_BIND, + PRAGMA_OMP_CLAUSE_SAFELEN, PRAGMA_OMP_CLAUSE_SECTIONS, + PRAGMA_OMP_CLAUSE_SIMDLEN, PRAGMA_OMP_CLAUSE_TASKGROUP, + PRAGMA_OMP_CLAUSE_TO and PRAGMA_OMP_CLAUSE_UNIFORM. + * c-pragma.c (omp_pragmas): Add new OpenMP 4.0 constructs. + * c-common.h (c_finish_omp_for): Add enum tree_code as second + argument. + (OMP_CLAUSE_MASK_1): Define. + (omp_clause_mask): For HWI >= 64 new typedef for + unsigned HOST_WIDE_INT, otherwise a class with needed ctors and + operators. + 2013-03-20 Jakub Jelinek * c-omp.c (c_finish_omp_atomic): Add swapped argument, if true, diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index f5638bfac1486..57f2f6062f771 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -1039,7 +1039,8 @@ extern tree c_finish_omp_atomic (location_t, enum tree_code, enum tree_code, extern void c_finish_omp_flush (location_t); extern void c_finish_omp_taskwait (location_t); extern void c_finish_omp_taskyield (location_t); -extern tree c_finish_omp_for (location_t, tree, tree, tree, tree, tree, tree); +extern tree c_finish_omp_for (location_t, enum tree_code, tree, tree, tree, + tree, tree, tree); extern void c_split_parallel_clauses (location_t, tree, tree *, tree *); extern enum omp_clause_default_kind c_omp_predetermined_sharing (tree); @@ -1133,4 +1134,129 @@ enum stv_conv { extern enum stv_conv scalar_to_vector (location_t loc, enum tree_code code, tree op0, tree op1, bool); +#if HOST_BITS_PER_WIDE_INT >= 64 +typedef unsigned HOST_WIDE_INT omp_clause_mask; +# define OMP_CLAUSE_MASK_1 ((omp_clause_mask) 1) +#else +struct omp_clause_mask +{ + inline omp_clause_mask (); + inline omp_clause_mask (unsigned HOST_WIDE_INT l); + inline omp_clause_mask (unsigned HOST_WIDE_INT l, + unsigned HOST_WIDE_INT h); + inline omp_clause_mask &operator &= (omp_clause_mask); + inline omp_clause_mask &operator |= (omp_clause_mask); + inline omp_clause_mask operator ~ () const; + inline omp_clause_mask operator & (omp_clause_mask) const; + inline omp_clause_mask operator | (omp_clause_mask) const; + inline omp_clause_mask operator >> (int); + inline omp_clause_mask operator << (int); + inline bool operator == (omp_clause_mask) const; + unsigned HOST_WIDE_INT low, high; +}; + +inline +omp_clause_mask::omp_clause_mask () +{ +} + +inline +omp_clause_mask::omp_clause_mask (unsigned HOST_WIDE_INT l) +: low (l), high (0) +{ +} + +inline +omp_clause_mask::omp_clause_mask (unsigned HOST_WIDE_INT l, + unsigned HOST_WIDE_INT h) +: low (l), high (h) +{ +} + +inline omp_clause_mask & +omp_clause_mask::operator &= (omp_clause_mask b) +{ + low &= b.low; + high &= b.high; + return *this; +} + +inline omp_clause_mask & +omp_clause_mask::operator |= (omp_clause_mask b) +{ + low |= b.low; + high |= b.high; + return *this; +} + +inline omp_clause_mask +omp_clause_mask::operator ~ () const +{ + omp_clause_mask ret (~low, ~high); + return ret; +} + +inline omp_clause_mask +omp_clause_mask::operator | (omp_clause_mask b) const +{ + omp_clause_mask ret (low | b.low, high | b.high); + return ret; +} + +inline omp_clause_mask +omp_clause_mask::operator & (omp_clause_mask b) const +{ + omp_clause_mask ret (low & b.low, high & b.high); + return ret; +} + +inline omp_clause_mask +omp_clause_mask::operator << (int amount) +{ + omp_clause_mask ret; + if (amount >= HOST_BITS_PER_WIDE_INT) + { + ret.low = 0; + ret.high = low << (amount - HOST_BITS_PER_WIDE_INT); + } + else if (amount == 0) + ret = *this; + else + { + ret.low = low << amount; + ret.high = (low >> (HOST_BITS_PER_WIDE_INT - amount)) + | (high << amount); + } + return ret; +} + +inline omp_clause_mask +omp_clause_mask::operator >> (int amount) +{ + omp_clause_mask ret; + if (amount >= HOST_BITS_PER_WIDE_INT) + { + ret.low = high >> (amount - HOST_BITS_PER_WIDE_INT); + ret.high = 0; + } + else if (amount == 0) + ret = *this; + else + { + ret.low = (high << (HOST_BITS_PER_WIDE_INT - amount)) + | (low >> amount); + ret.high = high >> amount; + } + return ret; +} + +inline bool +omp_clause_mask::operator == (omp_clause_mask b) const +{ + return low == b.low && high == b.high; +} + +# define OMP_CLAUSE_MASK_1 omp_clause_mask (1) +#endif + #endif /* ! GCC_C_COMMON_H */ diff --git a/gcc/c-family/c-omp.c b/gcc/c-family/c-omp.c index 634923017eba3..91112b3f6d351 100644 --- a/gcc/c-family/c-omp.c +++ b/gcc/c-family/c-omp.c @@ -343,8 +343,8 @@ check_omp_for_incr_expr (location_t loc, tree exp, tree decl) the loop. */ tree -c_finish_omp_for (location_t locus, tree declv, tree initv, tree condv, - tree incrv, tree body, tree pre_body) +c_finish_omp_for (location_t locus, enum tree_code code, tree declv, + tree initv, tree condv, tree incrv, tree body, tree pre_body) { location_t elocus; bool fail = false; @@ -569,7 +569,7 @@ c_finish_omp_for (location_t locus, tree declv, tree initv, tree condv, return NULL; else { - tree t = make_node (OMP_FOR); + tree t = make_node (code); TREE_TYPE (t) = void_type_node; OMP_FOR_INIT (t) = initv; @@ -621,6 +621,9 @@ c_split_parallel_clauses (location_t loc, tree clauses, case OMP_CLAUSE_SCHEDULE: case OMP_CLAUSE_ORDERED: case OMP_CLAUSE_COLLAPSE: + case OMP_CLAUSE_SAFELEN: + case OMP_CLAUSE_ALIGNED: + case OMP_CLAUSE_LINEAR: OMP_CLAUSE_CHAIN (clauses) = *ws_clauses; *ws_clauses = clauses; break; diff --git a/gcc/c-family/c-pragma.c b/gcc/c-family/c-pragma.c index 7d8a1a6058cb7..b03ddc1d3bac4 100644 --- a/gcc/c-family/c-pragma.c +++ b/gcc/c-family/c-pragma.c @@ -1162,7 +1162,11 @@ struct omp_pragma_def { const char *name; unsigned int id; }; static const struct omp_pragma_def omp_pragmas[] = { { "atomic", PRAGMA_OMP_ATOMIC }, { "barrier", PRAGMA_OMP_BARRIER }, + { "cancel", PRAGMA_OMP_CANCEL }, + { "cancellation", PRAGMA_OMP_CANCELLATION_POINT }, { "critical", PRAGMA_OMP_CRITICAL }, + { "declare", PRAGMA_OMP_DECLARE_REDUCTION }, + { "end", PRAGMA_OMP_END_DECLARE_TARGET }, { "flush", PRAGMA_OMP_FLUSH }, { "for", PRAGMA_OMP_FOR }, { "master", PRAGMA_OMP_MASTER }, @@ -1170,10 +1174,14 @@ static const struct omp_pragma_def omp_pragmas[] = { { "parallel", PRAGMA_OMP_PARALLEL }, { "section", PRAGMA_OMP_SECTION }, { "sections", PRAGMA_OMP_SECTIONS }, + { "simd", PRAGMA_OMP_SIMD }, { "single", PRAGMA_OMP_SINGLE }, + { "target", PRAGMA_OMP_TARGET }, { "task", PRAGMA_OMP_TASK }, + { "taskgroup", PRAGMA_OMP_TASKGROUP }, { "taskwait", PRAGMA_OMP_TASKWAIT }, { "taskyield", PRAGMA_OMP_TASKYIELD }, + { "teams", PRAGMA_OMP_TEAMS }, { "threadprivate", PRAGMA_OMP_THREADPRIVATE } }; diff --git a/gcc/c-family/c-pragma.h b/gcc/c-family/c-pragma.h index 41215db00a08b..cd121d46c0008 100644 --- a/gcc/c-family/c-pragma.h +++ b/gcc/c-family/c-pragma.h @@ -29,21 +29,36 @@ typedef enum pragma_kind { PRAGMA_OMP_ATOMIC, PRAGMA_OMP_BARRIER, + PRAGMA_OMP_CANCEL, + PRAGMA_OMP_CANCELLATION_POINT, PRAGMA_OMP_CRITICAL, + PRAGMA_OMP_DECLARE_REDUCTION, + PRAGMA_OMP_DECLARE_SIMD, + PRAGMA_OMP_DECLARE_TARGET, + PRAGMA_OMP_DISTRIBUTE, + PRAGMA_OMP_END_DECLARE_TARGET, PRAGMA_OMP_FLUSH, PRAGMA_OMP_FOR, + PRAGMA_OMP_FOR_SIMD, PRAGMA_OMP_MASTER, PRAGMA_OMP_ORDERED, PRAGMA_OMP_PARALLEL, PRAGMA_OMP_PARALLEL_FOR, + PRAGMA_OMP_PARALLEL_FOR_SIMD, PRAGMA_OMP_PARALLEL_SECTIONS, PRAGMA_OMP_SECTION, PRAGMA_OMP_SECTIONS, + PRAGMA_OMP_SIMD, PRAGMA_OMP_SINGLE, + PRAGMA_OMP_TARGET, + PRAGMA_OMP_TARGET_DATA, + PRAGMA_OMP_TARGET_UPDATE, PRAGMA_OMP_TASK, + PRAGMA_OMP_TASKGROUP, PRAGMA_OMP_TASKWAIT, PRAGMA_OMP_TASKYIELD, PRAGMA_OMP_THREADPRIVATE, + PRAGMA_OMP_TEAMS, PRAGMA_GCC_PCH_PREPROCESS, @@ -51,28 +66,47 @@ typedef enum pragma_kind { } pragma_kind; -/* All clauses defined by OpenMP 2.5 and 3.0. +/* All clauses defined by OpenMP 2.5, 3.0, 3.1 and 4.0. Used internally by both C and C++ parsers. */ typedef enum pragma_omp_clause { PRAGMA_OMP_CLAUSE_NONE = 0, + PRAGMA_OMP_CLAUSE_ALIGNED, PRAGMA_OMP_CLAUSE_COLLAPSE, PRAGMA_OMP_CLAUSE_COPYIN, PRAGMA_OMP_CLAUSE_COPYPRIVATE, PRAGMA_OMP_CLAUSE_DEFAULT, + PRAGMA_OMP_CLAUSE_DEPEND, + PRAGMA_OMP_CLAUSE_DEVICE, + PRAGMA_OMP_CLAUSE_DIST_SCHEDULE, + PRAGMA_OMP_CLAUSE_FINAL, PRAGMA_OMP_CLAUSE_FIRSTPRIVATE, + PRAGMA_OMP_CLAUSE_FOR, + PRAGMA_OMP_CLAUSE_FROM, PRAGMA_OMP_CLAUSE_IF, + PRAGMA_OMP_CLAUSE_INBRANCH, PRAGMA_OMP_CLAUSE_LASTPRIVATE, + PRAGMA_OMP_CLAUSE_LINEAR, + PRAGMA_OMP_CLAUSE_MAP, + PRAGMA_OMP_CLAUSE_MERGEABLE, + PRAGMA_OMP_CLAUSE_NOTINBRANCH, PRAGMA_OMP_CLAUSE_NOWAIT, + PRAGMA_OMP_CLAUSE_NUM_TEAMS, PRAGMA_OMP_CLAUSE_NUM_THREADS, PRAGMA_OMP_CLAUSE_ORDERED, + PRAGMA_OMP_CLAUSE_PARALLEL, PRAGMA_OMP_CLAUSE_PRIVATE, + PRAGMA_OMP_CLAUSE_PROC_BIND, PRAGMA_OMP_CLAUSE_REDUCTION, + PRAGMA_OMP_CLAUSE_SAFELEN, PRAGMA_OMP_CLAUSE_SCHEDULE, + PRAGMA_OMP_CLAUSE_SECTIONS, PRAGMA_OMP_CLAUSE_SHARED, - PRAGMA_OMP_CLAUSE_UNTIED, - PRAGMA_OMP_CLAUSE_FINAL, - PRAGMA_OMP_CLAUSE_MERGEABLE + PRAGMA_OMP_CLAUSE_SIMDLEN, + PRAGMA_OMP_CLAUSE_TASKGROUP, + PRAGMA_OMP_CLAUSE_TO, + PRAGMA_OMP_CLAUSE_UNIFORM, + PRAGMA_OMP_CLAUSE_UNTIED } pragma_omp_clause; extern struct cpp_reader* parse_in; diff --git a/gcc/c/ChangeLog.gomp b/gcc/c/ChangeLog.gomp index 75e2aebae0449..5169f08ddb42d 100644 --- a/gcc/c/ChangeLog.gomp +++ b/gcc/c/ChangeLog.gomp @@ -1,3 +1,14 @@ +2013-03-27 Jakub Jelinek + + * c-parser.c (c_parser_omp_all_clauses): Change mask argument type + from unsigned to omp_clause_mask. + (c_parser_omp_for_loop): Adjust c_finish_omp_for caller. + (OMP_FOR_CLAUSE_MASK, OMP_SECTIONS_CLAUSE_MASK, + OMP_PARALLEL_CLAUSE_MASK, OMP_SINGLE_CLAUSE_MASK, + OMP_TASK_CLAUSE_MASK): Use OMP_CLAUSE_MASK_1 instead of 1. + (c_parser_omp_parallel): Use omp_clause_mask type instead of unsigned + for mask, use OMP_CLAUSE_MASK_1 instead of 1 for masks. + 2013-03-20 Jakub Jelinek * c-parser.c (c_parser_expr_no_commas): Add omp_atomic_lhs argument diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index f1b39fda60396..5b06803317463 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -9350,7 +9350,7 @@ c_parser_omp_clause_untied (c_parser *parser ATTRIBUTE_UNUSED, tree list) of clause default goes in *pdefault. */ static tree -c_parser_omp_all_clauses (c_parser *parser, unsigned int mask, +c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask, const char *where) { tree clauses = NULL; @@ -10156,7 +10156,8 @@ c_parser_omp_for_loop (location_t loc, an error from the initialization parsing. */ if (!fail) { - stmt = c_finish_omp_for (loc, declv, initv, condv, incrv, body, NULL); + stmt = c_finish_omp_for (loc, OMP_FOR, declv, initv, condv, + incrv, body, NULL); if (stmt) { if (par_clauses != NULL) @@ -10218,15 +10219,15 @@ c_parser_omp_for_loop (location_t loc, LOC is the location of the #pragma token. */ -#define OMP_FOR_CLAUSE_MASK \ - ( (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_REDUCTION) \ - | (1u << PRAGMA_OMP_CLAUSE_ORDERED) \ - | (1u << PRAGMA_OMP_CLAUSE_SCHEDULE) \ - | (1u << PRAGMA_OMP_CLAUSE_COLLAPSE) \ - | (1u << PRAGMA_OMP_CLAUSE_NOWAIT)) +#define OMP_FOR_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDERED) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SCHEDULE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) static tree c_parser_omp_for (location_t loc, c_parser *parser) @@ -10367,12 +10368,12 @@ c_parser_omp_sections_scope (location_t sections_loc, c_parser *parser) LOC is the location of the #pragma token. */ -#define OMP_SECTIONS_CLAUSE_MASK \ - ( (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_REDUCTION) \ - | (1u << PRAGMA_OMP_CLAUSE_NOWAIT)) +#define OMP_SECTIONS_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) static tree c_parser_omp_sections (location_t loc, c_parser *parser) @@ -10400,15 +10401,15 @@ c_parser_omp_sections (location_t loc, c_parser *parser) LOC is the location of the #pragma token. */ -#define OMP_PARALLEL_CLAUSE_MASK \ - ( (1u << PRAGMA_OMP_CLAUSE_IF) \ - | (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_DEFAULT) \ - | (1u << PRAGMA_OMP_CLAUSE_SHARED) \ - | (1u << PRAGMA_OMP_CLAUSE_COPYIN) \ - | (1u << PRAGMA_OMP_CLAUSE_REDUCTION) \ - | (1u << PRAGMA_OMP_CLAUSE_NUM_THREADS)) +#define OMP_PARALLEL_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COPYIN) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS)) static tree c_parser_omp_parallel (location_t loc, c_parser *parser) @@ -10416,7 +10417,7 @@ c_parser_omp_parallel (location_t loc, c_parser *parser) enum pragma_kind p_kind = PRAGMA_OMP_PARALLEL; const char *p_name = "#pragma omp parallel"; tree stmt, clauses, par_clause, ws_clause, block; - unsigned int mask = OMP_PARALLEL_CLAUSE_MASK; + omp_clause_mask mask = OMP_PARALLEL_CLAUSE_MASK; if (c_parser_next_token_is_keyword (parser, RID_FOR)) { @@ -10424,7 +10425,7 @@ c_parser_omp_parallel (location_t loc, c_parser *parser) p_kind = PRAGMA_OMP_PARALLEL_FOR; p_name = "#pragma omp parallel for"; mask |= OMP_FOR_CLAUSE_MASK; - mask &= ~(1u << PRAGMA_OMP_CLAUSE_NOWAIT); + mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT); } else if (c_parser_next_token_is (parser, CPP_NAME)) { @@ -10435,7 +10436,7 @@ c_parser_omp_parallel (location_t loc, c_parser *parser) p_kind = PRAGMA_OMP_PARALLEL_SECTIONS; p_name = "#pragma omp parallel sections"; mask |= OMP_SECTIONS_CLAUSE_MASK; - mask &= ~(1u << PRAGMA_OMP_CLAUSE_NOWAIT); + mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT); } } @@ -10481,11 +10482,11 @@ c_parser_omp_parallel (location_t loc, c_parser *parser) LOC is the location of the #pragma. */ -#define OMP_SINGLE_CLAUSE_MASK \ - ( (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_COPYPRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_NOWAIT)) +#define OMP_SINGLE_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COPYPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) static tree c_parser_omp_single (location_t loc, c_parser *parser) @@ -10508,15 +10509,15 @@ c_parser_omp_single (location_t loc, c_parser *parser) LOC is the location of the #pragma. */ -#define OMP_TASK_CLAUSE_MASK \ - ( (1u << PRAGMA_OMP_CLAUSE_IF) \ - | (1u << PRAGMA_OMP_CLAUSE_UNTIED) \ - | (1u << PRAGMA_OMP_CLAUSE_DEFAULT) \ - | (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_SHARED) \ - | (1u << PRAGMA_OMP_CLAUSE_FINAL) \ - | (1u << PRAGMA_OMP_CLAUSE_MERGEABLE)) +#define OMP_TASK_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_UNTIED) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FINAL) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MERGEABLE)) static tree c_parser_omp_task (location_t loc, c_parser *parser) diff --git a/gcc/cp/ChangeLog.gomp b/gcc/cp/ChangeLog.gomp index b679679370376..93128b9ef2c27 100644 --- a/gcc/cp/ChangeLog.gomp +++ b/gcc/cp/ChangeLog.gomp @@ -1,3 +1,51 @@ +2013-03-27 Jakub Jelinek + + * cp-tree.h (OMP_FOR_GIMPLIFYING_P): Use OMP_LOOP_CHECK instead of + OMP_FOR_CHECK. + (finish_omp_for): Add enum tree_code second argument. + (finish_omp_cancel, finish_omp_cancellation_point): New prototypes. + * cp-gimplify.c (cp_gimplify_expr, cp_genericize_r): Handle + OMP_SIMD, OMP_FOR_SIMD and OMP_DISTRIBUTE. + * semantics.c (finish_omp_clauses): Handle new OpenMP 4.0 clauses. + (finish_omp_for): Add code argument, pass it down to make_node + or c_finish_omp_for. + (finish_omp_cancel, finish_omp_cancellation_point): New functions. + * parser.c (cp_parser_omp_clause_name): Add parsing of new + OpenMP 4.0 clauses. + (cp_parser_omp_var_list_no_open): Add COLON argument, if non-NULL, + accept termination by colon instead of closing paren. + (cp_parser_omp_var_list, cp_parser_omp_clause_reduction): Adjust + callers. + (cp_parser_omp_clause_branch, cp_parser_omp_clause_cancelkind, + cp_parser_omp_clause_num_teams, cp_parser_omp_clause_aligned, + cp_parser_omp_clause_linear, cp_parser_omp_clause_depend, + cp_parser_omp_clause_map, cp_parser_omp_clause_device, + cp_parser_omp_clause_dist_schedule, cp_parser_omp_clause_proc_bind): + New functions. + (cp_parser_omp_all_clauses): Change mask argument's type to + omp_clause_mask from unsigned. Fix c_name for + PRAGMA_OMP_CLAUSE_UNTIED. Handle new OpenMP 4.0 clauses. + (cp_parser_omp_for_loop): Add code argument. Pass it down to + finish_omp_for. + (OMP_SIMD_CLAUSE_MASK): Define. + (cp_parser_omp_simd): New function. + (OMP_FOR_CLAUSE_MASK, OMP_SECTIONS_CLAUSE_MASK, + OMP_PARALLEL_CLAUSE_MASK, OMP_SINGLE_CLAUSE_MASK, + OMP_TASK_CLAUSE_MASK): Use OMP_CLAUSE_MASK_1 instead of 1. + (cp_parser_omp_for): Handle parsing of #pragma omp for simd. + (cp_parser_omp_parallel): Handle parsing of + #pragma omp parallel for simd. Use omp_clause_mask type + instead of unsigned for mask, use OMP_CLAUSE_MASK_1 instead + of 1 for masks. + (OMP_CANCEL_CLAUSE_MASK, OMP_CANCELLATION_POINT_CLAUSE_MASK): Define. + (cp_parser_omp_cancel, cp_parser_omp_cancellation_point): New + functions. + (cp_parser_omp_construct): Handle PRAGMA_OMP_SIMD, PRAGMA_OMP_CANCEL + and PRAGMA_OMP_CANCELLATION_POINT. + (cp_parser_pragma): Handle PRAGMA_OMP_SIMD. + * pt.c (tsubst_expr): Handle OMP_SIMD, OMP_FOR_SIMD and + OMP_DISTRIBUTE. Pass down TREE_CODE to finish_omp_for. + 2013-03-20 Jakub Jelinek * parser.c (cp_parser_omp_atomic): Never restart unless diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c index b2bfd0c1fdc00..f5fb62b720d59 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -669,6 +669,9 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) gcc_unreachable (); case OMP_FOR: + case OMP_SIMD: + case OMP_FOR_SIMD: + case OMP_DISTRIBUTE: ret = cp_gimplify_omp_for (expr_p, pre_p); break; @@ -1116,7 +1119,10 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data) genericize_continue_stmt (stmt_p); else if (TREE_CODE (stmt) == BREAK_STMT) genericize_break_stmt (stmt_p); - else if (TREE_CODE (stmt) == OMP_FOR) + else if (TREE_CODE (stmt) == OMP_FOR + || TREE_CODE (stmt) == OMP_SIMD + || TREE_CODE (stmt) == OMP_FOR_SIMD + || TREE_CODE (stmt) == OMP_DISTRIBUTE) genericize_omp_for_stmt (stmt_p, walk_subtrees, data); else if (TREE_CODE (stmt) == SIZEOF_EXPR) { diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 7ce1acb06d70f..2d33218eb141e 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -60,7 +60,8 @@ c-common.h, not after. STMT_EXPR_NO_SCOPE (in STMT_EXPR) BIND_EXPR_TRY_BLOCK (in BIND_EXPR) TYPENAME_IS_ENUM_P (in TYPENAME_TYPE) - OMP_FOR_GIMPLIFYING_P (in OMP_FOR) + OMP_FOR_GIMPLIFYING_P (in OMP_FOR, OMP_SIMD, OMP_FOR_SIMD + and OMP_DISTRIBUTE) BASELINK_QUALIFIED_P (in BASELINK) TARGET_EXPR_IMPLICIT_P (in TARGET_EXPR) TEMPLATE_PARM_PARAMETER_PACK (in TEMPLATE_PARM_INDEX) @@ -3976,7 +3977,7 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) /* Used while gimplifying continue statements bound to OMP_FOR nodes. */ #define OMP_FOR_GIMPLIFYING_P(NODE) \ - (TREE_LANG_FLAG_0 (OMP_FOR_CHECK (NODE))) + (TREE_LANG_FLAG_0 (OMP_LOOP_CHECK (NODE))) /* A language-specific token attached to the OpenMP data clauses to hold code (or code fragments) related to ctors, dtors, and op=. @@ -5708,17 +5709,20 @@ extern tree begin_omp_parallel (void); extern tree finish_omp_parallel (tree, tree); 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 tree finish_omp_for (location_t, enum tree_code, + tree, tree, tree, tree, tree, + tree, tree); extern void finish_omp_atomic (enum tree_code, enum tree_code, tree, tree, tree, tree, tree); extern void finish_omp_barrier (void); extern void finish_omp_flush (void); extern void finish_omp_taskwait (void); +extern void finish_omp_taskyield (void); +extern void finish_omp_cancel (tree); +extern void finish_omp_cancellation_point (tree); extern tree begin_transaction_stmt (location_t, tree *, int); extern void finish_transaction_stmt (tree, tree, int, tree); extern tree build_transaction_expr (location_t, tree, int, tree); -extern void finish_omp_taskyield (void); extern bool cxx_omp_create_clause_info (tree, tree, bool, bool, bool); extern tree baselink_for_fns (tree); extern void finish_static_assert (tree, tree, location_t, diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index cf4242e2637a0..067d9d96f751e 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -25709,7 +25709,7 @@ cp_parser_objc_at_dynamic_declaration (cp_parser *parser) } -/* OpenMP 2.5 parsing routines. */ +/* OpenMP 2.5 / 3.0 / 3.1 / 4.0 parsing routines. */ /* Returns name of the next clause. If the clause is not recognized PRAGMA_OMP_CLAUSE_NONE is returned and @@ -25727,6 +25727,8 @@ cp_parser_omp_clause_name (cp_parser *parser) result = PRAGMA_OMP_CLAUSE_DEFAULT; else if (cp_lexer_next_token_is_keyword (parser->lexer, RID_PRIVATE)) result = PRAGMA_OMP_CLAUSE_PRIVATE; + else if (cp_lexer_next_token_is_keyword (parser->lexer, RID_FOR)) + result = PRAGMA_OMP_CLAUSE_FOR; else if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) { tree id = cp_lexer_peek_token (parser->lexer)->u.value; @@ -25734,6 +25736,10 @@ cp_parser_omp_clause_name (cp_parser *parser) switch (p[0]) { + case 'a': + if (!strcmp ("aligned", p)) + result = PRAGMA_OMP_CLAUSE_ALIGNED; + break; case 'c': if (!strcmp ("collapse", p)) result = PRAGMA_OMP_CLAUSE_COLLAPSE; @@ -25742,23 +25748,44 @@ cp_parser_omp_clause_name (cp_parser *parser) else if (!strcmp ("copyprivate", p)) result = PRAGMA_OMP_CLAUSE_COPYPRIVATE; break; + case 'd': + if (!strcmp ("depend", p)) + result = PRAGMA_OMP_CLAUSE_DEPEND; + else if (!strcmp ("device", p)) + result = PRAGMA_OMP_CLAUSE_DEVICE; + else if (!strcmp ("dist_schedule", p)) + result = PRAGMA_OMP_CLAUSE_DIST_SCHEDULE; + break; case 'f': if (!strcmp ("final", p)) result = PRAGMA_OMP_CLAUSE_FINAL; else if (!strcmp ("firstprivate", p)) result = PRAGMA_OMP_CLAUSE_FIRSTPRIVATE; + else if (!strcmp ("from", p)) + result = PRAGMA_OMP_CLAUSE_FROM; break; + case 'i': + if (!strcmp ("inbranch", p)) + result = PRAGMA_OMP_CLAUSE_INBRANCH; case 'l': if (!strcmp ("lastprivate", p)) result = PRAGMA_OMP_CLAUSE_LASTPRIVATE; + else if (!strcmp ("linear", p)) + result = PRAGMA_OMP_CLAUSE_LINEAR; break; case 'm': - if (!strcmp ("mergeable", p)) + if (!strcmp ("map", p)) + result = PRAGMA_OMP_CLAUSE_MAP; + else if (!strcmp ("mergeable", p)) result = PRAGMA_OMP_CLAUSE_MERGEABLE; break; case 'n': - if (!strcmp ("nowait", p)) + if (!strcmp ("notinbranch", p)) + result = PRAGMA_OMP_CLAUSE_NOTINBRANCH; + else if (!strcmp ("nowait", p)) result = PRAGMA_OMP_CLAUSE_NOWAIT; + else if (!strcmp ("num_teams", p)) + result = PRAGMA_OMP_CLAUSE_NUM_TEAMS; else if (!strcmp ("num_threads", p)) result = PRAGMA_OMP_CLAUSE_NUM_THREADS; break; @@ -25766,18 +25793,38 @@ cp_parser_omp_clause_name (cp_parser *parser) if (!strcmp ("ordered", p)) result = PRAGMA_OMP_CLAUSE_ORDERED; break; + case 'p': + if (!strcmp ("parallel", p)) + result = PRAGMA_OMP_CLAUSE_PARALLEL; + else if (!strcmp ("proc_bind", p)) + result = PRAGMA_OMP_CLAUSE_PROC_BIND; + break; case 'r': if (!strcmp ("reduction", p)) result = PRAGMA_OMP_CLAUSE_REDUCTION; break; case 's': - if (!strcmp ("schedule", p)) + if (!strcmp ("safelen", p)) + result = PRAGMA_OMP_CLAUSE_SAFELEN; + else if (!strcmp ("schedule", p)) result = PRAGMA_OMP_CLAUSE_SCHEDULE; + else if (!strcmp ("sections", p)) + result = PRAGMA_OMP_CLAUSE_SECTIONS; else if (!strcmp ("shared", p)) result = PRAGMA_OMP_CLAUSE_SHARED; + else if (!strcmp ("simdlen", p)) + result = PRAGMA_OMP_CLAUSE_SIMDLEN; + break; + case 't': + if (!strcmp ("taskgroup", p)) + result = PRAGMA_OMP_CLAUSE_TASKGROUP; + else if (!strcmp ("to", p)) + result = PRAGMA_OMP_CLAUSE_TO; break; case 'u': - if (!strcmp ("untied", p)) + if (!strcmp ("uniform", p)) + result = PRAGMA_OMP_CLAUSE_UNIFORM; + else if (!strcmp ("untied", p)) result = PRAGMA_OMP_CLAUSE_UNTIED; break; } @@ -25810,20 +25857,26 @@ check_no_duplicate_clause (tree clauses, enum omp_clause_code code, identifier variable-list , identifier - In addition, we match a closing parenthesis. An opening parenthesis - will have been consumed by the caller. + In addition, we match a closing parenthesis (or, if COLON is non-NULL, + colon). An opening parenthesis will have been consumed by the caller. If KIND is nonzero, create the appropriate node and install the decl in OMP_CLAUSE_DECL and add the node to the head of the list. If KIND is zero, create a TREE_LIST with the decl in TREE_PURPOSE; - return the list created. */ + return the list created. + + COLON can be NULL if only closing parenthesis should end the list, + or pointer to bool which will receive false if the list is terminated + by closing parenthesis or true if the list is terminated by colon. */ static tree cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, - tree list) + tree list, bool *colon) { cp_token *token; + if (colon) + *colon = false; while (1) { tree name, decl; @@ -25857,6 +25910,13 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, cp_lexer_consume_token (parser->lexer); } + if (colon != NULL && cp_lexer_next_token_is (parser->lexer, CPP_COLON)) + { + *colon = true; + cp_parser_require (parser, CPP_COLON, RT_COLON); + return list; + } + if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) { int ending; @@ -25882,7 +25942,7 @@ static tree cp_parser_omp_var_list (cp_parser *parser, enum omp_clause_code kind, tree list) { if (cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) - return cp_parser_omp_var_list_no_open (parser, kind, list); + return cp_parser_omp_var_list_no_open (parser, kind, list, NULL); return list; } @@ -26198,7 +26258,8 @@ cp_parser_omp_clause_reduction (cp_parser *parser, tree list) if (!cp_parser_require (parser, CPP_COLON, RT_COLON)) goto resync_fail; - nlist = cp_parser_omp_var_list_no_open (parser, OMP_CLAUSE_REDUCTION, list); + nlist = cp_parser_omp_var_list_no_open (parser, OMP_CLAUSE_REDUCTION, list, + NULL); for (c = nlist; c != list; c = OMP_CLAUSE_CHAIN (c)) OMP_CLAUSE_REDUCTION_CODE (c) = code; @@ -26313,12 +26374,393 @@ cp_parser_omp_clause_untied (cp_parser * /*parser*/, return c; } +/* OpenMP 4.0: + inbranch + notinbranch */ + +static tree +cp_parser_omp_clause_branch (cp_parser * /*parser*/, enum omp_clause_code code, + tree list, location_t location) +{ + check_no_duplicate_clause (list, code, omp_clause_code_name[code], location); + tree c = build_omp_clause (location, code); + OMP_CLAUSE_CHAIN (c) = list; + return c; +} + +/* OpenMP 4.0: + parallel + for + sections + taskgroup */ + +static tree +cp_parser_omp_clause_cancelkind (cp_parser * /*parser*/, + enum omp_clause_code code, + tree list, location_t location) +{ + tree c; + + for (c = list; c; c = OMP_CLAUSE_CHAIN (c)) + switch (OMP_CLAUSE_CODE (c)) + { + case OMP_CLAUSE_PARALLEL: + case OMP_CLAUSE_FOR: + case OMP_CLAUSE_SECTIONS: + case OMP_CLAUSE_TASKGROUP: + error_at (location, "only one of %, %, % " + "and % clauses can be specified"); + break; + default: + break; + } + c = build_omp_clause (location, code); + OMP_CLAUSE_CHAIN (c) = list; + return c; +} + +/* OpenMP 4.0: + num_teams ( expression ) */ + +static tree +cp_parser_omp_clause_num_teams (cp_parser *parser, tree list, + location_t location) +{ + tree t, c; + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + return list; + + t = cp_parser_expression (parser, false, NULL); + + if (t == error_mark_node + || !cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + + check_no_duplicate_clause (list, OMP_CLAUSE_NUM_TEAMS, + "num_teams", location); + + c = build_omp_clause (location, OMP_CLAUSE_NUM_TEAMS); + OMP_CLAUSE_NUM_TEAMS_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + + return c; +} + +/* OpenMP 4.0: + aligned ( variable-list ) + aligned ( variable-list : constant-expression ) */ + +static tree +cp_parser_omp_clause_aligned (cp_parser *parser, tree list) +{ + tree nlist, c, alignment = NULL_TREE; + bool colon; + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + return list; + + nlist = cp_parser_omp_var_list_no_open (parser, OMP_CLAUSE_ALIGNED, list, + &colon); + + if (colon) + { + alignment = cp_parser_constant_expression (parser, false, NULL); + + if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + + if (alignment == error_mark_node) + alignment = NULL_TREE; + } + + for (c = nlist; c != list; c = OMP_CLAUSE_CHAIN (c)) + OMP_CLAUSE_ALIGNED_ALIGNMENT (c) = alignment; + + return nlist; +} + +/* OpenMP 4.0: + linear ( variable-list ) + linear ( variable-list : expression ) */ + +static tree +cp_parser_omp_clause_linear (cp_parser *parser, tree list) +{ + tree nlist, c, step = integer_one_node; + bool colon; + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + return list; + + nlist = cp_parser_omp_var_list_no_open (parser, OMP_CLAUSE_LINEAR, list, + &colon); + + if (colon) + { + step = cp_parser_expression (parser, false, NULL); + + if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + + if (step == error_mark_node) + return list; + } + + for (c = nlist; c != list; c = OMP_CLAUSE_CHAIN (c)) + OMP_CLAUSE_LINEAR_STEP (c) = step; + + return nlist; +} + +/* OpenMP 4.0: + depend ( depend-kind : variable-list ) + + depend-kind: + in | out | inout */ + +static tree +cp_parser_omp_clause_depend (cp_parser *parser, tree list) +{ + tree nlist, c; + enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_INOUT; + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + return list; + + 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 ("in", p) == 0) + kind = OMP_CLAUSE_DEPEND_IN; + else if (strcmp ("inout", p) == 0) + kind = OMP_CLAUSE_DEPEND_INOUT; + else if (strcmp ("out", p) == 0) + kind = OMP_CLAUSE_DEPEND_OUT; + else + goto invalid_kind; + } + else + goto invalid_kind; + + cp_lexer_consume_token (parser->lexer); + if (!cp_parser_require (parser, CPP_COLON, RT_COLON)) + goto resync_fail; + + nlist = cp_parser_omp_var_list_no_open (parser, OMP_CLAUSE_DEPEND, list, + NULL); + + for (c = nlist; c != list; c = OMP_CLAUSE_CHAIN (c)) + OMP_CLAUSE_DEPEND_KIND (c) = kind; + + return nlist; + + invalid_kind: + cp_parser_error (parser, "invalid depend kind"); + resync_fail: + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + return list; +} + +/* OpenMP 4.0: + map ( map-kind : variable-list ) + map ( variable-list) + + map-kind: + alloc | to | from | tofrom */ + +static tree +cp_parser_omp_clause_map (cp_parser *parser, tree list) +{ + tree nlist, c; + enum omp_clause_map_kind kind = OMP_CLAUSE_MAP_TOFROM; + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + return list; + + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME) + && cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_COLON) + { + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + const char *p = IDENTIFIER_POINTER (id); + + if (strcmp ("alloc", p) == 0) + kind = OMP_CLAUSE_MAP_ALLOC; + else if (strcmp ("to", p) == 0) + kind = OMP_CLAUSE_MAP_TO; + else if (strcmp ("from", p) == 0) + kind = OMP_CLAUSE_MAP_FROM; + else if (strcmp ("tofrom", p) == 0) + kind = OMP_CLAUSE_MAP_TOFROM; + else + { + cp_parser_error (parser, "invalid map kind"); + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + return list; + } + cp_lexer_consume_token (parser->lexer); + cp_lexer_consume_token (parser->lexer); + } + + nlist = cp_parser_omp_var_list_no_open (parser, OMP_CLAUSE_MAP, list, + NULL); + + for (c = nlist; c != list; c = OMP_CLAUSE_CHAIN (c)) + OMP_CLAUSE_MAP_KIND (c) = kind; + + return nlist; +} + +/* OpenMP 4.0: + device ( expression ) */ + +static tree +cp_parser_omp_clause_device (cp_parser *parser, tree list, + location_t location) +{ + tree t, c; + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + return list; + + t = cp_parser_expression (parser, false, NULL); + + if (t == error_mark_node + || !cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + + check_no_duplicate_clause (list, OMP_CLAUSE_DEVICE, + "device", location); + + c = build_omp_clause (location, OMP_CLAUSE_DEVICE); + OMP_CLAUSE_DEVICE_ID (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + + return c; +} + +/* OpenMP 4.0: + dist_schedule ( static ) + dist_schedule ( static , expression ) */ + +static tree +cp_parser_omp_clause_dist_schedule (cp_parser *parser, tree list, + location_t location) +{ + tree c, t; + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + return list; + + c = build_omp_clause (location, OMP_CLAUSE_DIST_SCHEDULE); + + if (!cp_lexer_next_token_is_keyword (parser->lexer, RID_STATIC)) + goto invalid_kind; + cp_lexer_consume_token (parser->lexer); + + if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) + { + cp_lexer_consume_token (parser->lexer); + + t = cp_parser_assignment_expression (parser, false, NULL); + + if (t == error_mark_node) + goto resync_fail; + OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (c) = t; + + if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + goto resync_fail; + } + else if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_COMMA_CLOSE_PAREN)) + goto resync_fail; + + check_no_duplicate_clause (list, OMP_CLAUSE_DIST_SCHEDULE, "dist_schedule", + location); + OMP_CLAUSE_CHAIN (c) = list; + return c; + + invalid_kind: + cp_parser_error (parser, "invalid dist_schedule kind"); + resync_fail: + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + return list; +} + +/* OpenMP 4.0: + proc_bind ( proc-bind-kind ) + + proc-bind-kind: + master | close | spread */ + +static tree +cp_parser_omp_clause_proc_bind (cp_parser *parser, tree list, + location_t location) +{ + tree c; + enum omp_clause_proc_bind_kind kind; + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + return list; + + 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 ("master", p) == 0) + kind = OMP_CLAUSE_PROC_BIND_MASTER; + else if (strcmp ("close", p) == 0) + kind = OMP_CLAUSE_PROC_BIND_CLOSE; + else if (strcmp ("spread", p) == 0) + kind = OMP_CLAUSE_PROC_BIND_SPREAD; + else + goto invalid_kind; + } + else + goto invalid_kind; + + cp_lexer_consume_token (parser->lexer); + if (!cp_parser_require (parser, CPP_COLON, RT_COLON)) + goto resync_fail; + + c = build_omp_clause (location, OMP_CLAUSE_PROC_BIND); + check_no_duplicate_clause (list, OMP_CLAUSE_PROC_BIND, "proc_bind", + location); + OMP_CLAUSE_PROC_BIND_KIND (c) = kind; + OMP_CLAUSE_CHAIN (c) = list; + return c; + + invalid_kind: + cp_parser_error (parser, "invalid depend kind"); + resync_fail: + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + return list; +} + /* Parse all OpenMP clauses. The set clauses allowed by the directive is a bitmask in MASK. Return the list of clauses found; the result of clause default goes in *pdefault. */ static tree -cp_parser_omp_all_clauses (cp_parser *parser, unsigned int mask, +cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask, const char *where, cp_token *pragma_tok) { tree clauses = NULL; @@ -26418,7 +26860,89 @@ cp_parser_omp_all_clauses (cp_parser *parser, unsigned int mask, case PRAGMA_OMP_CLAUSE_UNTIED: clauses = cp_parser_omp_clause_untied (parser, clauses, token->location); - c_name = "nowait"; + c_name = "untied"; + break; + case PRAGMA_OMP_CLAUSE_INBRANCH: + clauses = cp_parser_omp_clause_branch (parser, OMP_CLAUSE_INBRANCH, + clauses, token->location); + c_name = "inbranch"; + break; + case PRAGMA_OMP_CLAUSE_NOTINBRANCH: + clauses = cp_parser_omp_clause_branch (parser, + OMP_CLAUSE_NOTINBRANCH, + clauses, token->location); + c_name = "notinbranch"; + break; + case PRAGMA_OMP_CLAUSE_PARALLEL: + clauses = cp_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_PARALLEL, + clauses, token->location); + c_name = "parallel"; + break; + case PRAGMA_OMP_CLAUSE_FOR: + clauses = cp_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_FOR, + clauses, token->location); + c_name = "for"; + break; + case PRAGMA_OMP_CLAUSE_SECTIONS: + clauses = cp_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_SECTIONS, + clauses, token->location); + c_name = "sections"; + break; + case PRAGMA_OMP_CLAUSE_TASKGROUP: + clauses = cp_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_TASKGROUP, + clauses, token->location); + c_name = "taskgroup"; + break; + case PRAGMA_OMP_CLAUSE_TO: + clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_TO, + clauses); + c_name = "to"; + break; + case PRAGMA_OMP_CLAUSE_FROM: + clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_FROM, + clauses); + c_name = "from"; + break; + case PRAGMA_OMP_CLAUSE_UNIFORM: + clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_UNIFORM, + clauses); + c_name = "uniform"; + break; + case PRAGMA_OMP_CLAUSE_NUM_TEAMS: + clauses = cp_parser_omp_clause_num_teams (parser, clauses, + token->location); + c_name = "num_teams"; + break; + case PRAGMA_OMP_CLAUSE_ALIGNED: + clauses = cp_parser_omp_clause_aligned (parser, clauses); + c_name = "aligned"; + break; + case PRAGMA_OMP_CLAUSE_LINEAR: + clauses = cp_parser_omp_clause_linear (parser, clauses); + c_name = "linear"; + break; + case PRAGMA_OMP_CLAUSE_DEPEND: + clauses = cp_parser_omp_clause_depend (parser, clauses); + c_name = "depend"; + break; + case PRAGMA_OMP_CLAUSE_MAP: + clauses = cp_parser_omp_clause_map (parser, clauses); + c_name = "map"; + break; + case PRAGMA_OMP_CLAUSE_DEVICE: + clauses = cp_parser_omp_clause_device (parser, clauses, + token->location); + c_name = "device"; + break; + case PRAGMA_OMP_CLAUSE_DIST_SCHEDULE: + clauses = cp_parser_omp_clause_dist_schedule (parser, clauses, + token->location); + c_name = "dist_schedule"; + break; + case PRAGMA_OMP_CLAUSE_PROC_BIND: + clauses = cp_parser_omp_clause_proc_bind (parser, clauses, + token->location); + c_name = "proc_bind"; break; default: cp_parser_error (parser, "expected %<#pragma omp%> clause"); @@ -27075,7 +27599,8 @@ cp_parser_omp_for_incr (cp_parser *parser, tree decl) /* Parse the restricted form of the for statement allowed by OpenMP. */ static tree -cp_parser_omp_for_loop (cp_parser *parser, tree clauses, tree *par_clauses) +cp_parser_omp_for_loop (cp_parser *parser, enum tree_code code, tree clauses, + tree *par_clauses) { tree init, cond, incr, body, decl, pre_body = NULL_TREE, ret; tree real_decl, initv, condv, incrv, declv; @@ -27434,7 +27959,7 @@ cp_parser_omp_for_loop (cp_parser *parser, tree clauses, tree *par_clauses) if (declv == NULL_TREE) ret = NULL_TREE; else - ret = finish_omp_for (loc_first, declv, initv, condv, incrv, body, + ret = finish_omp_for (loc_first, code, declv, initv, condv, incrv, body, pre_body, clauses); while (nbraces) @@ -27467,33 +27992,86 @@ cp_parser_omp_for_loop (cp_parser *parser, tree clauses, tree *par_clauses) return ret; } +/* OpenMP 4.0: + #pragma omp simd simd-clause[optseq] new-line + for-loop */ + +#define OMP_SIMD_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SAFELEN) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINEAR) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALIGNED) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE)) + +static tree +cp_parser_omp_simd (cp_parser *parser, cp_token *pragma_tok) +{ + tree clauses, sb, ret; + unsigned int save; + + clauses = cp_parser_omp_all_clauses (parser, OMP_SIMD_CLAUSE_MASK, + "#pragma omp simd", pragma_tok); + + sb = begin_omp_structured_block (); + save = cp_parser_begin_omp_structured_block (parser); + + ret = cp_parser_omp_for_loop (parser, OMP_SIMD, clauses, NULL); + + cp_parser_end_omp_structured_block (parser, save); + add_stmt (finish_omp_structured_block (sb)); + + return ret; +} + /* OpenMP 2.5: #pragma omp for for-clause[optseq] new-line + for-loop + + OpenMP 4.0: + #pragma omp for simd for-simd-clause[optseq] new-line for-loop */ -#define OMP_FOR_CLAUSE_MASK \ - ( (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_REDUCTION) \ - | (1u << PRAGMA_OMP_CLAUSE_ORDERED) \ - | (1u << PRAGMA_OMP_CLAUSE_SCHEDULE) \ - | (1u << PRAGMA_OMP_CLAUSE_NOWAIT) \ - | (1u << PRAGMA_OMP_CLAUSE_COLLAPSE)) +#define OMP_FOR_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDERED) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SCHEDULE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE)) static tree cp_parser_omp_for (cp_parser *parser, cp_token *pragma_tok) { tree clauses, sb, ret; unsigned int save; + enum tree_code code = OMP_FOR; + omp_clause_mask mask = OMP_FOR_CLAUSE_MASK; + const char *p_name = "#pragma omp for"; + + 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); - clauses = cp_parser_omp_all_clauses (parser, OMP_FOR_CLAUSE_MASK, - "#pragma omp for", pragma_tok); + if (strcmp (p, "simd") == 0) + { + cp_lexer_consume_token (parser->lexer); + code = OMP_FOR_SIMD; + mask |= OMP_SIMD_CLAUSE_MASK; + p_name = "#pragma omp for simd"; + } + } + + clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok); sb = begin_omp_structured_block (); save = cp_parser_begin_omp_structured_block (parser); - ret = cp_parser_omp_for_loop (parser, clauses, NULL); + ret = cp_parser_omp_for_loop (parser, code, clauses, NULL); cp_parser_end_omp_structured_block (parser, save); add_stmt (finish_omp_structured_block (sb)); @@ -27612,12 +28190,12 @@ cp_parser_omp_sections_scope (cp_parser *parser) # pragma omp sections sections-clause[optseq] newline sections-scope */ -#define OMP_SECTIONS_CLAUSE_MASK \ - ( (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_REDUCTION) \ - | (1u << PRAGMA_OMP_CLAUSE_NOWAIT)) +#define OMP_SECTIONS_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) static tree cp_parser_omp_sections (cp_parser *parser, cp_token *pragma_tok) @@ -27637,17 +28215,21 @@ cp_parser_omp_sections (cp_parser *parser, cp_token *pragma_tok) /* OpenMP 2.5: # pragma parallel parallel-clause new-line # pragma parallel for parallel-for-clause new-line - # pragma parallel sections parallel-sections-clause new-line */ - -#define OMP_PARALLEL_CLAUSE_MASK \ - ( (1u << PRAGMA_OMP_CLAUSE_IF) \ - | (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_DEFAULT) \ - | (1u << PRAGMA_OMP_CLAUSE_SHARED) \ - | (1u << PRAGMA_OMP_CLAUSE_COPYIN) \ - | (1u << PRAGMA_OMP_CLAUSE_REDUCTION) \ - | (1u << PRAGMA_OMP_CLAUSE_NUM_THREADS)) + # pragma parallel sections parallel-sections-clause new-line + + OpenMP 4.0: + # pragma parallel for simd parallel-for-simd-clause new-line */ + +#define OMP_PARALLEL_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COPYIN) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PROC_BIND)) static tree cp_parser_omp_parallel (cp_parser *parser, cp_token *pragma_tok) @@ -27655,7 +28237,7 @@ cp_parser_omp_parallel (cp_parser *parser, cp_token *pragma_tok) enum pragma_kind p_kind = PRAGMA_OMP_PARALLEL; const char *p_name = "#pragma omp parallel"; tree stmt, clauses, par_clause, ws_clause, block; - unsigned int mask = OMP_PARALLEL_CLAUSE_MASK; + omp_clause_mask mask = OMP_PARALLEL_CLAUSE_MASK; unsigned int save; location_t loc = cp_lexer_peek_token (parser->lexer)->location; @@ -27665,7 +28247,20 @@ cp_parser_omp_parallel (cp_parser *parser, cp_token *pragma_tok) p_kind = PRAGMA_OMP_PARALLEL_FOR; p_name = "#pragma omp parallel for"; mask |= OMP_FOR_CLAUSE_MASK; - mask &= ~(1u << PRAGMA_OMP_CLAUSE_NOWAIT); + mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT); + 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, "simd") == 0) + { + cp_lexer_consume_token (parser->lexer); + p_kind = PRAGMA_OMP_PARALLEL_FOR_SIMD; + p_name = "#pragma omp parallel for simd"; + mask |= OMP_SIMD_CLAUSE_MASK; + } + } } else if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) { @@ -27677,7 +28272,7 @@ cp_parser_omp_parallel (cp_parser *parser, cp_token *pragma_tok) p_kind = PRAGMA_OMP_PARALLEL_SECTIONS; p_name = "#pragma omp parallel sections"; mask |= OMP_SECTIONS_CLAUSE_MASK; - mask &= ~(1u << PRAGMA_OMP_CLAUSE_NOWAIT); + mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT); } } @@ -27694,7 +28289,12 @@ cp_parser_omp_parallel (cp_parser *parser, cp_token *pragma_tok) case PRAGMA_OMP_PARALLEL_FOR: c_split_parallel_clauses (loc, clauses, &par_clause, &ws_clause); - cp_parser_omp_for_loop (parser, ws_clause, &par_clause); + cp_parser_omp_for_loop (parser, OMP_FOR, ws_clause, &par_clause); + break; + + case PRAGMA_OMP_PARALLEL_FOR_SIMD: + c_split_parallel_clauses (loc, clauses, &par_clause, &ws_clause); + cp_parser_omp_for_loop (parser, OMP_FOR_SIMD, ws_clause, &par_clause); break; case PRAGMA_OMP_PARALLEL_SECTIONS: @@ -27719,11 +28319,11 @@ cp_parser_omp_parallel (cp_parser *parser, cp_token *pragma_tok) # pragma omp single single-clause[optseq] new-line structured-block */ -#define OMP_SINGLE_CLAUSE_MASK \ - ( (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_COPYPRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_NOWAIT)) +#define OMP_SINGLE_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COPYPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) static tree cp_parser_omp_single (cp_parser *parser, cp_token *pragma_tok) @@ -27743,15 +28343,16 @@ cp_parser_omp_single (cp_parser *parser, cp_token *pragma_tok) # pragma omp task task-clause[optseq] new-line structured-block */ -#define OMP_TASK_CLAUSE_MASK \ - ( (1u << PRAGMA_OMP_CLAUSE_IF) \ - | (1u << PRAGMA_OMP_CLAUSE_UNTIED) \ - | (1u << PRAGMA_OMP_CLAUSE_DEFAULT) \ - | (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ - | (1u << PRAGMA_OMP_CLAUSE_SHARED) \ - | (1u << PRAGMA_OMP_CLAUSE_FINAL) \ - | (1u << PRAGMA_OMP_CLAUSE_MERGEABLE)) +#define OMP_TASK_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_UNTIED) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FINAL) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MERGEABLE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND)) static tree cp_parser_omp_task (cp_parser *parser, cp_token *pragma_tok) @@ -27802,6 +28403,63 @@ cp_parser_omp_threadprivate (cp_parser *parser, cp_token *pragma_tok) finish_omp_threadprivate (vars); } +/* OpenMP 4.0: + # pragma omp cancel cancel-clause[optseq] new-line */ + +#define OMP_CANCEL_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PARALLEL) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FOR) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SECTIONS) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TASKGROUP) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF)) + +static void +cp_parser_omp_cancel (cp_parser *parser, cp_token *pragma_tok) +{ + tree clauses = cp_parser_omp_all_clauses (parser, OMP_CANCEL_CLAUSE_MASK, + "#pragma omp cancel", pragma_tok); + finish_omp_cancel (clauses); +} + +/* OpenMP 4.0: + # pragma omp cancellation point cancelpt-clause[optseq] new-line */ + +#define OMP_CANCELLATION_POINT_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PARALLEL) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FOR) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SECTIONS) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TASKGROUP)) + +static void +cp_parser_omp_cancellation_point (cp_parser *parser, cp_token *pragma_tok) +{ + tree clauses; + bool point_seen = 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, "point") == 0) + { + cp_lexer_consume_token (parser->lexer); + point_seen = true; + } + } + if (!point_seen) + { + cp_parser_require_pragma_eol (parser, pragma_tok); + return; + } + + clauses = cp_parser_omp_all_clauses (parser, + OMP_CANCELLATION_POINT_CLAUSE_MASK, + "#pragma omp cancellation point", + pragma_tok); + finish_omp_cancellation_point (clauses); +} + /* Main entry point to OpenMP statement pragmas. */ static void @@ -27832,6 +28490,9 @@ cp_parser_omp_construct (cp_parser *parser, cp_token *pragma_tok) case PRAGMA_OMP_SECTIONS: stmt = cp_parser_omp_sections (parser, pragma_tok); break; + case PRAGMA_OMP_SIMD: + stmt = cp_parser_omp_simd (parser, pragma_tok); + break; case PRAGMA_OMP_SINGLE: stmt = cp_parser_omp_single (parser, pragma_tok); break; @@ -28264,6 +28925,38 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context) } break; + case PRAGMA_OMP_CANCEL: + switch (context) + { + case pragma_compound: + cp_parser_omp_cancel (parser, pragma_tok); + return false; + case pragma_stmt: + error_at (pragma_tok->location, + "%<#pragma omp cancel%> may only be " + "used in compound statements"); + break; + default: + goto bad_stmt; + } + break; + + case PRAGMA_OMP_CANCELLATION_POINT: + switch (context) + { + case pragma_compound: + cp_parser_omp_cancellation_point (parser, pragma_tok); + return false; + case pragma_stmt: + error_at (pragma_tok->location, + "%<#pragma omp cancellation point%> may only be " + "used in compound statements"); + break; + default: + goto bad_stmt; + } + break; + case PRAGMA_OMP_THREADPRIVATE: cp_parser_omp_threadprivate (parser, pragma_tok); return false; @@ -28275,6 +28968,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context) case PRAGMA_OMP_ORDERED: case PRAGMA_OMP_PARALLEL: case PRAGMA_OMP_SECTIONS: + case PRAGMA_OMP_SIMD: case PRAGMA_OMP_SINGLE: case PRAGMA_OMP_TASK: if (context == pragma_external) diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 0bace4b314561..7ddb6a31dbc1f 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -13198,6 +13198,9 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, break; case OMP_FOR: + case OMP_SIMD: + case OMP_FOR_SIMD: + case OMP_DISTRIBUTE: { tree clauses, body, pre_body; tree declv, initv, condv, incrv; @@ -13225,8 +13228,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, RECUR (OMP_FOR_BODY (t)); body = pop_stmt_list (body); - t = finish_omp_for (EXPR_LOCATION (t), declv, initv, condv, incrv, - body, pre_body, clauses); + t = finish_omp_for (EXPR_LOCATION (t), TREE_CODE (t), declv, initv, + condv, incrv, body, pre_body, clauses); add_stmt (finish_omp_structured_block (stmt)); } diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index ae9bd18c6ed21..1ab4e588ff41c 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -4025,6 +4025,7 @@ tree finish_omp_clauses (tree clauses) { bitmap_head generic_head, firstprivate_head, lastprivate_head; + bitmap_head aligned_head; tree c, t, *pc = &clauses; const char *name; @@ -4032,6 +4033,7 @@ finish_omp_clauses (tree clauses) bitmap_initialize (&generic_head, &bitmap_default_obstack); bitmap_initialize (&firstprivate_head, &bitmap_default_obstack); bitmap_initialize (&lastprivate_head, &bitmap_default_obstack); + bitmap_initialize (&aligned_head, &bitmap_default_obstack); for (pc = &clauses, c = clauses; c ; c = *pc) { @@ -4054,6 +4056,27 @@ finish_omp_clauses (tree clauses) case OMP_CLAUSE_COPYIN: name = "copyin"; goto check_dup_generic; + case OMP_CLAUSE_LINEAR: + name = "linear"; + t = OMP_CLAUSE_LINEAR_STEP (c); + if (t == NULL_TREE) + t = integer_one_node; + if (t == error_mark_node) + remove = true; + else if (!type_dependent_expression_p (t) + && !INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + error ("linear step expression must be integral"); + remove = true; + } + else + { + t = mark_rvalue_use (t); + if (!processing_template_decl) + t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + OMP_CLAUSE_LINEAR_STEP (c) = t; + } + goto check_dup_generic; check_dup_generic: t = OMP_CLAUSE_DECL (c); if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) @@ -4181,12 +4204,210 @@ finish_omp_clauses (tree clauses) } break; + case OMP_CLAUSE_SIMDLEN: + case OMP_CLAUSE_SAFELEN: + t = OMP_CLAUSE_OPERAND (c, 0); + if (t == error_mark_node) + remove = true; + else if (!type_dependent_expression_p (t) + && !INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + error ("%qs length expression must be integral", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + else + { + t = mark_rvalue_use (t); + t = maybe_constant_value (t); + if (!processing_template_decl) + { + if (TREE_CODE (t) != INTEGER_CST + || tree_int_cst_sgn (t) == -1) + { + error ("%qs length expression must be positive constant" + " integer expression", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + } + OMP_CLAUSE_OPERAND (c, 0) = t; + } + break; + + case OMP_CLAUSE_NUM_TEAMS: + t = OMP_CLAUSE_NUM_TEAMS_EXPR (c); + if (t == error_mark_node) + remove = true; + else if (!type_dependent_expression_p (t) + && !INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + error ("% expression must be integral"); + remove = true; + } + else + { + t = mark_rvalue_use (t); + if (!processing_template_decl) + t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + OMP_CLAUSE_NUM_TEAMS_EXPR (c) = t; + } + break; + + case OMP_CLAUSE_DEVICE: + t = OMP_CLAUSE_DEVICE_ID (c); + if (t == error_mark_node) + remove = true; + else if (!type_dependent_expression_p (t) + && !INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + error ("% id must be integral"); + remove = true; + } + else + { + t = mark_rvalue_use (t); + if (!processing_template_decl) + t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + OMP_CLAUSE_DEVICE_ID (c) = t; + } + break; + + case OMP_CLAUSE_DIST_SCHEDULE: + t = OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (c); + if (t == NULL) + ; + else if (t == error_mark_node) + remove = true; + else if (!type_dependent_expression_p (t) + && !INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + error ("% chunk size expression must be " + "integral"); + remove = true; + } + else + { + t = mark_rvalue_use (t); + if (!processing_template_decl) + t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (c) = t; + } + break; + + case OMP_CLAUSE_ALIGNED: + t = OMP_CLAUSE_DECL (c); + if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) + { + if (processing_template_decl) + break; + if (DECL_P (t)) + error ("%qD is not a variable in % clause", t); + else + error ("%qE is not a variable in % clause", t); + remove = true; + } + else if (bitmap_bit_p (&aligned_head, DECL_UID (t))) + { + error ("%qD appears more than once in % clauses", t); + remove = true; + } + else + bitmap_set_bit (&aligned_head, DECL_UID (t)); + t = OMP_CLAUSE_ALIGNED_ALIGNMENT (c); + if (t == error_mark_node) + remove = true; + else if (!type_dependent_expression_p (t) + && !INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + error ("% clause alignment expression must " + "be integral"); + remove = true; + } + else + { + t = mark_rvalue_use (t); + t = maybe_constant_value (t); + if (!processing_template_decl) + { + if (TREE_CODE (t) != INTEGER_CST + || tree_int_cst_sgn (t) == -1) + { + error ("% clause alignment expression must be " + "positive constant integer expression"); + remove = true; + } + } + OMP_CLAUSE_ALIGNED_ALIGNMENT (c) = t; + } + break; + + case OMP_CLAUSE_DEPEND: + t = OMP_CLAUSE_DECL (c); + /* FIXME: depend clause argument may be also array section. */ + if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) + { + if (processing_template_decl) + break; + if (DECL_P (t)) + error ("%qD is not a variable in % clause", t); + else + error ("%qE is not a variable in % clause", t); + remove = true; + } + break; + + case OMP_CLAUSE_MAP: + case OMP_CLAUSE_TO: + case OMP_CLAUSE_FROM: + t = OMP_CLAUSE_DECL (c); + /* FIXME: map clause argument may be also array section. */ + if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) + { + if (processing_template_decl) + break; + if (DECL_P (t)) + error ("%qD is not a variable in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + else + error ("%qE is not a variable in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + else if (TREE_CODE (t) == VAR_DECL && DECL_THREAD_LOCAL_P (t)) + { + error ("%qD is threadprivate variable in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + break; + + case OMP_CLAUSE_UNIFORM: + if (TREE_CODE (t) != PARM_DECL) + { + if (processing_template_decl) + break; + if (DECL_P (t)) + error ("%qD is not an argument in % clause", t); + else + error ("%qE is not an argument in % clause", t); + remove = true; + } + break; + case OMP_CLAUSE_NOWAIT: case OMP_CLAUSE_ORDERED: case OMP_CLAUSE_DEFAULT: case OMP_CLAUSE_UNTIED: case OMP_CLAUSE_COLLAPSE: case OMP_CLAUSE_MERGEABLE: + case OMP_CLAUSE_INBRANCH: + case OMP_CLAUSE_NOTINBRANCH: + case OMP_CLAUSE_PARALLEL: + case OMP_CLAUSE_FOR: + case OMP_CLAUSE_SECTIONS: + case OMP_CLAUSE_TASKGROUP: + case OMP_CLAUSE_PROC_BIND: break; default: @@ -4741,8 +4962,8 @@ handle_omp_for_class_iterator (int i, location_t locus, tree declv, tree initv, sk_omp scope. */ tree -finish_omp_for (location_t locus, tree declv, tree initv, tree condv, - tree incrv, tree body, tree pre_body, tree clauses) +finish_omp_for (location_t locus, enum tree_code code, tree declv, tree initv, + tree condv, tree incrv, tree body, tree pre_body, tree clauses) { tree omp_for = NULL, orig_incr = NULL; tree decl, init, cond, incr; @@ -4811,7 +5032,7 @@ finish_omp_for (location_t locus, tree declv, tree initv, tree condv, { tree stmt; - stmt = make_node (OMP_FOR); + stmt = make_node (code); for (i = 0; i < TREE_VEC_LENGTH (declv); i++) { @@ -4923,7 +5144,7 @@ finish_omp_for (location_t locus, tree declv, tree initv, tree condv, if (IS_EMPTY_STMT (pre_body)) pre_body = NULL; - omp_for = c_finish_omp_for (locus, declv, initv, condv, incrv, + omp_for = c_finish_omp_for (locus, code, declv, initv, condv, incrv, body, pre_body); if (omp_for == NULL) @@ -5111,6 +5332,62 @@ finish_omp_taskyield (void) release_tree_vector (vec); finish_expr_stmt (stmt); } + +void +finish_omp_cancel (tree clauses) +{ + tree fn = builtin_decl_explicit (BUILT_IN_GOMP_CANCEL); + int mask = 0; + if (find_omp_clause (clauses, OMP_CLAUSE_PARALLEL)) + mask = 1; + else if (find_omp_clause (clauses, OMP_CLAUSE_FOR)) + mask = 2; + else if (find_omp_clause (clauses, OMP_CLAUSE_SECTIONS)) + mask = 4; + else if (find_omp_clause (clauses, OMP_CLAUSE_TASKGROUP)) + mask = 8; + else + { + error ("%<#pragma omp cancellation point must specify one of " + "%, %, % or % clauses"); + return; + } + vec *vec + = make_tree_vector_single (build_int_cst (integer_type_node, mask)); + tree stmt = finish_call_expr (fn, &vec, false, false, tf_warning_or_error); + release_tree_vector (vec); + tree ifc = find_omp_clause (clauses, OMP_CLAUSE_IF); + if (ifc != NULL_TREE) + stmt = build3 (COND_EXPR, void_type_node, OMP_CLAUSE_IF_EXPR (ifc), + stmt, NULL_TREE); + finish_expr_stmt (stmt); +} + +void +finish_omp_cancellation_point (tree clauses) +{ + tree fn = builtin_decl_explicit (BUILT_IN_GOMP_CANCELLATION_POINT); + int mask = 0; + if (find_omp_clause (clauses, OMP_CLAUSE_PARALLEL)) + mask = 1; + else if (find_omp_clause (clauses, OMP_CLAUSE_FOR)) + mask = 2; + else if (find_omp_clause (clauses, OMP_CLAUSE_SECTIONS)) + mask = 4; + else if (find_omp_clause (clauses, OMP_CLAUSE_TASKGROUP)) + mask = 8; + else + { + error ("%<#pragma omp cancellation point must specify one of " + "%, %, % or % clauses"); + return; + } + vec *vec + = make_tree_vector_single (build_int_cst (integer_type_node, mask)); + tree stmt = finish_call_expr (fn, &vec, false, false, tf_warning_or_error); + release_tree_vector (vec); + finish_expr_stmt (stmt); +} /* Begin a __transaction_atomic or __transaction_relaxed statement. If PCOMPOUND is non-null, this is for a function-transaction-block, and we diff --git a/gcc/fortran/ChangeLog.gomp b/gcc/fortran/ChangeLog.gomp new file mode 100644 index 0000000000000..56f769617f06b --- /dev/null +++ b/gcc/fortran/ChangeLog.gomp @@ -0,0 +1,9 @@ +2013-03-27 Jakub Jelinek + + * f95-lang.c (ATTR_NULL): Define. + +Copyright (C) 2013 Free Software Foundation, Inc. + +Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. diff --git a/gcc/fortran/f95-lang.c b/gcc/fortran/f95-lang.c index 60d790b085855..a67691dfb08e1 100644 --- a/gcc/fortran/f95-lang.c +++ b/gcc/fortran/f95-lang.c @@ -531,7 +531,8 @@ gfc_builtin_function (tree decl) return decl; } -/* So far we need just these 4 attribute types. */ +/* So far we need just these 6 attribute types. */ +#define ATTR_NULL 0 #define ATTR_NOTHROW_LEAF_LIST (ECF_NOTHROW | ECF_LEAF) #define ATTR_NOTHROW_LEAF_MALLOC_LIST (ECF_NOTHROW | ECF_LEAF | ECF_MALLOC) #define ATTR_CONST_NOTHROW_LEAF_LIST (ECF_NOTHROW | ECF_LEAF | ECF_CONST) diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c index 8c24a57d6d64f..2f3926d982f3c 100644 --- a/gcc/gimple-pretty-print.c +++ b/gcc/gimple-pretty-print.c @@ -1087,8 +1087,26 @@ dump_gimple_omp_for (pretty_printer *buffer, gimple gs, int spc, int flags) if (flags & TDF_RAW) { - dump_gimple_fmt (buffer, spc, flags, "%G <%+BODY <%S>%nCLAUSES <", gs, - gimple_omp_body (gs)); + const char *kind; + switch (gimple_omp_for_kind (gs)) + { + case GF_OMP_FOR_KIND_FOR: + kind = ""; + break; + case GF_OMP_FOR_KIND_SIMD: + kind = " simd"; + break; + case GF_OMP_FOR_KIND_FOR_SIMD: + kind = " for simd"; + break; + case GF_OMP_FOR_KIND_DISTRIBUTE: + kind = " distribute"; + break; + default: + gcc_unreachable (); + } + dump_gimple_fmt (buffer, spc, flags, "%G%s <%+BODY <%S>%nCLAUSES <", gs, + kind, gimple_omp_body (gs)); dump_omp_clauses (buffer, gimple_omp_for_clauses (gs), spc, flags); dump_gimple_fmt (buffer, spc, flags, " >,"); for (i = 0; i < gimple_omp_for_collapse (gs); i++) @@ -1104,7 +1122,23 @@ dump_gimple_omp_for (pretty_printer *buffer, gimple gs, int spc, int flags) } else { - pp_string (buffer, "#pragma omp for"); + switch (gimple_omp_for_kind (gs)) + { + case GF_OMP_FOR_KIND_FOR: + pp_string (buffer, "#pragma omp for"); + break; + case GF_OMP_FOR_KIND_SIMD: + pp_string (buffer, "#pragma omp simd"); + break; + case GF_OMP_FOR_KIND_FOR_SIMD: + pp_string (buffer, "#pragma omp for simd"); + break; + case GF_OMP_FOR_KIND_DISTRIBUTE: + pp_string (buffer, "#pragma omp distribute"); + break; + default: + gcc_unreachable (); + } dump_omp_clauses (buffer, gimple_omp_for_clauses (gs), spc, flags); for (i = 0; i < gimple_omp_for_collapse (gs); i++) { diff --git a/gcc/gimple.h b/gcc/gimple.h index 475d2ea9ee775..d25289f88b18b 100644 --- a/gcc/gimple.h +++ b/gcc/gimple.h @@ -100,6 +100,11 @@ enum gf_mask { GF_CALL_ALLOCA_FOR_VAR = 1 << 5, GF_CALL_INTERNAL = 1 << 6, GF_OMP_PARALLEL_COMBINED = 1 << 0, + GF_OMP_FOR_KIND_MASK = 3 << 0, + GF_OMP_FOR_KIND_FOR = 0 << 0, + GF_OMP_FOR_KIND_SIMD = 1 << 0, + GF_OMP_FOR_KIND_FOR_SIMD = 2 << 0, + GF_OMP_FOR_KIND_DISTRIBUTE = 3 << 0, /* True on an GIMPLE_OMP_RETURN statement if the return does not require a thread synchronization via some sort of barrier. The exact barrier @@ -3877,6 +3882,27 @@ gimple_omp_critical_set_name (gimple gs, tree name) } +/* Return the kind of OMP for statemement. */ + +static inline int +gimple_omp_for_kind (const_gimple g) +{ + GIMPLE_CHECK (g, GIMPLE_OMP_FOR); + return (gimple_omp_subcode (g) & GF_OMP_FOR_KIND_MASK); +} + + +/* Set the OMP for kind. */ + +static inline void +gimple_omp_for_set_kind (gimple g, int kind) +{ + GIMPLE_CHECK (g, GIMPLE_OMP_FOR); + g->gsbase.subcode = (g->gsbase.subcode & ~GF_OMP_FOR_KIND_MASK) + | (kind & GF_OMP_FOR_KIND_MASK); +} + + /* Return the clauses associated with OMP_FOR GS. */ static inline tree diff --git a/gcc/gimplify.c b/gcc/gimplify.c index e7119283ff379..c61215f1584b9 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -4742,6 +4742,9 @@ is_gimple_stmt (tree t) case STATEMENT_LIST: case OMP_PARALLEL: case OMP_FOR: + case OMP_SIMD: + case OMP_FOR_SIMD: + case OMP_DISTRIBUTE: case OMP_SECTIONS: case OMP_SECTION: case OMP_SINGLE: @@ -6689,6 +6692,22 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) gfor = gimple_build_omp_for (for_body, OMP_FOR_CLAUSES (for_stmt), TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)), for_pre_body); + switch (TREE_CODE (for_stmt)) + { + case OMP_FOR: + break; + case OMP_SIMD: + gimple_omp_for_set_kind (gfor, GF_OMP_FOR_KIND_SIMD); + break; + case OMP_FOR_SIMD: + gimple_omp_for_set_kind (gfor, GF_OMP_FOR_KIND_FOR_SIMD); + break; + case OMP_DISTRIBUTE: + gimple_omp_for_set_kind (gfor, GF_OMP_FOR_KIND_DISTRIBUTE); + break; + default: + gcc_unreachable (); + } for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)); i++) { @@ -7621,6 +7640,9 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, break; case OMP_FOR: + case OMP_SIMD: + case OMP_FOR_SIMD: + case OMP_DISTRIBUTE: ret = gimplify_omp_for (expr_p, pre_p); break; diff --git a/gcc/omp-builtins.def b/gcc/omp-builtins.def index 83c26c44fc970..c7cababa548d5 100644 --- a/gcc/omp-builtins.def +++ b/gcc/omp-builtins.def @@ -39,6 +39,10 @@ DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TASKWAIT, "GOMP_taskwait", BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST) DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TASKYIELD, "GOMP_taskyield", BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST) +DEF_GOMP_BUILTIN (BUILT_IN_GOMP_CANCEL, "GOMP_cancel", + BT_FN_VOID_INT, ATTR_NULL) +DEF_GOMP_BUILTIN (BUILT_IN_GOMP_CANCELLATION_POINT, "GOMP_cancellation_point", + BT_FN_VOID_INT, ATTR_NULL) DEF_GOMP_BUILTIN (BUILT_IN_GOMP_CRITICAL_START, "GOMP_critical_start", BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST) DEF_GOMP_BUILTIN (BUILT_IN_GOMP_CRITICAL_END, "GOMP_critical_end", diff --git a/gcc/tree-flow.h b/gcc/tree-flow.h index 20584b8c60faf..8ac13406b63d8 100644 --- a/gcc/tree-flow.h +++ b/gcc/tree-flow.h @@ -350,7 +350,6 @@ extern struct omp_region *new_omp_region (basic_block, enum gimple_code, struct omp_region *); extern void free_omp_regions (void); void omp_expand_local (basic_block); -extern tree find_omp_clause (tree, enum omp_clause_code); tree copy_var_decl (tree, tree, tree); /*--------------------------------------------------------------------------- diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c index 1613142f3caee..f3de68c1d918b 100644 --- a/gcc/tree-pretty-print.c +++ b/gcc/tree-pretty-print.c @@ -314,11 +314,20 @@ dump_omp_clause (pretty_printer *buffer, tree clause, int spc, int flags) case OMP_CLAUSE_COPYPRIVATE: name = "copyprivate"; goto print_remap; + case OMP_CLAUSE_FROM: + name = "from"; + goto print_remap; + case OMP_CLAUSE_TO: + name = "to"; + goto print_remap; + case OMP_CLAUSE_UNIFORM: + name = "uniform"; + goto print_remap; print_remap: pp_string (buffer, name); pp_character (buffer, '('); dump_generic_node (buffer, OMP_CLAUSE_DECL (clause), - spc, flags, false); + spc, flags, false); pp_character (buffer, ')'); break; @@ -327,21 +336,21 @@ dump_omp_clause (pretty_printer *buffer, tree clause, int spc, int flags) pp_string (buffer, op_symbol_code (OMP_CLAUSE_REDUCTION_CODE (clause))); pp_character (buffer, ':'); dump_generic_node (buffer, OMP_CLAUSE_DECL (clause), - spc, flags, false); + spc, flags, false); pp_character (buffer, ')'); break; case OMP_CLAUSE_IF: pp_string (buffer, "if("); dump_generic_node (buffer, OMP_CLAUSE_IF_EXPR (clause), - spc, flags, false); + spc, flags, false); pp_character (buffer, ')'); break; case OMP_CLAUSE_NUM_THREADS: pp_string (buffer, "num_threads("); dump_generic_node (buffer, OMP_CLAUSE_NUM_THREADS_EXPR (clause), - spc, flags, false); + spc, flags, false); pp_character (buffer, ')'); break; @@ -380,30 +389,29 @@ dump_omp_clause (pretty_printer *buffer, tree clause, int spc, int flags) pp_string (buffer, "schedule("); switch (OMP_CLAUSE_SCHEDULE_KIND (clause)) { - case OMP_CLAUSE_SCHEDULE_STATIC: - pp_string (buffer, "static"); - break; - case OMP_CLAUSE_SCHEDULE_DYNAMIC: - pp_string (buffer, "dynamic"); - break; - case OMP_CLAUSE_SCHEDULE_GUIDED: - pp_string (buffer, "guided"); - break; - case OMP_CLAUSE_SCHEDULE_RUNTIME: - pp_string (buffer, "runtime"); - break; - case OMP_CLAUSE_SCHEDULE_AUTO: - pp_string (buffer, "auto"); - break; - default: - gcc_unreachable (); + case OMP_CLAUSE_SCHEDULE_STATIC: + pp_string (buffer, "static"); + break; + case OMP_CLAUSE_SCHEDULE_DYNAMIC: + pp_string (buffer, "dynamic"); + break; + case OMP_CLAUSE_SCHEDULE_GUIDED: + pp_string (buffer, "guided"); + break; + case OMP_CLAUSE_SCHEDULE_RUNTIME: + pp_string (buffer, "runtime"); + break; + case OMP_CLAUSE_SCHEDULE_AUTO: + pp_string (buffer, "auto"); + break; + default: + gcc_unreachable (); } if (OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (clause)) { pp_character (buffer, ','); - dump_generic_node (buffer, - OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (clause), - spc, flags, false); + dump_generic_node (buffer, OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (clause), + spc, flags, false); } pp_character (buffer, ')'); break; @@ -414,8 +422,7 @@ dump_omp_clause (pretty_printer *buffer, tree clause, int spc, int flags) case OMP_CLAUSE_COLLAPSE: pp_string (buffer, "collapse("); - dump_generic_node (buffer, - OMP_CLAUSE_COLLAPSE_EXPR (clause), + dump_generic_node (buffer, OMP_CLAUSE_COLLAPSE_EXPR (clause), spc, flags, false); pp_character (buffer, ')'); break; @@ -423,7 +430,7 @@ dump_omp_clause (pretty_printer *buffer, tree clause, int spc, int flags) case OMP_CLAUSE_FINAL: pp_string (buffer, "final("); dump_generic_node (buffer, OMP_CLAUSE_FINAL_EXPR (clause), - spc, flags, false); + spc, flags, false); pp_character (buffer, ')'); break; @@ -431,6 +438,154 @@ dump_omp_clause (pretty_printer *buffer, tree clause, int spc, int flags) pp_string (buffer, "mergeable"); break; + case OMP_CLAUSE_LINEAR: + pp_string (buffer, "linear("); + dump_generic_node (buffer, OMP_CLAUSE_DECL (clause), + spc, flags, false); + pp_character (buffer, ':'); + dump_generic_node (buffer, OMP_CLAUSE_LINEAR_STEP (clause), + spc, flags, false); + pp_character (buffer, ')'); + break; + + case OMP_CLAUSE_ALIGNED: + pp_string (buffer, "aligned("); + dump_generic_node (buffer, OMP_CLAUSE_DECL (clause), + spc, flags, false); + if (OMP_CLAUSE_ALIGNED_ALIGNMENT (clause)) + { + pp_character (buffer, ':'); + dump_generic_node (buffer, OMP_CLAUSE_ALIGNED_ALIGNMENT (clause), + spc, flags, false); + } + pp_character (buffer, ')'); + break; + + case OMP_CLAUSE_DEPEND: + pp_string (buffer, "depend("); + switch (OMP_CLAUSE_DEPEND_KIND (clause)) + { + case OMP_CLAUSE_DEPEND_IN: + pp_string (buffer, "in"); + break; + case OMP_CLAUSE_DEPEND_OUT: + pp_string (buffer, "out"); + break; + case OMP_CLAUSE_DEPEND_INOUT: + pp_string (buffer, "inout"); + break; + default: + gcc_unreachable (); + } + pp_character (buffer, ':'); + dump_generic_node (buffer, OMP_CLAUSE_DECL (clause), + spc, flags, false); + pp_character (buffer, ')'); + break; + + case OMP_CLAUSE_MAP: + pp_string (buffer, "map("); + switch (OMP_CLAUSE_MAP_KIND (clause)) + { + case OMP_CLAUSE_MAP_ALLOC: + pp_string (buffer, "alloc"); + break; + case OMP_CLAUSE_MAP_TO: + pp_string (buffer, "to"); + break; + case OMP_CLAUSE_MAP_FROM: + pp_string (buffer, "from"); + break; + case OMP_CLAUSE_MAP_TOFROM: + pp_string (buffer, "tofrom"); + break; + default: + gcc_unreachable (); + } + pp_character (buffer, ':'); + dump_generic_node (buffer, OMP_CLAUSE_DECL (clause), + spc, flags, false); + pp_character (buffer, ')'); + break; + + case OMP_CLAUSE_NUM_TEAMS: + pp_string (buffer, "num_teams("); + dump_generic_node (buffer, OMP_CLAUSE_NUM_TEAMS_EXPR (clause), + spc, flags, false); + pp_character (buffer, ')'); + break; + + case OMP_CLAUSE_DEVICE: + pp_string (buffer, "device("); + dump_generic_node (buffer, OMP_CLAUSE_DEVICE_ID (clause), + spc, flags, false); + pp_character (buffer, ')'); + break; + + case OMP_CLAUSE_DIST_SCHEDULE: + pp_string (buffer, "dist_schedule(static"); + if (OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (clause)) + { + pp_character (buffer, ','); + dump_generic_node (buffer, + OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (clause), + spc, flags, false); + } + pp_character (buffer, ')'); + break; + + case OMP_CLAUSE_PROC_BIND: + pp_string (buffer, "proc_bind("); + switch (OMP_CLAUSE_PROC_BIND_KIND (clause)) + { + case OMP_CLAUSE_PROC_BIND_MASTER: + pp_string (buffer, "master"); + break; + case OMP_CLAUSE_PROC_BIND_CLOSE: + pp_string (buffer, "close"); + break; + case OMP_CLAUSE_PROC_BIND_SPREAD: + pp_string (buffer, "spread"); + break; + default: + gcc_unreachable (); + } + pp_character (buffer, ')'); + break; + + case OMP_CLAUSE_SAFELEN: + pp_string (buffer, "safelen("); + dump_generic_node (buffer, OMP_CLAUSE_SAFELEN_EXPR (clause), + spc, flags, false); + pp_character (buffer, ')'); + break; + + case OMP_CLAUSE_SIMDLEN: + pp_string (buffer, "simdlen("); + dump_generic_node (buffer, OMP_CLAUSE_SIMDLEN_EXPR (clause), + spc, flags, false); + pp_character (buffer, ')'); + break; + + case OMP_CLAUSE_INBRANCH: + pp_string (buffer, "inbranch"); + break; + case OMP_CLAUSE_NOTINBRANCH: + pp_string (buffer, "notinbranch"); + break; + case OMP_CLAUSE_FOR: + pp_string (buffer, "for"); + break; + case OMP_CLAUSE_PARALLEL: + pp_string (buffer, "parallel"); + break; + case OMP_CLAUSE_SECTIONS: + pp_string (buffer, "sections"); + break; + case OMP_CLAUSE_TASKGROUP: + pp_string (buffer, "taskgroup"); + break; + default: /* Should never happen. */ dump_generic_node (buffer, clause, spc, flags, false); @@ -2178,6 +2333,21 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags, case OMP_FOR: pp_string (buffer, "#pragma omp for"); + goto dump_omp_loop; + + case OMP_SIMD: + pp_string (buffer, "#pragma omp simd"); + goto dump_omp_loop; + + case OMP_FOR_SIMD: + pp_string (buffer, "#pragma omp for simd"); + goto dump_omp_loop; + + case OMP_DISTRIBUTE: + pp_string (buffer, "#pragma omp distribute"); + goto dump_omp_loop; + + dump_omp_loop: dump_omp_clauses (buffer, OMP_FOR_CLAUSES (node), spc, flags); if (!(flags & TDF_SLIM)) diff --git a/gcc/tree.c b/gcc/tree.c index 31f8037deb89e..36fadffffb15a 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -235,6 +235,13 @@ unsigned const char omp_clause_num_ops[] = 4, /* OMP_CLAUSE_REDUCTION */ 1, /* OMP_CLAUSE_COPYIN */ 1, /* OMP_CLAUSE_COPYPRIVATE */ + 2, /* OMP_CLAUSE_LINEAR */ + 2, /* OMP_CLAUSE_ALIGNED */ + 1, /* OMP_CLAUSE_DEPEND */ + 1, /* OMP_CLAUSE_FROM */ + 1, /* OMP_CLAUSE_TO */ + 1, /* OMP_CLAUSE_UNIFORM */ + 1, /* OMP_CLAUSE_MAP */ 1, /* OMP_CLAUSE_IF */ 1, /* OMP_CLAUSE_NUM_THREADS */ 1, /* OMP_CLAUSE_SCHEDULE */ @@ -244,7 +251,19 @@ unsigned const char omp_clause_num_ops[] = 3, /* OMP_CLAUSE_COLLAPSE */ 0, /* OMP_CLAUSE_UNTIED */ 1, /* OMP_CLAUSE_FINAL */ - 0 /* OMP_CLAUSE_MERGEABLE */ + 0, /* OMP_CLAUSE_MERGEABLE */ + 1, /* OMP_CLAUSE_DEVICE */ + 1, /* OMP_CLAUSE_DIST_SCHEDULE */ + 0, /* OMP_CLAUSE_INBRANCH */ + 0, /* OMP_CLAUSE_NOTINBRANCH */ + 1, /* OMP_CLAUSE_NUM_TEAMS */ + 0, /* OMP_CLAUSE_PROC_BIND */ + 1, /* OMP_CLAUSE_SAFELEN */ + 1, /* OMP_CLAUSE_SIMDLEN */ + 0, /* OMP_CLAUSE_FOR */ + 0, /* OMP_CLAUSE_PARALLEL */ + 0, /* OMP_CLAUSE_SECTIONS */ + 0 /* OMP_CLAUSE_TASKGROUP */ }; const char * const omp_clause_code_name[] = @@ -257,6 +276,13 @@ const char * const omp_clause_code_name[] = "reduction", "copyin", "copyprivate", + "linear", + "aligned", + "depend", + "from", + "to", + "uniform", + "map", "if", "num_threads", "schedule", @@ -266,7 +292,19 @@ const char * const omp_clause_code_name[] = "collapse", "untied", "final", - "mergeable" + "mergeable", + "device", + "dist_schedule", + "inbranch", + "notinbranch", + "num_teams", + "proc_bind", + "safelen", + "simdlen", + "for", + "parallel", + "sections", + "taskgroup" }; @@ -10761,6 +10799,16 @@ walk_tree_1 (tree *tp, walk_tree_fn func, void *data, case OMP_CLAUSE_IF: case OMP_CLAUSE_NUM_THREADS: case OMP_CLAUSE_SCHEDULE: + case OMP_CLAUSE_FROM: + case OMP_CLAUSE_TO: + case OMP_CLAUSE_UNIFORM: + case OMP_CLAUSE_DEPEND: + case OMP_CLAUSE_MAP: + case OMP_CLAUSE_NUM_TEAMS: + case OMP_CLAUSE_DEVICE: + case OMP_CLAUSE_DIST_SCHEDULE: + case OMP_CLAUSE_SAFELEN: + case OMP_CLAUSE_SIMDLEN: WALK_SUBTREE (OMP_CLAUSE_OPERAND (*tp, 0)); /* FALLTHRU */ @@ -10769,6 +10817,13 @@ walk_tree_1 (tree *tp, walk_tree_fn func, void *data, case OMP_CLAUSE_DEFAULT: case OMP_CLAUSE_UNTIED: case OMP_CLAUSE_MERGEABLE: + case OMP_CLAUSE_PROC_BIND: + case OMP_CLAUSE_INBRANCH: + case OMP_CLAUSE_NOTINBRANCH: + case OMP_CLAUSE_FOR: + case OMP_CLAUSE_PARALLEL: + case OMP_CLAUSE_SECTIONS: + case OMP_CLAUSE_TASKGROUP: WALK_SUBTREE_TAIL (OMP_CLAUSE_CHAIN (*tp)); case OMP_CLAUSE_LASTPRIVATE: @@ -10784,6 +10839,12 @@ walk_tree_1 (tree *tp, walk_tree_fn func, void *data, WALK_SUBTREE_TAIL (OMP_CLAUSE_CHAIN (*tp)); } + case OMP_CLAUSE_ALIGNED: + case OMP_CLAUSE_LINEAR: + WALK_SUBTREE (OMP_CLAUSE_DECL (*tp)); + WALK_SUBTREE (OMP_CLAUSE_OPERAND (*tp, 1)); + WALK_SUBTREE_TAIL (OMP_CLAUSE_CHAIN (*tp)); + case OMP_CLAUSE_REDUCTION: { int i; diff --git a/gcc/tree.def b/gcc/tree.def index da30074b10925..92df7d721ced8 100644 --- a/gcc/tree.def +++ b/gcc/tree.def @@ -1030,6 +1030,18 @@ DEFTREECODE (OMP_TASK, "omp_task", tcc_statement, 2) unspecified by the standard. */ DEFTREECODE (OMP_FOR, "omp_for", tcc_statement, 6) +/* OpenMP - #pragma omp simd [clause1 ... clauseN] + Operands like for OMP_FOR. */ +DEFTREECODE (OMP_SIMD, "omp_simd", tcc_statement, 6) + +/* OpenMP - #pragma omp for simd [clause1 ... clauseN] + Operands like for OMP_FOR. */ +DEFTREECODE (OMP_FOR_SIMD, "omp_for_simd", tcc_statement, 6) + +/* OpenMP - #pragma omp distribute [clause1 ... clauseN] + Operands like for OMP_FOR. */ +DEFTREECODE (OMP_DISTRIBUTE, "omp_distribute", tcc_statement, 6) + /* OpenMP - #pragma omp sections [clause1 ... clauseN] Operand 0: OMP_SECTIONS_BODY: Sections body. Operand 1: OMP_SECTIONS_CLAUSES: List of clauses. */ diff --git a/gcc/tree.h b/gcc/tree.h index b852f1d9434a1..d97f6eb409ac1 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -361,6 +361,27 @@ enum omp_clause_code /* OpenMP clause: copyprivate (variable_list). */ OMP_CLAUSE_COPYPRIVATE, + /* OpenMP clause: linear (variable-list[:linear-step]). */ + OMP_CLAUSE_LINEAR, + + /* OpenMP clause: aligned (variable-list[:alignment]). */ + OMP_CLAUSE_ALIGNED, + + /* OpenMP clause: depend ({in,out,inout}:variable-list). */ + OMP_CLAUSE_DEPEND, + + /* OpenMP clause: from (variable-list). */ + OMP_CLAUSE_FROM, + + /* OpenMP clause: to (variable-list). */ + OMP_CLAUSE_TO, + + /* OpenMP clause: uniform (argument-list). */ + OMP_CLAUSE_UNIFORM, + + /* OpenMP clause: map ({alloc:,to:,from:,tofrom:,}variable-list). */ + OMP_CLAUSE_MAP, + /* OpenMP clause: if (scalar-expression). */ OMP_CLAUSE_IF, @@ -389,7 +410,43 @@ enum omp_clause_code OMP_CLAUSE_FINAL, /* OpenMP clause: mergeable. */ - OMP_CLAUSE_MERGEABLE + OMP_CLAUSE_MERGEABLE, + + /* OpenMP clause: device (integer-expression). */ + OMP_CLAUSE_DEVICE, + + /* OpenMP clause: dist_schedule (static[:chunk-size]). */ + OMP_CLAUSE_DIST_SCHEDULE, + + /* OpenMP clause: inbranch. */ + OMP_CLAUSE_INBRANCH, + + /* OpenMP clause: notinbranch. */ + OMP_CLAUSE_NOTINBRANCH, + + /* OpenMP clause: num_teams(integer-expression). */ + OMP_CLAUSE_NUM_TEAMS, + + /* OpenMP clause: proc_bind ({master,close,spread}). */ + OMP_CLAUSE_PROC_BIND, + + /* OpenMP clause: safelen (constant-integer-expression). */ + OMP_CLAUSE_SAFELEN, + + /* OpenMP clause: simdlen (constant-integer-expression). */ + OMP_CLAUSE_SIMDLEN, + + /* OpenMP clause: for. */ + OMP_CLAUSE_FOR, + + /* OpenMP clause: parallel. */ + OMP_CLAUSE_PARALLEL, + + /* OpenMP clause: sections. */ + OMP_CLAUSE_SECTIONS, + + /* OpenMP clause: taskgroup. */ + OMP_CLAUSE_TASKGROUP }; /* The definition of tree nodes fills the next several pages. */ @@ -1766,12 +1823,13 @@ extern void protected_set_expr_location (tree, location_t); #define OMP_TASKREG_BODY(NODE) TREE_OPERAND (OMP_TASKREG_CHECK (NODE), 0) #define OMP_TASKREG_CLAUSES(NODE) TREE_OPERAND (OMP_TASKREG_CHECK (NODE), 1) -#define OMP_FOR_BODY(NODE) TREE_OPERAND (OMP_FOR_CHECK (NODE), 0) -#define OMP_FOR_CLAUSES(NODE) TREE_OPERAND (OMP_FOR_CHECK (NODE), 1) -#define OMP_FOR_INIT(NODE) TREE_OPERAND (OMP_FOR_CHECK (NODE), 2) -#define OMP_FOR_COND(NODE) TREE_OPERAND (OMP_FOR_CHECK (NODE), 3) -#define OMP_FOR_INCR(NODE) TREE_OPERAND (OMP_FOR_CHECK (NODE), 4) -#define OMP_FOR_PRE_BODY(NODE) TREE_OPERAND (OMP_FOR_CHECK (NODE), 5) +#define OMP_LOOP_CHECK(NODE) TREE_RANGE_CHECK (NODE, OMP_FOR, OMP_DISTRIBUTE) +#define OMP_FOR_BODY(NODE) TREE_OPERAND (OMP_LOOP_CHECK (NODE), 0) +#define OMP_FOR_CLAUSES(NODE) TREE_OPERAND (OMP_LOOP_CHECK (NODE), 1) +#define OMP_FOR_INIT(NODE) TREE_OPERAND (OMP_LOOP_CHECK (NODE), 2) +#define OMP_FOR_COND(NODE) TREE_OPERAND (OMP_LOOP_CHECK (NODE), 3) +#define OMP_FOR_INCR(NODE) TREE_OPERAND (OMP_LOOP_CHECK (NODE), 4) +#define OMP_FOR_PRE_BODY(NODE) TREE_OPERAND (OMP_LOOP_CHECK (NODE), 5) #define OMP_SECTIONS_BODY(NODE) TREE_OPERAND (OMP_SECTIONS_CHECK (NODE), 0) #define OMP_SECTIONS_CLAUSES(NODE) TREE_OPERAND (OMP_SECTIONS_CHECK (NODE), 1) @@ -1792,7 +1850,7 @@ extern void protected_set_expr_location (tree, location_t); #define OMP_CLAUSE_DECL(NODE) \ OMP_CLAUSE_OPERAND (OMP_CLAUSE_RANGE_CHECK (OMP_CLAUSE_CHECK (NODE), \ OMP_CLAUSE_PRIVATE, \ - OMP_CLAUSE_COPYPRIVATE), 0) + OMP_CLAUSE_MAP), 0) #define OMP_CLAUSE_HAS_LOCATION(NODE) \ (LOCATION_LOCUS ((OMP_CLAUSE_CHECK (NODE))->omp_clause.locus) \ != UNKNOWN_LOCATION) @@ -1859,6 +1917,28 @@ extern void protected_set_expr_location (tree, location_t); #define OMP_CLAUSE_REDUCTION_PLACEHOLDER(NODE) \ OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_REDUCTION), 3) +#define OMP_CLAUSE_LINEAR_STEP(NODE) \ + OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_LINEAR), 1) + +#define OMP_CLAUSE_ALIGNED_ALIGNMENT(NODE) \ + OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_ALIGNED), 1) + +#define OMP_CLAUSE_NUM_TEAMS_EXPR(NODE) \ + OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_NUM_TEAMS), 0) + +#define OMP_CLAUSE_DEVICE_ID(NODE) \ + OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_DEVICE), 0) + +#define OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR(NODE) \ + OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, \ + OMP_CLAUSE_DIST_SCHEDULE), 0) + +#define OMP_CLAUSE_SAFELEN_EXPR(NODE) \ + OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_SAFELEN), 0) + +#define OMP_CLAUSE_SIMDLEN_EXPR(NODE) \ + OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_SIMDLEN), 0) + enum omp_clause_schedule_kind { OMP_CLAUSE_SCHEDULE_STATIC, @@ -1883,6 +1963,40 @@ enum omp_clause_default_kind #define OMP_CLAUSE_DEFAULT_KIND(NODE) \ (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_DEFAULT)->omp_clause.subcode.default_kind) +enum omp_clause_depend_kind +{ + OMP_CLAUSE_DEPEND_IN, + OMP_CLAUSE_DEPEND_OUT, + OMP_CLAUSE_DEPEND_INOUT +}; + +#define OMP_CLAUSE_DEPEND_KIND(NODE) \ + (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_DEPEND)->omp_clause.subcode.depend_kind) + +enum omp_clause_map_kind +{ + OMP_CLAUSE_MAP_ALLOC, + OMP_CLAUSE_MAP_TO, + OMP_CLAUSE_MAP_FROM, + OMP_CLAUSE_MAP_TOFROM +}; + +#define OMP_CLAUSE_MAP_KIND(NODE) \ + (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_MAP)->omp_clause.subcode.map_kind) + +enum omp_clause_proc_bind_kind +{ + /* Numbers should match omp_proc_bind_t enum in omp.h. */ + OMP_CLAUSE_PROC_BIND_FALSE = 0, + OMP_CLAUSE_PROC_BIND_TRUE = 1, + OMP_CLAUSE_PROC_BIND_MASTER = 2, + OMP_CLAUSE_PROC_BIND_CLOSE = 3, + OMP_CLAUSE_PROC_BIND_SPREAD = 4 +}; + +#define OMP_CLAUSE_PROC_BIND_KIND(NODE) \ + (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_PROC_BIND)->omp_clause.subcode.proc_bind_kind) + struct GTY(()) tree_exp { struct tree_typed typed; location_t locus; @@ -2006,9 +2120,12 @@ struct GTY(()) tree_omp_clause { location_t locus; enum omp_clause_code code; union omp_clause_subcode { - enum omp_clause_default_kind default_kind; - enum omp_clause_schedule_kind schedule_kind; - enum tree_code reduction_code; + enum omp_clause_default_kind default_kind; + enum omp_clause_schedule_kind schedule_kind; + enum omp_clause_depend_kind depend_kind; + enum omp_clause_map_kind map_kind; + enum omp_clause_proc_bind_kind proc_bind_kind; + enum tree_code reduction_code; } GTY ((skip)) subcode; /* The gimplification of OMP_CLAUSE_REDUCTION_{INIT,MERGE} for omp-low's @@ -4774,6 +4891,7 @@ extern tree build_translation_unit_decl (tree); extern tree build_block (tree, tree, tree, tree); extern tree build_empty_stmt (location_t); extern tree build_omp_clause (location_t, enum omp_clause_code); +extern tree find_omp_clause (tree, enum omp_clause_code); extern tree build_vl_exp_stat (enum tree_code, int MEM_STAT_DECL); #define build_vl_exp(c,n) build_vl_exp_stat (c,n MEM_STAT_INFO) From 5c84774acb5ce694f5910ade4b850937520bc207 Mon Sep 17 00:00:00 2001 From: jakub Date: Fri, 5 Apr 2013 13:06:49 +0000 Subject: [PATCH 07/63] * semantics.c (finish_omp_for): Disallow class iterators for OMP_SIMD and OMP_FOR_SIMD loops. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gomp-4_0-branch@197515 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/cp/ChangeLog.gomp | 5 +++++ gcc/cp/semantics.c | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/gcc/cp/ChangeLog.gomp b/gcc/cp/ChangeLog.gomp index 93128b9ef2c27..a97549ab3660b 100644 --- a/gcc/cp/ChangeLog.gomp +++ b/gcc/cp/ChangeLog.gomp @@ -1,3 +1,8 @@ +2013-04-05 Jakub Jelinek + + * semantics.c (finish_omp_for): Disallow class iterators for + OMP_SIMD and OMP_FOR_SIMD loops. + 2013-03-27 Jakub Jelinek * cp-tree.h (OMP_FOR_GIMPLIFYING_P): Use OMP_LOOP_CHECK instead of diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 1ab4e588ff41c..4f72d69495b1f 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -5090,6 +5090,13 @@ finish_omp_for (location_t locus, enum tree_code code, tree declv, tree initv, if (CLASS_TYPE_P (TREE_TYPE (decl))) { + if (code == OMP_SIMD || code == OMP_FOR_SIMD) + { + error_at (elocus, "%<#pragma omp%s simd%> used with class " + "iteration variable %qE", + code == OMP_FOR_SIMD ? " for" : "", decl); + return NULL; + } if (handle_omp_for_class_iterator (i, locus, declv, initv, condv, incrv, &body, &pre_body, clauses)) return NULL; From c7c269bbd4085a25d19823bd4d6ade0ca0e06a32 Mon Sep 17 00:00:00 2001 From: jakub Date: Wed, 10 Apr 2013 11:12:52 +0000 Subject: [PATCH 08/63] * libgomp.map (omp_get_cancellation, omp_get_cancellation_, omp_get_proc_bind, omp_get_proc_bind_, omp_set_default_device, omp_set_default_device_, omp_set_default_device_8_, omp_get_default_device, omp_get_default_device_, omp_get_num_devices, omp_get_num_devices_, omp_get_num_teams, omp_get_num_teams_, omp_get_team_num, omp_get_team_num_): Export @@OMP_4.0. (GOMP_cancel, GOMP_cancellation_point, GOMP_parallel_loop_dynamic, GOMP_parallel_loop_guided, GOMP_parallel_loop_runtime, GOMP_parallel_loop_static, GOMP_parallel_sections, GOMP_parallel, GOMP_taskgroup_start, GOMP_taskgroup_end): Export @@GOMP_4.0. * parallel.c (GOMP_parallel_end): Add ialias. (GOMP_parallel, GOMP_cancel, GOMP_cancellation_point): New functions. * omp.h.in (omp_proc_bind_t): New typedef. (omp_get_cancellation, omp_get_proc_bind, omp_set_default_device, omp_get_default_device, omp_get_num_devices, omp_get_num_teams, omp_get_team_num): New prototypes. * env.c (omp_get_cancellation, omp_get_proc_bind, omp_set_default_device, omp_get_default_device, omp_get_num_devices, omp_get_num_teams, omp_get_team_num): New functions. * fortran.c (ULP, STR1, STR2, ialias_redirect): Removed. (omp_get_cancellation_, omp_get_proc_bind_, omp_set_default_device_, omp_set_default_device_8_, omp_get_default_device_, omp_get_num_devices_, omp_get_num_teams_, omp_get_team_num_): New functions. * libgomp.h (ialias_ulp, ialias_str1, ialias_str2, ialias_redirect, ialias_call): Define. * libgomp_g.h (GOMP_parallel_loop_static, GOMP_parallel_loop_dynamic, GOMP_parallel_loop_guided, GOMP_parallel_loop_runtime, GOMP_parallel, GOMP_cancel, GOMP_cancellation_point, GOMP_taskgroup_start, GOMP_taskgroup_end, GOMP_parallel_sections): New prototypes. * task.c (GOMP_taskgroup_start, GOMP_taskgroup_end): New functions. * sections.c (GOMP_parallel_sections): New function. * loop.c (GOMP_parallel_loop_static, GOMP_parallel_loop_dynamic, GOMP_parallel_loop_guided, GOMP_parallel_loop_runtime): New functions. (GOMP_parallel_end): Add ialias_redirect. * omp_lib.f90.in (omp_proc_bind_kind, omp_proc_bind_false, omp_proc_bind_true, omp_proc_bind_master, omp_proc_bind_close, omp_proc_bind_spread): New params. (omp_get_cancellation, omp_get_proc_bind, omp_set_default_device, omp_get_default_device, omp_get_num_devices, omp_get_num_teams, omp_get_team_num): New interfaces. * omp_lib.h.in (omp_proc_bind_kind, omp_proc_bind_false, omp_proc_bind_true, omp_proc_bind_master, omp_proc_bind_close, omp_proc_bind_spread): New params. (omp_get_cancellation, omp_get_proc_bind, omp_set_default_device, omp_get_default_device, omp_get_num_devices, omp_get_num_teams, omp_get_team_num): New externals. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gomp-4_0-branch@197670 138bc75d-0d04-0410-961f-82ee72b054a4 --- libgomp/ChangeLog.gomp | 53 ++++++++++++++++++++++++++++++++++ libgomp/env.c | 49 +++++++++++++++++++++++++++++++ libgomp/fortran.c | 60 ++++++++++++++++++++++++++++++++++---- libgomp/libgomp.h | 8 ++++++ libgomp/libgomp.map | 33 +++++++++++++++++++++ libgomp/libgomp_g.h | 19 ++++++++++++ libgomp/loop.c | 51 +++++++++++++++++++++++++++++++++ libgomp/omp.h.in | 40 +++++++++++++++++++------- libgomp/omp_lib.f90.in | 65 +++++++++++++++++++++++++++++++++++++++--- libgomp/omp_lib.h.in | 24 ++++++++++++++++ libgomp/parallel.c | 21 ++++++++++++++ libgomp/sections.c | 17 +++++++++++ libgomp/task.c | 10 +++++++ 13 files changed, 430 insertions(+), 20 deletions(-) diff --git a/libgomp/ChangeLog.gomp b/libgomp/ChangeLog.gomp index 218b730b0b155..d62cdc9305590 100644 --- a/libgomp/ChangeLog.gomp +++ b/libgomp/ChangeLog.gomp @@ -1,3 +1,56 @@ +2013-04-10 Jakub Jelinek + + * libgomp.map (omp_get_cancellation, omp_get_cancellation_, + omp_get_proc_bind, omp_get_proc_bind_, omp_set_default_device, + omp_set_default_device_, omp_set_default_device_8_, + omp_get_default_device, omp_get_default_device_, + omp_get_num_devices, omp_get_num_devices_, omp_get_num_teams, + omp_get_num_teams_, omp_get_team_num, omp_get_team_num_): Export + @@OMP_4.0. + (GOMP_cancel, GOMP_cancellation_point, GOMP_parallel_loop_dynamic, + GOMP_parallel_loop_guided, GOMP_parallel_loop_runtime, + GOMP_parallel_loop_static, GOMP_parallel_sections, GOMP_parallel, + GOMP_taskgroup_start, GOMP_taskgroup_end): Export @@GOMP_4.0. + * parallel.c (GOMP_parallel_end): Add ialias. + (GOMP_parallel, GOMP_cancel, GOMP_cancellation_point): New + functions. + * omp.h.in (omp_proc_bind_t): New typedef. + (omp_get_cancellation, omp_get_proc_bind, omp_set_default_device, + omp_get_default_device, omp_get_num_devices, omp_get_num_teams, + omp_get_team_num): New prototypes. + * env.c (omp_get_cancellation, omp_get_proc_bind, + omp_set_default_device, omp_get_default_device, omp_get_num_devices, + omp_get_num_teams, omp_get_team_num): New functions. + * fortran.c (ULP, STR1, STR2, ialias_redirect): Removed. + (omp_get_cancellation_, omp_get_proc_bind_, omp_set_default_device_, + omp_set_default_device_8_, omp_get_default_device_, + omp_get_num_devices_, omp_get_num_teams_, omp_get_team_num_): New + functions. + * libgomp.h (ialias_ulp, ialias_str1, ialias_str2, ialias_redirect, + ialias_call): Define. + * libgomp_g.h (GOMP_parallel_loop_static, GOMP_parallel_loop_dynamic, + GOMP_parallel_loop_guided, GOMP_parallel_loop_runtime, GOMP_parallel, + GOMP_cancel, GOMP_cancellation_point, GOMP_taskgroup_start, + GOMP_taskgroup_end, GOMP_parallel_sections): New prototypes. + * task.c (GOMP_taskgroup_start, GOMP_taskgroup_end): New functions. + * sections.c (GOMP_parallel_sections): New function. + * loop.c (GOMP_parallel_loop_static, GOMP_parallel_loop_dynamic, + GOMP_parallel_loop_guided, GOMP_parallel_loop_runtime): New + functions. + (GOMP_parallel_end): Add ialias_redirect. + * omp_lib.f90.in (omp_proc_bind_kind, omp_proc_bind_false, + omp_proc_bind_true, omp_proc_bind_master, omp_proc_bind_close, + omp_proc_bind_spread): New params. + (omp_get_cancellation, omp_get_proc_bind, omp_set_default_device, + omp_get_default_device, omp_get_num_devices, omp_get_num_teams, + omp_get_team_num): New interfaces. + * omp_lib.h.in (omp_proc_bind_kind, omp_proc_bind_false, + omp_proc_bind_true, omp_proc_bind_master, omp_proc_bind_close, + omp_proc_bind_spread): New params. + (omp_get_cancellation, omp_get_proc_bind, omp_set_default_device, + omp_get_default_device, omp_get_num_devices, omp_get_num_teams, + omp_get_team_num): New externals. + 2013-03-20 Tobias Burnus * libgomp.texi (Environment Variables): Minor cleanup, diff --git a/libgomp/env.c b/libgomp/env.c index 5cd11649d7725..b9c1d140011e8 100644 --- a/libgomp/env.c +++ b/libgomp/env.c @@ -866,6 +866,48 @@ omp_get_max_active_levels (void) return gomp_max_active_levels_var; } +int +omp_get_cancellation (void) +{ + return 0; +} + +omp_proc_bind_t +omp_get_proc_bind (void) +{ + return omp_proc_bind_false; +} + +void +omp_set_default_device (int device_num) +{ + (void) device_num; +} + +int +omp_get_default_device (void) +{ + return 0; +} + +int +omp_get_num_devices (void) +{ + return 0; +} + +int +omp_get_num_teams (void) +{ + return 1; +} + +int +omp_get_team_num (void) +{ + return 0; +} + ialias (omp_set_dynamic) ialias (omp_set_nested) ialias (omp_set_num_threads) @@ -877,3 +919,10 @@ ialias (omp_get_max_threads) ialias (omp_get_thread_limit) ialias (omp_set_max_active_levels) ialias (omp_get_max_active_levels) +ialias (omp_get_cancellation) +ialias (omp_get_proc_bind) +ialias (omp_set_default_device) +ialias (omp_get_default_device) +ialias (omp_get_num_devices) +ialias (omp_get_num_teams) +ialias (omp_get_team_num) diff --git a/libgomp/fortran.c b/libgomp/fortran.c index 3a4a42a4c618e..6f1717812b639 100644 --- a/libgomp/fortran.c +++ b/libgomp/fortran.c @@ -31,11 +31,6 @@ #ifdef HAVE_ATTRIBUTE_ALIAS /* Use internal aliases if possible. */ -# define ULP STR1(__USER_LABEL_PREFIX__) -# define STR1(x) STR2(x) -# define STR2(x) #x -# define ialias_redirect(fn) \ - extern __typeof (fn) fn __asm__ (ULP "gomp_ialias_" #fn) attribute_hidden; # ifndef LIBGOMP_GNU_SYMBOL_VERSIONING ialias_redirect (omp_init_lock) ialias_redirect (omp_init_nest_lock) @@ -70,6 +65,13 @@ ialias_redirect (omp_get_ancestor_thread_num) ialias_redirect (omp_get_team_size) ialias_redirect (omp_get_active_level) ialias_redirect (omp_in_final) +ialias_redirect (omp_get_cancellation) +ialias_redirect (omp_get_proc_bind) +ialias_redirect (omp_set_default_device) +ialias_redirect (omp_get_default_device) +ialias_redirect (omp_get_num_devices) +ialias_redirect (omp_get_num_teams) +ialias_redirect (omp_get_team_num) #endif #ifndef LIBGOMP_GNU_SYMBOL_VERSIONING @@ -435,3 +437,51 @@ omp_in_final_ (void) { return omp_in_final (); } + +int32_t +omp_get_cancellation_ (void) +{ + return omp_get_cancellation (); +} + +int32_t +omp_get_proc_bind_ (void) +{ + return omp_get_proc_bind (); +} + +void +omp_set_default_device_ (const int32_t *device_num) +{ + return omp_set_default_device (*device_num); +} + +void +omp_set_default_device_8_ (const int64_t *device_num) +{ + return omp_set_default_device (TO_INT (*device_num)); +} + +int32_t +omp_get_default_device_ (void) +{ + return omp_get_default_device (); +} + +int32_t +omp_get_num_devices_ (void) +{ + return omp_get_num_devices (); +} + +int32_t +omp_get_num_teams_ (void) +{ + return omp_get_num_teams (); +} + +int32_t +omp_get_team_num_ (void) +{ + return omp_get_team_num (); +} diff --git a/libgomp/libgomp.h b/libgomp/libgomp.h index 322a43520ee79..fb6c1ba7c72a7 100644 --- a/libgomp/libgomp.h +++ b/libgomp/libgomp.h @@ -580,11 +580,19 @@ extern int gomp_test_nest_lock_25 (omp_nest_lock_25_t *) __GOMP_NOTHROW; #endif #ifdef HAVE_ATTRIBUTE_ALIAS +# define ialias_ulp ialias_str1(__USER_LABEL_PREFIX__) +# define ialias_str1(x) ialias_str2(x) +# define ialias_str2(x) #x # define ialias(fn) \ extern __typeof (fn) gomp_ialias_##fn \ __attribute__ ((alias (#fn))) attribute_hidden; +# define ialias_redirect(fn) \ + extern __typeof (fn) fn __asm__ (ialias_ulp "gomp_ialias_" #fn) attribute_hidden; +# define ialias_call(fn) gomp_ialias_ ## fn #else # define ialias(fn) +# define ialias_redirect(fn) +# define ialias_call(fn) fn #endif #endif /* LIBGOMP_H */ diff --git a/libgomp/libgomp.map b/libgomp/libgomp.map index 7b051f96aabb2..41d083dba2c33 100644 --- a/libgomp/libgomp.map +++ b/libgomp/libgomp.map @@ -113,6 +113,25 @@ OMP_3.1 { omp_in_final_; } OMP_3.0; +OMP_4.0 { + global: + omp_get_cancellation; + omp_get_cancellation_; + omp_get_proc_bind; + omp_get_proc_bind_; + omp_set_default_device; + omp_set_default_device_; + omp_set_default_device_8_; + omp_get_default_device; + omp_get_default_device_; + omp_get_num_devices; + omp_get_num_devices_; + omp_get_num_teams; + omp_get_num_teams_; + omp_get_team_num; + omp_get_team_num_; +} OMP_3.1; + GOMP_1.0 { global: GOMP_atomic_end; @@ -184,3 +203,17 @@ GOMP_3.0 { global: GOMP_taskyield; } GOMP_2.0; + +GOMP_4.0 { + global: + GOMP_cancel; + GOMP_cancellation_point; + GOMP_parallel_loop_dynamic; + GOMP_parallel_loop_guided; + GOMP_parallel_loop_runtime; + GOMP_parallel_loop_static; + GOMP_parallel_sections; + GOMP_parallel; + GOMP_taskgroup_start; + GOMP_taskgroup_end; +} GOMP_3.0; diff --git a/libgomp/libgomp_g.h b/libgomp/libgomp_g.h index a31e3458c1beb..8d42548c9fb76 100644 --- a/libgomp/libgomp_g.h +++ b/libgomp/libgomp_g.h @@ -76,6 +76,18 @@ extern void GOMP_parallel_loop_guided_start (void (*)(void *), void *, unsigned, long, long, long, long); extern void GOMP_parallel_loop_runtime_start (void (*)(void *), void *, unsigned, long, long, long); +extern void GOMP_parallel_loop_static (void (*)(void *), void *, + unsigned, long, long, long, long, + unsigned); +extern void GOMP_parallel_loop_dynamic (void (*)(void *), void *, + unsigned, long, long, long, long, + unsigned); +extern void GOMP_parallel_loop_guided (void (*)(void *), void *, + unsigned, long, long, long, long, + unsigned); +extern void GOMP_parallel_loop_runtime (void (*)(void *), void *, + unsigned, long, long, long, + unsigned); extern void GOMP_loop_end (void); extern void GOMP_loop_end_nowait (void); @@ -157,6 +169,9 @@ extern void GOMP_ordered_end (void); extern void GOMP_parallel_start (void (*) (void *), void *, unsigned); extern void GOMP_parallel_end (void); +extern void GOMP_parallel (void (*) (void *), void *, unsigned, unsigned); +extern void GOMP_cancel (void); +extern void GOMP_cancellation_point (void); /* task.c */ @@ -164,6 +179,8 @@ extern void GOMP_task (void (*) (void *), void *, void (*) (void *, void *), long, long, bool, unsigned); extern void GOMP_taskwait (void); extern void GOMP_taskyield (void); +extern void GOMP_taskgroup_start (void); +extern void GOMP_taskgroup_end (void); /* sections.c */ @@ -171,6 +188,8 @@ extern unsigned GOMP_sections_start (unsigned); extern unsigned GOMP_sections_next (void); extern void GOMP_parallel_sections_start (void (*) (void *), void *, unsigned, unsigned); +extern void GOMP_parallel_sections (void (*) (void *), void *, + unsigned, unsigned, unsigned); extern void GOMP_sections_end (void); extern void GOMP_sections_end_nowait (void); diff --git a/libgomp/loop.c b/libgomp/loop.c index 12c818b011045..7de3e4c5dfeac 100644 --- a/libgomp/loop.c +++ b/libgomp/loop.c @@ -486,6 +486,57 @@ GOMP_parallel_loop_runtime_start (void (*fn) (void *), void *data, icv->run_sched_var, icv->run_sched_modifier); } +ialias_redirect (GOMP_parallel_end) + +void +GOMP_parallel_loop_static (void (*fn) (void *), void *data, + unsigned num_threads, long start, long end, + long incr, long chunk_size, unsigned flags) +{ + (void) flags; + gomp_parallel_loop_start (fn, data, num_threads, start, end, incr, + GFS_STATIC, chunk_size); + fn (data); + GOMP_parallel_end (); +} + +void +GOMP_parallel_loop_dynamic (void (*fn) (void *), void *data, + unsigned num_threads, long start, long end, + long incr, long chunk_size, unsigned flags) +{ + (void) flags; + gomp_parallel_loop_start (fn, data, num_threads, start, end, incr, + GFS_DYNAMIC, chunk_size); + fn (data); + GOMP_parallel_end (); +} + +void +GOMP_parallel_loop_guided (void (*fn) (void *), void *data, + unsigned num_threads, long start, long end, + long incr, long chunk_size, unsigned flags) +{ + (void) flags; + gomp_parallel_loop_start (fn, data, num_threads, start, end, incr, + GFS_GUIDED, chunk_size); + fn (data); + GOMP_parallel_end (); +} + +void +GOMP_parallel_loop_runtime (void (*fn) (void *), void *data, + unsigned num_threads, long start, long end, + long incr, unsigned flags) +{ + (void) flags; + struct gomp_task_icv *icv = gomp_icv (false); + gomp_parallel_loop_start (fn, data, num_threads, start, end, incr, + icv->run_sched_var, icv->run_sched_modifier); + fn (data); + GOMP_parallel_end (); +} + /* The GOMP_loop_end* routines are called after the thread is told that all loop iterations are complete. This first version synchronizes all threads; the nowait version does not. */ diff --git a/libgomp/omp.h.in b/libgomp/omp.h.in index 5db440785db9c..5d808c1509e91 100644 --- a/libgomp/omp.h.in +++ b/libgomp/omp.h.in @@ -52,6 +52,15 @@ typedef enum omp_sched_t omp_sched_auto = 4 } omp_sched_t; +typedef enum omp_proc_bind_t +{ + omp_proc_bind_false = 0, + omp_proc_bind_true = 1, + omp_proc_bind_master = 2, + omp_proc_bind_close = 3, + omp_proc_bind_spread = 4 +} omp_proc_bind_t; + #ifdef __cplusplus extern "C" { # define __GOMP_NOTHROW throw () @@ -88,17 +97,26 @@ extern int omp_test_nest_lock (omp_nest_lock_t *) __GOMP_NOTHROW; extern double omp_get_wtime (void) __GOMP_NOTHROW; extern double omp_get_wtick (void) __GOMP_NOTHROW; -void omp_set_schedule (omp_sched_t, int) __GOMP_NOTHROW; -void omp_get_schedule (omp_sched_t *, int *) __GOMP_NOTHROW; -int omp_get_thread_limit (void) __GOMP_NOTHROW; -void omp_set_max_active_levels (int) __GOMP_NOTHROW; -int omp_get_max_active_levels (void) __GOMP_NOTHROW; -int omp_get_level (void) __GOMP_NOTHROW; -int omp_get_ancestor_thread_num (int) __GOMP_NOTHROW; -int omp_get_team_size (int) __GOMP_NOTHROW; -int omp_get_active_level (void) __GOMP_NOTHROW; - -int omp_in_final (void) __GOMP_NOTHROW; +extern void omp_set_schedule (omp_sched_t, int) __GOMP_NOTHROW; +extern void omp_get_schedule (omp_sched_t *, int *) __GOMP_NOTHROW; +extern int omp_get_thread_limit (void) __GOMP_NOTHROW; +extern void omp_set_max_active_levels (int) __GOMP_NOTHROW; +extern int omp_get_max_active_levels (void) __GOMP_NOTHROW; +extern int omp_get_level (void) __GOMP_NOTHROW; +extern int omp_get_ancestor_thread_num (int) __GOMP_NOTHROW; +extern int omp_get_team_size (int) __GOMP_NOTHROW; +extern int omp_get_active_level (void) __GOMP_NOTHROW; + +extern int omp_in_final (void) __GOMP_NOTHROW; + +extern int omp_get_cancellation (void) __GOMP_NOTHROW; +extern omp_proc_bind_t omp_get_proc_bind (void) __GOMP_NOTHROW; + +extern void omp_set_default_device (int) __GOMP_NOTHROW; +extern int omp_get_default_device (void) __GOMP_NOTHROW; +extern int omp_get_num_devices (void) __GOMP_NOTHROW; +extern int omp_get_num_teams (void) __GOMP_NOTHROW; +extern int omp_get_team_num (void) __GOMP_NOTHROW; #ifdef __cplusplus } diff --git a/libgomp/omp_lib.f90.in b/libgomp/omp_lib.f90.in index c6108e1c3848a..50bbeaee43be5 100644 --- a/libgomp/omp_lib.f90.in +++ b/libgomp/omp_lib.f90.in @@ -27,16 +27,22 @@ integer, parameter :: omp_lock_kind = @OMP_LOCK_KIND@ integer, parameter :: omp_nest_lock_kind = @OMP_NEST_LOCK_KIND@ integer, parameter :: omp_sched_kind = 4 + integer, parameter :: omp_proc_bind_kind = 4 + integer (omp_sched_kind), parameter :: omp_sched_static = 1 + integer (omp_sched_kind), parameter :: omp_sched_dynamic = 2 + integer (omp_sched_kind), parameter :: omp_sched_guided = 3 + integer (omp_sched_kind), parameter :: omp_sched_auto = 4 + integer (omp_proc_bind_kind), parameter :: omp_proc_bind_false = 0 + integer (omp_proc_bind_kind), parameter :: omp_proc_bind_true = 1 + integer (omp_proc_bind_kind), parameter :: omp_proc_bind_master = 2 + integer (omp_proc_bind_kind), parameter :: omp_proc_bind_close = 3 + integer (omp_proc_bind_kind), parameter :: omp_proc_bind_spread = 4 end module module omp_lib use omp_lib_kinds implicit none integer, parameter :: openmp_version = 201107 - integer (omp_sched_kind), parameter :: omp_sched_static = 1 - integer (omp_sched_kind), parameter :: omp_sched_dynamic = 2 - integer (omp_sched_kind), parameter :: omp_sched_guided = 3 - integer (omp_sched_kind), parameter :: omp_sched_auto = 4 interface subroutine omp_init_lock (lock) @@ -296,4 +302,55 @@ end function omp_in_final end interface + interface + function omp_get_cancellation () + use omp_lib_kinds + logical (4) :: omp_get_cancellation + end function omp_get_cancellation + end interface + + interface + function omp_get_proc_bind () + use omp_lib_kinds + integer (omp_proc_bind_kind) :: omp_get_proc_bind + end function omp_get_proc_bind + end interface + + interface omp_set_default_device + subroutine omp_set_default_device (device_num) + integer (4), intent (in) :: device_num + end subroutine omp_set_default_device + subroutine omp_set_default_device_8 (device_num) + integer (8), intent (in) :: device_num + end subroutine omp_set_default_device_8 + end interface + + interface + function omp_get_default_device () + use omp_lib_kinds + integer (4) :: omp_get_default_device + end function omp_get_default_device + end interface + + interface + function omp_get_num_devices () + use omp_lib_kinds + integer (4) :: omp_get_num_devices + end function omp_get_num_devices + end interface + + interface + function omp_get_num_teams () + use omp_lib_kinds + integer (4) :: omp_get_num_teams + end function omp_get_num_teams + end interface + + interface + function omp_get_team_num () + use omp_lib_kinds + integer (4) :: omp_get_team_num + end function omp_get_team_num + end interface + end module omp_lib diff --git a/libgomp/omp_lib.h.in b/libgomp/omp_lib.h.in index f188edcf6612d..3d3e7c77fe318 100644 --- a/libgomp/omp_lib.h.in +++ b/libgomp/omp_lib.h.in @@ -33,6 +33,18 @@ parameter (omp_sched_dynamic = 2) parameter (omp_sched_guided = 3) parameter (omp_sched_auto = 4) + integer omp_proc_bind_kind + parameter (omp_proc_bind_kind = 4) + integer (omp_proc_bind_kind) omp_proc_bind_false + integer (omp_proc_bind_kind) omp_proc_bind_true + integer (omp_proc_bind_kind) omp_proc_bind_master + integer (omp_proc_bind_kind) omp_proc_bind_close + integer (omp_proc_bind_kind) omp_proc_bind_spread + parameter (omp_proc_bind_false = 0) + parameter (omp_proc_bind_true = 1) + parameter (omp_proc_bind_master = 2) + parameter (omp_proc_bind_close = 3) + parameter (omp_proc_bind_spread = 4) parameter (openmp_version = 201107) external omp_init_lock, omp_init_nest_lock @@ -68,3 +80,15 @@ external omp_in_final logical(4) omp_in_final + + external omp_get_cancelllation + logical(4) omp_get_cancelllation + + external omp_get_proc_bind + integer(omp_proc_bind_kind) omp_get_proc_bind + + external omp_set_default_device, omp_get_default_device + external omp_get_num_devices, omp_get_num_teams + external omp_get_team_num + integer(4) omp_get_default_device, omp_get_num_devices + integer(4) omp_get_num_teams, omp_get_team_num diff --git a/libgomp/parallel.c b/libgomp/parallel.c index 4573511902589..b034f92dc86f5 100644 --- a/libgomp/parallel.c +++ b/libgomp/parallel.c @@ -129,7 +129,28 @@ GOMP_parallel_end (void) } gomp_team_end (); } +ialias (GOMP_parallel_end) +void +GOMP_parallel (void (*fn) (void *), void *data, unsigned num_threads, unsigned int flags) +{ + (void) flags; + num_threads = gomp_resolve_num_threads (num_threads, 0); + gomp_team_start (fn, data, num_threads, gomp_new_team (num_threads)); + fn (data); + ialias_call (GOMP_parallel_end) (); +} + +void +GOMP_cancel (void) +{ + /* Nothing so far. */ +} + +void +GOMP_cancellation_point (void) +{ +} /* The public OpenMP API for thread and team related inquiries. */ diff --git a/libgomp/sections.c b/libgomp/sections.c index 369f7a4426fd7..5da87cd060918 100644 --- a/libgomp/sections.c +++ b/libgomp/sections.c @@ -142,6 +142,23 @@ GOMP_parallel_sections_start (void (*fn) (void *), void *data, gomp_team_start (fn, data, num_threads, team); } +ialias_redirect (GOMP_parallel_end) + +void +GOMP_parallel_sections (void (*fn) (void *), void *data, + unsigned num_threads, unsigned count, unsigned flags) +{ + struct gomp_team *team; + + (void) flags; + num_threads = gomp_resolve_num_threads (num_threads, count); + team = gomp_new_team (num_threads); + gomp_sections_init (&team->work_shares[0], count); + gomp_team_start (fn, data, num_threads, team); + fn (data); + GOMP_parallel_end (); +} + /* The GOMP_section_end* routines are called after the thread is told that all sections are complete. This first version synchronizes all threads; the nowait version does not. */ diff --git a/libgomp/task.c b/libgomp/task.c index 7de650a43f145..fb7dcf581da65 100644 --- a/libgomp/task.c +++ b/libgomp/task.c @@ -398,6 +398,16 @@ GOMP_taskyield (void) /* Nothing at the moment. */ } +void +GOMP_taskgroup_start (void) +{ +} + +void +GOMP_taskgroup_end (void) +{ +} + int omp_in_final (void) { From 24296ed47feacaff611fe11bc390f1e5a93df5f8 Mon Sep 17 00:00:00 2001 From: jakub Date: Wed, 10 Apr 2013 17:14:29 +0000 Subject: [PATCH 09/63] * builtin-types.def (DEF_FUNCTION_TYPE_8): Document. (BT_FN_VOID_OMPFN_PTR_UINT, BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG, BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG): Remove. (BT_FN_VOID_OMPFN_PTR_UINT_UINT_UINT, BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_UINT, BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG_UINT): New. * gimplify.c (gimplify_scan_omp_clauses, gimplify_adjust_omp_clauses): Handle OMP_CLAUSE_PROC_BIND. * omp-builtins.def (BUILT_IN_GOMP_TASKGROUP_START, BUILT_IN_GOMP_TASKGROUP_END, BUILT_IN_GOMP_PARALLEL_LOOP_STATIC, BUILT_IN_GOMP_PARALLEL_LOOP_DYNAMIC, BUILT_IN_GOMP_PARALLEL_LOOP_GUIDED, BUILT_IN_GOMP_PARALLEL_LOOP_RUNTIME, BUILT_IN_GOMP_PARALLEL, BUILT_IN_GOMP_PARALLEL_SECTIONS): New built-ins. (BUILT_IN_GOMP_PARALLEL_LOOP_STATIC_START, BUILT_IN_GOMP_PARALLEL_LOOP_DYNAMIC_START, BUILT_IN_GOMP_PARALLEL_LOOP_GUIDED_START, BUILT_IN_GOMP_PARALLEL_LOOP_RUNTIME_START, BUILT_IN_GOMP_PARALLEL_START, BUILT_IN_GOMP_PARALLEL_END, BUILT_IN_GOMP_PARALLEL_SECTIONS_START): Remove. * omp-low.c (scan_sharing_clauses): Handle OMP_CLAUSE_PROC_BIND. (expand_parallel_call): Expand #pragma omp parallel* as calls to the new GOMP_parallel_* APIs without _start at the end, instead of GOMP_parallel_*_start followed by fn.omp_fn.N call, followed by GOMP_parallel_end. Handle OMP_CLAUSE_PROC_BIND. * tree-ssa-alias.c (ref_maybe_used_by_call_p_1, call_may_clobber_ref_p_1): Handle BUILT_IN_GOMP_TASKGROUP_END instead of BUILT_IN_GOMP_PARALLEL_END. c-family/ * c-common.c (DEF_FUNCTION_TYPE_8): Define. * c-omp.c (c_split_parallel_clauses): Handle OMP_CLAUSE_PROC_BIND. cp/ * cp-tree.h (finish_omp_taskgroup): New prototype. * parser.c (cp_parser_omp_clause_proc_bind): Require ) instead of colon at the end of the clause. (cp_parser_omp_taskgroup): New function. (cp_parser_omp_construct, cp_parser_pragma): Handle PRAGMA_OMP_TASKGROUP. * semantics.c (finish_omp_taskgroup): New function. fortran/ * f95-lang.c (DEF_FUNCTION_TYPE_8): Define. * types.def (DEF_FUNCTION_TYPE_8): Document. (BT_FN_VOID_OMPFN_PTR_UINT, BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG, BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG): Remove. (BT_FN_VOID_OMPFN_PTR_UINT_UINT_UINT, BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_UINT, BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG_UINT): New. ada/ * gcc-interface/utils.c (DEF_FUNCTION_TYPE_8): Define. lto/ * lto-lang.c (DEF_FUNCTION_TYPE_8): Define. testsuite/ * gcc.dg/gomp/combined-1.c: Look for GOMP_parallel_loop_runtime instead of GOMP_parallel_loop_runtime_start. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gomp-4_0-branch@197676 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog.gomp | 31 +++++++++++++++++++ gcc/ada/ChangeLog.gomp | 9 ++++++ gcc/ada/gcc-interface/utils.c | 6 ++++ gcc/builtin-types.def | 19 +++++++----- gcc/c-family/ChangeLog.gomp | 5 +++ gcc/c-family/c-common.c | 6 ++++ gcc/c-family/c-omp.c | 1 + gcc/cp/ChangeLog.gomp | 10 ++++++ gcc/cp/cp-tree.h | 1 + gcc/cp/parser.c | 30 +++++++++++++++++- gcc/cp/semantics.c | 14 +++++++++ gcc/fortran/ChangeLog.gomp | 10 ++++++ gcc/fortran/f95-lang.c | 15 +++++++++ gcc/fortran/types.def | 18 ++++++----- gcc/gimplify.c | 2 ++ gcc/lto/ChangeLog.gomp | 9 ++++++ gcc/lto/lto-lang.c | 6 ++++ gcc/omp-builtins.def | 42 ++++++++++++++------------ gcc/omp-low.c | 36 +++++++++------------- gcc/testsuite/ChangeLog.gomp | 5 +++ gcc/testsuite/gcc.dg/gomp/combined-1.c | 2 +- gcc/tree-ssa-alias.c | 4 +-- 22 files changed, 220 insertions(+), 61 deletions(-) create mode 100644 gcc/ada/ChangeLog.gomp create mode 100644 gcc/lto/ChangeLog.gomp diff --git a/gcc/ChangeLog.gomp b/gcc/ChangeLog.gomp index e14fe71770065..a4fcbb3dfea2c 100644 --- a/gcc/ChangeLog.gomp +++ b/gcc/ChangeLog.gomp @@ -1,3 +1,34 @@ +2013-04-10 Jakub Jelinek + + * builtin-types.def (DEF_FUNCTION_TYPE_8): Document. + (BT_FN_VOID_OMPFN_PTR_UINT, BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG, + BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG): Remove. + (BT_FN_VOID_OMPFN_PTR_UINT_UINT_UINT, + BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_UINT, + BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG_UINT): New. + * gimplify.c (gimplify_scan_omp_clauses, gimplify_adjust_omp_clauses): + Handle OMP_CLAUSE_PROC_BIND. + * omp-builtins.def (BUILT_IN_GOMP_TASKGROUP_START, + BUILT_IN_GOMP_TASKGROUP_END, BUILT_IN_GOMP_PARALLEL_LOOP_STATIC, + BUILT_IN_GOMP_PARALLEL_LOOP_DYNAMIC, + BUILT_IN_GOMP_PARALLEL_LOOP_GUIDED, + BUILT_IN_GOMP_PARALLEL_LOOP_RUNTIME, BUILT_IN_GOMP_PARALLEL, + BUILT_IN_GOMP_PARALLEL_SECTIONS): New built-ins. + (BUILT_IN_GOMP_PARALLEL_LOOP_STATIC_START, + BUILT_IN_GOMP_PARALLEL_LOOP_DYNAMIC_START, + BUILT_IN_GOMP_PARALLEL_LOOP_GUIDED_START, + BUILT_IN_GOMP_PARALLEL_LOOP_RUNTIME_START, + BUILT_IN_GOMP_PARALLEL_START, BUILT_IN_GOMP_PARALLEL_END, + BUILT_IN_GOMP_PARALLEL_SECTIONS_START): Remove. + * omp-low.c (scan_sharing_clauses): Handle OMP_CLAUSE_PROC_BIND. + (expand_parallel_call): Expand #pragma omp parallel* as + calls to the new GOMP_parallel_* APIs without _start at the end, + instead of GOMP_parallel_*_start followed by fn.omp_fn.N call, + followed by GOMP_parallel_end. Handle OMP_CLAUSE_PROC_BIND. + * tree-ssa-alias.c (ref_maybe_used_by_call_p_1, + call_may_clobber_ref_p_1): Handle BUILT_IN_GOMP_TASKGROUP_END + instead of BUILT_IN_GOMP_PARALLEL_END. + 2013-03-27 Jakub Jelinek * gimple-pretty-print.c (dump_gimple_omp_for): Handle different diff --git a/gcc/ada/ChangeLog.gomp b/gcc/ada/ChangeLog.gomp new file mode 100644 index 0000000000000..0bb46186d2b10 --- /dev/null +++ b/gcc/ada/ChangeLog.gomp @@ -0,0 +1,9 @@ +2013-04-10 Jakub Jelinek + + * gcc-interface/utils.c (DEF_FUNCTION_TYPE_8): Define. + +Copyright (C) 2013 Free Software Foundation, Inc. + +Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. diff --git a/gcc/ada/gcc-interface/utils.c b/gcc/ada/gcc-interface/utils.c index 309cff6ad32c0..ad3788ca6f557 100644 --- a/gcc/ada/gcc-interface/utils.c +++ b/gcc/ada/gcc-interface/utils.c @@ -5755,6 +5755,7 @@ enum c_builtin_type #define DEF_FUNCTION_TYPE_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) NAME, #define DEF_FUNCTION_TYPE_6(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6) NAME, #define DEF_FUNCTION_TYPE_7(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7) NAME, +#define DEF_FUNCTION_TYPE_8(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7, ARG8) NAME, #define DEF_FUNCTION_TYPE_VAR_0(NAME, RETURN) NAME, #define DEF_FUNCTION_TYPE_VAR_1(NAME, RETURN, ARG1) NAME, #define DEF_FUNCTION_TYPE_VAR_2(NAME, RETURN, ARG1, ARG2) NAME, @@ -5773,6 +5774,7 @@ enum c_builtin_type #undef DEF_FUNCTION_TYPE_5 #undef DEF_FUNCTION_TYPE_6 #undef DEF_FUNCTION_TYPE_7 +#undef DEF_FUNCTION_TYPE_8 #undef DEF_FUNCTION_TYPE_VAR_0 #undef DEF_FUNCTION_TYPE_VAR_1 #undef DEF_FUNCTION_TYPE_VAR_2 @@ -5868,6 +5870,10 @@ install_builtin_function_types (void) #define DEF_FUNCTION_TYPE_7(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ ARG6, ARG7) \ def_fn_type (ENUM, RETURN, 0, 7, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7); +#define DEF_FUNCTION_TYPE_8(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7, ARG8) \ + def_fn_type (ENUM, RETURN, 0, 8, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, \ + ARG7, ARG8); #define DEF_FUNCTION_TYPE_VAR_0(ENUM, RETURN) \ def_fn_type (ENUM, RETURN, 1, 0); #define DEF_FUNCTION_TYPE_VAR_1(ENUM, RETURN, ARG1) \ diff --git a/gcc/builtin-types.def b/gcc/builtin-types.def index 3ef2d1bbf4a25..4c866f2a73646 100644 --- a/gcc/builtin-types.def +++ b/gcc/builtin-types.def @@ -34,6 +34,8 @@ along with GCC; see the file COPYING3. If not see DEF_FUNCTION_TYPE_5 (ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) DEF_FUNCTION_TYPE_6 (ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6) DEF_FUNCTION_TYPE_7 (ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7) + DEF_FUNCTION_TYPE_8 (ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7, + ARG8) These macros describe function types. ENUM is as above. The RETURN type is one of the enumerals already defined. ARG1, ARG2, @@ -409,8 +411,6 @@ DEF_FUNCTION_TYPE_3 (BT_FN_I4_VPTR_I4_I4, BT_I4, BT_VOLATILE_PTR, BT_I4, BT_I4) DEF_FUNCTION_TYPE_3 (BT_FN_I8_VPTR_I8_I8, BT_I8, BT_VOLATILE_PTR, BT_I8, BT_I8) DEF_FUNCTION_TYPE_3 (BT_FN_I16_VPTR_I16_I16, BT_I16, BT_VOLATILE_PTR, BT_I16, BT_I16) -DEF_FUNCTION_TYPE_3 (BT_FN_VOID_OMPFN_PTR_UINT, BT_VOID, BT_PTR_FN_VOID_PTR, - BT_PTR, BT_UINT) DEF_FUNCTION_TYPE_3 (BT_FN_PTR_CONST_PTR_INT_SIZE, BT_PTR, BT_CONST_PTR, BT_INT, BT_SIZE) DEF_FUNCTION_TYPE_3 (BT_FN_I1_VPTR_I1_INT, BT_I1, BT_VOLATILE_PTR, BT_I1, BT_INT) @@ -465,6 +465,9 @@ DEF_FUNCTION_TYPE_5 (BT_FN_BOOL_VPTR_PTR_I8_INT_INT, BT_BOOL, BT_VOLATILE_PTR, BT_PTR, BT_I8, BT_INT, BT_INT) DEF_FUNCTION_TYPE_5 (BT_FN_BOOL_VPTR_PTR_I16_INT_INT, BT_BOOL, BT_VOLATILE_PTR, BT_PTR, BT_I16, BT_INT, BT_INT) +DEF_FUNCTION_TYPE_5 (BT_FN_VOID_OMPFN_PTR_UINT_UINT_UINT, + BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT, BT_UINT, + BT_UINT) DEF_FUNCTION_TYPE_6 (BT_FN_INT_STRING_SIZE_INT_SIZE_CONST_STRING_VALIST_ARG, BT_INT, BT_STRING, BT_SIZE, BT_INT, BT_SIZE, @@ -472,9 +475,6 @@ DEF_FUNCTION_TYPE_6 (BT_FN_INT_STRING_SIZE_INT_SIZE_CONST_STRING_VALIST_ARG, DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_LONG_LONG_LONG_LONG_LONGPTR_LONGPTR, BT_BOOL, BT_LONG, BT_LONG, BT_LONG, BT_LONG, BT_PTR_LONG, BT_PTR_LONG) -DEF_FUNCTION_TYPE_6 (BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG, - BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT, - BT_LONG, BT_LONG, BT_LONG) DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_BOOL_ULL_ULL_ULL_ULLPTR_ULLPTR, BT_BOOL, BT_BOOL, BT_ULONGLONG, BT_ULONGLONG, BT_ULONGLONG, BT_PTR_ULONGLONG, BT_PTR_ULONGLONG) @@ -496,10 +496,9 @@ DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_VPTR_PTR_I16_BOOL_INT_INT, DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_SIZE_VPTR_PTR_PTR_INT_INT, BT_BOOL, BT_SIZE, BT_VOLATILE_PTR, BT_PTR, BT_PTR, BT_INT, BT_INT) - -DEF_FUNCTION_TYPE_7 (BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG, +DEF_FUNCTION_TYPE_7 (BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_UINT, BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT, - BT_LONG, BT_LONG, BT_LONG, BT_LONG) + BT_LONG, BT_LONG, BT_LONG, BT_UINT) DEF_FUNCTION_TYPE_7 (BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT, BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_PTR_FN_VOID_PTR_PTR, BT_LONG, BT_LONG, @@ -509,6 +508,10 @@ DEF_FUNCTION_TYPE_7 (BT_FN_BOOL_BOOL_ULL_ULL_ULL_ULL_ULLPTR_ULLPTR, BT_ULONGLONG, BT_ULONGLONG, BT_PTR_ULONGLONG, BT_PTR_ULONGLONG) +DEF_FUNCTION_TYPE_8 (BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG_UINT, + BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT, + BT_LONG, BT_LONG, BT_LONG, BT_LONG, BT_UINT) + DEF_FUNCTION_TYPE_VAR_0 (BT_FN_VOID_VAR, BT_VOID) DEF_FUNCTION_TYPE_VAR_0 (BT_FN_INT_VAR, BT_INT) DEF_FUNCTION_TYPE_VAR_0 (BT_FN_PTR_VAR, BT_PTR) diff --git a/gcc/c-family/ChangeLog.gomp b/gcc/c-family/ChangeLog.gomp index 73d9dda26720f..22db33a10d1e4 100644 --- a/gcc/c-family/ChangeLog.gomp +++ b/gcc/c-family/ChangeLog.gomp @@ -1,3 +1,8 @@ +2013-04-10 Jakub Jelinek + + * c-common.c (DEF_FUNCTION_TYPE_8): Define. + * c-omp.c (c_split_parallel_clauses): Handle OMP_CLAUSE_PROC_BIND. + 2013-03-27 Jakub Jelinek * c-omp.c (c_finish_omp_for): Add code argument, pass it down to diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index c7cdd0fc7a0bb..3d1144e5edd48 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -5017,6 +5017,7 @@ enum c_builtin_type #define DEF_FUNCTION_TYPE_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) NAME, #define DEF_FUNCTION_TYPE_6(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6) NAME, #define DEF_FUNCTION_TYPE_7(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7) NAME, +#define DEF_FUNCTION_TYPE_8(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7, ARG8) NAME, #define DEF_FUNCTION_TYPE_VAR_0(NAME, RETURN) NAME, #define DEF_FUNCTION_TYPE_VAR_1(NAME, RETURN, ARG1) NAME, #define DEF_FUNCTION_TYPE_VAR_2(NAME, RETURN, ARG1, ARG2) NAME, @@ -5035,6 +5036,7 @@ enum c_builtin_type #undef DEF_FUNCTION_TYPE_5 #undef DEF_FUNCTION_TYPE_6 #undef DEF_FUNCTION_TYPE_7 +#undef DEF_FUNCTION_TYPE_8 #undef DEF_FUNCTION_TYPE_VAR_0 #undef DEF_FUNCTION_TYPE_VAR_1 #undef DEF_FUNCTION_TYPE_VAR_2 @@ -5117,6 +5119,10 @@ c_define_builtins (tree va_list_ref_type_node, tree va_list_arg_type_node) #define DEF_FUNCTION_TYPE_7(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ ARG6, ARG7) \ def_fn_type (ENUM, RETURN, 0, 7, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7); +#define DEF_FUNCTION_TYPE_8(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7, ARG8) \ + def_fn_type (ENUM, RETURN, 0, 8, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, \ + ARG7, ARG8); #define DEF_FUNCTION_TYPE_VAR_0(ENUM, RETURN) \ def_fn_type (ENUM, RETURN, 1, 0); #define DEF_FUNCTION_TYPE_VAR_1(ENUM, RETURN, ARG1) \ diff --git a/gcc/c-family/c-omp.c b/gcc/c-family/c-omp.c index 91112b3f6d351..06a2da28fe2f2 100644 --- a/gcc/c-family/c-omp.c +++ b/gcc/c-family/c-omp.c @@ -614,6 +614,7 @@ c_split_parallel_clauses (location_t loc, tree clauses, case OMP_CLAUSE_IF: case OMP_CLAUSE_NUM_THREADS: case OMP_CLAUSE_DEFAULT: + case OMP_CLAUSE_PROC_BIND: OMP_CLAUSE_CHAIN (clauses) = *par_clauses; *par_clauses = clauses; break; diff --git a/gcc/cp/ChangeLog.gomp b/gcc/cp/ChangeLog.gomp index a97549ab3660b..8fa457fbef950 100644 --- a/gcc/cp/ChangeLog.gomp +++ b/gcc/cp/ChangeLog.gomp @@ -1,3 +1,13 @@ +2013-04-10 Jakub Jelinek + + * cp-tree.h (finish_omp_taskgroup): New prototype. + * parser.c (cp_parser_omp_clause_proc_bind): Require ) instead of + colon at the end of the clause. + (cp_parser_omp_taskgroup): New function. + (cp_parser_omp_construct, cp_parser_pragma): Handle + PRAGMA_OMP_TASKGROUP. + * semantics.c (finish_omp_taskgroup): New function. + 2013-04-05 Jakub Jelinek * semantics.c (finish_omp_for): Disallow class iterators for diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 2d33218eb141e..df4ec2d6881b0 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5718,6 +5718,7 @@ extern void finish_omp_barrier (void); extern void finish_omp_flush (void); extern void finish_omp_taskwait (void); extern void finish_omp_taskyield (void); +extern void finish_omp_taskgroup (tree); extern void finish_omp_cancel (tree); extern void finish_omp_cancellation_point (tree); extern tree begin_transaction_stmt (location_t, tree *, int); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 067d9d96f751e..a8ae55334be65 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -26736,7 +26736,7 @@ cp_parser_omp_clause_proc_bind (cp_parser *parser, tree list, goto invalid_kind; cp_lexer_consume_token (parser->lexer); - if (!cp_parser_require (parser, CPP_COLON, RT_COLON)) + if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_COMMA_CLOSE_PAREN)) goto resync_fail; c = build_omp_clause (location, OMP_CLAUSE_PROC_BIND); @@ -28389,6 +28389,30 @@ cp_parser_omp_taskyield (cp_parser *parser, cp_token *pragma_tok) finish_omp_taskyield (); } +/* OpenMP 4.0: + # pragma omp taskgroup new-line + structured-block */ + +static void +cp_parser_omp_taskgroup (cp_parser *parser, cp_token *pragma_tok) +{ + tree sb; + unsigned int save; + location_t saved_loc; + + cp_parser_require_pragma_eol (parser, pragma_tok); + sb = begin_omp_structured_block (); + save = cp_parser_begin_omp_structured_block (parser); + cp_parser_statement (parser, NULL_TREE, false, NULL); + cp_parser_end_omp_structured_block (parser, save); + saved_loc = input_location; + input_location = pragma_tok->location; + finish_omp_taskgroup (finish_omp_structured_block (sb)); + input_location = saved_loc; +} + + + /* OpenMP 2.5: # pragma omp threadprivate (variable-list) */ @@ -28499,6 +28523,9 @@ cp_parser_omp_construct (cp_parser *parser, cp_token *pragma_tok) case PRAGMA_OMP_TASK: stmt = cp_parser_omp_task (parser, pragma_tok); break; + case PRAGMA_OMP_TASKGROUP: + cp_parser_omp_taskgroup (parser, pragma_tok); + return; default: gcc_unreachable (); } @@ -28971,6 +28998,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context) case PRAGMA_OMP_SIMD: case PRAGMA_OMP_SINGLE: case PRAGMA_OMP_TASK: + case PRAGMA_OMP_TASKGROUP: if (context == pragma_external) goto bad_stmt; cp_parser_omp_construct (parser, pragma_tok); diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 4f72d69495b1f..dfa6c8ad9cb82 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -5340,6 +5340,20 @@ finish_omp_taskyield (void) finish_expr_stmt (stmt); } +void +finish_omp_taskgroup (tree block_stmt) +{ + tree fn = builtin_decl_explicit (BUILT_IN_GOMP_TASKGROUP_START); + vec *vec = make_tree_vector (); + tree stmt = finish_call_expr (fn, &vec, false, false, tf_warning_or_error); + finish_expr_stmt (stmt); + finish_expr_stmt (block_stmt); + fn = builtin_decl_explicit (BUILT_IN_GOMP_TASKGROUP_END); + stmt = finish_call_expr (fn, &vec, false, false, tf_warning_or_error); + finish_expr_stmt (stmt); + release_tree_vector (vec); +} + void finish_omp_cancel (tree clauses) { diff --git a/gcc/fortran/ChangeLog.gomp b/gcc/fortran/ChangeLog.gomp index 56f769617f06b..78870f73c5593 100644 --- a/gcc/fortran/ChangeLog.gomp +++ b/gcc/fortran/ChangeLog.gomp @@ -1,3 +1,13 @@ +2013-04-10 Jakub Jelinek + + * f95-lang.c (DEF_FUNCTION_TYPE_8): Define. + * types.def (DEF_FUNCTION_TYPE_8): Document. + (BT_FN_VOID_OMPFN_PTR_UINT, BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG, + BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG): Remove. + (BT_FN_VOID_OMPFN_PTR_UINT_UINT_UINT, + BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_UINT, + BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG_UINT): New. + 2013-03-27 Jakub Jelinek * f95-lang.c (ATTR_NULL): Define. diff --git a/gcc/fortran/f95-lang.c b/gcc/fortran/f95-lang.c index a67691dfb08e1..91ca3052638d9 100644 --- a/gcc/fortran/f95-lang.c +++ b/gcc/fortran/f95-lang.c @@ -619,6 +619,7 @@ gfc_init_builtin_functions (void) #define DEF_FUNCTION_TYPE_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) NAME, #define DEF_FUNCTION_TYPE_6(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6) NAME, #define DEF_FUNCTION_TYPE_7(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7) NAME, +#define DEF_FUNCTION_TYPE_8(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7, ARG8) NAME, #define DEF_FUNCTION_TYPE_VAR_0(NAME, RETURN) NAME, #define DEF_POINTER_TYPE(NAME, TYPE) NAME, #include "types.def" @@ -631,6 +632,7 @@ gfc_init_builtin_functions (void) #undef DEF_FUNCTION_TYPE_5 #undef DEF_FUNCTION_TYPE_6 #undef DEF_FUNCTION_TYPE_7 +#undef DEF_FUNCTION_TYPE_8 #undef DEF_FUNCTION_TYPE_VAR_0 #undef DEF_POINTER_TYPE BT_LAST @@ -993,6 +995,19 @@ gfc_init_builtin_functions (void) builtin_types[(int) ARG6], \ builtin_types[(int) ARG7], \ NULL_TREE); +#define DEF_FUNCTION_TYPE_8(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7, ARG8) \ + builtin_types[(int) ENUM] \ + = build_function_type_list (builtin_types[(int) RETURN], \ + builtin_types[(int) ARG1], \ + builtin_types[(int) ARG2], \ + builtin_types[(int) ARG3], \ + builtin_types[(int) ARG4], \ + builtin_types[(int) ARG5], \ + builtin_types[(int) ARG6], \ + builtin_types[(int) ARG7], \ + builtin_types[(int) ARG8], \ + NULL_TREE); #define DEF_FUNCTION_TYPE_VAR_0(ENUM, RETURN) \ builtin_types[(int) ENUM] \ = build_varargs_function_type_list (builtin_types[(int) RETURN], \ diff --git a/gcc/fortran/types.def b/gcc/fortran/types.def index e4cd1d18eb955..e1f3da1522af0 100644 --- a/gcc/fortran/types.def +++ b/gcc/fortran/types.def @@ -34,6 +34,8 @@ along with GCC; see the file COPYING3. If not see DEF_FUNCTION_TYPE_5 (ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) DEF_FUNCTION_TYPE_6 (ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6) DEF_FUNCTION_TYPE_7 (ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7) + DEF_FUNCTION_TYPE_8 (ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7, + ARG8) These macros describe function types. ENUM is as above. The RETURN type is one of the enumerals already defined. ARG1, ARG2, @@ -137,8 +139,6 @@ DEF_FUNCTION_TYPE_3 (BT_FN_I4_VPTR_I4_I4, BT_I4, BT_VOLATILE_PTR, BT_I4, BT_I4) DEF_FUNCTION_TYPE_3 (BT_FN_I8_VPTR_I8_I8, BT_I8, BT_VOLATILE_PTR, BT_I8, BT_I8) DEF_FUNCTION_TYPE_3 (BT_FN_I16_VPTR_I16_I16, BT_I16, BT_VOLATILE_PTR, BT_I16, BT_I16) -DEF_FUNCTION_TYPE_3 (BT_FN_VOID_OMPFN_PTR_UINT, BT_VOID, BT_PTR_FN_VOID_PTR, - BT_PTR, BT_UINT) DEF_FUNCTION_TYPE_3 (BT_FN_I1_VPTR_I1_INT, BT_I1, BT_VOLATILE_PTR, BT_I1, BT_INT) DEF_FUNCTION_TYPE_3 (BT_FN_I2_VPTR_I2_INT, BT_I2, BT_VOLATILE_PTR, BT_I2, BT_INT) DEF_FUNCTION_TYPE_3 (BT_FN_I4_VPTR_I4_INT, BT_I4, BT_VOLATILE_PTR, BT_I4, BT_INT) @@ -159,6 +159,9 @@ DEF_FUNCTION_TYPE_4 (BT_FN_VOID_SIZE_VPTR_PTR_INT, BT_VOID, BT_SIZE, DEF_FUNCTION_TYPE_4 (BT_FN_VOID_SIZE_CONST_VPTR_PTR_INT, BT_VOID, BT_SIZE, BT_CONST_VOLATILE_PTR, BT_PTR, BT_INT) +DEF_FUNCTION_TYPE_5 (BT_FN_VOID_OMPFN_PTR_UINT_UINT_UINT, + BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT, BT_UINT, + BT_UINT) DEF_FUNCTION_TYPE_5 (BT_FN_BOOL_LONG_LONG_LONG_LONGPTR_LONGPTR, BT_BOOL, BT_LONG, BT_LONG, BT_LONG, BT_PTR_LONG, BT_PTR_LONG) @@ -168,9 +171,6 @@ DEF_FUNCTION_TYPE_5 (BT_FN_VOID_SIZE_VPTR_PTR_PTR_INT, BT_VOID, BT_SIZE, DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_LONG_LONG_LONG_LONG_LONGPTR_LONGPTR, BT_BOOL, BT_LONG, BT_LONG, BT_LONG, BT_LONG, BT_PTR_LONG, BT_PTR_LONG) -DEF_FUNCTION_TYPE_6 (BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG, - BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT, - BT_LONG, BT_LONG, BT_LONG) DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_BOOL_ULL_ULL_ULL_ULLPTR_ULLPTR, BT_BOOL, BT_BOOL, BT_ULONGLONG, BT_ULONGLONG, BT_ULONGLONG, BT_PTR_ULONGLONG, BT_PTR_ULONGLONG) @@ -192,9 +192,9 @@ DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_VPTR_PTR_I16_BOOL_INT_INT, DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_SIZE_VPTR_PTR_PTR_INT_INT, BT_BOOL, BT_SIZE, BT_VOLATILE_PTR, BT_PTR, BT_PTR, BT_INT, BT_INT) -DEF_FUNCTION_TYPE_7 (BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG, +DEF_FUNCTION_TYPE_7 (BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_UINT, BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT, - BT_LONG, BT_LONG, BT_LONG, BT_LONG) + BT_LONG, BT_LONG, BT_LONG, BT_UINT) DEF_FUNCTION_TYPE_7 (BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT, BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_PTR_FN_VOID_PTR_PTR, BT_LONG, BT_LONG, @@ -204,4 +204,8 @@ DEF_FUNCTION_TYPE_7 (BT_FN_BOOL_BOOL_ULL_ULL_ULL_ULL_ULLPTR_ULLPTR, BT_ULONGLONG, BT_ULONGLONG, BT_PTR_ULONGLONG, BT_PTR_ULONGLONG) +DEF_FUNCTION_TYPE_8 (BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG_UINT, + BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT, + BT_LONG, BT_LONG, BT_LONG, BT_LONG, BT_UINT) + DEF_FUNCTION_TYPE_VAR_0 (BT_FN_VOID_VAR, BT_VOID) diff --git a/gcc/gimplify.c b/gcc/gimplify.c index c61215f1584b9..2da2783d6b3a1 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -6301,6 +6301,7 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, case OMP_CLAUSE_UNTIED: case OMP_CLAUSE_COLLAPSE: case OMP_CLAUSE_MERGEABLE: + case OMP_CLAUSE_PROC_BIND: break; case OMP_CLAUSE_DEFAULT: @@ -6443,6 +6444,7 @@ gimplify_adjust_omp_clauses (tree *list_p) case OMP_CLAUSE_COLLAPSE: case OMP_CLAUSE_FINAL: case OMP_CLAUSE_MERGEABLE: + case OMP_CLAUSE_PROC_BIND: break; default: diff --git a/gcc/lto/ChangeLog.gomp b/gcc/lto/ChangeLog.gomp new file mode 100644 index 0000000000000..96cf420959b20 --- /dev/null +++ b/gcc/lto/ChangeLog.gomp @@ -0,0 +1,9 @@ +2013-04-10 Jakub Jelinek + + * lto-lang.c (DEF_FUNCTION_TYPE_8): Define. + +Copyright (C) 2013 Free Software Foundation, Inc. + +Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. diff --git a/gcc/lto/lto-lang.c b/gcc/lto/lto-lang.c index 87a756d57639b..79cc5609994d7 100644 --- a/gcc/lto/lto-lang.c +++ b/gcc/lto/lto-lang.c @@ -140,6 +140,7 @@ enum lto_builtin_type #define DEF_FUNCTION_TYPE_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) NAME, #define DEF_FUNCTION_TYPE_6(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6) NAME, #define DEF_FUNCTION_TYPE_7(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7) NAME, +#define DEF_FUNCTION_TYPE_8(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7, ARG8) NAME, #define DEF_FUNCTION_TYPE_VAR_0(NAME, RETURN) NAME, #define DEF_FUNCTION_TYPE_VAR_1(NAME, RETURN, ARG1) NAME, #define DEF_FUNCTION_TYPE_VAR_2(NAME, RETURN, ARG1, ARG2) NAME, @@ -158,6 +159,7 @@ enum lto_builtin_type #undef DEF_FUNCTION_TYPE_5 #undef DEF_FUNCTION_TYPE_6 #undef DEF_FUNCTION_TYPE_7 +#undef DEF_FUNCTION_TYPE_8 #undef DEF_FUNCTION_TYPE_VAR_0 #undef DEF_FUNCTION_TYPE_VAR_1 #undef DEF_FUNCTION_TYPE_VAR_2 @@ -631,6 +633,10 @@ lto_define_builtins (tree va_list_ref_type_node ATTRIBUTE_UNUSED, #define DEF_FUNCTION_TYPE_7(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ ARG6, ARG7) \ def_fn_type (ENUM, RETURN, 0, 7, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7); +#define DEF_FUNCTION_TYPE_8(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7, ARG8) \ + def_fn_type (ENUM, RETURN, 0, 8, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, \ + ARG7, ARG8); #define DEF_FUNCTION_TYPE_VAR_0(ENUM, RETURN) \ def_fn_type (ENUM, RETURN, 1, 0); #define DEF_FUNCTION_TYPE_VAR_1(ENUM, RETURN, ARG1) \ diff --git a/gcc/omp-builtins.def b/gcc/omp-builtins.def index c7cababa548d5..6a48ecd6cbc9e 100644 --- a/gcc/omp-builtins.def +++ b/gcc/omp-builtins.def @@ -39,6 +39,10 @@ DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TASKWAIT, "GOMP_taskwait", BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST) DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TASKYIELD, "GOMP_taskyield", BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST) +DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TASKGROUP_START, "GOMP_taskgroup_start", + BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST) +DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TASKGROUP_END, "GOMP_taskgroup_end", + BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST) DEF_GOMP_BUILTIN (BUILT_IN_GOMP_CANCEL, "GOMP_cancel", BT_FN_VOID_INT, ATTR_NULL) DEF_GOMP_BUILTIN (BUILT_IN_GOMP_CANCELLATION_POINT, "GOMP_cancellation_point", @@ -160,24 +164,24 @@ DEF_GOMP_BUILTIN (BUILT_IN_GOMP_LOOP_ULL_ORDERED_GUIDED_NEXT, DEF_GOMP_BUILTIN (BUILT_IN_GOMP_LOOP_ULL_ORDERED_RUNTIME_NEXT, "GOMP_loop_ull_ordered_runtime_next", BT_FN_BOOL_ULONGLONGPTR_ULONGLONGPTR, ATTR_NOTHROW_LEAF_LIST) -/* NOTE: Do not change the order of BUILT_IN_GOMP_PARALLEL_LOOP_*_START. +/* NOTE: Do not change the order of BUILT_IN_GOMP_PARALLEL_LOOP_*. They are used in index arithmetic with enum omp_clause_schedule_kind in omp-low.c. */ -DEF_GOMP_BUILTIN (BUILT_IN_GOMP_PARALLEL_LOOP_STATIC_START, - "GOMP_parallel_loop_static_start", - BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG, +DEF_GOMP_BUILTIN (BUILT_IN_GOMP_PARALLEL_LOOP_STATIC, + "GOMP_parallel_loop_static", + BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG_UINT, ATTR_NOTHROW_LIST) -DEF_GOMP_BUILTIN (BUILT_IN_GOMP_PARALLEL_LOOP_DYNAMIC_START, - "GOMP_parallel_loop_dynamic_start", - BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG, +DEF_GOMP_BUILTIN (BUILT_IN_GOMP_PARALLEL_LOOP_DYNAMIC, + "GOMP_parallel_loop_dynamic", + BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG_UINT, ATTR_NOTHROW_LIST) -DEF_GOMP_BUILTIN (BUILT_IN_GOMP_PARALLEL_LOOP_GUIDED_START, - "GOMP_parallel_loop_guided_start", - BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG, +DEF_GOMP_BUILTIN (BUILT_IN_GOMP_PARALLEL_LOOP_GUIDED, + "GOMP_parallel_loop_guided", + BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG_UINT, ATTR_NOTHROW_LIST) -DEF_GOMP_BUILTIN (BUILT_IN_GOMP_PARALLEL_LOOP_RUNTIME_START, - "GOMP_parallel_loop_runtime_start", - BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG, +DEF_GOMP_BUILTIN (BUILT_IN_GOMP_PARALLEL_LOOP_RUNTIME, + "GOMP_parallel_loop_runtime", + BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_UINT, ATTR_NOTHROW_LIST) DEF_GOMP_BUILTIN (BUILT_IN_GOMP_LOOP_END, "GOMP_loop_end", BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST) @@ -187,10 +191,8 @@ DEF_GOMP_BUILTIN (BUILT_IN_GOMP_ORDERED_START, "GOMP_ordered_start", BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST) DEF_GOMP_BUILTIN (BUILT_IN_GOMP_ORDERED_END, "GOMP_ordered_end", BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST) -DEF_GOMP_BUILTIN (BUILT_IN_GOMP_PARALLEL_START, "GOMP_parallel_start", - BT_FN_VOID_OMPFN_PTR_UINT, ATTR_NOTHROW_LIST) -DEF_GOMP_BUILTIN (BUILT_IN_GOMP_PARALLEL_END, "GOMP_parallel_end", - BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST) +DEF_GOMP_BUILTIN (BUILT_IN_GOMP_PARALLEL, "GOMP_parallel", + BT_FN_VOID_OMPFN_PTR_UINT_UINT, ATTR_NOTHROW_LIST) DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TASK, "GOMP_task", BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT, ATTR_NOTHROW_LIST) @@ -198,9 +200,9 @@ DEF_GOMP_BUILTIN (BUILT_IN_GOMP_SECTIONS_START, "GOMP_sections_start", BT_FN_UINT_UINT, ATTR_NOTHROW_LEAF_LIST) DEF_GOMP_BUILTIN (BUILT_IN_GOMP_SECTIONS_NEXT, "GOMP_sections_next", BT_FN_UINT, ATTR_NOTHROW_LEAF_LIST) -DEF_GOMP_BUILTIN (BUILT_IN_GOMP_PARALLEL_SECTIONS_START, - "GOMP_parallel_sections_start", - BT_FN_VOID_OMPFN_PTR_UINT_UINT, ATTR_NOTHROW_LIST) +DEF_GOMP_BUILTIN (BUILT_IN_GOMP_PARALLEL_SECTIONS, + "GOMP_parallel_sections", + BT_FN_VOID_OMPFN_PTR_UINT_UINT_UINT, ATTR_NOTHROW_LIST) DEF_GOMP_BUILTIN (BUILT_IN_GOMP_SECTIONS_END, "GOMP_sections_end", BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST) DEF_GOMP_BUILTIN (BUILT_IN_GOMP_SECTIONS_END_NOWAIT, diff --git a/gcc/omp-low.c b/gcc/omp-low.c index ef4ed5e98ace3..a301b19e8ea8f 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -1471,6 +1471,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) case OMP_CLAUSE_COLLAPSE: case OMP_CLAUSE_UNTIED: case OMP_CLAUSE_MERGEABLE: + case OMP_CLAUSE_PROC_BIND: break; default: @@ -1523,6 +1524,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) case OMP_CLAUSE_UNTIED: case OMP_CLAUSE_FINAL: case OMP_CLAUSE_MERGEABLE: + case OMP_CLAUSE_PROC_BIND: break; default: @@ -2945,7 +2947,7 @@ static void expand_parallel_call (struct omp_region *region, basic_block bb, gimple entry_stmt, vec *ws_args) { - tree t, t1, t2, val, cond, c, clauses; + tree t, t1, t2, val, cond, c, clauses, flags; gimple_stmt_iterator gsi; gimple stmt; enum built_in_function start_ix; @@ -2955,23 +2957,23 @@ expand_parallel_call (struct omp_region *region, basic_block bb, clauses = gimple_omp_parallel_clauses (entry_stmt); - /* Determine what flavor of GOMP_parallel_start we will be + /* Determine what flavor of GOMP_parallel we will be emitting. */ - start_ix = BUILT_IN_GOMP_PARALLEL_START; + start_ix = BUILT_IN_GOMP_PARALLEL; if (is_combined_parallel (region)) { switch (region->inner->type) { case GIMPLE_OMP_FOR: gcc_assert (region->inner->sched_kind != OMP_CLAUSE_SCHEDULE_AUTO); - start_ix2 = ((int)BUILT_IN_GOMP_PARALLEL_LOOP_STATIC_START + start_ix2 = ((int)BUILT_IN_GOMP_PARALLEL_LOOP_STATIC + (region->inner->sched_kind == OMP_CLAUSE_SCHEDULE_RUNTIME ? 3 : region->inner->sched_kind)); start_ix = (enum built_in_function)start_ix2; break; case GIMPLE_OMP_SECTIONS: - start_ix = BUILT_IN_GOMP_PARALLEL_SECTIONS_START; + start_ix = BUILT_IN_GOMP_PARALLEL_SECTIONS; break; default: gcc_unreachable (); @@ -2982,6 +2984,7 @@ expand_parallel_call (struct omp_region *region, basic_block bb, and there is no conditional. */ cond = NULL_TREE; val = build_int_cst (unsigned_type_node, 0); + flags = build_int_cst (unsigned_type_node, 0); c = find_omp_clause (clauses, OMP_CLAUSE_IF); if (c) @@ -2996,6 +2999,10 @@ expand_parallel_call (struct omp_region *region, basic_block bb, else clause_loc = gimple_location (entry_stmt); + c = find_omp_clause (clauses, OMP_CLAUSE_PROC_BIND); + if (c) + flags = build_int_cst (unsigned_type_node, OMP_CLAUSE_PROC_BIND_KIND (c)); + /* Ensure 'val' is of the correct type. */ val = fold_convert_loc (clause_loc, unsigned_type_node, val); @@ -3082,34 +3089,19 @@ expand_parallel_call (struct omp_region *region, basic_block bb, t1 = build_fold_addr_expr (t); t2 = build_fold_addr_expr (gimple_omp_parallel_child_fn (entry_stmt)); - vec_alloc (args, 3 + vec_safe_length (ws_args)); + vec_alloc (args, 4 + vec_safe_length (ws_args)); args->quick_push (t2); args->quick_push (t1); args->quick_push (val); if (ws_args) args->splice (*ws_args); + args->quick_push (flags); t = build_call_expr_loc_vec (UNKNOWN_LOCATION, builtin_decl_explicit (start_ix), args); force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, false, GSI_CONTINUE_LINKING); - - t = gimple_omp_parallel_data_arg (entry_stmt); - if (t == NULL) - t = null_pointer_node; - else - t = build_fold_addr_expr (t); - t = build_call_expr_loc (gimple_location (entry_stmt), - gimple_omp_parallel_child_fn (entry_stmt), 1, t); - force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, - false, GSI_CONTINUE_LINKING); - - t = build_call_expr_loc (gimple_location (entry_stmt), - builtin_decl_explicit (BUILT_IN_GOMP_PARALLEL_END), - 0); - force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, - false, GSI_CONTINUE_LINKING); } diff --git a/gcc/testsuite/ChangeLog.gomp b/gcc/testsuite/ChangeLog.gomp index 5791a4fe98afc..a844e07c98e15 100644 --- a/gcc/testsuite/ChangeLog.gomp +++ b/gcc/testsuite/ChangeLog.gomp @@ -1,3 +1,8 @@ +2013-04-10 Jakub Jelinek + + * gcc.dg/gomp/combined-1.c: Look for GOMP_parallel_loop_runtime + instead of GOMP_parallel_loop_runtime_start. + 2013-03-20 Jakub Jelinek * c-c++-common/gomp/atomic-15.c: Adjust for C diagnostics. diff --git a/gcc/testsuite/gcc.dg/gomp/combined-1.c b/gcc/testsuite/gcc.dg/gomp/combined-1.c index dfed647371f5b..7e23c3256cb8d 100644 --- a/gcc/testsuite/gcc.dg/gomp/combined-1.c +++ b/gcc/testsuite/gcc.dg/gomp/combined-1.c @@ -20,5 +20,5 @@ int foo (void) } } -/* { dg-final { scan-tree-dump-times "GOMP_parallel_loop_runtime_start" 3 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "GOMP_parallel_loop_runtime" 3 "optimized" } } */ /* { dg-final { cleanup-tree-dump "optimized" } } */ diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c index 878d8407185a1..cbb40bb065f27 100644 --- a/gcc/tree-ssa-alias.c +++ b/gcc/tree-ssa-alias.c @@ -1393,6 +1393,7 @@ ref_maybe_used_by_call_p_1 (gimple call, ao_ref *ref) case BUILT_IN_GOMP_ATOMIC_END: case BUILT_IN_GOMP_BARRIER: case BUILT_IN_GOMP_TASKWAIT: + case BUILT_IN_GOMP_TASKGROUP_END: case BUILT_IN_GOMP_CRITICAL_START: case BUILT_IN_GOMP_CRITICAL_END: case BUILT_IN_GOMP_CRITICAL_NAME_START: @@ -1400,7 +1401,6 @@ ref_maybe_used_by_call_p_1 (gimple call, ao_ref *ref) case BUILT_IN_GOMP_LOOP_END: case BUILT_IN_GOMP_ORDERED_START: case BUILT_IN_GOMP_ORDERED_END: - case BUILT_IN_GOMP_PARALLEL_END: case BUILT_IN_GOMP_SECTIONS_END: case BUILT_IN_GOMP_SINGLE_COPY_START: case BUILT_IN_GOMP_SINGLE_COPY_END: @@ -1737,6 +1737,7 @@ call_may_clobber_ref_p_1 (gimple call, ao_ref *ref) case BUILT_IN_GOMP_ATOMIC_END: case BUILT_IN_GOMP_BARRIER: case BUILT_IN_GOMP_TASKWAIT: + case BUILT_IN_GOMP_TASKGROUP_END: case BUILT_IN_GOMP_CRITICAL_START: case BUILT_IN_GOMP_CRITICAL_END: case BUILT_IN_GOMP_CRITICAL_NAME_START: @@ -1744,7 +1745,6 @@ call_may_clobber_ref_p_1 (gimple call, ao_ref *ref) case BUILT_IN_GOMP_LOOP_END: case BUILT_IN_GOMP_ORDERED_START: case BUILT_IN_GOMP_ORDERED_END: - case BUILT_IN_GOMP_PARALLEL_END: case BUILT_IN_GOMP_SECTIONS_END: case BUILT_IN_GOMP_SINGLE_COPY_START: case BUILT_IN_GOMP_SINGLE_COPY_END: From 025c555ed2452035f0e87f45b8d2a7b4ba0819cd Mon Sep 17 00:00:00 2001 From: jakub Date: Fri, 19 Apr 2013 12:59:31 +0000 Subject: [PATCH 10/63] * tree.h (OMP_CLAUSE_LINEAR_NO_COPYIN, OMP_CLAUSE_LINEAR_NO_COPYOUT): Define. * omp-low.c (extract_omp_for_data): Handle #pragma omp simd. (build_outer_var_ref): For #pragma omp simd allow linear etc. clauses to bind even to private vars. (scan_sharing_clauses): Handle OMP_CLAUSE_LINEAR, OMP_CLAUSE_ALIGNED and OMP_CLAUSE_SAFELEN. (lower_rec_input_clauses): Handle OMP_CLAUSE_LINEAR. Don't emit a GOMP_barrier call for firstprivate/lastprivate in #pragma omp simd. (lower_lastprivate_clauses): Handle also OMP_CLAUSE_LINEAR. (expand_omp_simd): New function. (expand_omp_for): Handle #pragma omp simd. * gimplify.c (enum gimplify_omp_var_data): Add GOVD_LINEAR and GOVD_ALIGNED, add GOVD_LINEAR into GOVD_DATA_SHARE_CLASS. (enum omp_region_type): Add ORT_SIMD. (gimple_add_tmp_var, gimplify_var_or_parm_decl, omp_check_private, omp_firstprivatize_variable, omp_notice_variable): Handle ORT_SIMD like ORT_WORKSHARE. (omp_is_private): Likewise. Add SIMD argument, tweak diagnostics and add extra errors in simd constructs. (gimplify_scan_omp_clauses, gimplify_adjust_omp_clauses): Handle OMP_CLAUSE_LINEAR, OMP_CLAUSE_ALIGNED and OMP_CLAUSE_SAFELEN. (gimplify_adjust_omp_clauses_1): Handle GOVD_LASTPRIVATE and GOVD_ALIGNED. (gimplify_omp_for): Handle #pragma omp simd. cp/ * cp-tree.h (CP_OMP_CLAUSE_INFO): Also allow it on OMP_CLAUSE_LINEAR. * parser.c (cp_parser_omp_var_list_no_open): If colon is non-NULL, temporarily disable colon_corrects_to_scope_p during the parsing of the variable list. (cp_parser_omp_clause_safelen, cp_parser_omp_clause_simdlen): New functions. (cp_parser_omp_all_clauses): Handle OMP_CLAUSE_SAFELEN and OMP_CLAUSE_SIMDLEN. * semantics.c (finish_omp_clauses): Allow NULL_TREE in OMP_CLAUSE_ALIGNED_ALIGNMENT. testsuite/ * c-c++-common/gomp/simd1.c: New test. * c-c++-common/gomp/simd2.c: New test. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gomp-4_0-branch@198092 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog.gomp | 28 ++ gcc/cp/ChangeLog.gomp | 13 + gcc/cp/cp-tree.h | 2 +- gcc/cp/parser.c | 84 +++++- gcc/cp/semantics.c | 2 + gcc/gimplify.c | 182 +++++++++++- gcc/omp-low.c | 353 +++++++++++++++++++++++- gcc/testsuite/ChangeLog.gomp | 5 + gcc/testsuite/c-c++-common/gomp/simd1.c | 31 +++ gcc/testsuite/c-c++-common/gomp/simd2.c | 29 ++ gcc/tree.h | 16 ++ 11 files changed, 712 insertions(+), 33 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/gomp/simd1.c create mode 100644 gcc/testsuite/c-c++-common/gomp/simd2.c diff --git a/gcc/ChangeLog.gomp b/gcc/ChangeLog.gomp index a4fcbb3dfea2c..f1eed5263bfc3 100644 --- a/gcc/ChangeLog.gomp +++ b/gcc/ChangeLog.gomp @@ -1,3 +1,31 @@ +2013-04-19 Jakub Jelinek + + * tree.h (OMP_CLAUSE_LINEAR_NO_COPYIN, + OMP_CLAUSE_LINEAR_NO_COPYOUT): Define. + * omp-low.c (extract_omp_for_data): Handle #pragma omp simd. + (build_outer_var_ref): For #pragma omp simd allow linear etc. + clauses to bind even to private vars. + (scan_sharing_clauses): Handle OMP_CLAUSE_LINEAR, OMP_CLAUSE_ALIGNED + and OMP_CLAUSE_SAFELEN. + (lower_rec_input_clauses): Handle OMP_CLAUSE_LINEAR. Don't emit + a GOMP_barrier call for firstprivate/lastprivate in #pragma omp simd. + (lower_lastprivate_clauses): Handle also OMP_CLAUSE_LINEAR. + (expand_omp_simd): New function. + (expand_omp_for): Handle #pragma omp simd. + * gimplify.c (enum gimplify_omp_var_data): Add GOVD_LINEAR and + GOVD_ALIGNED, add GOVD_LINEAR into GOVD_DATA_SHARE_CLASS. + (enum omp_region_type): Add ORT_SIMD. + (gimple_add_tmp_var, gimplify_var_or_parm_decl, omp_check_private, + omp_firstprivatize_variable, omp_notice_variable): Handle ORT_SIMD + like ORT_WORKSHARE. + (omp_is_private): Likewise. Add SIMD argument, tweak diagnostics + and add extra errors in simd constructs. + (gimplify_scan_omp_clauses, gimplify_adjust_omp_clauses): Handle + OMP_CLAUSE_LINEAR, OMP_CLAUSE_ALIGNED and OMP_CLAUSE_SAFELEN. + (gimplify_adjust_omp_clauses_1): Handle GOVD_LASTPRIVATE and + GOVD_ALIGNED. + (gimplify_omp_for): Handle #pragma omp simd. + 2013-04-10 Jakub Jelinek * builtin-types.def (DEF_FUNCTION_TYPE_8): Document. diff --git a/gcc/cp/ChangeLog.gomp b/gcc/cp/ChangeLog.gomp index 8fa457fbef950..602504488e8a1 100644 --- a/gcc/cp/ChangeLog.gomp +++ b/gcc/cp/ChangeLog.gomp @@ -1,3 +1,16 @@ +2013-04-19 Jakub Jelinek + + * cp-tree.h (CP_OMP_CLAUSE_INFO): Also allow it on OMP_CLAUSE_LINEAR. + * parser.c (cp_parser_omp_var_list_no_open): If colon is non-NULL, + temporarily disable colon_corrects_to_scope_p during the parsing + of the variable list. + (cp_parser_omp_clause_safelen, cp_parser_omp_clause_simdlen): New + functions. + (cp_parser_omp_all_clauses): Handle OMP_CLAUSE_SAFELEN and + OMP_CLAUSE_SIMDLEN. + * semantics.c (finish_omp_clauses): Allow NULL_TREE in + OMP_CLAUSE_ALIGNED_ALIGNMENT. + 2013-04-10 Jakub Jelinek * cp-tree.h (finish_omp_taskgroup): New prototype. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index df4ec2d6881b0..bb0a4ae72ce07 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -3984,7 +3984,7 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) See semantics.c for details. */ #define CP_OMP_CLAUSE_INFO(NODE) \ TREE_TYPE (OMP_CLAUSE_RANGE_CHECK (NODE, OMP_CLAUSE_PRIVATE, \ - OMP_CLAUSE_COPYPRIVATE)) + OMP_CLAUSE_LINEAR)) /* Nonzero if this transaction expression's body contains statements. */ #define TRANSACTION_EXPR_IS_STMT(NODE) \ diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index a8ae55334be65..b58da187877b6 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -25875,8 +25875,12 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, tree list, bool *colon) { cp_token *token; + bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p; if (colon) - *colon = false; + { + parser->colon_corrects_to_scope_p = false; + *colon = false; + } while (1) { tree name, decl; @@ -25888,7 +25892,12 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, /*declarator_p=*/false, /*optional_p=*/false); if (name == error_mark_node) - goto skip_comma; + { + if (colon) + parser->colon_corrects_to_scope_p + = saved_colon_corrects_to_scope_p; + goto skip_comma; + } decl = cp_parser_lookup_name_simple (parser, name, token->location); if (decl == error_mark_node) @@ -25910,6 +25919,9 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, cp_lexer_consume_token (parser->lexer); } + if (colon) + parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p; + if (colon != NULL && cp_lexer_next_token_is (parser->lexer, CPP_COLON)) { *colon = true; @@ -26519,6 +26531,64 @@ cp_parser_omp_clause_linear (cp_parser *parser, tree list) return nlist; } +/* OpenMP 4.0: + safelen ( constant-expression ) */ + +static tree +cp_parser_omp_clause_safelen (cp_parser *parser, tree list, + location_t location) +{ + tree t, c; + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + return list; + + t = cp_parser_constant_expression (parser, false, NULL); + + if (t == error_mark_node + || !cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + + check_no_duplicate_clause (list, OMP_CLAUSE_SAFELEN, "safelen", location); + + c = build_omp_clause (location, OMP_CLAUSE_SAFELEN); + OMP_CLAUSE_SAFELEN_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + + return c; +} + +/* OpenMP 4.0: + simdlen ( constant-expression ) */ + +static tree +cp_parser_omp_clause_simdlen (cp_parser *parser, tree list, + location_t location) +{ + tree t, c; + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + return list; + + t = cp_parser_constant_expression (parser, false, NULL); + + if (t == error_mark_node + || !cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + + check_no_duplicate_clause (list, OMP_CLAUSE_SIMDLEN, "simdlen", location); + + c = build_omp_clause (location, OMP_CLAUSE_SIMDLEN); + OMP_CLAUSE_SIMDLEN_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + + return c; +} + /* OpenMP 4.0: depend ( depend-kind : variable-list ) @@ -26944,6 +27014,16 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask, token->location); c_name = "proc_bind"; break; + case PRAGMA_OMP_CLAUSE_SAFELEN: + clauses = cp_parser_omp_clause_safelen (parser, clauses, + token->location); + c_name = "safelen"; + break; + case PRAGMA_OMP_CLAUSE_SIMDLEN: + clauses = cp_parser_omp_clause_simdlen (parser, clauses, + token->location); + c_name = "simdlen"; + break; default: cp_parser_error (parser, "expected %<#pragma omp%> clause"); goto saw_error; diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index dfa6c8ad9cb82..7a45c87f8814f 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -4317,6 +4317,8 @@ finish_omp_clauses (tree clauses) t = OMP_CLAUSE_ALIGNED_ALIGNMENT (c); if (t == error_mark_node) remove = true; + else if (t == NULL_TREE) + break; else if (!type_dependent_expression_p (t) && !INTEGRAL_TYPE_P (TREE_TYPE (t))) { diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 2da2783d6b3a1..f6b67173d1119 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -59,14 +59,18 @@ enum gimplify_omp_var_data GOVD_LOCAL = 128, GOVD_DEBUG_PRIVATE = 256, GOVD_PRIVATE_OUTER_REF = 512, + GOVD_LINEAR = 1024, + GOVD_ALIGNED = 2048, GOVD_DATA_SHARE_CLASS = (GOVD_SHARED | GOVD_PRIVATE | GOVD_FIRSTPRIVATE - | GOVD_LASTPRIVATE | GOVD_REDUCTION | GOVD_LOCAL) + | GOVD_LASTPRIVATE | GOVD_REDUCTION | GOVD_LINEAR + | GOVD_LOCAL) }; enum omp_region_type { ORT_WORKSHARE = 0, + ORT_SIMD = 1, /* #pragma omp for simd is ORT_WORKSHARE. */ ORT_PARALLEL = 2, ORT_COMBINED_PARALLEL = 3, ORT_TASK = 4, @@ -755,7 +759,9 @@ gimple_add_tmp_var (tree tmp) if (gimplify_omp_ctxp) { struct gimplify_omp_ctx *ctx = gimplify_omp_ctxp; - while (ctx && ctx->region_type == ORT_WORKSHARE) + while (ctx + && (ctx->region_type == ORT_WORKSHARE + || ctx->region_type == ORT_SIMD)) ctx = ctx->outer_context; if (ctx) omp_add_variable (ctx, tmp, GOVD_LOCAL | GOVD_SEEN); @@ -2102,7 +2108,9 @@ gimplify_var_or_parm_decl (tree *expr_p) && decl_function_context (decl) != current_function_decl) { struct gimplify_omp_ctx *ctx = gimplify_omp_ctxp; - while (ctx && ctx->region_type == ORT_WORKSHARE) + while (ctx + && (ctx->region_type == ORT_WORKSHARE + || ctx->region_type == ORT_SIMD)) ctx = ctx->outer_context; if (!ctx && !pointer_set_insert (nonlocal_vlas, decl)) { @@ -5751,7 +5759,8 @@ omp_firstprivatize_variable (struct gimplify_omp_ctx *ctx, tree decl) else return; } - else if (ctx->region_type != ORT_WORKSHARE) + else if (ctx->region_type != ORT_WORKSHARE + && ctx->region_type != ORT_SIMD) omp_add_variable (ctx, decl, GOVD_FIRSTPRIVATE); ctx = ctx->outer_context; @@ -5973,7 +5982,8 @@ omp_notice_variable (struct gimplify_omp_ctx *ctx, tree decl, bool in_code) enum omp_clause_default_kind default_kind, kind; struct gimplify_omp_ctx *octx; - if (ctx->region_type == ORT_WORKSHARE) + if (ctx->region_type == ORT_WORKSHARE + || ctx->region_type == ORT_SIMD) goto do_outer; /* ??? Some compiler-generated variables (like SAVE_EXPRs) could be @@ -6086,7 +6096,7 @@ omp_notice_variable (struct gimplify_omp_ctx *ctx, tree decl, bool in_code) to the contrary in the innermost scope, generate an error. */ static bool -omp_is_private (struct gimplify_omp_ctx *ctx, tree decl) +omp_is_private (struct gimplify_omp_ctx *ctx, tree decl, bool simd) { splay_tree_node n; @@ -6097,8 +6107,12 @@ omp_is_private (struct gimplify_omp_ctx *ctx, tree decl) { if (ctx == gimplify_omp_ctxp) { - error ("iteration variable %qE should be private", - DECL_NAME (decl)); + if (simd) + error ("iteration variable %qE is predetermined linear", + DECL_NAME (decl)); + else + error ("iteration variable %qE should be private", + DECL_NAME (decl)); n->value = GOVD_PRIVATE; return true; } @@ -6116,16 +6130,26 @@ omp_is_private (struct gimplify_omp_ctx *ctx, tree decl) else if ((n->value & GOVD_REDUCTION) != 0) error ("iteration variable %qE should not be reduction", DECL_NAME (decl)); + else if (simd && (n->value & GOVD_LASTPRIVATE) != 0) + error ("iteration variable %qE should not be lastprivate", + DECL_NAME (decl)); + else if (simd && (n->value & GOVD_PRIVATE) != 0) + error ("iteration variable %qE should not be private", + DECL_NAME (decl)); + else if (simd && (n->value & GOVD_LINEAR) != 0) + error ("iteration variable %qE is predetermined linear", + DECL_NAME (decl)); } return (ctx == gimplify_omp_ctxp || (ctx->region_type == ORT_COMBINED_PARALLEL && gimplify_omp_ctxp->outer_context == ctx)); } - if (ctx->region_type != ORT_WORKSHARE) + if (ctx->region_type != ORT_WORKSHARE + && ctx->region_type != ORT_SIMD) return false; else if (ctx->outer_context) - return omp_is_private (ctx->outer_context, decl); + return omp_is_private (ctx->outer_context, decl, simd); return false; } @@ -6150,7 +6174,8 @@ omp_check_private (struct gimplify_omp_ctx *ctx, tree decl) if (n != NULL) return (n->value & GOVD_SHARED) == 0; } - while (ctx->region_type == ORT_WORKSHARE); + while (ctx->region_type == ORT_WORKSHARE + || ctx->region_type == ORT_SIMD); return false; } @@ -6203,6 +6228,15 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, flags = GOVD_REDUCTION | GOVD_SEEN | GOVD_EXPLICIT; check_non_private = "reduction"; goto do_add; + case OMP_CLAUSE_LINEAR: + if (gimplify_expr (&OMP_CLAUSE_LINEAR_STEP (c), pre_p, NULL, + is_gimple_val, fb_rvalue) == GS_ERROR) + { + remove = true; + break; + } + flags = GOVD_LINEAR | GOVD_EXPLICIT; + goto do_add; do_add: decl = OMP_CLAUSE_DECL (c); @@ -6293,7 +6327,7 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, case OMP_CLAUSE_NUM_THREADS: if (gimplify_expr (&OMP_CLAUSE_OPERAND (c, 0), pre_p, NULL, is_gimple_val, fb_rvalue) == GS_ERROR) - remove = true; + remove = true; break; case OMP_CLAUSE_NOWAIT: @@ -6302,6 +6336,19 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, case OMP_CLAUSE_COLLAPSE: case OMP_CLAUSE_MERGEABLE: case OMP_CLAUSE_PROC_BIND: + case OMP_CLAUSE_SAFELEN: + break; + + case OMP_CLAUSE_ALIGNED: + decl = OMP_CLAUSE_DECL (c); + if (error_operand_p (decl)) + { + remove = true; + break; + } + if (!is_global_var (decl) + && TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE) + omp_add_variable (ctx, decl, GOVD_ALIGNED); break; case OMP_CLAUSE_DEFAULT: @@ -6372,6 +6419,10 @@ gimplify_adjust_omp_clauses_1 (splay_tree_node n, void *data) code = OMP_CLAUSE_PRIVATE; else if (flags & GOVD_FIRSTPRIVATE) code = OMP_CLAUSE_FIRSTPRIVATE; + else if (flags & GOVD_LASTPRIVATE) + code = OMP_CLAUSE_LASTPRIVATE; + else if (flags & GOVD_ALIGNED) + return 0; else gcc_unreachable (); @@ -6404,6 +6455,7 @@ gimplify_adjust_omp_clauses (tree *list_p) case OMP_CLAUSE_PRIVATE: case OMP_CLAUSE_SHARED: case OMP_CLAUSE_FIRSTPRIVATE: + case OMP_CLAUSE_LINEAR: decl = OMP_CLAUSE_DECL (c); n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl); remove = !(n->value & GOVD_SEEN); @@ -6419,6 +6471,27 @@ gimplify_adjust_omp_clauses (tree *list_p) OMP_CLAUSE_SET_CODE (c, OMP_CLAUSE_PRIVATE); OMP_CLAUSE_PRIVATE_DEBUG (c) = 1; } + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR + && ctx->outer_context + && ctx->outer_context->region_type == ORT_COMBINED_PARALLEL + && !(OMP_CLAUSE_LINEAR_NO_COPYIN (c) + && OMP_CLAUSE_LINEAR_NO_COPYOUT (c)) + && !is_global_var (decl)) + { + n = splay_tree_lookup (ctx->outer_context->variables, + (splay_tree_key) decl); + if (n == NULL + || (n->value & GOVD_DATA_SHARE_CLASS) == 0) + { + int flags = OMP_CLAUSE_LINEAR_NO_COPYIN (c) + ? GOVD_LASTPRIVATE : GOVD_SHARED; + if (n == NULL) + omp_add_variable (ctx->outer_context, decl, + flags | GOVD_SEEN); + else + n->value |= flags | GOVD_SEEN; + } + } } break; @@ -6431,6 +6504,15 @@ gimplify_adjust_omp_clauses (tree *list_p) = (n->value & GOVD_FIRSTPRIVATE) != 0; break; + case OMP_CLAUSE_ALIGNED: + decl = OMP_CLAUSE_DECL (c); + if (!is_global_var (decl)) + { + n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl); + remove = n == NULL || !(n->value & GOVD_SEEN); + } + break; + case OMP_CLAUSE_REDUCTION: case OMP_CLAUSE_COPYIN: case OMP_CLAUSE_COPYPRIVATE: @@ -6445,6 +6527,7 @@ gimplify_adjust_omp_clauses (tree *list_p) case OMP_CLAUSE_FINAL: case OMP_CLAUSE_MERGEABLE: case OMP_CLAUSE_PROC_BIND: + case OMP_CLAUSE_SAFELEN: break; default: @@ -6548,14 +6631,42 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) gimple gfor; gimple_seq for_body, for_pre_body; int i; + bool simd; + bitmap has_decl_expr = NULL; for_stmt = *expr_p; + simd = TREE_CODE (for_stmt) == OMP_SIMD + || TREE_CODE (for_stmt) == OMP_FOR_SIMD; gimplify_scan_omp_clauses (&OMP_FOR_CLAUSES (for_stmt), pre_p, - ORT_WORKSHARE); + TREE_CODE (for_stmt) == OMP_SIMD + ? ORT_SIMD : ORT_WORKSHARE); /* Handle OMP_FOR_INIT. */ for_pre_body = NULL; + if (simd && OMP_FOR_PRE_BODY (for_stmt)) + { + has_decl_expr = BITMAP_ALLOC (NULL); + if (TREE_CODE (OMP_FOR_PRE_BODY (for_stmt)) == DECL_EXPR + && TREE_CODE (DECL_EXPR_DECL (OMP_FOR_PRE_BODY (for_stmt))) + == VAR_DECL) + { + t = OMP_FOR_PRE_BODY (for_stmt); + bitmap_set_bit (has_decl_expr, DECL_UID (DECL_EXPR_DECL (t))); + } + else if (TREE_CODE (OMP_FOR_PRE_BODY (for_stmt)) == STATEMENT_LIST) + { + tree_stmt_iterator si; + for (si = tsi_start (OMP_FOR_PRE_BODY (for_stmt)); !tsi_end_p (si); + tsi_next (&si)) + { + t = tsi_stmt (si); + if (TREE_CODE (t) == DECL_EXPR + && TREE_CODE (DECL_EXPR_DECL (t)) == VAR_DECL) + bitmap_set_bit (has_decl_expr, DECL_UID (DECL_EXPR_DECL (t))); + } + } + } gimplify_and_add (OMP_FOR_PRE_BODY (for_stmt), &for_pre_body); OMP_FOR_PRE_BODY (for_stmt) = NULL_TREE; @@ -6574,7 +6685,29 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) || POINTER_TYPE_P (TREE_TYPE (decl))); /* Make sure the iteration variable is private. */ - if (omp_is_private (gimplify_omp_ctxp, decl)) + bool is_private = omp_is_private (gimplify_omp_ctxp, decl, simd); + tree c = NULL_TREE; + if (simd) + { + splay_tree_node n = splay_tree_lookup (gimplify_omp_ctxp->variables, + (splay_tree_key)decl); + if (n != NULL && (n->value & GOVD_DATA_SHARE_CLASS) != 0) + omp_notice_variable (gimplify_omp_ctxp, decl, true); + else + { + c = build_omp_clause (input_location, OMP_CLAUSE_LINEAR); + OMP_CLAUSE_LINEAR_NO_COPYIN (c) = 1; + if (has_decl_expr + && bitmap_bit_p (has_decl_expr, DECL_UID (decl))) + OMP_CLAUSE_LINEAR_NO_COPYOUT (c) = 1; + OMP_CLAUSE_DECL (c) = decl; + OMP_CLAUSE_CHAIN (c) = OMP_FOR_CLAUSES (for_stmt); + OMP_FOR_CLAUSES (for_stmt) = c; + omp_add_variable (gimplify_omp_ctxp, decl, + GOVD_LINEAR | GOVD_EXPLICIT | GOVD_SEEN); + } + } + else if (is_private) omp_notice_variable (gimplify_omp_ctxp, decl, true); else omp_add_variable (gimplify_omp_ctxp, decl, GOVD_PRIVATE | GOVD_SEEN); @@ -6616,6 +6749,8 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) case PREINCREMENT_EXPR: case POSTINCREMENT_EXPR: t = build_int_cst (TREE_TYPE (decl), 1); + if (c) + OMP_CLAUSE_LINEAR_STEP (c) = t; t = build2 (PLUS_EXPR, TREE_TYPE (decl), var, t); t = build2 (MODIFY_EXPR, TREE_TYPE (var), var, t); TREE_VEC_ELT (OMP_FOR_INCR (for_stmt), i) = t; @@ -6624,6 +6759,8 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) case PREDECREMENT_EXPR: case POSTDECREMENT_EXPR: t = build_int_cst (TREE_TYPE (decl), -1); + if (c) + OMP_CLAUSE_LINEAR_STEP (c) = t; t = build2 (PLUS_EXPR, TREE_TYPE (decl), var, t); t = build2 (MODIFY_EXPR, TREE_TYPE (var), var, t); TREE_VEC_ELT (OMP_FOR_INCR (for_stmt), i) = t; @@ -6657,6 +6794,20 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) tret = gimplify_expr (&TREE_OPERAND (t, 1), &for_pre_body, NULL, is_gimple_val, fb_rvalue); ret = MIN (ret, tret); + if (c) + { + OMP_CLAUSE_LINEAR_STEP (c) = TREE_OPERAND (t, 1); + if (TREE_CODE (t) == MINUS_EXPR) + { + t = TREE_OPERAND (t, 1); + OMP_CLAUSE_LINEAR_STEP (c) + = fold_build1 (NEGATE_EXPR, TREE_TYPE (t), t); + tret = gimplify_expr (&OMP_CLAUSE_LINEAR_STEP (c), + &for_pre_body, NULL, + is_gimple_val, fb_rvalue); + ret = MIN (ret, tret); + } + } break; default: @@ -6665,7 +6816,6 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) if (var != decl || TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)) > 1) { - tree c; for (c = OMP_FOR_CLAUSES (for_stmt); c ; c = OMP_CLAUSE_CHAIN (c)) if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE && OMP_CLAUSE_DECL (c) == decl @@ -6687,6 +6837,8 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) } } + BITMAP_FREE (has_decl_expr); + gimplify_and_add (OMP_FOR_BODY (for_stmt), &for_body); gimplify_adjust_omp_clauses (&OMP_FOR_CLAUSES (for_stmt)); diff --git a/gcc/omp-low.c b/gcc/omp-low.c index a301b19e8ea8f..58117d97c540e 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -222,6 +222,7 @@ extract_omp_for_data (gimple for_stmt, struct omp_for_data *fd, int i; struct omp_for_data_loop dummy_loop; location_t loc = gimple_location (for_stmt); + bool non_ws = gimple_omp_for_kind (for_stmt) == GF_OMP_FOR_KIND_SIMD; fd->for_stmt = for_stmt; fd->pre = NULL; @@ -292,7 +293,6 @@ extract_omp_for_data (gimple for_stmt, struct omp_for_data *fd, else loop = &dummy_loop; - loop->v = gimple_omp_for_index (for_stmt, i); gcc_assert (SSA_VAR_P (loop->v)); gcc_assert (TREE_CODE (TREE_TYPE (loop->v)) == INTEGER_TYPE @@ -349,7 +349,18 @@ extract_omp_for_data (gimple for_stmt, struct omp_for_data *fd, gcc_unreachable (); } - if (iter_type != long_long_unsigned_type_node) + if (non_ws) + { + if (fd->collapse == 1) + iter_type = TREE_TYPE (loop->v); + else if (i == 0 + || TYPE_PRECISION (iter_type) + < TYPE_PRECISION (TREE_TYPE (loop->v))) + iter_type + = build_nonstandard_integer_type + (TYPE_PRECISION (TREE_TYPE (loop->v)), 1); + } + else if (iter_type != long_long_unsigned_type_node) { if (POINTER_TYPE_P (TREE_TYPE (loop->v))) iter_type = long_long_unsigned_type_node; @@ -440,7 +451,7 @@ extract_omp_for_data (gimple for_stmt, struct omp_for_data *fd, } } - if (count) + if (count && !non_ws) { if (!tree_int_cst_lt (count, TYPE_MAX_VALUE (long_integer_type_node))) iter_type = long_long_unsigned_type_node; @@ -919,6 +930,11 @@ build_outer_var_ref (tree var, omp_context *ctx) /* This can happen with orphaned constructs. If var is reference, it is possible it is shared and as such valid. */ x = var; + else if (gimple_code (ctx->stmt) == GIMPLE_OMP_FOR + && gimple_omp_for_kind (ctx->stmt) == GF_OMP_FOR_KIND_SIMD) + /* #pragma omp simd isn't a worksharing construct, and can reference even + private vars in its linear etc. clauses. */ + x = var; else gcc_unreachable (); @@ -1420,6 +1436,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) case OMP_CLAUSE_FIRSTPRIVATE: case OMP_CLAUSE_REDUCTION: + case OMP_CLAUSE_LINEAR: decl = OMP_CLAUSE_DECL (c); do_private: if (is_variable_sized (decl)) @@ -1472,6 +1489,8 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) case OMP_CLAUSE_UNTIED: case OMP_CLAUSE_MERGEABLE: case OMP_CLAUSE_PROC_BIND: + case OMP_CLAUSE_SAFELEN: + case OMP_CLAUSE_ALIGNED: break; default: @@ -1495,6 +1514,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) case OMP_CLAUSE_PRIVATE: case OMP_CLAUSE_FIRSTPRIVATE: case OMP_CLAUSE_REDUCTION: + case OMP_CLAUSE_LINEAR: decl = OMP_CLAUSE_DECL (c); if (is_variable_sized (decl)) install_var_local (decl, ctx); @@ -1525,6 +1545,8 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) case OMP_CLAUSE_FINAL: case OMP_CLAUSE_MERGEABLE: case OMP_CLAUSE_PROC_BIND: + case OMP_CLAUSE_SAFELEN: + case OMP_CLAUSE_ALIGNED: break; default: @@ -2297,6 +2319,7 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, case OMP_CLAUSE_FIRSTPRIVATE: case OMP_CLAUSE_COPYIN: case OMP_CLAUSE_REDUCTION: + case OMP_CLAUSE_LINEAR: break; case OMP_CLAUSE_LASTPRIVATE: if (OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE (c)) @@ -2442,6 +2465,7 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, } else x = NULL; + do_private: x = lang_hooks.decls.omp_clause_default_ctor (c, new_var, x); if (x) gimplify_and_add (x, ilist); @@ -2459,6 +2483,15 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, } break; + case OMP_CLAUSE_LINEAR: + if (!OMP_CLAUSE_LINEAR_NO_COPYIN (c)) + goto do_firstprivate; + if (OMP_CLAUSE_LINEAR_NO_COPYOUT (c)) + x = NULL; + else + x = build_outer_var_ref (var, ctx); + goto do_private; + case OMP_CLAUSE_FIRSTPRIVATE: if (is_task_ctx (ctx)) { @@ -2474,6 +2507,7 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, goto do_dtor; } } + do_firstprivate: x = build_outer_var_ref (var, ctx); x = lang_hooks.decls.omp_clause_copy_ctor (c, new_var, x); gimplify_and_add (x, ilist); @@ -2537,7 +2571,12 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, lastprivate clauses we need to ensure the lastprivate copying happens after firstprivate copying in all threads. */ if (copyin_by_ref || lastprivate_firstprivate) - gimplify_and_add (build_omp_barrier (), ilist); + { + /* Don't add any barrier for #pragma omp simd. */ + if (gimple_code (ctx->stmt) != GIMPLE_OMP_FOR + || gimple_omp_for_kind (ctx->stmt) != GF_OMP_FOR_KIND_SIMD) + gimplify_and_add (build_omp_barrier (), ilist); + } } @@ -2547,13 +2586,17 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, static void lower_lastprivate_clauses (tree clauses, tree predicate, gimple_seq *stmt_list, - omp_context *ctx) + omp_context *ctx) { tree x, c, label = NULL; bool par_clauses = false; - /* Early exit if there are no lastprivate clauses. */ - clauses = find_omp_clause (clauses, OMP_CLAUSE_LASTPRIVATE); + /* Early exit if there are no lastprivate or linear clauses. */ + for (; clauses ; clauses = OMP_CLAUSE_CHAIN (clauses)) + if (OMP_CLAUSE_CODE (clauses) == OMP_CLAUSE_LASTPRIVATE + || (OMP_CLAUSE_CODE (clauses) == OMP_CLAUSE_LINEAR + && !OMP_CLAUSE_LINEAR_NO_COPYOUT (clauses))) + break; if (clauses == NULL) { /* If this was a workshare clause, see if it had been combined @@ -2595,18 +2638,21 @@ lower_lastprivate_clauses (tree clauses, tree predicate, gimple_seq *stmt_list, tree var, new_var; location_t clause_loc = OMP_CLAUSE_LOCATION (c); - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE + || (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR + && !OMP_CLAUSE_LINEAR_NO_COPYOUT (c))) { var = OMP_CLAUSE_DECL (c); new_var = lookup_decl (var, ctx); - if (OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c)) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE + && OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c)) { lower_omp (&OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c), ctx); gimple_seq_add_seq (stmt_list, OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c)); + OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c) = NULL; } - OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c) = NULL; x = build_outer_var_ref (var, ctx); if (is_reference (var)) @@ -4625,6 +4671,273 @@ expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd) } +/* A subroutine of expand_omp_for. Generate code for a simd non-worksharing + loop. Given parameters: + + for (V = N1; V cond N2; V += STEP) BODY; + + where COND is "<" or ">", we generate pseudocode + + V = N1; + goto L1; + L0: + BODY; + V += STEP; + L1: + if (V cond N2) goto L0; else goto L2; + L2: + + For collapsed loops, given parameters: + collapse(3) + for (V1 = N11; V1 cond1 N12; V1 += STEP1) + for (V2 = N21; V2 cond2 N22; V2 += STEP2) + for (V3 = N31; V3 cond3 N32; V3 += STEP3) + BODY; + + we generate pseudocode + + if (cond3 is <) + adj = STEP3 - 1; + else + adj = STEP3 + 1; + count3 = (adj + N32 - N31) / STEP3; + if (cond2 is <) + adj = STEP2 - 1; + else + adj = STEP2 + 1; + count2 = (adj + N22 - N21) / STEP2; + if (cond1 is <) + adj = STEP1 - 1; + else + adj = STEP1 + 1; + count1 = (adj + N12 - N11) / STEP1; + count = count1 * count2 * count3; + V = 0; + V1 = N11; + V2 = N21; + V3 = N31; + goto L1; + L0: + BODY; + V += 1; + V3 += STEP3; + V2 += (V3 cond3 N32) ? 0 : STEP2; + V3 = (V3 cond3 N32) ? V3 : N31; + V1 += (V2 cond2 N22) ? 0 : STEP1; + V2 = (V2 cond2 N22) ? V2 : N21; + L1: + if (V < count) goto L0; else goto L2; + L2: + + */ + +static void +expand_omp_simd (struct omp_region *region, struct omp_for_data *fd) +{ + tree type, t; + basic_block entry_bb, cont_bb, exit_bb, l0_bb, l1_bb, l2_bb; + gimple_stmt_iterator gsi; + gimple stmt; + bool broken_loop = region->cont == NULL; + edge e, ne; + tree *counts = NULL; + int i; + + type = TREE_TYPE (fd->loop.v); + entry_bb = region->entry; + cont_bb = region->cont; + gcc_assert (EDGE_COUNT (entry_bb->succs) == 2); + gcc_assert (broken_loop + || BRANCH_EDGE (entry_bb)->dest == FALLTHRU_EDGE (cont_bb)->dest); + l0_bb = FALLTHRU_EDGE (entry_bb)->dest; + if (!broken_loop) + { + gcc_assert (BRANCH_EDGE (cont_bb)->dest == l0_bb); + gcc_assert (EDGE_COUNT (cont_bb->succs) == 2); + l1_bb = split_block (cont_bb, last_stmt (cont_bb))->dest; + l2_bb = BRANCH_EDGE (entry_bb)->dest; + } + else + { + BRANCH_EDGE (entry_bb)->flags &= ~EDGE_ABNORMAL; + l1_bb = split_edge (BRANCH_EDGE (entry_bb)); + l2_bb = single_succ (l1_bb); + } + exit_bb = region->exit; + + gsi = gsi_last_bb (entry_bb); + + gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR); + /* Not needed in SSA form right now. */ + gcc_assert (!gimple_in_ssa_p (cfun)); + if (fd->collapse > 1) + { + counts = XALLOCAVEC (tree, fd->collapse); + for (i = 0; i < fd->collapse; i++) + { + tree itype = TREE_TYPE (fd->loops[i].v); + + if (POINTER_TYPE_P (itype)) + itype = signed_type_for (itype); + t = build_int_cst (itype, (fd->loops[i].cond_code == LT_EXPR + ? -1 : 1)); + t = fold_build2 (PLUS_EXPR, itype, + fold_convert (itype, fd->loops[i].step), t); + t = fold_build2 (PLUS_EXPR, itype, t, + fold_convert (itype, fd->loops[i].n2)); + t = fold_build2 (MINUS_EXPR, itype, t, + fold_convert (itype, fd->loops[i].n1)); + if (TYPE_UNSIGNED (itype) && fd->loops[i].cond_code == GT_EXPR) + t = fold_build2 (TRUNC_DIV_EXPR, itype, + fold_build1 (NEGATE_EXPR, itype, t), + fold_build1 (NEGATE_EXPR, itype, + fold_convert (itype, + fd->loops[i].step))); + else + t = fold_build2 (TRUNC_DIV_EXPR, itype, t, + fold_convert (itype, fd->loops[i].step)); + t = fold_convert (type, t); + if (TREE_CODE (t) == INTEGER_CST) + counts[i] = t; + else + { + counts[i] = create_tmp_reg (type, ".count"); + t = force_gimple_operand_gsi (&gsi, t, false, NULL_TREE, + true, GSI_SAME_STMT); + stmt = gimple_build_assign (counts[i], t); + gsi_insert_before (&gsi, stmt, GSI_SAME_STMT); + } + if (SSA_VAR_P (fd->loop.n2)) + { + if (i == 0) + t = counts[0]; + else + { + t = fold_build2 (MULT_EXPR, type, fd->loop.n2, counts[i]); + t = force_gimple_operand_gsi (&gsi, t, false, NULL_TREE, + true, GSI_SAME_STMT); + } + stmt = gimple_build_assign (fd->loop.n2, t); + gsi_insert_before (&gsi, stmt, GSI_SAME_STMT); + } + } + } + t = fold_convert (type, fd->loop.n1); + t = force_gimple_operand_gsi (&gsi, t, false, NULL_TREE, + true, GSI_SAME_STMT); + gsi_insert_before (&gsi, gimple_build_assign (fd->loop.v, t), GSI_SAME_STMT); + if (fd->collapse > 1) + for (i = 0; i < fd->collapse; i++) + { + t = fold_convert (TREE_TYPE (fd->loops[i].v), fd->loops[i].n1); + t = force_gimple_operand_gsi (&gsi, t, false, NULL_TREE, + true, GSI_SAME_STMT); + gsi_insert_before (&gsi, gimple_build_assign (fd->loops[i].v, t), + GSI_SAME_STMT); + } + + /* Remove the GIMPLE_OMP_FOR statement. */ + gsi_remove (&gsi, true); + + if (!broken_loop) + { + /* Code to control the increment goes in the CONT_BB. */ + gsi = gsi_last_bb (cont_bb); + stmt = gsi_stmt (gsi); + gcc_assert (gimple_code (stmt) == GIMPLE_OMP_CONTINUE); + + if (POINTER_TYPE_P (type)) + t = fold_build_pointer_plus (fd->loop.v, fd->loop.step); + else + t = fold_build2 (PLUS_EXPR, type, fd->loop.v, fd->loop.step); + t = force_gimple_operand_gsi (&gsi, t, false, NULL_TREE, + true, GSI_SAME_STMT); + stmt = gimple_build_assign (fd->loop.v, t); + gsi_insert_before (&gsi, stmt, GSI_SAME_STMT); + + if (fd->collapse > 1) + { + i = fd->collapse - 1; + t = fold_convert (TREE_TYPE (fd->loops[i].v), fd->loops[i].step); + t = build2 (PLUS_EXPR, TREE_TYPE (fd->loops[i].v), + fd->loops[i].v, t); + t = force_gimple_operand_gsi (&gsi, t, false, NULL_TREE, + true, GSI_SAME_STMT); + stmt = gimple_build_assign (fd->loops[i].v, t); + gsi_insert_before (&gsi, stmt, GSI_SAME_STMT); + + for (i = fd->collapse - 1; i > 0; i--) + { + tree itype = TREE_TYPE (fd->loops[i].v); + tree itype2 = TREE_TYPE (fd->loops[i - 1].v); + t = build3 (COND_EXPR, itype2, + build2 (fd->loops[i].cond_code, boolean_type_node, + fd->loops[i].v, + fold_convert (itype, fd->loops[i].n2)), + build_int_cst (itype2, 0), + fold_convert (itype2, fd->loops[i - 1].step)); + t = build2 (PLUS_EXPR, itype2, fd->loops[i - 1].v, t); + t = force_gimple_operand_gsi (&gsi, t, false, NULL_TREE, + true, GSI_SAME_STMT); + stmt = gimple_build_assign (fd->loops[i - 1].v, t); + gsi_insert_before (&gsi, stmt, GSI_SAME_STMT); + + t = build3 (COND_EXPR, itype, + build2 (fd->loops[i].cond_code, boolean_type_node, + fd->loops[i].v, + fold_convert (itype, fd->loops[i].n2)), + fd->loops[i].v, + fold_convert (itype, fd->loops[i].n1)); + t = force_gimple_operand_gsi (&gsi, t, false, NULL_TREE, + true, GSI_SAME_STMT); + stmt = gimple_build_assign (fd->loops[i].v, t); + gsi_insert_before (&gsi, stmt, GSI_SAME_STMT); + } + } + + /* Remove GIMPLE_OMP_CONTINUE. */ + gsi_remove (&gsi, true); + } + + /* Emit the condition in L1_BB. */ + gsi = gsi_start_bb (l1_bb); + + t = fold_convert (type, fd->loop.n2); + t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, + false, GSI_CONTINUE_LINKING); + t = build2 (fd->loop.cond_code, boolean_type_node, fd->loop.v, t); + gsi_insert_after (&gsi, gimple_build_cond_empty (t), GSI_CONTINUE_LINKING); + + /* Remove GIMPLE_OMP_RETURN. */ + gsi = gsi_last_bb (exit_bb); + gsi_remove (&gsi, true); + + /* Connect the new blocks. */ + remove_edge (FALLTHRU_EDGE (entry_bb)); + + if (!broken_loop) + { + remove_edge (BRANCH_EDGE (entry_bb)); + make_edge (entry_bb, l1_bb, EDGE_FALLTHRU); + + e = BRANCH_EDGE (l1_bb); + ne = FALLTHRU_EDGE (l1_bb); + e->flags = EDGE_TRUE_VALUE; + ne->flags = EDGE_FALSE_VALUE; + e->probability = REG_BR_PROB_BASE * 7 / 8; + ne->probability = REG_BR_PROB_BASE / 8; + + set_immediate_dominator (CDI_DOMINATORS, l1_bb, entry_bb); + set_immediate_dominator (CDI_DOMINATORS, l2_bb, l1_bb); + set_immediate_dominator (CDI_DOMINATORS, l0_bb, l1_bb); + } + else + { + single_succ_edge (entry_bb)->flags = EDGE_FALLTHRU; + } +} + + /* Expand the OpenMP loop defined by REGION. */ static void @@ -4650,10 +4963,12 @@ expand_omp_for (struct omp_region *region) FALLTHRU_EDGE (region->cont)->flags &= ~EDGE_ABNORMAL; } - if (fd.sched_kind == OMP_CLAUSE_SCHEDULE_STATIC - && !fd.have_ordered - && fd.collapse == 1 - && region->cont != NULL) + if (gimple_omp_for_kind (fd.for_stmt) == GF_OMP_FOR_KIND_SIMD) + expand_omp_simd (region, &fd); + else if (fd.sched_kind == OMP_CLAUSE_SCHEDULE_STATIC + && !fd.have_ordered + && fd.collapse == 1 + && region->cont != NULL) { if (fd.chunk_size == NULL) expand_omp_for_static_nochunk (region, &fd); @@ -6318,7 +6633,8 @@ lower_omp_for (gimple_stmt_iterator *gsi_p, omp_context *ctx) /* Once lowered, extract the bounds and clauses. */ extract_omp_for_data (stmt, &fd, NULL); - lower_omp_for_lastprivate (&fd, &body, &dlist, ctx); + if (gimple_omp_for_kind (fd.for_stmt) != GF_OMP_FOR_KIND_SIMD) + lower_omp_for_lastprivate (&fd, &body, &dlist, ctx); gimple_seq_add_stmt (&body, stmt); gimple_seq_add_seq (&body, gimple_omp_body (stmt)); @@ -6334,6 +6650,13 @@ lower_omp_for (gimple_stmt_iterator *gsi_p, omp_context *ctx) /* Region exit marker goes at the end of the loop body. */ gimple_seq_add_stmt (&body, gimple_build_omp_return (fd.have_nowait)); + if (gimple_omp_for_kind (fd.for_stmt) == GF_OMP_FOR_KIND_SIMD) + { + dlist = NULL; + lower_lastprivate_clauses (gimple_omp_for_clauses (fd.for_stmt), + NULL_TREE, &dlist, ctx); + gimple_seq_add_seq (&body, dlist); + } pop_gimplify_context (new_stmt); diff --git a/gcc/testsuite/ChangeLog.gomp b/gcc/testsuite/ChangeLog.gomp index a844e07c98e15..53e40768ac168 100644 --- a/gcc/testsuite/ChangeLog.gomp +++ b/gcc/testsuite/ChangeLog.gomp @@ -1,3 +1,8 @@ +2013-04-19 Jakub Jelinek + + * c-c++-common/gomp/simd1.c: New test. + * c-c++-common/gomp/simd2.c: New test. + 2013-04-10 Jakub Jelinek * gcc.dg/gomp/combined-1.c: Look for GOMP_parallel_loop_runtime diff --git a/gcc/testsuite/c-c++-common/gomp/simd1.c b/gcc/testsuite/c-c++-common/gomp/simd1.c new file mode 100644 index 0000000000000..ec0101a1e52c5 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/simd1.c @@ -0,0 +1,31 @@ +/* { dg-do compile { target { ! c } } } */ +/* { dg-options "-fopenmp" } */ +/* { dg-additional-options "-std=c99" { target c } } */ + +extern int a[1024], b[1024], k, l, m; + +void +foo () +{ + int i; + #pragma omp simd safelen(16) aligned(a, b : 32) + for (i = 0; i < 1024; i++) + a[i] *= b[i]; +} + +void +bar (int *p) +{ + int i; + #pragma omp simd safelen(16) aligned(a, p : 32) linear(k, l : m + 1) + for (i = 0; i < 1024; i++) + a[i] *= p[i], k += m + 1; +} + +void +baz (int *p) +{ + #pragma omp simd safelen(16) aligned(a, p : 32) linear(k, l : m + 1) + for (int i = 0; i < 1024; i++) + a[i] *= p[i], k += m + 1; +} diff --git a/gcc/testsuite/c-c++-common/gomp/simd2.c b/gcc/testsuite/c-c++-common/gomp/simd2.c new file mode 100644 index 0000000000000..ad44f8e26c7cc --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/simd2.c @@ -0,0 +1,29 @@ +/* { dg-do compile { target { ! c } } } */ +/* { dg-options "-fopenmp" } */ +/* { dg-additional-options "-std=c99" { target c } } */ + +extern int a[13][13][13][13], k, l, m; + +void +foo (int *q, float *p) +{ + int i, j, n, o; +#pragma omp simd collapse (4) linear(k : m + 1) aligned(p, q) + for (i = 0; i < 13; i++) + for (j = 0; j < 13; j++) + for (n = 0; n < 13; n++) + for (o = 0; o < 13; o += 2) + q[k] *= p[k] + 7 * i + 14 * j + 21 * n + 28 * o, k += m + 1; +} + +void +bar (float *p) +{ + int i, j, n, o; +#pragma omp simd collapse (4) linear(k : m + 1) + for (i = 0; i < 13; i++) + for (j = 0; j < 13; j++) + for (n = 0; n < 13; n++) + for (o = 0; o < 13; o += 2) + a[i][j][n][o] *= p[k], k += m + 1; +} diff --git a/gcc/tree.h b/gcc/tree.h index d97f6eb409ac1..b4bd6c490f45e 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -613,6 +613,9 @@ struct GTY(()) tree_base { OMP_CLAUSE_PRIVATE_DEBUG in OMP_CLAUSE_PRIVATE + OMP_CLAUSE_LINEAR_NO_COPYIN in + OMP_CLAUSE_LINEAR + TRANSACTION_EXPR_RELAXED in TRANSACTION_EXPR @@ -633,6 +636,9 @@ struct GTY(()) tree_base { OMP_CLAUSE_PRIVATE_OUTER_REF in OMP_CLAUSE_PRIVATE + OMP_CLAUSE_LINEAR_NO_COPYOUT in + OMP_CLAUSE_LINEAR + TYPE_REF_IS_RVALUE in REFERENCE_TYPE @@ -1917,6 +1923,16 @@ extern void protected_set_expr_location (tree, location_t); #define OMP_CLAUSE_REDUCTION_PLACEHOLDER(NODE) \ OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_REDUCTION), 3) +/* True if a LINEAR clause doesn't need copy in. True for iterator vars which + are always initialized inside of the loop construct, false otherwise. */ +#define OMP_CLAUSE_LINEAR_NO_COPYIN(NODE) \ + (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_LINEAR)->base.public_flag) + +/* True if a LINEAR clause doesn't need copy out. True for iterator vars which + are declared inside of the simd construct. */ +#define OMP_CLAUSE_LINEAR_NO_COPYOUT(NODE) \ + TREE_PRIVATE (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_LINEAR)) + #define OMP_CLAUSE_LINEAR_STEP(NODE) \ OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_LINEAR), 1) From b2270ce0ab7ee4eb37b68b706fcf2e15941eb6ef Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Mon, 22 Apr 2013 13:54:42 -0500 Subject: [PATCH 11/63] Rewrite Cilk Plus <#pragma simd> parsing and rewrite to use gomp4's OMP_SIMD infrastructure. --- gcc/Makefile.in | 4 + gcc/c-family/c-cilkplus.c | 278 +++++++++++ gcc/c-family/c-pragma.c | 6 + gcc/c-family/c-pragma.h | 16 + gcc/c-family/c.opt | 4 + gcc/c/c-parser.c | 462 ++++++++++++++++++ gcc/c/c-tree.h | 5 + gcc/gimplify.c | 4 + gcc/omp-low.c | 4 + .../cilk-simd/compile/cilk-simd-compile.exp | 23 + .../cilk-plus/cilk-simd/compile/clauses1.c | 84 ++++ .../cilk-plus/cilk-simd/compile/clauses2.c | 19 + .../gcc.dg/cilk-plus/cilk-simd/compile/for1.c | 135 +++++ .../gcc.dg/cilk-plus/cilk-simd/compile/for2.c | 66 +++ .../gcc.dg/cilk-plus/cilk-simd/compile/for3.c | 8 + gcc/tree-pretty-print.c | 11 + gcc/tree.c | 8 + gcc/tree.h | 15 +- 18 files changed, 1151 insertions(+), 1 deletion(-) create mode 100644 gcc/c-family/c-cilkplus.c create mode 100644 gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/cilk-simd-compile.exp create mode 100644 gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/clauses1.c create mode 100644 gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/clauses2.c create mode 100644 gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for1.c create mode 100644 gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for2.c create mode 100644 gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for3.c diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 54ea04f644a1a..e0d6092710cb7 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1137,6 +1137,7 @@ C_COMMON_OBJS = c-family/c-common.o c-family/c-cppbuiltin.o c-family/c-dump.o \ c-family/c-format.o c-family/c-gimplify.o c-family/c-lex.o \ c-family/c-omp.o c-family/c-opts.o c-family/c-pch.o \ c-family/c-ppoutput.o c-family/c-pragma.o c-family/c-pretty-print.o \ + c-family/c-cilkplus.o \ c-family/c-semantics.o c-family/c-ada-spec.o tree-mudflap.o # Language-independent object files. @@ -1966,6 +1967,9 @@ c-family/c-lex.o : c-family/c-lex.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ c-family/c-omp.o : c-family/c-omp.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ $(TREE_H) $(C_COMMON_H) $(GIMPLE_H) langhooks.h +c-family/c-cilkplus.o : c-family/c-cilkplus.c $(CONFIG_H) $(SYSTEM_H) \ + coretypes.h $(TREE_H) $(C_COMMON_H) langhooks.h + CFLAGS-c-family/c-opts.o += @TARGET_SYSTEM_ROOT_DEFINE@ c-family/c-opts.o : c-family/c-opts.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ $(TREE_H) $(C_PRAGMA_H) $(FLAGS_H) toplev.h langhooks.h \ diff --git a/gcc/c-family/c-cilkplus.c b/gcc/c-family/c-cilkplus.c new file mode 100644 index 0000000000000..d5f069fcae5a0 --- /dev/null +++ b/gcc/c-family/c-cilkplus.c @@ -0,0 +1,278 @@ +/* This file contains routines to construct and validate Cilk Plus + constructs within the C and C++ front ends. + + Copyright (C) 2011-2013 Free Software Foundation, Inc. + Contributed by Balaji V. Iyer , + Aldy Hernandez . + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tree.h" +#include "c-common.h" + +/* Helper function for c_check_cilk_loop. + + Validate the increment in a _Cilk_for construct or a <#pragma simd> + for loop. + + LOC is the location of the `for' keyword. DECL is the induction + variable. INCR is the original increment expression. + + Returns the canonicalized increment expression for an OMP_FOR_INCR. + If there is a validation error, returns error_mark_node. */ + +static tree +c_check_cilk_loop_incr (location_t loc, tree decl, tree incr) +{ + if (EXPR_HAS_LOCATION (incr)) + loc = EXPR_LOCATION (incr); + + if (!incr) + { + error_at (loc, "missing increment"); + return error_mark_node; + } + + switch (TREE_CODE (incr)) + { + case POSTINCREMENT_EXPR: + case PREINCREMENT_EXPR: + case POSTDECREMENT_EXPR: + case PREDECREMENT_EXPR: + if (TREE_OPERAND (incr, 0) != decl) + break; + + // Bah... canonicalize into whatever OMP_FOR_INCR needs. + if (POINTER_TYPE_P (TREE_TYPE (decl)) + && TREE_OPERAND (incr, 1)) + { + tree t = fold_convert_loc (loc, + sizetype, TREE_OPERAND (incr, 1)); + + if (TREE_CODE (incr) == POSTDECREMENT_EXPR + || TREE_CODE (incr) == PREDECREMENT_EXPR) + t = fold_build1_loc (loc, NEGATE_EXPR, sizetype, t); + t = fold_build_pointer_plus (decl, t); + incr = build2 (MODIFY_EXPR, void_type_node, decl, t); + } + return incr; + + case MODIFY_EXPR: + { + tree rhs; + + if (TREE_OPERAND (incr, 0) != decl) + break; + + rhs = TREE_OPERAND (incr, 1); + if (TREE_CODE (rhs) == PLUS_EXPR + && (TREE_OPERAND (rhs, 0) == decl + || TREE_OPERAND (rhs, 1) == decl) + && INTEGRAL_TYPE_P (TREE_TYPE (rhs))) + return incr; + else if (TREE_CODE (rhs) == MINUS_EXPR + && TREE_OPERAND (rhs, 0) == decl + && INTEGRAL_TYPE_P (TREE_TYPE (rhs))) + return incr; + // Otherwise fail because only PLUS_EXPR and MINUS_EXPR are + // allowed. + break; + } + + default: + break; + } + + error_at (loc, "invalid increment expression"); + return error_mark_node; +} + +/* Validate a _Cilk_for construct (or a #pragma simd for loop, which + has the same syntactic restrictions). Returns TRUE if there were + no errors, FALSE otherwise. LOC is the location of the for. DECL + is the controlling variable. COND is the condition. INCR is the + increment expression. BODY is the body of the LOOP. */ + +static bool +c_check_cilk_loop (location_t loc, tree decl, tree cond, tree incr, tree body) +{ + if (decl == error_mark_node + || cond == error_mark_node + || incr == error_mark_node + || body == error_mark_node) + return false; + + /* Validate the initialization. */ + gcc_assert (decl != NULL); + if (TREE_THIS_VOLATILE (decl)) + { + error_at (loc, "induction variable cannot be volatile"); + return false; + } + if (DECL_EXTERNAL (decl)) + { + error_at (loc, "induction variable cannot be extern"); + return false; + } + if (TREE_STATIC (decl)) + { + error_at (loc, "induction variable cannot be static"); + return false; + } + if (DECL_REGISTER (decl)) + { + error_at (loc, "induction variable cannot be declared register"); + return false; + } + if (!INTEGRAL_TYPE_P (TREE_TYPE (decl)) + && !POINTER_TYPE_P (TREE_TYPE (decl))) + { + error_at (loc, "initialization variable must be of integral " + "or pointer type"); + return false; + } + + /* Validate the condition. */ + if (!cond) + { + error_at (loc, "missing condition"); + return false; + } + bool cond_ok = false; + if (TREE_CODE (cond) == NE_EXPR + || TREE_CODE (cond) == LT_EXPR + || TREE_CODE (cond) == LE_EXPR + || TREE_CODE (cond) == GT_EXPR + || TREE_CODE (cond) == GE_EXPR) + { + /* Comparison must either be: + DECL EXPR + EXPR DECL + */ + if (decl == TREE_OPERAND (cond, 0)) + cond_ok = true; + else if (decl == TREE_OPERAND (cond, 1)) + { + /* Canonicalize the comparison so the DECL is on the LHS. */ + TREE_SET_CODE (cond, + swap_tree_comparison (TREE_CODE (cond))); + TREE_OPERAND (cond, 1) = TREE_OPERAND (cond, 0); + TREE_OPERAND (cond, 0) = decl; + cond_ok = true; + } + } + if (!cond_ok) + { + error_at (loc, "invalid controlling predicate"); + return false; + } + + /* Validate the increment. */ + incr = c_check_cilk_loop_incr (loc, decl, incr); + if (incr == error_mark_node) + return false; + + return true; + } + +/* Validate and emit code for the FOR loop following a # + construct. + + LOC is the location of the location of the FOR. + DECL is the iteration variable. + INIT is the initialization expression. + COND is the controlling predicate. + INCR is the increment expression. + BODY is the body of the loop. + CLAUSES are the clauses associated with the pragma simd loop. + + Returns the generated statement. */ + +tree +c_finish_cilk_simd_loop (location_t loc, + tree decl, + tree init, tree cond, tree incr, + tree body, + tree clauses) +{ + location_t rhs_loc; + + if (!c_check_cilk_loop (loc, decl, cond, incr, body)) + return NULL; + + /* In the case of "for (int i = 0...)", init will be a decl. It should + have a DECL_INITIAL that we can turn into an assignment. */ + if (init == decl) + { + rhs_loc = DECL_SOURCE_LOCATION (decl); + + init = DECL_INITIAL (decl); + if (init == NULL) + { + error_at (rhs_loc, "%qE is not initialized", decl); + init = integer_zero_node; + return NULL; + } + + init = build_modify_expr (loc, decl, NULL_TREE, NOP_EXPR, rhs_loc, + init, NULL_TREE); + } + gcc_assert (TREE_CODE (init) == MODIFY_EXPR); + gcc_assert (TREE_OPERAND (init, 0) == decl); + + tree initv = make_tree_vec (1); + tree condv = make_tree_vec (1); + tree incrv = make_tree_vec (1); + TREE_VEC_ELT (initv, 0) = init; + TREE_VEC_ELT (condv, 0) = cond; + TREE_VEC_ELT (incrv, 0) = incr; + + // FIXME: What should we do about nested loops? Look at specs. + + /* The OpenMP <#pragma omp simd> construct is exactly the same as + the Cilk Plus one, with the exception of the vectorlength() + clause in Cilk Plus. Emitting an OMP_SIMD simlifies + everything. */ + tree t = make_node (OMP_SIMD); + TREE_TYPE (t) = void_type_node; + OMP_FOR_INIT (t) = initv; + OMP_FOR_COND (t) = condv; + OMP_FOR_INCR (t) = incrv; + OMP_FOR_BODY (t) = body; + OMP_FOR_PRE_BODY (t) = NULL; + OMP_FOR_CLAUSES (t) = clauses; + + SET_EXPR_LOCATION (t, loc); + return add_stmt (t); +} + +/* Validate and emit code for <#pragma simd> clauses. */ + +tree +c_finish_cilk_clauses (tree clauses) +{ + // FIXME: "...no variable shall be the subject of more than one + // linear clause". Verify and check for this. + + // FIXME: Also, do whatever we were doing before in + // same_var_in_multiple_lists_p, but rewrite to use OMP_CLAUSEs. + + return clauses; +} diff --git a/gcc/c-family/c-pragma.c b/gcc/c-family/c-pragma.c index b03ddc1d3bac4..c05b8d0a8f415 100644 --- a/gcc/c-family/c-pragma.c +++ b/gcc/c-family/c-pragma.c @@ -1352,6 +1352,12 @@ init_pragma (void) omp_pragmas[i].id, true, true); } + if (flag_enable_cilk && !flag_preprocess_only) + { + cpp_register_deferred_pragma (parse_in, NULL, "simd", + PRAGMA_CILK_SIMD, true, false); + } + if (!flag_preprocess_only) cpp_register_deferred_pragma (parse_in, "GCC", "pch_preprocess", PRAGMA_GCC_PCH_PREPROCESS, false, false); diff --git a/gcc/c-family/c-pragma.h b/gcc/c-family/c-pragma.h index cd121d46c0008..2ff5a00ae8b22 100644 --- a/gcc/c-family/c-pragma.h +++ b/gcc/c-family/c-pragma.h @@ -60,6 +60,9 @@ typedef enum pragma_kind { PRAGMA_OMP_THREADPRIVATE, PRAGMA_OMP_TEAMS, + /* Top level clause to handle all Cilk Plus pragma simd clauses. */ + PRAGMA_CILK_SIMD, + PRAGMA_GCC_PCH_PREPROCESS, PRAGMA_FIRST_EXTERNAL @@ -109,6 +112,19 @@ typedef enum pragma_omp_clause { PRAGMA_OMP_CLAUSE_UNTIED } pragma_omp_clause; +/* All Cilk Plus #pragma omp clauses. */ +typedef enum pragma_cilk_clause { + PRAGMA_CILK_CLAUSE_NONE = 0, + PRAGMA_CILK_CLAUSE_NOASSERT, + PRAGMA_CILK_CLAUSE_ASSERT, + PRAGMA_CILK_CLAUSE_VECTORLENGTH, + PRAGMA_CILK_CLAUSE_LINEAR, + PRAGMA_CILK_CLAUSE_PRIVATE, + PRAGMA_CILK_CLAUSE_FIRSTPRIVATE, + PRAGMA_CILK_CLAUSE_LASTPRIVATE, + PRAGMA_CILK_CLAUSE_REDUCTION +} pragma_cilk_clause; + extern struct cpp_reader* parse_in; /* It's safe to always leave visibility pragma enabled as if diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index 10ae84dbb24b9..e502b3f4d4bfa 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -839,6 +839,10 @@ Recognize built-in functions fbuiltin- C ObjC C++ ObjC++ Joined +fcilkplus +C ObjC C++ ObjC++ LTO Report Var(flag_enable_cilk) Init(0) +Enable Cilk + fcanonical-system-headers C ObjC C++ ObjC++ Where shorter, use canonicalized paths to systems headers. diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index 5b06803317463..41d44a4713980 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -1217,6 +1217,11 @@ static void c_parser_objc_at_dynamic_declaration (c_parser *); static bool c_parser_objc_diagnose_bad_element_prefix (c_parser *, struct c_declspecs *); +/* Cilk Plus supporting routines. */ +static void c_parser_cilk_for_statement (c_parser *, enum rid, tree); +static void c_parser_cilk_simd_construct (c_parser *); +static bool c_parser_cilk_verify_simd (c_parser *, enum pragma_context); + /* Parse a translation unit (C90 6.7, C99 6.9). translation-unit: @@ -8622,6 +8627,13 @@ c_parser_pragma (c_parser *parser, enum pragma_context context) c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); return false; + case PRAGMA_CILK_SIMD: + if (!c_parser_cilk_verify_simd (parser, context)) + return false; + c_parser_consume_pragma (parser); + c_parser_cilk_simd_construct (parser); + return false; + default: if (id < PRAGMA_FIRST_EXTERNAL) { @@ -10664,7 +10676,457 @@ c_parser_omp_threadprivate (c_parser *parser) c_parser_skip_to_pragma_eol (parser); } + +/* Cilk Plus <#pragma simd> parsing routines. */ + +/* Helper function for c_parser_pragma. Perform some sanity checking + for <#pragma simd> constructs. Returns FALSE if there was a + problem. */ + +static bool +c_parser_cilk_verify_simd (c_parser *parser, + enum pragma_context context) +{ + if (!flag_enable_cilk) + { + warning (0, "pragma simd ignored because -fcilkplus is not enabled"); + c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); + return false; + } + if (!flag_tree_vectorize) + { + warning (0, "pragma simd is useless without -ftree-vectorize"); + c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); + return false; + } + if (context == pragma_external) + { + c_parser_error (parser,"pragma simd must be inside a function"); + c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); + return false; + } + return true; +} + +/* Cilk Plus: + assert */ + +static tree +c_parser_cilk_clause_assert (c_parser *parser, tree clauses) +{ + check_no_duplicate_clause (clauses, OMP_CLAUSE_CILK_ASSERT, "assert"); + + location_t loc = c_parser_peek_token (parser)->location; + tree c = build_omp_clause (loc, OMP_CLAUSE_CILK_ASSERT); + OMP_CLAUSE_CHAIN (c) = clauses; + return c; +} + +/* Cilk Plus: + noassert */ + +static tree +c_parser_cilk_clause_noassert (c_parser *parser ATTRIBUTE_UNUSED, + tree clauses) +{ + /* Only check that we don't already have an assert clause. */ + check_no_duplicate_clause (clauses, OMP_CLAUSE_CILK_ASSERT, "assert"); + + return clauses; +} + +/* Cilk Plus: + vectorlength (constant-expression-list ) + + constant-expression-list: + constant-expression + constant-expression-list , constant-expression */ + +static tree +c_parser_cilk_clause_vectorlength (c_parser *parser, tree clauses) +{ + check_no_duplicate_clause (clauses, OMP_CLAUSE_CILK_VECTORLENGTH, + "vectorlength"); + + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return clauses; + + location_t loc = c_parser_peek_token (parser)->location; + while (true) + { + tree expr = c_parser_expr_no_commas (parser, NULL).value; + expr = c_fully_fold (expr, false, NULL); + + if (!TREE_TYPE (expr) + || !TREE_CONSTANT (expr) + || !INTEGRAL_TYPE_P (TREE_TYPE (expr))) + error_at (loc, "vectorlength must be an integer constant"); + else + { + tree u = build_omp_clause (loc, OMP_CLAUSE_CILK_VECTORLENGTH); + OMP_CLAUSE_CILK_VECTORLENGTH_EXPR (u) = expr; + OMP_CLAUSE_CHAIN (u) = clauses; + clauses = u; + } + + if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + { + c_parser_consume_token (parser); + return clauses; + } + if (c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); + } + + return clauses; +} + +/* Cilk Plus: + linear ( simd-linear-variable-list ) + + simd-linear-variable-list: + simd-linear-variable + simd-linear-variable-list , simd-linear-variable + + simd-linear-variable: + id-expression + id-expression : simd-linear-step + + simd-linear-step: + conditional-expression */ + +static tree +c_parser_cilk_clause_linear (c_parser *parser, tree clauses) +{ + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return clauses; + + location_t loc = c_parser_peek_token (parser)->location; + if (c_parser_next_token_is_not (parser, CPP_NAME) + || c_parser_peek_token (parser)->id_kind != C_ID_ID) + c_parser_error (parser, "expected identifier"); + + while (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_token (parser)->id_kind == C_ID_ID) + { + tree var = lookup_name (c_parser_peek_token (parser)->value); + + if (var == NULL) + { + undeclared_variable (c_parser_peek_token (parser)->location, + c_parser_peek_token (parser)->value); + c_parser_consume_token (parser); + } + else if (var == error_mark_node) + c_parser_consume_token (parser); + else + { + tree step = integer_one_node; + + /* Parse the linear step if present. */ + if (c_parser_peek_2nd_token (parser)->type == CPP_COLON) + { + c_parser_consume_token (parser); + c_parser_consume_token (parser); + + tree expr = c_parser_expr_no_commas (parser, NULL).value; + expr = c_fully_fold (expr, false, NULL); + + if (!TREE_TYPE (expr) + || !TREE_CONSTANT (expr) + || !INTEGRAL_TYPE_P (TREE_TYPE (expr))) + c_parser_error (parser, + "step size must be an integer constant"); + else + step = expr; + } + else + c_parser_consume_token (parser); + + /* Use OMP_CLAUSE_LINEAR, which has the same semantics. */ + tree u = build_omp_clause (loc, OMP_CLAUSE_LINEAR); + OMP_CLAUSE_DECL (u) = var; + OMP_CLAUSE_LINEAR_STEP (u) = step; + OMP_CLAUSE_CHAIN (u) = clauses; + clauses = u; + } + + if (c_parser_next_token_is_not (parser, CPP_COMMA)) + break; + + c_parser_consume_token (parser); + } + + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + + return clauses; +} + +/* Returns the name of the next clause. If the clause is not + recognized SIMD_OMP_CLAUSE_NONE is returned and the next token is + not consumed. Otherwise, the appropriate pragma_simd_clause is + returned and the token is consumed. */ + +static pragma_cilk_clause +c_parser_cilk_clause_name (c_parser *parser) +{ + pragma_cilk_clause result; + c_token *token = c_parser_peek_token (parser); + + if (!token->value || token->type != CPP_NAME) + return PRAGMA_CILK_CLAUSE_NONE; + + const char *p = IDENTIFIER_POINTER (token->value); + + if (!strcmp (p, "noassert")) + result = PRAGMA_CILK_CLAUSE_NOASSERT; + else if (!strcmp (p, "assert")) + result = PRAGMA_CILK_CLAUSE_ASSERT; + else if (!strcmp (p, "vectorlength")) + result = PRAGMA_CILK_CLAUSE_VECTORLENGTH; + else if (!strcmp (p, "linear")) + result = PRAGMA_CILK_CLAUSE_LINEAR; + else if (!strcmp (p, "private")) + result = PRAGMA_CILK_CLAUSE_PRIVATE; + else if (!strcmp (p, "firstprivate")) + result = PRAGMA_CILK_CLAUSE_FIRSTPRIVATE; + else if (!strcmp (p, "lastprivate")) + result = PRAGMA_CILK_CLAUSE_LASTPRIVATE; + else if (!strcmp (p, "reduction")) + result = PRAGMA_CILK_CLAUSE_REDUCTION; + else + return PRAGMA_CILK_CLAUSE_NONE; + + c_parser_consume_token (parser); + return result; +} + +/* Parse all # clauses. Return the list of clauses + found. */ + +static tree +c_parser_cilk_all_clauses (c_parser *parser) +{ + tree clauses = NULL; + + while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) + { + pragma_cilk_clause c_kind; + + c_kind = c_parser_cilk_clause_name (parser); + + switch (c_kind) + { + case PRAGMA_CILK_CLAUSE_NOASSERT: + clauses = c_parser_cilk_clause_noassert (parser, clauses); + break; + case PRAGMA_CILK_CLAUSE_ASSERT: + clauses = c_parser_cilk_clause_assert (parser, clauses); + break; + case PRAGMA_CILK_CLAUSE_VECTORLENGTH: + clauses = c_parser_cilk_clause_vectorlength (parser, clauses); + break; + case PRAGMA_CILK_CLAUSE_LINEAR: + clauses = c_parser_cilk_clause_linear (parser, clauses); + break; + case PRAGMA_CILK_CLAUSE_PRIVATE: + /* Use the OpenMP counterpart. */ + clauses = c_parser_omp_clause_private (parser, clauses); + break; + case PRAGMA_CILK_CLAUSE_FIRSTPRIVATE: + /* Use the OpenMP counterpart. */ + clauses = c_parser_omp_clause_firstprivate (parser, clauses); + break; + case PRAGMA_CILK_CLAUSE_LASTPRIVATE: + /* Use the OpenMP counterpart. */ + clauses = c_parser_omp_clause_lastprivate (parser, clauses); + break; + case PRAGMA_CILK_CLAUSE_REDUCTION: + /* Use the OpenMP counterpart. */ + clauses = c_parser_omp_clause_reduction (parser, clauses); + break; + default: + c_parser_error (parser, "expected %<#pragma simd%> clause"); + goto saw_error; + } + } + + saw_error: + c_parser_skip_to_pragma_eol (parser); + return c_finish_cilk_clauses (clauses); +} + +/* Parse the restriction form of the for statement allowed by + Cilk Plus. This function parses both the _CILK_FOR construct as + well as the for loop following a <#pragma simd> construct, both of + which have the same syntactic restrictions. + + FOR_KEYWORD can be either RID_CILK_FOR or RID_FOR, for parsing + _cilk_for or the <#pragma simd> for loop construct respectively. + + (NOTE: For now, only RID_FOR is handled). + + For a <#pragma simd>, CLAUSES are the clauses that should have been + previously parsed. If there are none, or if we are parsing a + _Cilk_for instead, this will be NULL. */ + +static void +c_parser_cilk_for_statement (c_parser *parser, enum rid for_keyword, + tree clauses) +{ + tree init, decl, cond, stmt; + tree block, incr, save_break, save_cont, body; + location_t loc; + bool fail = false; + + gcc_assert (/*for_keyword == RID_CILK_FOR || */for_keyword == RID_FOR); + + if (!c_parser_next_token_is_keyword (parser, for_keyword)) + { + if (for_keyword == RID_FOR) + c_parser_error (parser, "for statement expected"); + else + c_parser_error (parser, "_Cilk_for statement expected"); + return; + } + + loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + + block = c_begin_compound_stmt (true); + + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + add_stmt (c_end_compound_stmt (loc, block, true)); + return; + } + + /* Parse the initialization declaration. */ + if (c_parser_next_tokens_start_declaration (parser)) + { + c_parser_declaration_or_fndef (parser, true, false, false, + false, false, NULL); + decl = check_for_loop_decls (loc, flag_isoc99); + if (decl == NULL) + goto error_init; + if (DECL_INITIAL (decl) == error_mark_node) + decl = error_mark_node; + init = decl; + } + else if (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_2nd_token (parser)->type == CPP_EQ) + { + struct c_expr decl_exp; + struct c_expr init_exp; + location_t init_loc; + + decl_exp = c_parser_postfix_expression (parser); + decl = decl_exp.value; + + c_parser_require (parser, CPP_EQ, "expected %<=%>"); + + init_loc = c_parser_peek_token (parser)->location; + init_exp = c_parser_expr_no_commas (parser, NULL); + init_exp = default_function_array_read_conversion (init_loc, + init_exp); + init = build_modify_expr (init_loc, decl, decl_exp.original_type, + NOP_EXPR, init_loc, init_exp.value, + init_exp.original_type); + init = c_process_expr_stmt (init_loc, init); + + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + } + else + { + error_init: + c_parser_error (parser, + "expected iteration declaration or initialization"); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + return; + } + + /* Parse the loop condition. */ + cond = NULL_TREE; + if (c_parser_next_token_is_not (parser, CPP_SEMICOLON)) + { + location_t cond_loc = c_parser_peek_token (parser)->location; + struct c_expr cond_expr = c_parser_binary_expression (parser, NULL, + NULL); + + cond = cond_expr.value; + cond = c_objc_common_truthvalue_conversion (cond_loc, cond); + cond = c_fully_fold (cond, false, NULL); + } + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + + /* Parse the increment expression. */ + incr = NULL_TREE; + if (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN)) + { + location_t incr_loc = c_parser_peek_token (parser)->location; + incr = c_process_expr_stmt (incr_loc, + c_parser_expression (parser).value); + } + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + + if (decl == NULL || decl == error_mark_node || init == error_mark_node) + fail = true; + + save_break = c_break_label; + /* Magic number to inform c_finish_bc_stmt() that we are within a + Cilk for construct. */ + c_break_label = build_int_cst (size_type_node, 2); + + save_cont = c_cont_label; + c_cont_label = NULL_TREE; + body = c_parser_c99_block_statement (parser); + c_break_label = save_break; + c_cont_label = save_cont; + + // FIXME: Disallow the following constructs within a SIMD loop: + // + // RETURN + // GOTO + // _Cilk_spawn + // _Cilk_for + // OpenMP directive or construct + // Calls to setjmp() + + if (!fail) + { + /* + // FIXME: Uncomment when RID_CILK_FOR is implemented. + if (for_keyword == RID_CILK_FOR) + c_finish_cilk_loop (loc, decl, cond, incr, body, grain); + else + */ + c_finish_cilk_simd_loop (loc, decl, init, cond, incr, body, clauses); + } + + stmt = c_end_compound_stmt (loc, block, true); + add_stmt (stmt); + c_break_label = save_break; + c_cont_label = save_cont; +} + +/* Main entry point for parsing Cilk Plus <#pragma simd> for + loops. */ + +static void +c_parser_cilk_simd_construct (c_parser *parser) +{ + tree clauses = c_parser_cilk_all_clauses (parser); + + /* For <#pragma simd> we will be generating OMP_SIMD's and let the + OpenMP mechanism handle everything. */ + if (!flag_openmp) + flag_openmp = true; + + c_parser_cilk_for_statement (parser, RID_FOR, clauses); +} + /* Parse a transaction attribute (GCC Extension). transaction-attribute: diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index c4210a53f67af..0fd9cc63c4001 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -642,6 +642,11 @@ extern tree c_build_va_arg (location_t, tree, tree); extern tree c_finish_transaction (location_t, tree, int); extern bool c_tree_equal (tree, tree); +/* In c-cilkplus.c */ +extern tree c_finish_cilk_simd_loop (location_t, tree, tree, tree, tree, + tree, tree); +extern tree c_finish_cilk_clauses (tree); + /* Set to 0 at beginning of a function definition, set to 1 if a return statement that specifies a return value is seen. */ diff --git a/gcc/gimplify.c b/gcc/gimplify.c index f6b67173d1119..013fe43f04d9c 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -6337,6 +6337,8 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, case OMP_CLAUSE_MERGEABLE: case OMP_CLAUSE_PROC_BIND: case OMP_CLAUSE_SAFELEN: + case OMP_CLAUSE_CILK_ASSERT: + case OMP_CLAUSE_CILK_VECTORLENGTH: break; case OMP_CLAUSE_ALIGNED: @@ -6528,6 +6530,8 @@ gimplify_adjust_omp_clauses (tree *list_p) case OMP_CLAUSE_MERGEABLE: case OMP_CLAUSE_PROC_BIND: case OMP_CLAUSE_SAFELEN: + case OMP_CLAUSE_CILK_ASSERT: + case OMP_CLAUSE_CILK_VECTORLENGTH: break; default: diff --git a/gcc/omp-low.c b/gcc/omp-low.c index 58117d97c540e..b38ed9b27e7c9 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -1491,6 +1491,8 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) case OMP_CLAUSE_PROC_BIND: case OMP_CLAUSE_SAFELEN: case OMP_CLAUSE_ALIGNED: + case OMP_CLAUSE_CILK_ASSERT: + case OMP_CLAUSE_CILK_VECTORLENGTH: break; default: @@ -1547,6 +1549,8 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) case OMP_CLAUSE_PROC_BIND: case OMP_CLAUSE_SAFELEN: case OMP_CLAUSE_ALIGNED: + case OMP_CLAUSE_CILK_ASSERT: + case OMP_CLAUSE_CILK_VECTORLENGTH: break; default: diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/cilk-simd-compile.exp b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/cilk-simd-compile.exp new file mode 100644 index 0000000000000..154bb8c0d6740 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/cilk-simd-compile.exp @@ -0,0 +1,23 @@ +# Copyright (C) 2013 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# . + +load_lib gcc-dg.exp + +set OPTS "-fcilkplus -c -ftree-vectorize" + +dg-init +dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.c]] " $OPTS" " " +dg-finish diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/clauses1.c b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/clauses1.c new file mode 100644 index 0000000000000..ae01db3abf5fc --- /dev/null +++ b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/clauses1.c @@ -0,0 +1,84 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -std=c99 -fcilkplus" } */ + +volatile int *a, *b; + +void foo() +{ + int i, j, k; + +#pragma simd assert aoeu /* { dg-error "expected '#pragma simd' clause" } */ + for (int i=0; i < 1000; ++i) + a[i] = b[j]; + +#pragma simd noassert aoeu /* { dg-error "expected '#pragma simd' clause" } */ + for (int i=0; i < 1000; ++i) + a[i] = b[j]; + +#pragma simd assert noassert /* { dg-error "too many 'assert' clauses" } */ + for (int i=0; i < 1000; ++i) + a[i] = b[j]; + +#pragma simd vectorlength /* { dg-error "expected '\\('" } */ + for (int i=0; i < 1000; ++i) + a[i] = b[j]; + +#pragma simd vectorlength /* { dg-error "expected '\\('" } */ + for (int i=0; i < 1000; ++i) + a[i] = b[j]; + +#pragma simd vectorlength(sizeof (a) == sizeof (float) ? 4 : 8) + for (int i=0; i < 1000; ++i) + a[i] = b[j]; + +#pragma simd vectorlength(4,8) + for (int i=0; i < 1000; ++i) + a[i] = b[j]; + +#pragma simd vectorlength(i) /* { dg-error "vectorlength must be an integer" } */ + for (int i=0; i < 1000; ++i) + a[i] = b[j]; + +#pragma simd linear(35) /* { dg-error "expected identifier" } */ + for (int i=0; i < 1000; ++i) + a[i] = b[j]; + +#pragma simd linear(blah) /* { dg-error "'blah' undeclared" } */ + for (int i=0; i < 1000; ++i) + a[i] = b[j]; + +#pragma simd linear(blah2, 36) + /* { dg-error "'blah2' undeclared" "undeclared" { target *-*-* } 50 } */ + /* { dg-error "expected '\\)'" "expected" { target *-*-* } 50 } */ + for (int i=0; i < 1000; ++i) + a[i] = b[j]; + +#pragma simd linear(j, 36, k) /* { dg-error "expected '\\)'" } */ + for (int i=0; i < 1000; ++i) + a[i] = b[j]; + +#pragma simd linear(i, j) + for (int i=0; i < 1000; ++i) + a[i] = b[j]; + +#pragma simd linear(i) + for (int i=0; i < 1000; ++i) + a[i] = b[j]; + +#pragma simd linear(i : 4) + for (int i=0; i < 1000; ++i) + a[i] = b[j]; + +#pragma simd linear(i : 2, j : 4, k) + for (int i=0; i < 1000; ++i) + a[i] = b[j]; + +#pragma simd linear(j : sizeof (a) == sizeof (float) ? 4 : 8) + for (int i=0; i < 1000; ++i) + a[i] = b[j]; + + // And now everyone in unison! +#pragma simd assert linear(j : 4) vectorlength(4) + for (i=0; i < 1000; ++i) + a[i] = b[j]; +} diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/clauses2.c b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/clauses2.c new file mode 100644 index 0000000000000..6be6085c54bb4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/clauses2.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -std=c99 -fcilkplus -fdump-tree-original" } */ + +volatile int *a, *b; + +void foo() +{ + int i, j, k; + +#pragma simd assert linear(j : 4, k) vectorlength(4) + for (i=0; i < 1000; ++i) + a[i] = b[j]; +} + +/* { dg-final { scan-tree-dump-times "linear\\(j:4\\)" 1 "original" } } */ +/* { dg-final { scan-tree-dump-times "linear\\(k:1\\)" 1 "original" } } */ +/* { dg-final { scan-tree-dump-times "cilk_vectorlength\\(4\\)" 1 "original" } } */ +/* { dg-final { scan-tree-dump-times "cilk_assert" 1 "original" } } */ +/* { dg-final { cleanup-tree-dump "original" } } */ diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for1.c b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for1.c new file mode 100644 index 0000000000000..38700e43454fd --- /dev/null +++ b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for1.c @@ -0,0 +1,135 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -std=c99 -fcilkplus" } */ + +int *a, *b, *c; + +void foo() +{ + int i, j; + + // The initialization shall declare or initialize a *SINGLE* variable. +#pragma simd + for (i=0, j=5; i < 1000; i++) // { dg-error "expected ';' before ','" } + a[i] = b[j]; + + // Declaration and initialization is allowed. +#pragma simd + for (int i=0; i < 1000; i++) + a[i] = b[j]; + + // Empty initialization is not allowed. +#pragma simd + for (; i < 5; ++i) // { dg-error "expected iteration decl" } + a[i] = i; + + // Empty condition is not allowed. +#pragma simd + for (i=0; ; ++i) /* { dg-error "missing condition" } */ + a[i] = i; + + // Empty increment is not allowed. +#pragma simd + for (i=0; i < 1234; ) /* { dg-error "missing increment" } */ + a[i] = i*2; + +#pragma simd + i = 5; /* { dg-error "for statement expected" } */ + + // Initialization variables must be either integral or pointer types. + struct S { + int i; + }; +#pragma simd + for (struct S ss = { 0 }; ss.i <= 1000; ++ss.i) /* { dg-error "initialization variable must be of integral or pointer type" } */ + a[ss.i] = b[ss.i]; + + #pragma simd + for (float f=0.0; f < 15.0; ++f) /* { dg-error "must be of integral" } */ + a[(int)f] = (int) f; + + // Pointers are OK. + #pragma simd + for (int *i=c; i < &c[100]; ++i) + *a = '5'; + + // Condition of '==' is not allowed. +#pragma simd + for (i=j; i == 5; ++i) /* { dg-error "invalid controlling predicate" } */ + a[i] = b[i]; + + // The LHS or RHS of the condition must be the initialization variable. +#pragma simd + for (i=0; i+j < 1234; ++i) /* { dg-error "invalid controlling predicate" } */ + a[i] = b[i]; + + // Likewise. +#pragma simd + for (i=0; 1234 < i + j; ++i) /* { dg-error "invalid controlling predicate" } */ + a[i] = b[i]; + + // Likewise, this is ok. +#pragma simd + for (i=0; 1234 + j < i; ++i) + a[i] = b[i]; + + // According to the CilkPlus forum, casts are not allowed, even if + // they are no-ops. +#pragma simd + for (i=0; (char)i < 1234; ++i) /* { dg-error "invalid controlling predicate" } */ + a[i] = b[i]; + + // ?? This condition gets folded into "i != 0" by + // c_parser_cilk_for_statement(). Does this count as a "!=", or is + // this disallowed? Assume it is allowed. +#pragma simd + for (i=100; i; --i) + a[i] = b[i]; + + // Increment must be on the induction variable. +#pragma simd + for (i=0; i < 100; j++) /* { dg-error "invalid increment expression" } */ + a[i] = b[i]; + + // Likewise. +#pragma simd + for (i=0; i < 100; j = i + 1) /* { dg-error "invalid increment expression" } */ + a[i] = b[i]; + + // Likewise. +#pragma simd + for (i=0; i < 100; i = j + 1) /* { dg-error "invalid increment expression" } */ + a[i] = b[i]; + +#pragma simd + for (i=0; i < 100; i = i + 5) + a[i] = b[i]; + + // Only PLUS and MINUS increments are allowed. +#pragma simd + for (i=0; i < 100; i *= 5) /* { dg-error "invalid increment expression" } */ + a[i] = b[i]; + +#pragma simd + for (i=0; i < 100; i -= j) + a[i] = b[i]; + +#pragma simd + for (i=0; i < 100; i = i + j) + a[i] = b[i]; + +#pragma simd + for (i=0; i < 100; i = j + i) + a[i] = b[i]; + +#pragma simd + for (i=0; i < 100; ++i, ++j) /* { dg-error "invalid increment expression" } */ + a[i] = b[i]; + +#pragma simd + for (int *point=0; point < b; ++point) + *point = 555; + +#pragma simd + for (int *point=0; point > b; --point) + *point = 555; +} diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for2.c b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for2.c new file mode 100644 index 0000000000000..2d09ae82d4946 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for2.c @@ -0,0 +1,66 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -std=c99 -fcilkplus" } */ + +// Test storage classes in the initialization of a <#pragma simd> for +// loop. + +int *a, *b; + +void foo() +{ +#pragma simd + for (static int foo=5; foo < 10; ++foo) + a[foo] = b[foo]; + /* { dg-error "declaration of static variable" "storage class1" { target *-*-* } 12 } */ + /* { dg-error "induction variable cannot be static" "storage class2" { target *-*-* } 12 } */ + + static int bar; +#pragma simd + for (bar=0; bar < 1000; ++bar) /* { dg-error "induction variable cannot be static" } */ + a[bar] = bar; + +#pragma simd + for (extern int var=0; var < 1000; ++var) + a[var] = var; + /* { dg-error "has both 'extern' and initializer" "extern" { target *-*-* } 23 } */ + /* { dg-error "declaration of static variable" "" { target *-*-* } 23 } */ + /* { dg-error "induction variable cannot be static" "" { target *-*-* } 23 } */ + + extern int extvar; +#pragma simd + for (extvar = 0; extvar < 1000; ++extvar) /* { dg-error "induction variable cannot be extern" } */ + b[extvar] = a[extvar]; + + // This seems like it should be ok. + // Must check with standards people. +#pragma simd + for (auto int autoi = 0; autoi < 1000; ++autoi) + b[autoi] = a[autoi] * 2; + // Similarly here. + auto int autoj; +#pragma simd + for (auto int autoj = 0; autoj < 1000; ++autoj) + b[autoj] = a[autoj] * 2; + + register int regi; +#pragma simd + for (regi = 0; regi < 1000; ++regi) /* { dg-error "induction variable cannot be declared register" } */ + b[regi] = a[regi] * 2; + +#pragma simd + for (register int regj = 0; regj < 1000; ++regj) /* { dg-error "induction variable cannot be declared register" } */ + b[regj] = a[regj] * 2; + + volatile int vi; +#pragma simd + for (vi=0; vi<1000; ++vi) /* { dg-error "induction variable cannot be volatile" } */ + a[vi] = b[vi]; + +#pragma simd + for (volatile int vj=0; vj<1000; ++vj) /* { dg-error "induction variable cannot be volatile" } */ + a[vj] = b[vj]; + +#pragma simd + for (const int ci=0; ci<1000; ++ci) /* { dg-error "increment of read-only var" } */ + a[ci] = b[ci]; +} diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for3.c b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for3.c new file mode 100644 index 0000000000000..86606275ac471 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for3.c @@ -0,0 +1,8 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fcilkplus" } */ + +#pragma simd /* { dg-error "must be inside a function" } */ + +void foo() +{ +} diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c index f3de68c1d918b..8d1f06e92d544 100644 --- a/gcc/tree-pretty-print.c +++ b/gcc/tree-pretty-print.c @@ -586,6 +586,17 @@ dump_omp_clause (pretty_printer *buffer, tree clause, int spc, int flags) pp_string (buffer, "taskgroup"); break; + case OMP_CLAUSE_CILK_ASSERT: + pp_string (buffer, "cilk_assert"); + break; + + case OMP_CLAUSE_CILK_VECTORLENGTH: + pp_string (buffer, "cilk_vectorlength("); + dump_generic_node (buffer, OMP_CLAUSE_CILK_VECTORLENGTH_EXPR (clause), + spc, flags, false); + pp_character (buffer, ')'); + break; + default: /* Should never happen. */ dump_generic_node (buffer, clause, spc, flags, false); diff --git a/gcc/tree.c b/gcc/tree.c index 36fadffffb15a..2bc61311d7565 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -264,6 +264,8 @@ unsigned const char omp_clause_num_ops[] = 0, /* OMP_CLAUSE_PARALLEL */ 0, /* OMP_CLAUSE_SECTIONS */ 0 /* OMP_CLAUSE_TASKGROUP */ + , 0, /* OMP_CLAUSE_CILK_ASSERT */ + 1, /* OMP_CLAUSE_CILK_VECTORLENGTH */ }; const char * const omp_clause_code_name[] = @@ -305,6 +307,8 @@ const char * const omp_clause_code_name[] = "parallel", "sections", "taskgroup" + , "cilk_assert", + "cilk_vectorlength", }; @@ -10809,6 +10813,7 @@ walk_tree_1 (tree *tp, walk_tree_fn func, void *data, case OMP_CLAUSE_DIST_SCHEDULE: case OMP_CLAUSE_SAFELEN: case OMP_CLAUSE_SIMDLEN: + case OMP_CLAUSE_CILK_VECTORLENGTH: WALK_SUBTREE (OMP_CLAUSE_OPERAND (*tp, 0)); /* FALLTHRU */ @@ -10853,6 +10858,9 @@ walk_tree_1 (tree *tp, walk_tree_fn func, void *data, WALK_SUBTREE_TAIL (OMP_CLAUSE_CHAIN (*tp)); } + case OMP_CLAUSE_CILK_ASSERT: + break; + default: gcc_unreachable (); } diff --git a/gcc/tree.h b/gcc/tree.h index b4bd6c490f45e..75fbebf5d48f2 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -446,7 +446,13 @@ enum omp_clause_code OMP_CLAUSE_SECTIONS, /* OpenMP clause: taskgroup. */ - OMP_CLAUSE_TASKGROUP + OMP_CLAUSE_TASKGROUP, + + /* Cilk Plus clause: assert. */ + OMP_CLAUSE_CILK_ASSERT, + + /* Cilk Plus clause: vectorlength (constant-expression-list). */ + OMP_CLAUSE_CILK_VECTORLENGTH }; /* The definition of tree nodes fills the next several pages. */ @@ -1857,6 +1863,13 @@ extern void protected_set_expr_location (tree, location_t); OMP_CLAUSE_OPERAND (OMP_CLAUSE_RANGE_CHECK (OMP_CLAUSE_CHECK (NODE), \ OMP_CLAUSE_PRIVATE, \ OMP_CLAUSE_MAP), 0) + +/* In an OMP_SIMD_CLAUSE_CILK_VECTORLENGTH, one vectorlength + expression. */ +#define OMP_CLAUSE_CILK_VECTORLENGTH_EXPR(NODE) \ + OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK \ + (NODE, OMP_CLAUSE_CILK_VECTORLENGTH), 0) + #define OMP_CLAUSE_HAS_LOCATION(NODE) \ (LOCATION_LOCUS ((OMP_CLAUSE_CHECK (NODE))->omp_clause.locus) \ != UNKNOWN_LOCATION) From 63949300783c35767247e84ec2f1841efa726db2 Mon Sep 17 00:00:00 2001 From: jakub Date: Tue, 23 Apr 2013 14:44:49 +0000 Subject: [PATCH 12/63] * Makefile.in (omp-low.o): Depend on $(TARGET_H). * gimplify.c (gimplify_adjust_omp_clauses): For linear clauses if outer_context is non-NULL, but not ORT_COMBINED_PARALLEL, call omp_notice_variable. Remove aligned clauses that can't be handled yet. * omp-low.c: Include target.h. (scan_sharing_clauses): For aligned clauses with global arrays register local replacement. (omp_clause_aligned_alignment): New function. (lower_rec_input_clauses): For aligned clauses for global arrays or automatic pointers emit __builtin_assume_aligned before the loop if possible. (expand_omp_regimplify_p, expand_omp_build_assign): New functions. (expand_omp_simd): Use them. Handle pointer iterators and broken loops. (lower_omp_for): Call lower_omp on gimple_omp_body_ptr after calling lower_rec_input_clauses, not before it. cp/ * semantics.c (finish_omp_clauses): On OMP_CLAUSE_LINEAR clauses verify OMP_CLAUSE_DECL has integral or pointer type, and handle linear steps for pointer type decls. FIx up handling of OMP_CLAUSE_UNIFORM. testsuite/ * c-c++-common/gomp/simd3.c: New test. * c-c++-common/gomp/simd4.c: New test. * c-c++-common/gomp/simd5.c: New test. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gomp-4_0-branch@198193 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog.gomp | 20 +++ gcc/Makefile.in | 2 +- gcc/cp/ChangeLog.gomp | 7 + gcc/cp/semantics.c | 25 ++- gcc/gimplify.c | 61 +++++-- gcc/omp-low.c | 224 +++++++++++++++++++----- gcc/testsuite/ChangeLog.gomp | 6 + gcc/testsuite/c-c++-common/gomp/simd3.c | 26 +++ gcc/testsuite/c-c++-common/gomp/simd4.c | 21 +++ gcc/testsuite/c-c++-common/gomp/simd5.c | 19 ++ 10 files changed, 349 insertions(+), 62 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/gomp/simd3.c create mode 100644 gcc/testsuite/c-c++-common/gomp/simd4.c create mode 100644 gcc/testsuite/c-c++-common/gomp/simd5.c diff --git a/gcc/ChangeLog.gomp b/gcc/ChangeLog.gomp index f1eed5263bfc3..9e0126272ba3f 100644 --- a/gcc/ChangeLog.gomp +++ b/gcc/ChangeLog.gomp @@ -1,3 +1,23 @@ +2013-04-23 Jakub Jelinek + + * Makefile.in (omp-low.o): Depend on $(TARGET_H). + * gimplify.c (gimplify_adjust_omp_clauses): For linear clauses + if outer_context is non-NULL, but not ORT_COMBINED_PARALLEL, + call omp_notice_variable. Remove aligned clauses that can't + be handled yet. + * omp-low.c: Include target.h. + (scan_sharing_clauses): For aligned clauses with global arrays + register local replacement. + (omp_clause_aligned_alignment): New function. + (lower_rec_input_clauses): For aligned clauses for global + arrays or automatic pointers emit __builtin_assume_aligned + before the loop if possible. + (expand_omp_regimplify_p, expand_omp_build_assign): New functions. + (expand_omp_simd): Use them. Handle pointer iterators and broken + loops. + (lower_omp_for): Call lower_omp on gimple_omp_body_ptr after + calling lower_rec_input_clauses, not before it. + 2013-04-19 Jakub Jelinek * tree.h (OMP_CLAUSE_LINEAR_NO_COPYIN, diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 54ea04f644a1a..429db7e4abab1 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -2535,7 +2535,7 @@ omp-low.o : omp-low.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ $(RTL_H) $(GIMPLE_H) $(TREE_INLINE_H) langhooks.h $(DIAGNOSTIC_CORE_H) \ $(TREE_FLOW_H) $(FLAGS_H) $(EXPR_H) $(DIAGNOSTIC_CORE_H) \ $(TREE_PASS_H) $(GGC_H) $(EXCEPT_H) $(SPLAY_TREE_H) $(OPTABS_H) \ - $(CFGLOOP_H) tree-iterator.h gt-omp-low.h + $(CFGLOOP_H) tree-iterator.h $(TARGET_H) gt-omp-low.h tree-browser.o : tree-browser.c tree-browser.def $(CONFIG_H) $(SYSTEM_H) \ coretypes.h $(TREE_H) $(TREE_PRETTY_PRINT_H) omega.o : omega.c $(OMEGA_H) $(CONFIG_H) $(SYSTEM_H) coretypes.h dumpfile.h \ diff --git a/gcc/cp/ChangeLog.gomp b/gcc/cp/ChangeLog.gomp index 602504488e8a1..ffc3f03c3a702 100644 --- a/gcc/cp/ChangeLog.gomp +++ b/gcc/cp/ChangeLog.gomp @@ -1,3 +1,10 @@ +2013-04-23 Jakub Jelinek + + * semantics.c (finish_omp_clauses): On OMP_CLAUSE_LINEAR clauses + verify OMP_CLAUSE_DECL has integral or pointer type, and handle + linear steps for pointer type decls. FIx up handling of + OMP_CLAUSE_UNIFORM. + 2013-04-19 Jakub Jelinek * cp-tree.h (CP_OMP_CLAUSE_INFO): Also allow it on OMP_CLAUSE_LINEAR. diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 7a45c87f8814f..ff8ac7b5f092d 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -4058,6 +4058,15 @@ finish_omp_clauses (tree clauses) goto check_dup_generic; case OMP_CLAUSE_LINEAR: name = "linear"; + t = OMP_CLAUSE_DECL (c); + if (!type_dependent_expression_p (t) + && !INTEGRAL_TYPE_P (TREE_TYPE (t)) + && TREE_CODE (TREE_TYPE (t)) != POINTER_TYPE) + { + error ("linear clause applied to non-integral non-pointer"); + remove = true; + break; + } t = OMP_CLAUSE_LINEAR_STEP (c); if (t == NULL_TREE) t = integer_one_node; @@ -4073,7 +4082,20 @@ finish_omp_clauses (tree clauses) { t = mark_rvalue_use (t); if (!processing_template_decl) - t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + { + t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + if (TREE_CODE (TREE_TYPE (OMP_CLAUSE_DECL (c))) + == POINTER_TYPE) + { + t = pointer_int_sum (OMP_CLAUSE_LOCATION (c), PLUS_EXPR, + OMP_CLAUSE_DECL (c), t); + t = fold_build2_loc (OMP_CLAUSE_LOCATION (c), + MINUS_EXPR, sizetype, t, + OMP_CLAUSE_DECL (c)); + if (t == error_mark_node) + remove = true; + } + } OMP_CLAUSE_LINEAR_STEP (c) = t; } goto check_dup_generic; @@ -4385,6 +4407,7 @@ finish_omp_clauses (tree clauses) break; case OMP_CLAUSE_UNIFORM: + t = OMP_CLAUSE_DECL (c); if (TREE_CODE (t) != PARM_DECL) { if (processing_template_decl) diff --git a/gcc/gimplify.c b/gcc/gimplify.c index f6b67173d1119..f990fac62106d 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -6473,24 +6473,28 @@ gimplify_adjust_omp_clauses (tree *list_p) } if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR && ctx->outer_context - && ctx->outer_context->region_type == ORT_COMBINED_PARALLEL && !(OMP_CLAUSE_LINEAR_NO_COPYIN (c) && OMP_CLAUSE_LINEAR_NO_COPYOUT (c)) && !is_global_var (decl)) { - n = splay_tree_lookup (ctx->outer_context->variables, - (splay_tree_key) decl); - if (n == NULL - || (n->value & GOVD_DATA_SHARE_CLASS) == 0) + if (ctx->outer_context->region_type == ORT_COMBINED_PARALLEL) { - int flags = OMP_CLAUSE_LINEAR_NO_COPYIN (c) - ? GOVD_LASTPRIVATE : GOVD_SHARED; - if (n == NULL) - omp_add_variable (ctx->outer_context, decl, - flags | GOVD_SEEN); - else - n->value |= flags | GOVD_SEEN; + n = splay_tree_lookup (ctx->outer_context->variables, + (splay_tree_key) decl); + if (n == NULL + || (n->value & GOVD_DATA_SHARE_CLASS) == 0) + { + int flags = OMP_CLAUSE_LINEAR_NO_COPYIN (c) + ? GOVD_LASTPRIVATE : GOVD_SHARED; + if (n == NULL) + omp_add_variable (ctx->outer_context, decl, + flags | GOVD_SEEN); + else + n->value |= flags | GOVD_SEEN; + } } + else + omp_notice_variable (ctx->outer_context, decl, true); } } break; @@ -6510,6 +6514,39 @@ gimplify_adjust_omp_clauses (tree *list_p) { n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl); remove = n == NULL || !(n->value & GOVD_SEEN); + if (!remove && TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE) + { + struct gimplify_omp_ctx *octx; + if (n != NULL + && (n->value & (GOVD_DATA_SHARE_CLASS + & ~GOVD_FIRSTPRIVATE))) + remove = true; + else + for (octx = ctx->outer_context; octx; + octx = octx->outer_context) + { + n = splay_tree_lookup (octx->variables, + (splay_tree_key) decl); + if (n == NULL) + continue; + if (n->value & GOVD_LOCAL) + break; + /* We have to avoid assigning a shared variable + to itself when trying to add + __builtin_assume_aligned. */ + if (n->value & GOVD_SHARED) + { + remove = true; + break; + } + } + } + } + else if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE) + { + n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl); + if (n != NULL && (n->value & GOVD_DATA_SHARE_CLASS) != 0) + remove = true; } break; diff --git a/gcc/omp-low.c b/gcc/omp-low.c index 58117d97c540e..e658634310427 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -42,6 +42,7 @@ along with GCC; see the file COPYING3. If not see #include "splay-tree.h" #include "optabs.h" #include "cfgloop.h" +#include "target.h" /* Lowering of OpenMP parallel and workshare constructs proceeds in two @@ -1490,7 +1491,13 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) case OMP_CLAUSE_MERGEABLE: case OMP_CLAUSE_PROC_BIND: case OMP_CLAUSE_SAFELEN: + break; + case OMP_CLAUSE_ALIGNED: + decl = OMP_CLAUSE_DECL (c); + if (is_global_var (decl) + && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE) + install_var_local (decl, ctx); break; default: @@ -2275,6 +2282,49 @@ omp_reduction_init (tree clause, tree type) } } +/* Return alignment to be assumed for var in CLAUSE, which should be + OMP_CLAUSE_ALIGNED. */ + +static tree +omp_clause_aligned_alignment (tree clause) +{ + if (OMP_CLAUSE_ALIGNED_ALIGNMENT (clause)) + return OMP_CLAUSE_ALIGNED_ALIGNMENT (clause); + + /* Otherwise return implementation defined alignment. */ + unsigned int al = 1; + enum machine_mode mode, vmode; + int vs = targetm.vectorize.autovectorize_vector_sizes (); + if (vs) + vs = 1 << floor_log2 (vs); + static enum mode_class classes[] + = { MODE_INT, MODE_VECTOR_INT, MODE_FLOAT, MODE_VECTOR_FLOAT }; + for (int i = 0; i < 4; i += 2) + for (mode = GET_CLASS_NARROWEST_MODE (classes[i]); + mode != VOIDmode; + mode = GET_MODE_WIDER_MODE (mode)) + { + vmode = targetm.vectorize.preferred_simd_mode (mode); + if (GET_MODE_CLASS (vmode) != classes[i + 1]) + continue; + while (vs + && GET_MODE_SIZE (vmode) < vs + && GET_MODE_2XWIDER_MODE (vmode) != VOIDmode) + vmode = GET_MODE_2XWIDER_MODE (vmode); + + tree type = lang_hooks.types.type_for_mode (mode, 1); + if (type == NULL_TREE || TYPE_MODE (type) != mode) + continue; + type = build_vector_type (type, GET_MODE_SIZE (vmode) + / GET_MODE_SIZE (mode)); + if (TYPE_MODE (type) != vmode) + continue; + if (TYPE_ALIGN_UNIT (type) > al) + al = TYPE_ALIGN_UNIT (type); + } + return build_int_cst (integer_type_node, al); +} + /* Generate code to implement the input clauses, FIRSTPRIVATE and COPYIN, from the receiver (aka child) side and initializers for REFERENCE_TYPE private variables. Initialization statements go in ILIST, while calls @@ -2329,6 +2379,42 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, continue; } break; + case OMP_CLAUSE_ALIGNED: + if (pass == 0) + continue; + var = OMP_CLAUSE_DECL (c); + if (TREE_CODE (TREE_TYPE (var)) == POINTER_TYPE + && !is_global_var (var)) + { + new_var = maybe_lookup_decl (var, ctx); + if (new_var == NULL_TREE) + new_var = maybe_lookup_decl_in_outer_ctx (var, ctx); + x = builtin_decl_explicit (BUILT_IN_ASSUME_ALIGNED); + x = build_call_expr_loc (clause_loc, x, 2, new_var, + omp_clause_aligned_alignment (c)); + x = fold_convert_loc (clause_loc, TREE_TYPE (new_var), x); + x = build2 (MODIFY_EXPR, TREE_TYPE (new_var), new_var, x); + gimplify_and_add (x, ilist); + } + else if (TREE_CODE (TREE_TYPE (var)) == ARRAY_TYPE + && is_global_var (var)) + { + tree ptype = build_pointer_type (TREE_TYPE (var)), t, t2; + new_var = lookup_decl (var, ctx); + t = maybe_lookup_decl_in_outer_ctx (var, ctx); + t = build_fold_addr_expr_loc (clause_loc, t); + t2 = builtin_decl_explicit (BUILT_IN_ASSUME_ALIGNED); + t = build_call_expr_loc (clause_loc, t2, 2, t, + omp_clause_aligned_alignment (c)); + t = fold_convert_loc (clause_loc, ptype, t); + x = create_tmp_var (ptype, NULL); + t = build2 (MODIFY_EXPR, ptype, x, t); + gimplify_and_add (t, ilist); + t = build_simple_mem_ref_loc (clause_loc, x); + SET_DECL_VALUE_EXPR (new_var, t); + DECL_HAS_VALUE_EXPR_P (new_var) = 1; + } + continue; default: continue; } @@ -3422,6 +3508,43 @@ optimize_omp_library_calls (gimple entry_stmt) } } +/* Callback for expand_omp_build_assign. Return non-NULL if *tp needs to be + regimplified. */ + +static tree +expand_omp_regimplify_p (tree *tp, int *walk_subtrees, void *) +{ + tree t = *tp; + + /* Any variable with DECL_VALUE_EXPR needs to be regimplified. */ + if (TREE_CODE (t) == VAR_DECL && DECL_HAS_VALUE_EXPR_P (t)) + return t; + + if (TREE_CODE (t) == ADDR_EXPR) + recompute_tree_invariant_for_addr_expr (t); + + *walk_subtrees = !TYPE_P (t) && !DECL_P (t); + return NULL_TREE; +} + +/* Prepend TO = FROM assignment before *GSI_P. */ + +static void +expand_omp_build_assign (gimple_stmt_iterator *gsi_p, tree to, tree from) +{ + bool simple_p = DECL_P (to) && TREE_ADDRESSABLE (to); + from = force_gimple_operand_gsi (gsi_p, from, simple_p, NULL_TREE, + true, GSI_SAME_STMT); + gimple stmt = gimple_build_assign (to, from); + gsi_insert_before (gsi_p, stmt, GSI_SAME_STMT); + if (walk_tree (&from, expand_omp_regimplify_p, NULL, NULL) + || walk_tree (&to, expand_omp_regimplify_p, NULL, NULL)) + { + gimple_stmt_iterator gsi = gsi_for_stmt (stmt); + gimple_regimplify_operands (stmt, &gsi); + } +} + /* Expand the OpenMP parallel or task directive starting at REGION. */ static void @@ -4802,38 +4925,27 @@ expand_omp_simd (struct omp_region *region, struct omp_for_data *fd) else { counts[i] = create_tmp_reg (type, ".count"); - t = force_gimple_operand_gsi (&gsi, t, false, NULL_TREE, - true, GSI_SAME_STMT); - stmt = gimple_build_assign (counts[i], t); - gsi_insert_before (&gsi, stmt, GSI_SAME_STMT); + expand_omp_build_assign (&gsi, counts[i], t); } if (SSA_VAR_P (fd->loop.n2)) { if (i == 0) t = counts[0]; else - { - t = fold_build2 (MULT_EXPR, type, fd->loop.n2, counts[i]); - t = force_gimple_operand_gsi (&gsi, t, false, NULL_TREE, - true, GSI_SAME_STMT); - } - stmt = gimple_build_assign (fd->loop.n2, t); - gsi_insert_before (&gsi, stmt, GSI_SAME_STMT); + t = fold_build2 (MULT_EXPR, type, fd->loop.n2, counts[i]); + expand_omp_build_assign (&gsi, fd->loop.n2, t); } } } - t = fold_convert (type, fd->loop.n1); - t = force_gimple_operand_gsi (&gsi, t, false, NULL_TREE, - true, GSI_SAME_STMT); - gsi_insert_before (&gsi, gimple_build_assign (fd->loop.v, t), GSI_SAME_STMT); + expand_omp_build_assign (&gsi, fd->loop.v, fold_convert (type, fd->loop.n1)); if (fd->collapse > 1) for (i = 0; i < fd->collapse; i++) { + tree itype = TREE_TYPE (fd->loops[i].v); + if (POINTER_TYPE_P (itype)) + itype = signed_type_for (itype); t = fold_convert (TREE_TYPE (fd->loops[i].v), fd->loops[i].n1); - t = force_gimple_operand_gsi (&gsi, t, false, NULL_TREE, - true, GSI_SAME_STMT); - gsi_insert_before (&gsi, gimple_build_assign (fd->loops[i].v, t), - GSI_SAME_STMT); + expand_omp_build_assign (&gsi, fd->loops[i].v, t); } /* Remove the GIMPLE_OMP_FOR statement. */ @@ -4850,37 +4962,42 @@ expand_omp_simd (struct omp_region *region, struct omp_for_data *fd) t = fold_build_pointer_plus (fd->loop.v, fd->loop.step); else t = fold_build2 (PLUS_EXPR, type, fd->loop.v, fd->loop.step); - t = force_gimple_operand_gsi (&gsi, t, false, NULL_TREE, - true, GSI_SAME_STMT); - stmt = gimple_build_assign (fd->loop.v, t); - gsi_insert_before (&gsi, stmt, GSI_SAME_STMT); + expand_omp_build_assign (&gsi, fd->loop.v, t); if (fd->collapse > 1) { i = fd->collapse - 1; - t = fold_convert (TREE_TYPE (fd->loops[i].v), fd->loops[i].step); - t = build2 (PLUS_EXPR, TREE_TYPE (fd->loops[i].v), - fd->loops[i].v, t); - t = force_gimple_operand_gsi (&gsi, t, false, NULL_TREE, - true, GSI_SAME_STMT); - stmt = gimple_build_assign (fd->loops[i].v, t); - gsi_insert_before (&gsi, stmt, GSI_SAME_STMT); + if (POINTER_TYPE_P (TREE_TYPE (fd->loops[i].v))) + { + t = fold_convert (sizetype, fd->loop.step); + t = fold_build_pointer_plus (fd->loops[i].v, t); + } + else + { + t = fold_convert (TREE_TYPE (fd->loops[i].v), + fd->loops[i].step); + t = fold_build2 (PLUS_EXPR, TREE_TYPE (fd->loops[i].v), + fd->loops[i].v, t); + } + expand_omp_build_assign (&gsi, fd->loops[i].v, t); for (i = fd->collapse - 1; i > 0; i--) { tree itype = TREE_TYPE (fd->loops[i].v); tree itype2 = TREE_TYPE (fd->loops[i - 1].v); + if (POINTER_TYPE_P (itype2)) + itype2 = signed_type_for (itype2); t = build3 (COND_EXPR, itype2, build2 (fd->loops[i].cond_code, boolean_type_node, fd->loops[i].v, fold_convert (itype, fd->loops[i].n2)), build_int_cst (itype2, 0), fold_convert (itype2, fd->loops[i - 1].step)); - t = build2 (PLUS_EXPR, itype2, fd->loops[i - 1].v, t); - t = force_gimple_operand_gsi (&gsi, t, false, NULL_TREE, - true, GSI_SAME_STMT); - stmt = gimple_build_assign (fd->loops[i - 1].v, t); - gsi_insert_before (&gsi, stmt, GSI_SAME_STMT); + if (POINTER_TYPE_P (TREE_TYPE (fd->loops[i - 1].v))) + t = fold_build_pointer_plus (fd->loops[i - 1].v, t); + else + t = fold_build2 (PLUS_EXPR, itype2, fd->loops[i - 1].v, t); + expand_omp_build_assign (&gsi, fd->loops[i - 1].v, t); t = build3 (COND_EXPR, itype, build2 (fd->loops[i].cond_code, boolean_type_node, @@ -4888,10 +5005,7 @@ expand_omp_simd (struct omp_region *region, struct omp_for_data *fd) fold_convert (itype, fd->loops[i].n2)), fd->loops[i].v, fold_convert (itype, fd->loops[i].n1)); - t = force_gimple_operand_gsi (&gsi, t, false, NULL_TREE, - true, GSI_SAME_STMT); - stmt = gimple_build_assign (fd->loops[i].v, t); - gsi_insert_before (&gsi, stmt, GSI_SAME_STMT); + expand_omp_build_assign (&gsi, fd->loops[i].v, t); } } @@ -4906,7 +5020,16 @@ expand_omp_simd (struct omp_region *region, struct omp_for_data *fd) t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, false, GSI_CONTINUE_LINKING); t = build2 (fd->loop.cond_code, boolean_type_node, fd->loop.v, t); - gsi_insert_after (&gsi, gimple_build_cond_empty (t), GSI_CONTINUE_LINKING); + stmt = gimple_build_cond_empty (t); + gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING); + if (walk_tree (gimple_cond_lhs_ptr (stmt), expand_omp_regimplify_p, + NULL, NULL) + || walk_tree (gimple_cond_rhs_ptr (stmt), expand_omp_regimplify_p, + NULL, NULL)) + { + gsi = gsi_for_stmt (stmt); + gimple_regimplify_operands (stmt, &gsi); + } /* Remove GIMPLE_OMP_RETURN. */ gsi = gsi_last_bb (exit_bb); @@ -4923,18 +5046,22 @@ expand_omp_simd (struct omp_region *region, struct omp_for_data *fd) e = BRANCH_EDGE (l1_bb); ne = FALLTHRU_EDGE (l1_bb); e->flags = EDGE_TRUE_VALUE; - ne->flags = EDGE_FALSE_VALUE; - e->probability = REG_BR_PROB_BASE * 7 / 8; - ne->probability = REG_BR_PROB_BASE / 8; - - set_immediate_dominator (CDI_DOMINATORS, l1_bb, entry_bb); - set_immediate_dominator (CDI_DOMINATORS, l2_bb, l1_bb); - set_immediate_dominator (CDI_DOMINATORS, l0_bb, l1_bb); } else { single_succ_edge (entry_bb)->flags = EDGE_FALLTHRU; + + ne = single_succ_edge (l1_bb); + e = make_edge (l1_bb, l0_bb, EDGE_TRUE_VALUE); + } + ne->flags = EDGE_FALSE_VALUE; + e->probability = REG_BR_PROB_BASE * 7 / 8; + ne->probability = REG_BR_PROB_BASE / 8; + + set_immediate_dominator (CDI_DOMINATORS, l1_bb, entry_bb); + set_immediate_dominator (CDI_DOMINATORS, l2_bb, l1_bb); + set_immediate_dominator (CDI_DOMINATORS, l0_bb, l1_bb); } @@ -6583,7 +6710,6 @@ lower_omp_for (gimple_stmt_iterator *gsi_p, omp_context *ctx) push_gimplify_context (&gctx); lower_omp (gimple_omp_for_pre_body_ptr (stmt), ctx); - lower_omp (gimple_omp_body_ptr (stmt), ctx); block = make_node (BLOCK); new_stmt = gimple_build_bind (NULL, NULL, block); @@ -6608,6 +6734,8 @@ lower_omp_for (gimple_stmt_iterator *gsi_p, omp_context *ctx) lower_rec_input_clauses (gimple_omp_for_clauses (stmt), &body, &dlist, ctx); gimple_seq_add_seq (&body, gimple_omp_for_pre_body (stmt)); + lower_omp (gimple_omp_body_ptr (stmt), ctx); + /* Lower the header expressions. At this point, we can assume that the header is of the form: diff --git a/gcc/testsuite/ChangeLog.gomp b/gcc/testsuite/ChangeLog.gomp index 53e40768ac168..1c4e357481513 100644 --- a/gcc/testsuite/ChangeLog.gomp +++ b/gcc/testsuite/ChangeLog.gomp @@ -1,3 +1,9 @@ +2013-04-23 Jakub Jelinek + + * c-c++-common/gomp/simd3.c: New test. + * c-c++-common/gomp/simd4.c: New test. + * c-c++-common/gomp/simd5.c: New test. + 2013-04-19 Jakub Jelinek * c-c++-common/gomp/simd1.c: New test. diff --git a/gcc/testsuite/c-c++-common/gomp/simd3.c b/gcc/testsuite/c-c++-common/gomp/simd3.c new file mode 100644 index 0000000000000..d505b2ee4ab73 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/simd3.c @@ -0,0 +1,26 @@ +/* { dg-do compile { target { ! c } } } */ +/* { dg-options "-fopenmp" } */ +/* { dg-additional-options "-std=c99" { target c } } */ + +extern int a[13*13*13*13*2], b[1024], *k, l, m; + +void +foo (int *q, float *p) +{ + int *i, *j, *n, *o; +#pragma omp simd collapse (4) linear(k : m + 1) aligned(p, q) + for (i = &a[0]; i < &a[13*13*13*13*2]; i += 13*13*13*2) + for (j = &a[0]; j < &a[13*13*13*2]; j += 13*13*2) + for (n = &a[0]; n < &a[13*13*2]; n += 13*2) + for (o = &a[0]; o < &a[13*2]; o += 2) + q[k - &a[0]] *= p[k - &a[0]] + 7 * (i-&a[0]) + 14 * (j-&a[0]) + 21 * (n-&a[0]) + 28 * (o-&a[0]), k += m + 1; +} + +void +bar () +{ + int *i; + #pragma omp simd safelen(16) aligned(a, b : 32) + for (i = &a[0]; i < &a[1024]; i++) + *i *= b[i - &a[0]]; +} diff --git a/gcc/testsuite/c-c++-common/gomp/simd4.c b/gcc/testsuite/c-c++-common/gomp/simd4.c new file mode 100644 index 0000000000000..8d7187506d75e --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/simd4.c @@ -0,0 +1,21 @@ +/* { dg-do compile { target { ! c } } } */ +/* { dg-options "-fopenmp" } */ +/* { dg-additional-options "-std=c99" { target c } } */ + +struct S *p; /* { dg-error "forward declaration" } */ +float f; +int j; + +void +foo (void) +{ +#pragma omp simd linear(p) linear(f : 1) + for (int i = 0; i < 10; i++) + ; +#pragma omp simd linear(j : 7.0) /* { dg-error "linear step expression must be integral" } */ + for (int i = 0; i < 10; i++) + ; +} + +/* { dg-error "linear clause applied to" "" { target *-*-* } 12 } */ +/* { dg-error "incomplete type" "" { target *-*-* } 12 } */ diff --git a/gcc/testsuite/c-c++-common/gomp/simd5.c b/gcc/testsuite/c-c++-common/gomp/simd5.c new file mode 100644 index 0000000000000..85a28fcc21724 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/simd5.c @@ -0,0 +1,19 @@ +/* { dg-do compile { target { ! c } } } */ +/* { dg-options "-fopenmp" } */ +/* { dg-additional-options "-std=c99" { target c } } */ + +void baz (void) __attribute__((noreturn)); + +void +foo (int x) +{ + if (x) + #pragma omp simd + for (int i = 0; i < 10; i++) + baz (); +#pragma omp simd collapse(3) + for (int i = 0; i < 10; i++) + for (int j = 0; j < 10; j++) + for (int k = 0; k < 10; k++) + baz (); +} From 0b8a12b8afc2d51658afb3b81550aa2ab2a696e0 Mon Sep 17 00:00:00 2001 From: jakub Date: Wed, 24 Apr 2013 21:01:13 +0000 Subject: [PATCH 13/63] c/ * c-parser.c (c_parser_compound_statement, c_parser_statement): Adjust comments for OpenMP 3.0+ additions. (c_parser_pragma): Handle PRAGMA_OMP_CANCEL and PRAGMA_OMP_CANCELLATION_POINT. (c_parser_omp_clause_name): Handle new OpenMP 4.0 clauses. (c_parser_omp_clause_collapse): Fully fold collapse expression. (c_parser_omp_clause_branch, c_parser_omp_clause_cancelkind, c_parser_omp_clause_num_teams, c_parser_omp_clause_aligned, c_parser_omp_clause_linear, c_parser_omp_clause_safelen, c_parser_omp_clause_simdlen, c_parser_omp_clause_depend, c_parser_omp_clause_map, c_parser_omp_clause_device, c_parser_omp_clause_dist_schedule, c_parser_omp_clause_proc_bind, c_parser_omp_clause_to, c_parser_omp_clause_from, c_parser_omp_clause_uniform): New functions. (c_parser_omp_all_clauses): Handle new OpenMP 4.0 clauses. (c_parser_omp_for_loop): Add CODE argument, pass it through to c_finish_omp_for. (OMP_SIMD_CLAUSE_MASK): Define. (c_parser_omp_simd): New function. (c_parser_omp_for): Parse #pragma omp for simd. (OMP_PARALLEL_CLAUSE_MASK): Add OMP_CLAUSE_PROC_BIND. (c_parser_omp_parallel): Parse #pragma omp parallel for simd. (OMP_TASK_CLAUSE_MASK): Add OMP_CLAUSE_DEPEND. (c_parser_omp_taskgroup): New function. (OMP_CANCEL_CLAUSE_MASK, OMP_CANCELLATION_POINT_CLAUSE_MASK): Define. (c_parser_omp_cancel, c_parser_omp_cancellation_point): New functions. (c_parser_omp_construct): Handle PRAGMA_OMP_SIMD and PRAGMA_OMP_TASKGROUP. (c_parser_transaction_cancel): Formatting fix. * c-tree.h (c_begin_omp_taskgroup, c_finish_omp_taskgroup, c_finish_omp_cancel, c_finish_omp_cancellation_point): New prototypes. * c-typeck.c (c_begin_omp_taskgroup, c_finish_omp_taskgroup, c_finish_omp_cancel, c_finish_omp_cancellation_point): New functions. (c_finish_omp_clauses): Handle new OpenMP 4.0 clauses. cp/ * parser.c (cp_parser_omp_clause_name): Add missing break after case 'i'. (cp_parser_omp_cancellation_point): Diagnose error if #pragma omp cancellation isn't followed by point. * semantics.c (finish_omp_clauses): Complain also about zero in alignment of aligned directive or safelen/simdlen expressions. (finish_omp_cancel): Fix up diagnostics wording. testsuite/ * c-c++-common/gomp/simd1.c: Enable also for C. * c-c++-common/gomp/simd2.c: Likewise. * c-c++-common/gomp/simd3.c: Likewise. * c-c++-common/gomp/simd4.c: Likewise. Adjust expected diagnostics for C. * c-c++-common/gomp/simd5.c: Enable also for C. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gomp-4_0-branch@198264 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/c/ChangeLog.gomp | 39 ++ gcc/c/c-parser.c | 877 +++++++++++++++++++++++- gcc/c/c-tree.h | 4 + gcc/c/c-typeck.c | 178 +++++ gcc/cp/ChangeLog.gomp | 10 + gcc/cp/parser.c | 4 +- gcc/cp/semantics.c | 6 +- gcc/testsuite/ChangeLog.gomp | 9 + gcc/testsuite/c-c++-common/gomp/simd1.c | 2 +- gcc/testsuite/c-c++-common/gomp/simd2.c | 2 +- gcc/testsuite/c-c++-common/gomp/simd3.c | 2 +- gcc/testsuite/c-c++-common/gomp/simd4.c | 8 +- gcc/testsuite/c-c++-common/gomp/simd5.c | 2 +- 13 files changed, 1113 insertions(+), 30 deletions(-) diff --git a/gcc/c/ChangeLog.gomp b/gcc/c/ChangeLog.gomp index 5169f08ddb42d..83c2f14baf05c 100644 --- a/gcc/c/ChangeLog.gomp +++ b/gcc/c/ChangeLog.gomp @@ -1,3 +1,42 @@ +2013-04-24 Jakub Jelinek + + * c-parser.c (c_parser_compound_statement, + c_parser_statement): Adjust comments for OpenMP 3.0+ + additions. + (c_parser_pragma): Handle PRAGMA_OMP_CANCEL and + PRAGMA_OMP_CANCELLATION_POINT. + (c_parser_omp_clause_name): Handle new OpenMP 4.0 clauses. + (c_parser_omp_clause_collapse): Fully fold collapse + expression. + (c_parser_omp_clause_branch, c_parser_omp_clause_cancelkind, + c_parser_omp_clause_num_teams, c_parser_omp_clause_aligned, + c_parser_omp_clause_linear, c_parser_omp_clause_safelen, + c_parser_omp_clause_simdlen, c_parser_omp_clause_depend, + c_parser_omp_clause_map, c_parser_omp_clause_device, + c_parser_omp_clause_dist_schedule, c_parser_omp_clause_proc_bind, + c_parser_omp_clause_to, c_parser_omp_clause_from, + c_parser_omp_clause_uniform): New functions. + (c_parser_omp_all_clauses): Handle new OpenMP 4.0 clauses. + (c_parser_omp_for_loop): Add CODE argument, pass it through + to c_finish_omp_for. + (OMP_SIMD_CLAUSE_MASK): Define. + (c_parser_omp_simd): New function. + (c_parser_omp_for): Parse #pragma omp for simd. + (OMP_PARALLEL_CLAUSE_MASK): Add OMP_CLAUSE_PROC_BIND. + (c_parser_omp_parallel): Parse #pragma omp parallel for simd. + (OMP_TASK_CLAUSE_MASK): Add OMP_CLAUSE_DEPEND. + (c_parser_omp_taskgroup): New function. + (OMP_CANCEL_CLAUSE_MASK, OMP_CANCELLATION_POINT_CLAUSE_MASK): Define. + (c_parser_omp_cancel, c_parser_omp_cancellation_point): New functions. + (c_parser_omp_construct): Handle PRAGMA_OMP_SIMD and + PRAGMA_OMP_TASKGROUP. + (c_parser_transaction_cancel): Formatting fix. + * c-tree.h (c_begin_omp_taskgroup, c_finish_omp_taskgroup, + c_finish_omp_cancel, c_finish_omp_cancellation_point): New prototypes. + * c-typeck.c (c_begin_omp_taskgroup, c_finish_omp_taskgroup, + c_finish_omp_cancel, c_finish_omp_cancellation_point): New functions. + (c_finish_omp_clauses): Handle new OpenMP 4.0 clauses. + 2013-03-27 Jakub Jelinek * c-parser.c (c_parser_omp_all_clauses): Change mask argument type diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index 5b06803317463..eea10811f0d26 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -1186,6 +1186,8 @@ static void c_parser_omp_barrier (c_parser *); static void c_parser_omp_flush (c_parser *); static void c_parser_omp_taskwait (c_parser *); static void c_parser_omp_taskyield (c_parser *); +static void c_parser_omp_cancel (c_parser *); +static void c_parser_omp_cancellation_point (c_parser *); enum pragma_context { pragma_external, pragma_stmt, pragma_compound }; static bool c_parser_pragma (c_parser *, enum pragma_context); @@ -4054,7 +4056,11 @@ c_parser_initval (c_parser *parser, struct c_expr *after, openmp-directive: barrier-directive - flush-directive */ + flush-directive + taskwait-directive + taskyield-directive + cancel-directive + cancellation-point-directive */ static tree c_parser_compound_statement (c_parser *parser) @@ -4384,9 +4390,12 @@ c_parser_label (c_parser *parser) openmp-construct: parallel-construct for-construct + simd-construct + for-simd-construct sections-construct single-construct parallel-for-construct + parallel-for-simd-construct parallel-sections-construct master-construct critical-construct @@ -4399,6 +4408,12 @@ c_parser_label (c_parser *parser) for-construct: for-directive iteration-statement + simd-construct: + simd-directive iteration-statements + + for-simd-construct: + for-simd-directive iteration-statements + sections-construct: sections-directive section-scope @@ -4408,6 +4423,9 @@ c_parser_label (c_parser *parser) parallel-for-construct: parallel-for-directive iteration-statement + parallel-for-simd-construct: + parallel-for-simd-directive iteration-statement + parallel-sections-construct: parallel-sections-directive section-scope @@ -8606,6 +8624,28 @@ c_parser_pragma (c_parser *parser, enum pragma_context context) c_parser_omp_taskyield (parser); return false; + case PRAGMA_OMP_CANCEL: + if (context != pragma_compound) + { + if (context == pragma_stmt) + c_parser_error (parser, "%<#pragma omp cancel%> may only be " + "used in compound statements"); + goto bad_stmt; + } + c_parser_omp_cancel (parser); + return false; + + case PRAGMA_OMP_CANCELLATION_POINT: + if (context != pragma_compound) + { + if (context == pragma_stmt) + c_parser_error (parser, "%<#pragma omp cancellation point%> may " + "only be used in compound statements"); + goto bad_stmt; + } + c_parser_omp_cancellation_point (parser); + return false; + case PRAGMA_OMP_THREADPRIVATE: c_parser_omp_threadprivate (parser); return false; @@ -8690,7 +8730,7 @@ c_parser_pragma_pch_preprocess (c_parser *parser) c_common_pch_pragma (parse_in, TREE_STRING_POINTER (name)); } -/* OpenMP 2.5 parsing routines. */ +/* OpenMP 2.5 / 3.0 / 3.1 / 4.0 parsing routines. */ /* Returns name of the next clause. If the clause is not recognized PRAGMA_OMP_CLAUSE_NONE is returned and @@ -8706,12 +8746,18 @@ c_parser_omp_clause_name (c_parser *parser) result = PRAGMA_OMP_CLAUSE_IF; else if (c_parser_next_token_is_keyword (parser, RID_DEFAULT)) result = PRAGMA_OMP_CLAUSE_DEFAULT; + else if (c_parser_next_token_is_keyword (parser, RID_FOR)) + result = PRAGMA_OMP_CLAUSE_FOR; else if (c_parser_next_token_is (parser, CPP_NAME)) { const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); switch (p[0]) { + case 'a': + if (!strcmp ("aligned", p)) + result = PRAGMA_OMP_CLAUSE_ALIGNED; + break; case 'c': if (!strcmp ("collapse", p)) result = PRAGMA_OMP_CLAUSE_COLLAPSE; @@ -8720,23 +8766,45 @@ c_parser_omp_clause_name (c_parser *parser) else if (!strcmp ("copyprivate", p)) result = PRAGMA_OMP_CLAUSE_COPYPRIVATE; break; + case 'd': + if (!strcmp ("depend", p)) + result = PRAGMA_OMP_CLAUSE_DEPEND; + else if (!strcmp ("device", p)) + result = PRAGMA_OMP_CLAUSE_DEVICE; + else if (!strcmp ("dist_schedule", p)) + result = PRAGMA_OMP_CLAUSE_DIST_SCHEDULE; + break; case 'f': if (!strcmp ("final", p)) result = PRAGMA_OMP_CLAUSE_FINAL; else if (!strcmp ("firstprivate", p)) result = PRAGMA_OMP_CLAUSE_FIRSTPRIVATE; + else if (!strcmp ("from", p)) + result = PRAGMA_OMP_CLAUSE_FROM; + break; + case 'i': + if (!strcmp ("inbranch", p)) + result = PRAGMA_OMP_CLAUSE_INBRANCH; break; case 'l': if (!strcmp ("lastprivate", p)) result = PRAGMA_OMP_CLAUSE_LASTPRIVATE; + else if (!strcmp ("linear", p)) + result = PRAGMA_OMP_CLAUSE_LINEAR; break; case 'm': - if (!strcmp ("mergeable", p)) + if (!strcmp ("map", p)) + result = PRAGMA_OMP_CLAUSE_MAP; + else if (!strcmp ("mergeable", p)) result = PRAGMA_OMP_CLAUSE_MERGEABLE; break; case 'n': - if (!strcmp ("nowait", p)) + if (!strcmp ("notinbranch", p)) + result = PRAGMA_OMP_CLAUSE_NOTINBRANCH; + else if (!strcmp ("nowait", p)) result = PRAGMA_OMP_CLAUSE_NOWAIT; + else if (!strcmp ("num_teams", p)) + result = PRAGMA_OMP_CLAUSE_NUM_TEAMS; else if (!strcmp ("num_threads", p)) result = PRAGMA_OMP_CLAUSE_NUM_THREADS; break; @@ -8745,21 +8813,39 @@ c_parser_omp_clause_name (c_parser *parser) result = PRAGMA_OMP_CLAUSE_ORDERED; break; case 'p': - if (!strcmp ("private", p)) + if (!strcmp ("parallel", p)) + result = PRAGMA_OMP_CLAUSE_PARALLEL; + else if (!strcmp ("private", p)) result = PRAGMA_OMP_CLAUSE_PRIVATE; + else if (!strcmp ("proc_bind", p)) + result = PRAGMA_OMP_CLAUSE_PROC_BIND; break; case 'r': if (!strcmp ("reduction", p)) result = PRAGMA_OMP_CLAUSE_REDUCTION; break; case 's': - if (!strcmp ("schedule", p)) + if (!strcmp ("safelen", p)) + result = PRAGMA_OMP_CLAUSE_SAFELEN; + else if (!strcmp ("schedule", p)) result = PRAGMA_OMP_CLAUSE_SCHEDULE; + else if (!strcmp ("sections", p)) + result = PRAGMA_OMP_CLAUSE_SECTIONS; else if (!strcmp ("shared", p)) result = PRAGMA_OMP_CLAUSE_SHARED; + else if (!strcmp ("simdlen", p)) + result = PRAGMA_OMP_CLAUSE_SIMDLEN; + break; + case 't': + if (!strcmp ("taskgroup", p)) + result = PRAGMA_OMP_CLAUSE_TASKGROUP; + else if (!strcmp ("to", p)) + result = PRAGMA_OMP_CLAUSE_TO; break; case 'u': - if (!strcmp ("untied", p)) + if (!strcmp ("uniform", p)) + result = PRAGMA_OMP_CLAUSE_UNIFORM; + else if (!strcmp ("untied", p)) result = PRAGMA_OMP_CLAUSE_UNTIED; break; } @@ -8879,6 +8965,8 @@ c_parser_omp_clause_collapse (c_parser *parser, tree list) } if (num == error_mark_node) return list; + mark_exp_read (num); + num = c_fully_fold (num, false, NULL); if (!INTEGRAL_TYPE_P (TREE_TYPE (num)) || !host_integerp (num, 0) || (n = tree_low_cst (num, 0)) <= 0 @@ -9144,7 +9232,7 @@ c_parser_omp_clause_private (c_parser *parser, tree list) reduction-operator: One of: + * - & ^ | && || - + OpenMP 3.1: reduction-operator: @@ -9345,6 +9433,510 @@ c_parser_omp_clause_untied (c_parser *parser ATTRIBUTE_UNUSED, tree list) return c; } +/* OpenMP 4.0: + inbranch + notinbranch */ + +static tree +c_parser_omp_clause_branch (c_parser *parser ATTRIBUTE_UNUSED, + enum omp_clause_code code, tree list) +{ + check_no_duplicate_clause (list, code, omp_clause_code_name[code]); + + tree c = build_omp_clause (c_parser_peek_token (parser)->location, code); + OMP_CLAUSE_CHAIN (c) = list; + + return c; +} + +/* OpenMP 4.0: + parallel + for + sections + taskgroup */ + +static tree +c_parser_omp_clause_cancelkind (c_parser *parser ATTRIBUTE_UNUSED, + enum omp_clause_code code, tree list) +{ + tree c; + location_t loc = c_parser_peek_token (parser)->location; + + for (c = list; c; c = OMP_CLAUSE_CHAIN (c)) + switch (OMP_CLAUSE_CODE (c)) + { + case OMP_CLAUSE_PARALLEL: + case OMP_CLAUSE_FOR: + case OMP_CLAUSE_SECTIONS: + case OMP_CLAUSE_TASKGROUP: + error_at (loc, "only one of %, %, % " + "and % clauses can be specified"); + break; + default: + break; + } + + c = build_omp_clause (loc, code); + OMP_CLAUSE_CHAIN (c) = list; + + return c; +} + +/* OpenMP 4.0: + num_teams ( expression ) */ + +static tree +c_parser_omp_clause_num_teams (c_parser *parser, tree list) +{ + location_t num_teams_loc = c_parser_peek_token (parser)->location; + if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + location_t expr_loc = c_parser_peek_token (parser)->location; + tree c, t = c_parser_expression (parser).value; + mark_exp_read (t); + t = c_fully_fold (t, false, NULL); + + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + + if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + c_parser_error (parser, "expected integer expression"); + return list; + } + + /* Attempt to statically determine when the number isn't positive. */ + c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, t, + build_int_cst (TREE_TYPE (t), 0)); + if (CAN_HAVE_LOCATION_P (c)) + SET_EXPR_LOCATION (c, expr_loc); + if (c == boolean_true_node) + { + warning_at (expr_loc, 0, "% value must be positive"); + t = integer_one_node; + } + + check_no_duplicate_clause (list, OMP_CLAUSE_NUM_TEAMS, "num_teams"); + + c = build_omp_clause (num_teams_loc, OMP_CLAUSE_NUM_TEAMS); + OMP_CLAUSE_NUM_TEAMS_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + list = c; + } + + return list; +} + +/* OpenMP 4.0: + aligned ( variable-list ) + aligned ( variable-list : constant-expression ) */ + +static tree +c_parser_omp_clause_aligned (c_parser *parser, tree list) +{ + location_t clause_loc = c_parser_peek_token (parser)->location; + tree nl, c; + + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return list; + + nl = c_parser_omp_variable_list (parser, clause_loc, + OMP_CLAUSE_ALIGNED, list); + + if (c_parser_next_token_is (parser, CPP_COLON)) + { + c_parser_consume_token (parser); + tree alignment = c_parser_expr_no_commas (parser, NULL).value; + mark_exp_read (alignment); + alignment = c_fully_fold (alignment, false, NULL); + if (!INTEGRAL_TYPE_P (TREE_TYPE (alignment)) + && TREE_CODE (alignment) != INTEGER_CST + && tree_int_cst_sgn (alignment) != 1) + { + error_at (clause_loc, "% clause alignment expression must " + "be positive constant integer expression"); + alignment = NULL_TREE; + } + + for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) + OMP_CLAUSE_ALIGNED_ALIGNMENT (c) = alignment; + } + + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + return nl; +} + +/* OpenMP 4.0: + linear ( variable-list ) + linear ( variable-list : expression ) */ + +static tree +c_parser_omp_clause_linear (c_parser *parser, tree list) +{ + location_t clause_loc = c_parser_peek_token (parser)->location; + tree nl, c, step; + + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return list; + + nl = c_parser_omp_variable_list (parser, clause_loc, + OMP_CLAUSE_LINEAR, list); + + if (c_parser_next_token_is (parser, CPP_COLON)) + { + c_parser_consume_token (parser); + step = c_parser_expression (parser).value; + mark_exp_read (step); + step = c_fully_fold (step, false, NULL); + if (!INTEGRAL_TYPE_P (TREE_TYPE (step))) + { + error_at (clause_loc, "% clause step expression must " + "be integral"); + step = integer_one_node; + } + + } + else + step = integer_one_node; + + for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) + { + tree s = step; + if (TREE_CODE (TREE_TYPE (OMP_CLAUSE_DECL (c))) == POINTER_TYPE) + { + s = pointer_int_sum (clause_loc, PLUS_EXPR, OMP_CLAUSE_DECL (c), s); + s = fold_build2_loc (clause_loc, MINUS_EXPR, sizetype, s, + OMP_CLAUSE_DECL (c)); + if (s == error_mark_node) + s = size_one_node; + } + OMP_CLAUSE_LINEAR_STEP (c) = s; + } + + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + return nl; +} + +/* OpenMP 4.0: + safelen ( constant-expression ) */ + +static tree +c_parser_omp_clause_safelen (c_parser *parser, tree list) +{ + location_t clause_loc = c_parser_peek_token (parser)->location; + tree c, t; + + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return list; + + t = c_parser_expr_no_commas (parser, NULL).value; + mark_exp_read (t); + t = c_fully_fold (t, false, NULL); + if (!INTEGRAL_TYPE_P (TREE_TYPE (t)) + && TREE_CODE (t) != INTEGER_CST + && tree_int_cst_sgn (t) != 1) + { + error_at (clause_loc, "% clause expression must " + "be positive constant integer expression"); + t = NULL_TREE; + } + + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + if (t == NULL_TREE || t == error_mark_node) + return list; + + check_no_duplicate_clause (list, OMP_CLAUSE_SAFELEN, "safelen"); + + c = build_omp_clause (clause_loc, OMP_CLAUSE_SAFELEN); + OMP_CLAUSE_SAFELEN_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + return c; +} + +/* OpenMP 4.0: + simdlen ( constant-expression ) */ + +static tree +c_parser_omp_clause_simdlen (c_parser *parser, tree list) +{ + location_t clause_loc = c_parser_peek_token (parser)->location; + tree c, t; + + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return list; + + t = c_parser_expr_no_commas (parser, NULL).value; + mark_exp_read (t); + t = c_fully_fold (t, false, NULL); + if (!INTEGRAL_TYPE_P (TREE_TYPE (t)) + && TREE_CODE (t) != INTEGER_CST + && tree_int_cst_sgn (t) != 1) + { + error_at (clause_loc, "% clause expression must " + "be positive constant integer expression"); + t = NULL_TREE; + } + + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + if (t == NULL_TREE || t == error_mark_node) + return list; + + check_no_duplicate_clause (list, OMP_CLAUSE_SIMDLEN, "simdlen"); + + c = build_omp_clause (clause_loc, OMP_CLAUSE_SIMDLEN); + OMP_CLAUSE_SIMDLEN_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + return c; +} + +/* OpenMP 4.0: + depend ( depend-kind: variable-list ) + + depend-kind: + in | out | inout */ + +static tree +c_parser_omp_clause_depend (c_parser *parser, tree list) +{ + location_t clause_loc = c_parser_peek_token (parser)->location; + enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_INOUT; + tree nl, c; + + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return list; + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp ("in", p) == 0) + kind = OMP_CLAUSE_DEPEND_IN; + else if (strcmp ("inout", p) == 0) + kind = OMP_CLAUSE_DEPEND_INOUT; + else if (strcmp ("out", p) == 0) + kind = OMP_CLAUSE_DEPEND_OUT; + else + goto invalid_kind; + } + else + goto invalid_kind; + + c_parser_consume_token (parser); + if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) + goto resync_fail; + + nl = c_parser_omp_variable_list (parser, clause_loc, + OMP_CLAUSE_DEPEND, list); + + for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) + OMP_CLAUSE_DEPEND_KIND (c) = kind; + + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + return nl; + + invalid_kind: + c_parser_error (parser, "invalid depend kind"); + resync_fail: + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + return list; +} + +/* OpenMP 4.0: + map ( map-kind: variable-list ) + map ( variable-list ) + + map-kind: + alloc | to | from | tofrom */ + +static tree +c_parser_omp_clause_map (c_parser *parser, tree list) +{ + location_t clause_loc = c_parser_peek_token (parser)->location; + enum omp_clause_map_kind kind = OMP_CLAUSE_MAP_TOFROM; + tree nl, c; + + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return list; + + if (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_2nd_token (parser)->type == CPP_COLON) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp ("alloc", p) == 0) + kind = OMP_CLAUSE_MAP_ALLOC; + else if (strcmp ("to", p) == 0) + kind = OMP_CLAUSE_MAP_TO; + else if (strcmp ("from", p) == 0) + kind = OMP_CLAUSE_MAP_FROM; + else if (strcmp ("tofrom", p) == 0) + kind = OMP_CLAUSE_MAP_TOFROM; + else + { + c_parser_error (parser, "invalid map kind"); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + return list; + } + c_parser_consume_token (parser); + c_parser_consume_token (parser); + } + + nl = c_parser_omp_variable_list (parser, clause_loc, + OMP_CLAUSE_MAP, list); + + for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) + OMP_CLAUSE_MAP_KIND (c) = kind; + + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + return nl; +} + +/* OpenMP 4.0: + device ( expression ) */ + +static tree +c_parser_omp_clause_device (c_parser *parser, tree list) +{ + location_t clause_loc = c_parser_peek_token (parser)->location; + if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + tree c, t = c_parser_expr_no_commas (parser, NULL).value; + mark_exp_read (t); + t = c_fully_fold (t, false, NULL); + + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + + if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + c_parser_error (parser, "expected integer expression"); + return list; + } + + check_no_duplicate_clause (list, OMP_CLAUSE_DEVICE, "device"); + + c = build_omp_clause (clause_loc, OMP_CLAUSE_DEVICE); + OMP_CLAUSE_DEVICE_ID (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + list = c; + } + + return list; +} + +/* OpenMP 4.0: + dist_schedule ( static ) + dist_schedule ( static , expression ) */ + +static tree +c_parser_omp_clause_dist_schedule (c_parser *parser, tree list) +{ + tree c, t = NULL_TREE; + location_t loc = c_parser_peek_token (parser)->location; + + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return list; + + if (!c_parser_next_token_is_keyword (parser, RID_STATIC)) + { + c_parser_error (parser, "invalid dist_schedule kind"); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + return list; + } + + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_COMMA)) + { + c_parser_consume_token (parser); + + t = c_parser_expr_no_commas (parser, NULL).value; + mark_exp_read (t); + t = c_fully_fold (t, false, NULL); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + } + else + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<,%> or %<)%>"); + + check_no_duplicate_clause (list, OMP_CLAUSE_SCHEDULE, "schedule"); + if (t == error_mark_node) + return list; + + c = build_omp_clause (loc, OMP_CLAUSE_DIST_SCHEDULE); + OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + return c; +} + +/* OpenMP 4.0: + proc_bind ( proc-bind-kind ) + + proc-bind-kind: + master | close | spread */ + +static tree +c_parser_omp_clause_proc_bind (c_parser *parser, tree list) +{ + location_t clause_loc = c_parser_peek_token (parser)->location; + enum omp_clause_proc_bind_kind kind; + tree c; + + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return list; + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp ("master", p) == 0) + kind = OMP_CLAUSE_PROC_BIND_MASTER; + else if (strcmp ("close", p) == 0) + kind = OMP_CLAUSE_PROC_BIND_CLOSE; + else if (strcmp ("spread", p) == 0) + kind = OMP_CLAUSE_PROC_BIND_SPREAD; + else + goto invalid_kind; + } + else + goto invalid_kind; + + c_parser_consume_token (parser); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + c = build_omp_clause (clause_loc, OMP_CLAUSE_PROC_BIND); + OMP_CLAUSE_PROC_BIND_KIND (c) = kind; + OMP_CLAUSE_CHAIN (c) = list; + return c; + + invalid_kind: + c_parser_error (parser, "invalid proc_bind kind"); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + return list; +} + +/* OpenMP 4.0: + to ( variable-list ) */ + +static tree +c_parser_omp_clause_to (c_parser *parser, tree list) +{ + return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_TO, list); +} + +/* OpenMP 4.0: + from ( variable-list ) */ + +static tree +c_parser_omp_clause_from (c_parser *parser, tree list) +{ + return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_FROM, list); +} + +/* OpenMP 4.0: + uniform ( variable-list ) */ + +static tree +c_parser_omp_clause_uniform (c_parser *parser, tree list) +{ + return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_UNIFORM, list); +} + /* Parse all OpenMP clauses. The set clauses allowed by the directive is a bitmask in MASK. Return the list of clauses found; the result of clause default goes in *pdefault. */ @@ -9440,6 +10032,92 @@ c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask, clauses = c_parser_omp_clause_untied (parser, clauses); c_name = "untied"; break; + case PRAGMA_OMP_CLAUSE_INBRANCH: + clauses = c_parser_omp_clause_branch (parser, OMP_CLAUSE_INBRANCH, + clauses); + c_name = "inbranch"; + break; + case PRAGMA_OMP_CLAUSE_NOTINBRANCH: + clauses = c_parser_omp_clause_branch (parser, OMP_CLAUSE_NOTINBRANCH, + clauses); + c_name = "notinbranch"; + break; + case PRAGMA_OMP_CLAUSE_PARALLEL: + clauses + = c_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_PARALLEL, + clauses); + c_name = "parallel"; + break; + case PRAGMA_OMP_CLAUSE_FOR: + clauses + = c_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_FOR, + clauses); + c_name = "for"; + break; + case PRAGMA_OMP_CLAUSE_SECTIONS: + clauses + = c_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_SECTIONS, + clauses); + c_name = "sections"; + break; + case PRAGMA_OMP_CLAUSE_TASKGROUP: + clauses + = c_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_TASKGROUP, + clauses); + c_name = "taskgroup"; + break; + case PRAGMA_OMP_CLAUSE_TO: + clauses = c_parser_omp_clause_to (parser, clauses); + c_name = "to"; + break; + case PRAGMA_OMP_CLAUSE_FROM: + clauses = c_parser_omp_clause_from (parser, clauses); + c_name = "from"; + break; + case PRAGMA_OMP_CLAUSE_UNIFORM: + clauses = c_parser_omp_clause_uniform (parser, clauses); + c_name = "uniform"; + break; + case PRAGMA_OMP_CLAUSE_NUM_TEAMS: + clauses = c_parser_omp_clause_num_teams (parser, clauses); + c_name = "num_teams"; + break; + case PRAGMA_OMP_CLAUSE_ALIGNED: + clauses = c_parser_omp_clause_aligned (parser, clauses); + c_name = "aligned"; + break; + case PRAGMA_OMP_CLAUSE_LINEAR: + clauses = c_parser_omp_clause_linear (parser, clauses); + c_name = "linear"; + break; + case PRAGMA_OMP_CLAUSE_DEPEND: + clauses = c_parser_omp_clause_depend (parser, clauses); + c_name = "depend"; + break; + case PRAGMA_OMP_CLAUSE_MAP: + clauses = c_parser_omp_clause_map (parser, clauses); + c_name = "map"; + break; + case PRAGMA_OMP_CLAUSE_DEVICE: + clauses = c_parser_omp_clause_device (parser, clauses); + c_name = "device"; + break; + case PRAGMA_OMP_CLAUSE_DIST_SCHEDULE: + clauses = c_parser_omp_clause_dist_schedule (parser, clauses); + c_name = "dist_schedule"; + break; + case PRAGMA_OMP_CLAUSE_PROC_BIND: + clauses = c_parser_omp_clause_proc_bind (parser, clauses); + c_name = "proc_bind"; + break; + case PRAGMA_OMP_CLAUSE_SAFELEN: + clauses = c_parser_omp_clause_safelen (parser, clauses); + c_name = "safelen"; + break; + case PRAGMA_OMP_CLAUSE_SIMDLEN: + clauses = c_parser_omp_clause_simdlen (parser, clauses); + c_name = "simdlen"; + break; default: c_parser_error (parser, "expected %<#pragma omp%> clause"); goto saw_error; @@ -9928,8 +10606,8 @@ c_parser_omp_flush (c_parser *parser) LOC is the location of the OMP in "#pragma omp". */ static tree -c_parser_omp_for_loop (location_t loc, - c_parser *parser, tree clauses, tree *par_clauses) +c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code, + tree clauses, tree *par_clauses) { tree decl, cond, incr, save_break, save_cont, body, init, stmt, cl; tree declv, condv, incrv, initv, ret = NULL; @@ -10156,7 +10834,7 @@ c_parser_omp_for_loop (location_t loc, an error from the initialization parsing. */ if (!fail) { - stmt = c_finish_omp_for (loc, OMP_FOR, declv, initv, condv, + stmt = c_finish_omp_for (loc, code, declv, initv, condv, incrv, body, NULL); if (stmt) { @@ -10212,10 +10890,46 @@ c_parser_omp_for_loop (location_t loc, return ret; } +/* OpenMP 4.0: + #pragma omp simd simd-clause[optseq] new-line + for-loop + + LOC is the location of the #pragma token. +*/ + +#define OMP_SIMD_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SAFELEN) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINEAR) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALIGNED) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE)) + +static tree +c_parser_omp_simd (location_t loc, c_parser *parser) +{ + tree block, clauses, ret; + + clauses = c_parser_omp_all_clauses (parser, OMP_SIMD_CLAUSE_MASK, + "#pragma omp simd"); + + block = c_begin_compound_stmt (true); + ret = c_parser_omp_for_loop (loc, parser, OMP_SIMD, clauses, NULL); + block = c_end_compound_stmt (loc, block, true); + add_stmt (block); + + return ret; +} + /* OpenMP 2.5: #pragma omp for for-clause[optseq] new-line for-loop + OpenMP 4.0: + #pragma omp for simd for-simd-clause[optseq] new-line + for-loop + LOC is the location of the #pragma token. */ @@ -10233,12 +10947,27 @@ static tree c_parser_omp_for (location_t loc, c_parser *parser) { tree block, clauses, ret; + enum tree_code code = OMP_FOR; + omp_clause_mask mask = OMP_FOR_CLAUSE_MASK; + const char *p_name = "#pragma omp for"; + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + + if (strcmp (p, "simd") == 0) + { + c_parser_consume_token (parser); + code = OMP_FOR_SIMD; + mask |= OMP_SIMD_CLAUSE_MASK; + p_name = "#pragma omp for simd"; + } + } - clauses = c_parser_omp_all_clauses (parser, OMP_FOR_CLAUSE_MASK, - "#pragma omp for"); + clauses = c_parser_omp_all_clauses (parser, mask, p_name); block = c_begin_compound_stmt (true); - ret = c_parser_omp_for_loop (loc, parser, clauses, NULL); + ret = c_parser_omp_for_loop (loc, parser, code, clauses, NULL); block = c_end_compound_stmt (loc, block, true); add_stmt (block); @@ -10409,7 +11138,8 @@ c_parser_omp_sections (location_t loc, c_parser *parser) | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COPYIN) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS)) + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PROC_BIND)) static tree c_parser_omp_parallel (location_t loc, c_parser *parser) @@ -10426,6 +11156,18 @@ c_parser_omp_parallel (location_t loc, c_parser *parser) p_name = "#pragma omp parallel for"; mask |= OMP_FOR_CLAUSE_MASK; mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT); + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p + = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp (p, "simd") == 0) + { + c_parser_consume_token (parser); + p_kind = PRAGMA_OMP_PARALLEL_FOR_SIMD; + p_name = "#pragma omp parallel for simd"; + mask |= OMP_SIMD_CLAUSE_MASK; + } + } } else if (c_parser_next_token_is (parser, CPP_NAME)) { @@ -10453,7 +11195,16 @@ c_parser_omp_parallel (location_t loc, c_parser *parser) case PRAGMA_OMP_PARALLEL_FOR: block = c_begin_omp_parallel (); c_split_parallel_clauses (loc, clauses, &par_clause, &ws_clause); - c_parser_omp_for_loop (loc, parser, ws_clause, &par_clause); + c_parser_omp_for_loop (loc, parser, OMP_FOR, ws_clause, &par_clause); + stmt = c_finish_omp_parallel (loc, par_clause, block); + OMP_PARALLEL_COMBINED (stmt) = 1; + break; + + case PRAGMA_OMP_PARALLEL_FOR_SIMD: + block = c_begin_omp_parallel (); + c_split_parallel_clauses (loc, clauses, &par_clause, &ws_clause); + c_parser_omp_for_loop (loc, parser, OMP_FOR_SIMD, ws_clause, + &par_clause); stmt = c_finish_omp_parallel (loc, par_clause, block); OMP_PARALLEL_COMBINED (stmt) = 1; break; @@ -10517,7 +11268,8 @@ c_parser_omp_single (location_t loc, c_parser *parser) | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FINAL) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MERGEABLE)) + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MERGEABLE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND)) static tree c_parser_omp_task (location_t loc, c_parser *parser) @@ -10560,6 +11312,89 @@ c_parser_omp_taskyield (c_parser *parser) c_finish_omp_taskyield (loc); } +/* OpenMP 4.0: + # pragma omp taskgroup new-line +*/ + +static void +c_parser_omp_taskgroup (c_parser *parser) +{ + location_t loc = c_parser_peek_token (parser)->location; + c_parser_skip_to_pragma_eol (parser); + + tree block = c_begin_omp_taskgroup (); + c_parser_statement (parser); + c_finish_omp_taskgroup (loc, block); +} + +/* OpenMP 4.0: + # pragma omp cancel cancel-clause[optseq] new-line + + LOC is the location of the #pragma. +*/ + +#define OMP_CANCEL_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PARALLEL) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FOR) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SECTIONS) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TASKGROUP) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF)) + +static void +c_parser_omp_cancel (c_parser *parser) +{ + location_t loc = c_parser_peek_token (parser)->location; + + c_parser_consume_pragma (parser); + tree clauses = c_parser_omp_all_clauses (parser, OMP_CANCEL_CLAUSE_MASK, + "#pragma omp cancel"); + + c_finish_omp_cancel (loc, clauses); +} + +/* OpenMP 4.0: + # pragma omp cancellation point cancelpt-clause[optseq] new-line + + LOC is the location of the #pragma. +*/ + +#define OMP_CANCELLATION_POINT_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PARALLEL) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FOR) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SECTIONS) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TASKGROUP)) + +static void +c_parser_omp_cancellation_point (c_parser *parser) +{ + location_t loc = c_parser_peek_token (parser)->location; + tree clauses; + bool point_seen = false; + + c_parser_consume_pragma (parser); + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp (p, "point") == 0) + { + c_parser_consume_token (parser); + point_seen = true; + } + } + if (!point_seen) + { + c_parser_error (parser, "expected %"); + c_parser_skip_to_pragma_eol (parser); + return; + } + + clauses + = c_parser_omp_all_clauses (parser, OMP_CANCELLATION_POINT_CLAUSE_MASK, + "#pragma omp cancellation point"); + + c_finish_omp_cancellation_point (loc, clauses); +} + /* Main entry point to parsing most OpenMP pragmas. */ static void @@ -10596,12 +11431,18 @@ c_parser_omp_construct (c_parser *parser) case PRAGMA_OMP_SECTIONS: stmt = c_parser_omp_sections (loc, parser); break; + case PRAGMA_OMP_SIMD: + stmt = c_parser_omp_simd (loc, parser); + break; case PRAGMA_OMP_SINGLE: stmt = c_parser_omp_single (loc, parser); break; case PRAGMA_OMP_TASK: stmt = c_parser_omp_task (loc, parser); break; + case PRAGMA_OMP_TASKGROUP: + c_parser_omp_taskgroup (parser); + return; default: gcc_unreachable (); } @@ -10828,7 +11669,7 @@ c_parser_transaction_expression (c_parser *parser, enum rid keyword) */ static tree -c_parser_transaction_cancel(c_parser *parser) +c_parser_transaction_cancel (c_parser *parser) { location_t loc = c_parser_peek_token (parser)->location; tree attrs; diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index c4210a53f67af..7e973ea6aa83e 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -637,6 +637,10 @@ extern tree c_begin_omp_parallel (void); extern tree c_finish_omp_parallel (location_t, tree, tree); extern tree c_begin_omp_task (void); extern tree c_finish_omp_task (location_t, tree, tree); +extern tree c_begin_omp_taskgroup (void); +extern void c_finish_omp_taskgroup (location_t, tree); +extern void c_finish_omp_cancel (location_t, tree); +extern void c_finish_omp_cancellation_point (location_t, tree); extern tree c_finish_omp_clauses (tree); extern tree c_build_va_arg (location_t, tree, tree); extern tree c_finish_transaction (location_t, tree, int); diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index 789029401b3a1..addba4b16896e 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -10573,6 +10573,93 @@ c_finish_omp_task (location_t loc, tree clauses, tree block) return add_stmt (stmt); } +/* Like c_begin_compound_stmt, except force the retention of the BLOCK. */ + +tree +c_begin_omp_taskgroup (void) +{ + tree block; + + keep_next_level (); + block = c_begin_compound_stmt (true); + + return block; +} + +/* Generate code for #pragma omp taskgroup. */ + +void +c_finish_omp_taskgroup (location_t loc, tree block) +{ + tree fn = builtin_decl_explicit (BUILT_IN_GOMP_TASKGROUP_START); + tree stmt = build_call_expr_loc (loc, fn, 0); + block = c_end_compound_stmt (loc, block, true); + add_stmt (stmt); + add_stmt (block); + fn = builtin_decl_explicit (BUILT_IN_GOMP_TASKGROUP_END); + stmt = build_call_expr_loc (loc, fn, 0); + add_stmt (stmt); +} + +/* Generate GOMP_cancel call for #pragma omp cancel. */ + +void +c_finish_omp_cancel (location_t loc, tree clauses) +{ + tree fn = builtin_decl_explicit (BUILT_IN_GOMP_CANCEL); + int mask = 0; + if (find_omp_clause (clauses, OMP_CLAUSE_PARALLEL)) + mask = 1; + else if (find_omp_clause (clauses, OMP_CLAUSE_FOR)) + mask = 2; + else if (find_omp_clause (clauses, OMP_CLAUSE_SECTIONS)) + mask = 4; + else if (find_omp_clause (clauses, OMP_CLAUSE_TASKGROUP)) + mask = 8; + else + { + error_at (loc, "%<#pragma omp cancel must specify one of " + "%, %, % or % " + "clauses"); + return; + } + tree stmt = build_call_expr_loc (loc, fn, 1, + build_int_cst (integer_type_node, mask)); + tree ifc = find_omp_clause (clauses, OMP_CLAUSE_IF); + if (ifc != NULL_TREE) + stmt = build3 (COND_EXPR, void_type_node, OMP_CLAUSE_IF_EXPR (ifc), + stmt, NULL_TREE); + add_stmt (stmt); +} + +/* Generate GOMP_cancellation_point call for + #pragma omp cancellation point. */ + +void +c_finish_omp_cancellation_point (location_t loc, tree clauses) +{ + tree fn = builtin_decl_explicit (BUILT_IN_GOMP_CANCELLATION_POINT); + int mask = 0; + if (find_omp_clause (clauses, OMP_CLAUSE_PARALLEL)) + mask = 1; + else if (find_omp_clause (clauses, OMP_CLAUSE_FOR)) + mask = 2; + else if (find_omp_clause (clauses, OMP_CLAUSE_SECTIONS)) + mask = 4; + else if (find_omp_clause (clauses, OMP_CLAUSE_TASKGROUP)) + mask = 8; + else + { + error_at (loc, "%<#pragma omp cancellation point must specify one of " + "%, %, % or % " + "clauses"); + return; + } + tree stmt = build_call_expr_loc (loc, fn, 1, + build_int_cst (integer_type_node, mask)); + add_stmt (stmt); +} + /* For all elements of CLAUSES, validate them vs OpenMP constraints. Remove any elements from the list that are invalid. */ @@ -10580,6 +10667,7 @@ tree c_finish_omp_clauses (tree clauses) { bitmap_head generic_head, firstprivate_head, lastprivate_head; + bitmap_head aligned_head; tree c, t, *pc = &clauses; const char *name; @@ -10587,6 +10675,7 @@ c_finish_omp_clauses (tree clauses) bitmap_initialize (&generic_head, &bitmap_default_obstack); bitmap_initialize (&firstprivate_head, &bitmap_default_obstack); bitmap_initialize (&lastprivate_head, &bitmap_default_obstack); + bitmap_initialize (&aligned_head, &bitmap_default_obstack); for (pc = &clauses, c = clauses; c ; c = *pc) { @@ -10674,6 +10763,19 @@ c_finish_omp_clauses (tree clauses) } goto check_dup_generic; + case OMP_CLAUSE_LINEAR: + name = "linear"; + t = OMP_CLAUSE_DECL (c); + if (!INTEGRAL_TYPE_P (TREE_TYPE (t)) + && TREE_CODE (TREE_TYPE (t)) != POINTER_TYPE) + { + error_at (OMP_CLAUSE_LOCATION (c), + "linear clause applied to non-integral non-pointer"); + remove = true; + break; + } + goto check_dup_generic; + check_dup_generic: t = OMP_CLAUSE_DECL (c); if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) @@ -10738,6 +10840,71 @@ c_finish_omp_clauses (tree clauses) bitmap_set_bit (&lastprivate_head, DECL_UID (t)); break; + case OMP_CLAUSE_ALIGNED: + t = OMP_CLAUSE_DECL (c); + if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is not a variable in % clause", t); + remove = true; + } + else if (bitmap_bit_p (&aligned_head, DECL_UID (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE appears more than once in % clauses", + t); + remove = true; + } + else + bitmap_set_bit (&aligned_head, DECL_UID (t)); + break; + + case OMP_CLAUSE_DEPEND: + t = OMP_CLAUSE_DECL (c); + /* FIXME: depend clause argument may be also array section. */ + if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is not a variable in % clause", t); + remove = true; + } + break; + + case OMP_CLAUSE_MAP: + case OMP_CLAUSE_TO: + case OMP_CLAUSE_FROM: + t = OMP_CLAUSE_DECL (c); + /* FIXME: map clause argument may be also array section. */ + if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is not a variable in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + else if (TREE_CODE (t) == VAR_DECL && DECL_THREAD_LOCAL_P (t)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qD is threadprivate variable in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + break; + + case OMP_CLAUSE_UNIFORM: + t = OMP_CLAUSE_DECL (c); + if (TREE_CODE (t) != PARM_DECL) + { + if (DECL_P (t)) + error_at (OMP_CLAUSE_LOCATION (c), + "%qD is not an argument in % clause", t); + else + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is not an argument in % clause", t); + remove = true; + } + break; + case OMP_CLAUSE_IF: case OMP_CLAUSE_NUM_THREADS: case OMP_CLAUSE_SCHEDULE: @@ -10748,6 +10915,17 @@ c_finish_omp_clauses (tree clauses) case OMP_CLAUSE_COLLAPSE: case OMP_CLAUSE_FINAL: case OMP_CLAUSE_MERGEABLE: + case OMP_CLAUSE_SAFELEN: + case OMP_CLAUSE_SIMDLEN: + case OMP_CLAUSE_DEVICE: + case OMP_CLAUSE_DIST_SCHEDULE: + case OMP_CLAUSE_INBRANCH: + case OMP_CLAUSE_NOTINBRANCH: + case OMP_CLAUSE_PARALLEL: + case OMP_CLAUSE_FOR: + case OMP_CLAUSE_SECTIONS: + case OMP_CLAUSE_TASKGROUP: + case OMP_CLAUSE_PROC_BIND: pc = &OMP_CLAUSE_CHAIN (c); continue; diff --git a/gcc/cp/ChangeLog.gomp b/gcc/cp/ChangeLog.gomp index ffc3f03c3a702..ac49b6e603bdb 100644 --- a/gcc/cp/ChangeLog.gomp +++ b/gcc/cp/ChangeLog.gomp @@ -1,3 +1,13 @@ +2013-04-24 Jakub Jelinek + + * parser.c (cp_parser_omp_clause_name): Add missing break after + case 'i'. + (cp_parser_omp_cancellation_point): Diagnose error if + #pragma omp cancellation isn't followed by point. + * semantics.c (finish_omp_clauses): Complain also about zero + in alignment of aligned directive or safelen/simdlen expressions. + (finish_omp_cancel): Fix up diagnostics wording. + 2013-04-23 Jakub Jelinek * semantics.c (finish_omp_clauses): On OMP_CLAUSE_LINEAR clauses diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index b58da187877b6..bcee34589bc80 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -25767,6 +25767,7 @@ cp_parser_omp_clause_name (cp_parser *parser) case 'i': if (!strcmp ("inbranch", p)) result = PRAGMA_OMP_CLAUSE_INBRANCH; + break; case 'l': if (!strcmp ("lastprivate", p)) result = PRAGMA_OMP_CLAUSE_LASTPRIVATE; @@ -26644,7 +26645,7 @@ cp_parser_omp_clause_depend (cp_parser *parser, tree list) /* OpenMP 4.0: map ( map-kind : variable-list ) - map ( variable-list) + map ( variable-list ) map-kind: alloc | to | from | tofrom */ @@ -28553,6 +28554,7 @@ cp_parser_omp_cancellation_point (cp_parser *parser, cp_token *pragma_tok) } if (!point_seen) { + cp_parser_error (parser, "expected %"); cp_parser_require_pragma_eol (parser, pragma_tok); return; } diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index ff8ac7b5f092d..96e6c538d1175 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -4245,7 +4245,7 @@ finish_omp_clauses (tree clauses) if (!processing_template_decl) { if (TREE_CODE (t) != INTEGER_CST - || tree_int_cst_sgn (t) == -1) + || tree_int_cst_sgn (t) != 1) { error ("%qs length expression must be positive constant" " integer expression", @@ -4355,7 +4355,7 @@ finish_omp_clauses (tree clauses) if (!processing_template_decl) { if (TREE_CODE (t) != INTEGER_CST - || tree_int_cst_sgn (t) == -1) + || tree_int_cst_sgn (t) != 1) { error ("% clause alignment expression must be " "positive constant integer expression"); @@ -5394,7 +5394,7 @@ finish_omp_cancel (tree clauses) mask = 8; else { - error ("%<#pragma omp cancellation point must specify one of " + error ("%<#pragma omp cancel must specify one of " "%, %, % or % clauses"); return; } diff --git a/gcc/testsuite/ChangeLog.gomp b/gcc/testsuite/ChangeLog.gomp index 1c4e357481513..5b1bb9e4eae0d 100644 --- a/gcc/testsuite/ChangeLog.gomp +++ b/gcc/testsuite/ChangeLog.gomp @@ -1,3 +1,12 @@ +2013-04-24 Jakub Jelinek + + * c-c++-common/gomp/simd1.c: Enable also for C. + * c-c++-common/gomp/simd2.c: Likewise. + * c-c++-common/gomp/simd3.c: Likewise. + * c-c++-common/gomp/simd4.c: Likewise. Adjust expected + diagnostics for C. + * c-c++-common/gomp/simd5.c: Enable also for C. + 2013-04-23 Jakub Jelinek * c-c++-common/gomp/simd3.c: New test. diff --git a/gcc/testsuite/c-c++-common/gomp/simd1.c b/gcc/testsuite/c-c++-common/gomp/simd1.c index ec0101a1e52c5..29e464ca035bd 100644 --- a/gcc/testsuite/c-c++-common/gomp/simd1.c +++ b/gcc/testsuite/c-c++-common/gomp/simd1.c @@ -1,4 +1,4 @@ -/* { dg-do compile { target { ! c } } } */ +/* { dg-do compile } */ /* { dg-options "-fopenmp" } */ /* { dg-additional-options "-std=c99" { target c } } */ diff --git a/gcc/testsuite/c-c++-common/gomp/simd2.c b/gcc/testsuite/c-c++-common/gomp/simd2.c index ad44f8e26c7cc..dda9c62d6d131 100644 --- a/gcc/testsuite/c-c++-common/gomp/simd2.c +++ b/gcc/testsuite/c-c++-common/gomp/simd2.c @@ -1,4 +1,4 @@ -/* { dg-do compile { target { ! c } } } */ +/* { dg-do compile } */ /* { dg-options "-fopenmp" } */ /* { dg-additional-options "-std=c99" { target c } } */ diff --git a/gcc/testsuite/c-c++-common/gomp/simd3.c b/gcc/testsuite/c-c++-common/gomp/simd3.c index d505b2ee4ab73..e8270fc452131 100644 --- a/gcc/testsuite/c-c++-common/gomp/simd3.c +++ b/gcc/testsuite/c-c++-common/gomp/simd3.c @@ -1,4 +1,4 @@ -/* { dg-do compile { target { ! c } } } */ +/* { dg-do compile } */ /* { dg-options "-fopenmp" } */ /* { dg-additional-options "-std=c99" { target c } } */ diff --git a/gcc/testsuite/c-c++-common/gomp/simd4.c b/gcc/testsuite/c-c++-common/gomp/simd4.c index 8d7187506d75e..37901b6a07f24 100644 --- a/gcc/testsuite/c-c++-common/gomp/simd4.c +++ b/gcc/testsuite/c-c++-common/gomp/simd4.c @@ -1,8 +1,8 @@ -/* { dg-do compile { target { ! c } } } */ +/* { dg-do compile } */ /* { dg-options "-fopenmp" } */ /* { dg-additional-options "-std=c99" { target c } } */ -struct S *p; /* { dg-error "forward declaration" } */ +struct S *p; /* { dg-error "forward declaration" "" { target c++ } } */ float f; int j; @@ -12,10 +12,10 @@ foo (void) #pragma omp simd linear(p) linear(f : 1) for (int i = 0; i < 10; i++) ; -#pragma omp simd linear(j : 7.0) /* { dg-error "linear step expression must be integral" } */ +#pragma omp simd linear(j : 7.0) /* { dg-error "step expression must be integral" } */ for (int i = 0; i < 10; i++) ; } /* { dg-error "linear clause applied to" "" { target *-*-* } 12 } */ -/* { dg-error "incomplete type" "" { target *-*-* } 12 } */ +/* { dg-error "(incomplete|undefined) type" "" { target *-*-* } 12 } */ diff --git a/gcc/testsuite/c-c++-common/gomp/simd5.c b/gcc/testsuite/c-c++-common/gomp/simd5.c index 85a28fcc21724..a57896d870469 100644 --- a/gcc/testsuite/c-c++-common/gomp/simd5.c +++ b/gcc/testsuite/c-c++-common/gomp/simd5.c @@ -1,4 +1,4 @@ -/* { dg-do compile { target { ! c } } } */ +/* { dg-do compile } */ /* { dg-options "-fopenmp" } */ /* { dg-additional-options "-std=c99" { target c } } */ From f80ffc7b2fae735613819d0781401475a83af9dc Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Wed, 24 Apr 2013 17:03:08 -0500 Subject: [PATCH 14/63] Verify the integrity of the _Cilk_for body. --- gcc/c-family/c-cilkplus.c | 103 ++++++++++++++++++ gcc/c/c-parser.c | 21 ++-- gcc/c/c-typeck.c | 7 ++ .../gcc.dg/cilk-plus/cilk-simd/compile/body.c | 27 +++++ 4 files changed, 148 insertions(+), 10 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/body.c diff --git a/gcc/c-family/c-cilkplus.c b/gcc/c-family/c-cilkplus.c index d5f069fcae5a0..bdc73bc3f6ce0 100644 --- a/gcc/c-family/c-cilkplus.c +++ b/gcc/c-family/c-cilkplus.c @@ -104,6 +104,106 @@ c_check_cilk_loop_incr (location_t loc, tree decl, tree incr) return error_mark_node; } +/* Callback for walk_tree. + + This function is passed in as a function pointer to walk_tree. *TP is + the current tree pointer, *WALK_SUBTREES is set to 0 by this function if + recursing into TP's subtrees is unnecessary. *DATA is a bool variable that + is set to false if an error has occured. */ + +static tree +find_invalid_stmts_in_loops (tree *tp, int *walk_subtrees, void *data) +{ + if (!tp || !*tp) + return NULL_TREE; + + bool *valid = (bool *) data; + + // FIXME: Disallow the following constructs within a SIMD loop: + // + // _Cilk_spawn + // _Cilk_for + // try + + /* FIXME: Jumps are disallowed into or out of the body of a + _Cilk_for. We can't just check for GOTO_EXPR here, since + GOTO_EXPR's can also be generated by switches and loops. + + We should check for this case after we have built the CFG, + possibly at OMP expansion (ompexp). However, since by then we + have expanded the _Cilk_for into an OMP_FOR, we should probably + set a tree bit in OMP_FOR differentiating it from the Cilk SIMD + construct and handle it appropriately. */ + + switch (TREE_CODE (*tp)) + { + case RETURN_EXPR: + error_at (EXPR_LOCATION (*tp), "return statments are not allowed " + "within loops annotated with #pragma simd"); + *valid = false; + *walk_subtrees = 0; + break; + case CALL_EXPR: + { + tree fndecl = CALL_EXPR_FN (*tp); + + if (TREE_CODE (fndecl) == ADDR_EXPR) + fndecl = TREE_OPERAND (fndecl, 0); + if (TREE_CODE (fndecl) == FUNCTION_DECL) + { + if (setjmp_call_p (fndecl)) + { + error_at (EXPR_LOCATION (*tp), + "calls to setjmp are not allowed within loops " + "annotated with #pragma simd"); + *valid = false; + *walk_subtrees = 0; + } + } + break; + } + + case OMP_PARALLEL: + case OMP_TASK: + case OMP_FOR: + case OMP_SIMD: + case OMP_FOR_SIMD: + case OMP_DISTRIBUTE: + case OMP_SECTIONS: + case OMP_SINGLE: + case OMP_SECTION: + case OMP_MASTER: + case OMP_ORDERED: + case OMP_CRITICAL: + case OMP_ATOMIC: + case OMP_ATOMIC_READ: + case OMP_ATOMIC_CAPTURE_OLD: + case OMP_ATOMIC_CAPTURE_NEW: + error_at (EXPR_LOCATION (*tp), "OpenMP statments are not allowed " + "within loops annotated with #pragma simd"); + *valid = false; + *walk_subtrees = 0; + break; + + default: + break; + } + return NULL_TREE; +} + +/* Validate the body of a _Cilk_for construct or a <#pragma simd> for + loop. + + Returns true if there were no errors, false otherwise. */ + +static bool +c_check_cilk_loop_body (tree body) +{ + bool valid = true; + walk_tree (&body, find_invalid_stmts_in_loops, (void *) &valid, NULL); + return valid; +} + /* Validate a _Cilk_for construct (or a #pragma simd for loop, which has the same syntactic restrictions). Returns TRUE if there were no errors, FALSE otherwise. LOC is the location of the for. DECL @@ -189,6 +289,9 @@ c_check_cilk_loop (location_t loc, tree decl, tree cond, tree incr, tree body) if (incr == error_mark_node) return false; + if (!c_check_cilk_loop_body (body)) + return false; + return true; } diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index 41d44a4713980..aeaabbfdb6973 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -10736,7 +10736,7 @@ c_parser_cilk_clause_noassert (c_parser *parser ATTRIBUTE_UNUSED, } /* Cilk Plus: - vectorlength (constant-expression-list ) + vectorlength ( constant-expression-list ) constant-expression-list: constant-expression @@ -10781,6 +10781,16 @@ c_parser_cilk_clause_vectorlength (c_parser *parser, tree clauses) return clauses; } +/* Cilk Plus: + vectorlengthfor ( type-name ) */ +/* +static tree +c_parser_cilk_clause_vectorlengthfor (c_parser *parser, tree clauses) +{ + // FIXME: Implement +} +*/ + /* Cilk Plus: linear ( simd-linear-variable-list ) @@ -11085,15 +11095,6 @@ c_parser_cilk_for_statement (c_parser *parser, enum rid for_keyword, c_break_label = save_break; c_cont_label = save_cont; - // FIXME: Disallow the following constructs within a SIMD loop: - // - // RETURN - // GOTO - // _Cilk_spawn - // _Cilk_for - // OpenMP directive or construct - // Calls to setjmp() - if (!fail) { /* diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index 789029401b3a1..8c75bbe25aa12 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -9093,6 +9093,13 @@ c_finish_bc_stmt (location_t loc, tree *label_p, bool is_break) error_at (loc, "break statement used with OpenMP for loop"); return NULL_TREE; + case 2: + if (is_break) + error ("break statement within _Cilk_for loop"); + else + error ("continue statement within _Cilk_for loop"); + return NULL_TREE; + default: gcc_unreachable (); } diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/body.c b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/body.c new file mode 100644 index 0000000000000..7e32f18d314ef --- /dev/null +++ b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/body.c @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fcilkplus" } */ + +int *a, *b, c; +void *jmpbuf[10]; + +void foo() +{ + int i, j; + +#pragma simd + for (i=0; i < 1000; ++i) + { + if (c == 5) + return; /* { dg-error "return statments are not allowed" } */ + if (c == 6) + __builtin_setjmp (jmpbuf); /* { dg-error "calls to setjmp are not allowed" } */ + a[i] = b[i]; + } + +#pragma simd + for (i=0; i < 1000; ++i) + { + if (c==5) + break; /* { dg-error "break statement within" } */ + } +} From 061de24d320fbfdd7eb40fa920fb415a7b17c481 Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Wed, 24 Apr 2013 18:03:55 -0500 Subject: [PATCH 15/63] Fix typo in last commit. --- gcc/c-family/c-cilkplus.c | 2 +- .../gcc.dg/cilk-plus/cilk-simd/compile/body.c | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/gcc/c-family/c-cilkplus.c b/gcc/c-family/c-cilkplus.c index bdc73bc3f6ce0..06cb2719f74de 100644 --- a/gcc/c-family/c-cilkplus.c +++ b/gcc/c-family/c-cilkplus.c @@ -179,7 +179,7 @@ find_invalid_stmts_in_loops (tree *tp, int *walk_subtrees, void *data) case OMP_ATOMIC_READ: case OMP_ATOMIC_CAPTURE_OLD: case OMP_ATOMIC_CAPTURE_NEW: - error_at (EXPR_LOCATION (*tp), "OpenMP statments are not allowed " + error_at (EXPR_LOCATION (*tp), "OpenMP statements are not allowed " "within loops annotated with #pragma simd"); *valid = false; *walk_subtrees = 0; diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/body.c b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/body.c index 7e32f18d314ef..50b3ab1446b88 100644 --- a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/body.c +++ b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/body.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O3 -fcilkplus" } */ +/* { dg-options "-O3 -fcilkplus -fopenmp" } */ int *a, *b, c; void *jmpbuf[10]; @@ -24,4 +24,12 @@ void foo() if (c==5) break; /* { dg-error "break statement within" } */ } + +#pragma simd + for (i=0; i < 1000; ++i) + { +#pragma omp for /* { dg-error "OpenMP statements are not allowed" } */ + for (j=0; j < 1000; ++j) + a[i] = b[i]; + } } From 1176fa6f0c7a7b5bf1f840341a22d15e405e4047 Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Wed, 24 Apr 2013 19:12:02 -0500 Subject: [PATCH 16/63] Disallow a condition of != in _Cilk_for. --- gcc/c-family/c-cilkplus.c | 8 ++++++-- .../gcc.dg/cilk-plus/cilk-simd/compile/for1.c | 12 ++++++++---- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/gcc/c-family/c-cilkplus.c b/gcc/c-family/c-cilkplus.c index 06cb2719f74de..d18cdc9b71d51 100644 --- a/gcc/c-family/c-cilkplus.c +++ b/gcc/c-family/c-cilkplus.c @@ -163,6 +163,11 @@ find_invalid_stmts_in_loops (tree *tp, int *walk_subtrees, void *data) break; } + /* FIXME: Perhaps we could do without these OMP tests and defer + to the OMP type checking, since OMP_SIMD cannot have OpenMP + constructs either. From OpenMP 4.0rc2: "No OpenMP construct + can appear in the simd region". Similarly for the call to + setjmp above. */ case OMP_PARALLEL: case OMP_TASK: case OMP_FOR: @@ -256,8 +261,7 @@ c_check_cilk_loop (location_t loc, tree decl, tree cond, tree incr, tree body) return false; } bool cond_ok = false; - if (TREE_CODE (cond) == NE_EXPR - || TREE_CODE (cond) == LT_EXPR + if (TREE_CODE (cond) == LT_EXPR || TREE_CODE (cond) == LE_EXPR || TREE_CODE (cond) == GT_EXPR || TREE_CODE (cond) == GE_EXPR) diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for1.c b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for1.c index 38700e43454fd..044f1c98ff45b 100644 --- a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for1.c +++ b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for1.c @@ -78,11 +78,15 @@ void foo() for (i=0; (char)i < 1234; ++i) /* { dg-error "invalid controlling predicate" } */ a[i] = b[i]; - // ?? This condition gets folded into "i != 0" by - // c_parser_cilk_for_statement(). Does this count as a "!=", or is - // this disallowed? Assume it is allowed. + // icc disallows !=, we'll do the same. #pragma simd - for (i=100; i; --i) + for (i=255; i != 5; --i) /* { dg-error "invalid controlling predicate" } */ + a[i] = b[i]; + + // This condition gets folded into "i != 0" by + // c_parser_cilk_for_statement(). Disallow != like above. +#pragma simd + for (i=100; i; --i) /* { dg-error "invalid controlling predicate" } */ a[i] = b[i]; // Increment must be on the induction variable. From c311b69aeec434722dd84e2c6eb5a3390347de53 Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Fri, 26 Apr 2013 07:54:35 -0500 Subject: [PATCH 17/63] Generate an OMP safelen clause when a Cilk Plus vectorlength clause is present. --- gcc/c-family/c-cilkplus.c | 50 +++++++++++++++++-- .../cilk-plus/cilk-simd/compile/safelen.c | 15 ++++++ 2 files changed, 61 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/safelen.c diff --git a/gcc/c-family/c-cilkplus.c b/gcc/c-family/c-cilkplus.c index d18cdc9b71d51..ca3fb32fea66b 100644 --- a/gcc/c-family/c-cilkplus.c +++ b/gcc/c-family/c-cilkplus.c @@ -297,7 +297,43 @@ c_check_cilk_loop (location_t loc, tree decl, tree cond, tree incr, tree body) return false; return true; - } +} + +/* Adjust any clauses to match the requirements for OpenMP. */ + +static tree +adjust_clauses_for_omp (tree clauses) +{ + unsigned int max_vlen = 0; + tree c, max_vlen_tree = NULL; + + for (c = clauses; c; c = OMP_CLAUSE_CHAIN (c)) + { + /* #pragma simd vectorlength (a, b, c) + is equivalent to: + #pragma omp simd safelen (max (a, b, c)). */ + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_CILK_VECTORLENGTH) + { + unsigned int vlen; + + vlen = TREE_INT_CST_LOW (OMP_CLAUSE_CILK_VECTORLENGTH_EXPR (c)); + if (vlen > max_vlen) + { + max_vlen = vlen; + max_vlen_tree = OMP_CLAUSE_CILK_VECTORLENGTH_EXPR (c); + } + } + } + if (max_vlen) + { + c = build_omp_clause (EXPR_LOCATION (max_vlen_tree), + OMP_CLAUSE_SAFELEN); + OMP_CLAUSE_SAFELEN_EXPR (c) = max_vlen_tree; + OMP_CLAUSE_CHAIN (c) = clauses; + clauses = c; + } + return clauses; +} /* Validate and emit code for the FOR loop following a # construct. @@ -351,8 +387,6 @@ c_finish_cilk_simd_loop (location_t loc, TREE_VEC_ELT (condv, 0) = cond; TREE_VEC_ELT (incrv, 0) = incr; - // FIXME: What should we do about nested loops? Look at specs. - /* The OpenMP <#pragma omp simd> construct is exactly the same as the Cilk Plus one, with the exception of the vectorlength() clause in Cilk Plus. Emitting an OMP_SIMD simlifies @@ -360,11 +394,19 @@ c_finish_cilk_simd_loop (location_t loc, tree t = make_node (OMP_SIMD); TREE_TYPE (t) = void_type_node; OMP_FOR_INIT (t) = initv; + + /* FIXME: The spec says "The increment and limit expressions may be + evaluated fewer times than in the serialization. If different + evaluations of the same expression yield different values, the + behavior of the program is undefined." This means that the RHS + of the condition and increment could be wrapped in a + SAVE_EXPR. */ OMP_FOR_COND (t) = condv; OMP_FOR_INCR (t) = incrv; + OMP_FOR_BODY (t) = body; OMP_FOR_PRE_BODY (t) = NULL; - OMP_FOR_CLAUSES (t) = clauses; + OMP_FOR_CLAUSES (t) = adjust_clauses_for_omp (clauses); SET_EXPR_LOCATION (t, loc); return add_stmt (t); diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/safelen.c b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/safelen.c new file mode 100644 index 0000000000000..33a43138dd6ec --- /dev/null +++ b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/safelen.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fcilkplus -fdump-tree-gimple" } */ + +int *a, *b; + +void foo() +{ + int i; +#pragma simd vectorlength(4, 8) + for (i=0; i < 1000; ++i) + a[i] = b[i]; +} + +/* { dg-final { scan-tree-dump-times "safelen\\(8\\)" 1 "gimple" } } */ +/* { dg-final { cleanup-tree-dump "gimple" } } */ From d56c70f7a1a99b8e5741999662f894e1c927ddab Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Fri, 26 Apr 2013 11:05:31 -0500 Subject: [PATCH 18/63] Implement the parsing bits for the vectorlengthfor clause. --- gcc/c-family/c-cilkplus.c | 19 +++++++ gcc/c-family/c-pragma.h | 1 + gcc/c/c-parser.c | 51 ++++++++++++++++-- gcc/gimplify.c | 2 + gcc/omp-low.c | 2 + .../cilk-simd/compile/vectorlength.c | 54 +++++++++++++++++++ gcc/tree-pretty-print.c | 8 +++ gcc/tree.c | 3 ++ gcc/tree.h | 11 +++- 9 files changed, 145 insertions(+), 6 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/vectorlength.c diff --git a/gcc/c-family/c-cilkplus.c b/gcc/c-family/c-cilkplus.c index ca3fb32fea66b..a1dca9554811c 100644 --- a/gcc/c-family/c-cilkplus.c +++ b/gcc/c-family/c-cilkplus.c @@ -323,6 +323,25 @@ adjust_clauses_for_omp (tree clauses) max_vlen_tree = OMP_CLAUSE_CILK_VECTORLENGTH_EXPR (c); } } + else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_CILK_VECTORLENGTHFOR) + { + tree type = OMP_CLAUSE_CILK_VECTORLENGTHFOR_TYPE (c); + + /* FIXME: An appropriate safelen clause must be added like + we do above for vectorlength, but don't yet know the + target vector size so we can't calculate + size_of_vector_register / sizeof(data_type). */ + + if ((TREE_CODE (type) != INTEGER_TYPE + && TREE_CODE (type) != REAL_TYPE + && TREE_CODE (type) != COMPLEX_TYPE + && TREE_CODE (type) != POINTER_TYPE) + || (TREE_CODE (type) == COMPLEX_TYPE + && (TREE_CODE (TREE_TYPE (type)) != INTEGER_TYPE + && TREE_CODE (TREE_TYPE (type)) != REAL_TYPE))) + error_at (OMP_CLAUSE_LOCATION (c), + "type must be integer, real, or complex"); + } } if (max_vlen) { diff --git a/gcc/c-family/c-pragma.h b/gcc/c-family/c-pragma.h index 2ff5a00ae8b22..6b0b2c75b73c7 100644 --- a/gcc/c-family/c-pragma.h +++ b/gcc/c-family/c-pragma.h @@ -118,6 +118,7 @@ typedef enum pragma_cilk_clause { PRAGMA_CILK_CLAUSE_NOASSERT, PRAGMA_CILK_CLAUSE_ASSERT, PRAGMA_CILK_CLAUSE_VECTORLENGTH, + PRAGMA_CILK_CLAUSE_VECTORLENGTHFOR, PRAGMA_CILK_CLAUSE_LINEAR, PRAGMA_CILK_CLAUSE_PRIVATE, PRAGMA_CILK_CLAUSE_FIRSTPRIVATE, diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index aeaabbfdb6973..949e2ef1344c3 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -10745,8 +10745,12 @@ c_parser_cilk_clause_noassert (c_parser *parser ATTRIBUTE_UNUSED, static tree c_parser_cilk_clause_vectorlength (c_parser *parser, tree clauses) { - check_no_duplicate_clause (clauses, OMP_CLAUSE_CILK_VECTORLENGTH, - "vectorlength"); + /* The icc manual says vectorlength and vectorlengthfor clauses + cannot coexist, but multiple vectorlength clauses are treated as + a union. The 1.1 spec says nothing. We will assume the icc + manual is correct. */ + check_no_duplicate_clause (clauses, OMP_CLAUSE_CILK_VECTORLENGTHFOR, + "vectorlengthfor"); if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) return clauses; @@ -10761,6 +10765,8 @@ c_parser_cilk_clause_vectorlength (c_parser *parser, tree clauses) || !TREE_CONSTANT (expr) || !INTEGRAL_TYPE_P (TREE_TYPE (expr))) error_at (loc, "vectorlength must be an integer constant"); + else if (exact_log2 (TREE_INT_CST_LOW (expr)) == -1) + error_at (loc, "vectorlength must be a power of 2"); else { tree u = build_omp_clause (loc, OMP_CLAUSE_CILK_VECTORLENGTH); @@ -10783,13 +10789,43 @@ c_parser_cilk_clause_vectorlength (c_parser *parser, tree clauses) /* Cilk Plus: vectorlengthfor ( type-name ) */ -/* static tree c_parser_cilk_clause_vectorlengthfor (c_parser *parser, tree clauses) { - // FIXME: Implement + /* The icc manual says vectorlength and vectorlengthfor clauses + cannot coexist, but multiple vectorlength clauses are treated as + a union. The 1.1 spec says nothing. We will assume the icc + manual is correct. */ + check_no_duplicate_clause (clauses, OMP_CLAUSE_CILK_VECTORLENGTH, + "vectorlength"); + + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return clauses; + + location_t loc = c_parser_peek_token (parser)->location; + tree type = NULL; + struct c_type_name *type_name = c_parser_type_name (parser); + + /* FIXME: The specs are not clear whether typedef substitutions are + allowed. Assume they are. I have asked on the forum... */ + + if (type_name) + type = groktypename (type_name, NULL, NULL); + if (type == error_mark_node) + type = NULL; + + if (type != NULL) + { + tree u = build_omp_clause (loc, OMP_CLAUSE_CILK_VECTORLENGTHFOR); + OMP_CLAUSE_CILK_VECTORLENGTHFOR_TYPE (u) = type; + OMP_CLAUSE_CHAIN (u) = clauses; + clauses = u; + } + + c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + + return clauses; } -*/ /* Cilk Plus: linear ( simd-linear-variable-list ) @@ -10895,6 +10931,8 @@ c_parser_cilk_clause_name (c_parser *parser) result = PRAGMA_CILK_CLAUSE_ASSERT; else if (!strcmp (p, "vectorlength")) result = PRAGMA_CILK_CLAUSE_VECTORLENGTH; + else if (!strcmp (p, "vectorlengthfor")) + result = PRAGMA_CILK_CLAUSE_VECTORLENGTHFOR; else if (!strcmp (p, "linear")) result = PRAGMA_CILK_CLAUSE_LINEAR; else if (!strcmp (p, "private")) @@ -10937,6 +10975,9 @@ c_parser_cilk_all_clauses (c_parser *parser) case PRAGMA_CILK_CLAUSE_VECTORLENGTH: clauses = c_parser_cilk_clause_vectorlength (parser, clauses); break; + case PRAGMA_CILK_CLAUSE_VECTORLENGTHFOR: + clauses = c_parser_cilk_clause_vectorlengthfor (parser, clauses); + break; case PRAGMA_CILK_CLAUSE_LINEAR: clauses = c_parser_cilk_clause_linear (parser, clauses); break; diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 6dd6461afe97b..b1145fc7c4de2 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -6339,6 +6339,7 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, case OMP_CLAUSE_SAFELEN: case OMP_CLAUSE_CILK_ASSERT: case OMP_CLAUSE_CILK_VECTORLENGTH: + case OMP_CLAUSE_CILK_VECTORLENGTHFOR: break; case OMP_CLAUSE_ALIGNED: @@ -6569,6 +6570,7 @@ gimplify_adjust_omp_clauses (tree *list_p) case OMP_CLAUSE_SAFELEN: case OMP_CLAUSE_CILK_ASSERT: case OMP_CLAUSE_CILK_VECTORLENGTH: + case OMP_CLAUSE_CILK_VECTORLENGTHFOR: break; default: diff --git a/gcc/omp-low.c b/gcc/omp-low.c index 0a0d2394e567d..64bfbf073668c 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -1493,6 +1493,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) case OMP_CLAUSE_SAFELEN: case OMP_CLAUSE_CILK_ASSERT: case OMP_CLAUSE_CILK_VECTORLENGTH: + case OMP_CLAUSE_CILK_VECTORLENGTHFOR: break; case OMP_CLAUSE_ALIGNED: @@ -1558,6 +1559,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) case OMP_CLAUSE_ALIGNED: case OMP_CLAUSE_CILK_ASSERT: case OMP_CLAUSE_CILK_VECTORLENGTH: + case OMP_CLAUSE_CILK_VECTORLENGTHFOR: break; default: diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/vectorlength.c b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/vectorlength.c new file mode 100644 index 0000000000000..11c933cf4e7ce --- /dev/null +++ b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/vectorlength.c @@ -0,0 +1,54 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fcilkplus" } */ + +volatile int *a, *b, N; +typedef int tint; +struct someclass { + int a; + char b; + int *p; +}; + +void foo() +{ + int i; +#pragma simd vectorlength(4) vectorlength(8) + for (i=0; i < N; ++i) + a[i] = b[i]; + +#pragma simd vectorlength(3) /* { dg-error "must be a power of 2" } */ + for (i=0; i < N; ++i) + a[i] = b[i]; + +#pragma simd vectorlength(4) vectorlengthfor(int) /* { dg-error "too many 'vectorlength'" } */ + for (i=0; i < N; ++i) + a[i] = b[i]; + +#pragma simd vectorlengthfor(int) vectorlengthfor(short int) + for (i=0; i < N; ++i) + a[i] = b[i]; + +#pragma simd vectorlengthfor(tint) + for (i=0; i < N; ++i) + a[i] = b[i]; + +#pragma simd vectorlengthfor(float) + for (i=0; i < N; ++i) + a[i] = b[i]; + +#pragma simd vectorlengthfor(_Complex double) + for (i=0; i < N; ++i) + a[i] = b[i]; + +#pragma simd vectorlengthfor(unsigned char) + for (i=0; i < N; ++i) + a[i] = b[i]; + +#pragma simd vectorlengthfor(struct someclass) /* { dg-error "type must be" } */ + for (i=0; i < N; ++i) + a[i] = b[i]; + +#pragma simd vectorlengthfor(struct someclass *) + for (i=0; i < N; ++i) + a[i] = b[i]; +} diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c index 8d1f06e92d544..1746926abdf76 100644 --- a/gcc/tree-pretty-print.c +++ b/gcc/tree-pretty-print.c @@ -597,6 +597,14 @@ dump_omp_clause (pretty_printer *buffer, tree clause, int spc, int flags) pp_character (buffer, ')'); break; + case OMP_CLAUSE_CILK_VECTORLENGTHFOR: + pp_string (buffer, "cilk_vectorlengthfor("); + dump_generic_node (buffer, + OMP_CLAUSE_CILK_VECTORLENGTHFOR_TYPE (clause), + spc, flags, false); + pp_character (buffer, ')'); + break; + default: /* Should never happen. */ dump_generic_node (buffer, clause, spc, flags, false); diff --git a/gcc/tree.c b/gcc/tree.c index 2bc61311d7565..42bb8c56dba45 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -266,6 +266,7 @@ unsigned const char omp_clause_num_ops[] = 0 /* OMP_CLAUSE_TASKGROUP */ , 0, /* OMP_CLAUSE_CILK_ASSERT */ 1, /* OMP_CLAUSE_CILK_VECTORLENGTH */ + 1, /* OMP_CLAUSE_CILK_VECTORLENGTHFOR */ }; const char * const omp_clause_code_name[] = @@ -309,6 +310,7 @@ const char * const omp_clause_code_name[] = "taskgroup" , "cilk_assert", "cilk_vectorlength", + "cilk_vectorlengthfor" }; @@ -10814,6 +10816,7 @@ walk_tree_1 (tree *tp, walk_tree_fn func, void *data, case OMP_CLAUSE_SAFELEN: case OMP_CLAUSE_SIMDLEN: case OMP_CLAUSE_CILK_VECTORLENGTH: + case OMP_CLAUSE_CILK_VECTORLENGTHFOR: WALK_SUBTREE (OMP_CLAUSE_OPERAND (*tp, 0)); /* FALLTHRU */ diff --git a/gcc/tree.h b/gcc/tree.h index 75fbebf5d48f2..a8004343e5547 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -452,7 +452,10 @@ enum omp_clause_code OMP_CLAUSE_CILK_ASSERT, /* Cilk Plus clause: vectorlength (constant-expression-list). */ - OMP_CLAUSE_CILK_VECTORLENGTH + OMP_CLAUSE_CILK_VECTORLENGTH, + + /* Cilk Plus clause: vectorlength (type-name). */ + OMP_CLAUSE_CILK_VECTORLENGTHFOR }; /* The definition of tree nodes fills the next several pages. */ @@ -1870,6 +1873,12 @@ extern void protected_set_expr_location (tree, location_t); OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK \ (NODE, OMP_CLAUSE_CILK_VECTORLENGTH), 0) +/* In an OMP_SIMD_CLAUSE_CILK_VECTORLENGTHFOR, the type for the + vectorlengthfor clause. */ +#define OMP_CLAUSE_CILK_VECTORLENGTHFOR_TYPE(NODE) \ + OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK \ + (NODE, OMP_CLAUSE_CILK_VECTORLENGTHFOR), 0) + #define OMP_CLAUSE_HAS_LOCATION(NODE) \ (LOCATION_LOCUS ((OMP_CLAUSE_CHECK (NODE))->omp_clause.locus) \ != UNKNOWN_LOCATION) From 50ee630c9a6fc0fd93a48aa3a9274623a9304e10 Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Mon, 29 Apr 2013 14:12:37 -0500 Subject: [PATCH 19/63] Remove vectorlengthfor clause which has been deprecated. --- gcc/c-family/c-cilkplus.c | 19 ------- gcc/c-family/c-pragma.h | 1 - gcc/c/c-parser.c | 53 +------------------ gcc/gimplify.c | 2 - gcc/omp-low.c | 2 - .../cilk-simd/compile/vectorlength.c | 30 +---------- gcc/tree-pretty-print.c | 8 --- gcc/tree.c | 7 +-- gcc/tree.h | 11 +--- 9 files changed, 6 insertions(+), 127 deletions(-) diff --git a/gcc/c-family/c-cilkplus.c b/gcc/c-family/c-cilkplus.c index a1dca9554811c..ca3fb32fea66b 100644 --- a/gcc/c-family/c-cilkplus.c +++ b/gcc/c-family/c-cilkplus.c @@ -323,25 +323,6 @@ adjust_clauses_for_omp (tree clauses) max_vlen_tree = OMP_CLAUSE_CILK_VECTORLENGTH_EXPR (c); } } - else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_CILK_VECTORLENGTHFOR) - { - tree type = OMP_CLAUSE_CILK_VECTORLENGTHFOR_TYPE (c); - - /* FIXME: An appropriate safelen clause must be added like - we do above for vectorlength, but don't yet know the - target vector size so we can't calculate - size_of_vector_register / sizeof(data_type). */ - - if ((TREE_CODE (type) != INTEGER_TYPE - && TREE_CODE (type) != REAL_TYPE - && TREE_CODE (type) != COMPLEX_TYPE - && TREE_CODE (type) != POINTER_TYPE) - || (TREE_CODE (type) == COMPLEX_TYPE - && (TREE_CODE (TREE_TYPE (type)) != INTEGER_TYPE - && TREE_CODE (TREE_TYPE (type)) != REAL_TYPE))) - error_at (OMP_CLAUSE_LOCATION (c), - "type must be integer, real, or complex"); - } } if (max_vlen) { diff --git a/gcc/c-family/c-pragma.h b/gcc/c-family/c-pragma.h index 6b0b2c75b73c7..2ff5a00ae8b22 100644 --- a/gcc/c-family/c-pragma.h +++ b/gcc/c-family/c-pragma.h @@ -118,7 +118,6 @@ typedef enum pragma_cilk_clause { PRAGMA_CILK_CLAUSE_NOASSERT, PRAGMA_CILK_CLAUSE_ASSERT, PRAGMA_CILK_CLAUSE_VECTORLENGTH, - PRAGMA_CILK_CLAUSE_VECTORLENGTHFOR, PRAGMA_CILK_CLAUSE_LINEAR, PRAGMA_CILK_CLAUSE_PRIVATE, PRAGMA_CILK_CLAUSE_FIRSTPRIVATE, diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index 949e2ef1344c3..59e44a347ccc4 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -10745,12 +10745,8 @@ c_parser_cilk_clause_noassert (c_parser *parser ATTRIBUTE_UNUSED, static tree c_parser_cilk_clause_vectorlength (c_parser *parser, tree clauses) { - /* The icc manual says vectorlength and vectorlengthfor clauses - cannot coexist, but multiple vectorlength clauses are treated as - a union. The 1.1 spec says nothing. We will assume the icc - manual is correct. */ - check_no_duplicate_clause (clauses, OMP_CLAUSE_CILK_VECTORLENGTHFOR, - "vectorlengthfor"); + /* Multiple vectorlength clauses are allowed and treated as a + union, so we don't check for a duplicate clause. */ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) return clauses; @@ -10787,46 +10783,6 @@ c_parser_cilk_clause_vectorlength (c_parser *parser, tree clauses) return clauses; } -/* Cilk Plus: - vectorlengthfor ( type-name ) */ -static tree -c_parser_cilk_clause_vectorlengthfor (c_parser *parser, tree clauses) -{ - /* The icc manual says vectorlength and vectorlengthfor clauses - cannot coexist, but multiple vectorlength clauses are treated as - a union. The 1.1 spec says nothing. We will assume the icc - manual is correct. */ - check_no_duplicate_clause (clauses, OMP_CLAUSE_CILK_VECTORLENGTH, - "vectorlength"); - - if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) - return clauses; - - location_t loc = c_parser_peek_token (parser)->location; - tree type = NULL; - struct c_type_name *type_name = c_parser_type_name (parser); - - /* FIXME: The specs are not clear whether typedef substitutions are - allowed. Assume they are. I have asked on the forum... */ - - if (type_name) - type = groktypename (type_name, NULL, NULL); - if (type == error_mark_node) - type = NULL; - - if (type != NULL) - { - tree u = build_omp_clause (loc, OMP_CLAUSE_CILK_VECTORLENGTHFOR); - OMP_CLAUSE_CILK_VECTORLENGTHFOR_TYPE (u) = type; - OMP_CLAUSE_CHAIN (u) = clauses; - clauses = u; - } - - c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"); - - return clauses; -} - /* Cilk Plus: linear ( simd-linear-variable-list ) @@ -10931,8 +10887,6 @@ c_parser_cilk_clause_name (c_parser *parser) result = PRAGMA_CILK_CLAUSE_ASSERT; else if (!strcmp (p, "vectorlength")) result = PRAGMA_CILK_CLAUSE_VECTORLENGTH; - else if (!strcmp (p, "vectorlengthfor")) - result = PRAGMA_CILK_CLAUSE_VECTORLENGTHFOR; else if (!strcmp (p, "linear")) result = PRAGMA_CILK_CLAUSE_LINEAR; else if (!strcmp (p, "private")) @@ -10975,9 +10929,6 @@ c_parser_cilk_all_clauses (c_parser *parser) case PRAGMA_CILK_CLAUSE_VECTORLENGTH: clauses = c_parser_cilk_clause_vectorlength (parser, clauses); break; - case PRAGMA_CILK_CLAUSE_VECTORLENGTHFOR: - clauses = c_parser_cilk_clause_vectorlengthfor (parser, clauses); - break; case PRAGMA_CILK_CLAUSE_LINEAR: clauses = c_parser_cilk_clause_linear (parser, clauses); break; diff --git a/gcc/gimplify.c b/gcc/gimplify.c index b1145fc7c4de2..6dd6461afe97b 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -6339,7 +6339,6 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, case OMP_CLAUSE_SAFELEN: case OMP_CLAUSE_CILK_ASSERT: case OMP_CLAUSE_CILK_VECTORLENGTH: - case OMP_CLAUSE_CILK_VECTORLENGTHFOR: break; case OMP_CLAUSE_ALIGNED: @@ -6570,7 +6569,6 @@ gimplify_adjust_omp_clauses (tree *list_p) case OMP_CLAUSE_SAFELEN: case OMP_CLAUSE_CILK_ASSERT: case OMP_CLAUSE_CILK_VECTORLENGTH: - case OMP_CLAUSE_CILK_VECTORLENGTHFOR: break; default: diff --git a/gcc/omp-low.c b/gcc/omp-low.c index 64bfbf073668c..0a0d2394e567d 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -1493,7 +1493,6 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) case OMP_CLAUSE_SAFELEN: case OMP_CLAUSE_CILK_ASSERT: case OMP_CLAUSE_CILK_VECTORLENGTH: - case OMP_CLAUSE_CILK_VECTORLENGTHFOR: break; case OMP_CLAUSE_ALIGNED: @@ -1559,7 +1558,6 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) case OMP_CLAUSE_ALIGNED: case OMP_CLAUSE_CILK_ASSERT: case OMP_CLAUSE_CILK_VECTORLENGTH: - case OMP_CLAUSE_CILK_VECTORLENGTHFOR: break; default: diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/vectorlength.c b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/vectorlength.c index 11c933cf4e7ce..4661e9b576ac8 100644 --- a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/vectorlength.c +++ b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/vectorlength.c @@ -20,35 +20,7 @@ void foo() for (i=0; i < N; ++i) a[i] = b[i]; -#pragma simd vectorlength(4) vectorlengthfor(int) /* { dg-error "too many 'vectorlength'" } */ - for (i=0; i < N; ++i) - a[i] = b[i]; - -#pragma simd vectorlengthfor(int) vectorlengthfor(short int) - for (i=0; i < N; ++i) - a[i] = b[i]; - -#pragma simd vectorlengthfor(tint) - for (i=0; i < N; ++i) - a[i] = b[i]; - -#pragma simd vectorlengthfor(float) - for (i=0; i < N; ++i) - a[i] = b[i]; - -#pragma simd vectorlengthfor(_Complex double) - for (i=0; i < N; ++i) - a[i] = b[i]; - -#pragma simd vectorlengthfor(unsigned char) - for (i=0; i < N; ++i) - a[i] = b[i]; - -#pragma simd vectorlengthfor(struct someclass) /* { dg-error "type must be" } */ - for (i=0; i < N; ++i) - a[i] = b[i]; - -#pragma simd vectorlengthfor(struct someclass *) +#pragma simd vectorlength(4) vectorlength(8, 16) for (i=0; i < N; ++i) a[i] = b[i]; } diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c index 1746926abdf76..8d1f06e92d544 100644 --- a/gcc/tree-pretty-print.c +++ b/gcc/tree-pretty-print.c @@ -597,14 +597,6 @@ dump_omp_clause (pretty_printer *buffer, tree clause, int spc, int flags) pp_character (buffer, ')'); break; - case OMP_CLAUSE_CILK_VECTORLENGTHFOR: - pp_string (buffer, "cilk_vectorlengthfor("); - dump_generic_node (buffer, - OMP_CLAUSE_CILK_VECTORLENGTHFOR_TYPE (clause), - spc, flags, false); - pp_character (buffer, ')'); - break; - default: /* Should never happen. */ dump_generic_node (buffer, clause, spc, flags, false); diff --git a/gcc/tree.c b/gcc/tree.c index 42bb8c56dba45..536539b29dfdc 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -265,8 +265,7 @@ unsigned const char omp_clause_num_ops[] = 0, /* OMP_CLAUSE_SECTIONS */ 0 /* OMP_CLAUSE_TASKGROUP */ , 0, /* OMP_CLAUSE_CILK_ASSERT */ - 1, /* OMP_CLAUSE_CILK_VECTORLENGTH */ - 1, /* OMP_CLAUSE_CILK_VECTORLENGTHFOR */ + 1 /* OMP_CLAUSE_CILK_VECTORLENGTH */ }; const char * const omp_clause_code_name[] = @@ -309,8 +308,7 @@ const char * const omp_clause_code_name[] = "sections", "taskgroup" , "cilk_assert", - "cilk_vectorlength", - "cilk_vectorlengthfor" + "cilk_vectorlength" }; @@ -10816,7 +10814,6 @@ walk_tree_1 (tree *tp, walk_tree_fn func, void *data, case OMP_CLAUSE_SAFELEN: case OMP_CLAUSE_SIMDLEN: case OMP_CLAUSE_CILK_VECTORLENGTH: - case OMP_CLAUSE_CILK_VECTORLENGTHFOR: WALK_SUBTREE (OMP_CLAUSE_OPERAND (*tp, 0)); /* FALLTHRU */ diff --git a/gcc/tree.h b/gcc/tree.h index a8004343e5547..75fbebf5d48f2 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -452,10 +452,7 @@ enum omp_clause_code OMP_CLAUSE_CILK_ASSERT, /* Cilk Plus clause: vectorlength (constant-expression-list). */ - OMP_CLAUSE_CILK_VECTORLENGTH, - - /* Cilk Plus clause: vectorlength (type-name). */ - OMP_CLAUSE_CILK_VECTORLENGTHFOR + OMP_CLAUSE_CILK_VECTORLENGTH }; /* The definition of tree nodes fills the next several pages. */ @@ -1873,12 +1870,6 @@ extern void protected_set_expr_location (tree, location_t); OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK \ (NODE, OMP_CLAUSE_CILK_VECTORLENGTH), 0) -/* In an OMP_SIMD_CLAUSE_CILK_VECTORLENGTHFOR, the type for the - vectorlengthfor clause. */ -#define OMP_CLAUSE_CILK_VECTORLENGTHFOR_TYPE(NODE) \ - OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK \ - (NODE, OMP_CLAUSE_CILK_VECTORLENGTHFOR), 0) - #define OMP_CLAUSE_HAS_LOCATION(NODE) \ (LOCATION_LOCUS ((OMP_CLAUSE_CHECK (NODE))->omp_clause.locus) \ != UNKNOWN_LOCATION) From 1cfb1fbd9cf4691f9373bf850bf665c631663dec Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Mon, 29 Apr 2013 16:00:07 -0500 Subject: [PATCH 20/63] Implement c_finish_cilk_clauses to verify <#pragma simd> clauses. --- gcc/c-family/c-cilkplus.c | 48 +++++++++++++++++-- .../cilk-plus/cilk-simd/compile/clauses3.c | 41 ++++++++++++++++ 2 files changed, 85 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/clauses3.c diff --git a/gcc/c-family/c-cilkplus.c b/gcc/c-family/c-cilkplus.c index ca3fb32fea66b..46c0f49c4814c 100644 --- a/gcc/c-family/c-cilkplus.c +++ b/gcc/c-family/c-cilkplus.c @@ -417,11 +417,51 @@ c_finish_cilk_simd_loop (location_t loc, tree c_finish_cilk_clauses (tree clauses) { - // FIXME: "...no variable shall be the subject of more than one - // linear clause". Verify and check for this. + /* FIXME: Must validate reduction clauses too. Right now we're + ignoring them. */ + for (tree c = clauses; c; c = OMP_CLAUSE_CHAIN (c)) + { + tree prev = clauses; + + /* If a variable appears in a linear clause it cannot appear in + any other OMP clause. */ + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR) + for (tree c2 = clauses; c2; c2 = OMP_CLAUSE_CHAIN (c2)) + { + if (c == c2) + continue; + enum omp_clause_code code = OMP_CLAUSE_CODE (c2); + + switch (code) + { + case OMP_CLAUSE_LINEAR: + case OMP_CLAUSE_PRIVATE: + case OMP_CLAUSE_FIRSTPRIVATE: + case OMP_CLAUSE_LASTPRIVATE: + case OMP_CLAUSE_REDUCTION: + break; + + case OMP_CLAUSE_CILK_ASSERT: + case OMP_CLAUSE_CILK_VECTORLENGTH: + goto next; + + default: + gcc_unreachable (); + } - // FIXME: Also, do whatever we were doing before in - // same_var_in_multiple_lists_p, but rewrite to use OMP_CLAUSEs. + if (OMP_CLAUSE_DECL (c) == OMP_CLAUSE_DECL (c2)) + { + error_at (OMP_CLAUSE_LOCATION (c2), + "variable appears in more than one clause"); + inform (OMP_CLAUSE_LOCATION (c), + "multiple clause defined here"); + // Remove problematic clauses. + OMP_CLAUSE_CHAIN (prev) = OMP_CLAUSE_CHAIN (c2); + } + next: + prev = c2; + } + } return clauses; } diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/clauses3.c b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/clauses3.c new file mode 100644 index 0000000000000..5536884ea0672 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/clauses3.c @@ -0,0 +1,41 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -std=c99 -fcilkplus" } */ + +#define N 1000 + +int A[N], B[N], C[N]; +int main (void) +{ + int ii = 0; + +#pragma simd private (B) linear(B:1) /* { dg-error "more than one clause" } */ + for (ii = 0; ii < N; ii++) + { + A[ii] = B[ii] + C[ii]; + } + +#pragma simd private (B, C) linear(B:1) /* { dg-error "more than one clause" } */ + for (ii = 0; ii < N; ii++) + { + A[ii] = B[ii] + C[ii]; + } + +#pragma simd private (B) linear(C:2, B:1) /* { dg-error "more than one clause" } */ + for (ii = 0; ii < N; ii++) + { + A[ii] = B[ii] + C[ii]; + } + +#pragma simd reduction (+:B) linear(B:1) /* { dg-error "more than one clause" } */ + for (ii = 0; ii < N; ii++) + { + A[ii] = B[ii] + C[ii]; + } + +#pragma simd reduction (+:B) linear(B) /* { dg-error "more than one clause" } */ + for (ii = 0; ii < N; ii++) + { + A[ii] = B[ii] + C[ii]; + } + return 0; +} From 8775598cc47d0490103f4ee18b7313a8c9838e64 Mon Sep 17 00:00:00 2001 From: jakub Date: Tue, 30 Apr 2013 16:01:00 +0000 Subject: [PATCH 21/63] * omp-low.c (check_omp_nesting_restrictions): Diagnose OpenMP constructs nested inside simd region. Don't treat #pragma omp simd as work-sharing region. Disallow work-sharing constructs inside of critical region. Complain if ordered region is nested inside of parallel region without loop region in between. (scan_omp_1_stmt): Call check_omp_nesting_restrictions even for GOMP_{cancel{,lation_point},taskyield,taskwait} calls. * gfortran.dg/gomp/appendix-a/a.35.5.f90: Add dg-error. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gomp-4_0-branch@198459 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog.gomp | 11 ++++++ gcc/omp-low.c | 38 +++++++++++++++++-- gcc/testsuite/ChangeLog.gomp | 4 ++ .../gfortran.dg/gomp/appendix-a/a.35.5.f90 | 2 +- 4 files changed, 50 insertions(+), 5 deletions(-) diff --git a/gcc/ChangeLog.gomp b/gcc/ChangeLog.gomp index 9e0126272ba3f..c8d5f76f5649e 100644 --- a/gcc/ChangeLog.gomp +++ b/gcc/ChangeLog.gomp @@ -1,3 +1,14 @@ +2013-04-30 Jakub Jelinek + + * omp-low.c (check_omp_nesting_restrictions): Diagnose + OpenMP constructs nested inside simd region. Don't treat + #pragma omp simd as work-sharing region. Disallow work-sharing + constructs inside of critical region. Complain if ordered + region is nested inside of parallel region without loop + region in between. + (scan_omp_1_stmt): Call check_omp_nesting_restrictions even + for GOMP_{cancel{,lation_point},taskyield,taskwait} calls. + 2013-04-23 Jakub Jelinek * Makefile.in (omp-low.o): Depend on $(TARGET_H). diff --git a/gcc/omp-low.c b/gcc/omp-low.c index e658634310427..ea46d76e65aa0 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -1859,9 +1859,21 @@ scan_omp_single (gimple stmt, omp_context *outer_ctx) static bool check_omp_nesting_restrictions (gimple stmt, omp_context *ctx) { + if (ctx != NULL + && gimple_code (ctx->stmt) == GIMPLE_OMP_FOR + && (gimple_omp_for_kind (ctx->stmt) == GF_OMP_FOR_KIND_SIMD + || gimple_omp_for_kind (ctx->stmt) == GF_OMP_FOR_KIND_FOR_SIMD)) + { + error_at (gimple_location (stmt), + "OpenMP constructs may not be nested inside simd region"); + return false; + } switch (gimple_code (stmt)) { case GIMPLE_OMP_FOR: + if (gimple_omp_for_kind (stmt) == GF_OMP_FOR_KIND_SIMD) + return true; + /* FALLTHRU */ case GIMPLE_OMP_SECTIONS: case GIMPLE_OMP_SINGLE: case GIMPLE_CALL: @@ -1874,8 +1886,12 @@ check_omp_nesting_restrictions (gimple stmt, omp_context *ctx) case GIMPLE_OMP_ORDERED: case GIMPLE_OMP_MASTER: case GIMPLE_OMP_TASK: + case GIMPLE_OMP_CRITICAL: if (is_gimple_call (stmt)) { + if (DECL_FUNCTION_CODE (gimple_call_fndecl (stmt)) + != BUILT_IN_GOMP_BARRIER) + return true; error_at (gimple_location (stmt), "barrier region may not be closely nested inside " "of work-sharing, critical, ordered, master or " @@ -1932,7 +1948,10 @@ check_omp_nesting_restrictions (gimple stmt, omp_context *ctx) } return true; case GIMPLE_OMP_PARALLEL: - return true; + error_at (gimple_location (stmt), + "ordered region must be closely nested inside " + "a loop region with an ordered clause"); + return false; default: break; } @@ -2029,9 +2048,20 @@ scan_omp_1_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p, else if (is_gimple_call (stmt)) { tree fndecl = gimple_call_fndecl (stmt); - if (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL - && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_GOMP_BARRIER) - remove = !check_omp_nesting_restrictions (stmt, ctx); + if (fndecl + && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL) + switch (DECL_FUNCTION_CODE (fndecl)) + { + case BUILT_IN_GOMP_BARRIER: + case BUILT_IN_GOMP_CANCEL: + case BUILT_IN_GOMP_CANCELLATION_POINT: + case BUILT_IN_GOMP_TASKYIELD: + case BUILT_IN_GOMP_TASKWAIT: + remove = !check_omp_nesting_restrictions (stmt, ctx); + break; + default: + break; + } } if (remove) { diff --git a/gcc/testsuite/ChangeLog.gomp b/gcc/testsuite/ChangeLog.gomp index 5b1bb9e4eae0d..b4f8668c84b3f 100644 --- a/gcc/testsuite/ChangeLog.gomp +++ b/gcc/testsuite/ChangeLog.gomp @@ -1,3 +1,7 @@ +2013-04-30 Jakub Jelinek + + * gfortran.dg/gomp/appendix-a/a.35.5.f90: Add dg-error. + 2013-04-24 Jakub Jelinek * c-c++-common/gomp/simd1.c: Enable also for C. diff --git a/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.35.5.f90 b/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.35.5.f90 index 083c0b3b7232e..a580a3baf663c 100644 --- a/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.35.5.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.35.5.f90 @@ -6,7 +6,7 @@ SUBROUTINE WRONG5(N) !$OMP CRITICAL CALL WORK(N,1) ! incorrect nesting of barrier region in a critical region -!$OMP BARRIER +!$OMP BARRIER ! { dg-error "region may not be closely nested inside of" } CALL WORK(N,2) !$OMP END CRITICAL !$OMP END PARALLEL From 740af7171c00b73643a8f8560905e5355b33f41d Mon Sep 17 00:00:00 2001 From: jakub Date: Tue, 30 Apr 2013 16:01:57 +0000 Subject: [PATCH 22/63] * c-pragma.c (omp_pragmas): Add PRAGMA_OMP_DISTRIBUTE. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gomp-4_0-branch@198460 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/c-family/ChangeLog.gomp | 4 ++++ gcc/c-family/c-pragma.c | 1 + 2 files changed, 5 insertions(+) diff --git a/gcc/c-family/ChangeLog.gomp b/gcc/c-family/ChangeLog.gomp index 22db33a10d1e4..6bf1bfd8e4496 100644 --- a/gcc/c-family/ChangeLog.gomp +++ b/gcc/c-family/ChangeLog.gomp @@ -1,3 +1,7 @@ +2013-04-30 Jakub Jelinek + + * c-pragma.c (omp_pragmas): Add PRAGMA_OMP_DISTRIBUTE. + 2013-04-10 Jakub Jelinek * c-common.c (DEF_FUNCTION_TYPE_8): Define. diff --git a/gcc/c-family/c-pragma.c b/gcc/c-family/c-pragma.c index b03ddc1d3bac4..0c47a93bdf9ee 100644 --- a/gcc/c-family/c-pragma.c +++ b/gcc/c-family/c-pragma.c @@ -1166,6 +1166,7 @@ static const struct omp_pragma_def omp_pragmas[] = { { "cancellation", PRAGMA_OMP_CANCELLATION_POINT }, { "critical", PRAGMA_OMP_CRITICAL }, { "declare", PRAGMA_OMP_DECLARE_REDUCTION }, + { "distribute", PRAGMA_OMP_DISTRIBUTE }, { "end", PRAGMA_OMP_END_DECLARE_TARGET }, { "flush", PRAGMA_OMP_FLUSH }, { "for", PRAGMA_OMP_FOR }, From d22e24666757a3e0e1ff5b4616d98898b1df8315 Mon Sep 17 00:00:00 2001 From: jakub Date: Tue, 30 Apr 2013 16:07:01 +0000 Subject: [PATCH 23/63] * gimple-pretty-print.c (dump_gimple_omp_atomic_load, dump_gimple_omp_atomic_store): Handle gimple_omp_atomic_seq_cst_p. * gimple.h (enum gf_mask): Add GF_OMP_ATOMIC_SEQ_CST. (gimple_omp_atomic_set_seq_cst, gimple_omp_atomic_seq_cst_p): New inline functions. * omp-low.c (expand_omp_atomic_load, expand_omp_atomic_store, expand_omp_atomic_fetch_op): If gimple_omp_atomic_seq_cst_p, pass MEMMODEL_SEQ_CST instead of MEMMODEL_RELAXED to the builtin. * gimplify.c (gimplify_omp_atomic): Handle OMP_ATOMIC_SEQ_CST. * tree-pretty-print.c (dump_generic_node): Handle OMP_ATOMIC_SEQ_CST. * tree.def (OMP_ATOMIC): Add comment that OMP_ATOMIC* must stay consecutive. * tree.h (OMP_ATOMIC_SEQ_CST): Define. c/ * c-parser.c (c_parser_omp_atomic): Parse seq_cst clause, pass true if it is present to c_finish_omp_atomic. cp/ * pt.c (tsubst_expr): Pass OMP_ATOMIC_SEQ_CST to finish_omp_atomic. * semantics.c (finish_omp_atomic): Add seq_cst argument, pass it through to c_finish_omp_atomic or store into OMP_ATOMIC_SEQ_CST. * cp-tree.h (finish_omp_atomic): Adjust prototype. * parser.c (cp_parser_omp_atomic): Parse seq_cst clause, pass true if it is present to finish_omp_atomic. c-family/ * c-omp.c (c_finish_omp_atomic): Add seq_cst argument, store it into OMP_ATOMIC_SEQ_CST bit. * c-common.h (c_finish_omp_atomic): Adjust prototype. testsuite/ * testsuite/libgomp.c/atomic-17.c: New test. * testsuite/libgomp.c++/atomic-14.C: New test. * testsuite/libgomp.c++/atomic-15.C: New test. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gomp-4_0-branch@198461 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog.gomp | 14 +++ gcc/c-family/ChangeLog.gomp | 4 + gcc/c-family/c-common.h | 2 +- gcc/c-family/c-omp.c | 4 +- gcc/c/ChangeLog.gomp | 5 + gcc/c/c-parser.c | 32 ++++++- gcc/cp/ChangeLog.gomp | 9 ++ gcc/cp/cp-tree.h | 3 +- gcc/cp/parser.c | 35 ++++++- gcc/cp/pt.c | 6 +- gcc/cp/semantics.c | 7 +- gcc/gimple-pretty-print.c | 4 + gcc/gimple.h | 24 +++++ gcc/gimplify.c | 7 +- gcc/omp-low.c | 16 +++- gcc/tree-pretty-print.c | 6 ++ gcc/tree.def | 3 + gcc/tree.h | 9 ++ libgomp/ChangeLog.gomp | 6 ++ libgomp/testsuite/libgomp.c++/atomic-14.C | 99 ++++++++++++++++++++ libgomp/testsuite/libgomp.c++/atomic-15.C | 108 ++++++++++++++++++++++ libgomp/testsuite/libgomp.c/atomic-17.c | 99 ++++++++++++++++++++ 22 files changed, 489 insertions(+), 13 deletions(-) create mode 100644 libgomp/testsuite/libgomp.c++/atomic-14.C create mode 100644 libgomp/testsuite/libgomp.c++/atomic-15.C create mode 100644 libgomp/testsuite/libgomp.c/atomic-17.c diff --git a/gcc/ChangeLog.gomp b/gcc/ChangeLog.gomp index c8d5f76f5649e..3802a119cfa14 100644 --- a/gcc/ChangeLog.gomp +++ b/gcc/ChangeLog.gomp @@ -1,5 +1,19 @@ 2013-04-30 Jakub Jelinek + * gimple-pretty-print.c (dump_gimple_omp_atomic_load, + dump_gimple_omp_atomic_store): Handle gimple_omp_atomic_seq_cst_p. + * gimple.h (enum gf_mask): Add GF_OMP_ATOMIC_SEQ_CST. + (gimple_omp_atomic_set_seq_cst, gimple_omp_atomic_seq_cst_p): New + inline functions. + * omp-low.c (expand_omp_atomic_load, expand_omp_atomic_store, + expand_omp_atomic_fetch_op): If gimple_omp_atomic_seq_cst_p, + pass MEMMODEL_SEQ_CST instead of MEMMODEL_RELAXED to the builtin. + * gimplify.c (gimplify_omp_atomic): Handle OMP_ATOMIC_SEQ_CST. + * tree-pretty-print.c (dump_generic_node): Handle OMP_ATOMIC_SEQ_CST. + * tree.def (OMP_ATOMIC): Add comment that OMP_ATOMIC* must stay + consecutive. + * tree.h (OMP_ATOMIC_SEQ_CST): Define. + * omp-low.c (check_omp_nesting_restrictions): Diagnose OpenMP constructs nested inside simd region. Don't treat #pragma omp simd as work-sharing region. Disallow work-sharing diff --git a/gcc/c-family/ChangeLog.gomp b/gcc/c-family/ChangeLog.gomp index 6bf1bfd8e4496..9ed6de1a55f73 100644 --- a/gcc/c-family/ChangeLog.gomp +++ b/gcc/c-family/ChangeLog.gomp @@ -1,5 +1,9 @@ 2013-04-30 Jakub Jelinek + * c-omp.c (c_finish_omp_atomic): Add seq_cst argument, store it + into OMP_ATOMIC_SEQ_CST bit. + * c-common.h (c_finish_omp_atomic): Adjust prototype. + * c-pragma.c (omp_pragmas): Add PRAGMA_OMP_DISTRIBUTE. 2013-04-10 Jakub Jelinek diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index 57f2f6062f771..ea2600cda2164 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -1035,7 +1035,7 @@ extern tree c_finish_omp_critical (location_t, tree, tree); extern tree c_finish_omp_ordered (location_t, tree); extern void c_finish_omp_barrier (location_t); extern tree c_finish_omp_atomic (location_t, enum tree_code, enum tree_code, - tree, tree, tree, tree, tree, bool); + tree, tree, tree, tree, tree, bool, bool); extern void c_finish_omp_flush (location_t); extern void c_finish_omp_taskwait (location_t); extern void c_finish_omp_taskyield (location_t); diff --git a/gcc/c-family/c-omp.c b/gcc/c-family/c-omp.c index 06a2da28fe2f2..d8edcf8145f5a 100644 --- a/gcc/c-family/c-omp.c +++ b/gcc/c-family/c-omp.c @@ -122,7 +122,7 @@ c_finish_omp_taskyield (location_t loc) tree c_finish_omp_atomic (location_t loc, enum tree_code code, enum tree_code opcode, tree lhs, tree rhs, - tree v, tree lhs1, tree rhs1, bool swapped) + tree v, tree lhs1, tree rhs1, bool swapped, bool seq_cst) { tree x, type, addr; @@ -168,6 +168,7 @@ c_finish_omp_atomic (location_t loc, enum tree_code code, { x = build1 (OMP_ATOMIC_READ, type, addr); SET_EXPR_LOCATION (x, loc); + OMP_ATOMIC_SEQ_CST (x) = seq_cst; return build_modify_expr (loc, v, NULL_TREE, NOP_EXPR, loc, x, NULL_TREE); return x; @@ -192,6 +193,7 @@ c_finish_omp_atomic (location_t loc, enum tree_code code, type = void_type_node; x = build2 (code, type, addr, rhs); SET_EXPR_LOCATION (x, loc); + OMP_ATOMIC_SEQ_CST (x) = seq_cst; /* Generally it is hard to prove lhs1 and lhs are the same memory location, just diagnose different variables. */ diff --git a/gcc/c/ChangeLog.gomp b/gcc/c/ChangeLog.gomp index 83c2f14baf05c..3e1f7156faa16 100644 --- a/gcc/c/ChangeLog.gomp +++ b/gcc/c/ChangeLog.gomp @@ -1,3 +1,8 @@ +2013-04-30 Jakub Jelinek + + * c-parser.c (c_parser_omp_atomic): Parse seq_cst clause, pass + true if it is present to c_finish_omp_atomic. + 2013-04-24 Jakub Jelinek * c-parser.c (c_parser_compound_statement, diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index eea10811f0d26..58e53d5629484 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -10218,7 +10218,20 @@ c_parser_omp_atomic (location_t loc, c_parser *parser) location_t eloc; bool structured_block = false; bool swapped = false; + bool seq_cst = false; + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (!strcmp (p, "seq_cst")) + { + seq_cst = true; + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_COMMA) + && c_parser_peek_2nd_token (parser)->type == CPP_NAME) + c_parser_consume_token (parser); + } + } if (c_parser_next_token_is (parser, CPP_NAME)) { const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); @@ -10236,6 +10249,23 @@ c_parser_omp_atomic (location_t loc, c_parser *parser) if (p) c_parser_consume_token (parser); } + if (!seq_cst) + { + if (c_parser_next_token_is (parser, CPP_COMMA) + && c_parser_peek_2nd_token (parser)->type == CPP_NAME) + c_parser_consume_token (parser); + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p + = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (!strcmp (p, "seq_cst")) + { + seq_cst = true; + c_parser_consume_token (parser); + } + } + } c_parser_skip_to_pragma_eol (parser); switch (code) @@ -10526,7 +10556,7 @@ c_parser_omp_atomic (location_t loc, c_parser *parser) } else stmt = c_finish_omp_atomic (loc, code, opcode, lhs, rhs, v, lhs1, rhs1, - swapped); + swapped, seq_cst); if (stmt != error_mark_node) add_stmt (stmt); diff --git a/gcc/cp/ChangeLog.gomp b/gcc/cp/ChangeLog.gomp index ac49b6e603bdb..aa7d736e47d0e 100644 --- a/gcc/cp/ChangeLog.gomp +++ b/gcc/cp/ChangeLog.gomp @@ -1,3 +1,12 @@ +2013-04-30 Jakub Jelinek + + * pt.c (tsubst_expr): Pass OMP_ATOMIC_SEQ_CST to finish_omp_atomic. + * semantics.c (finish_omp_atomic): Add seq_cst argument, pass + it through to c_finish_omp_atomic or store into OMP_ATOMIC_SEQ_CST. + * cp-tree.h (finish_omp_atomic): Adjust prototype. + * parser.c (cp_parser_omp_atomic): Parse seq_cst clause, pass + true if it is present to finish_omp_atomic. + 2013-04-24 Jakub Jelinek * parser.c (cp_parser_omp_clause_name): Add missing break after diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index bb0a4ae72ce07..f99a8e67a4850 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5713,7 +5713,8 @@ extern tree finish_omp_for (location_t, enum tree_code, tree, tree, tree, tree, tree, tree, tree); extern void finish_omp_atomic (enum tree_code, enum tree_code, - tree, tree, tree, tree, tree); + tree, tree, tree, tree, tree, + bool); extern void finish_omp_barrier (void); extern void finish_omp_flush (void); extern void finish_omp_taskwait (void); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index bcee34589bc80..943764c3d5437 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -27146,7 +27146,22 @@ cp_parser_omp_atomic (cp_parser *parser, cp_token *pragma_tok) tree rhs1 = NULL_TREE, orig_lhs; enum tree_code code = OMP_ATOMIC, opcode = NOP_EXPR; bool structured_block = false; + bool seq_cst = 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, "seq_cst")) + { + seq_cst = true; + cp_lexer_consume_token (parser->lexer); + if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA) + && cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_NAME) + cp_lexer_consume_token (parser->lexer); + } + } if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) { tree id = cp_lexer_peek_token (parser->lexer)->u.value; @@ -27165,6 +27180,24 @@ cp_parser_omp_atomic (cp_parser *parser, cp_token *pragma_tok) if (p) cp_lexer_consume_token (parser->lexer); } + if (!seq_cst) + { + if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA) + && cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_NAME) + cp_lexer_consume_token (parser->lexer); + + 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, "seq_cst")) + { + seq_cst = true; + cp_lexer_consume_token (parser->lexer); + } + } + } cp_parser_require_pragma_eol (parser, pragma_tok); switch (code) @@ -27471,7 +27504,7 @@ cp_parser_omp_atomic (cp_parser *parser, cp_token *pragma_tok) cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE); } done: - finish_omp_atomic (code, opcode, lhs, rhs, v, lhs1, rhs1); + finish_omp_atomic (code, opcode, lhs, rhs, v, lhs1, rhs1, seq_cst); if (!structured_block) cp_parser_consume_semicolon_at_end_of_statement (parser); return; diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 7ddb6a31dbc1f..a225849359cc6 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -13276,7 +13276,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, lhs = RECUR (TREE_OPERAND (op1, 0)); rhs = RECUR (TREE_OPERAND (op1, 1)); finish_omp_atomic (OMP_ATOMIC, TREE_CODE (op1), lhs, rhs, - NULL_TREE, NULL_TREE, rhs1); + NULL_TREE, NULL_TREE, rhs1, + OMP_ATOMIC_SEQ_CST (t)); } else { @@ -13313,7 +13314,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, lhs = RECUR (TREE_OPERAND (op1, 0)); rhs = RECUR (TREE_OPERAND (op1, 1)); } - finish_omp_atomic (code, opcode, lhs, rhs, v, lhs1, rhs1); + finish_omp_atomic (code, opcode, lhs, rhs, v, lhs1, rhs1, + OMP_ATOMIC_SEQ_CST (t)); } break; diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 96e6c538d1175..004d690d59b5e 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -5221,7 +5221,7 @@ finish_omp_for (location_t locus, enum tree_code code, tree declv, tree initv, void finish_omp_atomic (enum tree_code code, enum tree_code opcode, tree lhs, - tree rhs, tree v, tree lhs1, tree rhs1) + tree rhs, tree v, tree lhs1, tree rhs1, bool seq_cst) { tree orig_lhs; tree orig_rhs; @@ -5292,7 +5292,7 @@ finish_omp_atomic (enum tree_code code, enum tree_code opcode, tree lhs, return; } stmt = c_finish_omp_atomic (input_location, code, opcode, lhs, rhs, - v, lhs1, rhs1, swapped); + v, lhs1, rhs1, swapped, seq_cst); if (stmt == error_mark_node) return; } @@ -5302,6 +5302,7 @@ finish_omp_atomic (enum tree_code code, enum tree_code opcode, tree lhs, { stmt = build_min_nt_loc (EXPR_LOCATION (orig_lhs), OMP_ATOMIC_READ, orig_lhs); + OMP_ATOMIC_SEQ_CST (stmt) = seq_cst; stmt = build2 (MODIFY_EXPR, void_type_node, orig_v, stmt); } else @@ -5317,10 +5318,12 @@ finish_omp_atomic (enum tree_code code, enum tree_code opcode, tree lhs, { stmt = build_min_nt_loc (EXPR_LOCATION (orig_lhs1), code, orig_lhs1, stmt); + OMP_ATOMIC_SEQ_CST (stmt) = seq_cst; stmt = build2 (MODIFY_EXPR, void_type_node, orig_v, stmt); } } stmt = build2 (OMP_ATOMIC, void_type_node, integer_zero_node, stmt); + OMP_ATOMIC_SEQ_CST (stmt) = seq_cst; } add_stmt (stmt); } diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c index 2f3926d982f3c..28baa411b4b54 100644 --- a/gcc/gimple-pretty-print.c +++ b/gcc/gimple-pretty-print.c @@ -1805,6 +1805,8 @@ dump_gimple_omp_atomic_load (pretty_printer *buffer, gimple gs, int spc, else { pp_string (buffer, "#pragma omp atomic_load"); + if (gimple_omp_atomic_seq_cst_p (gs)) + pp_string (buffer, " seq_cst"); if (gimple_omp_atomic_need_value_p (gs)) pp_string (buffer, " [needed]"); newline_and_indent (buffer, spc + 2); @@ -1835,6 +1837,8 @@ dump_gimple_omp_atomic_store (pretty_printer *buffer, gimple gs, int spc, else { pp_string (buffer, "#pragma omp atomic_store "); + if (gimple_omp_atomic_seq_cst_p (gs)) + pp_string (buffer, "seq_cst "); if (gimple_omp_atomic_need_value_p (gs)) pp_string (buffer, "[needed] "); pp_character (buffer, '('); diff --git a/gcc/gimple.h b/gcc/gimple.h index d25289f88b18b..36ad626c9aa96 100644 --- a/gcc/gimple.h +++ b/gcc/gimple.h @@ -114,6 +114,7 @@ enum gf_mask { GF_OMP_SECTION_LAST = 1 << 0, GF_OMP_ATOMIC_NEED_VALUE = 1 << 0, + GF_OMP_ATOMIC_SEQ_CST = 1 << 1, GF_PREDICT_TAKEN = 1 << 15 }; @@ -1727,6 +1728,29 @@ gimple_omp_atomic_set_need_value (gimple g) } +/* Return true if OMP atomic load/store statement G has the + GF_OMP_ATOMIC_SEQ_CST flag set. */ + +static inline bool +gimple_omp_atomic_seq_cst_p (const_gimple g) +{ + if (gimple_code (g) != GIMPLE_OMP_ATOMIC_LOAD) + GIMPLE_CHECK (g, GIMPLE_OMP_ATOMIC_STORE); + return (gimple_omp_subcode (g) & GF_OMP_ATOMIC_SEQ_CST) != 0; +} + + +/* Set the GF_OMP_ATOMIC_SEQ_CST flag on G. */ + +static inline void +gimple_omp_atomic_set_seq_cst (gimple g) +{ + if (gimple_code (g) != GIMPLE_OMP_ATOMIC_LOAD) + GIMPLE_CHECK (g, GIMPLE_OMP_ATOMIC_STORE); + g->gsbase.subcode |= GF_OMP_ATOMIC_SEQ_CST; +} + + /* Return the number of operands for statement GS. */ static inline unsigned diff --git a/gcc/gimplify.c b/gcc/gimplify.c index f990fac62106d..7488706de0ed1 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -7076,6 +7076,11 @@ gimplify_omp_atomic (tree *expr_p, gimple_seq *pre_p) rhs = tmp_load; storestmt = gimple_build_omp_atomic_store (rhs); gimplify_seq_add_stmt (pre_p, storestmt); + if (OMP_ATOMIC_SEQ_CST (*expr_p)) + { + gimple_omp_atomic_set_seq_cst (loadstmt); + gimple_omp_atomic_set_seq_cst (storestmt); + } switch (TREE_CODE (*expr_p)) { case OMP_ATOMIC_READ: @@ -7092,7 +7097,7 @@ gimplify_omp_atomic (tree *expr_p, gimple_seq *pre_p) break; } - return GS_ALL_DONE; + return GS_ALL_DONE; } /* Gimplify a TRANSACTION_EXPR. This involves gimplification of the diff --git a/gcc/omp-low.c b/gcc/omp-low.c index ea46d76e65aa0..b320817b5674e 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -5472,7 +5472,10 @@ expand_omp_atomic_load (basic_block load_bb, tree addr, itype = TREE_TYPE (TREE_TYPE (decl)); call = build_call_expr_loc (loc, decl, 2, addr, - build_int_cst (NULL, MEMMODEL_RELAXED)); + build_int_cst (NULL, + gimple_omp_atomic_seq_cst_p (stmt) + ? MEMMODEL_SEQ_CST + : MEMMODEL_RELAXED)); if (!useless_type_conversion_p (type, itype)) call = fold_build1_loc (loc, VIEW_CONVERT_EXPR, type, call); call = build2_loc (loc, MODIFY_EXPR, void_type_node, loaded_val, call); @@ -5544,7 +5547,10 @@ expand_omp_atomic_store (basic_block load_bb, tree addr, if (!useless_type_conversion_p (itype, type)) stored_val = fold_build1_loc (loc, VIEW_CONVERT_EXPR, itype, stored_val); call = build_call_expr_loc (loc, decl, 3, addr, stored_val, - build_int_cst (NULL, MEMMODEL_RELAXED)); + build_int_cst (NULL, + gimple_omp_atomic_seq_cst_p (stmt) + ? MEMMODEL_SEQ_CST + : MEMMODEL_RELAXED)); if (exchange) { if (!useless_type_conversion_p (type, itype)) @@ -5585,6 +5591,7 @@ expand_omp_atomic_fetch_op (basic_block load_bb, enum tree_code code; bool need_old, need_new; enum machine_mode imode; + bool seq_cst; /* We expect to find the following sequences: @@ -5610,6 +5617,7 @@ expand_omp_atomic_fetch_op (basic_block load_bb, return false; need_new = gimple_omp_atomic_need_value_p (gsi_stmt (gsi)); need_old = gimple_omp_atomic_need_value_p (last_stmt (load_bb)); + seq_cst = gimple_omp_atomic_seq_cst_p (last_stmt (load_bb)); gcc_checking_assert (!need_old || !need_new); if (!operand_equal_p (gimple_assign_lhs (stmt), stored_val, 0)) @@ -5676,7 +5684,9 @@ expand_omp_atomic_fetch_op (basic_block load_bb, use the RELAXED memory model. */ call = build_call_expr_loc (loc, decl, 3, addr, fold_convert_loc (loc, itype, rhs), - build_int_cst (NULL, MEMMODEL_RELAXED)); + build_int_cst (NULL, + seq_cst ? MEMMODEL_SEQ_CST + : MEMMODEL_RELAXED)); if (need_old || need_new) { diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c index f3de68c1d918b..0c3fec75d04c5 100644 --- a/gcc/tree-pretty-print.c +++ b/gcc/tree-pretty-print.c @@ -2431,6 +2431,8 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags, case OMP_ATOMIC: pp_string (buffer, "#pragma omp atomic"); + if (OMP_ATOMIC_SEQ_CST (node)) + pp_string (buffer, " seq_cst"); newline_and_indent (buffer, spc + 2); dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); pp_space (buffer); @@ -2441,6 +2443,8 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags, case OMP_ATOMIC_READ: pp_string (buffer, "#pragma omp atomic read"); + if (OMP_ATOMIC_SEQ_CST (node)) + pp_string (buffer, " seq_cst"); newline_and_indent (buffer, spc + 2); dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); pp_space (buffer); @@ -2449,6 +2453,8 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags, case OMP_ATOMIC_CAPTURE_OLD: case OMP_ATOMIC_CAPTURE_NEW: pp_string (buffer, "#pragma omp atomic capture"); + if (OMP_ATOMIC_SEQ_CST (node)) + pp_string (buffer, " seq_cst"); newline_and_indent (buffer, spc + 2); dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); pp_space (buffer); diff --git a/gcc/tree.def b/gcc/tree.def index 92df7d721ced8..147b6805b0a70 100644 --- a/gcc/tree.def +++ b/gcc/tree.def @@ -1069,6 +1069,9 @@ DEFTREECODE (OMP_ORDERED, "omp_ordered", tcc_statement, 1) Operand 1: OMP_CRITICAL_NAME: Identifier for critical section. */ DEFTREECODE (OMP_CRITICAL, "omp_critical", tcc_statement, 2) +/* OMP_ATOMIC through OMP_ATOMIC_CAPTURE_NEW must be consecutive, + or OMP_ATOMIC_SEQ_CST needs adjusting. */ + /* OpenMP - #pragma omp atomic Operand 0: The address at which the atomic operation is to be performed. This address should be stabilized with save_expr. diff --git a/gcc/tree.h b/gcc/tree.h index b4bd6c490f45e..46bb2b415cb8d 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -633,6 +633,9 @@ struct GTY(()) tree_base { OMP_PARALLEL_COMBINED in OMP_PARALLEL + OMP_ATOMIC_SEQ_CST in + OMP_ATOMIC* + OMP_CLAUSE_PRIVATE_OUTER_REF in OMP_CLAUSE_PRIVATE @@ -1872,6 +1875,12 @@ extern void protected_set_expr_location (tree, location_t); #define OMP_PARALLEL_COMBINED(NODE) \ (OMP_PARALLEL_CHECK (NODE)->base.private_flag) +/* True if OMP_ATOMIC* is supposed to be sequentially consistent + as opposed to relaxed. */ +#define OMP_ATOMIC_SEQ_CST(NODE) \ + (TREE_RANGE_CHECK (NODE, OMP_ATOMIC, \ + OMP_ATOMIC_CAPTURE_NEW)->base.private_flag) + /* True on a PRIVATE clause if its decl is kept around for debugging information only and its DECL_VALUE_EXPR is supposed to point to what it has been remapped to. */ diff --git a/libgomp/ChangeLog.gomp b/libgomp/ChangeLog.gomp index d62cdc9305590..e01eaa946d2fc 100644 --- a/libgomp/ChangeLog.gomp +++ b/libgomp/ChangeLog.gomp @@ -1,3 +1,9 @@ +2013-04-30 Jakub Jelinek + + * testsuite/libgomp.c/atomic-17.c: New test. + * testsuite/libgomp.c++/atomic-14.C: New test. + * testsuite/libgomp.c++/atomic-15.C: New test. + 2013-04-10 Jakub Jelinek * libgomp.map (omp_get_cancellation, omp_get_cancellation_, diff --git a/libgomp/testsuite/libgomp.c++/atomic-14.C b/libgomp/testsuite/libgomp.c++/atomic-14.C new file mode 100644 index 0000000000000..dccea3acd803a --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/atomic-14.C @@ -0,0 +1,99 @@ +// { dg-do run } + +extern "C" void abort (void); +int x = 6; + +int +main () +{ + int v, l = 2, s = 1; + #pragma omp atomic seq_cst + x = -3 + x; + #pragma omp atomic read seq_cst + v = x; + if (v != 3) + abort (); + #pragma omp atomic seq_cst update + x = 3 * 2 * 1 + x; + #pragma omp atomic read, seq_cst + v = x; + if (v != 9) + abort (); + #pragma omp atomic seq_cst, capture + v = x = x | 16; + if (v != 25) + abort (); + #pragma omp atomic capture seq_cst + v = x = x + 14 * 2 / 4; + if (v != 32) + abort (); + #pragma omp atomic seq_cst capture + v = x = 5 | x; + if (v != 37) + abort (); + #pragma omp atomic capture, seq_cst + v = x = 40 + 12 - 2 - 7 - x; + if (v != 6) + abort (); + #pragma omp atomic seq_cst read + v = x; + if (v != 6) + abort (); + #pragma omp atomic capture seq_cst + { v = x; x = 3 + x; } + if (v != 6) + abort (); + #pragma omp atomic seq_cst capture + { v = x; x = -1 * -1 * -1 * -1 - x; } + if (v != 9) + abort (); + #pragma omp atomic read seq_cst + v = x; + if (v != -8) + abort (); + #pragma omp atomic capture, seq_cst + { x = 2 * 2 - x; v = x; } + if (v != 12) + abort (); + #pragma omp atomic seq_cst capture + { x = 7 & x; v = x; } + if (v != 4) + abort (); + #pragma omp atomic capture seq_cst + { v = x; x = 6; } + if (v != 4) + abort (); + #pragma omp atomic read, seq_cst + v = x; + if (v != 6) + abort (); + #pragma omp atomic capture seq_cst + { v = x; x = 7 * 8 + 23; } + if (v != 6) + abort (); + #pragma omp atomic seq_cst, read + v = x; + if (v != 79) + abort (); + #pragma omp atomic capture , seq_cst + { v = x; x = 23 + 6 * 4; } + if (v != 79) + abort (); + #pragma omp atomic read seq_cst + v = x; + if (v != 47) + abort (); + #pragma omp atomic seq_cst capture + { v = x; x = l ? 17 : 12; } + if (v != 47) + abort (); + #pragma omp atomic capture seq_cst + { v = x; x = l = s++ + 3; } + if (v != 17 || l != 4 || s != 2) + abort (); + #pragma omp atomic read seq_cst + v = x; + if (v != 4) + abort (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/atomic-15.C b/libgomp/testsuite/libgomp.c++/atomic-15.C new file mode 100644 index 0000000000000..9abefb6468897 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/atomic-15.C @@ -0,0 +1,108 @@ +// { dg-do run } + +extern "C" void abort (void); + +template +void +foo () +{ + extern T x; + T v, l = 2, s = 1; + #pragma omp atomic seq_cst + x = -3 + x; + #pragma omp atomic read seq_cst + v = x; + if (v != 3) + abort (); + #pragma omp atomic seq_cst update + x = 3 * 2 * 1 + x; + #pragma omp atomic read, seq_cst + v = x; + if (v != 9) + abort (); + #pragma omp atomic seq_cst, capture + v = x = x | 16; + if (v != 25) + abort (); + #pragma omp atomic capture seq_cst + v = x = x + 14 * 2 / 4; + if (v != 32) + abort (); + #pragma omp atomic seq_cst capture + v = x = 5 | x; + if (v != 37) + abort (); + #pragma omp atomic capture, seq_cst + v = x = 40 + 12 - 2 - 7 - x; + if (v != 6) + abort (); + #pragma omp atomic seq_cst read + v = x; + if (v != 6) + abort (); + #pragma omp atomic capture seq_cst + { v = x; x = 3 + x; } + if (v != 6) + abort (); + #pragma omp atomic seq_cst capture + { v = x; x = -1 * -1 * -1 * -1 - x; } + if (v != 9) + abort (); + #pragma omp atomic read seq_cst + v = x; + if (v != -8) + abort (); + #pragma omp atomic capture, seq_cst + { x = 2 * 2 - x; v = x; } + if (v != 12) + abort (); + #pragma omp atomic seq_cst capture + { x = 7 & x; v = x; } + if (v != 4) + abort (); + #pragma omp atomic capture seq_cst + { v = x; x = 6; } + if (v != 4) + abort (); + #pragma omp atomic read, seq_cst + v = x; + if (v != 6) + abort (); + #pragma omp atomic capture seq_cst + { v = x; x = 7 * 8 + 23; } + if (v != 6) + abort (); + #pragma omp atomic seq_cst, read + v = x; + if (v != 79) + abort (); + #pragma omp atomic capture , seq_cst + { v = x; x = 23 + 6 * 4; } + if (v != 79) + abort (); + #pragma omp atomic read seq_cst + v = x; + if (v != 47) + abort (); + #pragma omp atomic seq_cst capture + { v = x; x = l ? 17 : 12; } + if (v != 47) + abort (); + #pragma omp atomic capture seq_cst + { v = x; x = l = s++ + 3; } + if (v != 17 || l != 4 || s != 2) + abort (); + #pragma omp atomic read seq_cst + v = x; + if (v != 4) + abort (); +} + +int x = 6; + +int +main () +{ + foo (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c/atomic-17.c b/libgomp/testsuite/libgomp.c/atomic-17.c new file mode 100644 index 0000000000000..147ab26a95302 --- /dev/null +++ b/libgomp/testsuite/libgomp.c/atomic-17.c @@ -0,0 +1,99 @@ +// { dg-do run } + +extern void abort (void); +int x = 6; + +int +main () +{ + int v, l = 2, s = 1; + #pragma omp atomic seq_cst + x = -3 + x; + #pragma omp atomic read seq_cst + v = x; + if (v != 3) + abort (); + #pragma omp atomic seq_cst update + x = 3 * 2 * 1 + x; + #pragma omp atomic read, seq_cst + v = x; + if (v != 9) + abort (); + #pragma omp atomic seq_cst, capture + v = x = x | 16; + if (v != 25) + abort (); + #pragma omp atomic capture seq_cst + v = x = x + 14 * 2 / 4; + if (v != 32) + abort (); + #pragma omp atomic seq_cst capture + v = x = 5 | x; + if (v != 37) + abort (); + #pragma omp atomic capture, seq_cst + v = x = 40 + 12 - 2 - 7 - x; + if (v != 6) + abort (); + #pragma omp atomic seq_cst read + v = x; + if (v != 6) + abort (); + #pragma omp atomic capture seq_cst + { v = x; x = 3 + x; } + if (v != 6) + abort (); + #pragma omp atomic seq_cst capture + { v = x; x = -1 * -1 * -1 * -1 - x; } + if (v != 9) + abort (); + #pragma omp atomic read seq_cst + v = x; + if (v != -8) + abort (); + #pragma omp atomic capture, seq_cst + { x = 2 * 2 - x; v = x; } + if (v != 12) + abort (); + #pragma omp atomic seq_cst capture + { x = 7 & x; v = x; } + if (v != 4) + abort (); + #pragma omp atomic capture seq_cst + { v = x; x = 6; } + if (v != 4) + abort (); + #pragma omp atomic read, seq_cst + v = x; + if (v != 6) + abort (); + #pragma omp atomic capture seq_cst + { v = x; x = 7 * 8 + 23; } + if (v != 6) + abort (); + #pragma omp atomic seq_cst, read + v = x; + if (v != 79) + abort (); + #pragma omp atomic capture , seq_cst + { v = x; x = 23 + 6 * 4; } + if (v != 79) + abort (); + #pragma omp atomic read seq_cst + v = x; + if (v != 47) + abort (); + #pragma omp atomic seq_cst capture + { v = x; x = l ? 17 : 12; } + if (v != 47) + abort (); + #pragma omp atomic capture seq_cst + { v = x; x = l = s++ + 3; } + if (v != 17 || l != 4 || s != 2) + abort (); + #pragma omp atomic read seq_cst + v = x; + if (v != 4) + abort (); + return 0; +} From 5ac236d9a4b9b6be6a7771c5f514640cd220883f Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Fri, 3 May 2013 16:10:38 -0500 Subject: [PATCH 24/63] Allow "!=" in for Cilk for conditionals. Remove deprecated vectorlength clause features. Remove deprecated assert and noassert clauses. Implement vectorlength clause in OpenMP safelen terms. --- gcc/c-family/c-cilkplus.c | 34 +------ gcc/c-family/c-pragma.h | 2 - gcc/c/c-parser.c | 97 ++++++------------- gcc/gimplify.c | 4 - gcc/omp-low.c | 4 - .../cilk-plus/cilk-simd/compile/clauses1.c | 32 +++--- .../cilk-plus/cilk-simd/compile/clauses2.c | 5 +- .../gcc.dg/cilk-plus/cilk-simd/compile/for1.c | 13 ++- .../cilk-plus/cilk-simd/compile/safelen.c | 2 +- .../cilk-simd/compile/vectorlength.c | 6 +- gcc/tree-pretty-print.c | 11 --- gcc/tree.c | 8 -- gcc/tree.h | 14 +-- 13 files changed, 56 insertions(+), 176 deletions(-) diff --git a/gcc/c-family/c-cilkplus.c b/gcc/c-family/c-cilkplus.c index 46c0f49c4814c..d5df7b69a4cd3 100644 --- a/gcc/c-family/c-cilkplus.c +++ b/gcc/c-family/c-cilkplus.c @@ -261,7 +261,8 @@ c_check_cilk_loop (location_t loc, tree decl, tree cond, tree incr, tree body) return false; } bool cond_ok = false; - if (TREE_CODE (cond) == LT_EXPR + if (TREE_CODE (cond) == NE_EXPR + || TREE_CODE (cond) == LT_EXPR || TREE_CODE (cond) == LE_EXPR || TREE_CODE (cond) == GT_EXPR || TREE_CODE (cond) == GE_EXPR) @@ -304,34 +305,6 @@ c_check_cilk_loop (location_t loc, tree decl, tree cond, tree incr, tree body) static tree adjust_clauses_for_omp (tree clauses) { - unsigned int max_vlen = 0; - tree c, max_vlen_tree = NULL; - - for (c = clauses; c; c = OMP_CLAUSE_CHAIN (c)) - { - /* #pragma simd vectorlength (a, b, c) - is equivalent to: - #pragma omp simd safelen (max (a, b, c)). */ - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_CILK_VECTORLENGTH) - { - unsigned int vlen; - - vlen = TREE_INT_CST_LOW (OMP_CLAUSE_CILK_VECTORLENGTH_EXPR (c)); - if (vlen > max_vlen) - { - max_vlen = vlen; - max_vlen_tree = OMP_CLAUSE_CILK_VECTORLENGTH_EXPR (c); - } - } - } - if (max_vlen) - { - c = build_omp_clause (EXPR_LOCATION (max_vlen_tree), - OMP_CLAUSE_SAFELEN); - OMP_CLAUSE_SAFELEN_EXPR (c) = max_vlen_tree; - OMP_CLAUSE_CHAIN (c) = clauses; - clauses = c; - } return clauses; } @@ -441,8 +414,7 @@ c_finish_cilk_clauses (tree clauses) case OMP_CLAUSE_REDUCTION: break; - case OMP_CLAUSE_CILK_ASSERT: - case OMP_CLAUSE_CILK_VECTORLENGTH: + case OMP_CLAUSE_SAFELEN: goto next; default: diff --git a/gcc/c-family/c-pragma.h b/gcc/c-family/c-pragma.h index 2ff5a00ae8b22..1f84a78dfd6d7 100644 --- a/gcc/c-family/c-pragma.h +++ b/gcc/c-family/c-pragma.h @@ -115,8 +115,6 @@ typedef enum pragma_omp_clause { /* All Cilk Plus #pragma omp clauses. */ typedef enum pragma_cilk_clause { PRAGMA_CILK_CLAUSE_NONE = 0, - PRAGMA_CILK_CLAUSE_NOASSERT, - PRAGMA_CILK_CLAUSE_ASSERT, PRAGMA_CILK_CLAUSE_VECTORLENGTH, PRAGMA_CILK_CLAUSE_LINEAR, PRAGMA_CILK_CLAUSE_PRIVATE, diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index b27354a6efc89..dbaee43c025cc 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -11580,77 +11580,38 @@ c_parser_cilk_verify_simd (c_parser *parser, } /* Cilk Plus: - assert */ - -static tree -c_parser_cilk_clause_assert (c_parser *parser, tree clauses) -{ - check_no_duplicate_clause (clauses, OMP_CLAUSE_CILK_ASSERT, "assert"); - - location_t loc = c_parser_peek_token (parser)->location; - tree c = build_omp_clause (loc, OMP_CLAUSE_CILK_ASSERT); - OMP_CLAUSE_CHAIN (c) = clauses; - return c; -} - -/* Cilk Plus: - noassert */ - -static tree -c_parser_cilk_clause_noassert (c_parser *parser ATTRIBUTE_UNUSED, - tree clauses) -{ - /* Only check that we don't already have an assert clause. */ - check_no_duplicate_clause (clauses, OMP_CLAUSE_CILK_ASSERT, "assert"); - - return clauses; -} - -/* Cilk Plus: - vectorlength ( constant-expression-list ) - - constant-expression-list: - constant-expression - constant-expression-list , constant-expression */ + vectorlength ( constant-expression ) */ static tree c_parser_cilk_clause_vectorlength (c_parser *parser, tree clauses) { - /* Multiple vectorlength clauses are allowed and treated as a - union, so we don't check for a duplicate clause. */ + /* The vectorlength clause behaves exactly like OpenMP's safelen + clause. Represent it in OpenMP terms. */ + check_no_duplicate_clause (clauses, OMP_CLAUSE_SAFELEN, "vectorlength"); if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) return clauses; location_t loc = c_parser_peek_token (parser)->location; - while (true) + tree expr = c_parser_expr_no_commas (parser, NULL).value; + expr = c_fully_fold (expr, false, NULL); + + if (!TREE_TYPE (expr) + || !TREE_CONSTANT (expr) + || !INTEGRAL_TYPE_P (TREE_TYPE (expr))) + error_at (loc, "vectorlength must be an integer constant"); + else if (exact_log2 (TREE_INT_CST_LOW (expr)) == -1) + error_at (loc, "vectorlength must be a power of 2"); + else { - tree expr = c_parser_expr_no_commas (parser, NULL).value; - expr = c_fully_fold (expr, false, NULL); - - if (!TREE_TYPE (expr) - || !TREE_CONSTANT (expr) - || !INTEGRAL_TYPE_P (TREE_TYPE (expr))) - error_at (loc, "vectorlength must be an integer constant"); - else if (exact_log2 (TREE_INT_CST_LOW (expr)) == -1) - error_at (loc, "vectorlength must be a power of 2"); - else - { - tree u = build_omp_clause (loc, OMP_CLAUSE_CILK_VECTORLENGTH); - OMP_CLAUSE_CILK_VECTORLENGTH_EXPR (u) = expr; - OMP_CLAUSE_CHAIN (u) = clauses; - clauses = u; - } - - if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) - { - c_parser_consume_token (parser); - return clauses; - } - if (c_parser_next_token_is (parser, CPP_COMMA)) - c_parser_consume_token (parser); + tree u = build_omp_clause (loc, OMP_CLAUSE_SAFELEN); + OMP_CLAUSE_SAFELEN_EXPR (u) = expr; + OMP_CLAUSE_CHAIN (u) = clauses; + clauses = u; } + c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + return clauses; } @@ -11752,11 +11713,7 @@ c_parser_cilk_clause_name (c_parser *parser) const char *p = IDENTIFIER_POINTER (token->value); - if (!strcmp (p, "noassert")) - result = PRAGMA_CILK_CLAUSE_NOASSERT; - else if (!strcmp (p, "assert")) - result = PRAGMA_CILK_CLAUSE_ASSERT; - else if (!strcmp (p, "vectorlength")) + if (!strcmp (p, "vectorlength")) result = PRAGMA_CILK_CLAUSE_VECTORLENGTH; else if (!strcmp (p, "linear")) result = PRAGMA_CILK_CLAUSE_LINEAR; @@ -11791,12 +11748,6 @@ c_parser_cilk_all_clauses (c_parser *parser) switch (c_kind) { - case PRAGMA_CILK_CLAUSE_NOASSERT: - clauses = c_parser_cilk_clause_noassert (parser, clauses); - break; - case PRAGMA_CILK_CLAUSE_ASSERT: - clauses = c_parser_cilk_clause_assert (parser, clauses); - break; case PRAGMA_CILK_CLAUSE_VECTORLENGTH: clauses = c_parser_cilk_clause_vectorlength (parser, clauses); break; @@ -11809,6 +11760,12 @@ c_parser_cilk_all_clauses (c_parser *parser) break; case PRAGMA_CILK_CLAUSE_FIRSTPRIVATE: /* Use the OpenMP counterpart. */ + /* FIXME: Note from the Cilk Plus forum: "For the time + being, assume that firstprivate refers to the vector + lane. (This is what is implemented in the icc compiler.) + As we update the spec, we will harmonize these + definitions with OpenMP 4, possibly deprecating + firstprivate." */ clauses = c_parser_omp_clause_firstprivate (parser, clauses); break; case PRAGMA_CILK_CLAUSE_LASTPRIVATE: diff --git a/gcc/gimplify.c b/gcc/gimplify.c index e81a9a2d16521..7488706de0ed1 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -6337,8 +6337,6 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, case OMP_CLAUSE_MERGEABLE: case OMP_CLAUSE_PROC_BIND: case OMP_CLAUSE_SAFELEN: - case OMP_CLAUSE_CILK_ASSERT: - case OMP_CLAUSE_CILK_VECTORLENGTH: break; case OMP_CLAUSE_ALIGNED: @@ -6567,8 +6565,6 @@ gimplify_adjust_omp_clauses (tree *list_p) case OMP_CLAUSE_MERGEABLE: case OMP_CLAUSE_PROC_BIND: case OMP_CLAUSE_SAFELEN: - case OMP_CLAUSE_CILK_ASSERT: - case OMP_CLAUSE_CILK_VECTORLENGTH: break; default: diff --git a/gcc/omp-low.c b/gcc/omp-low.c index 3a0451148dfd0..b320817b5674e 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -1491,8 +1491,6 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) case OMP_CLAUSE_MERGEABLE: case OMP_CLAUSE_PROC_BIND: case OMP_CLAUSE_SAFELEN: - case OMP_CLAUSE_CILK_ASSERT: - case OMP_CLAUSE_CILK_VECTORLENGTH: break; case OMP_CLAUSE_ALIGNED: @@ -1556,8 +1554,6 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) case OMP_CLAUSE_PROC_BIND: case OMP_CLAUSE_SAFELEN: case OMP_CLAUSE_ALIGNED: - case OMP_CLAUSE_CILK_ASSERT: - case OMP_CLAUSE_CILK_VECTORLENGTH: break; default: diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/clauses1.c b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/clauses1.c index ae01db3abf5fc..d0a2f7965923a 100644 --- a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/clauses1.c +++ b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/clauses1.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O3 -std=c99 -fcilkplus" } */ +/* { dg-options "-O3 -std=c99 -fcilkplus -Werror -Wunknown-pragmas" } */ volatile int *a, *b; @@ -7,17 +7,9 @@ void foo() { int i, j, k; -#pragma simd assert aoeu /* { dg-error "expected '#pragma simd' clause" } */ - for (int i=0; i < 1000; ++i) - a[i] = b[j]; - -#pragma simd noassert aoeu /* { dg-error "expected '#pragma simd' clause" } */ - for (int i=0; i < 1000; ++i) - a[i] = b[j]; - -#pragma simd assert noassert /* { dg-error "too many 'assert' clauses" } */ - for (int i=0; i < 1000; ++i) - a[i] = b[j]; +#pragma simd assert /* { dg-error "expected '#pragma simd' clause" } */ + for (i=0; i < 100; ++i) + a[i] = b[i]; #pragma simd vectorlength /* { dg-error "expected '\\('" } */ for (int i=0; i < 1000; ++i) @@ -31,7 +23,7 @@ void foo() for (int i=0; i < 1000; ++i) a[i] = b[j]; -#pragma simd vectorlength(4,8) +#pragma simd vectorlength(4,8) /* { dg-error "expected '\\)'" } */ for (int i=0; i < 1000; ++i) a[i] = b[j]; @@ -47,12 +39,6 @@ void foo() for (int i=0; i < 1000; ++i) a[i] = b[j]; -#pragma simd linear(blah2, 36) - /* { dg-error "'blah2' undeclared" "undeclared" { target *-*-* } 50 } */ - /* { dg-error "expected '\\)'" "expected" { target *-*-* } 50 } */ - for (int i=0; i < 1000; ++i) - a[i] = b[j]; - #pragma simd linear(j, 36, k) /* { dg-error "expected '\\)'" } */ for (int i=0; i < 1000; ++i) a[i] = b[j]; @@ -78,7 +64,13 @@ void foo() a[i] = b[j]; // And now everyone in unison! -#pragma simd assert linear(j : 4) vectorlength(4) +#pragma simd linear(j : 4) vectorlength(4) for (i=0; i < 1000; ++i) a[i] = b[j]; + +#pragma simd linear(blah2, 36) + /* { dg-error "'blah2' undeclared" "undeclared" { target *-*-* } 71 } */ + /* { dg-error "expected '\\)'" "expected" { target *-*-* } 71 } */ + for (int i=0; i < 1000; ++i) + a[i] = b[j]; } diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/clauses2.c b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/clauses2.c index 6be6085c54bb4..ca99ca879799a 100644 --- a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/clauses2.c +++ b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/clauses2.c @@ -7,13 +7,12 @@ void foo() { int i, j, k; -#pragma simd assert linear(j : 4, k) vectorlength(4) +#pragma simd linear(j : 4, k) vectorlength(4) for (i=0; i < 1000; ++i) a[i] = b[j]; } /* { dg-final { scan-tree-dump-times "linear\\(j:4\\)" 1 "original" } } */ /* { dg-final { scan-tree-dump-times "linear\\(k:1\\)" 1 "original" } } */ -/* { dg-final { scan-tree-dump-times "cilk_vectorlength\\(4\\)" 1 "original" } } */ -/* { dg-final { scan-tree-dump-times "cilk_assert" 1 "original" } } */ +/* { dg-final { scan-tree-dump-times "safelen\\(4\\)" 1 "original" } } */ /* { dg-final { cleanup-tree-dump "original" } } */ diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for1.c b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for1.c index 044f1c98ff45b..f8cc5588f1e3c 100644 --- a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for1.c +++ b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for1.c @@ -2,6 +2,7 @@ /* { dg-options "-O3 -std=c99 -fcilkplus" } */ int *a, *b, *c; +int something; void foo() { @@ -78,15 +79,19 @@ void foo() for (i=0; (char)i < 1234; ++i) /* { dg-error "invalid controlling predicate" } */ a[i] = b[i]; - // icc disallows !=, we'll do the same. #pragma simd - for (i=255; i != 5; --i) /* { dg-error "invalid controlling predicate" } */ + for (i=255; i != something; --i) a[i] = b[i]; // This condition gets folded into "i != 0" by - // c_parser_cilk_for_statement(). Disallow != like above. + // c_parser_cilk_for_statement(). This is allowed as per the "!=" + // allowance above. #pragma simd - for (i=100; i; --i) /* { dg-error "invalid controlling predicate" } */ + for (i=100; i; --i) + a[i] = b[i]; + +#pragma simd + for (i=100; i != 5; i += something) a[i] = b[i]; // Increment must be on the induction variable. diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/safelen.c b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/safelen.c index 33a43138dd6ec..430aa416506ef 100644 --- a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/safelen.c +++ b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/safelen.c @@ -6,7 +6,7 @@ int *a, *b; void foo() { int i; -#pragma simd vectorlength(4, 8) +#pragma simd vectorlength(8) for (i=0; i < 1000; ++i) a[i] = b[i]; } diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/vectorlength.c b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/vectorlength.c index 4661e9b576ac8..4bff17ddf84ab 100644 --- a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/vectorlength.c +++ b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/vectorlength.c @@ -12,15 +12,11 @@ struct someclass { void foo() { int i; -#pragma simd vectorlength(4) vectorlength(8) +#pragma simd vectorlength(4) vectorlength(8) /* { dg-error "too many 'vectorlength' clauses" } */ for (i=0; i < N; ++i) a[i] = b[i]; #pragma simd vectorlength(3) /* { dg-error "must be a power of 2" } */ for (i=0; i < N; ++i) a[i] = b[i]; - -#pragma simd vectorlength(4) vectorlength(8, 16) - for (i=0; i < N; ++i) - a[i] = b[i]; } diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c index 4a0c74e3f77de..0c3fec75d04c5 100644 --- a/gcc/tree-pretty-print.c +++ b/gcc/tree-pretty-print.c @@ -586,17 +586,6 @@ dump_omp_clause (pretty_printer *buffer, tree clause, int spc, int flags) pp_string (buffer, "taskgroup"); break; - case OMP_CLAUSE_CILK_ASSERT: - pp_string (buffer, "cilk_assert"); - break; - - case OMP_CLAUSE_CILK_VECTORLENGTH: - pp_string (buffer, "cilk_vectorlength("); - dump_generic_node (buffer, OMP_CLAUSE_CILK_VECTORLENGTH_EXPR (clause), - spc, flags, false); - pp_character (buffer, ')'); - break; - default: /* Should never happen. */ dump_generic_node (buffer, clause, spc, flags, false); diff --git a/gcc/tree.c b/gcc/tree.c index 536539b29dfdc..36fadffffb15a 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -264,8 +264,6 @@ unsigned const char omp_clause_num_ops[] = 0, /* OMP_CLAUSE_PARALLEL */ 0, /* OMP_CLAUSE_SECTIONS */ 0 /* OMP_CLAUSE_TASKGROUP */ - , 0, /* OMP_CLAUSE_CILK_ASSERT */ - 1 /* OMP_CLAUSE_CILK_VECTORLENGTH */ }; const char * const omp_clause_code_name[] = @@ -307,8 +305,6 @@ const char * const omp_clause_code_name[] = "parallel", "sections", "taskgroup" - , "cilk_assert", - "cilk_vectorlength" }; @@ -10813,7 +10809,6 @@ walk_tree_1 (tree *tp, walk_tree_fn func, void *data, case OMP_CLAUSE_DIST_SCHEDULE: case OMP_CLAUSE_SAFELEN: case OMP_CLAUSE_SIMDLEN: - case OMP_CLAUSE_CILK_VECTORLENGTH: WALK_SUBTREE (OMP_CLAUSE_OPERAND (*tp, 0)); /* FALLTHRU */ @@ -10858,9 +10853,6 @@ walk_tree_1 (tree *tp, walk_tree_fn func, void *data, WALK_SUBTREE_TAIL (OMP_CLAUSE_CHAIN (*tp)); } - case OMP_CLAUSE_CILK_ASSERT: - break; - default: gcc_unreachable (); } diff --git a/gcc/tree.h b/gcc/tree.h index 938f4b6d34e6a..3cc3881295025 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -446,13 +446,7 @@ enum omp_clause_code OMP_CLAUSE_SECTIONS, /* OpenMP clause: taskgroup. */ - OMP_CLAUSE_TASKGROUP, - - /* Cilk Plus clause: assert. */ - OMP_CLAUSE_CILK_ASSERT, - - /* Cilk Plus clause: vectorlength (constant-expression-list). */ - OMP_CLAUSE_CILK_VECTORLENGTH + OMP_CLAUSE_TASKGROUP }; /* The definition of tree nodes fills the next several pages. */ @@ -1867,12 +1861,6 @@ extern void protected_set_expr_location (tree, location_t); OMP_CLAUSE_PRIVATE, \ OMP_CLAUSE_MAP), 0) -/* In an OMP_SIMD_CLAUSE_CILK_VECTORLENGTH, one vectorlength - expression. */ -#define OMP_CLAUSE_CILK_VECTORLENGTH_EXPR(NODE) \ - OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK \ - (NODE, OMP_CLAUSE_CILK_VECTORLENGTH), 0) - #define OMP_CLAUSE_HAS_LOCATION(NODE) \ (LOCATION_LOCUS ((OMP_CLAUSE_CHECK (NODE))->omp_clause.locus) \ != UNKNOWN_LOCATION) From 7d2ab0945b63675d33a6345bcdcdc98abad5fe83 Mon Sep 17 00:00:00 2001 From: jakub Date: Thu, 9 May 2013 15:07:52 +0000 Subject: [PATCH 25/63] * tree.c (omp_declare_simd_clauses_equal): New function. (attribute_value_equal): Call it for -fopenmp if TREE_VALUE of the attributes are both OMP_CLAUSEs. * tree.h (omp_declare_simd_clauses_equal): Declare. c-family/ * c-common.c (c_common_attribute_table): Add "omp declare simd" attribute. (handle_omp_declare_simd_attribute): New function. * c-common.h (c_omp_declare_simd_clauses_to_numbers, c_omp_declare_simd_clauses_to_decls): Declare. * c-omp.c (c_omp_declare_simd_clause_cmp, c_omp_declare_simd_clauses_to_numbers, c_omp_declare_simd_clauses_to_decls): New functions. cp/ * cp-tree.h (cp_decl_specifier_seq): Add omp_declare_simd_clauses field. (finish_omp_declare_simd): Declare. * decl2.c (is_late_template_attribute): Return true for "omp declare simd" attribute. (cp_check_const_attributes): Don't check TREE_VALUE of arg if arg isn't a TREE_LIST. * decl.c (grokfndecl): Add omp_declare_simd_clauses argument, call finish_omp_declare_simd if non-NULL. (grokdeclarator): Pass it declspecs->omp_declare_simd_clauses to grokfndecl. * pt.c (apply_late_template_attributes): Handle "omp declare simd" attribute specially. (tsubst_omp_clauses): Add declare_simd argument, don't call finish_omp_clauses if it is set. Handle OpenMP 4.0 clauses. (tsubst_expr): Adjust tsubst_omp_clauses callers. * semantics.c (finish_omp_clauses): Diagnose inbranch notinbranch. (finish_omp_declare_simd): New function. * parser.h (struct cp_parser): Add omp_declare_simd_clauses field. * parser.c (cp_ensure_no_omp_declare_simd, cp_finish_omp_declare_simd): New functions. (enum pragma_context): Add pragma_member and pragma_objc_icode. (cp_parser_linkage_specification, cp_parser_namespace_definition, cp_parser_class_specifier_1): Call cp_ensure_no_omp_declare_simd. (cp_parser_init_declarator, cp_parser_member_declaration, cp_parser_function_definition_from_specifiers_and_declarator, cp_parser_save_member_function_body): Copy parser->omp_declare_simd_clauses to decl_specifiers->omp_declare_simd_clauses, call cp_finish_omp_declare_simd. (cp_parser_member_specification_opt): Pass pragma_member instead of pragma_external to cp_parser_pragma. (cp_parser_objc_interstitial_code): Pass pragma_objc_icode instead of pragma_external to cp_parser_pragma. (cp_parser_omp_var_list_no_open): If parser->omp_declare_simd_clauses, just cp_parser_identifier the argument names. (cp_parser_omp_all_clauses): Don't call finish_omp_clauses for parser->omp_declare_simd_clauses. (OMP_DECLARE_SIMD_CLAUSE_MASK): Define. (cp_parser_omp_declare_simd, cp_parser_omp_declare): New functions. (cp_parser_pragma): Call cp_ensure_no_omp_declare_simd. Handle PRAGMA_OMP_DECLARE_REDUCTION. Replace == pragma_external with != pragma_stmt and != pragma_compound. testsuite/ * g++.dg/gomp/declare-simd-1.C: New test. * g++.dg/gomp/declare-simd-2.C: New test. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gomp-4_0-branch@198739 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog.gomp | 7 + gcc/c-family/ChangeLog.gomp | 11 + gcc/c-family/c-common.c | 13 ++ gcc/c-family/c-common.h | 2 + gcc/c-family/c-omp.c | 94 +++++++++ gcc/cp/ChangeLog.gomp | 46 +++++ gcc/cp/cp-tree.h | 5 + gcc/cp/decl.c | 12 +- gcc/cp/decl2.c | 8 + gcc/cp/parser.c | 216 +++++++++++++++++--- gcc/cp/parser.h | 9 + gcc/cp/pt.c | 70 +++++-- gcc/cp/semantics.c | 98 ++++++++- gcc/testsuite/ChangeLog.gomp | 5 + gcc/testsuite/g++.dg/gomp/declare-simd-1.C | 224 +++++++++++++++++++++ gcc/testsuite/g++.dg/gomp/declare-simd-2.C | 60 ++++++ gcc/tree.c | 49 +++++ gcc/tree.h | 4 + 18 files changed, 891 insertions(+), 42 deletions(-) create mode 100644 gcc/testsuite/g++.dg/gomp/declare-simd-1.C create mode 100644 gcc/testsuite/g++.dg/gomp/declare-simd-2.C diff --git a/gcc/ChangeLog.gomp b/gcc/ChangeLog.gomp index 3802a119cfa14..88291c65b6d17 100644 --- a/gcc/ChangeLog.gomp +++ b/gcc/ChangeLog.gomp @@ -1,3 +1,10 @@ +2013-05-09 Jakub Jelinek + + * tree.c (omp_declare_simd_clauses_equal): New function. + (attribute_value_equal): Call it for -fopenmp if + TREE_VALUE of the attributes are both OMP_CLAUSEs. + * tree.h (omp_declare_simd_clauses_equal): Declare. + 2013-04-30 Jakub Jelinek * gimple-pretty-print.c (dump_gimple_omp_atomic_load, diff --git a/gcc/c-family/ChangeLog.gomp b/gcc/c-family/ChangeLog.gomp index 9ed6de1a55f73..f8e095b90c419 100644 --- a/gcc/c-family/ChangeLog.gomp +++ b/gcc/c-family/ChangeLog.gomp @@ -1,3 +1,14 @@ +2013-05-09 Jakub Jelinek + + * c-common.c (c_common_attribute_table): Add "omp declare simd" + attribute. + (handle_omp_declare_simd_attribute): New function. + * c-common.h (c_omp_declare_simd_clauses_to_numbers, + c_omp_declare_simd_clauses_to_decls): Declare. + * c-omp.c (c_omp_declare_simd_clause_cmp, + c_omp_declare_simd_clauses_to_numbers, + c_omp_declare_simd_clauses_to_decls): New functions. + 2013-04-30 Jakub Jelinek * c-omp.c (c_finish_omp_atomic): Add seq_cst argument, store it diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 3d1144e5edd48..f28c1f46e4328 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -368,6 +368,8 @@ static tree handle_optimize_attribute (tree *, tree, tree, int, bool *); static tree ignore_attribute (tree *, tree, tree, int, bool *); static tree handle_no_split_stack_attribute (tree *, tree, tree, int, bool *); static tree handle_fnspec_attribute (tree *, tree, tree, int, bool *); +static tree handle_omp_declare_simd_attribute (tree *, tree, tree, int, + bool *); static void check_function_nonnull (tree, int, tree *); static void check_nonnull_arg (void *, tree, unsigned HOST_WIDE_INT); @@ -738,6 +740,8 @@ const struct attribute_spec c_common_attribute_table[] = The name contains space to prevent its usage in source code. */ { "fn spec", 1, 1, false, true, true, handle_fnspec_attribute, false }, + { "omp declare simd", 0, -1, true, false, false, + handle_omp_declare_simd_attribute, false }, { NULL, 0, 0, false, false, false, NULL, false } }; @@ -7958,6 +7962,15 @@ handle_fnspec_attribute (tree *node ATTRIBUTE_UNUSED, tree ARG_UNUSED (name), return NULL_TREE; } +/* Handle an "omp declare simd" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_omp_declare_simd_attribute (tree *, tree, tree, int, bool *) +{ + return NULL_TREE; +} + /* Handle a "returns_twice" attribute; arguments as in struct attribute_spec.handler. */ diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index ea2600cda2164..78ace779cb266 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -1042,6 +1042,8 @@ extern void c_finish_omp_taskyield (location_t); extern tree c_finish_omp_for (location_t, enum tree_code, tree, tree, tree, tree, tree, tree); extern void c_split_parallel_clauses (location_t, tree, tree *, tree *); +extern tree c_omp_declare_simd_clauses_to_numbers (tree, tree); +extern void c_omp_declare_simd_clauses_to_decls (tree, tree); extern enum omp_clause_default_kind c_omp_predetermined_sharing (tree); /* Not in c-omp.c; provided by the front end. */ diff --git a/gcc/c-family/c-omp.c b/gcc/c-family/c-omp.c index d8edcf8145f5a..941854bf36725 100644 --- a/gcc/c-family/c-omp.c +++ b/gcc/c-family/c-omp.c @@ -637,6 +637,100 @@ c_split_parallel_clauses (location_t loc, tree clauses, } } +/* qsort callback to compare #pragma omp declare simd clauses. */ + +static int +c_omp_declare_simd_clause_cmp (const void *p, const void *q) +{ + tree a = *(const tree *) p; + tree b = *(const tree *) q; + if (OMP_CLAUSE_CODE (a) != OMP_CLAUSE_CODE (b)) + { + if (OMP_CLAUSE_CODE (a) > OMP_CLAUSE_CODE (b)) + return -1; + return 1; + } + if (OMP_CLAUSE_CODE (a) != OMP_CLAUSE_SIMDLEN + && OMP_CLAUSE_CODE (a) != OMP_CLAUSE_INBRANCH + && OMP_CLAUSE_CODE (a) != OMP_CLAUSE_NOTINBRANCH) + { + int c = tree_low_cst (OMP_CLAUSE_DECL (a), 0); + int d = tree_low_cst (OMP_CLAUSE_DECL (b), 0); + if (c < d) + return 1; + if (c > d) + return -1; + } + return 0; +} + +/* Change PARM_DECLs in OMP_CLAUSE_DECL of #pragma omp declare simd + CLAUSES on FNDECL into argument indexes and sort them. */ + +tree +c_omp_declare_simd_clauses_to_numbers (tree fndecl, tree clauses) +{ + tree c; + vec clvec = vNULL; + + for (c = clauses; c; c = OMP_CLAUSE_CHAIN (c)) + { + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_SIMDLEN + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_INBRANCH + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_NOTINBRANCH) + { + tree decl = OMP_CLAUSE_DECL (c); + tree arg; + int idx; + for (arg = DECL_ARGUMENTS (fndecl), idx = 0; arg; + arg = TREE_CHAIN (arg), idx++) + if (arg == decl) + break; + if (arg == NULL_TREE) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qD is not an argument of %qD", decl, fndecl); + continue; + } + OMP_CLAUSE_DECL (c) = build_int_cst (integer_type_node, idx); + } + clvec.safe_push (c); + } + if (!clvec.is_empty ()) + { + unsigned int len = clvec.length (), i; + clvec.qsort (c_omp_declare_simd_clause_cmp); + clauses = clvec[0]; + for (i = 0; i < len; i++) + OMP_CLAUSE_CHAIN (clvec[i]) = (i < len - 1) ? clvec[i + 1] : NULL_TREE; + } + clvec.release (); + return clauses; +} + +/* Change argument indexes in CLAUSES of FNDECL back to PARM_DECLs. */ + +void +c_omp_declare_simd_clauses_to_decls (tree fndecl, tree clauses) +{ + tree c; + + for (c = clauses; c; c = OMP_CLAUSE_CHAIN (c)) + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_SIMDLEN + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_INBRANCH + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_NOTINBRANCH) + { + int idx = tree_low_cst (OMP_CLAUSE_DECL (c), 0), i; + tree arg; + for (arg = DECL_ARGUMENTS (fndecl), i = 0; arg; + arg = TREE_CHAIN (arg), i++) + if (i == idx) + break; + gcc_assert (arg); + OMP_CLAUSE_DECL (c) = arg; + } +} + /* True if OpenMP sharing attribute of DECL is predetermined. */ enum omp_clause_default_kind diff --git a/gcc/cp/ChangeLog.gomp b/gcc/cp/ChangeLog.gomp index aa7d736e47d0e..69be3ded3780b 100644 --- a/gcc/cp/ChangeLog.gomp +++ b/gcc/cp/ChangeLog.gomp @@ -1,3 +1,49 @@ +2013-05-09 Jakub Jelinek + + * cp-tree.h (cp_decl_specifier_seq): Add omp_declare_simd_clauses + field. + (finish_omp_declare_simd): Declare. + * decl2.c (is_late_template_attribute): Return true for + "omp declare simd" attribute. + (cp_check_const_attributes): Don't check TREE_VALUE of arg if + arg isn't a TREE_LIST. + * decl.c (grokfndecl): Add omp_declare_simd_clauses argument, call + finish_omp_declare_simd if non-NULL. + (grokdeclarator): Pass it declspecs->omp_declare_simd_clauses + to grokfndecl. + * pt.c (apply_late_template_attributes): Handle "omp declare simd" + attribute specially. + (tsubst_omp_clauses): Add declare_simd argument, don't call + finish_omp_clauses if it is set. Handle OpenMP 4.0 clauses. + (tsubst_expr): Adjust tsubst_omp_clauses callers. + * semantics.c (finish_omp_clauses): Diagnose inbranch notinbranch. + (finish_omp_declare_simd): New function. + * parser.h (struct cp_parser): Add omp_declare_simd_clauses field. + * parser.c (cp_ensure_no_omp_declare_simd, + cp_finish_omp_declare_simd): New functions. + (enum pragma_context): Add pragma_member and pragma_objc_icode. + (cp_parser_linkage_specification, cp_parser_namespace_definition, + cp_parser_class_specifier_1): Call cp_ensure_no_omp_declare_simd. + (cp_parser_init_declarator, cp_parser_member_declaration, + cp_parser_function_definition_from_specifiers_and_declarator, + cp_parser_save_member_function_body): Copy + parser->omp_declare_simd_clauses to + decl_specifiers->omp_declare_simd_clauses, call + cp_finish_omp_declare_simd. + (cp_parser_member_specification_opt): Pass pragma_member instead + of pragma_external to cp_parser_pragma. + (cp_parser_objc_interstitial_code): Pass pragma_objc_icode instead + of pragma_external to cp_parser_pragma. + (cp_parser_omp_var_list_no_open): If parser->omp_declare_simd_clauses, + just cp_parser_identifier the argument names. + (cp_parser_omp_all_clauses): Don't call finish_omp_clauses for + parser->omp_declare_simd_clauses. + (OMP_DECLARE_SIMD_CLAUSE_MASK): Define. + (cp_parser_omp_declare_simd, cp_parser_omp_declare): New functions. + (cp_parser_pragma): Call cp_ensure_no_omp_declare_simd. Handle + PRAGMA_OMP_DECLARE_REDUCTION. Replace == pragma_external with + != pragma_stmt and != pragma_compound. + 2013-04-30 Jakub Jelinek * pt.c (tsubst_expr): Pass OMP_ATOMIC_SEQ_CST to finish_omp_atomic. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index f99a8e67a4850..38f68dc57a172 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -4745,6 +4745,10 @@ typedef struct cp_decl_specifier_seq { /* If non-NULL, a built-in type that the user attempted to redefine to some other type. */ tree redefined_builtin_type; + /* When parsing #pragma omp declare simd, this is a vector of + the clauses, each tree is either NULL_TREE, or OMP_CLAUSE + with optional chain of other clauses. */ + vec *omp_declare_simd_clauses; /* The storage class specified -- or sc_none if no storage class was explicitly specified. */ cp_storage_class storage_class; @@ -5702,6 +5706,7 @@ extern void simplify_aggr_init_expr (tree *); extern void finalize_nrv (tree *, tree, tree); extern void note_decl_for_pch (tree); extern tree finish_omp_clauses (tree); +extern void finish_omp_declare_simd (tree, vec *); extern void finish_omp_threadprivate (tree); extern tree begin_omp_structured_block (void); extern tree finish_omp_structured_block (tree); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index facaae7ff19c3..55ec240747593 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -7323,7 +7323,8 @@ grokfndecl (tree ctype, int template_count, tree in_namespace, tree* attrlist, - location_t location) + location_t location, + vec *omp_declare_simd_clauses) { tree decl; int staticp = ctype && TREE_CODE (type) == FUNCTION_TYPE; @@ -7594,6 +7595,9 @@ grokfndecl (tree ctype, if (TYPE_NOTHROW_P (type) || nothrow_libfn_p (decl)) TREE_NOTHROW (decl) = 1; + if (omp_declare_simd_clauses) + finish_omp_declare_simd (decl, omp_declare_simd_clauses); + /* Caller will do the rest of this. */ if (check < 0) return decl; @@ -10416,7 +10420,8 @@ grokdeclarator (const cp_declarator *declarator, inlinep | (2 * constexpr_p), sfk, funcdef_flag, template_count, in_namespace, - attrlist, declarator->id_loc); + attrlist, declarator->id_loc, + declspecs->omp_declare_simd_clauses); decl = set_virt_specifiers (decl, virt_specifiers); if (decl == NULL_TREE) return error_mark_node; @@ -10637,7 +10642,8 @@ grokdeclarator (const cp_declarator *declarator, publicp, inlinep | (2 * constexpr_p), sfk, funcdef_flag, template_count, in_namespace, attrlist, - declarator->id_loc); + declarator->id_loc, + declspecs->omp_declare_simd_clauses); if (decl == NULL_TREE) return error_mark_node; diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 82bc6f79e5b63..b8ad5b61b5af7 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -1111,6 +1111,11 @@ is_late_template_attribute (tree attr, tree decl) if (is_attribute_p ("unused", name)) return false; + /* #pragma omp declare simd attribute needs to be always finalized. */ + if (flag_openmp + && is_attribute_p ("omp declare simd", name)) + return true; + /* If any of the arguments are dependent expressions, we can't evaluate the attribute until instantiation time. */ for (arg = args; arg; arg = TREE_CHAIN (arg)) @@ -1296,6 +1301,9 @@ cp_check_const_attributes (tree attributes) for (attr = attributes; attr; attr = TREE_CHAIN (attr)) { tree arg; + if (TREE_VALUE (attr) == NULL_TREE + || TREE_CODE (TREE_VALUE (attr)) != TREE_LIST) + continue; for (arg = TREE_VALUE (attr); arg; arg = TREE_CHAIN (arg)) { tree expr = TREE_VALUE (arg); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 943764c3d5437..232d1896b55de 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -1169,6 +1169,43 @@ cp_token_cache_new (cp_token *first, cp_token *last) return cache; } +/* Diagnose if #pragma omp declare simd isn't followed immediately + by function declaration or definition. */ + +static inline void +cp_ensure_no_omp_declare_simd (cp_parser *parser) +{ + if (parser->omp_declare_simd_clauses + && (*parser->omp_declare_simd_clauses)[0] != error_mark_node) + { + error ("%<#pragma omp declare simd%> not immediately followed by " + "function declaration or definition"); + parser->omp_declare_simd_clauses = NULL; + } +} + +/* Finalize #pragma omp declare simd clauses after FNDECL has been parsed, + and put that into "omp declare simd" attribute. */ + +static inline void +cp_finish_omp_declare_simd (cp_parser *parser, + cp_decl_specifier_seq *declspecs, tree fndecl) +{ + if (__builtin_expect (parser->omp_declare_simd_clauses != NULL, 0)) + { + if (fndecl == error_mark_node) + { + parser->omp_declare_simd_clauses = NULL; + return; + } + if (TREE_CODE (fndecl) != FUNCTION_DECL) + { + cp_ensure_no_omp_declare_simd (parser); + return; + } + } + declspecs->omp_declare_simd_clauses = NULL; +} /* Decl-specifiers. */ @@ -2149,7 +2186,13 @@ static bool cp_parser_function_transaction static tree cp_parser_transaction_cancel (cp_parser *); -enum pragma_context { pragma_external, pragma_stmt, pragma_compound }; +enum pragma_context { + pragma_external, + pragma_member, + pragma_objc_icode, + pragma_stmt, + pragma_compound +}; static bool cp_parser_pragma (cp_parser *, enum pragma_context); @@ -11154,6 +11197,8 @@ cp_parser_linkage_specification (cp_parser* parser) production. */ if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) { + cp_ensure_no_omp_declare_simd (parser); + /* Consume the `{' token. */ cp_lexer_consume_token (parser->lexer); /* Parse the declarations. */ @@ -15049,6 +15094,7 @@ cp_parser_namespace_definition (cp_parser* parser) bool has_visibility; bool is_inline; + cp_ensure_no_omp_declare_simd (parser); if (cp_lexer_next_token_is_keyword (parser->lexer, RID_INLINE)) { maybe_warn_cpp0x (CPP0X_INLINE_NAMESPACES); @@ -15978,10 +16024,12 @@ cp_parser_init_declarator (cp_parser* parser, { if (parser->in_unbraced_linkage_specification_p) decl_specifiers->storage_class = sc_extern; + decl_specifiers->omp_declare_simd_clauses + = parser->omp_declare_simd_clauses; decl = start_decl (declarator, decl_specifiers, range_for_decl_p? SD_INITIALIZED : is_initialized, - attributes, prefix_attributes, - &pushed_scope); + attributes, prefix_attributes, &pushed_scope); + cp_finish_omp_declare_simd (parser, decl_specifiers, decl); /* Adjust location of decl if declarator->id_loc is more appropriate: set, and decl wasn't merged with another decl, in which case its location would be different from input_location, and more accurate. */ @@ -16085,12 +16133,14 @@ cp_parser_init_declarator (cp_parser* parser, pop_scope (pushed_scope); pushed_scope = NULL_TREE; } + decl_specifiers->omp_declare_simd_clauses + = parser->omp_declare_simd_clauses; decl = grokfield (declarator, decl_specifiers, initializer, !is_non_constant_init, - /*asmspec=*/NULL_TREE, - prefix_attributes); + /*asmspec=*/NULL_TREE, prefix_attributes); if (decl && TREE_CODE (decl) == FUNCTION_DECL) cp_parser_save_default_args (parser, decl); + cp_finish_omp_declare_simd (parser, decl_specifiers, decl); } /* Finish processing the declaration. But, skip member @@ -18302,6 +18352,8 @@ cp_parser_class_specifier_1 (cp_parser* parser) return error_mark_node; } + cp_ensure_no_omp_declare_simd (parser); + /* Issue an error message if type-definitions are forbidden here. */ cp_parser_check_type_definition (parser); /* Remember that we are defining one more class. */ @@ -19079,7 +19131,7 @@ cp_parser_member_specification_opt (cp_parser* parser) /* Accept #pragmas at class scope. */ if (token->type == CPP_PRAGMA) { - cp_parser_pragma (parser, pragma_external); + cp_parser_pragma (parser, pragma_member); break; } @@ -19531,13 +19583,16 @@ cp_parser_member_declaration (cp_parser* parser) else if (declarator->kind == cdk_function) declarator->id_loc = token->location; - /* Create the declaration. */ - decl = grokfield (declarator, &decl_specifiers, - initializer, /*init_const_expr_p=*/true, - asm_specification, - attributes); + /* Create the declaration. */ + decl_specifiers.omp_declare_simd_clauses + = parser->omp_declare_simd_clauses; + decl = grokfield (declarator, &decl_specifiers, + initializer, /*init_const_expr_p=*/true, + asm_specification, attributes); } + cp_finish_omp_declare_simd (parser, &decl_specifiers, decl); + /* Reset PREFIX_ATTRIBUTES. */ while (attributes && TREE_CHAIN (attributes) != first_attribute) attributes = TREE_CHAIN (attributes); @@ -21666,6 +21721,8 @@ cp_parser_function_definition_from_specifiers_and_declarator bool success_p; /* Begin the function-definition. */ + decl_specifiers->omp_declare_simd_clauses + = parser->omp_declare_simd_clauses; success_p = start_function (decl_specifiers, declarator, attributes); /* The things we're about to see are not directly qualified by any @@ -21678,9 +21735,17 @@ cp_parser_function_definition_from_specifiers_and_declarator might be a friend. */ perform_deferred_access_checks (tf_warning_or_error); + if (success_p) + { + cp_finish_omp_declare_simd (parser, decl_specifiers, + current_function_decl); + parser->omp_declare_simd_clauses = NULL; + } + if (!success_p) { /* Skip the entire function. */ + decl_specifiers->omp_declare_simd_clauses = NULL; cp_parser_skip_to_end_of_block_or_statement (parser); fn = error_mark_node; } @@ -22196,7 +22261,10 @@ cp_parser_save_member_function_body (cp_parser* parser, tree fn; /* Create the FUNCTION_DECL. */ + decl_specifiers->omp_declare_simd_clauses + = parser->omp_declare_simd_clauses; fn = grokmethod (decl_specifiers, declarator, attributes); + cp_finish_omp_declare_simd (parser, decl_specifiers, fn); /* If something went badly wrong, bail out now. */ if (fn == error_mark_node) { @@ -24544,7 +24612,7 @@ cp_parser_objc_interstitial_code (cp_parser* parser) cp_parser_linkage_specification (parser); /* Handle #pragma, if any. */ else if (token->type == CPP_PRAGMA) - cp_parser_pragma (parser, pragma_external); + cp_parser_pragma (parser, pragma_objc_icode); /* Allow stray semicolons. */ else if (token->type == CPP_SEMICOLON) cp_lexer_consume_token (parser->lexer); @@ -25887,20 +25955,25 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, tree name, decl; token = cp_lexer_peek_token (parser->lexer); - name = cp_parser_id_expression (parser, /*template_p=*/false, - /*check_dependency_p=*/true, - /*template_p=*/NULL, - /*declarator_p=*/false, - /*optional_p=*/false); - if (name == error_mark_node) + if (parser->omp_declare_simd_clauses) + decl = name = cp_parser_identifier (parser); + else { - if (colon) - parser->colon_corrects_to_scope_p - = saved_colon_corrects_to_scope_p; - goto skip_comma; - } + name = cp_parser_id_expression (parser, /*template_p=*/false, + /*check_dependency_p=*/true, + /*template_p=*/NULL, + /*declarator_p=*/false, + /*optional_p=*/false); + if (name == error_mark_node) + { + if (colon) + parser->colon_corrects_to_scope_p + = saved_colon_corrects_to_scope_p; + goto skip_comma; + } - decl = cp_parser_lookup_name_simple (parser, name, token->location); + decl = cp_parser_lookup_name_simple (parser, name, token->location); + } if (decl == error_mark_node) cp_parser_name_lookup_error (parser, name, decl, NLE_NULL, token->location); @@ -27040,6 +27113,8 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask, } saw_error: cp_parser_skip_to_pragma_eol (parser, pragma_tok); + if (parser->omp_declare_simd_clauses) + return clauses; return finish_omp_clauses (clauses); } @@ -28599,6 +28674,91 @@ cp_parser_omp_cancellation_point (cp_parser *parser, cp_token *pragma_tok) finish_omp_cancellation_point (clauses); } +/* OpenMP 4.0: + # pragma omp declare simd declare-simd-clauses[optseq] new-line */ + +#define OMP_DECLARE_SIMD_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SIMDLEN) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINEAR) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALIGNED) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_UNIFORM) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_INBRANCH) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOTINBRANCH)) + +static void +cp_parser_omp_declare_simd (cp_parser *parser, cp_token *pragma_tok, + enum pragma_context context) +{ + bool first_p = parser->omp_declare_simd_clauses == NULL; + vec_safe_push (parser->omp_declare_simd_clauses, NULL_TREE); + tree clauses + = cp_parser_omp_all_clauses (parser, OMP_DECLARE_SIMD_CLAUSE_MASK, + "#pragma omp declare simd", pragma_tok); + parser->omp_declare_simd_clauses->last () = clauses; + if (first_p) + { + while (cp_lexer_next_token_is (parser->lexer, CPP_PRAGMA)) + cp_parser_pragma (parser, context); + switch (context) + { + case pragma_external: + cp_parser_declaration (parser); + break; + case pragma_member: + cp_parser_member_declaration (parser); + break; + case pragma_objc_icode: + cp_parser_block_declaration (parser, /*statement_p=*/false); + break; + default: + cp_parser_declaration_statement (parser); + break; + } + if (parser->omp_declare_simd_clauses + && (*parser->omp_declare_simd_clauses)[0] != error_mark_node + && (*parser->omp_declare_simd_clauses)[0] != integer_zero_node) + error_at (pragma_tok->location, + "%<#pragma omp declare simd%> not immediately followed by " + "function declaration or definition"); + parser->omp_declare_simd_clauses = NULL; + } +} + +/* OpenMP 4.0 + #pragma omp declare simd declare-simd-clauses[optseq] new-line + #pragma omp declare reduction (reduction-id : typename-list : expression) \ + identity-clause[opt] new-line */ + +static void +cp_parser_omp_declare (cp_parser *parser, cp_token *pragma_tok, + enum pragma_context context) +{ + 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, "simd") == 0) + { + cp_lexer_consume_token (parser->lexer); + cp_parser_omp_declare_simd (parser, pragma_tok, + context); + return; + } + cp_ensure_no_omp_declare_simd (parser); +/* if (strcmp (p, "reduction") == 0) + { + cp_lexer_consume_token (parser->lexer); + cp_parser_omp_declare_reduction (parser, pragma_tok, + context); + return; + } */ + } + cp_parser_error (parser, "expected % or %"); + cp_parser_require_pragma_eol (parser, pragma_tok); +} + /* Main entry point to OpenMP statement pragmas. */ static void @@ -28998,6 +29158,8 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context) parser->lexer->in_pragma = true; id = pragma_tok->pragma_kind; + if (id != PRAGMA_OMP_DECLARE_REDUCTION) + cp_ensure_no_omp_declare_simd (parser); switch (id) { case PRAGMA_GCC_PCH_PREPROCESS: @@ -29103,6 +29265,10 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context) cp_parser_omp_threadprivate (parser, pragma_tok); return false; + case PRAGMA_OMP_DECLARE_REDUCTION: + cp_parser_omp_declare (parser, pragma_tok, context); + return false; + case PRAGMA_OMP_ATOMIC: case PRAGMA_OMP_CRITICAL: case PRAGMA_OMP_FOR: @@ -29114,7 +29280,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context) case PRAGMA_OMP_SINGLE: case PRAGMA_OMP_TASK: case PRAGMA_OMP_TASKGROUP: - if (context == pragma_external) + if (context != pragma_stmt && context != pragma_compound) goto bad_stmt; cp_parser_omp_construct (parser, pragma_tok); return true; diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h index fe787e4c8588b..44d52cb0d7d7f 100644 --- a/gcc/cp/parser.h +++ b/gcc/cp/parser.h @@ -340,6 +340,15 @@ typedef struct GTY(()) cp_parser { /* The number of template parameter lists that apply directly to the current declaration. */ unsigned num_template_parameter_lists; + + /* When parsing #pragma omp declare simd, this is a vector of + the clauses, each tree is either NULL_TREE, or OMP_CLAUSE + with optional chain of other clauses. If error regarding + omp declare simd has been reported already, either + omp_declare_simd_clauses is set to NULL, or first element set + to error_mark_node. If a FUNCTION_DECL has been seen already, + first element is set to integer_zero_node. */ + vec *omp_declare_simd_clauses; } cp_parser; /* In parser.c */ diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index a225849359cc6..1c72cf93fb76f 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -8431,6 +8431,8 @@ can_complete_type_without_circularity (tree type) return 1; } +static tree tsubst_omp_clauses (tree, bool, tree, tsubst_flags_t, tree); + /* Apply any attributes which had to be deferred until instantiation time. DECL_P, ATTRIBUTES and ATTR_FLAGS are as cplus_decl_attributes; ARGS, COMPLAIN, IN_DECL are as tsubst. */ @@ -8472,15 +8474,28 @@ apply_late_template_attributes (tree *decl_p, tree attributes, int attr_flags, { *p = TREE_CHAIN (t); TREE_CHAIN (t) = NULL_TREE; + if (flag_openmp + && is_attribute_p ("omp declare simd", + get_attribute_name (t)) + && TREE_VALUE (t)) + { + tree clauses = TREE_VALUE (t); + clauses = tsubst_omp_clauses (clauses, true, args, + complain, in_decl); + c_omp_declare_simd_clauses_to_decls (*decl_p, clauses); + clauses = finish_omp_clauses (clauses); + TREE_VALUE (t) + = c_omp_declare_simd_clauses_to_numbers (*decl_p, clauses); + } /* If the first attribute argument is an identifier, don't pass it through tsubst. Attributes like mode, format, cleanup and several target specific attributes expect it unmodified. */ - if (TREE_VALUE (t) - && TREE_CODE (TREE_VALUE (t)) == TREE_LIST - && TREE_VALUE (TREE_VALUE (t)) - && (TREE_CODE (TREE_VALUE (TREE_VALUE (t))) - == IDENTIFIER_NODE)) + else if (TREE_VALUE (t) + && TREE_CODE (TREE_VALUE (t)) == TREE_LIST + && TREE_VALUE (TREE_VALUE (t)) + && (TREE_CODE (TREE_VALUE (TREE_VALUE (t))) + == IDENTIFIER_NODE)) { tree chain = tsubst_expr (TREE_CHAIN (TREE_VALUE (t)), args, complain, @@ -12562,8 +12577,8 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl) /* Like tsubst_copy, but specifically for OpenMP clauses. */ static tree -tsubst_omp_clauses (tree clauses, tree args, tsubst_flags_t complain, - tree in_decl) +tsubst_omp_clauses (tree clauses, bool declare_simd, + tree args, tsubst_flags_t complain, tree in_decl) { tree new_clauses = NULL, nc, oc; @@ -12596,22 +12611,52 @@ tsubst_omp_clauses (tree clauses, tree args, tsubst_flags_t complain, case OMP_CLAUSE_SCHEDULE: case OMP_CLAUSE_COLLAPSE: case OMP_CLAUSE_FINAL: + case OMP_CLAUSE_DEPEND: + case OMP_CLAUSE_FROM: + case OMP_CLAUSE_TO: + case OMP_CLAUSE_UNIFORM: + case OMP_CLAUSE_MAP: + case OMP_CLAUSE_DEVICE: + case OMP_CLAUSE_DIST_SCHEDULE: + case OMP_CLAUSE_NUM_TEAMS: + case OMP_CLAUSE_SAFELEN: + case OMP_CLAUSE_SIMDLEN: OMP_CLAUSE_OPERAND (nc, 0) = tsubst_expr (OMP_CLAUSE_OPERAND (oc, 0), args, complain, in_decl, /*integral_constant_expression_p=*/false); break; + case OMP_CLAUSE_LINEAR: + case OMP_CLAUSE_ALIGNED: + OMP_CLAUSE_OPERAND (nc, 0) + = tsubst_expr (OMP_CLAUSE_OPERAND (oc, 0), args, complain, + in_decl, /*integral_constant_expression_p=*/false); + OMP_CLAUSE_OPERAND (nc, 1) + = tsubst_expr (OMP_CLAUSE_OPERAND (oc, 1), args, complain, + in_decl, /*integral_constant_expression_p=*/false); + break; + case OMP_CLAUSE_NOWAIT: case OMP_CLAUSE_ORDERED: case OMP_CLAUSE_DEFAULT: case OMP_CLAUSE_UNTIED: case OMP_CLAUSE_MERGEABLE: + case OMP_CLAUSE_INBRANCH: + case OMP_CLAUSE_NOTINBRANCH: + case OMP_CLAUSE_PROC_BIND: + case OMP_CLAUSE_FOR: + case OMP_CLAUSE_PARALLEL: + case OMP_CLAUSE_SECTIONS: + case OMP_CLAUSE_TASKGROUP: break; default: gcc_unreachable (); } } - return finish_omp_clauses (nreverse (new_clauses)); + new_clauses = nreverse (new_clauses); + if (!declare_simd) + new_clauses = finish_omp_clauses (new_clauses); + return new_clauses; } /* Like tsubst_copy_and_build, but unshare TREE_LIST nodes. */ @@ -13181,7 +13226,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, break; case OMP_PARALLEL: - tmp = tsubst_omp_clauses (OMP_PARALLEL_CLAUSES (t), + tmp = tsubst_omp_clauses (OMP_PARALLEL_CLAUSES (t), false, args, complain, in_decl); stmt = begin_omp_parallel (); RECUR (OMP_PARALLEL_BODY (t)); @@ -13190,7 +13235,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, break; case OMP_TASK: - tmp = tsubst_omp_clauses (OMP_TASK_CLAUSES (t), + tmp = tsubst_omp_clauses (OMP_TASK_CLAUSES (t), false, args, complain, in_decl); stmt = begin_omp_task (); RECUR (OMP_TASK_BODY (t)); @@ -13206,7 +13251,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, tree declv, initv, condv, incrv; int i; - clauses = tsubst_omp_clauses (OMP_FOR_CLAUSES (t), + clauses = tsubst_omp_clauses (OMP_FOR_CLAUSES (t), false, args, complain, in_decl); declv = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (t))); initv = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (t))); @@ -13237,7 +13282,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, case OMP_SECTIONS: case OMP_SINGLE: - tmp = tsubst_omp_clauses (OMP_CLAUSES (t), args, complain, in_decl); + tmp = tsubst_omp_clauses (OMP_CLAUSES (t), false, + args, complain, in_decl); stmt = push_stmt_list (); RECUR (OMP_BODY (t)); stmt = pop_stmt_list (stmt); diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 004d690d59b5e..eeb7771b59e88 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -4028,6 +4028,7 @@ finish_omp_clauses (tree clauses) bitmap_head aligned_head; tree c, t, *pc = &clauses; const char *name; + bool branch_seen = false; bitmap_obstack_initialize (NULL); bitmap_initialize (&generic_head, &bitmap_default_obstack); @@ -4426,8 +4427,6 @@ finish_omp_clauses (tree clauses) case OMP_CLAUSE_UNTIED: case OMP_CLAUSE_COLLAPSE: case OMP_CLAUSE_MERGEABLE: - case OMP_CLAUSE_INBRANCH: - case OMP_CLAUSE_NOTINBRANCH: case OMP_CLAUSE_PARALLEL: case OMP_CLAUSE_FOR: case OMP_CLAUSE_SECTIONS: @@ -4435,6 +4434,17 @@ finish_omp_clauses (tree clauses) case OMP_CLAUSE_PROC_BIND: break; + case OMP_CLAUSE_INBRANCH: + case OMP_CLAUSE_NOTINBRANCH: + if (branch_seen) + { + error ("% clause is incompatible with " + "%"); + remove = true; + } + branch_seen = true; + break; + default: gcc_unreachable (); } @@ -4619,6 +4629,90 @@ finish_omp_clauses (tree clauses) return clauses; } +/* Finalize #pragma omp declare simd clauses after FNDECL has been parsed, + and put that into "omp declare simd" attribute. */ + +void +finish_omp_declare_simd (tree fndecl, vec *clauses) +{ + tree cl; + int i; + + if (TREE_CODE (fndecl) != FUNCTION_DECL) + return; + if ((*clauses)[0] == integer_zero_node) + { + error_at (DECL_SOURCE_LOCATION (fndecl), + "%<#pragma omp declare simd%> not immediately followed by " + "a single function declaration or definition"); + (*clauses)[0] = error_mark_node; + return; + } + if ((*clauses)[0] == error_mark_node) + return; + + FOR_EACH_VEC_SAFE_ELT (clauses, i, cl) + { + tree c, *pc, decl, name; + for (pc = &cl, c = cl; c; c = *pc) + { + bool remove = false; + switch (OMP_CLAUSE_CODE (c)) + { + case OMP_CLAUSE_UNIFORM: + case OMP_CLAUSE_LINEAR: + case OMP_CLAUSE_ALIGNED: + case OMP_CLAUSE_REDUCTION: + name = OMP_CLAUSE_DECL (c); + if (name == error_mark_node) + remove = true; + else + { + for (decl = DECL_ARGUMENTS (fndecl); decl; + decl = TREE_CHAIN (decl)) + if (DECL_NAME (decl) == name) + break; + if (decl == NULL_TREE) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is not a function parameter", name); + remove = true; + } + else + OMP_CLAUSE_DECL (c) = decl; + } + break; + default: + break; + } + if (remove) + *pc = OMP_CLAUSE_CHAIN (c); + else + pc = &OMP_CLAUSE_CHAIN (c); + } + cl = finish_omp_clauses (cl); + cl = c_omp_declare_simd_clauses_to_numbers (fndecl, cl); + if (!processing_template_decl) + { + for (c = lookup_attribute ("omp declare simd", + DECL_ATTRIBUTES (fndecl)); + c; c = lookup_attribute ("omp declare simd", + TREE_CHAIN (c))) + if (omp_declare_simd_clauses_equal (TREE_VALUE (c), cl)) + break; + if (c) + continue; + } + c = build_tree_list (get_identifier ("omp declare simd"), cl); + TREE_CHAIN (c) = DECL_ATTRIBUTES (fndecl); + if (processing_template_decl) + ATTR_IS_DEPENDENT (c) = 1; + DECL_ATTRIBUTES (fndecl) = c; + } + + (*clauses)[0] = integer_zero_node; +} + /* For all variables in the tree_list VARS, mark them as thread local. */ void diff --git a/gcc/testsuite/ChangeLog.gomp b/gcc/testsuite/ChangeLog.gomp index b4f8668c84b3f..91558ea14a5e5 100644 --- a/gcc/testsuite/ChangeLog.gomp +++ b/gcc/testsuite/ChangeLog.gomp @@ -1,3 +1,8 @@ +2013-05-09 Jakub Jelinek + + * g++.dg/gomp/declare-simd-1.C: New test. + * g++.dg/gomp/declare-simd-2.C: New test. + 2013-04-30 Jakub Jelinek * gfortran.dg/gomp/appendix-a/a.35.5.f90: Add dg-error. diff --git a/gcc/testsuite/g++.dg/gomp/declare-simd-1.C b/gcc/testsuite/g++.dg/gomp/declare-simd-1.C new file mode 100644 index 0000000000000..669b0e475583a --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/declare-simd-1.C @@ -0,0 +1,224 @@ +// Test parsing of #pragma omp declare simd +// { dg-do compile } + +#pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) \ + linear (c : 4) simdlen (8) notinbranch +#pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a \ + : 4) simdlen (4) inbranch +int f1 (int a, int *b, int c); + +#pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) simdlen (8) +int f2 (int a, int *b, int c) +{ + return a + *b + c; +} + +#pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a : 4) simdlen (4) +template +T f3 (int a, int *b, T c); + +template <> +int f3 (int, int *, int); + +#pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a : 4) notinbranch simdlen (4) +template +int f4 (int a, int *b, T c) +{ + return a + *b + c; +} + +template <> +int f4 (int, int *, int); + +template +int f5 (int a, int *b, T c); + +#pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a : 4) simdlen (4) +template <> +int f5 (int a, int *b, int c); + +template +int f6 (int a, int *b, int c); + +#pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a : 4) inbranch simdlen (4) +template <> +int f6<3> (int a, int *b, int c); + +#pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (long long)) linear (c : 4) simdlen (8) +__extension__ +long long f7 (long long a, long long *b, long long c); + +#pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) notinbranch simdlen (8) +extern "C" +int f8 (int a, int *b, int c); + +extern "C" +{ + #pragma omp declare simd + int f9 (int a, int *b, int c); +} + +namespace N1 +{ + namespace N2 + { + #pragma omp declare simd simdlen (2) aligned (b : sizeof (long long) * 2) + __extension__ long long + f10 (long long *b) + { + return *b; + } + } +} + +struct A +{ + #pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) simdlen (8) + #pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a : 4) simdlen (4) + int f11 (int a, int *b, int c); + + #pragma omp declare simd + template + int f12 (int a, int *b, int c); + + #pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) notinbranch simdlen (8) + #pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a : 4) simdlen (4) inbranch + static int f13 (int a, int *b, int c); + + #pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) simdlen (8) + #pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a : 4) simdlen (4) + int f14 (int a, int *b, int c) { return a + *b + c; } + + #pragma omp declare simd + template + int f15 (int a, int *b, int c) { return a + *b + c; } + + #pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) simdlen (8) + #pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a : 4) simdlen (4) + static int f16 (int a, int *b, int c) { return a + *b + c; } +}; + +template <> +int A::f12<2> (int, int *, int); + +template <> +int A::f15<2> (int, int *, int); + +template +struct B +{ + #pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) simdlen (8) notinbranch + #pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a : 4) simdlen (4) inbranch + int f17 (int a, int *b, int c); + + #pragma omp declare simd + template + int f18 (int a, int *b, int c); + + #pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) simdlen (8) + #pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a : 4) simdlen (4) + static int f19 (int a, int *b, int c); + + #pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) simdlen (8) + #pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a : 4) simdlen (4) + int f20 (int a, int *b, int c) { return a + *b + c; } + + #pragma omp declare simd + template + int f21 (int a, int *b, int c) { return a + *b + c; } + + #pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) simdlen (8) + #pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a : 4) simdlen (4) + static int f22 (int a, int *b, int c) { return a + *b + c; } + + template + int f23 (int, int *, int); + + template + static int f24 (int, int *, int); + + template + int f25 (int, int *, int); + + template + static int f26 (int, int *, int); +}; + +B b; + +template <> +template <> +int B::f18<0> (int, int *, int); + +template <> +template <> +int B::f21<9> (int, int *, int); + +#pragma omp declare simd simdlen (8) aligned (b : 8 * sizeof (int)) uniform (a, c) +template <> +template <> +int B::f23<7> (int a, int *b, int c); + +#pragma omp declare simd simdlen (4) aligned (b : 8 * sizeof (int)) linear (a, c : 2) +template <> +template <> +int B::f24<-1> (int a, int *b, int c); + +#pragma omp declare simd simdlen (8) aligned (b : 8 * sizeof (int)) uniform (a, c) +template <> +template <> +int B::f25<7> (int a, int *b, int c) +{ + return a + *b + c; +} + +#pragma omp declare simd simdlen (4) aligned (b : 8 * sizeof (int)) linear (a, c : 2) +template <> +template <> +int B::f26<-1> (int a, int *b, int c) +{ + return a + *b + c; +} + +int +f27 (int x) +{ + #pragma omp declare simd simdlen (8) aligned (b : 8 * sizeof (int)) + extern int f28 (int a, int *b, int c); + { + x++; + #pragma omp declare simd simdlen (4) linear (c) + extern int f29 (int a, int *b, int c); + } + return x; +} + +#pragma omp declare simd simdlen (16) +int +f30 (int x) +{ + #pragma omp declare simd simdlen (8) aligned (b : 8 * sizeof (int)) + extern int f31 (int a, int *b, int c); + return x; +} + +template +struct C +{ + #pragma omp declare simd simdlen (N) aligned (a : N * sizeof (int)) linear (c : N) notinbranch + int f32 (int a, int *b, int c); +}; + +C <2> c; + +int +f33 (int x) +{ + if (x) + #pragma omp declare simd simdlen (8) aligned (b : 8 * sizeof (int)) + extern int f34 (int a, int *b, int c); + while (x < 10) + #pragma omp declare simd simdlen (8) aligned (b : 8 * sizeof (int)) + extern int f35 (int a, int *b, int c); + return x; +} diff --git a/gcc/testsuite/g++.dg/gomp/declare-simd-2.C b/gcc/testsuite/g++.dg/gomp/declare-simd-2.C new file mode 100644 index 0000000000000..eb449fe2fb6fc --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/declare-simd-2.C @@ -0,0 +1,60 @@ +// Test parsing of #pragma omp declare simd +// { dg-do compile } + +#pragma omp declare simd +int a; // { dg-error "not immediately followed by function declaration or definition" } + +#pragma omp declare simd +int fn1 (int a), fn2 (int a); // { dg-error "not immediately followed by a single function declaration or definition" } + +#pragma omp declare simd +int b, fn3 (int a); // { dg-error "not immediately followed by function declaration or definition" } + +#pragma omp declare simd linear (a) +int fn4 (int a), c; // { dg-error "not immediately followed by function declaration or definition" } + +#pragma omp declare simd +extern "C" // { dg-error "not immediately followed by function declaration or definition" } +{ + int fn5 (int a); +} + +#pragma omp declare simd // { dg-error "not immediately followed by function declaration or definition" } +namespace N1 +{ + int fn6 (int a); +} + +#pragma omp declare simd simdlen (4) +struct A +{ // { dg-error "not immediately followed by function declaration or definition" } + int fn7 (int a); +}; + +#pragma omp declare simd +template +struct B +{ // { dg-error "not immediately followed by function declaration or definition" } + int fn8 (int a); +}; + +struct C +{ +#pragma omp declare simd // { dg-error "not immediately followed by function declaration or definition" } + public: // { dg-error "expected unqualified-id before" } + int fn9 (int a); +}; + +int t; + +#pragma omp declare simd +#pragma omp declare simd +#pragma omp threadprivate(t) // { dg-error "not immediately followed by function declaration or definition" } +int fn10 (int a); + +#pragma omp declare simd inbranch notinbranch +int fn11 (int); // { dg-error "clause is incompatible with" } + +#pragma omp declare simd simdlen (N) // { dg-error "was not declared in this scope" } +template +int fn12 (int); diff --git a/gcc/tree.c b/gcc/tree.c index 36fadffffb15a..7d77a8712062e 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -4397,6 +4397,48 @@ build_type_attribute_qual_variant (tree ttype, tree attribute, int quals) return ttype; } +/* Check if "omp declare simd" attribute arguments, CLAUSES1 and CLAUSES2, are + the same. */ + +bool +omp_declare_simd_clauses_equal (tree clauses1, tree clauses2) +{ + tree cl1, cl2; + for (cl1 = clauses1, cl2 = clauses2; + cl1 && cl2; + cl1 = OMP_CLAUSE_CHAIN (cl1), cl2 = OMP_CLAUSE_CHAIN (cl2)) + { + if (OMP_CLAUSE_CODE (cl1) != OMP_CLAUSE_CODE (cl2)) + return false; + if (OMP_CLAUSE_CODE (cl1) != OMP_CLAUSE_SIMDLEN) + { + if (simple_cst_equal (OMP_CLAUSE_DECL (cl1), + OMP_CLAUSE_DECL (cl2)) != 1) + return false; + } + switch (OMP_CLAUSE_CODE (cl1)) + { + case OMP_CLAUSE_ALIGNED: + if (simple_cst_equal (OMP_CLAUSE_ALIGNED_ALIGNMENT (cl1), + OMP_CLAUSE_ALIGNED_ALIGNMENT (cl2)) != 1) + return false; + break; + case OMP_CLAUSE_LINEAR: + if (simple_cst_equal (OMP_CLAUSE_LINEAR_STEP (cl1), + OMP_CLAUSE_LINEAR_STEP (cl2)) != 1) + return false; + break; + case OMP_CLAUSE_SIMDLEN: + if (simple_cst_equal (OMP_CLAUSE_SIMDLEN_EXPR (cl1), + OMP_CLAUSE_SIMDLEN_EXPR (cl2)) != 1) + return false; + default: + break; + } + } + return true; +} + /* Compare two attributes for their value identity. Return true if the attribute values are known to be equal; otherwise return false. */ @@ -4414,6 +4456,13 @@ attribute_value_equal (const_tree attr1, const_tree attr2) return (simple_cst_list_equal (TREE_VALUE (attr1), TREE_VALUE (attr2)) == 1); + if (flag_openmp + && TREE_VALUE (attr1) && TREE_VALUE (attr2) + && TREE_CODE (TREE_VALUE (attr1)) == OMP_CLAUSE + && TREE_CODE (TREE_VALUE (attr2)) == OMP_CLAUSE) + return omp_declare_simd_clauses_equal (TREE_VALUE (attr1), + TREE_VALUE (attr2)); + return (simple_cst_equal (TREE_VALUE (attr1), TREE_VALUE (attr2)) == 1); } diff --git a/gcc/tree.h b/gcc/tree.h index 46bb2b415cb8d..65d3b2d2753d0 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -5051,6 +5051,10 @@ extern tree build_type_attribute_variant (tree, tree); extern tree build_decl_attribute_variant (tree, tree); extern tree build_type_attribute_qual_variant (tree, tree, int); +/* Check if "omp declare simd" attribute arguments, CLAUSES1 and CLAUSES2, are + the same. */ +extern bool omp_declare_simd_clauses_equal (tree, tree); + /* Return 0 if the attributes for two types are incompatible, 1 if they are compatible, and 2 if they are nearly compatible (which causes a warning to be generated). */ From ec8f0b42e3e3e9085b0808cec0f6cad7d818ed83 Mon Sep 17 00:00:00 2001 From: "Balaji V. Iyer" Date: Fri, 10 May 2013 17:29:57 -0400 Subject: [PATCH 26/63] Fixed a uninit. variable error in c-typeck.c --- gcc/c/c-typeck.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index c033fd4c774f8..a6bafd5ac8bc9 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -10847,7 +10847,8 @@ c_finish_omp_clauses (tree clauses) bitmap_set_bit (&lastprivate_head, DECL_UID (t)); break; - case OMP_CLAUSE_ALIGNED: + case OMP_CLAUSE_ALIGNED: + name = "aligned"; t = OMP_CLAUSE_DECL (c); if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) { @@ -10867,6 +10868,7 @@ c_finish_omp_clauses (tree clauses) break; case OMP_CLAUSE_DEPEND: + name = "depend"; t = OMP_CLAUSE_DECL (c); /* FIXME: depend clause argument may be also array section. */ if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) @@ -10878,8 +10880,11 @@ c_finish_omp_clauses (tree clauses) break; case OMP_CLAUSE_MAP: + name = "map"; case OMP_CLAUSE_TO: + name = "to"; case OMP_CLAUSE_FROM: + name = "from"; t = OMP_CLAUSE_DECL (c); /* FIXME: map clause argument may be also array section. */ if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) @@ -10899,6 +10904,7 @@ c_finish_omp_clauses (tree clauses) break; case OMP_CLAUSE_UNIFORM: + name = "uniform"; t = OMP_CLAUSE_DECL (c); if (TREE_CODE (t) != PARM_DECL) { @@ -10913,26 +10919,87 @@ c_finish_omp_clauses (tree clauses) break; case OMP_CLAUSE_IF: + name = "if"; + pc = &OMP_CLAUSE_CHAIN (c); + continue; case OMP_CLAUSE_NUM_THREADS: + name = "num_threads"; + pc = &OMP_CLAUSE_CHAIN (c); + continue; case OMP_CLAUSE_SCHEDULE: + name = "schedule"; + pc = &OMP_CLAUSE_CHAIN (c); + continue; case OMP_CLAUSE_NOWAIT: + name = "nowait"; + pc = &OMP_CLAUSE_CHAIN (c); + continue; case OMP_CLAUSE_ORDERED: + name = "ordered"; + pc = &OMP_CLAUSE_CHAIN (c); + continue; case OMP_CLAUSE_DEFAULT: + name = "default"; + pc = &OMP_CLAUSE_CHAIN (c); + continue; case OMP_CLAUSE_UNTIED: + name = "untied"; + pc = &OMP_CLAUSE_CHAIN (c); + continue; case OMP_CLAUSE_COLLAPSE: + name = "collapse"; + pc = &OMP_CLAUSE_CHAIN (c); + continue; case OMP_CLAUSE_FINAL: + name = "final"; + pc = &OMP_CLAUSE_CHAIN (c); + continue; case OMP_CLAUSE_MERGEABLE: + name = "mergeable"; + pc = &OMP_CLAUSE_CHAIN (c); + continue; case OMP_CLAUSE_SAFELEN: + name = "safelen"; + pc = &OMP_CLAUSE_CHAIN (c); + continue; case OMP_CLAUSE_SIMDLEN: + name = "simdlen"; + pc = &OMP_CLAUSE_CHAIN (c); + continue; case OMP_CLAUSE_DEVICE: + name = "device"; + pc = &OMP_CLAUSE_CHAIN (c); + continue; case OMP_CLAUSE_DIST_SCHEDULE: + name = "dist_schedule"; + pc = &OMP_CLAUSE_CHAIN (c); + continue; case OMP_CLAUSE_INBRANCH: + name = "inbranch"; + pc = &OMP_CLAUSE_CHAIN (c); + continue; case OMP_CLAUSE_NOTINBRANCH: + name = "notinbranch"; + pc = &OMP_CLAUSE_CHAIN (c); + continue; case OMP_CLAUSE_PARALLEL: + name = "parallel"; + pc = &OMP_CLAUSE_CHAIN (c); + continue; case OMP_CLAUSE_FOR: + name = "for"; + pc = &OMP_CLAUSE_CHAIN (c); + continue; case OMP_CLAUSE_SECTIONS: + name = "sections"; + pc = &OMP_CLAUSE_CHAIN (c); + continue; case OMP_CLAUSE_TASKGROUP: + name = "taskgroup"; + pc = &OMP_CLAUSE_CHAIN (c); + continue; case OMP_CLAUSE_PROC_BIND: + name = "proc_bind"; pc = &OMP_CLAUSE_CHAIN (c); continue; From 908efe616065de683f402168de1c1e492286cee4 Mon Sep 17 00:00:00 2001 From: jakub Date: Mon, 13 May 2013 12:59:56 +0000 Subject: [PATCH 27/63] * c-tree.h (c_finish_omp_declare_simd): New prototype. * c-typeck.c (c_finish_omp_clauses): Handle OMP_CLAUSE_LINEAR_STEP adjustments for pointer-types here. Diagnose inbranch notinbranch being used together. (c_finish_omp_declare_simd): New function. * c-parser.c (enum pragma_context): Add pragma_struct and pragma_param. (c_parser_declaration_or_fndef): Add omp_declare_simd_clauses argument. Call c_finish_omp_declare_simd if needed. (c_parser_external_declaration, c_parser_compound_statement_nostart, c_parser_label, c_parser_for_statement, c_parser_objc_methodprotolist, c_parser_omp_for_loop): Adjust c_parser_declaration_or_fndef callers. (c_parser_struct_or_union_specifier): Use pragma_struct instead of pragma_external. (c_parser_parameter_declaration): Use pragma_param instead of pragma_external. (c_parser_pragma): Handle PRAGMA_OMP_DECLARE_REDUCTION. Replace == pragma_external with != pragma_stmt && != pragma_compound test. (c_parser_omp_variable_list): Add declare_simd argument. Don't lookup vars if it is true, just store identifiers. (c_parser_omp_var_list_parens, c_parser_omp_clause_depend, c_parser_omp_clause_map): Adjust callers. (c_parser_omp_clause_reduction, c_parser_omp_clause_aligned): Add declare_simd argument, pass it through to c_parser_omp_variable_list. (c_parser_omp_clause_linear): Likewise. Don't handle OMP_CLAUSE_LINEAR_STEP adjustements for pointer-types here. (c_parser_omp_clause_uniform): Call c_parser_omp_variable_list instead of c_parser_omp_var_list_parens to pass true as declare_simd. (c_parser_omp_all_clauses): Add declare_simd argument, pass it through clause parsing routines as needed. Don't call c_finish_omp_clauses if set. (c_parser_omp_simd, c_parser_omp_for, c_parser_omp_sections, c_parser_omp_parallel, c_parser_omp_single, c_parser_omp_task, c_parser_omp_cancel, c_parser_omp_cancellation_point): Adjust callers. (OMP_DECLARE_SIMD_CLAUSE_MASK): Define. (c_parser_omp_declare_simd, c_parser_omp_declare): New functions. * gcc.dg/gomp/declare-simd-1.c: New test. * gcc.dg/gomp/declare-simd-2.c: New test. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gomp-4_0-branch@198828 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/c/ChangeLog.gomp | 40 +++ gcc/c/c-parser.c | 278 +++++++++++++++++---- gcc/c/c-tree.h | 1 + gcc/c/c-typeck.c | 115 ++++++++- gcc/testsuite/ChangeLog.gomp | 5 + gcc/testsuite/gcc.dg/gomp/declare-simd-1.c | 82 ++++++ gcc/testsuite/gcc.dg/gomp/declare-simd-2.c | 24 ++ 7 files changed, 494 insertions(+), 51 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/gomp/declare-simd-1.c create mode 100644 gcc/testsuite/gcc.dg/gomp/declare-simd-2.c diff --git a/gcc/c/ChangeLog.gomp b/gcc/c/ChangeLog.gomp index 3e1f7156faa16..816a4acc0149c 100644 --- a/gcc/c/ChangeLog.gomp +++ b/gcc/c/ChangeLog.gomp @@ -1,3 +1,43 @@ +2013-05-13 Jakub Jelinek + + * c-tree.h (c_finish_omp_declare_simd): New prototype. + * c-typeck.c (c_finish_omp_clauses): Handle OMP_CLAUSE_LINEAR_STEP + adjustments for pointer-types here. Diagnose inbranch notinbranch + being used together. + (c_finish_omp_declare_simd): New function. + * c-parser.c (enum pragma_context): Add pragma_struct and + pragma_param. + (c_parser_declaration_or_fndef): Add omp_declare_simd_clauses + argument. Call c_finish_omp_declare_simd if needed. + (c_parser_external_declaration, c_parser_compound_statement_nostart, + c_parser_label, c_parser_for_statement, c_parser_objc_methodprotolist, + c_parser_omp_for_loop): Adjust c_parser_declaration_or_fndef callers. + (c_parser_struct_or_union_specifier): Use pragma_struct instead of + pragma_external. + (c_parser_parameter_declaration): Use pragma_param instead of + pragma_external. + (c_parser_pragma): Handle PRAGMA_OMP_DECLARE_REDUCTION. + Replace == pragma_external with != pragma_stmt && != pragma_compound + test. + (c_parser_omp_variable_list): Add declare_simd argument. Don't lookup + vars if it is true, just store identifiers. + (c_parser_omp_var_list_parens, c_parser_omp_clause_depend, + c_parser_omp_clause_map): Adjust callers. + (c_parser_omp_clause_reduction, c_parser_omp_clause_aligned): Add + declare_simd argument, pass it through to c_parser_omp_variable_list. + (c_parser_omp_clause_linear): Likewise. Don't handle + OMP_CLAUSE_LINEAR_STEP adjustements for pointer-types here. + (c_parser_omp_clause_uniform): Call c_parser_omp_variable_list + instead of c_parser_omp_var_list_parens to pass true as declare_simd. + (c_parser_omp_all_clauses): Add declare_simd argument, pass it through + clause parsing routines as needed. Don't call c_finish_omp_clauses if + set. + (c_parser_omp_simd, c_parser_omp_for, c_parser_omp_sections, + c_parser_omp_parallel, c_parser_omp_single, c_parser_omp_task, + c_parser_omp_cancel, c_parser_omp_cancellation_point): Adjust callers. + (OMP_DECLARE_SIMD_CLAUSE_MASK): Define. + (c_parser_omp_declare_simd, c_parser_omp_declare): New functions. + 2013-04-30 Jakub Jelinek * c-parser.c (c_parser_omp_atomic): Parse seq_cst clause, pass diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index 58e53d5629484..28d13baf6a2df 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -1112,7 +1112,7 @@ enum c_parser_prec { static void c_parser_external_declaration (c_parser *); static void c_parser_asm_definition (c_parser *); static void c_parser_declaration_or_fndef (c_parser *, bool, bool, bool, - bool, bool, tree *); + bool, bool, tree *, vec); static void c_parser_static_assert_declaration_no_semi (c_parser *); static void c_parser_static_assert_declaration (c_parser *); static void c_parser_declspecs (c_parser *, struct c_declspecs *, bool, bool, @@ -1189,8 +1189,10 @@ static void c_parser_omp_taskyield (c_parser *); static void c_parser_omp_cancel (c_parser *); static void c_parser_omp_cancellation_point (c_parser *); -enum pragma_context { pragma_external, pragma_stmt, pragma_compound }; +enum pragma_context { pragma_external, pragma_struct, pragma_param, + pragma_stmt, pragma_compound }; static bool c_parser_pragma (c_parser *, enum pragma_context); +static void c_parser_omp_declare (c_parser *, enum pragma_context); /* These Objective-C parser functions are only ever called when compiling Objective-C. */ @@ -1361,7 +1363,8 @@ c_parser_external_declaration (c_parser *parser) an @interface or @protocol with prefix attributes). We can only tell which after parsing the declaration specifiers, if any, and the first declarator. */ - c_parser_declaration_or_fndef (parser, true, true, true, false, true, NULL); + c_parser_declaration_or_fndef (parser, true, true, true, false, true, + NULL, vNULL); break; } } @@ -1441,7 +1444,8 @@ static void c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, bool static_assert_ok, bool empty_ok, bool nested, bool start_attr_ok, - tree *objc_foreach_object_declaration) + tree *objc_foreach_object_declaration, + vec omp_declare_simd_clauses) { struct c_declspecs *specs; tree prefix_attrs; @@ -1611,6 +1615,9 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, C_DTR_NORMAL, &dummy); if (declarator == NULL) { + if (omp_declare_simd_clauses.exists ()) + c_finish_omp_declare_simd (NULL_TREE, NULL_TREE, + omp_declare_simd_clauses); c_parser_skip_to_end_of_block_or_statement (parser); return; } @@ -1647,6 +1654,9 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, chainon (postfix_attrs, all_prefix_attrs)); if (!d) d = error_mark_node; + if (omp_declare_simd_clauses.exists ()) + c_finish_omp_declare_simd (d, NULL_TREE, + omp_declare_simd_clauses); start_init (d, asm_name, global_bindings_p ()); init_loc = c_parser_peek_token (parser)->location; init = c_parser_initializer (parser); @@ -1663,6 +1673,24 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, tree d = start_decl (declarator, specs, false, chainon (postfix_attrs, all_prefix_attrs)); + if (omp_declare_simd_clauses.exists ()) + { + tree parms = NULL_TREE; + if (d && TREE_CODE (d) == FUNCTION_DECL) + { + struct c_declarator *ce = declarator; + while (ce != NULL) + if (ce->kind == cdk_function) + { + parms = ce->u.arg_info->parms; + break; + } + else + ce = ce->declarator; + } + c_finish_omp_declare_simd (d, parms, + omp_declare_simd_clauses); + } if (d) finish_decl (d, UNKNOWN_LOCATION, NULL_TREE, NULL_TREE, asm_name); @@ -1752,8 +1780,11 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, while (c_parser_next_token_is_not (parser, CPP_EOF) && c_parser_next_token_is_not (parser, CPP_OPEN_BRACE)) c_parser_declaration_or_fndef (parser, false, false, false, - true, false, NULL); + true, false, NULL, vNULL); store_parm_decls (); + if (omp_declare_simd_clauses.exists ()) + c_finish_omp_declare_simd (current_function_decl, NULL_TREE, + omp_declare_simd_clauses); DECL_STRUCT_FUNCTION (current_function_decl)->function_start_locus = c_parser_peek_token (parser)->location; fnbody = c_parser_compound_statement (parser); @@ -2480,7 +2511,7 @@ c_parser_struct_or_union_specifier (c_parser *parser) /* Accept #pragmas at struct scope. */ if (c_parser_next_token_is (parser, CPP_PRAGMA)) { - c_parser_pragma (parser, pragma_external); + c_parser_pragma (parser, pragma_struct); continue; } /* Parse some comma-separated declarations, but not the @@ -3311,7 +3342,7 @@ c_parser_parameter_declaration (c_parser *parser, tree attrs) /* Accept #pragmas between parameter declarations. */ while (c_parser_next_token_is (parser, CPP_PRAGMA)) - c_parser_pragma (parser, pragma_external); + c_parser_pragma (parser, pragma_param); if (!c_parser_next_token_starts_declspecs (parser)) { @@ -4161,7 +4192,8 @@ c_parser_compound_statement_nostart (c_parser *parser) { last_label = false; mark_valid_location_for_stdc_pragma (false); - c_parser_declaration_or_fndef (parser, true, true, true, true, true, NULL); + c_parser_declaration_or_fndef (parser, true, true, true, true, + true, NULL, vNULL); if (last_stmt) pedwarn_c90 (loc, (pedantic && !flag_isoc99) @@ -4189,7 +4221,7 @@ c_parser_compound_statement_nostart (c_parser *parser) last_label = false; mark_valid_location_for_stdc_pragma (false); c_parser_declaration_or_fndef (parser, true, true, true, true, - true, NULL); + true, NULL, vNULL); /* Following the old parser, __extension__ does not disable this diagnostic. */ restore_extension_diagnostics (ext); @@ -4327,7 +4359,8 @@ c_parser_label (c_parser *parser) c_parser_declaration_or_fndef (parser, /*fndef_ok*/ false, /*static_assert_ok*/ true, /*empty_ok*/ true, /*nested*/ true, - /*start_attr_ok*/ true, NULL); + /*start_attr_ok*/ true, NULL, + vNULL); } } } @@ -4947,7 +4980,7 @@ c_parser_for_statement (c_parser *parser) else if (c_parser_next_tokens_start_declaration (parser)) { c_parser_declaration_or_fndef (parser, true, true, true, true, true, - &object_expression); + &object_expression, vNULL); parser->objc_could_be_foreach_context = false; if (c_parser_next_token_is_keyword (parser, RID_IN)) @@ -4976,7 +5009,7 @@ c_parser_for_statement (c_parser *parser) ext = disable_extension_diagnostics (); c_parser_consume_token (parser); c_parser_declaration_or_fndef (parser, true, true, true, true, - true, &object_expression); + true, &object_expression, vNULL); parser->objc_could_be_foreach_context = false; restore_extension_diagnostics (ext); @@ -7643,7 +7676,7 @@ c_parser_objc_methodprotolist (c_parser *parser) } else c_parser_declaration_or_fndef (parser, false, false, true, - false, true, NULL); + false, true, NULL, vNULL); break; } } @@ -8657,6 +8690,10 @@ c_parser_pragma (c_parser *parser, enum pragma_context context) c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); return false; + case PRAGMA_OMP_DECLARE_REDUCTION: + c_parser_omp_declare (parser, context); + return false; + case PRAGMA_GCC_PCH_PREPROCESS: c_parser_error (parser, "%<#pragma GCC pch_preprocess%> must be first"); c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); @@ -8665,7 +8702,7 @@ c_parser_pragma (c_parser *parser, enum pragma_context context) default: if (id < PRAGMA_FIRST_EXTERNAL) { - if (context == pragma_external) + if (context != pragma_stmt && context != pragma_compound) { bad_stmt: c_parser_error (parser, "expected declaration specifiers"); @@ -8890,7 +8927,7 @@ static tree c_parser_omp_variable_list (c_parser *parser, location_t clause_loc, enum omp_clause_code kind, - tree list) + tree list, bool declare_simd) { if (c_parser_next_token_is_not (parser, CPP_NAME) || c_parser_peek_token (parser)->id_kind != C_ID_ID) @@ -8899,7 +8936,12 @@ c_parser_omp_variable_list (c_parser *parser, while (c_parser_next_token_is (parser, CPP_NAME) && c_parser_peek_token (parser)->id_kind == C_ID_ID) { - tree t = lookup_name (c_parser_peek_token (parser)->value); + tree t; + + if (declare_simd) + t = c_parser_peek_token (parser)->value; + else + t = lookup_name (c_parser_peek_token (parser)->value); if (t == NULL_TREE) undeclared_variable (c_parser_peek_token (parser)->location, @@ -8939,7 +8981,7 @@ c_parser_omp_var_list_parens (c_parser *parser, enum omp_clause_code kind, if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) { - list = c_parser_omp_variable_list (parser, loc, kind, list); + list = c_parser_omp_variable_list (parser, loc, kind, list, false); c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); } return list; @@ -9239,7 +9281,7 @@ c_parser_omp_clause_private (c_parser *parser, tree list) One of: + * - & ^ | && || max min */ static tree -c_parser_omp_clause_reduction (c_parser *parser, tree list) +c_parser_omp_clause_reduction (c_parser *parser, tree list, bool declare_simd) { location_t clause_loc = c_parser_peek_token (parser)->location; if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) @@ -9301,7 +9343,8 @@ c_parser_omp_clause_reduction (c_parser *parser, tree list) tree nl, c; nl = c_parser_omp_variable_list (parser, clause_loc, - OMP_CLAUSE_REDUCTION, list); + OMP_CLAUSE_REDUCTION, list, + declare_simd); for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) OMP_CLAUSE_REDUCTION_CODE (c) = code; @@ -9531,7 +9574,7 @@ c_parser_omp_clause_num_teams (c_parser *parser, tree list) aligned ( variable-list : constant-expression ) */ static tree -c_parser_omp_clause_aligned (c_parser *parser, tree list) +c_parser_omp_clause_aligned (c_parser *parser, tree list, bool declare_simd) { location_t clause_loc = c_parser_peek_token (parser)->location; tree nl, c; @@ -9540,7 +9583,7 @@ c_parser_omp_clause_aligned (c_parser *parser, tree list) return list; nl = c_parser_omp_variable_list (parser, clause_loc, - OMP_CLAUSE_ALIGNED, list); + OMP_CLAUSE_ALIGNED, list, declare_simd); if (c_parser_next_token_is (parser, CPP_COLON)) { @@ -9570,7 +9613,7 @@ c_parser_omp_clause_aligned (c_parser *parser, tree list) linear ( variable-list : expression ) */ static tree -c_parser_omp_clause_linear (c_parser *parser, tree list) +c_parser_omp_clause_linear (c_parser *parser, tree list, bool declare_simd) { location_t clause_loc = c_parser_peek_token (parser)->location; tree nl, c, step; @@ -9579,7 +9622,7 @@ c_parser_omp_clause_linear (c_parser *parser, tree list) return list; nl = c_parser_omp_variable_list (parser, clause_loc, - OMP_CLAUSE_LINEAR, list); + OMP_CLAUSE_LINEAR, list, declare_simd); if (c_parser_next_token_is (parser, CPP_COLON)) { @@ -9600,16 +9643,7 @@ c_parser_omp_clause_linear (c_parser *parser, tree list) for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) { - tree s = step; - if (TREE_CODE (TREE_TYPE (OMP_CLAUSE_DECL (c))) == POINTER_TYPE) - { - s = pointer_int_sum (clause_loc, PLUS_EXPR, OMP_CLAUSE_DECL (c), s); - s = fold_build2_loc (clause_loc, MINUS_EXPR, sizetype, s, - OMP_CLAUSE_DECL (c)); - if (s == error_mark_node) - s = size_one_node; - } - OMP_CLAUSE_LINEAR_STEP (c) = s; + OMP_CLAUSE_LINEAR_STEP (c) = step; } c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); @@ -9724,7 +9758,7 @@ c_parser_omp_clause_depend (c_parser *parser, tree list) goto resync_fail; nl = c_parser_omp_variable_list (parser, clause_loc, - OMP_CLAUSE_DEPEND, list); + OMP_CLAUSE_DEPEND, list, false); for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) OMP_CLAUSE_DEPEND_KIND (c) = kind; @@ -9780,7 +9814,7 @@ c_parser_omp_clause_map (c_parser *parser, tree list) } nl = c_parser_omp_variable_list (parser, clause_loc, - OMP_CLAUSE_MAP, list); + OMP_CLAUSE_MAP, list, false); for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) OMP_CLAUSE_MAP_KIND (c) = kind; @@ -9934,7 +9968,16 @@ c_parser_omp_clause_from (c_parser *parser, tree list) static tree c_parser_omp_clause_uniform (c_parser *parser, tree list) { - return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_UNIFORM, list); + /* The clauses location. */ + location_t loc = c_parser_peek_token (parser)->location; + + if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + list = c_parser_omp_variable_list (parser, loc, OMP_CLAUSE_UNIFORM, + list, true); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + } + return list; } /* Parse all OpenMP clauses. The set clauses allowed by the directive @@ -9943,7 +9986,7 @@ c_parser_omp_clause_uniform (c_parser *parser, tree list) static tree c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask, - const char *where) + const char *where, bool declare_simd) { tree clauses = NULL; bool first = true; @@ -10017,7 +10060,8 @@ c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask, c_name = "private"; break; case PRAGMA_OMP_CLAUSE_REDUCTION: - clauses = c_parser_omp_clause_reduction (parser, clauses); + clauses = c_parser_omp_clause_reduction (parser, clauses, + declare_simd); c_name = "reduction"; break; case PRAGMA_OMP_CLAUSE_SCHEDULE: @@ -10083,11 +10127,12 @@ c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask, c_name = "num_teams"; break; case PRAGMA_OMP_CLAUSE_ALIGNED: - clauses = c_parser_omp_clause_aligned (parser, clauses); + clauses = c_parser_omp_clause_aligned (parser, clauses, + declare_simd); c_name = "aligned"; break; case PRAGMA_OMP_CLAUSE_LINEAR: - clauses = c_parser_omp_clause_linear (parser, clauses); + clauses = c_parser_omp_clause_linear (parser, clauses, declare_simd); c_name = "linear"; break; case PRAGMA_OMP_CLAUSE_DEPEND: @@ -10135,6 +10180,9 @@ c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask, saw_error: c_parser_skip_to_pragma_eol (parser); + if (declare_simd) + return clauses; + return c_finish_omp_clauses (clauses); } @@ -10677,7 +10725,8 @@ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code, { if (i > 0) vec_safe_push (for_block, c_begin_compound_stmt (true)); - c_parser_declaration_or_fndef (parser, true, true, true, true, true, NULL); + c_parser_declaration_or_fndef (parser, true, true, true, true, true, + NULL, vNULL); decl = check_for_loop_decls (for_loc, flag_isoc99); if (decl == NULL) goto error_init; @@ -10942,7 +10991,7 @@ c_parser_omp_simd (location_t loc, c_parser *parser) tree block, clauses, ret; clauses = c_parser_omp_all_clauses (parser, OMP_SIMD_CLAUSE_MASK, - "#pragma omp simd"); + "#pragma omp simd", false); block = c_begin_compound_stmt (true); ret = c_parser_omp_for_loop (loc, parser, OMP_SIMD, clauses, NULL); @@ -10994,7 +11043,7 @@ c_parser_omp_for (location_t loc, c_parser *parser) } } - clauses = c_parser_omp_all_clauses (parser, mask, p_name); + clauses = c_parser_omp_all_clauses (parser, mask, p_name, false); block = c_begin_compound_stmt (true); ret = c_parser_omp_for_loop (loc, parser, code, clauses, NULL); @@ -11140,7 +11189,7 @@ c_parser_omp_sections (location_t loc, c_parser *parser) tree block, clauses, ret; clauses = c_parser_omp_all_clauses (parser, OMP_SECTIONS_CLAUSE_MASK, - "#pragma omp sections"); + "#pragma omp sections", false); block = c_begin_compound_stmt (true); ret = c_parser_omp_sections_scope (loc, parser); @@ -11212,7 +11261,7 @@ c_parser_omp_parallel (location_t loc, c_parser *parser) } } - clauses = c_parser_omp_all_clauses (parser, mask, p_name); + clauses = c_parser_omp_all_clauses (parser, mask, p_name, false); switch (p_kind) { @@ -11278,7 +11327,7 @@ c_parser_omp_single (location_t loc, c_parser *parser) OMP_SINGLE_CLAUSES (stmt) = c_parser_omp_all_clauses (parser, OMP_SINGLE_CLAUSE_MASK, - "#pragma omp single"); + "#pragma omp single", false); OMP_SINGLE_BODY (stmt) = c_parser_omp_structured_block (parser); return add_stmt (stmt); @@ -11307,7 +11356,7 @@ c_parser_omp_task (location_t loc, c_parser *parser) tree clauses, block; clauses = c_parser_omp_all_clauses (parser, OMP_TASK_CLAUSE_MASK, - "#pragma omp task"); + "#pragma omp task", false); block = c_begin_omp_task (); c_parser_statement (parser); @@ -11377,7 +11426,7 @@ c_parser_omp_cancel (c_parser *parser) c_parser_consume_pragma (parser); tree clauses = c_parser_omp_all_clauses (parser, OMP_CANCEL_CLAUSE_MASK, - "#pragma omp cancel"); + "#pragma omp cancel", false); c_finish_omp_cancel (loc, clauses); } @@ -11420,11 +11469,142 @@ c_parser_omp_cancellation_point (c_parser *parser) clauses = c_parser_omp_all_clauses (parser, OMP_CANCELLATION_POINT_CLAUSE_MASK, - "#pragma omp cancellation point"); + "#pragma omp cancellation point", false); c_finish_omp_cancellation_point (loc, clauses); } +/* OpenMP 4.0: + # pragma omp declare simd declare-simd-clauses[optseq] new-line */ + +#define OMP_DECLARE_SIMD_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SIMDLEN) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINEAR) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALIGNED) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_UNIFORM) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_INBRANCH) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOTINBRANCH)) + +static void +c_parser_omp_declare_simd (c_parser *parser, enum pragma_context context) +{ + vec clauses = vNULL; + tree cl = c_parser_omp_all_clauses (parser, OMP_DECLARE_SIMD_CLAUSE_MASK, + "#pragma omp declare simd", true); + clauses.safe_push (cl); + + while (c_parser_next_token_is (parser, CPP_PRAGMA)) + { + if (c_parser_peek_token (parser)->pragma_kind + != PRAGMA_OMP_DECLARE_REDUCTION + || c_parser_peek_2nd_token (parser)->type != CPP_NAME + || strcmp (IDENTIFIER_POINTER + (c_parser_peek_2nd_token (parser)->value), + "simd") != 0) + { + c_parser_error (parser, + "%<#pragma omp declare simd%> must be followed by " + "function declaration or definition or another " + "%<#pragma omp declare simd%>"); + clauses.release (); + return; + } + c_parser_consume_pragma (parser); + c_parser_consume_token (parser); + cl = c_parser_omp_all_clauses (parser, OMP_DECLARE_SIMD_CLAUSE_MASK, + "#pragma omp declare simd", true); + clauses.safe_push (cl); + } + + switch (context) + { + case pragma_external: + if (c_parser_next_token_is (parser, CPP_KEYWORD) + && c_parser_peek_token (parser)->keyword == RID_EXTENSION) + { + int ext = disable_extension_diagnostics (); + do + c_parser_consume_token (parser); + while (c_parser_next_token_is (parser, CPP_KEYWORD) + && c_parser_peek_token (parser)->keyword == RID_EXTENSION); + c_parser_declaration_or_fndef (parser, true, true, true, false, true, + NULL, clauses); + restore_extension_diagnostics (ext); + } + else + c_parser_declaration_or_fndef (parser, true, true, true, false, true, + NULL, clauses); + break; + case pragma_struct: + case pragma_param: + c_parser_error (parser, "%<#pragma omp declare simd%> must be followed by " + "function declaration or definition"); + break; + case pragma_compound: + case pragma_stmt: + if (c_parser_next_token_is (parser, CPP_KEYWORD) + && c_parser_peek_token (parser)->keyword == RID_EXTENSION) + { + int ext = disable_extension_diagnostics (); + do + c_parser_consume_token (parser); + while (c_parser_next_token_is (parser, CPP_KEYWORD) + && c_parser_peek_token (parser)->keyword == RID_EXTENSION); + if (c_parser_next_tokens_start_declaration (parser)) + { + c_parser_declaration_or_fndef (parser, true, true, true, true, + true, NULL, clauses); + restore_extension_diagnostics (ext); + break; + } + restore_extension_diagnostics (ext); + } + else if (c_parser_next_tokens_start_declaration (parser)) + { + c_parser_declaration_or_fndef (parser, true, true, true, true, true, + NULL, clauses); + break; + } + c_parser_error (parser, "%<#pragma omp declare simd%> must be followed by " + "function declaration or definition"); + break; + default: + gcc_unreachable (); + } + clauses.release (); +} + +/* OpenMP 4.0 + #pragma omp declare simd declare-simd-clauses[optseq] new-line + #pragma omp declare reduction (reduction-id : typename-list : expression) \ + identity-clause[opt] new-line */ + +static void +c_parser_omp_declare (c_parser *parser, enum pragma_context context) +{ + c_parser_consume_pragma (parser); + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp (p, "simd") == 0) + { + c_parser_consume_token (parser); + c_parser_omp_declare_simd (parser, context); + return; + } +/* if (strcmp (p, "reduction") == 0) + { + c_parser_consume_token (parser); + c_parser_omp_declare_reduction (parser); + return; + } */ + } + + c_parser_error (parser, "expected % or %"); + c_parser_skip_to_pragma_eol (parser); +} + /* Main entry point to parsing most OpenMP pragmas. */ static void diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index 7e973ea6aa83e..93516dabd6628 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -642,6 +642,7 @@ extern void c_finish_omp_taskgroup (location_t, tree); extern void c_finish_omp_cancel (location_t, tree); extern void c_finish_omp_cancellation_point (location_t, tree); extern tree c_finish_omp_clauses (tree); +extern void c_finish_omp_declare_simd (tree, tree, vec); extern tree c_build_va_arg (location_t, tree, tree); extern tree c_finish_transaction (location_t, tree, int); extern bool c_tree_equal (tree, tree); diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index addba4b16896e..7987c3c395a22 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -10670,6 +10670,7 @@ c_finish_omp_clauses (tree clauses) bitmap_head aligned_head; tree c, t, *pc = &clauses; const char *name; + bool branch_seen = false; bitmap_obstack_initialize (NULL); bitmap_initialize (&generic_head, &bitmap_default_obstack); @@ -10774,6 +10775,17 @@ c_finish_omp_clauses (tree clauses) remove = true; break; } + if (TREE_CODE (TREE_TYPE (OMP_CLAUSE_DECL (c))) == POINTER_TYPE) + { + tree s = OMP_CLAUSE_LINEAR_STEP (c); + s = pointer_int_sum (OMP_CLAUSE_LOCATION (c), PLUS_EXPR, + OMP_CLAUSE_DECL (c), s); + s = fold_build2_loc (OMP_CLAUSE_LOCATION (c), MINUS_EXPR, + sizetype, s, OMP_CLAUSE_DECL (c)); + if (s == error_mark_node) + s = size_one_node; + OMP_CLAUSE_LINEAR_STEP (c) = s; + } goto check_dup_generic; check_dup_generic: @@ -10919,8 +10931,6 @@ c_finish_omp_clauses (tree clauses) case OMP_CLAUSE_SIMDLEN: case OMP_CLAUSE_DEVICE: case OMP_CLAUSE_DIST_SCHEDULE: - case OMP_CLAUSE_INBRANCH: - case OMP_CLAUSE_NOTINBRANCH: case OMP_CLAUSE_PARALLEL: case OMP_CLAUSE_FOR: case OMP_CLAUSE_SECTIONS: @@ -10929,6 +10939,20 @@ c_finish_omp_clauses (tree clauses) pc = &OMP_CLAUSE_CHAIN (c); continue; + case OMP_CLAUSE_INBRANCH: + case OMP_CLAUSE_NOTINBRANCH: + if (branch_seen) + { + error_at (OMP_CLAUSE_LOCATION (c), + "% clause is incompatible with " + "%"); + remove = true; + break; + } + branch_seen = true; + pc = &OMP_CLAUSE_CHAIN (c); + continue; + default: gcc_unreachable (); } @@ -10987,6 +11011,93 @@ c_finish_omp_clauses (tree clauses) return clauses; } +/* Finalize #pragma omp declare simd clauses after FNDECL has been parsed, + and put that into "omp declare simd" attribute. */ + +void +c_finish_omp_declare_simd (tree fndecl, tree parms, vec clauses) +{ + tree cl; + int i; + + if (clauses[0] == error_mark_node) + return; + if (fndecl == NULL_TREE || TREE_CODE (fndecl) != FUNCTION_DECL) + { + error ("%<#pragma omp declare simd%> not immediately followed by " + "a function declaration or definition"); + clauses[0] = error_mark_node; + return; + } + if (clauses[0] == integer_zero_node) + { + error_at (DECL_SOURCE_LOCATION (fndecl), + "%<#pragma omp declare simd%> not immediately followed by " + "a single function declaration or definition"); + clauses[0] = error_mark_node; + return; + } + + if (parms == NULL_TREE) + parms = DECL_ARGUMENTS (fndecl); + + FOR_EACH_VEC_ELT (clauses, i, cl) + { + tree c, *pc, decl, name; + for (pc = &cl, c = cl; c; c = *pc) + { + bool remove = false; + switch (OMP_CLAUSE_CODE (c)) + { + case OMP_CLAUSE_UNIFORM: + case OMP_CLAUSE_LINEAR: + case OMP_CLAUSE_ALIGNED: + case OMP_CLAUSE_REDUCTION: + name = OMP_CLAUSE_DECL (c); + if (name == error_mark_node) + remove = true; + else + { + for (decl = parms; decl; decl = TREE_CHAIN (decl)) + if (DECL_NAME (decl) == name) + break; + if (decl == NULL_TREE) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is not a function parameter", name); + remove = true; + } + else + OMP_CLAUSE_DECL (c) = decl; + } + break; + default: + break; + } + if (remove) + *pc = OMP_CLAUSE_CHAIN (c); + else + pc = &OMP_CLAUSE_CHAIN (c); + } + cl = c_finish_omp_clauses (cl); + tree saved_arguments = DECL_ARGUMENTS (fndecl); + DECL_ARGUMENTS (fndecl) = parms; + cl = c_omp_declare_simd_clauses_to_numbers (fndecl, cl); + DECL_ARGUMENTS (fndecl) = saved_arguments; + for (c = lookup_attribute ("omp declare simd", DECL_ATTRIBUTES (fndecl)); + c; c = lookup_attribute ("omp declare simd", TREE_CHAIN (c))) + if (omp_declare_simd_clauses_equal (TREE_VALUE (c), cl)) + break; + if (c) + continue; + c = build_tree_list (get_identifier ("omp declare simd"), cl); + TREE_CHAIN (c) = DECL_ATTRIBUTES (fndecl); + DECL_ATTRIBUTES (fndecl) = c; + } + + clauses[0] = integer_zero_node; +} + /* Create a transaction node. */ tree diff --git a/gcc/testsuite/ChangeLog.gomp b/gcc/testsuite/ChangeLog.gomp index 91558ea14a5e5..ffd03ffd3bf43 100644 --- a/gcc/testsuite/ChangeLog.gomp +++ b/gcc/testsuite/ChangeLog.gomp @@ -1,3 +1,8 @@ +2013-05-13 Jakub Jelinek + + * gcc.dg/gomp/declare-simd-1.c: New test. + * gcc.dg/gomp/declare-simd-2.c: New test. + 2013-05-09 Jakub Jelinek * g++.dg/gomp/declare-simd-1.C: New test. diff --git a/gcc/testsuite/gcc.dg/gomp/declare-simd-1.c b/gcc/testsuite/gcc.dg/gomp/declare-simd-1.c new file mode 100644 index 0000000000000..1decd3f1f4064 --- /dev/null +++ b/gcc/testsuite/gcc.dg/gomp/declare-simd-1.c @@ -0,0 +1,82 @@ +/* Test parsing of #pragma omp declare simd */ +/* { dg-do compile } */ + +#pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) \ + linear (c : 4) simdlen (8) notinbranch +#pragma omp declare simd uniform (c) aligned (b : 4 * sizeof (int)) linear (a \ + : 4) simdlen (4) inbranch +int f1 (int a, int *b, int c); + +#pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) simdlen (8) +int f2 (int a, int *b, int c) +{ + return a + *b + c; +} + +#pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (long long)) linear (c : 4) simdlen (8) +__extension__ +long long f3 (long long a, long long *b, long long c); + +int +f4 (int x) +{ + #pragma omp declare simd simdlen (8) aligned (b : 8 * sizeof (int)) + __extension__ __extension__ __extension__ + extern int f5 (int a, int *b, int c); + { + x++; + #pragma omp declare simd simdlen (4) linear (c) + extern int f6 (int a, int *b, int c); + } + return x; +} + +#pragma omp declare simd simdlen (16) +int +f7 (int x) +{ + #pragma omp declare simd simdlen (8) aligned (b : 8 * sizeof (int)) + extern int f8 (int a, int *b, int c); + return x; +} + +int +f9 (int x) +{ + if (x) + #pragma omp declare simd simdlen (8) aligned (b : 8 * sizeof (int)) + extern int f10 (int a, int *b, int c); + while (x < 10) + #pragma omp declare simd simdlen (8) aligned (b : 8 * sizeof (int)) + extern int f11 (int a, int *b, int c); + return x; +} + +#pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) simdlen (8) +int f12 (int c; int *b; int a; int a, int *b, int c); + +#pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) simdlen (8) +int +f13 (int c; int *b; int a; int a, int *b, int c) +{ + return a + *b + c; +} + +#pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) simdlen (8) +int +f14 (a, b, c) + int a, c; + int *b; +{ + return a + *b + c; +} + +#pragma omp declare simd uniform (a) aligned (b : 8 * sizeof (int)) linear (c : 4) simdlen (8) +int +f15 (int a, int *b, int c) +{ + return a + *b + c; +} + +#pragma omp declare simd uniform (d) aligned (e : 8 * sizeof (int)) linear (f : 4) simdlen (8) +int f15 (int d, int *e, int f); diff --git a/gcc/testsuite/gcc.dg/gomp/declare-simd-2.c b/gcc/testsuite/gcc.dg/gomp/declare-simd-2.c new file mode 100644 index 0000000000000..118549be908dc --- /dev/null +++ b/gcc/testsuite/gcc.dg/gomp/declare-simd-2.c @@ -0,0 +1,24 @@ +/* Test parsing of #pragma omp declare simd */ +/* { dg-do compile } */ + +#pragma omp declare simd +int a; /* { dg-error "not immediately followed by a function declaration or definition" } */ + +#pragma omp declare simd +int fn1 (int a), fn2 (int a); /* { dg-error "not immediately followed by a single function declaration or definition" } */ + +#pragma omp declare simd +int b, fn3 (int a); /* { dg-error "not immediately followed by a function declaration or definition" } */ + +#pragma omp declare simd linear (a) +int fn4 (int a), c; /* { dg-error "not immediately followed by a function declaration or definition" } */ + +int t; + +#pragma omp declare simd +#pragma omp declare simd +#pragma omp threadprivate(t) /* { dg-error "must be followed by function declaration or definition or another" } */ +int fn5 (int a); + +#pragma omp declare simd inbranch notinbranch /* { dg-error "clause is incompatible with" } */ +int fn6 (int); From 41a99b0bde43611bd9047078fc493ee6622a0629 Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Mon, 13 May 2013 18:51:03 -0500 Subject: [PATCH 28/63] Add fixme and get rid of gratuitous line space change. --- gcc/c-family/c-cilkplus.c | 3 +++ gcc/tree.h | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/gcc/c-family/c-cilkplus.c b/gcc/c-family/c-cilkplus.c index d5df7b69a4cd3..40284fea0a4e4 100644 --- a/gcc/c-family/c-cilkplus.c +++ b/gcc/c-family/c-cilkplus.c @@ -390,6 +390,9 @@ c_finish_cilk_simd_loop (location_t loc, tree c_finish_cilk_clauses (tree clauses) { + /* FIXME: Should we do some minimal type checking of the clauses + here, or at the minimum gcc_asserts? */ + /* FIXME: Must validate reduction clauses too. Right now we're ignoring them. */ for (tree c = clauses; c; c = OMP_CLAUSE_CHAIN (c)) diff --git a/gcc/tree.h b/gcc/tree.h index 3cc3881295025..46bb2b415cb8d 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -1860,7 +1860,6 @@ extern void protected_set_expr_location (tree, location_t); OMP_CLAUSE_OPERAND (OMP_CLAUSE_RANGE_CHECK (OMP_CLAUSE_CHECK (NODE), \ OMP_CLAUSE_PRIVATE, \ OMP_CLAUSE_MAP), 0) - #define OMP_CLAUSE_HAS_LOCATION(NODE) \ (LOCATION_LOCUS ((OMP_CLAUSE_CHECK (NODE))->omp_clause.locus) \ != UNKNOWN_LOCATION) From 7c1ba6b80f96c32d7765a272d9a98a6fa5062a5f Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Mon, 13 May 2013 19:05:59 -0500 Subject: [PATCH 29/63] Add changelog entries. --- gcc/ChangeLog.cilkplus | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 gcc/ChangeLog.cilkplus diff --git a/gcc/ChangeLog.cilkplus b/gcc/ChangeLog.cilkplus new file mode 100644 index 0000000000000..5e9fb7935d9aa --- /dev/null +++ b/gcc/ChangeLog.cilkplus @@ -0,0 +1,27 @@ +2013-05-13 Aldy Hernandez + + * Makefile.in (C_COMMON_OBJS): Depend on c-family/c-cilkplus.o. + (c-cilkplus.o): New dependency. + +c-family/ + * c-cilkplus.c: New. + * c-pragma.c (init_pragma): Register "simd" pragma. + * c-pragma.h (enum pragma_kind): Add PRAGMA_CILK_SIMD enum. + (enum pragma_cilk_clause): New. + * c.opt (fcilkplus): New flag. + +c/ + * c-parser.c (c_parser_pragma): Add case for PRAGMA_CILK_SIMD. + (c_parser_cilk_verify_simd): New. + (c_parser_cilk_clause_vectorlength): New. + (c_parser_cilk_clause_linear): New. + (c_parser_cilk_clause_name): New. + (c_parser_cilk_all_clauses): New. + (c_parser_cilk_for_statement): New. + (c_parser_cilk_simd_construct): New. + * c-tree.h (c_finish_cilk_simd_loop): Protoize. + (c_finish_cilk_clauses): Same. + * c-typeck.c (c_finish_bc_stmt): Add case for _Cilk_for loops. + +testsuite/ + * gcc.dg/cilk-plus: New directory and associated infrastructure. From 415e3110e9eb8593ab429ebdbfaf4f5fa6ae921c Mon Sep 17 00:00:00 2001 From: jakub Date: Tue, 14 May 2013 13:30:24 +0000 Subject: [PATCH 30/63] * cfgloop.h (struct loop): Add safelen and force_vect fields. * function.h (struct function): Add has_force_vect_loops field. * omp-low.c (expand_omp_simd): If !broken_loop, create loop for the simd region and set safelen and force_vect fields in it. * tree-vectorizer.c (vectorize_loops): If loop has force_vect set, vectorize it even if flag_vectorize isn't set. Clear loop->force_vect after vectorization. * tree-ssa-loop.c (gate_tree_vectorize): Return true even cfun->has_force_vect_loops. * tree-ssa-loop-ivcanon.c (tree_unroll_loops_completely_1): Don't unroll loops with loop->force_vect. * tree-vect-data-refs.c (vect_analyze_data_ref_dependence): For unknown or bad data dependency, if loop->safelen is non-zero, just decrease *max_vf to loop->safelen if needed and return false. * tree-if-conv.c (main_tree_if_conversion): If-convert also loops with loop->force_vect. (gate_tree_if_conversion): Return true even if cfun->has_force_vect_loops. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gomp-4_0-branch@198884 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog.gomp | 21 +++++++++++++++++++++ gcc/cfgloop.h | 9 +++++++++ gcc/function.h | 4 ++++ gcc/omp-low.c | 30 ++++++++++++++++++++++++++++++ gcc/tree-if-conv.c | 7 ++++++- gcc/tree-ssa-loop-ivcanon.c | 5 +++++ gcc/tree-ssa-loop.c | 2 +- gcc/tree-vect-data-refs.c | 18 ++++++++++++++++++ gcc/tree-vectorizer.c | 6 +++++- 9 files changed, 99 insertions(+), 3 deletions(-) diff --git a/gcc/ChangeLog.gomp b/gcc/ChangeLog.gomp index 88291c65b6d17..1e2f6dcf8c8f2 100644 --- a/gcc/ChangeLog.gomp +++ b/gcc/ChangeLog.gomp @@ -1,3 +1,24 @@ +2013-05-14 Jakub Jelinek + + * cfgloop.h (struct loop): Add safelen and force_vect fields. + * function.h (struct function): Add has_force_vect_loops field. + * omp-low.c (expand_omp_simd): If !broken_loop, create loop for + the simd region and set safelen and force_vect fields in it. + * tree-vectorizer.c (vectorize_loops): If loop has force_vect set, + vectorize it even if flag_vectorize isn't set. Clear loop->force_vect + after vectorization. + * tree-ssa-loop.c (gate_tree_vectorize): Return true even + cfun->has_force_vect_loops. + * tree-ssa-loop-ivcanon.c (tree_unroll_loops_completely_1): Don't + unroll loops with loop->force_vect. + * tree-vect-data-refs.c (vect_analyze_data_ref_dependence): For + unknown or bad data dependency, if loop->safelen is non-zero, just + decrease *max_vf to loop->safelen if needed and return false. + * tree-if-conv.c (main_tree_if_conversion): If-convert also loops with + loop->force_vect. + (gate_tree_if_conversion): Return true even if + cfun->has_force_vect_loops. + 2013-05-09 Jakub Jelinek * tree.c (omp_declare_simd_clauses_equal): New function. diff --git a/gcc/cfgloop.h b/gcc/cfgloop.h index 0f24799663057..5536e60c20c07 100644 --- a/gcc/cfgloop.h +++ b/gcc/cfgloop.h @@ -168,6 +168,15 @@ struct GTY ((chain_next ("%h.next"))) loop { describes what is the state of the estimation. */ enum loop_estimation estimate_state; + /* If > 0, an integer, where the user asserted that for any + I in [ 0, nb_iterations ) and for any J in + [ I, min ( I + safelen, nb_iterations ) ), the Ith and Jth iterations + of the loop can be safely evaluated concurrently. */ + int safelen; + + /* True if we should try harder to vectorize this loop. */ + bool force_vect; + /* Upper bound on number of iterations of a loop. */ struct nb_iter_bound *bounds; diff --git a/gcc/function.h b/gcc/function.h index c0e42d3c39c27..a39fe13dfbde3 100644 --- a/gcc/function.h +++ b/gcc/function.h @@ -641,6 +641,10 @@ struct GTY(()) function { adjusts one of its arguments and forwards to another function. */ unsigned int is_thunk : 1; + + /* Nonzero if the current function contains any loops with + loop->force_vect set. */ + unsigned int has_force_vect_loops : 1; }; /* Add the decl D to the local_decls list of FUN. */ diff --git a/gcc/omp-low.c b/gcc/omp-low.c index b1188732edf26..9a0523b6da6f5 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -4960,6 +4960,8 @@ expand_omp_simd (struct omp_region *region, struct omp_for_data *fd) edge e, ne; tree *counts = NULL; int i; + tree safelen = find_omp_clause (gimple_omp_for_clauses (fd->for_stmt), + OMP_CLAUSE_SAFELEN); type = TREE_TYPE (fd->loop.v); entry_bb = region->entry; @@ -5157,6 +5159,34 @@ expand_omp_simd (struct omp_region *region, struct omp_for_data *fd) set_immediate_dominator (CDI_DOMINATORS, l1_bb, entry_bb); set_immediate_dominator (CDI_DOMINATORS, l2_bb, l1_bb); set_immediate_dominator (CDI_DOMINATORS, l0_bb, l1_bb); + + if (!broken_loop) + { + struct loop *loop = alloc_loop (); + loop->header = l1_bb; + loop->latch = e->dest; + add_loop (loop, l1_bb->loop_father); + if (safelen == NULL_TREE) + loop->safelen = INT_MAX; + else + { + safelen = OMP_CLAUSE_SAFELEN_EXPR (safelen); + if (!host_integerp (safelen, 1) + || (unsigned HOST_WIDE_INT) tree_low_cst (safelen, 1) + > INT_MAX) + loop->safelen = INT_MAX; + else + loop->safelen = tree_low_cst (safelen, 1); + } + /* If not -fno-tree-vectorize, hint that we want to vectorize + the loop. */ + if (flag_tree_vectorize + || !global_options_set.x_flag_tree_vectorize) + { + loop->force_vect = true; + cfun->has_force_vect_loops = true; + } + } } diff --git a/gcc/tree-if-conv.c b/gcc/tree-if-conv.c index 0ebb8c36cea7e..eb3a3fa78d3ea 100644 --- a/gcc/tree-if-conv.c +++ b/gcc/tree-if-conv.c @@ -1822,6 +1822,10 @@ main_tree_if_conversion (void) return 0; FOR_EACH_LOOP (li, loop, 0) + if (flag_tree_loop_if_convert == 1 + || flag_tree_loop_if_convert_stores == 1 + || flag_tree_vectorize + || loop->force_vect) changed |= tree_if_conversion (loop); if (changed) @@ -1848,7 +1852,8 @@ main_tree_if_conversion (void) static bool gate_tree_if_conversion (void) { - return ((flag_tree_vectorize && flag_tree_loop_if_convert != 0) + return (((flag_tree_vectorize || cfun->has_force_vect_loops) + && flag_tree_loop_if_convert != 0) || flag_tree_loop_if_convert == 1 || flag_tree_loop_if_convert_stores == 1); } diff --git a/gcc/tree-ssa-loop-ivcanon.c b/gcc/tree-ssa-loop-ivcanon.c index b5751cb7f7fcc..1a09170f5256e 100644 --- a/gcc/tree-ssa-loop-ivcanon.c +++ b/gcc/tree-ssa-loop-ivcanon.c @@ -1123,6 +1123,11 @@ tree_unroll_loops_completely_1 (bool may_increase_size, bool unroll_outer, if (changed) return true; + /* Don't unroll #pragma omp simd loops until the vectorizer + attempts to vectorize those. */ + if (loop->force_vect) + return false; + /* Try to unroll this loop. */ loop_father = loop_outer (loop); if (!loop_father) diff --git a/gcc/tree-ssa-loop.c b/gcc/tree-ssa-loop.c index 99e27a1359a60..2160318c47ce6 100644 --- a/gcc/tree-ssa-loop.c +++ b/gcc/tree-ssa-loop.c @@ -225,7 +225,7 @@ tree_vectorize (void) static bool gate_tree_vectorize (void) { - return flag_tree_vectorize; + return flag_tree_vectorize || cfun->has_force_vect_loops; } struct gimple_opt_pass pass_vectorize = diff --git a/gcc/tree-vect-data-refs.c b/gcc/tree-vect-data-refs.c index bf0b510db44d1..cd46917b37422 100644 --- a/gcc/tree-vect-data-refs.c +++ b/gcc/tree-vect-data-refs.c @@ -255,6 +255,15 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr, /* Unknown data dependence. */ if (DDR_ARE_DEPENDENT (ddr) == chrec_dont_know) { + /* If user asserted safelen consecutive iterations can be + executed concurrently, assume independence. */ + if (loop->safelen >= 2) + { + if (loop->safelen < *max_vf) + *max_vf = loop->safelen; + return false; + } + if (STMT_VINFO_GATHER_P (stmtinfo_a) || STMT_VINFO_GATHER_P (stmtinfo_b)) { @@ -291,6 +300,15 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr, /* Known data dependence. */ if (DDR_NUM_DIST_VECTS (ddr) == 0) { + /* If user asserted safelen consecutive iterations can be + executed concurrently, assume independence. */ + if (loop->safelen >= 2) + { + if (loop->safelen < *max_vf) + *max_vf = loop->safelen; + return false; + } + if (STMT_VINFO_GATHER_P (stmtinfo_a) || STMT_VINFO_GATHER_P (stmtinfo_b)) { diff --git a/gcc/tree-vectorizer.c b/gcc/tree-vectorizer.c index 843a03ca85ceb..16c205c685428 100644 --- a/gcc/tree-vectorizer.c +++ b/gcc/tree-vectorizer.c @@ -101,7 +101,8 @@ vectorize_loops (void) than all previously defined loops. This fact allows us to run only over initial loops skipping newly generated ones. */ FOR_EACH_LOOP (li, loop, 0) - if (optimize_loop_nest_for_speed_p (loop)) + if ((flag_tree_vectorize && optimize_loop_nest_for_speed_p (loop)) + || loop->force_vect) { loop_vec_info loop_vinfo; vect_location = find_loop_location (loop); @@ -122,6 +123,9 @@ vectorize_loops (void) LOC_FILE (vect_location), LOC_LINE (vect_location)); vect_transform_loop (loop_vinfo); num_vectorized_loops++; + /* Now that the loop has been vectorized, allow it to be unrolled + etc. */ + loop->force_vect = false; } vect_location = UNKNOWN_LOC; From 7a267155b8647d2897568570007f5280164227aa Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Fri, 17 May 2013 12:15:16 -0500 Subject: [PATCH 31/63] Revert: Fixed a uninit. variable error in c-typeck.c --- gcc/c/c-typeck.c | 69 +----------------------------------------------- 1 file changed, 1 insertion(+), 68 deletions(-) diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index 78e714430376a..141162b4f0618 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -10859,8 +10859,7 @@ c_finish_omp_clauses (tree clauses) bitmap_set_bit (&lastprivate_head, DECL_UID (t)); break; - case OMP_CLAUSE_ALIGNED: - name = "aligned"; + case OMP_CLAUSE_ALIGNED: t = OMP_CLAUSE_DECL (c); if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) { @@ -10880,7 +10879,6 @@ c_finish_omp_clauses (tree clauses) break; case OMP_CLAUSE_DEPEND: - name = "depend"; t = OMP_CLAUSE_DECL (c); /* FIXME: depend clause argument may be also array section. */ if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) @@ -10892,11 +10890,8 @@ c_finish_omp_clauses (tree clauses) break; case OMP_CLAUSE_MAP: - name = "map"; case OMP_CLAUSE_TO: - name = "to"; case OMP_CLAUSE_FROM: - name = "from"; t = OMP_CLAUSE_DECL (c); /* FIXME: map clause argument may be also array section. */ if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) @@ -10916,7 +10911,6 @@ c_finish_omp_clauses (tree clauses) break; case OMP_CLAUSE_UNIFORM: - name = "uniform"; t = OMP_CLAUSE_DECL (c); if (TREE_CODE (t) != PARM_DECL) { @@ -10931,87 +10925,26 @@ c_finish_omp_clauses (tree clauses) break; case OMP_CLAUSE_IF: - name = "if"; - pc = &OMP_CLAUSE_CHAIN (c); - continue; case OMP_CLAUSE_NUM_THREADS: - name = "num_threads"; - pc = &OMP_CLAUSE_CHAIN (c); - continue; case OMP_CLAUSE_SCHEDULE: - name = "schedule"; - pc = &OMP_CLAUSE_CHAIN (c); - continue; case OMP_CLAUSE_NOWAIT: - name = "nowait"; - pc = &OMP_CLAUSE_CHAIN (c); - continue; case OMP_CLAUSE_ORDERED: - name = "ordered"; - pc = &OMP_CLAUSE_CHAIN (c); - continue; case OMP_CLAUSE_DEFAULT: - name = "default"; - pc = &OMP_CLAUSE_CHAIN (c); - continue; case OMP_CLAUSE_UNTIED: - name = "untied"; - pc = &OMP_CLAUSE_CHAIN (c); - continue; case OMP_CLAUSE_COLLAPSE: - name = "collapse"; - pc = &OMP_CLAUSE_CHAIN (c); - continue; case OMP_CLAUSE_FINAL: - name = "final"; - pc = &OMP_CLAUSE_CHAIN (c); - continue; case OMP_CLAUSE_MERGEABLE: - name = "mergeable"; - pc = &OMP_CLAUSE_CHAIN (c); - continue; case OMP_CLAUSE_SAFELEN: - name = "safelen"; - pc = &OMP_CLAUSE_CHAIN (c); - continue; case OMP_CLAUSE_SIMDLEN: - name = "simdlen"; - pc = &OMP_CLAUSE_CHAIN (c); - continue; case OMP_CLAUSE_DEVICE: - name = "device"; - pc = &OMP_CLAUSE_CHAIN (c); - continue; case OMP_CLAUSE_DIST_SCHEDULE: - name = "dist_schedule"; - pc = &OMP_CLAUSE_CHAIN (c); - continue; case OMP_CLAUSE_INBRANCH: - name = "inbranch"; - pc = &OMP_CLAUSE_CHAIN (c); - continue; case OMP_CLAUSE_NOTINBRANCH: - name = "notinbranch"; - pc = &OMP_CLAUSE_CHAIN (c); - continue; case OMP_CLAUSE_PARALLEL: - name = "parallel"; - pc = &OMP_CLAUSE_CHAIN (c); - continue; case OMP_CLAUSE_FOR: - name = "for"; - pc = &OMP_CLAUSE_CHAIN (c); - continue; case OMP_CLAUSE_SECTIONS: - name = "sections"; - pc = &OMP_CLAUSE_CHAIN (c); - continue; case OMP_CLAUSE_TASKGROUP: - name = "taskgroup"; - pc = &OMP_CLAUSE_CHAIN (c); - continue; case OMP_CLAUSE_PROC_BIND: - name = "proc_bind"; pc = &OMP_CLAUSE_CHAIN (c); continue; From 1cc2a31de048921c29013547b19af91d619263c3 Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Fri, 17 May 2013 12:36:20 -0500 Subject: [PATCH 32/63] Fix gomp-4_0-branch merge buglets. --- gcc/c/c-parser.c | 4 ++-- gcc/c/c-typeck.c | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index 8ddddacfad8bf..d857f2ab30bfc 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -11961,7 +11961,7 @@ c_parser_cilk_all_clauses (c_parser *parser) break; case PRAGMA_CILK_CLAUSE_REDUCTION: /* Use the OpenMP counterpart. */ - clauses = c_parser_omp_clause_reduction (parser, clauses); + clauses = c_parser_omp_clause_reduction (parser, clauses, false); break; default: c_parser_error (parser, "expected %<#pragma simd%> clause"); @@ -12023,7 +12023,7 @@ c_parser_cilk_for_statement (c_parser *parser, enum rid for_keyword, if (c_parser_next_tokens_start_declaration (parser)) { c_parser_declaration_or_fndef (parser, true, false, false, - false, false, NULL); + false, false, NULL, vNULL); decl = check_for_loop_decls (loc, flag_isoc99); if (decl == NULL) goto error_init; diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index 141162b4f0618..ea4ec3d86b538 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -10938,8 +10938,6 @@ c_finish_omp_clauses (tree clauses) case OMP_CLAUSE_SIMDLEN: case OMP_CLAUSE_DEVICE: case OMP_CLAUSE_DIST_SCHEDULE: - case OMP_CLAUSE_INBRANCH: - case OMP_CLAUSE_NOTINBRANCH: case OMP_CLAUSE_PARALLEL: case OMP_CLAUSE_FOR: case OMP_CLAUSE_SECTIONS: From 8604b5d7d7199af279794a7b839090871886762c Mon Sep 17 00:00:00 2001 From: jakub Date: Mon, 20 May 2013 15:59:12 +0000 Subject: [PATCH 33/63] * omp-low.c (expand_omp_simd): For collapse > 1 loops, if some loop condition might be not true initially, add runtime test and skip the whole loop. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gomp-4_0-branch@199108 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog.gomp | 6 ++++++ gcc/omp-low.c | 40 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/gcc/ChangeLog.gomp b/gcc/ChangeLog.gomp index 1e2f6dcf8c8f2..d9b120f7ddf47 100644 --- a/gcc/ChangeLog.gomp +++ b/gcc/ChangeLog.gomp @@ -1,3 +1,9 @@ +2013-05-20 Jakub Jelinek + + * omp-low.c (expand_omp_simd): For collapse > 1 loops, + if some loop condition might be not true initially, add runtime + test and skip the whole loop. + 2013-05-14 Jakub Jelinek * cfgloop.h (struct loop): Add safelen and force_vect fields. diff --git a/gcc/omp-low.c b/gcc/omp-low.c index f3211034bf0de..6d964840839d1 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -5120,7 +5120,7 @@ static void expand_omp_simd (struct omp_region *region, struct omp_for_data *fd) { tree type, t; - basic_block entry_bb, cont_bb, exit_bb, l0_bb, l1_bb, l2_bb; + basic_block entry_bb, cont_bb, exit_bb, l0_bb, l1_bb, l2_bb, l2_dom_bb; gimple_stmt_iterator gsi; gimple stmt; bool broken_loop = region->cont == NULL; @@ -5151,6 +5151,7 @@ expand_omp_simd (struct omp_region *region, struct omp_for_data *fd) l2_bb = single_succ (l1_bb); } exit_bb = region->exit; + l2_dom_bb = l1_bb; gsi = gsi_last_bb (entry_bb); @@ -5164,6 +5165,41 @@ expand_omp_simd (struct omp_region *region, struct omp_for_data *fd) { tree itype = TREE_TYPE (fd->loops[i].v); + if (SSA_VAR_P (fd->loop.n2) + && ((t = fold_binary (fd->loops[i].cond_code, boolean_type_node, + fold_convert (itype, fd->loops[i].n1), + fold_convert (itype, fd->loops[i].n2))) + == NULL_TREE || !integer_onep (t))) + { + tree n1, n2; + n1 = fold_convert (itype, unshare_expr (fd->loops[i].n1)); + n1 = force_gimple_operand_gsi (&gsi, n1, true, NULL_TREE, + true, GSI_SAME_STMT); + n2 = fold_convert (itype, unshare_expr (fd->loops[i].n2)); + n2 = force_gimple_operand_gsi (&gsi, n2, true, NULL_TREE, + true, GSI_SAME_STMT); + stmt = gimple_build_cond (fd->loops[i].cond_code, n1, n2, + NULL_TREE, NULL_TREE); + gsi_insert_before (&gsi, stmt, GSI_SAME_STMT); + if (walk_tree (gimple_cond_lhs_ptr (stmt), + expand_omp_regimplify_p, NULL, NULL) + || walk_tree (gimple_cond_rhs_ptr (stmt), + expand_omp_regimplify_p, NULL, NULL)) + { + gsi = gsi_for_stmt (stmt); + gimple_regimplify_operands (stmt, &gsi); + } + e = split_block (entry_bb, stmt); + ne = make_edge (entry_bb, l2_bb, EDGE_FALSE_VALUE); + ne->probability = REG_BR_PROB_BASE / 2000 - 1; + e->flags = EDGE_TRUE_VALUE; + e->probability = REG_BR_PROB_BASE - ne->probability; + if (l2_dom_bb == l1_bb) + l2_dom_bb = entry_bb; + entry_bb = e->dest; + e = BRANCH_EDGE (entry_bb); + gsi = gsi_last_bb (entry_bb); + } if (POINTER_TYPE_P (itype)) itype = signed_type_for (itype); t = build_int_cst (itype, (fd->loops[i].cond_code == LT_EXPR @@ -5324,7 +5360,7 @@ expand_omp_simd (struct omp_region *region, struct omp_for_data *fd) ne->probability = REG_BR_PROB_BASE / 8; set_immediate_dominator (CDI_DOMINATORS, l1_bb, entry_bb); - set_immediate_dominator (CDI_DOMINATORS, l2_bb, l1_bb); + set_immediate_dominator (CDI_DOMINATORS, l2_bb, l2_dom_bb); set_immediate_dominator (CDI_DOMINATORS, l0_bb, l1_bb); if (!broken_loop) From 25ec3ed12efae23194e4a4cd956d54d6f37ab91c Mon Sep 17 00:00:00 2001 From: "Balaji V. Iyer" Date: Mon, 20 May 2013 23:09:27 -0400 Subject: [PATCH 34/63] Moved 2 declarations from c-tree to c-common.h. --- gcc/c-family/c-common.h | 5 +++++ gcc/c/c-tree.h | 4 ---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index 78ace779cb266..c96c6f13ed56e 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -521,6 +521,11 @@ struct GTY(()) c_language_function { #define building_stmt_list_p() (stmt_list_stack && !stmt_list_stack->is_empty()) +/* In c-cilkplus.c */ +extern tree c_finish_cilk_simd_loop (location_t, tree, tree, tree, tree, + tree, tree); +extern tree c_finish_cilk_clauses (tree); + /* Language-specific hooks. */ /* If non-NULL, this function is called after a precompile header file diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index 84471db707e4f..356bd6cfd1f53 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -647,10 +647,6 @@ extern tree c_build_va_arg (location_t, tree, tree); extern tree c_finish_transaction (location_t, tree, int); extern bool c_tree_equal (tree, tree); -/* In c-cilkplus.c */ -extern tree c_finish_cilk_simd_loop (location_t, tree, tree, tree, tree, - tree, tree); -extern tree c_finish_cilk_clauses (tree); /* Set to 0 at beginning of a function definition, set to 1 if a return statement that specifies a return value is seen. */ From df8a60d818fe5d1bd03a5f9edbac70868e56d687 Mon Sep 17 00:00:00 2001 From: jakub Date: Mon, 27 May 2013 07:23:21 +0000 Subject: [PATCH 35/63] * tree.def (OMP_TEAMS, OMP_TARGET_DATA, OMP_TARGET, OMP_TARGET_UPDATE): New tree codes. * tree-cfg.c (make_edges): Handle GIMPLE_OMP_TARGET and GIMPLE_OMP_TEAMS. * omp-low.c (scan_sharing_clauses): Handle OMP_CLAUSE_DIST_SCHEDULE. * gimple-low.c (lower_stmt): Handle GIMPLE_OMP_TARGET and GIMPLE_OMP_TEAMS. * tree.h (OMP_TEAMS_BODY, OMP_TEAMS_CLAUSES, OMP_TARGET_DATA_BODY, OMP_TARGET_DATA_CLAUSES, OMP_TARGET_BODY, OMP_TARGET_CLAUSES, OMP_TARGET_UPDATE_CLAUSES): Define. * tree-nested.c (convert_nonlocal_reference_stmt, convert_local_reference_stmt, convert_gimple_call): Handle GIMPLE_OMP_TARGET and GIMPLE_OMP_TEAMS. * tree-inline.c (estimate_num_insns): Likewise. (remap_gimple_stmt): Likewise. Adjust gimple_build_omp_for caller. * gimple.def: Adjust comments describing OMP_CLAUSEs. (GIMPLE_OMP_TARGET, GIMPLE_OMP_TEAMS): New GIMPLE stmts. * tree-parloops.c (create_parallel_loop): Adjust gimple_build_omp_for caller. * tree-pretty-print.c (dump_generic_node): Handle OMP_TEAMS, OMP_TARGET, OMP_TARGET_DATA and OMP_TARGET_UPDATE. * gimple.h (GF_OMP_TARGET_KIND_MASK, GF_OMP_TARGET_KIND_REGION, GF_OMP_TARGET_KIND_DATA, GF_OMP_TARGET_KIND_UPDATE): New. (gimple_build_omp_for): Add kind argument to prototype. (gimple_build_omp_target, gimple_build_omp_teams): New prototypes. (gimple_has_substatements): Handle GIMPLE_OMP_TARGET and GIMPLE_OMP_TEAMS. (gimple_omp_subcode): Change GIMPLE_OMP_SINGLE to GIMPLE_OMP_TEAMS. (gimple_omp_target_clauses, gimple_omp_target_clauses_ptr, gimple_omp_target_set_clauses, gimple_omp_target_kind, gimple_omp_target_set_kind, gimple_omp_teams_clauses, gimple_omp_teams_clauses_ptr, gimple_omp_teams_set_clauses): New inline functions. (gimple_return_set_retval): Handle GIMPLE_OMP_TARGET and GIMPLE_OMP_TEAMS. * gimple.c (gimple_build_omp_for): Add kind argument, call gimple_omp_for_set_kind. (gimple_build_omp_target, gimple_build_omp_teams): New functions. (walk_gimple_op, walk_gimple_stmt, gimple_copy): Handle GIMPLE_OMP_TARGET and GIMPLE_OMP_TEAMS. * gimple-pretty-print.c (dump_gimple_omp_target, dump_gimple_omp_teams): New functions. (pp_gimple_stmt_1): Handle GIMPLE_OMP_TARGET and GIMPLE_OMP_TEAMS. * gimplify.c (enum gimplify_omp_var_data): Add GOVD_MAP. (enum omp_region_type): Add ORT_TEAMS, ORT_TARGET and ORT_TARGET_DATA. (omp_add_variable): Add temporary assertions. (omp_notice_threadprivate_variable): Complain if threadprivate vars appear in target region. (omp_notice_variable): ORT_TARGET, ORT_TARGET_DATA and ORT_TEAMS handling. (omp_check_private): Ignore ORT_TARGET and ORT_TARGET_DATA regions. (gimplify_scan_omp_clauses): Handle OMP_CLAUSE_MAP, OMP_CLAUSE_TO, OMP_CLAUSE_FROM, OMP_CLAUSE_NUM_TEAMS, OMP_CLAUSE_DIST_SCHEDULE and OMP_CLAUSE_DEVICE. (gimplify_adjust_omp_clauses): Likewise. (gimplify_adjust_omp_clauses_1): Handle GOVD_MAP. Fix up check for privatization by also testing for GOVD_LINEAR. (gimplify_omp_for): Adjust gimple_build_omp_for caller. Clear *expr_p. (gimplify_omp_workshare): Handle also OMP_TARGET, OMP_TARGET_DATA and OMP_TEAMS. Clear *expr_p. (gimplify_omp_target_update): New function. (gimplify_expr): Handle OMP_TARGET, OMP_TARGET_DATA, OMP_TARGET_UPDATE and OMP_TEAMS. cp/ * parser.c (cp_parser_omp_clause_cancelkind): Remove diagnostics. (cp_parser_omp_all_clauses): Require that OMP_CLAUSE_{TO,FROM} and OMP_CLAUSE_{PARALLEL,FOR,SECTIONS,TASKGROUP} must be first in the list of clauses. (OMP_TEAMS_CLAUSE_MASK, OMP_TARGET_CLAUSE_MASK, OMP_TARGET_DATA_CLAUSE_MASK, OMP_TARGET_UPDATE_CLAUSE_MASK, OMP_DISTRIBUTE_CLAUSE_MASK): Define. (cp_parser_omp_teams, cp_parser_omp_target, cp_parser_omp_target_data, cp_parser_omp_target_update, cp_parser_omp_distribute): New functions. (cp_parser_omp_construct): Handle PRAGMA_OMP_DISTRIBUTE and PRAGMA_OMP_TEAMS. (cp_parser_pragma): Handle PRAGMA_OMP_DISTRIBUTE, PRAGMA_OMP_TEAMS and PRAGMA_OMP_TARGET. * pt.c (tsubst_expr): Handle OMP_TEAMS, OMP_TARGET, OMP_TARGET_DATA and OMP_TARGET_UPDATE. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gomp-4_0-branch@199349 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog.gomp | 68 ++++++++++ gcc/cp/ChangeLog.gomp | 18 +++ gcc/cp/parser.c | 222 ++++++++++++++++++++++++++++--- gcc/cp/pt.c | 11 ++ gcc/gimple-low.c | 2 + gcc/gimple-pretty-print.c | 80 +++++++++++ gcc/gimple.c | 56 +++++++- gcc/gimple.def | 20 ++- gcc/gimple.h | 97 +++++++++++++- gcc/gimplify.c | 271 +++++++++++++++++++++++++++++++++----- gcc/omp-low.c | 2 + gcc/tree-cfg.c | 2 + gcc/tree-inline.c | 18 ++- gcc/tree-nested.c | 34 +++++ gcc/tree-parloops.c | 2 +- gcc/tree-pretty-print.c | 21 +++ gcc/tree.def | 19 +++ gcc/tree.h | 14 ++ 18 files changed, 894 insertions(+), 63 deletions(-) diff --git a/gcc/ChangeLog.gomp b/gcc/ChangeLog.gomp index d9b120f7ddf47..0db46c9aef55f 100644 --- a/gcc/ChangeLog.gomp +++ b/gcc/ChangeLog.gomp @@ -1,3 +1,71 @@ +2013-05-27 Jakub Jelinek + + * tree.def (OMP_TEAMS, OMP_TARGET_DATA, OMP_TARGET, + OMP_TARGET_UPDATE): New tree codes. + * tree-cfg.c (make_edges): Handle GIMPLE_OMP_TARGET + and GIMPLE_OMP_TEAMS. + * omp-low.c (scan_sharing_clauses): Handle OMP_CLAUSE_DIST_SCHEDULE. + * gimple-low.c (lower_stmt): Handle GIMPLE_OMP_TARGET + and GIMPLE_OMP_TEAMS. + * tree.h (OMP_TEAMS_BODY, OMP_TEAMS_CLAUSES, OMP_TARGET_DATA_BODY, + OMP_TARGET_DATA_CLAUSES, OMP_TARGET_BODY, OMP_TARGET_CLAUSES, + OMP_TARGET_UPDATE_CLAUSES): Define. + * tree-nested.c (convert_nonlocal_reference_stmt, + convert_local_reference_stmt, convert_gimple_call): Handle + GIMPLE_OMP_TARGET and GIMPLE_OMP_TEAMS. + * tree-inline.c (estimate_num_insns): Likewise. + (remap_gimple_stmt): Likewise. Adjust gimple_build_omp_for + caller. + * gimple.def: Adjust comments describing OMP_CLAUSEs. + (GIMPLE_OMP_TARGET, GIMPLE_OMP_TEAMS): New GIMPLE stmts. + * tree-parloops.c (create_parallel_loop): Adjust gimple_build_omp_for + caller. + * tree-pretty-print.c (dump_generic_node): Handle OMP_TEAMS, + OMP_TARGET, OMP_TARGET_DATA and OMP_TARGET_UPDATE. + * gimple.h (GF_OMP_TARGET_KIND_MASK, GF_OMP_TARGET_KIND_REGION, + GF_OMP_TARGET_KIND_DATA, GF_OMP_TARGET_KIND_UPDATE): New. + (gimple_build_omp_for): Add kind argument to prototype. + (gimple_build_omp_target, gimple_build_omp_teams): New prototypes. + (gimple_has_substatements): Handle GIMPLE_OMP_TARGET and + GIMPLE_OMP_TEAMS. + (gimple_omp_subcode): Change GIMPLE_OMP_SINGLE to GIMPLE_OMP_TEAMS. + (gimple_omp_target_clauses, gimple_omp_target_clauses_ptr, + gimple_omp_target_set_clauses, gimple_omp_target_kind, + gimple_omp_target_set_kind, gimple_omp_teams_clauses, + gimple_omp_teams_clauses_ptr, gimple_omp_teams_set_clauses): New + inline functions. + (gimple_return_set_retval): Handle GIMPLE_OMP_TARGET and + GIMPLE_OMP_TEAMS. + * gimple.c (gimple_build_omp_for): Add kind argument, call + gimple_omp_for_set_kind. + (gimple_build_omp_target, gimple_build_omp_teams): New functions. + (walk_gimple_op, walk_gimple_stmt, gimple_copy): Handle + GIMPLE_OMP_TARGET and GIMPLE_OMP_TEAMS. + * gimple-pretty-print.c (dump_gimple_omp_target, + dump_gimple_omp_teams): New functions. + (pp_gimple_stmt_1): Handle GIMPLE_OMP_TARGET and GIMPLE_OMP_TEAMS. + * gimplify.c (enum gimplify_omp_var_data): Add GOVD_MAP. + (enum omp_region_type): Add ORT_TEAMS, ORT_TARGET and ORT_TARGET_DATA. + (omp_add_variable): Add temporary assertions. + (omp_notice_threadprivate_variable): Complain if threadprivate vars + appear in target region. + (omp_notice_variable): ORT_TARGET, ORT_TARGET_DATA and ORT_TEAMS + handling. + (omp_check_private): Ignore ORT_TARGET and ORT_TARGET_DATA regions. + (gimplify_scan_omp_clauses): Handle OMP_CLAUSE_MAP, OMP_CLAUSE_TO, + OMP_CLAUSE_FROM, OMP_CLAUSE_NUM_TEAMS, OMP_CLAUSE_DIST_SCHEDULE + and OMP_CLAUSE_DEVICE. + (gimplify_adjust_omp_clauses): Likewise. + (gimplify_adjust_omp_clauses_1): Handle GOVD_MAP. Fix up + check for privatization by also testing for GOVD_LINEAR. + (gimplify_omp_for): Adjust gimple_build_omp_for caller. + Clear *expr_p. + (gimplify_omp_workshare): Handle also OMP_TARGET, OMP_TARGET_DATA + and OMP_TEAMS. Clear *expr_p. + (gimplify_omp_target_update): New function. + (gimplify_expr): Handle OMP_TARGET, OMP_TARGET_DATA, OMP_TARGET_UPDATE + and OMP_TEAMS. + 2013-05-20 Jakub Jelinek * omp-low.c (expand_omp_simd): For collapse > 1 loops, diff --git a/gcc/cp/ChangeLog.gomp b/gcc/cp/ChangeLog.gomp index 69be3ded3780b..9f3f38c18c66b 100644 --- a/gcc/cp/ChangeLog.gomp +++ b/gcc/cp/ChangeLog.gomp @@ -1,3 +1,21 @@ +2013-05-27 Jakub Jelinek + + * parser.c (cp_parser_omp_clause_cancelkind): Remove diagnostics. + (cp_parser_omp_all_clauses): Require that OMP_CLAUSE_{TO,FROM} + and OMP_CLAUSE_{PARALLEL,FOR,SECTIONS,TASKGROUP} must be first in + the list of clauses. + (OMP_TEAMS_CLAUSE_MASK, OMP_TARGET_CLAUSE_MASK, + OMP_TARGET_DATA_CLAUSE_MASK, OMP_TARGET_UPDATE_CLAUSE_MASK, + OMP_DISTRIBUTE_CLAUSE_MASK): Define. + (cp_parser_omp_teams, cp_parser_omp_target, cp_parser_omp_target_data, + cp_parser_omp_target_update, cp_parser_omp_distribute): New functions. + (cp_parser_omp_construct): Handle PRAGMA_OMP_DISTRIBUTE and + PRAGMA_OMP_TEAMS. + (cp_parser_pragma): Handle PRAGMA_OMP_DISTRIBUTE, PRAGMA_OMP_TEAMS + and PRAGMA_OMP_TARGET. + * pt.c (tsubst_expr): Handle OMP_TEAMS, OMP_TARGET, OMP_TARGET_DATA + and OMP_TARGET_UPDATE. + 2013-05-09 Jakub Jelinek * cp-tree.h (cp_decl_specifier_seq): Add omp_declare_simd_clauses diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index d7b041c0b5c77..5bbb46b1c8792 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -26823,22 +26823,7 @@ cp_parser_omp_clause_cancelkind (cp_parser * /*parser*/, enum omp_clause_code code, tree list, location_t location) { - tree c; - - for (c = list; c; c = OMP_CLAUSE_CHAIN (c)) - switch (OMP_CLAUSE_CODE (c)) - { - case OMP_CLAUSE_PARALLEL: - case OMP_CLAUSE_FOR: - case OMP_CLAUSE_SECTIONS: - case OMP_CLAUSE_TASKGROUP: - error_at (location, "only one of %, %, % " - "and % clauses can be specified"); - break; - default: - break; - } - c = build_omp_clause (location, code); + tree c = build_omp_clause (location, code); OMP_CLAUSE_CHAIN (c) = list; return c; } @@ -27260,7 +27245,6 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask, token = cp_lexer_peek_token (parser->lexer); c_kind = cp_parser_omp_clause_name (parser); - first = false; switch (c_kind) { @@ -27359,31 +27343,48 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask, clauses = cp_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_PARALLEL, clauses, token->location); c_name = "parallel"; + if (!first) + { + clause_not_first: + error_at (token->location, "%qs must be the first clause of %qs", + c_name, where); + clauses = prev; + } break; case PRAGMA_OMP_CLAUSE_FOR: clauses = cp_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_FOR, clauses, token->location); c_name = "for"; + if (!first) + goto clause_not_first; break; case PRAGMA_OMP_CLAUSE_SECTIONS: clauses = cp_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_SECTIONS, clauses, token->location); c_name = "sections"; + if (!first) + goto clause_not_first; break; case PRAGMA_OMP_CLAUSE_TASKGROUP: clauses = cp_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_TASKGROUP, clauses, token->location); c_name = "taskgroup"; + if (!first) + goto clause_not_first; break; case PRAGMA_OMP_CLAUSE_TO: clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_TO, clauses); c_name = "to"; + if (!first) + goto clause_not_first; break; case PRAGMA_OMP_CLAUSE_FROM: clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_FROM, clauses); c_name = "from"; + if (!first) + goto clause_not_first; break; case PRAGMA_OMP_CLAUSE_UNIFORM: clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_UNIFORM, @@ -27441,6 +27442,8 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask, goto saw_error; } + first = false; + if (((mask >> c_kind) & 1) == 0) { /* Remove the invalid clause(s) from the list to avoid @@ -29012,6 +29015,180 @@ cp_parser_omp_cancellation_point (cp_parser *parser, cp_token *pragma_tok) finish_omp_cancellation_point (clauses); } +/* OpenMP 4.0: + # pragma omp teams teams-clause[optseq] new-line + structured-block */ + +#define OMP_TEAMS_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_TEAMS) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT)) + +static tree +cp_parser_omp_teams (cp_parser *parser, cp_token *pragma_tok) +{ + tree stmt = make_node (OMP_TEAMS); + TREE_TYPE (stmt) = void_type_node; + + OMP_TEAMS_CLAUSES (stmt) + = cp_parser_omp_all_clauses (parser, OMP_TEAMS_CLAUSE_MASK, + "#pragma omp teams", pragma_tok); + OMP_TEAMS_BODY (stmt) = cp_parser_omp_structured_block (parser); + + return add_stmt (stmt); +} + +/* OpenMP 4.0: + # pragma omp target data target-data-clause[optseq] new-line + structured-block */ + +#define OMP_TARGET_DATA_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF)) + +static tree +cp_parser_omp_target_data (cp_parser *parser, cp_token *pragma_tok) +{ + tree stmt = make_node (OMP_TARGET_DATA); + TREE_TYPE (stmt) = void_type_node; + + OMP_TARGET_DATA_CLAUSES (stmt) + = cp_parser_omp_all_clauses (parser, OMP_TARGET_DATA_CLAUSE_MASK, + "#pragma omp target data", pragma_tok); + OMP_TARGET_DATA_BODY (stmt) = cp_parser_omp_structured_block (parser); + + SET_EXPR_LOCATION (stmt, pragma_tok->location); + return add_stmt (stmt); +} + +/* OpenMP 4.0: + # pragma omp target update target-update-clause[optseq] new-line */ + +#define OMP_TARGET_UPDATE_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FROM) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TO) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF)) + +static bool +cp_parser_omp_target_update (cp_parser *parser, cp_token *pragma_tok, + enum pragma_context context) +{ + if (context == pragma_stmt) + { + error_at (pragma_tok->location, + "%<#pragma omp target update%> may only be " + "used in compound statements"); + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + return false; + } + + tree clauses + = cp_parser_omp_all_clauses (parser, OMP_TARGET_UPDATE_CLAUSE_MASK, + "#pragma omp target update", pragma_tok); + if (find_omp_clause (clauses, OMP_CLAUSE_TO) == NULL_TREE + && find_omp_clause (clauses, OMP_CLAUSE_FROM) == NULL_TREE) + { + error_at (pragma_tok->location, + "%<#pragma omp target update must contain either " + "% or % clauses"); + return false; + } + + tree stmt = make_node (OMP_TARGET_UPDATE); + TREE_TYPE (stmt) = void_type_node; + OMP_TARGET_UPDATE_CLAUSES (stmt) = clauses; + SET_EXPR_LOCATION (stmt, pragma_tok->location); + add_stmt (stmt); + return false; +} + +/* OpenMP 4.0: + # pragma omp target target-clause[optseq] new-line + structured-block */ + +#define OMP_TARGET_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF)) + +static bool +cp_parser_omp_target (cp_parser *parser, cp_token *pragma_tok, + enum pragma_context context) +{ + if (context != pragma_stmt && context != pragma_compound) + { + cp_parser_error (parser, "expected declaration specifiers"); + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + return 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, "data") == 0) + { + cp_lexer_consume_token (parser->lexer); + cp_parser_omp_target_data (parser, pragma_tok); + return true; + } + else if (strcmp (p, "update") == 0) + { + cp_lexer_consume_token (parser->lexer); + return cp_parser_omp_target_update (parser, pragma_tok, context); + } + } + + tree stmt = make_node (OMP_TARGET); + TREE_TYPE (stmt) = void_type_node; + + OMP_TARGET_CLAUSES (stmt) + = cp_parser_omp_all_clauses (parser, OMP_TARGET_CLAUSE_MASK, + "#pragma omp target", pragma_tok); + OMP_TARGET_BODY (stmt) = cp_parser_omp_structured_block (parser); + + SET_EXPR_LOCATION (stmt, pragma_tok->location); + add_stmt (stmt); + return true; +} + +/* OpenMP 4.0: + #pragma omp distribute distribute-clause[optseq] new-line + for-loop */ + +#define OMP_DISTRIBUTE_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)\ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE)) + +static tree +cp_parser_omp_distribute (cp_parser *parser, cp_token *pragma_tok) +{ + tree clauses, sb, ret; + unsigned int save; + + clauses = cp_parser_omp_all_clauses (parser, OMP_DISTRIBUTE_CLAUSE_MASK, + "#pragma omp distribute", pragma_tok); + + sb = begin_omp_structured_block (); + save = cp_parser_begin_omp_structured_block (parser); + + ret = cp_parser_omp_for_loop (parser, OMP_DISTRIBUTE, clauses, NULL); + + cp_parser_end_omp_structured_block (parser, save); + add_stmt (finish_omp_structured_block (sb)); + + return ret; +} + /* OpenMP 4.0: # pragma omp declare simd declare-simd-clauses[optseq] new-line */ @@ -29112,6 +29289,9 @@ cp_parser_omp_construct (cp_parser *parser, cp_token *pragma_tok) case PRAGMA_OMP_CRITICAL: stmt = cp_parser_omp_critical (parser, pragma_tok); break; + case PRAGMA_OMP_DISTRIBUTE: + stmt = cp_parser_omp_distribute (parser, pragma_tok); + break; case PRAGMA_OMP_FOR: stmt = cp_parser_omp_for (parser, pragma_tok); break; @@ -29139,6 +29319,9 @@ cp_parser_omp_construct (cp_parser *parser, cp_token *pragma_tok) case PRAGMA_OMP_TASKGROUP: cp_parser_omp_taskgroup (parser, pragma_tok); return; + case PRAGMA_OMP_TEAMS: + stmt = cp_parser_omp_teams (parser, pragma_tok); + break; default: gcc_unreachable (); } @@ -29609,6 +29792,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context) case PRAGMA_OMP_ATOMIC: case PRAGMA_OMP_CRITICAL: + case PRAGMA_OMP_DISTRIBUTE: case PRAGMA_OMP_FOR: case PRAGMA_OMP_MASTER: case PRAGMA_OMP_ORDERED: @@ -29618,11 +29802,15 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context) case PRAGMA_OMP_SINGLE: case PRAGMA_OMP_TASK: case PRAGMA_OMP_TASKGROUP: + case PRAGMA_OMP_TEAMS: if (context != pragma_stmt && context != pragma_compound) goto bad_stmt; cp_parser_omp_construct (parser, pragma_tok); return true; + case PRAGMA_OMP_TARGET: + return cp_parser_omp_target (parser, pragma_tok, context); + case PRAGMA_OMP_SECTION: error_at (pragma_tok->location, "%<#pragma omp section%> may only be used in " diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 284f6ab6539e5..9583afd51ce76 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -13330,6 +13330,9 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, case OMP_SECTIONS: case OMP_SINGLE: + case OMP_TEAMS: + case OMP_TARGET_DATA: + case OMP_TARGET: tmp = tsubst_omp_clauses (OMP_CLAUSES (t), false, args, complain, in_decl); stmt = push_stmt_list (); @@ -13342,6 +13345,14 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, add_stmt (t); break; + case OMP_TARGET_UPDATE: + tmp = tsubst_omp_clauses (OMP_TARGET_UPDATE_CLAUSES (t), false, + args, complain, in_decl); + t = copy_node (t); + OMP_CLAUSES (t) = tmp; + add_stmt (t); + break; + case OMP_SECTION: case OMP_CRITICAL: case OMP_MASTER: diff --git a/gcc/gimple-low.c b/gcc/gimple-low.c index b06d194da657c..cf61ef0d6468d 100644 --- a/gcc/gimple-low.c +++ b/gcc/gimple-low.c @@ -444,6 +444,8 @@ lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data) case GIMPLE_OMP_PARALLEL: case GIMPLE_OMP_TASK: + case GIMPLE_OMP_TARGET: + case GIMPLE_OMP_TEAMS: data->cannot_fallthru = false; lower_omp_directive (gsi, data); data->cannot_fallthru = false; diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c index 14872166946c6..ee264e10a8889 100644 --- a/gcc/gimple-pretty-print.c +++ b/gcc/gimple-pretty-print.c @@ -1264,6 +1264,78 @@ dump_gimple_omp_single (pretty_printer *buffer, gimple gs, int spc, int flags) } } +/* Dump a GIMPLE_OMP_TARGET tuple on the pretty_printer BUFFER. */ + +static void +dump_gimple_omp_target (pretty_printer *buffer, gimple gs, int spc, int flags) +{ + const char *kind; + switch (gimple_omp_target_kind (gs)) + { + case GF_OMP_TARGET_KIND_REGION: + kind = ""; + break; + case GF_OMP_TARGET_KIND_DATA: + kind = " data"; + break; + case GF_OMP_TARGET_KIND_UPDATE: + kind = " update"; + break; + default: + gcc_unreachable (); + } + if (flags & TDF_RAW) + { + dump_gimple_fmt (buffer, spc, flags, "%G%s <%+BODY <%S>%nCLAUSES <", gs, + kind, gimple_omp_body (gs)); + dump_omp_clauses (buffer, gimple_omp_target_clauses (gs), spc, flags); + dump_gimple_fmt (buffer, spc, flags, " >"); + } + else + { + pp_string (buffer, "#pragma omp target"); + pp_string (buffer, kind); + dump_omp_clauses (buffer, gimple_omp_target_clauses (gs), spc, flags); + if (!gimple_seq_empty_p (gimple_omp_body (gs))) + { + newline_and_indent (buffer, spc + 2); + pp_character (buffer, '{'); + pp_newline (buffer); + dump_gimple_seq (buffer, gimple_omp_body (gs), spc + 4, flags); + newline_and_indent (buffer, spc + 2); + pp_character (buffer, '}'); + } + } +} + +/* Dump a GIMPLE_OMP_TEAMS tuple on the pretty_printer BUFFER. */ + +static void +dump_gimple_omp_teams (pretty_printer *buffer, gimple gs, int spc, int flags) +{ + if (flags & TDF_RAW) + { + dump_gimple_fmt (buffer, spc, flags, "%G <%+BODY <%S>%nCLAUSES <", gs, + gimple_omp_body (gs)); + dump_omp_clauses (buffer, gimple_omp_teams_clauses (gs), spc, flags); + dump_gimple_fmt (buffer, spc, flags, " >"); + } + else + { + pp_string (buffer, "#pragma omp teams"); + dump_omp_clauses (buffer, gimple_omp_teams_clauses (gs), spc, flags); + if (!gimple_seq_empty_p (gimple_omp_body (gs))) + { + newline_and_indent (buffer, spc + 2); + pp_character (buffer, '{'); + pp_newline (buffer); + dump_gimple_seq (buffer, gimple_omp_body (gs), spc + 4, flags); + newline_and_indent (buffer, spc + 2); + pp_character (buffer, '}'); + } + } +} + /* Dump a GIMPLE_OMP_SECTIONS tuple on the pretty_printer BUFFER. */ static void @@ -2038,6 +2110,14 @@ pp_gimple_stmt_1 (pretty_printer *buffer, gimple gs, int spc, int flags) dump_gimple_omp_single (buffer, gs, spc, flags); break; + case GIMPLE_OMP_TARGET: + dump_gimple_omp_target (buffer, gs, spc, flags); + break; + + case GIMPLE_OMP_TEAMS: + dump_gimple_omp_teams (buffer, gs, spc, flags); + break; + case GIMPLE_OMP_RETURN: dump_gimple_omp_return (buffer, gs, spc, flags); break; diff --git a/gcc/gimple.c b/gcc/gimple.c index f5074199381bf..7d137fdfc5aca 100644 --- a/gcc/gimple.c +++ b/gcc/gimple.c @@ -908,13 +908,14 @@ gimple_build_omp_critical (gimple_seq body, tree name) PRE_BODY is the sequence of statements that are loop invariant. */ gimple -gimple_build_omp_for (gimple_seq body, tree clauses, size_t collapse, +gimple_build_omp_for (gimple_seq body, int kind, tree clauses, size_t collapse, gimple_seq pre_body) { gimple p = gimple_alloc (GIMPLE_OMP_FOR, 0); if (body) gimple_omp_set_body (p, body); gimple_omp_for_set_clauses (p, clauses); + gimple_omp_for_set_kind (p, kind); p->gimple_omp_for.collapse = collapse; p->gimple_omp_for.iter = ggc_alloc_cleared_vec_gimple_omp_for_iter (collapse); @@ -1094,6 +1095,41 @@ gimple_build_omp_single (gimple_seq body, tree clauses) } +/* Build a GIMPLE_OMP_TARGET statement. + + BODY is the sequence of statements that will be executed. + CLAUSES are any of the OMP target construct's clauses. */ + +gimple +gimple_build_omp_target (gimple_seq body, int kind, tree clauses) +{ + gimple p = gimple_alloc (GIMPLE_OMP_TARGET, 0); + if (body) + gimple_omp_set_body (p, body); + gimple_omp_target_set_clauses (p, clauses); + gimple_omp_target_set_kind (p, kind); + + return p; +} + + +/* Build a GIMPLE_OMP_TEAMS statement. + + BODY is the sequence of statements that will be executed. + CLAUSES are any of the OMP teams construct's clauses. */ + +gimple +gimple_build_omp_teams (gimple_seq body, tree clauses) +{ + gimple p = gimple_alloc (GIMPLE_OMP_TEAMS, 0); + if (body) + gimple_omp_set_body (p, body); + gimple_omp_teams_set_clauses (p, clauses); + + return p; +} + + /* Build a GIMPLE_OMP_ATOMIC_LOAD statement. */ gimple @@ -1610,6 +1646,20 @@ walk_gimple_op (gimple stmt, walk_tree_fn callback_op, return ret; break; + case GIMPLE_OMP_TARGET: + ret = walk_tree (gimple_omp_target_clauses_ptr (stmt), callback_op, wi, + pset); + if (ret) + return ret; + break; + + case GIMPLE_OMP_TEAMS: + ret = walk_tree (gimple_omp_teams_clauses_ptr (stmt), callback_op, wi, + pset); + if (ret) + return ret; + break; + case GIMPLE_OMP_ATOMIC_LOAD: ret = walk_tree (gimple_omp_atomic_load_lhs_ptr (stmt), callback_op, wi, pset); @@ -1786,6 +1836,8 @@ walk_gimple_stmt (gimple_stmt_iterator *gsi, walk_stmt_fn callback_stmt, case GIMPLE_OMP_TASK: case GIMPLE_OMP_SECTIONS: case GIMPLE_OMP_SINGLE: + case GIMPLE_OMP_TARGET: + case GIMPLE_OMP_TEAMS: ret = walk_gimple_seq_mod (gimple_omp_body_ptr (stmt), callback_stmt, callback_op, wi); if (ret) @@ -2308,6 +2360,8 @@ gimple_copy (gimple stmt) /* FALLTHRU */ case GIMPLE_OMP_SINGLE: + case GIMPLE_OMP_TARGET: + case GIMPLE_OMP_TEAMS: case GIMPLE_OMP_SECTION: case GIMPLE_OMP_MASTER: case GIMPLE_OMP_ORDERED: diff --git a/gcc/gimple.def b/gcc/gimple.def index acad572e35307..8d75ada3ec3d0 100644 --- a/gcc/gimple.def +++ b/gcc/gimple.def @@ -287,7 +287,7 @@ DEFGSCODE(GIMPLE_OMP_ORDERED, "gimple_omp_ordered", GSS_OMP) BODY is a the sequence of statements to be executed by all threads. - CLAUSES is a TREE_LIST node with all the clauses. + CLAUSES is an OMP_CLAUSE chain with all the clauses. CHILD_FN is set when outlining the body of the parallel region. All the statements in BODY are moved into this newly created @@ -306,7 +306,7 @@ DEFGSCODE(GIMPLE_OMP_PARALLEL, "gimple_omp_parallel", GSS_OMP_PARALLEL) BODY is a the sequence of statements to be executed by all threads. - CLAUSES is a TREE_LIST node with all the clauses. + CLAUSES is an OMP_CLAUSE chain with all the clauses. CHILD_FN is set when outlining the body of the explicit task region. All the statements in BODY are moved into this newly created @@ -334,7 +334,7 @@ DEFGSCODE(GIMPLE_OMP_SECTION, "gimple_omp_section", GSS_OMP) /* OMP_SECTIONS represents #pragma omp sections. BODY is the sequence of statements in the sections body. - CLAUSES is a TREE_LIST node holding the list of associated clauses. + CLAUSES is an OMP_CLAUSE chain holding the list of associated clauses. CONTROL is a VAR_DECL used for deciding which of the sections to execute. */ DEFGSCODE(GIMPLE_OMP_SECTIONS, "gimple_omp_sections", GSS_OMP_SECTIONS) @@ -346,9 +346,21 @@ DEFGSCODE(GIMPLE_OMP_SECTIONS_SWITCH, "gimple_omp_sections_switch", GSS_BASE) /* GIMPLE_OMP_SINGLE represents #pragma omp single BODY is the sequence of statements inside the single section. - CLAUSES is a TREE_LIST node holding the associated clauses. */ + CLAUSES is an OMP_CLAUSE chain holding the associated clauses. */ DEFGSCODE(GIMPLE_OMP_SINGLE, "gimple_omp_single", GSS_OMP_SINGLE) +/* GIMPLE_OMP_TARGET represents + #pragma omp target {,data,update} + BODY is the sequence of statements inside the target construct + (NULL for target update). + CLAUSES is an OMP_CLAUSE chain holding the associated clauses. */ +DEFGSCODE(GIMPLE_OMP_TARGET, "gimple_omp_target", GSS_OMP_SINGLE) + +/* GIMPLE_OMP_TEAMS represents #pragma omp teams + BODY is the sequence of statements inside the single section. + CLAUSES is an OMP_CLAUSE chain holding the associated clauses. */ +DEFGSCODE(GIMPLE_OMP_TEAMS, "gimple_omp_teams", GSS_OMP_SINGLE) + /* GIMPLE_PREDICT specifies a hint for branch prediction. PREDICT is one of the predictors from predict.def. diff --git a/gcc/gimple.h b/gcc/gimple.h index 93e2c2732f807..5060b282afdcc 100644 --- a/gcc/gimple.h +++ b/gcc/gimple.h @@ -115,6 +115,10 @@ enum gf_mask { GF_OMP_FOR_KIND_SIMD = 1 << 0, GF_OMP_FOR_KIND_FOR_SIMD = 2 << 0, GF_OMP_FOR_KIND_DISTRIBUTE = 3 << 0, + GF_OMP_TARGET_KIND_MASK = 3 << 0, + GF_OMP_TARGET_KIND_REGION = 0 << 0, + GF_OMP_TARGET_KIND_DATA = 1 << 0, + GF_OMP_TARGET_KIND_UPDATE = 2 << 0, /* True on an GIMPLE_OMP_RETURN statement if the return does not require a thread synchronization via some sort of barrier. The exact barrier @@ -618,7 +622,7 @@ struct GTY(()) gimple_statement_omp_continue { tree control_use; }; -/* GIMPLE_OMP_SINGLE */ +/* GIMPLE_OMP_SINGLE, GIMPLE_OMP_TARGET, GIMPLE_OMP_TEAMS */ struct GTY(()) gimple_statement_omp_single { /* [ WORD 1-7 ] */ @@ -805,7 +809,7 @@ gimple gimple_build_switch_nlabels (unsigned, tree, tree); gimple gimple_build_switch (tree, tree, vec ); gimple gimple_build_omp_parallel (gimple_seq, tree, tree, tree); gimple gimple_build_omp_task (gimple_seq, tree, tree, tree, tree, tree, tree); -gimple gimple_build_omp_for (gimple_seq, tree, size_t, gimple_seq); +gimple gimple_build_omp_for (gimple_seq, int, tree, size_t, gimple_seq); gimple gimple_build_omp_critical (gimple_seq, tree); gimple gimple_build_omp_section (gimple_seq); gimple gimple_build_omp_continue (tree, tree); @@ -815,6 +819,8 @@ gimple gimple_build_omp_ordered (gimple_seq); gimple gimple_build_omp_sections (gimple_seq, tree); gimple gimple_build_omp_sections_switch (void); gimple gimple_build_omp_single (gimple_seq, tree); +gimple gimple_build_omp_target (gimple_seq, int, tree); +gimple gimple_build_omp_teams (gimple_seq, tree); gimple gimple_build_cdt (tree, tree); gimple gimple_build_omp_atomic_load (tree, tree); gimple gimple_build_omp_atomic_store (tree); @@ -1264,6 +1270,8 @@ gimple_has_substatements (gimple g) case GIMPLE_OMP_TASK: case GIMPLE_OMP_SECTIONS: case GIMPLE_OMP_SINGLE: + case GIMPLE_OMP_TARGET: + case GIMPLE_OMP_TEAMS: case GIMPLE_OMP_CRITICAL: case GIMPLE_WITH_CLEANUP_EXPR: case GIMPLE_TRANSACTION: @@ -1691,7 +1699,7 @@ static inline unsigned gimple_omp_subcode (const_gimple s) { gcc_gimple_checking_assert (gimple_code (s) >= GIMPLE_OMP_ATOMIC_LOAD - && gimple_code (s) <= GIMPLE_OMP_SINGLE); + && gimple_code (s) <= GIMPLE_OMP_TEAMS); return s->gsbase.subcode; } @@ -4604,6 +4612,87 @@ gimple_omp_single_set_clauses (gimple gs, tree clauses) } +/* Return the clauses associated with OMP_TARGET GS. */ + +static inline tree +gimple_omp_target_clauses (const_gimple gs) +{ + GIMPLE_CHECK (gs, GIMPLE_OMP_TARGET); + return gs->gimple_omp_single.clauses; +} + + +/* Return a pointer to the clauses associated with OMP_TARGET GS. */ + +static inline tree * +gimple_omp_target_clauses_ptr (gimple gs) +{ + GIMPLE_CHECK (gs, GIMPLE_OMP_TARGET); + return &gs->gimple_omp_single.clauses; +} + + +/* Set CLAUSES to be the clauses associated with OMP_TARGET GS. */ + +static inline void +gimple_omp_target_set_clauses (gimple gs, tree clauses) +{ + GIMPLE_CHECK (gs, GIMPLE_OMP_TARGET); + gs->gimple_omp_single.clauses = clauses; +} + + +/* Return the kind of OMP target statemement. */ + +static inline int +gimple_omp_target_kind (const_gimple g) +{ + GIMPLE_CHECK (g, GIMPLE_OMP_TARGET); + return (gimple_omp_subcode (g) & GF_OMP_TARGET_KIND_MASK); +} + + +/* Set the OMP target kind. */ + +static inline void +gimple_omp_target_set_kind (gimple g, int kind) +{ + GIMPLE_CHECK (g, GIMPLE_OMP_TARGET); + g->gsbase.subcode = (g->gsbase.subcode & ~GF_OMP_TARGET_KIND_MASK) + | (kind & GF_OMP_TARGET_KIND_MASK); +} + + +/* Return the clauses associated with OMP_TEAMS GS. */ + +static inline tree +gimple_omp_teams_clauses (const_gimple gs) +{ + GIMPLE_CHECK (gs, GIMPLE_OMP_TEAMS); + return gs->gimple_omp_single.clauses; +} + + +/* Return a pointer to the clauses associated with OMP_TEAMS GS. */ + +static inline tree * +gimple_omp_teams_clauses_ptr (gimple gs) +{ + GIMPLE_CHECK (gs, GIMPLE_OMP_TEAMS); + return &gs->gimple_omp_single.clauses; +} + + +/* Set CLAUSES to be the clauses associated with OMP_TEAMS GS. */ + +static inline void +gimple_omp_teams_set_clauses (gimple gs, tree clauses) +{ + GIMPLE_CHECK (gs, GIMPLE_OMP_TEAMS); + gs->gimple_omp_single.clauses = clauses; +} + + /* Return the clauses associated with OMP_SECTIONS GS. */ static inline tree @@ -4946,6 +5035,8 @@ gimple_return_set_retval (gimple gs, tree retval) case GIMPLE_OMP_SECTIONS: \ case GIMPLE_OMP_SECTIONS_SWITCH: \ case GIMPLE_OMP_SINGLE: \ + case GIMPLE_OMP_TARGET: \ + case GIMPLE_OMP_TEAMS: \ case GIMPLE_OMP_SECTION: \ case GIMPLE_OMP_MASTER: \ case GIMPLE_OMP_ORDERED: \ diff --git a/gcc/gimplify.c b/gcc/gimplify.c index ec377f8fc84e8..4fea48ab37aba 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -57,10 +57,11 @@ enum gimplify_omp_var_data GOVD_LASTPRIVATE = 32, GOVD_REDUCTION = 64, GOVD_LOCAL = 128, - GOVD_DEBUG_PRIVATE = 256, - GOVD_PRIVATE_OUTER_REF = 512, - GOVD_LINEAR = 1024, - GOVD_ALIGNED = 2048, + GOVD_MAP = 256, + GOVD_DEBUG_PRIVATE = 512, + GOVD_PRIVATE_OUTER_REF = 1024, + GOVD_LINEAR = 2048, + GOVD_ALIGNED = 4096, GOVD_DATA_SHARE_CLASS = (GOVD_SHARED | GOVD_PRIVATE | GOVD_FIRSTPRIVATE | GOVD_LASTPRIVATE | GOVD_REDUCTION | GOVD_LINEAR | GOVD_LOCAL) @@ -74,7 +75,10 @@ enum omp_region_type ORT_PARALLEL = 2, ORT_COMBINED_PARALLEL = 3, ORT_TASK = 4, - ORT_UNTIED_TASK = 5 + ORT_UNTIED_TASK = 5, + ORT_TEAMS = 8, + ORT_TARGET_DATA = 16, + ORT_TARGET = 32 }; struct gimplify_omp_ctx @@ -5829,6 +5833,9 @@ omp_add_variable (struct gimplify_omp_ctx *ctx, tree decl, unsigned int flags) the parameters of the type. */ if (DECL_SIZE (decl) && TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST) { + /* To be handled later. */ + gcc_assert ((flags & GOVD_MAP) == 0); + /* Add the pointer replacement variable as PRIVATE if the variable replacement is private, else FIRSTPRIVATE since we'll need the address of the original variable either for SHARED, or for the @@ -5870,6 +5877,9 @@ omp_add_variable (struct gimplify_omp_ctx *ctx, tree decl, unsigned int flags) } else if (lang_hooks.decls.omp_privatize_by_reference (decl)) { + /* To be handled later. */ + gcc_assert ((flags & GOVD_MAP) == 0); + gcc_assert ((flags & GOVD_LOCAL) == 0); omp_firstprivatize_type_sizes (ctx, TREE_TYPE (decl)); @@ -5896,6 +5906,22 @@ omp_notice_threadprivate_variable (struct gimplify_omp_ctx *ctx, tree decl, tree decl2) { splay_tree_node n; + struct gimplify_omp_ctx *octx; + + for (octx = ctx; octx; octx = octx->outer_context) + if (octx->region_type == ORT_TARGET) + { + n = splay_tree_lookup (ctx->variables, (splay_tree_key)decl); + if (n == NULL) + { + error ("threadprivate variable %qE used in target region", + DECL_NAME (decl)); + error_at (octx->location, "enclosing target region"); + splay_tree_insert (octx->variables, (splay_tree_key)decl, 0); + } + if (decl2) + splay_tree_insert (octx->variables, (splay_tree_key)decl2, 0); + } if (ctx->region_type != ORT_UNTIED_TASK) return false; @@ -5944,13 +5970,24 @@ omp_notice_variable (struct gimplify_omp_ctx *ctx, tree decl, bool in_code) } n = splay_tree_lookup (ctx->variables, (splay_tree_key)decl); + if (ctx->region_type == ORT_TARGET) + { + if (n == NULL) + omp_add_variable (ctx, decl, GOVD_MAP | flags); + else + n->value |= flags; + ret = lang_hooks.decls.omp_disregard_value_expr (decl, true); + goto do_outer; + } + if (n == NULL) { enum omp_clause_default_kind default_kind, kind; struct gimplify_omp_ctx *octx; if (ctx->region_type == ORT_WORKSHARE - || ctx->region_type == ORT_SIMD) + || ctx->region_type == ORT_SIMD + || ctx->region_type == ORT_TARGET_DATA) goto do_outer; /* ??? Some compiler-generated variables (like SAVE_EXPRs) could be @@ -5964,12 +6001,24 @@ omp_notice_variable (struct gimplify_omp_ctx *ctx, tree decl, bool in_code) switch (default_kind) { case OMP_CLAUSE_DEFAULT_NONE: - error ("%qE not specified in enclosing parallel", - DECL_NAME (lang_hooks.decls.omp_report_decl (decl))); if ((ctx->region_type & ORT_TASK) != 0) - error_at (ctx->location, "enclosing task"); + { + error ("%qE not specified in enclosing task", + DECL_NAME (lang_hooks.decls.omp_report_decl (decl))); + error_at (ctx->location, "enclosing task"); + } + else if (ctx->region_type == ORT_TEAMS) + { + error ("%qE not specified in enclosing teams construct", + DECL_NAME (lang_hooks.decls.omp_report_decl (decl))); + error_at (ctx->location, "enclosing teams construct"); + } else - error_at (ctx->location, "enclosing parallel"); + { + error ("%qE not specified in enclosing parallel", + DECL_NAME (lang_hooks.decls.omp_report_decl (decl))); + error_at (ctx->location, "enclosing parallel"); + } /* FALLTHRU */ case OMP_CLAUSE_DEFAULT_SHARED: flags |= GOVD_SHARED; @@ -5989,13 +6038,15 @@ omp_notice_variable (struct gimplify_omp_ctx *ctx, tree decl, bool in_code) { splay_tree_node n2; + if ((octx->region_type & (ORT_TARGET_DATA | ORT_TARGET)) != 0) + continue; n2 = splay_tree_lookup (octx->variables, (splay_tree_key) decl); if (n2 && (n2->value & GOVD_DATA_SHARE_CLASS) != GOVD_SHARED) { flags |= GOVD_FIRSTPRIVATE; break; } - if ((octx->region_type & ORT_PARALLEL) != 0) + if ((octx->region_type & (ORT_PARALLEL | ORT_TEAMS)) != 0) break; } if (flags & GOVD_FIRSTPRIVATE) @@ -6137,6 +6188,9 @@ omp_check_private (struct gimplify_omp_ctx *ctx, tree decl) /* References might be private, but might be shared too. */ || lang_hooks.decls.omp_privatize_by_reference (decl)); + if ((ctx->region_type & (ORT_TARGET | ORT_TARGET_DATA)) != 0) + continue; + n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl); if (n != NULL) return (n->value & GOVD_SHARED) == 0; @@ -6204,6 +6258,20 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, } flags = GOVD_LINEAR | GOVD_EXPLICIT; goto do_add; + case OMP_CLAUSE_MAP: + flags = GOVD_MAP | GOVD_EXPLICIT; + notice_outer = false; + goto do_add; + + case OMP_CLAUSE_TO: + case OMP_CLAUSE_FROM: + decl = OMP_CLAUSE_DECL (c); + if (error_operand_p (decl)) + { + remove = true; + break; + } + goto do_notice; do_add: decl = OMP_CLAUSE_DECL (c); @@ -6292,6 +6360,9 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, case OMP_CLAUSE_SCHEDULE: case OMP_CLAUSE_NUM_THREADS: + case OMP_CLAUSE_NUM_TEAMS: + case OMP_CLAUSE_DIST_SCHEDULE: + case OMP_CLAUSE_DEVICE: if (gimplify_expr (&OMP_CLAUSE_OPERAND (c, 0), pre_p, NULL, is_gimple_val, fb_rvalue) == GS_ERROR) remove = true; @@ -6357,12 +6428,40 @@ gimplify_adjust_omp_clauses_1 (splay_tree_node n, void *data) gcc_assert ((flags & GOVD_DATA_SHARE_CLASS) == GOVD_PRIVATE); private_debug = true; } + else if (flags & GOVD_MAP) + private_debug = false; else private_debug = lang_hooks.decls.omp_private_debug_clause (decl, !!(flags & GOVD_SHARED)); if (private_debug) code = OMP_CLAUSE_PRIVATE; + else if (flags & GOVD_MAP) + { + /* If decl is already in the enclosing device data environment, + the spec says that it should just be used and no init/assignment + should be done. If there was any privatization in between though, + it means that original decl might be in the enclosing device data + environment, but the privatized might not. */ + struct gimplify_omp_ctx *ctx; + for (ctx = gimplify_omp_ctxp->outer_context; + ctx; ctx = ctx->outer_context) + { + n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl); + if (n == NULL) + continue; + if (ctx->region_type == ORT_TARGET_DATA) + { + if ((n->value & GOVD_MAP) != 0) + return 0; + } + else if ((n->value & (GOVD_FIRSTPRIVATE | GOVD_LASTPRIVATE + | GOVD_PRIVATE | GOVD_REDUCTION + | GOVD_LINEAR)) != 0) + break; + } + code = OMP_CLAUSE_MAP; + } else if (flags & GOVD_SHARED) { if (is_global_var (decl)) @@ -6373,7 +6472,8 @@ gimplify_adjust_omp_clauses_1 (splay_tree_node n, void *data) splay_tree_node on = splay_tree_lookup (ctx->variables, (splay_tree_key) decl); if (on && (on->value & (GOVD_FIRSTPRIVATE | GOVD_LASTPRIVATE - | GOVD_PRIVATE | GOVD_REDUCTION)) != 0) + | GOVD_PRIVATE | GOVD_REDUCTION + | GOVD_LINEAR)) != 0) break; ctx = ctx->outer_context; } @@ -6400,6 +6500,8 @@ gimplify_adjust_omp_clauses_1 (splay_tree_node n, void *data) OMP_CLAUSE_PRIVATE_DEBUG (clause) = 1; else if (code == OMP_CLAUSE_PRIVATE && (flags & GOVD_PRIVATE_OUTER_REF)) OMP_CLAUSE_PRIVATE_OUTER_REF (clause) = 1; + else if (code == OMP_CLAUSE_MAP) + OMP_CLAUSE_MAP_KIND (clause) = OMP_CLAUSE_MAP_TOFROM; *list_p = clause; lang_hooks.decls.omp_finish_clause (clause); @@ -6517,11 +6619,47 @@ gimplify_adjust_omp_clauses (tree *list_p) } break; + case OMP_CLAUSE_MAP: + decl = OMP_CLAUSE_DECL (c); + n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl); + remove = false; + if (ctx->region_type == ORT_TARGET && !(n->value & GOVD_SEEN)) + remove = true; + else + { + /* If decl is already in the enclosing device data environment, + the spec says that it should just be used and no init/assignment + should be done. If there was any privatization in between though, + it means that original decl might be in the enclosing device data + environment, but the privatized might not. */ + struct gimplify_omp_ctx *octx; + for (octx = ctx->outer_context; octx; octx = octx->outer_context) + { + n = splay_tree_lookup (octx->variables, + (splay_tree_key) decl); + if (n == NULL) + continue; + if (octx->region_type == ORT_TARGET_DATA) + { + if ((n->value & GOVD_MAP) != 0) + remove = true; + } + else if ((n->value & (GOVD_FIRSTPRIVATE | GOVD_LASTPRIVATE + | GOVD_PRIVATE | GOVD_REDUCTION + | GOVD_LINEAR)) != 0) + break; + } + } + break; + case OMP_CLAUSE_REDUCTION: case OMP_CLAUSE_COPYIN: case OMP_CLAUSE_COPYPRIVATE: case OMP_CLAUSE_IF: case OMP_CLAUSE_NUM_THREADS: + case OMP_CLAUSE_NUM_TEAMS: + case OMP_CLAUSE_DIST_SCHEDULE: + case OMP_CLAUSE_DEVICE: case OMP_CLAUSE_SCHEDULE: case OMP_CLAUSE_NOWAIT: case OMP_CLAUSE_ORDERED: @@ -6532,6 +6670,8 @@ gimplify_adjust_omp_clauses (tree *list_p) case OMP_CLAUSE_MERGEABLE: case OMP_CLAUSE_PROC_BIND: case OMP_CLAUSE_SAFELEN: + case OMP_CLAUSE_TO: + case OMP_CLAUSE_FROM: break; default: @@ -6847,25 +6987,19 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) gimplify_adjust_omp_clauses (&OMP_FOR_CLAUSES (for_stmt)); - gfor = gimple_build_omp_for (for_body, OMP_FOR_CLAUSES (for_stmt), - TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)), - for_pre_body); + int kind; switch (TREE_CODE (for_stmt)) { - case OMP_FOR: - break; - case OMP_SIMD: - gimple_omp_for_set_kind (gfor, GF_OMP_FOR_KIND_SIMD); - break; - case OMP_FOR_SIMD: - gimple_omp_for_set_kind (gfor, GF_OMP_FOR_KIND_FOR_SIMD); - break; - case OMP_DISTRIBUTE: - gimple_omp_for_set_kind (gfor, GF_OMP_FOR_KIND_DISTRIBUTE); - break; + case OMP_FOR: kind = GF_OMP_FOR_KIND_FOR; break; + case OMP_SIMD: kind = GF_OMP_FOR_KIND_SIMD; break; + case OMP_FOR_SIMD: kind = GF_OMP_FOR_KIND_FOR_SIMD; break; + case OMP_DISTRIBUTE: kind = GF_OMP_FOR_KIND_DISTRIBUTE; break; default: gcc_unreachable (); } + gfor = gimple_build_omp_for (for_body, kind, OMP_FOR_CLAUSES (for_stmt), + TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)), + for_pre_body); for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)); i++) { @@ -6880,11 +7014,15 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) } gimplify_seq_add_stmt (pre_p, gfor); - return ret == GS_ALL_DONE ? GS_ALL_DONE : GS_ERROR; + if (ret != GS_ALL_DONE) + return GS_ERROR; + *expr_p = NULL_TREE; + return GS_ALL_DONE; } -/* Gimplify the gross structure of other OpenMP worksharing constructs. - In particular, OMP_SECTIONS and OMP_SINGLE. */ +/* Gimplify the gross structure of other OpenMP constructs. + In particular, OMP_SECTIONS, OMP_SINGLE, OMP_TARGET, OMP_TARGET_DATA + and OMP_TEAMS. */ static void gimplify_omp_workshare (tree *expr_p, gimple_seq *pre_p) @@ -6892,19 +7030,72 @@ gimplify_omp_workshare (tree *expr_p, gimple_seq *pre_p) tree expr = *expr_p; gimple stmt; gimple_seq body = NULL; + enum omp_region_type ort = ORT_WORKSHARE; - gimplify_scan_omp_clauses (&OMP_CLAUSES (expr), pre_p, ORT_WORKSHARE); + switch (TREE_CODE (expr)) + { + case OMP_SECTIONS: + case OMP_SINGLE: + break; + case OMP_TARGET: + ort = ORT_TARGET; + break; + case OMP_TARGET_DATA: + ort = ORT_TARGET_DATA; + break; + case OMP_TEAMS: + ort = ORT_TEAMS; + break; + default: + gcc_unreachable (); + } + gimplify_scan_omp_clauses (&OMP_CLAUSES (expr), pre_p, ort); gimplify_and_add (OMP_BODY (expr), &body); gimplify_adjust_omp_clauses (&OMP_CLAUSES (expr)); - if (TREE_CODE (expr) == OMP_SECTIONS) - stmt = gimple_build_omp_sections (body, OMP_CLAUSES (expr)); - else if (TREE_CODE (expr) == OMP_SINGLE) - stmt = gimple_build_omp_single (body, OMP_CLAUSES (expr)); - else - gcc_unreachable (); + switch (TREE_CODE (expr)) + { + case OMP_SECTIONS: + stmt = gimple_build_omp_sections (body, OMP_CLAUSES (expr)); + break; + case OMP_SINGLE: + stmt = gimple_build_omp_single (body, OMP_CLAUSES (expr)); + break; + case OMP_TARGET: + stmt = gimple_build_omp_target (body, GF_OMP_TARGET_KIND_REGION, + OMP_CLAUSES (expr)); + break; + case OMP_TARGET_DATA: + stmt = gimple_build_omp_target (body, GF_OMP_TARGET_KIND_DATA, + OMP_CLAUSES (expr)); + break; + case OMP_TEAMS: + stmt = gimple_build_omp_teams (body, OMP_CLAUSES (expr)); + break; + default: + gcc_unreachable (); + } + + gimplify_seq_add_stmt (pre_p, stmt); + *expr_p = NULL_TREE; +} + +/* Gimplify the gross structure of OpenMP target update construct. */ + +static void +gimplify_omp_target_update (tree *expr_p, gimple_seq *pre_p) +{ + tree expr = *expr_p; + gimple stmt; + + gimplify_scan_omp_clauses (&OMP_TARGET_UPDATE_CLAUSES (expr), pre_p, + ORT_WORKSHARE); + gimplify_adjust_omp_clauses (&OMP_TARGET_UPDATE_CLAUSES (expr)); + stmt = gimple_build_omp_target (NULL, GF_OMP_TARGET_KIND_UPDATE, + OMP_TARGET_UPDATE_CLAUSES (expr)); gimplify_seq_add_stmt (pre_p, stmt); + *expr_p = NULL_TREE; } /* A subroutine of gimplify_omp_atomic. The front end is supposed to have @@ -7811,10 +8002,18 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, case OMP_SECTIONS: case OMP_SINGLE: + case OMP_TARGET: + case OMP_TARGET_DATA: + case OMP_TEAMS: gimplify_omp_workshare (expr_p, pre_p); ret = GS_ALL_DONE; break; + case OMP_TARGET_UPDATE: + gimplify_omp_target_update (expr_p, pre_p); + ret = GS_ALL_DONE; + break; + case OMP_SECTION: case OMP_MASTER: case OMP_ORDERED: diff --git a/gcc/omp-low.c b/gcc/omp-low.c index 6d964840839d1..7c795624a7a1b 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -1483,6 +1483,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) case OMP_CLAUSE_IF: case OMP_CLAUSE_NUM_THREADS: case OMP_CLAUSE_SCHEDULE: + case OMP_CLAUSE_DIST_SCHEDULE: if (ctx->outer) scan_omp_op (&OMP_CLAUSE_OPERAND (c, 0), ctx->outer); break; @@ -1548,6 +1549,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) case OMP_CLAUSE_IF: case OMP_CLAUSE_NUM_THREADS: case OMP_CLAUSE_SCHEDULE: + case OMP_CLAUSE_DIST_SCHEDULE: case OMP_CLAUSE_NOWAIT: case OMP_CLAUSE_ORDERED: case OMP_CLAUSE_COLLAPSE: diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index 721c4f77d4ad2..c9a218bda5d51 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -592,6 +592,8 @@ make_edges (void) case GIMPLE_OMP_TASK: case GIMPLE_OMP_FOR: case GIMPLE_OMP_SINGLE: + case GIMPLE_OMP_TARGET: + case GIMPLE_OMP_TEAMS: case GIMPLE_OMP_MASTER: case GIMPLE_OMP_ORDERED: case GIMPLE_OMP_CRITICAL: diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index 57af7de2c09ec..b7b2b364dccca 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -1298,7 +1298,8 @@ remap_gimple_stmt (gimple stmt, copy_body_data *id) case GIMPLE_OMP_FOR: s1 = remap_gimple_seq (gimple_omp_body (stmt), id); s2 = remap_gimple_seq (gimple_omp_for_pre_body (stmt), id); - copy = gimple_build_omp_for (s1, gimple_omp_for_clauses (stmt), + copy = gimple_build_omp_for (s1, gimple_omp_for_kind (stmt), + gimple_omp_for_clauses (stmt), gimple_omp_for_collapse (stmt), s2); { size_t i; @@ -1345,6 +1346,19 @@ remap_gimple_stmt (gimple stmt, copy_body_data *id) (s1, gimple_omp_single_clauses (stmt)); break; + case GIMPLE_OMP_TARGET: + s1 = remap_gimple_seq (gimple_omp_body (stmt), id); + copy = gimple_build_omp_target + (s1, gimple_omp_target_kind (stmt), + gimple_omp_target_clauses (stmt)); + break; + + case GIMPLE_OMP_TEAMS: + s1 = remap_gimple_seq (gimple_omp_body (stmt), id); + copy = gimple_build_omp_teams + (s1, gimple_omp_teams_clauses (stmt)); + break; + case GIMPLE_OMP_CRITICAL: s1 = remap_gimple_seq (gimple_omp_body (stmt), id); copy @@ -3716,6 +3730,8 @@ estimate_num_insns (gimple stmt, eni_weights *weights) case GIMPLE_OMP_SECTION: case GIMPLE_OMP_SECTIONS: case GIMPLE_OMP_SINGLE: + case GIMPLE_OMP_TARGET: + case GIMPLE_OMP_TEAMS: return (weights->omp_cost + estimate_num_insns_seq (gimple_omp_body (stmt), weights)); diff --git a/gcc/tree-nested.c b/gcc/tree-nested.c index fe44679a0132b..41548821acf0f 100644 --- a/gcc/tree-nested.c +++ b/gcc/tree-nested.c @@ -1291,6 +1291,22 @@ convert_nonlocal_reference_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p, info->suppress_expansion = save_suppress; break; + case GIMPLE_OMP_TARGET: + save_suppress = info->suppress_expansion; + convert_nonlocal_omp_clauses (gimple_omp_target_clauses_ptr (stmt), wi); + walk_body (convert_nonlocal_reference_stmt, convert_nonlocal_reference_op, + info, gimple_omp_body_ptr (stmt)); + info->suppress_expansion = save_suppress; + break; + + case GIMPLE_OMP_TEAMS: + save_suppress = info->suppress_expansion; + convert_nonlocal_omp_clauses (gimple_omp_teams_clauses_ptr (stmt), wi); + walk_body (convert_nonlocal_reference_stmt, convert_nonlocal_reference_op, + info, gimple_omp_body_ptr (stmt)); + info->suppress_expansion = save_suppress; + break; + case GIMPLE_OMP_SECTION: case GIMPLE_OMP_MASTER: case GIMPLE_OMP_ORDERED: @@ -1714,6 +1730,22 @@ convert_local_reference_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p, info->suppress_expansion = save_suppress; break; + case GIMPLE_OMP_TARGET: + save_suppress = info->suppress_expansion; + convert_local_omp_clauses (gimple_omp_target_clauses_ptr (stmt), wi); + walk_body (convert_local_reference_stmt, convert_local_reference_op, + info, gimple_omp_body_ptr (stmt)); + info->suppress_expansion = save_suppress; + break; + + case GIMPLE_OMP_TEAMS: + save_suppress = info->suppress_expansion; + convert_local_omp_clauses (gimple_omp_teams_clauses_ptr (stmt), wi); + walk_body (convert_local_reference_stmt, convert_local_reference_op, + info, gimple_omp_body_ptr (stmt)); + info->suppress_expansion = save_suppress; + break; + case GIMPLE_OMP_SECTION: case GIMPLE_OMP_MASTER: case GIMPLE_OMP_ORDERED: @@ -2071,6 +2103,8 @@ convert_gimple_call (gimple_stmt_iterator *gsi, bool *handled_ops_p, case GIMPLE_OMP_SECTIONS: case GIMPLE_OMP_SECTION: case GIMPLE_OMP_SINGLE: + case GIMPLE_OMP_TARGET: + case GIMPLE_OMP_TEAMS: case GIMPLE_OMP_MASTER: case GIMPLE_OMP_ORDERED: case GIMPLE_OMP_CRITICAL: diff --git a/gcc/tree-parloops.c b/gcc/tree-parloops.c index cea6f030c0ac8..1e6bb07b39813 100644 --- a/gcc/tree-parloops.c +++ b/gcc/tree-parloops.c @@ -1686,7 +1686,7 @@ create_parallel_loop (struct loop *loop, tree loop_fn, tree data, t = build_omp_clause (loc, OMP_CLAUSE_SCHEDULE); OMP_CLAUSE_SCHEDULE_KIND (t) = OMP_CLAUSE_SCHEDULE_STATIC; - for_stmt = gimple_build_omp_for (NULL, t, 1, NULL); + for_stmt = gimple_build_omp_for (NULL, GF_OMP_FOR_KIND_FOR, t, 1, NULL); gimple_set_location (for_stmt, loc); gimple_omp_for_set_index (for_stmt, 0, initvar); gimple_omp_for_set_initial (for_stmt, 0, cvar_init); diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c index 2bdf9dcd23216..ace9e22ebd17f 100644 --- a/gcc/tree-pretty-print.c +++ b/gcc/tree-pretty-print.c @@ -2347,6 +2347,27 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags, pp_string (buffer, "#pragma omp distribute"); goto dump_omp_loop; + case OMP_TEAMS: + pp_string (buffer, "#pragma omp teams"); + dump_omp_clauses (buffer, OMP_TEAMS_CLAUSES (node), spc, flags); + goto dump_omp_body; + + case OMP_TARGET_DATA: + pp_string (buffer, "#pragma omp target data"); + dump_omp_clauses (buffer, OMP_TARGET_DATA_CLAUSES (node), spc, flags); + goto dump_omp_body; + + case OMP_TARGET: + pp_string (buffer, "#pragma omp target"); + dump_omp_clauses (buffer, OMP_TARGET_CLAUSES (node), spc, flags); + goto dump_omp_body; + + case OMP_TARGET_UPDATE: + pp_string (buffer, "#pragma omp target update"); + dump_omp_clauses (buffer, OMP_TARGET_UPDATE_CLAUSES (node), spc, flags); + is_expr = false; + break; + dump_omp_loop: dump_omp_clauses (buffer, OMP_FOR_CLAUSES (node), spc, flags); diff --git a/gcc/tree.def b/gcc/tree.def index 147b6805b0a70..a2e53e65f721e 100644 --- a/gcc/tree.def +++ b/gcc/tree.def @@ -1042,6 +1042,21 @@ DEFTREECODE (OMP_FOR_SIMD, "omp_for_simd", tcc_statement, 6) Operands like for OMP_FOR. */ DEFTREECODE (OMP_DISTRIBUTE, "omp_distribute", tcc_statement, 6) +/* OpenMP - #pragma omp teams [clause1 ... clauseN] + Operand 0: OMP_TEAMS_BODY: Teams body. + Operand 1: OMP_TEAMS_CLAUSES: List of clauses. */ +DEFTREECODE (OMP_TEAMS, "omp_teams", tcc_statement, 2) + +/* OpenMP - #pragma omp target data [clause1 ... clauseN] + Operand 0: OMP_TARGET_DATA_BODY: Target data construct body. + Operand 1: OMP_TARGET_DATA_CLAUSES: List of clauses. */ +DEFTREECODE (OMP_TARGET_DATA, "omp_target_data", tcc_statement, 2) + +/* OpenMP - #pragma omp target [clause1 ... clauseN] + Operand 0: OMP_TARGET_BODY: Target construct body. + Operand 1: OMP_TARGET_CLAUSES: List of clauses. */ +DEFTREECODE (OMP_TARGET, "omp_target", tcc_statement, 2) + /* OpenMP - #pragma omp sections [clause1 ... clauseN] Operand 0: OMP_SECTIONS_BODY: Sections body. Operand 1: OMP_SECTIONS_CLAUSES: List of clauses. */ @@ -1069,6 +1084,10 @@ DEFTREECODE (OMP_ORDERED, "omp_ordered", tcc_statement, 1) Operand 1: OMP_CRITICAL_NAME: Identifier for critical section. */ DEFTREECODE (OMP_CRITICAL, "omp_critical", tcc_statement, 2) +/* OpenMP - #pragma omp target update [clause1 ... clauseN] + Operand 0: OMP_TARGET_UPDATE_CLAUSES: List of clauses. */ +DEFTREECODE (OMP_TARGET_UPDATE, "omp_target_update", tcc_statement, 1) + /* OMP_ATOMIC through OMP_ATOMIC_CAPTURE_NEW must be consecutive, or OMP_ATOMIC_SEQ_CST needs adjusting. */ diff --git a/gcc/tree.h b/gcc/tree.h index 49da30a318663..f2a58a09e0d7c 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -1863,6 +1863,20 @@ extern void protected_set_expr_location (tree, location_t); #define OMP_CRITICAL_BODY(NODE) TREE_OPERAND (OMP_CRITICAL_CHECK (NODE), 0) #define OMP_CRITICAL_NAME(NODE) TREE_OPERAND (OMP_CRITICAL_CHECK (NODE), 1) +#define OMP_TEAMS_BODY(NODE) TREE_OPERAND (OMP_TEAMS_CHECK (NODE), 0) +#define OMP_TEAMS_CLAUSES(NODE) TREE_OPERAND (OMP_TEAMS_CHECK (NODE), 1) + +#define OMP_TARGET_DATA_BODY(NODE) \ + TREE_OPERAND (OMP_TARGET_DATA_CHECK (NODE), 0) +#define OMP_TARGET_DATA_CLAUSES(NODE)\ + TREE_OPERAND (OMP_TARGET_DATA_CHECK (NODE), 1) + +#define OMP_TARGET_BODY(NODE) TREE_OPERAND (OMP_TARGET_CHECK (NODE), 0) +#define OMP_TARGET_CLAUSES(NODE) TREE_OPERAND (OMP_TARGET_CHECK (NODE), 1) + +#define OMP_TARGET_UPDATE_CLAUSES(NODE)\ + TREE_OPERAND (OMP_TARGET_UPDATE_CHECK (NODE), 0) + #define OMP_CLAUSE_CHAIN(NODE) TREE_CHAIN (OMP_CLAUSE_CHECK (NODE)) #define OMP_CLAUSE_DECL(NODE) \ OMP_CLAUSE_OPERAND (OMP_CLAUSE_RANGE_CHECK (OMP_CLAUSE_CHECK (NODE), \ From add07b9c7c46dcbd1a8effa4522d59dd3b6a1e2d Mon Sep 17 00:00:00 2001 From: jakub Date: Wed, 29 May 2013 08:06:40 +0000 Subject: [PATCH 36/63] * omp-low.c (check_omp_nesting_restrictions): Add some accelerator related nesting restrictions. (scan_omp_1_stmt): Call check_omp_nesting_restrictions even for GOMP_taskgroup_{start,end}. * gimplify.c (omp_notice_threadprivate_variable): Fix a typo. (gimplify_body): For functions with "omp declare target" attribute add ORT_TARGET region around the body. cp/ * parser.c (cp_parser_omp_declare_target, cp_parser_omp_end_declare_target): New functions. (cp_parser_omp_declare): For target keyword call cp_parser_omp_declare_target. (cp_parser_pragma): Handle PRAGMA_OMP_END_DECLARE_TARGET. * cp-tree.h (current_omp_declare_target_attribute): Declare. * decl2.c (current_omp_declare_target_attribute): New variable. (cp_omp_mappable_type): New function. (cplus_decl_attributes): Handle addition of "omp declare target" attribute for decls in #pragma omp declare target region. Complain for invalid uses. c-family/ * c-common.c (c_common_attribute_table): Add "omp declare target" attribute. (handle_omp_declare_target_attribute): New function. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gomp-4_0-branch@199400 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog.gomp | 10 ++++++ gcc/c-family/ChangeLog.gomp | 6 ++++ gcc/c-family/c-common.c | 13 ++++++++ gcc/cp/ChangeLog.gomp | 14 +++++++++ gcc/cp/cp-tree.h | 4 +++ gcc/cp/decl2.c | 48 +++++++++++++++++++++++++++++ gcc/cp/parser.c | 34 +++++++++++++++++++++ gcc/gimplify.c | 15 ++++++++- gcc/omp-low.c | 61 ++++++++++++++++++++++++++++++++----- 9 files changed, 197 insertions(+), 8 deletions(-) diff --git a/gcc/ChangeLog.gomp b/gcc/ChangeLog.gomp index 0db46c9aef55f..6498cc13cac2b 100644 --- a/gcc/ChangeLog.gomp +++ b/gcc/ChangeLog.gomp @@ -1,3 +1,13 @@ +2013-05-29 Jakub Jelinek + + * omp-low.c (check_omp_nesting_restrictions): Add some + accelerator related nesting restrictions. + (scan_omp_1_stmt): Call check_omp_nesting_restrictions + even for GOMP_taskgroup_{start,end}. + * gimplify.c (omp_notice_threadprivate_variable): Fix a typo. + (gimplify_body): For functions with "omp declare target" attribute + add ORT_TARGET region around the body. + 2013-05-27 Jakub Jelinek * tree.def (OMP_TEAMS, OMP_TARGET_DATA, OMP_TARGET, diff --git a/gcc/c-family/ChangeLog.gomp b/gcc/c-family/ChangeLog.gomp index f8e095b90c419..996804f331c40 100644 --- a/gcc/c-family/ChangeLog.gomp +++ b/gcc/c-family/ChangeLog.gomp @@ -1,3 +1,9 @@ +2013-05-29 Jakub Jelinek + + * c-common.c (c_common_attribute_table): Add "omp declare target" + attribute. + (handle_omp_declare_target_attribute): New function. + 2013-05-09 Jakub Jelinek * c-common.c (c_common_attribute_table): Add "omp declare simd" diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 6f9d83a7dd042..9d5c6fbff1d78 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -370,6 +370,8 @@ static tree handle_no_split_stack_attribute (tree *, tree, tree, int, bool *); static tree handle_fnspec_attribute (tree *, tree, tree, int, bool *); static tree handle_omp_declare_simd_attribute (tree *, tree, tree, int, bool *); +static tree handle_omp_declare_target_attribute (tree *, tree, tree, int, + bool *); static void check_function_nonnull (tree, int, tree *); static void check_nonnull_arg (void *, tree, unsigned HOST_WIDE_INT); @@ -742,6 +744,8 @@ const struct attribute_spec c_common_attribute_table[] = handle_fnspec_attribute, false }, { "omp declare simd", 0, -1, true, false, false, handle_omp_declare_simd_attribute, false }, + { "omp declare target", 0, 0, true, false, false, + handle_omp_declare_target_attribute, false }, { NULL, 0, 0, false, false, false, NULL, false } }; @@ -7967,6 +7971,15 @@ handle_omp_declare_simd_attribute (tree *, tree, tree, int, bool *) return NULL_TREE; } +/* Handle an "omp declare target" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_omp_declare_target_attribute (tree *, tree, tree, int, bool *) +{ + return NULL_TREE; +} + /* Handle a "returns_twice" attribute; arguments as in struct attribute_spec.handler. */ diff --git a/gcc/cp/ChangeLog.gomp b/gcc/cp/ChangeLog.gomp index 9f3f38c18c66b..fe76ff861f1bd 100644 --- a/gcc/cp/ChangeLog.gomp +++ b/gcc/cp/ChangeLog.gomp @@ -1,3 +1,17 @@ +2013-05-29 Jakub Jelinek + + * parser.c (cp_parser_omp_declare_target, + cp_parser_omp_end_declare_target): New functions. + (cp_parser_omp_declare): For target keyword call + cp_parser_omp_declare_target. + (cp_parser_pragma): Handle PRAGMA_OMP_END_DECLARE_TARGET. + * cp-tree.h (current_omp_declare_target_attribute): Declare. + * decl2.c (current_omp_declare_target_attribute): New variable. + (cp_omp_mappable_type): New function. + (cplus_decl_attributes): Handle addition of "omp declare target" + attribute for decls in #pragma omp declare target region. Complain + for invalid uses. + 2013-05-27 Jakub Jelinek * parser.c (cp_parser_omp_clause_cancelkind): Remove diagnostics. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 1e2230b6ab5ed..7046713200384 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -4428,6 +4428,10 @@ extern GTY(()) vec *local_classes; extern int at_eof; +/* If non-zero, implicit "omp declare target" attribute is added into the + attribute lists. */ +extern GTY(()) int current_omp_declare_target_attribute; + /* A list of namespace-scope objects which have constructors or destructors which reside in the global scope. The decl is stored in the TREE_VALUE slot and the initializer is stored in the diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 37ea95e11b420..667d6b3440062 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -102,6 +102,9 @@ static GTY(()) vec *no_linkage_decls; int at_eof; +/* If non-zero, implicit "omp declare target" attribute is added into the + attribute lists. */ +int current_omp_declare_target_attribute; /* Return a member function type (a METHOD_TYPE), given FNTYPE (a @@ -1330,6 +1333,27 @@ cp_check_const_attributes (tree attributes) } } +/* Return true if TYPE is an OpenMP mappable type. */ +static bool +cp_omp_mappable_type (tree type) +{ + /* Mappable type has to be complete. */ + if (type == error_mark_node || !COMPLETE_TYPE_P (type)) + return false; + /* A mappable type cannot contain virtual members. */ + if (CLASS_TYPE_P (type) && CLASSTYPE_VTABLES (type)) + return false; + /* All data members must be non-static. */ + if (CLASS_TYPE_P (type)) + { + tree field; + for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) + if (TREE_CODE (field) == VAR_DECL) + return false; + } + return true; +} + /* Like decl_attributes, but handle C++ complexity. */ void @@ -1339,6 +1363,30 @@ cplus_decl_attributes (tree *decl, tree attributes, int flags) || *decl == error_mark_node) return; + /* Add implicit "omp declare target" attribute if requested. */ + if (current_omp_declare_target_attribute + && (TREE_CODE (*decl) == VAR_DECL + || TREE_CODE (*decl) == FUNCTION_DECL)) + { + if (TREE_CODE (*decl) == VAR_DECL + && RECORD_OR_UNION_CODE_P (TREE_CODE (CP_DECL_CONTEXT (*decl)))) + error ("%q+D static data member inside of declare target directive", + *decl); + else if (TREE_CODE (*decl) == VAR_DECL + && (TREE_CODE (CP_DECL_CONTEXT (*decl)) == FUNCTION_DECL + || (current_function_decl && !DECL_EXTERNAL (*decl)))) + error ("%q+D in block scope inside of declare target directive", + *decl); + else if (!processing_template_decl + && TREE_CODE (*decl) == VAR_DECL + && !cp_omp_mappable_type (TREE_TYPE (*decl))) + error ("%q+D in declare target directive does not have mappable type", + *decl); + else + attributes = tree_cons (get_identifier ("omp declare target"), + NULL_TREE, attributes); + } + if (processing_template_decl) { if (check_for_bare_parameter_packs (attributes)) diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 5bbb46b1c8792..a30f52ac4ce11 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -29240,6 +29240,30 @@ cp_parser_omp_declare_simd (cp_parser *parser, cp_token *pragma_tok, } } +/* OpenMP 4.0: + # pragma omp declare target new-line + declarations and definitions + # pragma omp end declare target new-line */ + +static void +cp_parser_omp_declare_target (cp_parser *parser, cp_token *pragma_tok) +{ + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + current_omp_declare_target_attribute++; +} + +static void +cp_parser_omp_end_declare_target (cp_parser *parser, cp_token *pragma_tok) +{ + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + if (!current_omp_declare_target_attribute) + error_at (pragma_tok->location, + "%<#pragma omp end declare target%> without corresponding " + "%<#pragma omp declare target%>"); + else + current_omp_declare_target_attribute--; +} + /* OpenMP 4.0 #pragma omp declare simd declare-simd-clauses[optseq] new-line #pragma omp declare reduction (reduction-id : typename-list : expression) \ @@ -29269,6 +29293,12 @@ cp_parser_omp_declare (cp_parser *parser, cp_token *pragma_tok, context); return; } */ + if (strcmp (p, "target") == 0) + { + cp_lexer_consume_token (parser->lexer); + cp_parser_omp_declare_target (parser, pragma_tok); + return; + } } cp_parser_error (parser, "expected % or %"); cp_parser_require_pragma_eol (parser, pragma_tok); @@ -29811,6 +29841,10 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context) case PRAGMA_OMP_TARGET: return cp_parser_omp_target (parser, pragma_tok, context); + case PRAGMA_OMP_END_DECLARE_TARGET: + cp_parser_omp_end_declare_target (parser, pragma_tok); + return false; + case PRAGMA_OMP_SECTION: error_at (pragma_tok->location, "%<#pragma omp section%> may only be used in " diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 4fea48ab37aba..0c0fe52f7d298 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -5911,7 +5911,7 @@ omp_notice_threadprivate_variable (struct gimplify_omp_ctx *ctx, tree decl, for (octx = ctx; octx; octx = octx->outer_context) if (octx->region_type == ORT_TARGET) { - n = splay_tree_lookup (ctx->variables, (splay_tree_key)decl); + n = splay_tree_lookup (octx->variables, (splay_tree_key)decl); if (n == NULL) { error ("threadprivate variable %qE used in target region", @@ -8587,6 +8587,13 @@ gimplify_body (tree fndecl, bool do_parms) gcc_assert (gimplify_ctxp == NULL); push_gimplify_context (&gctx); + if (flag_openmp) + { + gcc_assert (gimplify_omp_ctxp == NULL); + if (lookup_attribute ("omp declare target", DECL_ATTRIBUTES (fndecl))) + gimplify_omp_ctxp = new_omp_context (ORT_TARGET); + } + /* Unshare most shared trees in the body and in that of any nested functions. It would seem we don't have to do this for nested functions because they are supposed to be output and then the outer function gimplified @@ -8649,6 +8656,12 @@ gimplify_body (tree fndecl, bool do_parms) nonlocal_vlas = NULL; } + if (flag_openmp && gimplify_omp_ctxp) + { + delete_omp_context (gimplify_omp_ctxp); + gimplify_omp_ctxp = NULL; + } + pop_gimplify_context (outer_bind); gcc_assert (gimplify_ctxp == NULL); diff --git a/gcc/omp-low.c b/gcc/omp-low.c index 7c795624a7a1b..82f5b49b18f8b 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -1864,20 +1864,54 @@ scan_omp_single (gimple stmt, omp_context *outer_ctx) static bool check_omp_nesting_restrictions (gimple stmt, omp_context *ctx) { - if (ctx != NULL - && gimple_code (ctx->stmt) == GIMPLE_OMP_FOR - && (gimple_omp_for_kind (ctx->stmt) == GF_OMP_FOR_KIND_SIMD - || gimple_omp_for_kind (ctx->stmt) == GF_OMP_FOR_KIND_FOR_SIMD)) + if (ctx != NULL) { - error_at (gimple_location (stmt), - "OpenMP constructs may not be nested inside simd region"); - return false; + if (gimple_code (ctx->stmt) == GIMPLE_OMP_FOR + && (gimple_omp_for_kind (ctx->stmt) == GF_OMP_FOR_KIND_SIMD + || gimple_omp_for_kind (ctx->stmt) == GF_OMP_FOR_KIND_FOR_SIMD)) + { + error_at (gimple_location (stmt), + "OpenMP constructs may not be nested inside simd region"); + return false; + } + else if (gimple_code (ctx->stmt) == GIMPLE_OMP_TEAMS) + { + if ((gimple_code (stmt) != GIMPLE_OMP_FOR + || gimple_omp_for_kind (ctx->stmt) != GF_OMP_FOR_KIND_DISTRIBUTE) + && gimple_code (stmt) != GIMPLE_OMP_PARALLEL) + { + error_at (gimple_location (stmt), + "only distribute or parallel constructs are allowed to " + "be closely nested inside teams construct"); + return false; + } + } + else if (gimple_code (ctx->stmt) == GIMPLE_OMP_FOR + && gimple_omp_for_kind (ctx->stmt) == GF_OMP_FOR_KIND_DISTRIBUTE + && gimple_code (stmt) != GIMPLE_OMP_PARALLEL) + { + error_at (gimple_location (stmt), + "only parallel constructs are allowed to " + "be closely nested inside distribute construct"); + return false; + } } switch (gimple_code (stmt)) { case GIMPLE_OMP_FOR: if (gimple_omp_for_kind (stmt) == GF_OMP_FOR_KIND_SIMD) return true; + if (gimple_omp_for_kind (stmt) == GF_OMP_FOR_KIND_DISTRIBUTE) + { + if (ctx == NULL || gimple_code (ctx->stmt) != GIMPLE_OMP_TEAMS) + { + error_at (gimple_location (stmt), + "distribute construct must be closely nested inside " + "teams construct"); + return false; + } + return true; + } /* FALLTHRU */ case GIMPLE_OMP_SECTIONS: case GIMPLE_OMP_SINGLE: @@ -1973,6 +2007,17 @@ check_omp_nesting_restrictions (gimple stmt, omp_context *ctx) return false; } break; + case GIMPLE_OMP_TEAMS: + if (ctx == NULL + || gimple_code (ctx->stmt) != GIMPLE_OMP_TARGET + || gimple_omp_target_kind (ctx->stmt) != GF_OMP_TARGET_KIND_REGION) + { + error_at (gimple_location (stmt), + "teams construct not closely nested inside of target " + "region"); + return false; + } + break; default: break; } @@ -2062,6 +2107,8 @@ scan_omp_1_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p, case BUILT_IN_GOMP_CANCELLATION_POINT: case BUILT_IN_GOMP_TASKYIELD: case BUILT_IN_GOMP_TASKWAIT: + case BUILT_IN_GOMP_TASKGROUP_START: + case BUILT_IN_GOMP_TASKGROUP_END: remove = !check_omp_nesting_restrictions (stmt, ctx); break; default: From 2b06f9ea878bd23b46d947eda6c7646e5593fb8b Mon Sep 17 00:00:00 2001 From: jakub Date: Wed, 29 May 2013 08:07:42 +0000 Subject: [PATCH 37/63] * omp-builtins.def (BUILT_IN_OMP_GET_TEAM_NUM, BUILT_IN_OMP_GET_NUM_TEAMS): New built-ins. * omp-low.c (extract_omp_for_data, expand_omp_for_static_nochunk, expand_omp_for_static_chunk): Handle #pragma omp distribute. (expand_omp_for): Add assertion for non-finished distribute collapse > 1 support. (check_omp_nesting_restrictions): Allow orphaned distribute construct. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gomp-4_0-branch@199401 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog.gomp | 8 ++++++++ gcc/omp-builtins.def | 4 ++++ gcc/omp-low.c | 40 ++++++++++++++++++++++++++++++++++------ 3 files changed, 46 insertions(+), 6 deletions(-) diff --git a/gcc/ChangeLog.gomp b/gcc/ChangeLog.gomp index 6498cc13cac2b..76205633ec5c7 100644 --- a/gcc/ChangeLog.gomp +++ b/gcc/ChangeLog.gomp @@ -1,5 +1,13 @@ 2013-05-29 Jakub Jelinek + * omp-builtins.def (BUILT_IN_OMP_GET_TEAM_NUM, + BUILT_IN_OMP_GET_NUM_TEAMS): New built-ins. + * omp-low.c (extract_omp_for_data, expand_omp_for_static_nochunk, + expand_omp_for_static_chunk): Handle #pragma omp distribute. + (expand_omp_for): Add assertion for non-finished distribute collapse + > 1 support. + (check_omp_nesting_restrictions): Allow orphaned distribute construct. + * omp-low.c (check_omp_nesting_restrictions): Add some accelerator related nesting restrictions. (scan_omp_1_stmt): Call check_omp_nesting_restrictions diff --git a/gcc/omp-builtins.def b/gcc/omp-builtins.def index 6a48ecd6cbc9e..44c48f496fe4f 100644 --- a/gcc/omp-builtins.def +++ b/gcc/omp-builtins.def @@ -28,6 +28,10 @@ DEF_GOMP_BUILTIN (BUILT_IN_OMP_GET_THREAD_NUM, "omp_get_thread_num", BT_FN_INT, ATTR_CONST_NOTHROW_LEAF_LIST) DEF_GOMP_BUILTIN (BUILT_IN_OMP_GET_NUM_THREADS, "omp_get_num_threads", BT_FN_INT, ATTR_CONST_NOTHROW_LEAF_LIST) +DEF_GOMP_BUILTIN (BUILT_IN_OMP_GET_TEAM_NUM, "omp_get_team_num", + BT_FN_INT, ATTR_CONST_NOTHROW_LEAF_LIST) +DEF_GOMP_BUILTIN (BUILT_IN_OMP_GET_NUM_TEAMS, "omp_get_num_teams", + BT_FN_INT, ATTR_CONST_NOTHROW_LEAF_LIST) DEF_GOMP_BUILTIN (BUILT_IN_GOMP_ATOMIC_START, "GOMP_atomic_start", BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST) diff --git a/gcc/omp-low.c b/gcc/omp-low.c index 82f5b49b18f8b..d804d68b832a8 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -224,6 +224,8 @@ extract_omp_for_data (gimple for_stmt, struct omp_for_data *fd, struct omp_for_data_loop dummy_loop; location_t loc = gimple_location (for_stmt); bool non_ws = gimple_omp_for_kind (for_stmt) == GF_OMP_FOR_KIND_SIMD; + bool distribute = gimple_omp_for_kind (for_stmt) + == GF_OMP_FOR_KIND_DISTRIBUTE; fd->for_stmt = for_stmt; fd->pre = NULL; @@ -233,7 +235,8 @@ extract_omp_for_data (gimple for_stmt, struct omp_for_data *fd, else fd->loops = &fd->loop; - fd->have_nowait = fd->have_ordered = false; + fd->have_nowait = distribute; + fd->have_ordered = false; fd->sched_kind = OMP_CLAUSE_SCHEDULE_STATIC; fd->chunk_size = NULL_TREE; collapse_iter = NULL; @@ -249,9 +252,14 @@ extract_omp_for_data (gimple for_stmt, struct omp_for_data *fd, fd->have_ordered = true; break; case OMP_CLAUSE_SCHEDULE: + gcc_assert (!distribute); fd->sched_kind = OMP_CLAUSE_SCHEDULE_KIND (t); fd->chunk_size = OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (t); break; + case OMP_CLAUSE_DIST_SCHEDULE: + gcc_assert (distribute); + fd->chunk_size = OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (t); + break; case OMP_CLAUSE_COLLAPSE: if (fd->collapse > 1) { @@ -1903,7 +1911,7 @@ check_omp_nesting_restrictions (gimple stmt, omp_context *ctx) return true; if (gimple_omp_for_kind (stmt) == GF_OMP_FOR_KIND_DISTRIBUTE) { - if (ctx == NULL || gimple_code (ctx->stmt) != GIMPLE_OMP_TEAMS) + if (ctx != NULL && gimple_code (ctx->stmt) != GIMPLE_OMP_TEAMS) { error_at (gimple_location (stmt), "distribute construct must be closely nested inside " @@ -4527,6 +4535,8 @@ expand_omp_for_static_nochunk (struct omp_region *region, gimple_stmt_iterator gsi; gimple stmt; edge ep; + enum built_in_function get_num_threads = BUILT_IN_OMP_GET_NUM_THREADS; + enum built_in_function get_thread_num = BUILT_IN_OMP_GET_THREAD_NUM; itype = type = TREE_TYPE (fd->loop.v); if (POINTER_TYPE_P (type)) @@ -4547,6 +4557,12 @@ expand_omp_for_static_nochunk (struct omp_region *region, gsi = gsi_last_bb (entry_bb); gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR); + if (gimple_omp_for_kind (fd->for_stmt) == GF_OMP_FOR_KIND_DISTRIBUTE) + { + get_num_threads = BUILT_IN_OMP_GET_NUM_TEAMS; + get_thread_num = BUILT_IN_OMP_GET_TEAM_NUM; + } + t = fold_binary (fd->loop.cond_code, boolean_type_node, fold_convert (type, fd->loop.n1), fold_convert (type, fd->loop.n2)); @@ -4591,12 +4607,12 @@ expand_omp_for_static_nochunk (struct omp_region *region, gsi = gsi_last_bb (entry_bb); } - t = build_call_expr (builtin_decl_explicit (BUILT_IN_OMP_GET_NUM_THREADS), 0); + t = build_call_expr (builtin_decl_explicit (get_num_threads), 0); t = fold_convert (itype, t); nthreads = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, true, GSI_SAME_STMT); - t = build_call_expr (builtin_decl_explicit (BUILT_IN_OMP_GET_THREAD_NUM), 0); + t = build_call_expr (builtin_decl_explicit (get_thread_num), 0); t = fold_convert (itype, t); threadid = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, true, GSI_SAME_STMT); @@ -4798,6 +4814,8 @@ expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd) gimple_stmt_iterator si; gimple stmt; edge se; + enum built_in_function get_num_threads = BUILT_IN_OMP_GET_NUM_THREADS; + enum built_in_function get_thread_num = BUILT_IN_OMP_GET_THREAD_NUM; itype = type = TREE_TYPE (fd->loop.v); if (POINTER_TYPE_P (type)) @@ -4823,6 +4841,12 @@ expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd) si = gsi_last_bb (entry_bb); gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_FOR); + if (gimple_omp_for_kind (fd->for_stmt) == GF_OMP_FOR_KIND_DISTRIBUTE) + { + get_num_threads = BUILT_IN_OMP_GET_NUM_TEAMS; + get_thread_num = BUILT_IN_OMP_GET_TEAM_NUM; + } + t = fold_binary (fd->loop.cond_code, boolean_type_node, fold_convert (type, fd->loop.n1), fold_convert (type, fd->loop.n2)); @@ -4867,12 +4891,12 @@ expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd) si = gsi_last_bb (entry_bb); } - t = build_call_expr (builtin_decl_explicit (BUILT_IN_OMP_GET_NUM_THREADS), 0); + t = build_call_expr (builtin_decl_explicit (get_num_threads), 0); t = fold_convert (itype, t); nthreads = force_gimple_operand_gsi (&si, t, true, NULL_TREE, true, GSI_SAME_STMT); - t = build_call_expr (builtin_decl_explicit (BUILT_IN_OMP_GET_THREAD_NUM), 0); + t = build_call_expr (builtin_decl_explicit (get_thread_num), 0); t = fold_convert (itype, t); threadid = force_gimple_operand_gsi (&si, t, true, NULL_TREE, true, GSI_SAME_STMT); @@ -5488,6 +5512,10 @@ expand_omp_for (struct omp_region *region) { int fn_index, start_ix, next_ix; + /* FIXME: expand_omp_for_static_*chunk needs to handle + collapse > 1 for distribute. */ + gcc_assert (gimple_omp_for_kind (fd.for_stmt) + != GF_OMP_FOR_KIND_DISTRIBUTE); if (fd.chunk_size == NULL && fd.sched_kind == OMP_CLAUSE_SCHEDULE_STATIC) fd.chunk_size = integer_zero_node; From d8c7ef0f9b2b7f5ce56b9645f0d795e84dc6795f Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Mon, 3 Jun 2013 10:47:37 -0500 Subject: [PATCH 38/63] Move Cilk Plus pragma simd tests to a shared directory with C++. Adjust dejagnu files accordingly. --- .../cilk-plus/PS}/body.c | 2 +- .../cilk-plus/PS}/clauses1.c | 2 +- .../cilk-plus/PS}/clauses2.c | 2 +- .../cilk-plus/PS}/clauses3.c | 2 +- .../cilk-plus/PS}/for1.c | 2 +- .../cilk-plus/PS}/for2.c | 2 +- .../cilk-plus/PS}/for3.c | 2 +- .../cilk-plus/PS}/safelen.c | 2 +- .../cilk-plus/PS}/vectorlength.c | 2 +- gcc/testsuite/gcc.dg/cilk-plus/cilk-plus.exp | 50 +++++++++++++++++++ .../cilk-simd/compile/cilk-simd-compile.exp | 23 --------- 11 files changed, 59 insertions(+), 32 deletions(-) rename gcc/testsuite/{gcc.dg/cilk-plus/cilk-simd/compile => c-c++-common/cilk-plus/PS}/body.c (93%) rename gcc/testsuite/{gcc.dg/cilk-plus/cilk-simd/compile => c-c++-common/cilk-plus/PS}/clauses1.c (96%) rename gcc/testsuite/{gcc.dg/cilk-plus/cilk-simd/compile => c-c++-common/cilk-plus/PS}/clauses2.c (86%) rename gcc/testsuite/{gcc.dg/cilk-plus/cilk-simd/compile => c-c++-common/cilk-plus/PS}/clauses3.c (94%) rename gcc/testsuite/{gcc.dg/cilk-plus/cilk-simd/compile => c-c++-common/cilk-plus/PS}/for1.c (98%) rename gcc/testsuite/{gcc.dg/cilk-plus/cilk-simd/compile => c-c++-common/cilk-plus/PS}/for2.c (97%) rename gcc/testsuite/{gcc.dg/cilk-plus/cilk-simd/compile => c-c++-common/cilk-plus/PS}/for3.c (72%) rename gcc/testsuite/{gcc.dg/cilk-plus/cilk-simd/compile => c-c++-common/cilk-plus/PS}/safelen.c (81%) rename gcc/testsuite/{gcc.dg/cilk-plus/cilk-simd/compile => c-c++-common/cilk-plus/PS}/vectorlength.c (91%) create mode 100644 gcc/testsuite/gcc.dg/cilk-plus/cilk-plus.exp delete mode 100644 gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/cilk-simd-compile.exp diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/body.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/body.c similarity index 93% rename from gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/body.c rename to gcc/testsuite/c-c++-common/cilk-plus/PS/body.c index 50b3ab1446b88..4f7430a441127 100644 --- a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/body.c +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/body.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O3 -fcilkplus -fopenmp" } */ +/* { dg-options "-O3 -fopenmp" } */ int *a, *b, c; void *jmpbuf[10]; diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/clauses1.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/clauses1.c similarity index 96% rename from gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/clauses1.c rename to gcc/testsuite/c-c++-common/cilk-plus/PS/clauses1.c index d0a2f7965923a..c7295a829e195 100644 --- a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/clauses1.c +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/clauses1.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O3 -std=c99 -fcilkplus -Werror -Wunknown-pragmas" } */ +/* { dg-options "-O3 -std=c99 -Werror -Wunknown-pragmas" } */ volatile int *a, *b; diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/clauses2.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/clauses2.c similarity index 86% rename from gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/clauses2.c rename to gcc/testsuite/c-c++-common/cilk-plus/PS/clauses2.c index ca99ca879799a..1eb44f3f7e3a0 100644 --- a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/clauses2.c +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/clauses2.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O3 -std=c99 -fcilkplus -fdump-tree-original" } */ +/* { dg-options "-O3 -std=c99 -fdump-tree-original" } */ volatile int *a, *b; diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/clauses3.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/clauses3.c similarity index 94% rename from gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/clauses3.c rename to gcc/testsuite/c-c++-common/cilk-plus/PS/clauses3.c index 5536884ea0672..0f38e3cf77bf3 100644 --- a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/clauses3.c +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/clauses3.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O3 -std=c99 -fcilkplus" } */ +/* { dg-options "-O3 -std=c99" } */ #define N 1000 diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for1.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/for1.c similarity index 98% rename from gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for1.c rename to gcc/testsuite/c-c++-common/cilk-plus/PS/for1.c index f8cc5588f1e3c..c2e99fd9da796 100644 --- a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for1.c +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/for1.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O3 -std=c99 -fcilkplus" } */ +/* { dg-options "-O3 -std=c99" } */ int *a, *b, *c; int something; diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for2.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/for2.c similarity index 97% rename from gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for2.c rename to gcc/testsuite/c-c++-common/cilk-plus/PS/for2.c index 2d09ae82d4946..f9a5083e3facc 100644 --- a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for2.c +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/for2.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O3 -std=c99 -fcilkplus" } */ +/* { dg-options "-O3 -std=c99" } */ // Test storage classes in the initialization of a <#pragma simd> for // loop. diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for3.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/for3.c similarity index 72% rename from gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for3.c rename to gcc/testsuite/c-c++-common/cilk-plus/PS/for3.c index 86606275ac471..084790d53e495 100644 --- a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for3.c +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/for3.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O3 -fcilkplus" } */ +/* { dg-options "-O3" } */ #pragma simd /* { dg-error "must be inside a function" } */ diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/safelen.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/safelen.c similarity index 81% rename from gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/safelen.c rename to gcc/testsuite/c-c++-common/cilk-plus/PS/safelen.c index 430aa416506ef..eefd9aa346b85 100644 --- a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/safelen.c +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/safelen.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O3 -fcilkplus -fdump-tree-gimple" } */ +/* { dg-options "-O3 -fdump-tree-gimple" } */ int *a, *b; diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/vectorlength.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/vectorlength.c similarity index 91% rename from gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/vectorlength.c rename to gcc/testsuite/c-c++-common/cilk-plus/PS/vectorlength.c index 4bff17ddf84ab..4c6a98b8cbbb3 100644 --- a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/vectorlength.c +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/vectorlength.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O3 -fcilkplus" } */ +/* { dg-options "-O3" } */ volatile int *a, *b, N; typedef int tint; diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-plus.exp b/gcc/testsuite/gcc.dg/cilk-plus/cilk-plus.exp new file mode 100644 index 0000000000000..060b3933ac00a --- /dev/null +++ b/gcc/testsuite/gcc.dg/cilk-plus/cilk-plus.exp @@ -0,0 +1,50 @@ +# Copyright (C) 2013 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# . + +# Written by Balaji V. Iyer + + +load_lib gcc-dg.exp + +dg-init +dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -fcilkplus" " " +dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -O0 -fcilkplus" " " +dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -O1 -fcilkplus" " " +dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -O2 -ftree-vectorize -fcilkplus" " " +dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -O3 -fcilkplus" " " +dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -g -fcilkplus" " " +dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -g -O0 -fcilkplus" " " +dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -g -O1 -fcilkplus" " " +dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -g -O2 -ftree-vectorize -fcilkplus" " " +dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -g -O3 -fcilkplus" " " +dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -O3 -ftree-vectorize -fcilkplus -g" " " +dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -fcilkplus -std=c99" " " +dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -fcilkplus -O0 -std=c99" " " +dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -fcilkplus -O1 -std=c99" " " +dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -fcilkplus -O2 -ftree-vectorize -std=c99" " " +dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -fcilkplus -O3 -std=c99" " " +dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -fcilkplus -g -std=c99" " " +dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -fcilkplus -g -O0 -std=c99" " " +dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -fcilkplus -g -O1 -std=c99" " " +dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -fcilkplus -g -O2 -ftree-vectorize -std=c99" " " +dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -fcilkplus -g -O3 -std=c99" " " +dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -O3 -ftree-vectorize -std=c99 -g -fcilkplus" " " + +# pragma simd tests +# Run the tests that are shared with C++. +dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/PS/*.c]] " -ftree-vectorize -fcilkplus" " " + +dg-finish diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/cilk-simd-compile.exp b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/cilk-simd-compile.exp deleted file mode 100644 index 154bb8c0d6740..0000000000000 --- a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/cilk-simd-compile.exp +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright (C) 2013 Free Software Foundation, Inc. - -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with GCC; see the file COPYING3. If not see -# . - -load_lib gcc-dg.exp - -set OPTS "-fcilkplus -c -ftree-vectorize" - -dg-init -dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.c]] " $OPTS" " " -dg-finish From 11d1a18bdd47018ebefd4278276d2864585bcf0d Mon Sep 17 00:00:00 2001 From: jakub Date: Tue, 4 Jun 2013 18:57:41 +0000 Subject: [PATCH 39/63] * gimplify.c (gimplify_scan_omp_clauses): Handle array sections on OMP_CLAUSE_{MAP,TO,FROM} clauses, handle OMP_CLAUSE_DEPEND clause. (gimplify_adjust_omp_clauses): Handle array sections on OMP_CLAUSE_MAP, handle OMP_CLAUSE_DEPEND clause. * tree.c (omp_clause_num_ops): OMP_CLAUSE_{MAP,TO,FROM} now have 2 arguments, move OMP_CLAUSE_UNIFORM before these 3. (omp_clause_code_name): Adjust for OMP_CLAUSE_UNIFORM movement. (walk_tree_1): Adjust to handle 2 arguments of OMP_CLAUSE_{MAP,TO,FROM}. * tree-pretty-print.c (dump_omp_clause): For OMP_CLAUSE_{MAP,TO,FROM} print OMP_CLAUSE_SIZE, and for OMP_CLAUSE_MAP handle OMP_CLAUSE_MAP_POINTER. * tree.h (enum omp_clause_code): Move OMP_CLAUSE_UNIFORM before OMP_CLAUSE_{MAP,TO,FROM}. (OMP_CLAUSE_SIZE): Define. (enum omp_clause_map_kind): Add OMP_CLAUSE_MAP_POINTER. * omp-low.c (scan_sharing_clauses): Handle OMP_CLAUSE_DEPEND. cp/ * semantics.c (handle_omp_array_sections_1, handle_omp_array_sections): New functions. (finish_omp_clauses): Handle array sections on OMP_CLAUSE_{MAP,TO,FROM,DEPEND}. If not array sections, mark the decl addressable. * parser.c (cp_parser_omp_var_list_no_open): Parse array sections on OMP_CLAUSE_{MAP,TO,FROM,DEPEND} clauses. testsuite/ * g++.dg/gomp/depend-1.C: New test. * g++.dg/gomp/depend-2.C: New test. * c-c++-common/gomp/depend-1.c: New test. * c-c++-common/gomp/depend-2.c: New test. * c-c++-common/gomp/map-1.c: New test. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gomp-4_0-branch@199669 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog.gomp | 22 + gcc/cp/ChangeLog.gomp | 10 + gcc/cp/parser.c | 45 +- gcc/cp/semantics.c | 480 ++++++++++++++++++++- gcc/gimplify.c | 63 ++- gcc/omp-low.c | 2 + gcc/testsuite/ChangeLog.gomp | 8 + gcc/testsuite/c-c++-common/gomp/depend-1.c | 79 ++++ gcc/testsuite/c-c++-common/gomp/depend-2.c | 19 + gcc/testsuite/c-c++-common/gomp/map-1.c | 103 +++++ gcc/testsuite/g++.dg/gomp/depend-1.C | 70 +++ gcc/testsuite/g++.dg/gomp/depend-2.C | 87 ++++ gcc/tree-pretty-print.c | 30 +- gcc/tree.c | 14 +- gcc/tree.h | 17 +- 15 files changed, 1021 insertions(+), 28 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/gomp/depend-1.c create mode 100644 gcc/testsuite/c-c++-common/gomp/depend-2.c create mode 100644 gcc/testsuite/c-c++-common/gomp/map-1.c create mode 100644 gcc/testsuite/g++.dg/gomp/depend-1.C create mode 100644 gcc/testsuite/g++.dg/gomp/depend-2.C diff --git a/gcc/ChangeLog.gomp b/gcc/ChangeLog.gomp index 76205633ec5c7..a9bf4b4dfcf32 100644 --- a/gcc/ChangeLog.gomp +++ b/gcc/ChangeLog.gomp @@ -1,3 +1,25 @@ +2013-06-04 Jakub Jelinek + + * gimplify.c (gimplify_scan_omp_clauses): Handle array + sections on OMP_CLAUSE_{MAP,TO,FROM} clauses, handle + OMP_CLAUSE_DEPEND clause. + (gimplify_adjust_omp_clauses): Handle array sections on + OMP_CLAUSE_MAP, handle OMP_CLAUSE_DEPEND clause. + * tree.c (omp_clause_num_ops): OMP_CLAUSE_{MAP,TO,FROM} + now have 2 arguments, move OMP_CLAUSE_UNIFORM before these + 3. + (omp_clause_code_name): Adjust for OMP_CLAUSE_UNIFORM movement. + (walk_tree_1): Adjust to handle 2 arguments of + OMP_CLAUSE_{MAP,TO,FROM}. + * tree-pretty-print.c (dump_omp_clause): For OMP_CLAUSE_{MAP,TO,FROM} + print OMP_CLAUSE_SIZE, and for OMP_CLAUSE_MAP handle + OMP_CLAUSE_MAP_POINTER. + * tree.h (enum omp_clause_code): Move OMP_CLAUSE_UNIFORM before + OMP_CLAUSE_{MAP,TO,FROM}. + (OMP_CLAUSE_SIZE): Define. + (enum omp_clause_map_kind): Add OMP_CLAUSE_MAP_POINTER. + * omp-low.c (scan_sharing_clauses): Handle OMP_CLAUSE_DEPEND. + 2013-05-29 Jakub Jelinek * omp-builtins.def (BUILT_IN_OMP_GET_TEAM_NUM, diff --git a/gcc/cp/ChangeLog.gomp b/gcc/cp/ChangeLog.gomp index fe76ff861f1bd..ab582f5ac97ae 100644 --- a/gcc/cp/ChangeLog.gomp +++ b/gcc/cp/ChangeLog.gomp @@ -1,3 +1,13 @@ +2013-06-04 Jakub Jelinek + + * semantics.c (handle_omp_array_sections_1, handle_omp_array_sections): + New functions. + (finish_omp_clauses): Handle array sections on + OMP_CLAUSE_{MAP,TO,FROM,DEPEND}. If not array sections, mark the decl + addressable. + * parser.c (cp_parser_omp_var_list_no_open): Parse array sections + on OMP_CLAUSE_{MAP,TO,FROM,DEPEND} clauses. + 2013-05-29 Jakub Jelinek * parser.c (cp_parser_omp_declare_target, diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index a30f52ac4ce11..8c3e690879b23 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -26303,12 +26303,7 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, /*declarator_p=*/false, /*optional_p=*/false); if (name == error_mark_node) - { - if (colon) - parser->colon_corrects_to_scope_p - = saved_colon_corrects_to_scope_p; - goto skip_comma; - } + goto skip_comma; decl = cp_parser_lookup_name_simple (parser, name, token->location); } @@ -26317,6 +26312,42 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, token->location); else if (kind != 0) { + switch (kind) + { + case OMP_CLAUSE_MAP: + case OMP_CLAUSE_FROM: + case OMP_CLAUSE_TO: + case OMP_CLAUSE_DEPEND: + while (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_SQUARE)) + { + tree low_bound = NULL_TREE, length = NULL_TREE; + + parser->colon_corrects_to_scope_p = false; + cp_lexer_consume_token (parser->lexer); + if (!cp_lexer_next_token_is (parser->lexer, CPP_COLON)) + low_bound = cp_parser_expression (parser, /*cast_p=*/false, + NULL); + if (!colon) + parser->colon_corrects_to_scope_p + = saved_colon_corrects_to_scope_p; + /* Look for `:'. */ + if (!cp_parser_require (parser, CPP_COLON, RT_COLON)) + goto skip_comma; + if (!cp_lexer_next_token_is (parser->lexer, + CPP_CLOSE_SQUARE)) + length = cp_parser_expression (parser, /*cast_p=*/false, + NULL); + /* Look for the closing `]'. */ + if (!cp_parser_require (parser, CPP_CLOSE_SQUARE, + RT_CLOSE_SQUARE)) + goto skip_comma; + decl = tree_cons (low_bound, length, decl); + } + break; + default: + break; + } + tree u = build_omp_clause (token->location, kind); OMP_CLAUSE_DECL (u) = decl; OMP_CLAUSE_CHAIN (u) = list; @@ -26348,6 +26379,8 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, /* Try to resync to an unnested comma. Copied from cp_parser_parenthesized_expression_list. */ skip_comma: + if (colon) + parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p; ending = cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, /*or_comma=*/true, diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 154af66b0aab1..9c5dc74977dbc 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -4068,6 +4068,458 @@ cxx_omp_create_clause_info (tree c, tree type, bool need_default_ctor, return errorcount != save_errorcount; } +/* Helper function for handle_omp_array_sections. Called recursively + to handle multiple array-section-subscripts. C is the clause, + T current expression (initially OMP_CLAUSE_DECL), which is either + a TREE_LIST for array-section-subscript (TREE_PURPOSE is low-bound + expression if specified, TREE_VALUE length expression if specified, + TREE_CHAIN is what it has been specified after, or some decl. + TYPES vector is populated with array section types, MAYBE_ZERO_LEN + set to true if any of the array-section-subscript could have length + of zero (explicit or implicit), FIRST_NON_ONE is the index of the + first array-section-subscript which is known not to have length + of one. Given say: + map(a[:b][2:1][:c][:2][:d][e:f][2:5]) + FIRST_NON_ONE will be 3, array-section-subscript [:b], [2:1] and [:c] + all are or may have length of 1, array-section-subscript [:2] is the + first one knonwn not to have length 1. For array-section-subscript + <= FIRST_NON_ONE we diagnose non-contiguous arrays if low bound isn't + 0 or length isn't the array domain max + 1, for > FIRST_NON_ONE we + can if MAYBE_ZERO_LEN is false. MAYBE_ZERO_LEN will be true in the above + case though, as some lengths could be zero. */ + +static tree +handle_omp_array_sections_1 (tree c, tree t, vec &types, + bool &maybe_zero_len, unsigned int &first_non_one, + bool &pointer_based_p) +{ + tree ret, low_bound, length, type; + if (TREE_CODE (t) != TREE_LIST) + { + if (error_operand_p (t)) + return error_mark_node; + if (type_dependent_expression_p (t)) + return NULL_TREE; + if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) + { + if (processing_template_decl) + return NULL_TREE; + if (DECL_P (t)) + error_at (OMP_CLAUSE_LOCATION (c), + "%qD is not a variable in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + else + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is not a variable in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + else if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND + && TREE_CODE (t) == VAR_DECL && DECL_THREAD_LOCAL_P (t)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qD is threadprivate variable in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + if (!processing_template_decl + && POINTER_TYPE_P (TREE_TYPE (t)) + && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP) + pointer_based_p = true; + t = convert_from_reference (t); + return t; + } + + ret = handle_omp_array_sections_1 (c, TREE_CHAIN (t), types, + maybe_zero_len, first_non_one, + pointer_based_p); + if (ret == error_mark_node || ret == NULL_TREE) + return ret; + + type = TREE_TYPE (ret); + low_bound = TREE_PURPOSE (t); + length = TREE_VALUE (t); + if ((low_bound && type_dependent_expression_p (low_bound)) + || (length && type_dependent_expression_p (length))) + return NULL_TREE; + + if (low_bound == error_mark_node || length == error_mark_node) + return error_mark_node; + + if (low_bound && !INTEGRAL_TYPE_P (TREE_TYPE (low_bound))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "low bound %qE of array section does not have integral type", + low_bound); + return error_mark_node; + } + if (length && !INTEGRAL_TYPE_P (TREE_TYPE (length))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "length %qE of array section does not have integral type", + length); + return error_mark_node; + } + if (low_bound + && TREE_CODE (low_bound) == INTEGER_CST + && TYPE_PRECISION (TREE_TYPE (low_bound)) + > TYPE_PRECISION (sizetype)) + low_bound = fold_convert (sizetype, low_bound); + if (length + && TREE_CODE (length) == INTEGER_CST + && TYPE_PRECISION (TREE_TYPE (length)) + > TYPE_PRECISION (sizetype)) + length = fold_convert (sizetype, length); + if (low_bound == NULL_TREE) + low_bound = integer_zero_node; + + if (length != NULL_TREE) + { + if (!integer_nonzerop (length)) + maybe_zero_len = true; + if (first_non_one == types.length () + && (TREE_CODE (length) != INTEGER_CST || integer_onep (length))) + first_non_one++; + } + if (TREE_CODE (type) == ARRAY_TYPE) + { + if (length == NULL_TREE + && (TYPE_DOMAIN (type) == NULL_TREE + || TYPE_MAX_VALUE (TYPE_DOMAIN (type)) == NULL_TREE)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "for unknown bound array type length expression is " + "not optional"); + return error_mark_node; + } + if (TREE_CODE (low_bound) == INTEGER_CST + && tree_int_cst_sgn (low_bound) == -1) + { + error_at (OMP_CLAUSE_LOCATION (c), + "negative low bound in array section in %qs clause", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + if (length != NULL_TREE + && TREE_CODE (length) == INTEGER_CST + && tree_int_cst_sgn (length) == -1) + { + error_at (OMP_CLAUSE_LOCATION (c), + "negative length in array section in %qs clause", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + if (TYPE_DOMAIN (type) + && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) + && TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) + == INTEGER_CST) + { + tree size = size_binop (PLUS_EXPR, + TYPE_MAX_VALUE (TYPE_DOMAIN (type)), + size_one_node); + if (TREE_CODE (low_bound) == INTEGER_CST) + { + if (tree_int_cst_lt (size, low_bound)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "low bound %qE above array section size " + "in %qs clause", low_bound, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + if (tree_int_cst_equal (size, low_bound)) + maybe_zero_len = true; + else if (length == NULL_TREE + && first_non_one == types.length () + && tree_int_cst_equal + (TYPE_MAX_VALUE (TYPE_DOMAIN (type)), + low_bound)) + first_non_one++; + } + else if (length == NULL_TREE) + { + maybe_zero_len = true; + if (first_non_one == types.length ()) + first_non_one++; + } + if (length && TREE_CODE (length) == INTEGER_CST) + { + if (tree_int_cst_lt (size, length)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "length %qE above array section size " + "in %qs clause", length, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + if (TREE_CODE (low_bound) == INTEGER_CST) + { + tree lbpluslen + = size_binop (PLUS_EXPR, + fold_convert (sizetype, low_bound), + fold_convert (sizetype, length)); + if (TREE_CODE (lbpluslen) == INTEGER_CST + && tree_int_cst_lt (size, lbpluslen)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "high bound %qE above array section size " + "in %qs clause", lbpluslen, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + } + } + } + else if (length == NULL_TREE) + { + maybe_zero_len = true; + if (first_non_one == types.length ()) + first_non_one++; + } + + /* For [lb:] we will need to evaluate lb more than once. */ + if (length == NULL_TREE && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND) + { + tree lb = cp_save_expr (low_bound); + if (lb != low_bound) + { + TREE_PURPOSE (t) = lb; + low_bound = lb; + } + } + } + else if (TREE_CODE (type) == POINTER_TYPE) + { + if (length == NULL_TREE) + { + error_at (OMP_CLAUSE_LOCATION (c), + "for pointer type length expression is not optional"); + return error_mark_node; + } + /* If there is a pointer type anywhere but in the very first + array-section-subscript, the array section can't be contiguous. */ + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND + && TREE_CODE (TREE_CHAIN (t)) == TREE_LIST) + { + error_at (OMP_CLAUSE_LOCATION (c), + "array section is not contiguous in %qs clause", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + } + else + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE does not have pointer or array type", ret); + return error_mark_node; + } + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND) + types.safe_push (TREE_TYPE (ret)); + /* For pointer based array sections we will need to evaluate lb more + than once. */ + if (pointer_based_p) + { + tree lb = cp_save_expr (low_bound); + if (lb != low_bound) + { + TREE_PURPOSE (t) = lb; + low_bound = lb; + } + } + ret = grok_array_decl (OMP_CLAUSE_LOCATION (c), ret, low_bound, false); + return ret; +} + +/* Handle array sections for clause C. */ + +static bool +handle_omp_array_sections (tree c) +{ + bool maybe_zero_len = false; + bool pointer_based_p = false; + unsigned int first_non_one = 0; + vec types = vNULL; + tree first = handle_omp_array_sections_1 (c, OMP_CLAUSE_DECL (c), types, + maybe_zero_len, first_non_one, + pointer_based_p); + if (first == error_mark_node) + { + types.release (); + return true; + } + if (first == NULL_TREE) + { + types.release (); + return false; + } + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND) + { + tree t = OMP_CLAUSE_DECL (c); + tree tem = NULL_TREE; + types.release (); + if (processing_template_decl) + return false; + /* Need to evaluate side effects in the length expressions + if any. */ + while (TREE_CODE (t) == TREE_LIST) + { + if (TREE_VALUE (t) && TREE_SIDE_EFFECTS (TREE_VALUE (t))) + { + if (tem == NULL_TREE) + tem = TREE_VALUE (t); + else + tem = build2 (COMPOUND_EXPR, TREE_TYPE (tem), + TREE_VALUE (t), tem); + } + t = TREE_CHAIN (t); + } + if (tem) + first = build2 (COMPOUND_EXPR, TREE_TYPE (first), tem, first); + OMP_CLAUSE_DECL (c) = first; + } + else + { + unsigned int num = types.length (), i; + tree t, side_effects = NULL_TREE, size = NULL_TREE; + tree condition = NULL_TREE; + + if (int_size_in_bytes (TREE_TYPE (first)) <= 0) + maybe_zero_len = true; + if (processing_template_decl && maybe_zero_len) + { + types.release (); + return false; + } + + for (i = num, t = OMP_CLAUSE_DECL (c); i > 0; + t = TREE_CHAIN (t)) + { + tree low_bound = TREE_PURPOSE (t); + tree length = TREE_VALUE (t); + + i--; + if (low_bound + && TREE_CODE (low_bound) == INTEGER_CST + && TYPE_PRECISION (TREE_TYPE (low_bound)) + > TYPE_PRECISION (sizetype)) + low_bound = fold_convert (sizetype, low_bound); + if (length + && TREE_CODE (length) == INTEGER_CST + && TYPE_PRECISION (TREE_TYPE (length)) + > TYPE_PRECISION (sizetype)) + length = fold_convert (sizetype, length); + if (low_bound == NULL_TREE) + low_bound = integer_zero_node; + if (!maybe_zero_len && i > first_non_one) + { + if (integer_nonzerop (low_bound)) + goto do_warn_noncontiguous; + if (length != NULL_TREE + && TREE_CODE (length) == INTEGER_CST + && TYPE_DOMAIN (types[i]) + && TYPE_MAX_VALUE (TYPE_DOMAIN (types[i])) + && TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (types[i]))) + == INTEGER_CST) + { + tree size; + size = size_binop (PLUS_EXPR, + TYPE_MAX_VALUE (TYPE_DOMAIN (types[i])), + size_one_node); + if (!tree_int_cst_equal (length, size)) + { + do_warn_noncontiguous: + error_at (OMP_CLAUSE_LOCATION (c), + "array section is not contiguous in %qs " + "clause", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + types.release (); + return true; + } + } + if (!processing_template_decl + && length != NULL_TREE + && TREE_SIDE_EFFECTS (length)) + { + if (side_effects == NULL_TREE) + side_effects = length; + else + side_effects = build2 (COMPOUND_EXPR, + TREE_TYPE (side_effects), + length, side_effects); + } + } + else if (processing_template_decl) + continue; + else + { + tree l; + + if (i > first_non_one && length && integer_nonzerop (length)) + continue; + if (length) + l = fold_convert (sizetype, length); + else + { + l = size_binop (PLUS_EXPR, + TYPE_MAX_VALUE (TYPE_DOMAIN (types[i])), + size_one_node); + l = size_binop (MINUS_EXPR, l, + fold_convert (sizetype, low_bound)); + } + if (i > first_non_one) + { + l = fold_build2 (NE_EXPR, boolean_type_node, l, + size_zero_node); + if (condition == NULL_TREE) + condition = l; + else + condition = fold_build2 (BIT_AND_EXPR, boolean_type_node, + l, condition); + } + else if (size == NULL_TREE) + { + size = size_in_bytes (TREE_TYPE (types[i])); + size = size_binop (MULT_EXPR, size, l); + if (condition) + size = fold_build3 (COND_EXPR, sizetype, condition, + size, size_zero_node); + } + else + size = size_binop (MULT_EXPR, size, l); + } + } + types.release (); + if (!processing_template_decl) + { + if (side_effects) + size = build2 (COMPOUND_EXPR, sizetype, side_effects, size); + OMP_CLAUSE_DECL (c) = first; + OMP_CLAUSE_SIZE (c) = size; + if (pointer_based_p) + { + tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), + OMP_CLAUSE_MAP); + OMP_CLAUSE_MAP_KIND (c2) = OMP_CLAUSE_MAP_POINTER; + if (!cxx_mark_addressable (t)) + return false; + OMP_CLAUSE_DECL (c2) = t; + t = build_fold_addr_expr (first); + t = fold_convert_loc (OMP_CLAUSE_LOCATION (c), + build_pointer_type (char_type_node), t); + t = fold_build2_loc (OMP_CLAUSE_LOCATION (c), MINUS_EXPR, + ptrdiff_type_node, t, + fold_convert_loc (OMP_CLAUSE_LOCATION (c), + TREE_TYPE (t), + OMP_CLAUSE_DECL (c2))); + OMP_CLAUSE_SIZE (c2) = t; + OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (c); + OMP_CLAUSE_CHAIN (c) = c2; + } + } + } + return false; +} + /* For all elements of CLAUSES, validate them vs OpenMP constraints. Remove any elements from the list that are invalid. */ @@ -4419,8 +4871,15 @@ finish_omp_clauses (tree clauses) case OMP_CLAUSE_DEPEND: t = OMP_CLAUSE_DECL (c); - /* FIXME: depend clause argument may be also array section. */ - if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) + if (TREE_CODE (t) == TREE_LIST) + { + if (handle_omp_array_sections (c)) + remove = true; + break; + } + if (t == error_mark_node) + remove = true; + else if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) { if (processing_template_decl) break; @@ -4430,14 +4889,24 @@ finish_omp_clauses (tree clauses) error ("%qE is not a variable in % clause", t); remove = true; } + else if (!processing_template_decl + && !cxx_mark_addressable (t)) + remove = true; break; case OMP_CLAUSE_MAP: case OMP_CLAUSE_TO: case OMP_CLAUSE_FROM: t = OMP_CLAUSE_DECL (c); - /* FIXME: map clause argument may be also array section. */ - if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) + if (TREE_CODE (t) == TREE_LIST) + { + if (handle_omp_array_sections (c)) + remove = true; + break; + } + if (t == error_mark_node) + remove = true; + else if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) { if (processing_template_decl) break; @@ -4455,6 +4924,9 @@ finish_omp_clauses (tree clauses) omp_clause_code_name[OMP_CLAUSE_CODE (c)]); remove = true; } + else if (!processing_template_decl + && !cxx_mark_addressable (t)) + remove = true; break; case OMP_CLAUSE_UNIFORM: diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 0c0fe52f7d298..4caa79c42dc6a 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -6258,19 +6258,78 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, } flags = GOVD_LINEAR | GOVD_EXPLICIT; goto do_add; + case OMP_CLAUSE_MAP: + if (OMP_CLAUSE_SIZE (c) + && gimplify_expr (&OMP_CLAUSE_SIZE (c), pre_p, + NULL, is_gimple_val, fb_rvalue) == GS_ERROR) + { + remove = true; + break; + } + decl = OMP_CLAUSE_DECL (c); + if (!DECL_P (decl)) + { + if (gimplify_expr (&OMP_CLAUSE_DECL (c), pre_p, + NULL, is_gimple_lvalue, fb_lvalue) + == GS_ERROR) + { + remove = true; + break; + } + break; + } flags = GOVD_MAP | GOVD_EXPLICIT; notice_outer = false; goto do_add; + case OMP_CLAUSE_DEPEND: + if (TREE_CODE (OMP_CLAUSE_DECL (c)) == COMPOUND_EXPR) + { + gimplify_expr (&TREE_OPERAND (OMP_CLAUSE_DECL (c), 0), pre_p, + NULL, is_gimple_val, fb_rvalue); + OMP_CLAUSE_DECL (c) = TREE_OPERAND (OMP_CLAUSE_DECL (c), 1); + } + if (error_operand_p (OMP_CLAUSE_DECL (c))) + { + remove = true; + break; + } + OMP_CLAUSE_DECL (c) = build_fold_addr_expr (OMP_CLAUSE_DECL (c)); + if (gimplify_expr (&OMP_CLAUSE_DECL (c), pre_p, NULL, + is_gimple_val, fb_rvalue) == GS_ERROR) + { + remove = true; + break; + } + break; + case OMP_CLAUSE_TO: case OMP_CLAUSE_FROM: + if (OMP_CLAUSE_SIZE (c) + && gimplify_expr (&OMP_CLAUSE_SIZE (c), pre_p, + NULL, is_gimple_val, fb_rvalue) == GS_ERROR) + { + remove = true; + break; + } decl = OMP_CLAUSE_DECL (c); if (error_operand_p (decl)) { remove = true; break; } + if (!DECL_P (decl)) + { + if (gimplify_expr (&OMP_CLAUSE_DECL (c), pre_p, + NULL, is_gimple_lvalue, fb_lvalue) + == GS_ERROR) + { + remove = true; + break; + } + break; + } goto do_notice; do_add: @@ -6621,8 +6680,9 @@ gimplify_adjust_omp_clauses (tree *list_p) case OMP_CLAUSE_MAP: decl = OMP_CLAUSE_DECL (c); + if (!DECL_P (decl)) + break; n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl); - remove = false; if (ctx->region_type == ORT_TARGET && !(n->value & GOVD_SEEN)) remove = true; else @@ -6672,6 +6732,7 @@ gimplify_adjust_omp_clauses (tree *list_p) case OMP_CLAUSE_SAFELEN: case OMP_CLAUSE_TO: case OMP_CLAUSE_FROM: + case OMP_CLAUSE_DEPEND: break; default: diff --git a/gcc/omp-low.c b/gcc/omp-low.c index d804d68b832a8..b131cde703718 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -1492,6 +1492,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) case OMP_CLAUSE_NUM_THREADS: case OMP_CLAUSE_SCHEDULE: case OMP_CLAUSE_DIST_SCHEDULE: + case OMP_CLAUSE_DEPEND: if (ctx->outer) scan_omp_op (&OMP_CLAUSE_OPERAND (c, 0), ctx->outer); break; @@ -1567,6 +1568,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) case OMP_CLAUSE_PROC_BIND: case OMP_CLAUSE_SAFELEN: case OMP_CLAUSE_ALIGNED: + case OMP_CLAUSE_DEPEND: break; default: diff --git a/gcc/testsuite/ChangeLog.gomp b/gcc/testsuite/ChangeLog.gomp index ffd03ffd3bf43..8c20fa7cb51af 100644 --- a/gcc/testsuite/ChangeLog.gomp +++ b/gcc/testsuite/ChangeLog.gomp @@ -1,3 +1,11 @@ +2013-06-04 Jakub Jelinek + + * g++.dg/gomp/depend-1.C: New test. + * g++.dg/gomp/depend-2.C: New test. + * c-c++-common/gomp/depend-1.c: New test. + * c-c++-common/gomp/depend-2.c: New test. + * c-c++-common/gomp/map-1.c: New test. + 2013-05-13 Jakub Jelinek * gcc.dg/gomp/declare-simd-1.c: New test. diff --git a/gcc/testsuite/c-c++-common/gomp/depend-1.c b/gcc/testsuite/c-c++-common/gomp/depend-1.c new file mode 100644 index 0000000000000..03d4de98fec0f --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/depend-1.c @@ -0,0 +1,79 @@ +/* { dg-do compile { target c++ } } */ +/* { dg-options "-fopenmp" } */ + +extern int a[][10], a2[][10]; +int b[10], c[10][2], d[10], e[10], f[10]; +int b2[10], c2[10][2], d2[10], e2[10], f2[10]; +int k[10], l[10], m[10], n[10], o; +int *p; +void bar (void); +int t[10]; +#pragma omp threadprivate (t) + +void +foo (int g[3][10], int h[4][8], int i[2][10], int j[][9], + int g2[3][10], int h2[4][8], int i2[2][10], int j2[][9]) +{ + #pragma omp task depend(in: bar[2:5]) /* { dg-error "is not a variable" } */ + ; + #pragma omp task depend(out: t[2:5]) + ; + #pragma omp task depend(inout: k[0.5:]) /* { dg-error "low bound \[^\n\r]* of array section does not have integral type" } */ + ; + #pragma omp task depend(in: l[:7.5f]) /* { dg-error "length \[^\n\r]* of array section does not have integral type" } */ + ; + #pragma omp task depend(out: m[p:]) /* { dg-error "low bound \[^\n\r]* of array section does not have integral type" } */ + ; + #pragma omp task depend(inout: n[:p]) /* { dg-error "length \[^\n\r]* of array section does not have integral type" } */ + ; + #pragma omp task depend(in: o[2:5]) /* { dg-error "does not have pointer or array type" } */ + ; + #pragma omp task depend(out: a[:][2:4]) /* { dg-error "array type length expression is not optional" } */ + ; + #pragma omp task depend(inout: b[-1:]) /* { dg-error "negative low bound in array section" } */ + ; + #pragma omp task depend(inout: c[:-3][1:1]) /* { dg-error "negative length in array section" } */ + ; + #pragma omp task depend(in: d[11:]) /* { dg-error "low bound \[^\n\r]* above array section size" } */ + ; + #pragma omp task depend(out: e[:11]) /* { dg-error "length \[^\n\r]* above array section size" } */ + ; + #pragma omp task depend(out: f[1:10]) /* { dg-error "high bound \[^\n\r]* above array section size" } */ + ; + #pragma omp task depend(in: g[:][2:4]) /* { dg-error "for pointer type length expression is not optional" } */ + ; + #pragma omp task depend(in: h[2:2][-1:]) /* { dg-error "negative low bound in array section" } */ + ; + #pragma omp task depend(inout: h[:1][:-3]) /* { dg-error "negative length in array section" } */ + ; + #pragma omp task depend(out: i[:1][11:]) /* { dg-error "low bound \[^\n\r]* above array section size" } */ + ; + #pragma omp task depend(in: j[3:4][:10]) /* { dg-error "length \[^\n\r]* above array section size" } */ + ; + #pragma omp task depend(out: j[30:10][5:5]) /* { dg-error "high bound \[^\n\r]* above array section size" } */ + ; + #pragma omp task depend(out: a2[:3][2:4]) + ; + #pragma omp task depend(inout: b2[0:]) + ; + #pragma omp task depend(inout: c2[:3][1:1]) + ; + #pragma omp task depend(in: d2[9:]) + ; + #pragma omp task depend(out: e2[:10]) + ; + #pragma omp task depend(out: f2[1:9]) + ; + #pragma omp task depend(in: g2[:2][2:4]) + ; + #pragma omp task depend(in: h2[2:2][0:]) + ; + #pragma omp task depend(inout: h2[:1][:3]) + ; + #pragma omp task depend(out: i2[:1][9:]) + ; + #pragma omp task depend(in: j2[3:4][:9]) + ; + #pragma omp task depend(out: j2[30:10][5:4]) + ; +} diff --git a/gcc/testsuite/c-c++-common/gomp/depend-2.c b/gcc/testsuite/c-c++-common/gomp/depend-2.c new file mode 100644 index 0000000000000..723a05daf6938 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/depend-2.c @@ -0,0 +1,19 @@ +/* { dg-do compile { target c++ } } */ +/* { dg-options "-fopenmp" } */ + +void bar (int a[10][10][10]); +void +foo (int a[10][10][10], int **b) +{ + int c[10][10][10]; + #pragma omp task depend(out: a[2:4][3:][:7], b[1:7][2:8]) + bar (a); + int i = 1, j = 3, k = 2, l = 6; + #pragma omp task depend(in: a[++i:++j][++k:][:++l]) + bar (a); + #pragma omp task depend(out: a[7:2][:][:], c[5:2][:][:]) + { + bar (c); + bar (a); + } +} diff --git a/gcc/testsuite/c-c++-common/gomp/map-1.c b/gcc/testsuite/c-c++-common/gomp/map-1.c new file mode 100644 index 0000000000000..0fda207bc0702 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/map-1.c @@ -0,0 +1,103 @@ +/* { dg-do compile { target c++ } } */ +/* { dg-options "-fopenmp" } */ + +extern int a[][10], a2[][10]; +int b[10], c[10][2], d[10], e[10], f[10]; +int b2[10], c2[10][2], d2[10], e2[10], f2[10]; +int k[10], l[10], m[10], n[10], o; +int *p; +int **q; +int r[4][4][4][4][4]; +int t[10]; +#pragma omp threadprivate (t) +#pragma omp declare target +void bar (int *); +#pragma omp end declare target + +void +foo (int g[3][10], int h[4][8], int i[2][10], int j[][9], + int g2[3][10], int h2[4][8], int i2[2][10], int j2[][9]) +{ + #pragma omp target map(to: bar[2:5]) /* { dg-error "is not a variable" } */ + ; + #pragma omp target map(from: t[2:5]) /* { dg-error "is threadprivate variable" } */ + ; + #pragma omp target map(tofrom: k[0.5:]) /* { dg-error "low bound \[^\n\r]* of array section does not have integral type" } */ + ; + #pragma omp target map(from: l[:7.5f]) /* { dg-error "length \[^\n\r]* of array section does not have integral type" } */ + ; + #pragma omp target map(to: m[p:]) /* { dg-error "low bound \[^\n\r]* of array section does not have integral type" } */ + ; + #pragma omp target map(tofrom: n[:p]) /* { dg-error "length \[^\n\r]* of array section does not have integral type" } */ + ; + #pragma omp target map(to: o[2:5]) /* { dg-error "does not have pointer or array type" } */ + ; + #pragma omp target map(to: a[:][:]) /* { dg-error "array type length expression is not optional" } */ + bar (&a[0][0]); + #pragma omp target map(tofrom: b[-1:]) /* { dg-error "negative low bound in array section" } */ + bar (b); + #pragma omp target map(tofrom: c[:-3][:]) /* { dg-error "negative length in array section" } */ + bar (&c[0][0]); + #pragma omp target map(from: d[11:]) /* { dg-error "low bound \[^\n\r]* above array section size" } */ + bar (d); + #pragma omp target map(to: e[:11]) /* { dg-error "length \[^\n\r]* above array section size" } */ + bar (e); + #pragma omp target map(to: f[1:10]) /* { dg-error "high bound \[^\n\r]* above array section size" } */ + bar (f); + #pragma omp target map(from: g[:][0:10]) /* { dg-error "for pointer type length expression is not optional" } */ + bar (&g[0][0]); + #pragma omp target map(from: h[2:1][-1:]) /* { dg-error "negative low bound in array section" } */ + bar (&h[0][0]); + #pragma omp target map(tofrom: h[:1][:-3]) /* { dg-error "negative length in array section" } */ + bar (&h[0][0]); + #pragma omp target map(i[:1][11:]) /* { dg-error "low bound \[^\n\r]* above array section size" } */ + bar (&i[0][0]); + #pragma omp target map(from: j[3:1][:10]) /* { dg-error "length \[^\n\r]* above array section size" } */ + bar (&j[0][0]); + #pragma omp target map(to: j[30:1][5:5]) /* { dg-error "high bound \[^\n\r]* above array section size" } */ + bar (&j[0][0]); + #pragma omp target map(to: a2[:1][2:4]) + bar (&a2[0][0]); + #pragma omp target map(a2[3:5][:]) + bar (&a2[0][0]); + #pragma omp target map(to: a2[3:5][:10]) + bar (&a2[0][0]); + #pragma omp target map(tofrom: b2[0:]) + bar (b2); + #pragma omp target map(tofrom: c2[:3][:]) + bar (&c2[0][0]); + #pragma omp target map(from: d2[9:]) + bar (d2); + #pragma omp target map(to: e2[:10]) + bar (e2); + #pragma omp target map(to: f2[1:9]) + bar (f2); + #pragma omp target map(g2[:1][2:4]) + bar (&g2[0][0]); + #pragma omp target map(from: h2[2:2][0:]) + bar (&h2[0][0]); + #pragma omp target map(tofrom: h2[:1][:3]) + bar (&h2[0][0]); + #pragma omp target map(to: i2[:1][9:]) + bar (&i2[0][0]); + #pragma omp target map(from: j2[3:4][:9]) + bar (&j2[0][0]); + #pragma omp target map(to: j2[30:1][5:4]) + bar (&j2[0][0]); + #pragma omp target map(q[1:2]) + ; + #pragma omp target map(tofrom: q[3:5][:10]) /* { dg-error "array section is not contiguous" } */ + ; + #pragma omp target map(r[3:][2:1][1:2]) + ; + #pragma omp target map(r[3:][2:1][1:2][:][0:4]) + ; + #pragma omp target map(r[3:][2:1][1:2][1:][0:4]) /* { dg-error "array section is not contiguous" } */ + ; + #pragma omp target map(r[3:][2:1][1:2][:3][0:4]) /* { dg-error "array section is not contiguous" } */ + ; + #pragma omp target map(r[3:][2:1][1:2][:][1:]) /* { dg-error "array section is not contiguous" } */ + ; + #pragma omp target map(r[3:][2:1][1:2][:][:3]) /* { dg-error "array section is not contiguous" } */ + ; +} diff --git a/gcc/testsuite/g++.dg/gomp/depend-1.C b/gcc/testsuite/g++.dg/gomp/depend-1.C new file mode 100644 index 0000000000000..2084546db70ac --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/depend-1.C @@ -0,0 +1,70 @@ +// { dg-do compile } +// { dg-options "-fopenmp" } + +extern int a[][10], a2[][10]; +int b[10], c[10][2], d[10], e[10], f[10]; +int b2[10], c2[10][2], d2[10], e2[10], f2[10]; +int k[10], l[10], m[10], n[10], o; +int *p; +void bar (void); +int t[10]; +#pragma omp threadprivate (t) + +template +void +foo (int g[3][10], int h[4][8], int i[2][10], int j[][9], + int g2[3][10], int h2[4][8], int i2[2][10], int j2[][9]) +{ + #pragma omp task depend(out: t[2:5]) + ; + #pragma omp task depend(inout: k[0.5:]) // { dg-error "low bound \[^\n\r]* of array section does not have integral type" } + ; + #pragma omp task depend(in: l[:7.5f]) // { dg-error "length \[^\n\r]* of array section does not have integral type" } + ; + #pragma omp task depend(out: m[p:]) // { dg-error "low bound \[^\n\r]* of array section does not have integral type" } + ; + #pragma omp task depend(inout: n[:p]) // { dg-error "length \[^\n\r]* of array section does not have integral type" } + ; + #pragma omp task depend(in: o[2:5]) // { dg-error "does not have pointer or array type" } + ; + #pragma omp task depend(out: a[:][2:4]) // { dg-error "array type length expression is not optional" } + ; + #pragma omp task depend(in: d[11:]) // { dg-error "low bound \[^\n\r]* above array section size" } + ; + #pragma omp task depend(out: e[:11]) // { dg-error "length \[^\n\r]* above array section size" } + ; + #pragma omp task depend(out: f[1:10]) // { dg-error "high bound \[^\n\r]* above array section size" } + ; + #pragma omp task depend(in: g[:][2:4]) // { dg-error "for pointer type length expression is not optional" } + ; + #pragma omp task depend(out: i[:1][11:]) // { dg-error "low bound \[^\n\r]* above array section size" } + ; + #pragma omp task depend(in: j[3:4][:10]) // { dg-error "length \[^\n\r]* above array section size" } + ; + #pragma omp task depend(out: j[30:10][5:5]) // { dg-error "high bound \[^\n\r]* above array section size" } + ; + #pragma omp task depend(out: a2[:3][2:4]) + ; + #pragma omp task depend(inout: b2[0:]) + ; + #pragma omp task depend(inout: c2[:3][1:1]) + ; + #pragma omp task depend(in: d2[9:]) + ; + #pragma omp task depend(out: e2[:10]) + ; + #pragma omp task depend(out: f2[1:9]) + ; + #pragma omp task depend(in: g2[:2][2:4]) + ; + #pragma omp task depend(in: h2[2:2][0:]) + ; + #pragma omp task depend(inout: h2[:1][:3]) + ; + #pragma omp task depend(out: i2[:1][9:]) + ; + #pragma omp task depend(in: j2[3:4][:9]) + ; + #pragma omp task depend(out: j2[30:10][5:4]) + ; +} diff --git a/gcc/testsuite/g++.dg/gomp/depend-2.C b/gcc/testsuite/g++.dg/gomp/depend-2.C new file mode 100644 index 0000000000000..eb3f05c20053f --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/depend-2.C @@ -0,0 +1,87 @@ +// { dg-do compile } +// { dg-options "-fopenmp" } + +extern int a[][10], a2[][10]; +int b[10], c[10][2], d[10], e[10], f[10]; +int b2[10], c2[10][2], d2[10], e2[10], f2[10]; +int k[10], l[10], m[10], n[10], o; +int *p; +void bar (void); +int t[10]; +#pragma omp threadprivate (t) + +template +void +foo (int g[3][10], int h[4][8], int i[2][10], int j[][9], + int g2[3][10], int h2[4][8], int i2[2][10], int j2[][9]) +{ + #pragma omp task depend(in: bar[2:5]) // { dg-error "is not a variable" } + ; + #pragma omp task depend(out: t[2:5]) + ; + #pragma omp task depend(inout: k[0.5:]) // { dg-error "low bound \[^\n\r]* of array section does not have integral type" } + ; + #pragma omp task depend(in: l[:7.5f]) // { dg-error "length \[^\n\r]* of array section does not have integral type" } + ; + #pragma omp task depend(out: m[p:]) // { dg-error "low bound \[^\n\r]* of array section does not have integral type" } + ; + #pragma omp task depend(inout: n[:p]) // { dg-error "length \[^\n\r]* of array section does not have integral type" } + ; + #pragma omp task depend(in: o[2:5]) // { dg-error "does not have pointer or array type" } + ; + #pragma omp task depend(out: a[:][2:4]) // { dg-error "array type length expression is not optional" } + ; + #pragma omp task depend(inout: b[-1:]) // { dg-error "negative low bound in array section" } + ; + #pragma omp task depend(inout: c[:-3][1:1]) // { dg-error "negative length in array section" } + ; + #pragma omp task depend(in: d[11:]) // { dg-error "low bound \[^\n\r]* above array section size" } + ; + #pragma omp task depend(out: e[:11]) // { dg-error "length \[^\n\r]* above array section size" } + ; + #pragma omp task depend(out: f[1:10]) // { dg-error "high bound \[^\n\r]* above array section size" } + ; + #pragma omp task depend(in: g[:][2:4]) // { dg-error "for pointer type length expression is not optional" } + ; + #pragma omp task depend(in: h[2:2][-1:]) // { dg-error "negative low bound in array section" } + ; + #pragma omp task depend(inout: h[:1][:-3]) // { dg-error "negative length in array section" } + ; + #pragma omp task depend(out: i[:1][11:]) // { dg-error "low bound \[^\n\r]* above array section size" } + ; + #pragma omp task depend(in: j[3:4][:10]) // { dg-error "length \[^\n\r]* above array section size" } + ; + #pragma omp task depend(out: j[30:10][5:5]) // { dg-error "high bound \[^\n\r]* above array section size" } + ; + #pragma omp task depend(out: a2[:3][2:4]) + ; + #pragma omp task depend(inout: b2[0:]) + ; + #pragma omp task depend(inout: c2[:3][1:1]) + ; + #pragma omp task depend(in: d2[9:]) + ; + #pragma omp task depend(out: e2[:10]) + ; + #pragma omp task depend(out: f2[1:9]) + ; + #pragma omp task depend(in: g2[:2][2:4]) + ; + #pragma omp task depend(in: h2[2:2][0:]) + ; + #pragma omp task depend(inout: h2[:1][:3]) + ; + #pragma omp task depend(out: i2[:1][9:]) + ; + #pragma omp task depend(in: j2[3:4][:9]) + ; + #pragma omp task depend(out: j2[30:10][5:4]) + ; +} + +void +baz (int g[3][10], int h[4][8], int i[2][10], int j[][9], + int g2[3][10], int h2[4][8], int i2[2][10], int j2[][9]) +{ + foo<0> (g, h, i, j, g2, h2, i2, j2); +} diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c index ace9e22ebd17f..c42ea336d377e 100644 --- a/gcc/tree-pretty-print.c +++ b/gcc/tree-pretty-print.c @@ -314,12 +314,6 @@ dump_omp_clause (pretty_printer *buffer, tree clause, int spc, int flags) case OMP_CLAUSE_COPYPRIVATE: name = "copyprivate"; goto print_remap; - case OMP_CLAUSE_FROM: - name = "from"; - goto print_remap; - case OMP_CLAUSE_TO: - name = "to"; - goto print_remap; case OMP_CLAUSE_UNIFORM: name = "uniform"; goto print_remap; @@ -488,6 +482,7 @@ dump_omp_clause (pretty_printer *buffer, tree clause, int spc, int flags) switch (OMP_CLAUSE_MAP_KIND (clause)) { case OMP_CLAUSE_MAP_ALLOC: + case OMP_CLAUSE_MAP_POINTER: pp_string (buffer, "alloc"); break; case OMP_CLAUSE_MAP_TO: @@ -505,9 +500,32 @@ dump_omp_clause (pretty_printer *buffer, tree clause, int spc, int flags) pp_character (buffer, ':'); dump_generic_node (buffer, OMP_CLAUSE_DECL (clause), spc, flags, false); + print_clause_size: + if (OMP_CLAUSE_SIZE (clause)) + { + if (OMP_CLAUSE_MAP_KIND (clause) == OMP_CLAUSE_MAP_POINTER) + pp_string (buffer, " [pointer assign, bias: "); + else + pp_string (buffer, " [len: "); + dump_generic_node (buffer, OMP_CLAUSE_SIZE (clause), + spc, flags, false); + pp_character (buffer, ']'); + } pp_character (buffer, ')'); break; + case OMP_CLAUSE_FROM: + pp_string (buffer, "from("); + dump_generic_node (buffer, OMP_CLAUSE_DECL (clause), + spc, flags, false); + goto print_clause_size; + + case OMP_CLAUSE_TO: + pp_string (buffer, "to("); + dump_generic_node (buffer, OMP_CLAUSE_DECL (clause), + spc, flags, false); + goto print_clause_size; + case OMP_CLAUSE_NUM_TEAMS: pp_string (buffer, "num_teams("); dump_generic_node (buffer, OMP_CLAUSE_NUM_TEAMS_EXPR (clause), diff --git a/gcc/tree.c b/gcc/tree.c index a899c6a164ab6..d8b5aac4d8e1a 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -238,10 +238,10 @@ unsigned const char omp_clause_num_ops[] = 2, /* OMP_CLAUSE_LINEAR */ 2, /* OMP_CLAUSE_ALIGNED */ 1, /* OMP_CLAUSE_DEPEND */ - 1, /* OMP_CLAUSE_FROM */ - 1, /* OMP_CLAUSE_TO */ 1, /* OMP_CLAUSE_UNIFORM */ - 1, /* OMP_CLAUSE_MAP */ + 2, /* OMP_CLAUSE_FROM */ + 2, /* OMP_CLAUSE_TO */ + 2, /* OMP_CLAUSE_MAP */ 1, /* OMP_CLAUSE_IF */ 1, /* OMP_CLAUSE_NUM_THREADS */ 1, /* OMP_CLAUSE_SCHEDULE */ @@ -279,9 +279,9 @@ const char * const omp_clause_code_name[] = "linear", "aligned", "depend", + "uniform", "from", "to", - "uniform", "map", "if", "num_threads", @@ -11011,11 +11011,8 @@ walk_tree_1 (tree *tp, walk_tree_fn func, void *data, case OMP_CLAUSE_IF: case OMP_CLAUSE_NUM_THREADS: case OMP_CLAUSE_SCHEDULE: - case OMP_CLAUSE_FROM: - case OMP_CLAUSE_TO: case OMP_CLAUSE_UNIFORM: case OMP_CLAUSE_DEPEND: - case OMP_CLAUSE_MAP: case OMP_CLAUSE_NUM_TEAMS: case OMP_CLAUSE_DEVICE: case OMP_CLAUSE_DIST_SCHEDULE: @@ -11053,6 +11050,9 @@ walk_tree_1 (tree *tp, walk_tree_fn func, void *data, case OMP_CLAUSE_ALIGNED: case OMP_CLAUSE_LINEAR: + case OMP_CLAUSE_FROM: + case OMP_CLAUSE_TO: + case OMP_CLAUSE_MAP: WALK_SUBTREE (OMP_CLAUSE_DECL (*tp)); WALK_SUBTREE (OMP_CLAUSE_OPERAND (*tp, 1)); WALK_SUBTREE_TAIL (OMP_CLAUSE_CHAIN (*tp)); diff --git a/gcc/tree.h b/gcc/tree.h index f2a58a09e0d7c..fb36e74f7a63e 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -374,15 +374,15 @@ enum omp_clause_code /* OpenMP clause: depend ({in,out,inout}:variable-list). */ OMP_CLAUSE_DEPEND, + /* OpenMP clause: uniform (argument-list). */ + OMP_CLAUSE_UNIFORM, + /* OpenMP clause: from (variable-list). */ OMP_CLAUSE_FROM, /* OpenMP clause: to (variable-list). */ OMP_CLAUSE_TO, - /* OpenMP clause: uniform (argument-list). */ - OMP_CLAUSE_UNIFORM, - /* OpenMP clause: map ({alloc:,to:,from:,tofrom:,}variable-list). */ OMP_CLAUSE_MAP, @@ -1877,6 +1877,11 @@ extern void protected_set_expr_location (tree, location_t); #define OMP_TARGET_UPDATE_CLAUSES(NODE)\ TREE_OPERAND (OMP_TARGET_UPDATE_CHECK (NODE), 0) +#define OMP_CLAUSE_SIZE(NODE) \ + OMP_CLAUSE_OPERAND (OMP_CLAUSE_RANGE_CHECK (OMP_CLAUSE_CHECK (NODE), \ + OMP_CLAUSE_FROM, \ + OMP_CLAUSE_MAP), 1) + #define OMP_CLAUSE_CHAIN(NODE) TREE_CHAIN (OMP_CLAUSE_CHECK (NODE)) #define OMP_CLAUSE_DECL(NODE) \ OMP_CLAUSE_OPERAND (OMP_CLAUSE_RANGE_CHECK (OMP_CLAUSE_CHECK (NODE), \ @@ -2025,7 +2030,11 @@ enum omp_clause_map_kind OMP_CLAUSE_MAP_ALLOC, OMP_CLAUSE_MAP_TO, OMP_CLAUSE_MAP_FROM, - OMP_CLAUSE_MAP_TOFROM + OMP_CLAUSE_MAP_TOFROM, + /* This following is an internal only map kind, used for pointer based array + sections. OMP_CLAUSE_SIZE for these is not the pointer size, which is + implicitly POINTER_SIZE / BITS_PER_UNIT, but the bias. */ + OMP_CLAUSE_MAP_POINTER }; #define OMP_CLAUSE_MAP_KIND(NODE) \ From 0496be315aab51f93029e2d79fd630321991f7ba Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Wed, 5 Jun 2013 13:50:55 -0500 Subject: [PATCH 40/63] Initial implementation of <#pragma simd> for the C++ front-end. Test summary on x86-64 Linux: (make check-g++ RUNTESTFLAGS="cilk-plus.exp) === g++ Summary === Distinct failures are: c-c++-common/cilk-plus/PS/body.c c-c++-common/cilk-plus/PS/for1.c c-c++-common/cilk-plus/PS/for2.c c-c++-common/cilk-plus/PS/for3.c --- gcc/ChangeLog.cilkplus | 5 +- gcc/c-family/c-cilkplus.c | 15 +- gcc/c-family/c-common.h | 6 + gcc/c/c-tree.h | 5 - gcc/c/c-typeck.c | 4 +- gcc/cp/ChangeLog.cilkplus | 18 + gcc/cp/Make-lang.in | 4 +- gcc/cp/cp-cilkplus.c | 83 +++ gcc/cp/cp-tree.h | 3 + gcc/cp/parser.c | 670 ++++++++++++++++++ gcc/cp/parser.h | 1 + .../c-c++-common/cilk-plus/PS/body.c | 10 +- .../c-c++-common/cilk-plus/PS/clauses1.c | 14 +- .../c-c++-common/cilk-plus/PS/clauses2.c | 6 +- .../c-c++-common/cilk-plus/PS/clauses3.c | 14 +- .../c-c++-common/cilk-plus/PS/for1.c | 45 +- .../c-c++-common/cilk-plus/PS/for2.c | 2 +- .../c-c++-common/cilk-plus/PS/for3.c | 2 +- .../c-c++-common/cilk-plus/PS/safelen.c | 5 +- .../c-c++-common/cilk-plus/PS/vectorlength.c | 7 +- gcc/testsuite/g++.dg/cilk-plus/cilk-plus.exp | 30 + gcc/testsuite/g++.dg/cilk-plus/for.C | 12 + gcc/testsuite/g++.dg/dg.exp | 1 + gcc/testsuite/gcc.dg/cilk-plus/auto.c | 17 + gcc/testsuite/gcc.dg/cilk-plus/cilk-plus.exp | 11 +- gcc/testsuite/gcc.dg/cilk-plus/for1.c | 12 + 26 files changed, 922 insertions(+), 80 deletions(-) create mode 100644 gcc/cp/ChangeLog.cilkplus create mode 100644 gcc/cp/cp-cilkplus.c create mode 100644 gcc/testsuite/g++.dg/cilk-plus/cilk-plus.exp create mode 100644 gcc/testsuite/g++.dg/cilk-plus/for.C create mode 100644 gcc/testsuite/gcc.dg/cilk-plus/auto.c create mode 100644 gcc/testsuite/gcc.dg/cilk-plus/for1.c diff --git a/gcc/ChangeLog.cilkplus b/gcc/ChangeLog.cilkplus index 5e9fb7935d9aa..96a02c64e2288 100644 --- a/gcc/ChangeLog.cilkplus +++ b/gcc/ChangeLog.cilkplus @@ -1,4 +1,5 @@ 2013-05-13 Aldy Hernandez + Balaji V. Iyer * Makefile.in (C_COMMON_OBJS): Depend on c-family/c-cilkplus.o. (c-cilkplus.o): New dependency. @@ -9,6 +10,8 @@ c-family/ * c-pragma.h (enum pragma_kind): Add PRAGMA_CILK_SIMD enum. (enum pragma_cilk_clause): New. * c.opt (fcilkplus): New flag. + * c-common.h (c_finish_cilk_simd_loop): Protoize. + (c_finish_cilk_clauses): Same. c/ * c-parser.c (c_parser_pragma): Add case for PRAGMA_CILK_SIMD. @@ -19,8 +22,6 @@ c/ (c_parser_cilk_all_clauses): New. (c_parser_cilk_for_statement): New. (c_parser_cilk_simd_construct): New. - * c-tree.h (c_finish_cilk_simd_loop): Protoize. - (c_finish_cilk_clauses): Same. * c-typeck.c (c_finish_bc_stmt): Add case for _Cilk_for loops. testsuite/ diff --git a/gcc/c-family/c-cilkplus.c b/gcc/c-family/c-cilkplus.c index 40284fea0a4e4..84f164546084e 100644 --- a/gcc/c-family/c-cilkplus.c +++ b/gcc/c-family/c-cilkplus.c @@ -104,27 +104,22 @@ c_check_cilk_loop_incr (location_t loc, tree decl, tree incr) return error_mark_node; } -/* Callback for walk_tree. +/* Callback for walk_tree to validate the body of a pragma simd loop + or _cilk_for loop. This function is passed in as a function pointer to walk_tree. *TP is the current tree pointer, *WALK_SUBTREES is set to 0 by this function if recursing into TP's subtrees is unnecessary. *DATA is a bool variable that is set to false if an error has occured. */ -static tree -find_invalid_stmts_in_loops (tree *tp, int *walk_subtrees, void *data) +tree +c_validate_cilk_plus_loop (tree *tp, int *walk_subtrees, void *data) { if (!tp || !*tp) return NULL_TREE; bool *valid = (bool *) data; - // FIXME: Disallow the following constructs within a SIMD loop: - // - // _Cilk_spawn - // _Cilk_for - // try - /* FIXME: Jumps are disallowed into or out of the body of a _Cilk_for. We can't just check for GOTO_EXPR here, since GOTO_EXPR's can also be generated by switches and loops. @@ -205,7 +200,7 @@ static bool c_check_cilk_loop_body (tree body) { bool valid = true; - walk_tree (&body, find_invalid_stmts_in_loops, (void *) &valid, NULL); + walk_tree (&body, c_validate_cilk_plus_loop, (void *) &valid, NULL); return valid; } diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index 78ace779cb266..f0a488ec32915 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -1046,6 +1046,12 @@ extern tree c_omp_declare_simd_clauses_to_numbers (tree, tree); extern void c_omp_declare_simd_clauses_to_decls (tree, tree); extern enum omp_clause_default_kind c_omp_predetermined_sharing (tree); +/* In c-cilkplus.c */ +extern tree c_finish_cilk_simd_loop (location_t, tree, tree, tree, tree, + tree, tree); +extern tree c_finish_cilk_clauses (tree); +extern tree c_validate_cilk_plus_loop (tree *, int *, void *); + /* Not in c-omp.c; provided by the front end. */ extern bool c_omp_sharing_predetermined (tree); extern tree c_omp_remap_decl (tree, bool); diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index 84471db707e4f..93516dabd6628 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -647,11 +647,6 @@ extern tree c_build_va_arg (location_t, tree, tree); extern tree c_finish_transaction (location_t, tree, int); extern bool c_tree_equal (tree, tree); -/* In c-cilkplus.c */ -extern tree c_finish_cilk_simd_loop (location_t, tree, tree, tree, tree, - tree, tree); -extern tree c_finish_cilk_clauses (tree); - /* Set to 0 at beginning of a function definition, set to 1 if a return statement that specifies a return value is seen. */ diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index ea4ec3d86b538..fb7ffc57a814c 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -9095,9 +9095,9 @@ c_finish_bc_stmt (location_t loc, tree *label_p, bool is_break) case 2: if (is_break) - error ("break statement within _Cilk_for loop"); + error ("break statement within <#pragma simd> loop body"); else - error ("continue statement within _Cilk_for loop"); + error ("continue statement within <#pragma simd> loop loop"); return NULL_TREE; default: diff --git a/gcc/cp/ChangeLog.cilkplus b/gcc/cp/ChangeLog.cilkplus new file mode 100644 index 0000000000000..7254b815e01ad --- /dev/null +++ b/gcc/cp/ChangeLog.cilkplus @@ -0,0 +1,18 @@ +2013-05-21 Balaji V. Iyer + + * cp-tree.h (p_simd_valid_stmts_in_body_p): New prototype. + * parser.h (IN_CILK_P_SIMD_FOR): New #define. + * Make-lang.in (CXX_AND_OBJCXX_OBJS): Added new obj-file cp-cilkplus.o + * cp-cilkplus.c: New file. + * parser.c (cp_parser_pragma): Added a PRAGMA_CILK_SIMD case. + (cp_parser_cilk_simd_vectorlength): New function. + (cp_parser_cilk_simd_linear): Likewise. + (cp_parser_cilk_simd_clause_name): Likewise. + (cp_parser_cilk_simd_all_clauses): Likewise. + (cp_parser_cilk_simd_construct): Likewise. + (cp_parser_simd_for_init_statement): Likewise. + (cp_parser_cilk_for_expression_iterator): Likewise. + (cp_parser_cilk_for_condition): Likewise. + (cp_parser_cilk_for): Likewise. + (cp_parser_jump_statement): Added a IN_CILK_P_SIMD_FOR case. + diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in index df8ed3ee0d9de..0e4024621d854 100644 --- a/gcc/cp/Make-lang.in +++ b/gcc/cp/Make-lang.in @@ -80,7 +80,7 @@ CXX_AND_OBJCXX_OBJS = cp/call.o cp/decl.o cp/expr.o cp/pt.o cp/typeck2.o \ cp/typeck.o cp/cvt.o cp/except.o cp/friend.o cp/init.o cp/method.o \ cp/search.o cp/semantics.o cp/tree.o cp/repo.o cp/dump.o cp/optimize.o \ cp/mangle.o cp/cp-objcp-common.o cp/name-lookup.o cp/cxx-pretty-print.o \ - cp/cp-gimplify.o $(CXX_C_OBJS) + cp/cp-gimplify.o cp/cp-cilkplus.o $(CXX_C_OBJS) # Language-specific object files for C++. CXX_OBJS = cp/cp-lang.o c-family/stub-objc.o $(CXX_AND_OBJCXX_OBJS) @@ -345,3 +345,5 @@ cp/name-lookup.o: cp/name-lookup.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ cp/cxx-pretty-print.o: cp/cxx-pretty-print.c $(CXX_PRETTY_PRINT_H) \ $(CONFIG_H) $(SYSTEM_H) $(TM_H) coretypes.h $(CXX_TREE_H) tree-pretty-print.h +cp/cp-cilkplus.o: cp/cp-cilkplus.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ + $(CXX_TREE_H) $(DIAGNOSTIC_CORE_H) diff --git a/gcc/cp/cp-cilkplus.c b/gcc/cp/cp-cilkplus.c new file mode 100644 index 0000000000000..7bed9400c55c5 --- /dev/null +++ b/gcc/cp/cp-cilkplus.c @@ -0,0 +1,83 @@ +/* This file is part of the Intel(R) Cilk(TM) Plus support + This file contains routines to handle Cilk Plus specific + routines for the C++ Compiler. + Copyright (C) 2013 Free Software Foundation, Inc. + Contributed by Balaji V. Iyer , + Aldy Hernandez . + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + GCC is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING3. If not see + . */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "cp-tree.h" +#include "diagnostic-core.h" + + +/* Callback for cp_walk_tree to validate the body of a pragma simd loop + or _cilk_for loop. + + This function is passed in as a function pointer to walk_tree. *TP is + the current tree pointer, *WALK_SUBTREES is set to 0 by this function if + recursing into TP's subtrees is unnecessary. *DATA is a bool variable that + is set to false if an error has occured. */ + +static tree +cpp_validate_cilk_plus_loop_aux (tree *tp, int *walk_subtrees, void *data) +{ + bool *valid = (bool *) data; + location_t loc = EXPR_HAS_LOCATION (*tp) ? EXPR_LOCATION (*tp) : + UNKNOWN_LOCATION; + + if (!tp || !*tp) + return NULL_TREE; + + // Call generic C version. + (void) c_validate_cilk_plus_loop (tp, walk_subtrees, data); + + if (TREE_CODE (*tp) == THROW_EXPR) + { + error_at (loc, "throw expressions are not allowed inside loops " + "marked with pragma simd"); + *walk_subtrees = 0; + *valid = false; + } + else if (TREE_CODE (*tp) == TRY_BLOCK) + { + error_at (loc, "try statements are not allowed inside loops marked " + "with #pragma simd"); + *valid = false; + *walk_subtrees = 0; + } + /* FIXME: Add a check for TREE_CODE (*tp) == CILK_FOR_STMT and flag them as + invalid when cilk keywords are adopted. */ + return NULL_TREE; +} + + +/* Walks through all the subtrees of BODY using walk_tree to make sure invalid + statements/expressions are not found inside BODY. Returns false if any + invalid statements are found. */ + +bool +cpp_validate_cilk_plus_loop (tree body) +{ + bool valid = true; + cp_walk_tree (&body, cpp_validate_cilk_plus_loop_aux, + (void *) &valid, NULL); + return valid; +} diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 7046713200384..97e4e3cfde4f3 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6144,6 +6144,9 @@ extern bool cxx_omp_privatize_by_reference (const_tree); extern void suggest_alternatives_for (location_t, tree); extern tree strip_using_decl (tree); +/* in cp-cilkplus.c */ +extern bool cpp_validate_cilk_plus_loop (tree); + /* -- end of C++ */ #endif /* ! GCC_CP_TREE_H */ diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index a30f52ac4ce11..7de2e79d5a36d 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -231,6 +231,12 @@ static void cp_parser_initial_pragma static tree cp_literal_operator_id (const char *); +static void cp_parser_cilk_simd_construct + (cp_parser *, cp_token *); +static tree cp_parser_cilk_for + (cp_parser *, enum rid, tree); + + /* Manifest constants. */ #define CP_LEXER_BUFFER_SIZE ((256 * 1024) / sizeof (cp_token)) #define CP_SAVED_TOKEN_STACK 5 @@ -10297,6 +10303,10 @@ cp_parser_jump_statement (cp_parser* parser) case IN_OMP_FOR: error_at (token->location, "break statement used with OpenMP for loop"); break; + case IN_CILK_P_SIMD_FOR: + error_at (token->location, + "break statement within <#pragma simd> loop body"); + break; } cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON); break; @@ -10314,6 +10324,10 @@ cp_parser_jump_statement (cp_parser* parser) case IN_OMP_BLOCK: error_at (token->location, "invalid exit from OpenMP structured block"); break; + case IN_CILK_P_SIMD_FOR: + error_at (token->location, + "continue statement within <#pragma simd> loop loop"); + break; default: gcc_unreachable (); } @@ -29851,6 +29865,12 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context) "%<#pragma omp sections%> construct"); break; + case PRAGMA_CILK_SIMD: + if (context == pragma_external) + goto bad_stmt; + cp_parser_cilk_simd_construct (parser, pragma_tok); + return true; + default: gcc_assert (id >= PRAGMA_FIRST_EXTERNAL); c_invoke_pragma_handler (id); @@ -29916,4 +29936,654 @@ c_parse_file (void) the_parser = NULL; } + +/* Parses the Cilk Plus #pragma simd vectorlength clause: + Syntax: + vectorlength ( constant-expression ) */ + +static tree +cp_parser_cilk_simd_vectorlength (cp_parser *parser, tree clauses) +{ + location_t loc = cp_lexer_peek_token (parser->lexer)->location; + tree expr; + /* The vectorlength clause behaves exactly like OpenMP's safelen + clause. Thus, vectorlength is represented as OMP 4.0 + safelen. */ + check_no_duplicate_clause (clauses, OMP_CLAUSE_SAFELEN, "vectorlength", loc); + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + return error_mark_node; + + expr = cp_parser_constant_expression (parser, false, NULL); + expr = maybe_constant_value (expr); + + if (TREE_CONSTANT (expr) + && exact_log2 (TREE_INT_CST_LOW (expr)) == -1) + error_at (loc, "vectorlength must be a power of 2"); + else if (expr != error_mark_node) + { + tree c = build_omp_clause (loc, OMP_CLAUSE_SAFELEN); + OMP_CLAUSE_SAFELEN_EXPR (c) = expr; + OMP_CLAUSE_CHAIN (c) = clauses; + clauses = c; + } + + if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + return error_mark_node; + return clauses; +} + +/* Handles the Cilk Plus #pragma simd linear clause. + Syntax: + linear ( simd-linear-variable-list ) + + simd-linear-variable-list: + simd-linear-variable + simd-linear-variable-list , simd-linear-variable + + simd-linear-variable: + id-expression + id-expression : simd-linear-step + + simd-linear-step: + conditional-expression */ + +static tree +cp_parser_cilk_simd_linear (cp_parser *parser, tree clauses) +{ + location_t loc = cp_lexer_peek_token (parser->lexer)->location; + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + return clauses; + if (cp_lexer_next_token_is_not (parser->lexer, CPP_NAME)) + { + cp_parser_error (parser, "expected identifier"); + cp_parser_skip_to_closing_parenthesis (parser, false, false, true); + return error_mark_node; + } + + while (1) + { + cp_token *token = cp_lexer_peek_token (parser->lexer); + if (cp_lexer_next_token_is_not (parser->lexer, CPP_NAME)) + { + cp_parser_error (parser, "expected variable-name"); + clauses = error_mark_node; + break; + } + + tree var_name = cp_parser_id_expression (parser, false, true, NULL, + false, false); + tree decl = cp_parser_lookup_name_simple (parser, var_name, + token->location); + if (decl == error_mark_node) + { + cp_parser_name_lookup_error (parser, var_name, decl, NLE_NULL, + token->location); + clauses = error_mark_node; + } + else + { + tree e = NULL_TREE; + tree step_size = integer_one_node; + + /* If present, parse the linear step. Otherwise, assume the default + value of 1. */ + if (cp_lexer_peek_token (parser->lexer)->type == CPP_COLON) + { + cp_lexer_consume_token (parser->lexer); + + e = cp_parser_constant_expression (parser, false, NULL); + e = maybe_constant_value (e); + + if (e == error_mark_node) + { + /* If an error has occurred, then the whole pragma is + considered ill-formed. Thus, no reason to keep + parsing. */ + clauses = error_mark_node; + break; + } + else if (!TREE_TYPE (e) || !TREE_CONSTANT (e) + || !INTEGRAL_TYPE_P (TREE_TYPE (e))) + cp_parser_error (parser, + "step size must be an integer constant"); + else + step_size = e; + } + + /* Use the OMP_CLAUSE_LINEAR, which has the same semantics. */ + tree l = build_omp_clause (loc, OMP_CLAUSE_LINEAR); + OMP_CLAUSE_DECL (l) = decl; + OMP_CLAUSE_LINEAR_STEP (l) = step_size; + OMP_CLAUSE_CHAIN (l) = clauses; + clauses = l; + } + if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) + cp_lexer_consume_token (parser->lexer); + else if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN)) + break; + else + { + error_at (cp_lexer_peek_token (parser->lexer)->location, + "expected %<,%> or %<)%> after %qE", decl); + clauses = error_mark_node; + break; + } + } + cp_parser_skip_to_closing_parenthesis (parser, false, false, true); + return clauses; +} + +/* Returns the name of the next clause. If the clause is not + recognized, then PRAGMA_CILK_CLAUSE_NONE is returned and the next + token is not consumed. Otherwise, the appropriate enum from the + pragma_simd_clause is returned and the token is consumed. */ + +static pragma_cilk_clause +cp_parser_cilk_simd_clause_name (cp_parser *parser) +{ + pragma_cilk_clause clause_type; + cp_token *token = cp_lexer_peek_token (parser->lexer); + + if (token->keyword == RID_PRIVATE) + clause_type = PRAGMA_CILK_CLAUSE_PRIVATE; + else if (!token->u.value || token->type != CPP_NAME) + return PRAGMA_CILK_CLAUSE_NONE; + else if (!strcmp (IDENTIFIER_POINTER (token->u.value), "vectorlength")) + clause_type = PRAGMA_CILK_CLAUSE_VECTORLENGTH; + else if (!strcmp (IDENTIFIER_POINTER (token->u.value), "linear")) + clause_type = PRAGMA_CILK_CLAUSE_LINEAR; + else if (!strcmp (IDENTIFIER_POINTER (token->u.value), "firstprivate")) + clause_type = PRAGMA_CILK_CLAUSE_FIRSTPRIVATE; + else if (!strcmp (IDENTIFIER_POINTER (token->u.value), "lastprivate")) + clause_type = PRAGMA_CILK_CLAUSE_LASTPRIVATE; + else if (!strcmp (IDENTIFIER_POINTER (token->u.value), "reduction")) + clause_type = PRAGMA_CILK_CLAUSE_REDUCTION; + else + return PRAGMA_CILK_CLAUSE_NONE; + + cp_lexer_consume_token (parser->lexer); + return clause_type; +} + +/* Parses all the #pragma simd clauses. Returns a list of clauses found. */ + +static tree +cp_parser_cilk_simd_all_clauses (cp_parser *parser, cp_token *pragma_token) +{ + tree clauses = NULL_TREE; + + while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL) + && clauses != error_mark_node) + { + pragma_cilk_clause c_kind; + c_kind = cp_parser_cilk_simd_clause_name (parser); + if (c_kind == PRAGMA_CILK_CLAUSE_VECTORLENGTH) + clauses = cp_parser_cilk_simd_vectorlength (parser, clauses); + else if (c_kind == PRAGMA_CILK_CLAUSE_LINEAR) + clauses = cp_parser_cilk_simd_linear (parser, clauses); + else if (c_kind == PRAGMA_CILK_CLAUSE_PRIVATE) + /* Use the OpenMP 4.0 equivalent function. */ + clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_PRIVATE, clauses); + else if (c_kind == PRAGMA_CILK_CLAUSE_FIRSTPRIVATE) + /* Use the OpenMP 4.0 equivalent function. */ + clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_FIRSTPRIVATE, + clauses); + else if (c_kind == PRAGMA_CILK_CLAUSE_LASTPRIVATE) + /* Use the OMP 4.0 equivalent function. */ + clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_LASTPRIVATE, + clauses); + else if (c_kind == PRAGMA_CILK_CLAUSE_REDUCTION) + /* Use the OMP 4.0 equivalent function. */ + clauses = cp_parser_omp_clause_reduction (parser, clauses); + else + { + clauses = error_mark_node; + cp_parser_error (parser, "expected %<#pragma simd%> clause"); + break; + } + } + + cp_parser_skip_to_pragma_eol (parser, pragma_token); + + if (clauses == error_mark_node) + return error_mark_node; + else + return c_finish_cilk_clauses (clauses); +} + +/* Main entry-point for parsing Cilk Plus <#pragma simd> for loops. */ + +static void +cp_parser_cilk_simd_construct (cp_parser *parser, cp_token *pragma_token) +{ + tree clauses = cp_parser_cilk_simd_all_clauses (parser, pragma_token); + + if (clauses == error_mark_node) + return; + + if (cp_lexer_next_token_is_not_keyword (parser->lexer, RID_FOR)) + { + error_at (cp_lexer_peek_token (parser->lexer)->location, + "expected for-statement after %<#pragma simd%> clauses"); + return; + } + + /* #pragma simd is built on top of OpenMP 4.0's OMP_SIMD trees. */ + if (!flag_openmp) + flag_openmp = true; + + tree sb = begin_omp_structured_block (); + int save = cp_parser_begin_omp_structured_block (parser); + cp_parser_cilk_for (parser, RID_FOR, clauses); + cp_parser_end_omp_structured_block (parser, save); + add_stmt (finish_omp_structured_block (sb)); + return; +} + +/* Parses the initializer of a for/_Cilk_for statement. The initial value is + stored in *INIT, and the inital value's declaration is stored as DECL_EXPR + in *PRE_BODY. */ + +static tree +cp_parser_simd_for_init_statement (cp_parser *parser, tree *init, + tree *pre_body) +{ + cp_token *token = cp_lexer_peek_token (parser->lexer); + location_t loc = cp_lexer_peek_token (parser->lexer)->location; + tree decl = NULL_TREE; + cp_decl_specifier_seq type_specifiers; + tree this_pre_body = push_stmt_list (); + if (token->type == CPP_SEMICOLON) + { + error_at (loc, "for-loop initializer must declare variable"); + return error_mark_node; + } + cp_parser_parse_tentatively (parser); + cp_parser_type_specifier_seq (parser, true, false, &type_specifiers); + if (cp_parser_parse_definitely (parser)) + { + cp_declarator *cp_decl; + tree asm_spec, attr; + cp_decl = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED, NULL, + NULL, false); + attr = cp_parser_attributes_opt (parser); + asm_spec = cp_parser_asm_specification_opt (parser); + if (cp_decl == cp_error_declarator) + cp_parser_skip_to_end_of_statement (parser); + else + { + tree pushed_scope, auto_node; + decl = start_decl (cp_decl, &type_specifiers, SD_INITIALIZED, attr, + NULL_TREE, &pushed_scope); + auto_node = type_uses_auto (TREE_TYPE (decl)); + if (cp_lexer_next_token_is_not (parser->lexer, CPP_EQ)) + { + if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)) + error_at (loc, "parenthesized initialization is not allowed in" + " for-loop"); + else + { + if (!cp_parser_require (parser, CPP_EQ, RT_EQ)) + decl = error_mark_node; + } + + *init = error_mark_node; + cp_parser_skip_to_end_of_statement (parser); + } + else if (CLASS_TYPE_P (TREE_TYPE (decl)) || auto_node + || type_dependent_expression_p (decl)) + { + bool is_direct_init, is_non_constant_init; + *init = cp_parser_initializer (parser, &is_direct_init, + &is_non_constant_init); + if (auto_node) + { + TREE_TYPE (decl) = do_auto_deduction (TREE_TYPE (decl), *init, + auto_node); + if (!CLASS_TYPE_P (TREE_TYPE (decl)) + && !type_dependent_expression_p (decl)) + goto non_class; + } + cp_finish_decl (decl, *init, !is_non_constant_init, asm_spec, + LOOKUP_ONLYCONVERTING); + if (CLASS_TYPE_P (TREE_TYPE (decl))) + *init = NULL_TREE; + else + *init = pop_stmt_list (this_pre_body); + this_pre_body = NULL_TREE; + } + else + { + /* Consume the '='. */ + cp_lexer_consume_token (parser->lexer); + *init = cp_parser_assignment_expression (parser, false, NULL); + non_class: + if (TREE_CODE (TREE_TYPE (decl)) == REFERENCE_TYPE) + *init = error_mark_node; + else + cp_finish_decl (decl, NULL_TREE, false, asm_spec, + LOOKUP_ONLYCONVERTING); + if (decl != error_mark_node) + DECL_INITIAL (decl) = (*init || *init != error_mark_node) ? + *init : NULL_TREE; + } + if (pushed_scope) + pop_scope (pushed_scope); + } + } + else + { + cp_id_kind idk; + cp_parser_parse_tentatively (parser); + decl = cp_parser_primary_expression (parser, false, false, false, &idk); + if (!cp_parser_error_occurred (parser) && decl && DECL_P (decl) + && CLASS_TYPE_P (TREE_TYPE (decl))) + { + tree rhs, new_expr; + cp_parser_parse_definitely (parser); + cp_parser_require (parser, CPP_EQ, RT_EQ); + rhs = cp_parser_assignment_expression (parser, false, NULL); + new_expr = build_x_modify_expr (EXPR_LOCATION (rhs), decl, NOP_EXPR, + rhs, tf_warning_or_error); + finish_expr_stmt (new_expr); + } + else + { + decl = NULL_TREE; + cp_parser_abort_tentative_parse (parser); + *init = cp_parser_expression (parser, false, NULL); + } + } + + if (this_pre_body) + this_pre_body = pop_stmt_list (this_pre_body); + + *pre_body = this_pre_body; + return decl; +} + + +/* Parses the increment expresion for a cilk_for or for statement with + #pragma simd. */ + +static tree +cp_parser_cilk_for_expression_iterator (cp_parser *parser) +{ + cp_token *token = cp_lexer_peek_token (parser->lexer); + tree name = NULL_TREE, expr = NULL_TREE; + enum tree_code t_code = NOP_EXPR; + + if (token->type == CPP_SEMICOLON) + { + error_at (token->location, "missing loop expression"); + return error_mark_node; + } + if (token->type == CPP_PLUS_PLUS || token->type == CPP_MINUS_MINUS) + { + cp_lexer_consume_token (parser->lexer); + token = cp_lexer_peek_token (parser->lexer); + t_code = token->type == CPP_PLUS_PLUS ? PREINCREMENT_EXPR + : PREDECREMENT_EXPR; + } + + if (token->type != CPP_NAME) + { + error_at (token->location, "invalid loop expression"); + cp_parser_skip_to_end_of_statement (parser); + return error_mark_node; + } + + name = cp_parser_lookup_name (parser, token->u.value, none_type, false, false, + false, NULL, token->location); + if (name == error_mark_node) + return error_mark_node; + + /* If name is not a declaration, then the loop is not valid. */ + if (!DECL_P (name)) + { + error_at (token->location, "invalid loop increment expression"); + return error_mark_node; + } + cp_lexer_consume_token (parser->lexer); + token = cp_lexer_peek_token (parser->lexer); + + if (t_code != NOP_EXPR) + { + if (token->type != CPP_CLOSE_PAREN) + { + error_at (token->location, "invalid loop expression"); + return error_mark_node; + } + return build2 (t_code, void_type_node, name, NULL_TREE); + } + + if (token->type == CPP_CLOSE_PAREN) + { + error_at (token->location, + "loop expression must modify control variable"); + return error_mark_node; + } + + cp_lexer_consume_token (parser->lexer); + if (token->type == CPP_PLUS_PLUS || token->type == CPP_MINUS_MINUS) + return build2 (token->type == CPP_PLUS_PLUS ? POSTINCREMENT_EXPR + : POSTDECREMENT_EXPR, void_type_node, name, NULL_TREE); + else if (token->type == CPP_EQ) + { + sorry ("loop with = operator"); + return error_mark_node; + } + else if (token->type == CPP_PLUS_EQ || token->type == CPP_MINUS_EQ) + t_code = token->type == CPP_PLUS_EQ ? PLUS_EXPR : MINUS_EXPR; + else if (token->type == CPP_MOD_EQ || token->type == CPP_XOR_EQ + || token->type == CPP_DIV_EQ || token->type == CPP_AND_EQ + || token->type == CPP_OR_EQ || token->type == CPP_AND_EQ + || token->type == CPP_LSHIFT_EQ || token->type == CPP_RSHIFT_EQ) + { + error_at (token->location, "invalid loop increment operation"); + return error_mark_node; + } + else + { + error_at (token->location, "invalid loop expression"); + return error_mark_node; + } + expr = cp_parser_binary_expression (parser, false, false, PREC_NOT_OPERATOR, + NULL); + if (expr == error_mark_node) + return expr; + + return build2 (MODIFY_EXPR, void_type_node, name, + build2 (t_code, TREE_TYPE (name), name, expr)); +} + +/* Parses the condition for a for-loop with pragma simd or _Cilk_for loop. */ + +static tree +cp_parser_cilk_for_condition (cp_parser *parser) +{ + tree lhs, rhs; + enum tree_code code = ERROR_MARK; + + lhs = cp_parser_binary_expression (parser, false, false, + PREC_SHIFT_EXPRESSION, NULL); + switch (cp_lexer_peek_token (parser->lexer)->type) + { + case CPP_NOT_EQ: + code = NE_EXPR; + break; + case CPP_LESS: + code = LT_EXPR; + break; + case CPP_LESS_EQ: + code = LE_EXPR; + break; + case CPP_GREATER_EQ: + code = GE_EXPR; + break; + case CPP_GREATER: + code = GT_EXPR; + break; + case CPP_EQ_EQ: + error_at (cp_lexer_peek_token (parser->lexer)->location, + "equality test not permitted in the Cilk_for loop"); + break; + default: + error_at (cp_lexer_peek_token (parser->lexer)->location, + "missing comparison operator in the loop condition"); + } + cp_lexer_consume_token (parser->lexer); + + rhs = cp_parser_binary_expression (parser, false, false, + PREC_SHIFT_EXPRESSION, NULL); + parser->scope = NULL_TREE; + parser->qualifying_scope = NULL_TREE; + parser->object_scope = NULL_TREE; + + if (code == ERROR_MARK || lhs == error_mark_node || rhs == error_mark_node) + return error_mark_node; + + return build2 (code, boolean_type_node, lhs, rhs); +} + +/* Top-level function to parse _Cilk_for and for statements. */ + +static tree +cp_parser_cilk_for (cp_parser *parser, enum rid for_keyword, tree clauses) +{ + bool valid = true; + tree cond = NULL_TREE; + tree incr_expr = NULL_TREE; + tree init = NULL_TREE, pre_body = NULL_TREE, decl; + location_t loc = cp_lexer_peek_token (parser->lexer)->location; + + /* FIXME: Allow CILK_FOR into this function. That is, use this function to + parse _Cilk_for statments also. To do this correctly, add another param. + called "grain" to hold the grainsize. */ + + gcc_assert (for_keyword == RID_FOR); + + if (!cp_lexer_next_token_is_keyword (parser->lexer, for_keyword)) + { + if (for_keyword == RID_FOR) + cp_parser_error (parser, "for statement expected"); + else + cp_parser_error (parser, "_Cilk_for statement expected"); + return error_mark_node; + } + cp_lexer_consume_token (parser->lexer); + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + { + cp_parser_skip_to_end_of_statement (parser); + return error_mark_node; + } + + if (for_keyword == RID_FOR) + decl = cp_parser_simd_for_init_statement (parser, &init, &pre_body); + + if (decl == error_mark_node) + valid = false; + else if (!decl || (TREE_CODE (decl) != VAR_DECL + && TREE_CODE (decl) != DECL_EXPR)) + { + error_at (loc, "%s-loop initializer does not declare a variable", + for_keyword == RID_FOR ? "for" : "_Cilk_for"); + valid = false; + decl = error_mark_node; + } + else if (!processing_template_decl + && !DECL_NONTRIVIALLY_INITIALIZED_P (decl) + && !DECL_INITIAL (decl) + && !TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))) + { + error_at (loc, "control variable for the %s-loop needs to be initialized", + for_keyword == RID_FOR ? "for" : "_Cilk_for"); + valid = false; + } + if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) + { + error_at (loc, "%s-loop initializer cannot have multiple variable " + "declarations", for_keyword == RID_FOR ? "for" : "_Cilk_for"); + cp_parser_skip_to_end_of_statement (parser); + valid = false; + } + + if (!cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON)) + return error_mark_node; + if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)) + { + error_at (loc, "%s-loop requires a condition", + for_keyword == RID_FOR ? "for" : "_Cilk_for"); + cond = error_mark_node; + } + else + cond = cp_parser_cilk_for_condition (parser); + + if (cond == error_mark_node) + valid = false; + cp_parser_consume_semicolon_at_end_of_statement (parser); + + if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN)) + { + error_at (loc, "%s-loop requires an increment expression", + for_keyword == RID_FOR ? "for" : "_Cilk_for"); + incr_expr = error_mark_node; + } + else + incr_expr = cp_parser_cilk_for_expression_iterator (parser); + + if (incr_expr == error_mark_node) + { + cp_parser_skip_to_closing_parenthesis (parser, true, false, false); + valid = false; + } + + if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + { + cp_parser_skip_to_end_of_statement (parser); + valid = false; + } + + if (!valid) + { + gcc_assert (sorrycount || errorcount); + return error_mark_node; + } + + if (for_keyword == RID_FOR) + { + tree initv, incrv, condv, declv, omp_simd_node, body = NULL_TREE; + + parser->in_statement = IN_CILK_P_SIMD_FOR; + body = push_stmt_list (); + cp_parser_statement (parser, NULL_TREE, false, NULL); + body = pop_stmt_list (body); + + /* Check if the body satisfies all the requirement of a #pragma + simd for body. If it is invalid, then do not make the OpenMP + nodes, just return an error mark node. */ + if (!cpp_validate_cilk_plus_loop (body)) + return error_mark_node; + + /* Now pass all the information into finish_omp_for. */ + initv = make_tree_vec (1); + condv = make_tree_vec (1); + incrv = make_tree_vec (1); + declv = make_tree_vec (1); + TREE_VEC_ELT (initv, 0) = init; + TREE_VEC_ELT (condv, 0) = cond; + TREE_VEC_ELT (incrv, 0) = incr_expr; + TREE_VEC_ELT (declv, 0) = decl; + omp_simd_node = finish_omp_for (loc, OMP_SIMD, declv, initv, condv, incrv, + body, pre_body, clauses); + return omp_simd_node; + } + else + /* Fix this when _Cilk_for is added into the mix. */ + return NULL_TREE; +} + #include "gt-cp-parser.h" diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h index 6d9f1fb8dd6fa..48ec8ddafa11c 100644 --- a/gcc/cp/parser.h +++ b/gcc/cp/parser.h @@ -292,6 +292,7 @@ typedef struct GTY(()) cp_parser { #define IN_OMP_BLOCK 4 #define IN_OMP_FOR 8 #define IN_IF_STMT 16 +#define IN_CILK_P_SIMD_FOR 32 unsigned char in_statement; /* TRUE if we are presently parsing the body of a switch statement. diff --git a/gcc/testsuite/c-c++-common/cilk-plus/PS/body.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/body.c index 4f7430a441127..5ecefd5bea279 100644 --- a/gcc/testsuite/c-c++-common/cilk-plus/PS/body.c +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/body.c @@ -1,15 +1,15 @@ /* { dg-do compile } */ -/* { dg-options "-O3 -fopenmp" } */ +/* { dg-options "-fcilkplus -fopenmp" } */ int *a, *b, c; void *jmpbuf[10]; void foo() { - int i, j; + int j; #pragma simd - for (i=0; i < 1000; ++i) + for (int i=0; i < 1000; ++i) { if (c == 5) return; /* { dg-error "return statments are not allowed" } */ @@ -19,14 +19,14 @@ void foo() } #pragma simd - for (i=0; i < 1000; ++i) + for (int i=0; i < 1000; ++i) { if (c==5) break; /* { dg-error "break statement within" } */ } #pragma simd - for (i=0; i < 1000; ++i) + for (int i=0; i < 1000; ++i) { #pragma omp for /* { dg-error "OpenMP statements are not allowed" } */ for (j=0; j < 1000; ++j) diff --git a/gcc/testsuite/c-c++-common/cilk-plus/PS/clauses1.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/clauses1.c index c7295a829e195..6d84791c60585 100644 --- a/gcc/testsuite/c-c++-common/cilk-plus/PS/clauses1.c +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/clauses1.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O3 -std=c99 -Werror -Wunknown-pragmas" } */ +/* { dg-options "-O3 -Werror -Wunknown-pragmas -fcilkplus" } */ volatile int *a, *b; @@ -27,7 +27,7 @@ void foo() for (int i=0; i < 1000; ++i) a[i] = b[j]; -#pragma simd vectorlength(i) /* { dg-error "vectorlength must be an integer" } */ +#pragma simd vectorlength(i) /* { dg-error "\(vectorlength must be an integer\|in a constant\)" } */ for (int i=0; i < 1000; ++i) a[i] = b[j]; @@ -35,11 +35,11 @@ void foo() for (int i=0; i < 1000; ++i) a[i] = b[j]; -#pragma simd linear(blah) /* { dg-error "'blah' undeclared" } */ +#pragma simd linear(blah) /* { dg-error "'blah' \(undeclared\|has not been\)" } */ for (int i=0; i < 1000; ++i) a[i] = b[j]; -#pragma simd linear(j, 36, k) /* { dg-error "expected '\\)'" } */ +#pragma simd linear(j, 36, k) /* { dg-error "expected" } */ for (int i=0; i < 1000; ++i) a[i] = b[j]; @@ -65,12 +65,12 @@ void foo() // And now everyone in unison! #pragma simd linear(j : 4) vectorlength(4) - for (i=0; i < 1000; ++i) + for (int i=0; i < 1000; ++i) a[i] = b[j]; #pragma simd linear(blah2, 36) - /* { dg-error "'blah2' undeclared" "undeclared" { target *-*-* } 71 } */ - /* { dg-error "expected '\\)'" "expected" { target *-*-* } 71 } */ + /* { dg-error "'blah2' \(undeclared\|has not been\)" "undeclared" { target *-*-* } 71 } */ + /* { dg-error "expected" "expected" { target *-*-* } 71 } */ for (int i=0; i < 1000; ++i) a[i] = b[j]; } diff --git a/gcc/testsuite/c-c++-common/cilk-plus/PS/clauses2.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/clauses2.c index 1eb44f3f7e3a0..71589c2b1786f 100644 --- a/gcc/testsuite/c-c++-common/cilk-plus/PS/clauses2.c +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/clauses2.c @@ -1,14 +1,14 @@ /* { dg-do compile } */ -/* { dg-options "-O3 -std=c99 -fdump-tree-original" } */ +/* { dg-options "-O3 -fdump-tree-original -fcilkplus" } */ volatile int *a, *b; void foo() { - int i, j, k; + int j, k; #pragma simd linear(j : 4, k) vectorlength(4) - for (i=0; i < 1000; ++i) + for (int i=0; i < 1000; ++i) a[i] = b[j]; } diff --git a/gcc/testsuite/c-c++-common/cilk-plus/PS/clauses3.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/clauses3.c index 0f38e3cf77bf3..579b718a01c69 100644 --- a/gcc/testsuite/c-c++-common/cilk-plus/PS/clauses3.c +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/clauses3.c @@ -1,39 +1,37 @@ /* { dg-do compile } */ -/* { dg-options "-O3 -std=c99" } */ +/* { dg-options "-O3 -fcilkplus" } */ #define N 1000 int A[N], B[N], C[N]; int main (void) { - int ii = 0; - #pragma simd private (B) linear(B:1) /* { dg-error "more than one clause" } */ - for (ii = 0; ii < N; ii++) + for (int ii = 0; ii < N; ii++) { A[ii] = B[ii] + C[ii]; } #pragma simd private (B, C) linear(B:1) /* { dg-error "more than one clause" } */ - for (ii = 0; ii < N; ii++) + for (int ii = 0; ii < N; ii++) { A[ii] = B[ii] + C[ii]; } #pragma simd private (B) linear(C:2, B:1) /* { dg-error "more than one clause" } */ - for (ii = 0; ii < N; ii++) + for (int ii = 0; ii < N; ii++) { A[ii] = B[ii] + C[ii]; } #pragma simd reduction (+:B) linear(B:1) /* { dg-error "more than one clause" } */ - for (ii = 0; ii < N; ii++) + for (int ii = 0; ii < N; ii++) { A[ii] = B[ii] + C[ii]; } #pragma simd reduction (+:B) linear(B) /* { dg-error "more than one clause" } */ - for (ii = 0; ii < N; ii++) + for (int ii = 0; ii < N; ii++) { A[ii] = B[ii] + C[ii]; } diff --git a/gcc/testsuite/c-c++-common/cilk-plus/PS/for1.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/for1.c index c2e99fd9da796..04773d127556d 100644 --- a/gcc/testsuite/c-c++-common/cilk-plus/PS/for1.c +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/for1.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O3 -std=c99" } */ +/* { dg-options "-O3 -fcilkplus" } */ int *a, *b, *c; int something; @@ -8,11 +8,6 @@ void foo() { int i, j; - // The initialization shall declare or initialize a *SINGLE* variable. -#pragma simd - for (i=0, j=5; i < 1000; i++) // { dg-error "expected ';' before ','" } - a[i] = b[j]; - // Declaration and initialization is allowed. #pragma simd for (int i=0; i < 1000; i++) @@ -25,12 +20,12 @@ void foo() // Empty condition is not allowed. #pragma simd - for (i=0; ; ++i) /* { dg-error "missing condition" } */ + for (int i=0; ; ++i) /* { dg-error "missing condition" } */ a[i] = i; // Empty increment is not allowed. #pragma simd - for (i=0; i < 1234; ) /* { dg-error "missing increment" } */ + for (int i=0; i < 1234; ) /* { dg-error "missing increment" } */ a[i] = i*2; #pragma simd @@ -55,83 +50,83 @@ void foo() // Condition of '==' is not allowed. #pragma simd - for (i=j; i == 5; ++i) /* { dg-error "invalid controlling predicate" } */ + for (int i=j; i == 5; ++i) /* { dg-error "invalid controlling predicate" } */ a[i] = b[i]; // The LHS or RHS of the condition must be the initialization variable. #pragma simd - for (i=0; i+j < 1234; ++i) /* { dg-error "invalid controlling predicate" } */ + for (int i=0; i+j < 1234; ++i) /* { dg-error "invalid controlling predicate" } */ a[i] = b[i]; // Likewise. #pragma simd - for (i=0; 1234 < i + j; ++i) /* { dg-error "invalid controlling predicate" } */ + for (int i=0; 1234 < i + j; ++i) /* { dg-error "invalid controlling predicate" } */ a[i] = b[i]; // Likewise, this is ok. #pragma simd - for (i=0; 1234 + j < i; ++i) + for (int i=0; 1234 + j < i; ++i) a[i] = b[i]; // According to the CilkPlus forum, casts are not allowed, even if // they are no-ops. #pragma simd - for (i=0; (char)i < 1234; ++i) /* { dg-error "invalid controlling predicate" } */ + for (int i=0; (char)i < 1234; ++i) /* { dg-error "invalid controlling predicate" } */ a[i] = b[i]; #pragma simd - for (i=255; i != something; --i) + for (int i=255; i != something; --i) a[i] = b[i]; // This condition gets folded into "i != 0" by // c_parser_cilk_for_statement(). This is allowed as per the "!=" // allowance above. #pragma simd - for (i=100; i; --i) + for (int i=100; i; --i) a[i] = b[i]; #pragma simd - for (i=100; i != 5; i += something) + for (int i=100; i != 5; i += something) a[i] = b[i]; // Increment must be on the induction variable. #pragma simd - for (i=0; i < 100; j++) /* { dg-error "invalid increment expression" } */ + for (int i=0; i < 100; j++) /* { dg-error "invalid increment expression" } */ a[i] = b[i]; // Likewise. #pragma simd - for (i=0; i < 100; j = i + 1) /* { dg-error "invalid increment expression" } */ + for (int i=0; i < 100; j = i + 1) /* { dg-error "invalid increment expression" } */ a[i] = b[i]; // Likewise. #pragma simd - for (i=0; i < 100; i = j + 1) /* { dg-error "invalid increment expression" } */ + for (int i=0; i < 100; i = j + 1) /* { dg-error "invalid increment expression" } */ a[i] = b[i]; #pragma simd - for (i=0; i < 100; i = i + 5) + for (int i=0; i < 100; i = i + 5) a[i] = b[i]; // Only PLUS and MINUS increments are allowed. #pragma simd - for (i=0; i < 100; i *= 5) /* { dg-error "invalid increment expression" } */ + for (int i=0; i < 100; i *= 5) /* { dg-error "invalid increment expression" } */ a[i] = b[i]; #pragma simd - for (i=0; i < 100; i -= j) + for (int i=0; i < 100; i -= j) a[i] = b[i]; #pragma simd - for (i=0; i < 100; i = i + j) + for (int i=0; i < 100; i = i + j) a[i] = b[i]; #pragma simd - for (i=0; i < 100; i = j + i) + for (int i=0; i < 100; i = j + i) a[i] = b[i]; #pragma simd - for (i=0; i < 100; ++i, ++j) /* { dg-error "invalid increment expression" } */ + for (int i=0; i < 100; ++i, ++j) /* { dg-error "invalid increment expression" } */ a[i] = b[i]; #pragma simd diff --git a/gcc/testsuite/c-c++-common/cilk-plus/PS/for2.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/for2.c index f9a5083e3facc..dc0a41e4be5c3 100644 --- a/gcc/testsuite/c-c++-common/cilk-plus/PS/for2.c +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/for2.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O3 -std=c99" } */ +/* { dg-options "-O3 -fcilkplus" } */ // Test storage classes in the initialization of a <#pragma simd> for // loop. diff --git a/gcc/testsuite/c-c++-common/cilk-plus/PS/for3.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/for3.c index 084790d53e495..86606275ac471 100644 --- a/gcc/testsuite/c-c++-common/cilk-plus/PS/for3.c +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/for3.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O3" } */ +/* { dg-options "-O3 -fcilkplus" } */ #pragma simd /* { dg-error "must be inside a function" } */ diff --git a/gcc/testsuite/c-c++-common/cilk-plus/PS/safelen.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/safelen.c index eefd9aa346b85..2c59de9b02d92 100644 --- a/gcc/testsuite/c-c++-common/cilk-plus/PS/safelen.c +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/safelen.c @@ -1,13 +1,12 @@ /* { dg-do compile } */ -/* { dg-options "-O3 -fdump-tree-gimple" } */ +/* { dg-options "-O3 -fdump-tree-gimple -fcilkplus" } */ int *a, *b; void foo() { - int i; #pragma simd vectorlength(8) - for (i=0; i < 1000; ++i) + for (int i=0; i < 1000; ++i) a[i] = b[i]; } diff --git a/gcc/testsuite/c-c++-common/cilk-plus/PS/vectorlength.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/vectorlength.c index 4c6a98b8cbbb3..9aa4a68290d56 100644 --- a/gcc/testsuite/c-c++-common/cilk-plus/PS/vectorlength.c +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/vectorlength.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O3" } */ +/* { dg-options "-O3 -fcilkplus" } */ volatile int *a, *b, N; typedef int tint; @@ -11,12 +11,11 @@ struct someclass { void foo() { - int i; #pragma simd vectorlength(4) vectorlength(8) /* { dg-error "too many 'vectorlength' clauses" } */ - for (i=0; i < N; ++i) + for (int i=0; i < N; ++i) a[i] = b[i]; #pragma simd vectorlength(3) /* { dg-error "must be a power of 2" } */ - for (i=0; i < N; ++i) + for (int i=0; i < N; ++i) a[i] = b[i]; } diff --git a/gcc/testsuite/g++.dg/cilk-plus/cilk-plus.exp b/gcc/testsuite/g++.dg/cilk-plus/cilk-plus.exp new file mode 100644 index 0000000000000..ab389035a6bfd --- /dev/null +++ b/gcc/testsuite/g++.dg/cilk-plus/cilk-plus.exp @@ -0,0 +1,30 @@ +# Copyright (C) 2013 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# . + +# Written by Balaji V. Iyer + +# Load support procs. +load_lib g++-dg.exp + +dg-init + +# Run the tests that are shared with C. +g++-dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/PS/*.c]] "" + +# Run the C++ only tests. +g++-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.C]] "" + +dg-finish diff --git a/gcc/testsuite/g++.dg/cilk-plus/for.C b/gcc/testsuite/g++.dg/cilk-plus/for.C new file mode 100644 index 0000000000000..2295d214620ab --- /dev/null +++ b/gcc/testsuite/g++.dg/cilk-plus/for.C @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "-ftree-vectorize -fcilkplus" } */ + +int *a, *b; + +void foo() +{ + int i; +#pragma simd + for (i=0; i < 10000; ++i) /* { dg-error "initializer does not declare a var" } */ + a[i] = b[i]; +} diff --git a/gcc/testsuite/g++.dg/dg.exp b/gcc/testsuite/g++.dg/dg.exp index 720135942bbf6..a3e9c1fb05920 100644 --- a/gcc/testsuite/g++.dg/dg.exp +++ b/gcc/testsuite/g++.dg/dg.exp @@ -48,6 +48,7 @@ set tests [prune $tests $srcdir/$subdir/tree-prof/*] set tests [prune $tests $srcdir/$subdir/torture/*] set tests [prune $tests $srcdir/$subdir/graphite/*] set tests [prune $tests $srcdir/$subdir/tm/*] +set tests [prune $tests $srcdir/$subdir/cilk-plus/*] set tests [prune $tests $srcdir/$subdir/guality/*] set tests [prune $tests $srcdir/$subdir/simulate-thread/*] set tests [prune $tests $srcdir/$subdir/asan/*] diff --git a/gcc/testsuite/gcc.dg/cilk-plus/auto.c b/gcc/testsuite/gcc.dg/cilk-plus/auto.c new file mode 100644 index 0000000000000..253acee1e0858 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cilk-plus/auto.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ + +int *a, *b; + +void foo() +{ + // This seems like it should be ok. + // Must check with standards people. +#pragma simd + for (auto int autoi = 0; autoi < 1000; ++autoi) + b[autoi] = a[autoi] * 2; + // Similarly here. + auto int autoj; +#pragma simd + for (auto int autoj = 0; autoj < 1000; ++autoj) + b[autoj] = a[autoj] * 2; +} diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-plus.exp b/gcc/testsuite/gcc.dg/cilk-plus/cilk-plus.exp index 060b3933ac00a..623c3b0ed1f55 100644 --- a/gcc/testsuite/gcc.dg/cilk-plus/cilk-plus.exp +++ b/gcc/testsuite/gcc.dg/cilk-plus/cilk-plus.exp @@ -20,6 +20,11 @@ load_lib gcc-dg.exp dg-init + +# Run the tests that are shared with C++. + +dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/PS/*.c]] " -ftree-vectorize -fcilkplus -std=c99" " " + dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -fcilkplus" " " dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -O0 -fcilkplus" " " dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -O1 -fcilkplus" " " @@ -43,8 +48,8 @@ dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -f dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -fcilkplus -g -O3 -std=c99" " " dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -O3 -ftree-vectorize -std=c99 -g -fcilkplus" " " -# pragma simd tests -# Run the tests that are shared with C++. -dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/PS/*.c]] " -ftree-vectorize -fcilkplus" " " +# Run the C-only tests. +dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.c]] \ + "-ftree-vectorize -fcilkplus -std=c99" " " dg-finish diff --git a/gcc/testsuite/gcc.dg/cilk-plus/for1.c b/gcc/testsuite/gcc.dg/cilk-plus/for1.c new file mode 100644 index 0000000000000..4fb534286d9a6 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cilk-plus/for1.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ + +int *a, *b, *c; + +void foo() +{ + int i, j; + // The initialization shall declare or initialize a *SINGLE* variable. +#pragma simd + for (i=0, j=5; i < 1000; i++) // { dg-error "expected ';' before ','" } + a[i] = b[j]; +} From de33368123a10bce1a07e1b3d480eec572c54716 Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Wed, 5 Jun 2013 14:11:05 -0500 Subject: [PATCH 41/63] Cosmetic fixes to C++ <#pragma simd>. --- gcc/cp/cp-cilkplus.c | 10 +++++----- gcc/cp/parser.c | 44 ++++++++++++++++++++++++-------------------- 2 files changed, 29 insertions(+), 25 deletions(-) diff --git a/gcc/cp/cp-cilkplus.c b/gcc/cp/cp-cilkplus.c index 7bed9400c55c5..f387e2fee12d7 100644 --- a/gcc/cp/cp-cilkplus.c +++ b/gcc/cp/cp-cilkplus.c @@ -63,15 +63,15 @@ cpp_validate_cilk_plus_loop_aux (tree *tp, int *walk_subtrees, void *data) *valid = false; *walk_subtrees = 0; } - /* FIXME: Add a check for TREE_CODE (*tp) == CILK_FOR_STMT and flag them as - invalid when cilk keywords are adopted. */ + /* FIXME: Add a check for TREE_CODE (*tp) == CILK_FOR_STMT and + flag them as invalid when cilk keywords are adopted. */ return NULL_TREE; } -/* Walks through all the subtrees of BODY using walk_tree to make sure invalid - statements/expressions are not found inside BODY. Returns false if any - invalid statements are found. */ +/* Walks through all the subtrees of BODY using walk_tree to make sure + invalid statements/expressions are not found inside BODY. Returns + false if any invalid statements are found. */ bool cpp_validate_cilk_plus_loop (tree body) diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 7de2e79d5a36d..b4c6ba37118d4 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -236,7 +236,6 @@ static void cp_parser_cilk_simd_construct static tree cp_parser_cilk_for (cp_parser *, enum rid, tree); - /* Manifest constants. */ #define CP_LEXER_BUFFER_SIZE ((256 * 1024) / sizeof (cp_token)) #define CP_SAVED_TOKEN_STACK 5 @@ -30182,9 +30181,9 @@ cp_parser_cilk_simd_construct (cp_parser *parser, cp_token *pragma_token) return; } -/* Parses the initializer of a for/_Cilk_for statement. The initial value is - stored in *INIT, and the inital value's declaration is stored as DECL_EXPR - in *PRE_BODY. */ +/* Parses the initializer of a for/_Cilk_for statement. The initial + value is stored in *INIT, and the inital value's declaration is + stored as DECL_EXPR in *PRE_BODY. */ static tree cp_parser_simd_for_init_statement (cp_parser *parser, tree *init, @@ -30206,8 +30205,8 @@ cp_parser_simd_for_init_statement (cp_parser *parser, tree *init, { cp_declarator *cp_decl; tree asm_spec, attr; - cp_decl = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED, NULL, - NULL, false); + cp_decl = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED, + NULL, NULL, false); attr = cp_parser_attributes_opt (parser); asm_spec = cp_parser_asm_specification_opt (parser); if (cp_decl == cp_error_declarator) @@ -30221,8 +30220,8 @@ cp_parser_simd_for_init_statement (cp_parser *parser, tree *init, if (cp_lexer_next_token_is_not (parser->lexer, CPP_EQ)) { if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)) - error_at (loc, "parenthesized initialization is not allowed in" - " for-loop"); + error_at (loc, "parenthesized initialization is " + "not allowed in for-loop"); else { if (!cp_parser_require (parser, CPP_EQ, RT_EQ)) @@ -30240,8 +30239,8 @@ cp_parser_simd_for_init_statement (cp_parser *parser, tree *init, &is_non_constant_init); if (auto_node) { - TREE_TYPE (decl) = do_auto_deduction (TREE_TYPE (decl), *init, - auto_node); + TREE_TYPE (decl) + = do_auto_deduction (TREE_TYPE (decl), *init, auto_node); if (!CLASS_TYPE_P (TREE_TYPE (decl)) && !type_dependent_expression_p (decl)) goto non_class; @@ -30277,7 +30276,8 @@ cp_parser_simd_for_init_statement (cp_parser *parser, tree *init, { cp_id_kind idk; cp_parser_parse_tentatively (parser); - decl = cp_parser_primary_expression (parser, false, false, false, &idk); + decl = cp_parser_primary_expression (parser, false, false, + false, &idk); if (!cp_parser_error_occurred (parser) && decl && DECL_P (decl) && CLASS_TYPE_P (TREE_TYPE (decl))) { @@ -30285,8 +30285,9 @@ cp_parser_simd_for_init_statement (cp_parser *parser, tree *init, cp_parser_parse_definitely (parser); cp_parser_require (parser, CPP_EQ, RT_EQ); rhs = cp_parser_assignment_expression (parser, false, NULL); - new_expr = build_x_modify_expr (EXPR_LOCATION (rhs), decl, NOP_EXPR, - rhs, tf_warning_or_error); + new_expr = build_x_modify_expr (EXPR_LOCATION (rhs), decl, + NOP_EXPR, rhs, + tf_warning_or_error); finish_expr_stmt (new_expr); } else @@ -30399,7 +30400,8 @@ cp_parser_cilk_for_expression_iterator (cp_parser *parser) build2 (t_code, TREE_TYPE (name), name, expr)); } -/* Parses the condition for a for-loop with pragma simd or _Cilk_for loop. */ +/* Parses the condition for a for-loop with pragma simd or _Cilk_for + loop. */ static tree cp_parser_cilk_for_condition (cp_parser *parser) @@ -30459,9 +30461,10 @@ cp_parser_cilk_for (cp_parser *parser, enum rid for_keyword, tree clauses) tree init = NULL_TREE, pre_body = NULL_TREE, decl; location_t loc = cp_lexer_peek_token (parser->lexer)->location; - /* FIXME: Allow CILK_FOR into this function. That is, use this function to - parse _Cilk_for statments also. To do this correctly, add another param. - called "grain" to hold the grainsize. */ + /* FIXME: Allow CILK_FOR into this function. That is, use this + function to parse _Cilk_for statments also. To do this + correctly, add another param. called "grain" to hold the + grainsize. */ gcc_assert (for_keyword == RID_FOR); @@ -30499,7 +30502,8 @@ cp_parser_cilk_for (cp_parser *parser, enum rid for_keyword, tree clauses) && !DECL_INITIAL (decl) && !TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))) { - error_at (loc, "control variable for the %s-loop needs to be initialized", + error_at (loc, "control variable for the %s-loop needs to " + "be initialized", for_keyword == RID_FOR ? "for" : "_Cilk_for"); valid = false; } @@ -30577,8 +30581,8 @@ cp_parser_cilk_for (cp_parser *parser, enum rid for_keyword, tree clauses) TREE_VEC_ELT (condv, 0) = cond; TREE_VEC_ELT (incrv, 0) = incr_expr; TREE_VEC_ELT (declv, 0) = decl; - omp_simd_node = finish_omp_for (loc, OMP_SIMD, declv, initv, condv, incrv, - body, pre_body, clauses); + omp_simd_node = finish_omp_for (loc, OMP_SIMD, declv, initv, condv, + incrv, body, pre_body, clauses); return omp_simd_node; } else From 51d8e99dd59ec4beb523101a35eedd21f2d439a4 Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Fri, 7 Jun 2013 12:06:12 -0500 Subject: [PATCH 42/63] Clean up C++ implementation of pragma simd to use shared C/C++ type checking. Change error messages to match C front-end when possible. Misc fixes. --- gcc/c-family/c-cilkplus.c | 21 +- gcc/cp/ChangeLog.cilkplus | 3 + gcc/cp/cp-cilkplus.c | 3 - gcc/cp/cp-tree.h | 1 + gcc/cp/parser.c | 198 +++--------------- gcc/cp/semantics.c | 7 + .../c-c++-common/cilk-plus/PS/for4.c | 14 ++ .../c-c++-common/cilk-plus/PS/for5.c | 11 + 8 files changed, 77 insertions(+), 181 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/cilk-plus/PS/for4.c create mode 100644 gcc/testsuite/c-c++-common/cilk-plus/PS/for5.c diff --git a/gcc/c-family/c-cilkplus.c b/gcc/c-family/c-cilkplus.c index 84f164546084e..c02851eba6d17 100644 --- a/gcc/c-family/c-cilkplus.c +++ b/gcc/c-family/c-cilkplus.c @@ -207,12 +207,16 @@ c_check_cilk_loop_body (tree body) /* Validate a _Cilk_for construct (or a #pragma simd for loop, which has the same syntactic restrictions). Returns TRUE if there were no errors, FALSE otherwise. LOC is the location of the for. DECL - is the controlling variable. COND is the condition. INCR is the - increment expression. BODY is the body of the LOOP. */ + is the controlling variable. COND is the condition. INCRP is a + pointer the increment expression (in case, the increment needs to + be canonicalized). BODY is the body of the LOOP. */ static bool -c_check_cilk_loop (location_t loc, tree decl, tree cond, tree incr, tree body) +c_check_cilk_loop (location_t loc, tree decl, tree cond, tree *incrp, + tree body) { + tree incr = *incrp; + if (decl == error_mark_node || cond == error_mark_node || incr == error_mark_node @@ -284,10 +288,11 @@ c_check_cilk_loop (location_t loc, tree decl, tree cond, tree incr, tree body) return false; } - /* Validate the increment. */ + /* Validate and canonicalize the increment. */ incr = c_check_cilk_loop_incr (loc, decl, incr); if (incr == error_mark_node) return false; + *incrp = incr; if (!c_check_cilk_loop_body (body)) return false; @@ -325,7 +330,7 @@ c_finish_cilk_simd_loop (location_t loc, { location_t rhs_loc; - if (!c_check_cilk_loop (loc, decl, cond, incr, body)) + if (!c_check_cilk_loop (loc, decl, cond, &incr, body)) return NULL; /* In the case of "for (int i = 0...)", init will be a decl. It should @@ -345,7 +350,11 @@ c_finish_cilk_simd_loop (location_t loc, init = build_modify_expr (loc, decl, NULL_TREE, NOP_EXPR, rhs_loc, init, NULL_TREE); } - gcc_assert (TREE_CODE (init) == MODIFY_EXPR); + + // The C++ parser just gives us the rhs. + if (TREE_CODE (init) != MODIFY_EXPR) + init = build2 (MODIFY_EXPR, void_type_node, decl, init); + gcc_assert (TREE_OPERAND (init, 0) == decl); tree initv = make_tree_vec (1); diff --git a/gcc/cp/ChangeLog.cilkplus b/gcc/cp/ChangeLog.cilkplus index 7254b815e01ad..e7f7596ea89df 100644 --- a/gcc/cp/ChangeLog.cilkplus +++ b/gcc/cp/ChangeLog.cilkplus @@ -1,9 +1,12 @@ 2013-05-21 Balaji V. Iyer + Aldy Hernandez * cp-tree.h (p_simd_valid_stmts_in_body_p): New prototype. + (finish_cilk_for_cond): Likewise. * parser.h (IN_CILK_P_SIMD_FOR): New #define. * Make-lang.in (CXX_AND_OBJCXX_OBJS): Added new obj-file cp-cilkplus.o * cp-cilkplus.c: New file. + * semantics.c (finish_cilk_for_cond): New. * parser.c (cp_parser_pragma): Added a PRAGMA_CILK_SIMD case. (cp_parser_cilk_simd_vectorlength): New function. (cp_parser_cilk_simd_linear): Likewise. diff --git a/gcc/cp/cp-cilkplus.c b/gcc/cp/cp-cilkplus.c index f387e2fee12d7..e6bdf8ab80a92 100644 --- a/gcc/cp/cp-cilkplus.c +++ b/gcc/cp/cp-cilkplus.c @@ -46,9 +46,6 @@ cpp_validate_cilk_plus_loop_aux (tree *tp, int *walk_subtrees, void *data) if (!tp || !*tp) return NULL_TREE; - // Call generic C version. - (void) c_validate_cilk_plus_loop (tp, walk_subtrees, data); - if (TREE_CODE (*tp) == THROW_EXPR) { error_at (loc, "throw expressions are not allowed inside loops " diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 97e4e3cfde4f3..ba088a5040584 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5790,6 +5790,7 @@ extern void finish_omp_taskyield (void); extern void finish_omp_taskgroup (tree); extern void finish_omp_cancel (tree); extern void finish_omp_cancellation_point (tree); +extern tree finish_cilk_for_cond (tree); extern tree begin_transaction_stmt (location_t, tree *, int); extern void finish_transaction_stmt (tree, tree, int, tree); extern tree build_transaction_expr (location_t, tree, int, tree); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 68a277bea906e..c93ea9eb6d8c6 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -29899,7 +29899,11 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context) case PRAGMA_CILK_SIMD: if (context == pragma_external) - goto bad_stmt; + { + error_at (pragma_tok->location, + "%<#pragma simd%> must be inside a function"); + break; + } cp_parser_cilk_simd_construct (parser, pragma_tok); return true; @@ -30198,7 +30202,7 @@ cp_parser_cilk_simd_construct (cp_parser *parser, cp_token *pragma_token) if (cp_lexer_next_token_is_not_keyword (parser->lexer, RID_FOR)) { error_at (cp_lexer_peek_token (parser->lexer)->location, - "expected for-statement after %<#pragma simd%> clauses"); + "for statement expected"); return; } @@ -30229,7 +30233,7 @@ cp_parser_simd_for_init_statement (cp_parser *parser, tree *init, tree this_pre_body = push_stmt_list (); if (token->type == CPP_SEMICOLON) { - error_at (loc, "for-loop initializer must declare variable"); + error_at (loc, "expected iteration declaration"); return error_mark_node; } cp_parser_parse_tentatively (parser); @@ -30315,6 +30319,9 @@ cp_parser_simd_for_init_statement (cp_parser *parser, tree *init, && CLASS_TYPE_P (TREE_TYPE (decl))) { tree rhs, new_expr; + // ?? FIXME: I don't see any definition for *init in this + // code path. ?? + gcc_unreachable (); cp_parser_parse_definitely (parser); cp_parser_require (parser, CPP_EQ, RT_EQ); rhs = cp_parser_assignment_expression (parser, false, NULL); @@ -30338,151 +30345,6 @@ cp_parser_simd_for_init_statement (cp_parser *parser, tree *init, return decl; } - -/* Parses the increment expresion for a cilk_for or for statement with - #pragma simd. */ - -static tree -cp_parser_cilk_for_expression_iterator (cp_parser *parser) -{ - cp_token *token = cp_lexer_peek_token (parser->lexer); - tree name = NULL_TREE, expr = NULL_TREE; - enum tree_code t_code = NOP_EXPR; - - if (token->type == CPP_SEMICOLON) - { - error_at (token->location, "missing loop expression"); - return error_mark_node; - } - if (token->type == CPP_PLUS_PLUS || token->type == CPP_MINUS_MINUS) - { - cp_lexer_consume_token (parser->lexer); - token = cp_lexer_peek_token (parser->lexer); - t_code = token->type == CPP_PLUS_PLUS ? PREINCREMENT_EXPR - : PREDECREMENT_EXPR; - } - - if (token->type != CPP_NAME) - { - error_at (token->location, "invalid loop expression"); - cp_parser_skip_to_end_of_statement (parser); - return error_mark_node; - } - - name = cp_parser_lookup_name (parser, token->u.value, none_type, false, false, - false, NULL, token->location); - if (name == error_mark_node) - return error_mark_node; - - /* If name is not a declaration, then the loop is not valid. */ - if (!DECL_P (name)) - { - error_at (token->location, "invalid loop increment expression"); - return error_mark_node; - } - cp_lexer_consume_token (parser->lexer); - token = cp_lexer_peek_token (parser->lexer); - - if (t_code != NOP_EXPR) - { - if (token->type != CPP_CLOSE_PAREN) - { - error_at (token->location, "invalid loop expression"); - return error_mark_node; - } - return build2 (t_code, void_type_node, name, NULL_TREE); - } - - if (token->type == CPP_CLOSE_PAREN) - { - error_at (token->location, - "loop expression must modify control variable"); - return error_mark_node; - } - - cp_lexer_consume_token (parser->lexer); - if (token->type == CPP_PLUS_PLUS || token->type == CPP_MINUS_MINUS) - return build2 (token->type == CPP_PLUS_PLUS ? POSTINCREMENT_EXPR - : POSTDECREMENT_EXPR, void_type_node, name, NULL_TREE); - else if (token->type == CPP_EQ) - { - sorry ("loop with = operator"); - return error_mark_node; - } - else if (token->type == CPP_PLUS_EQ || token->type == CPP_MINUS_EQ) - t_code = token->type == CPP_PLUS_EQ ? PLUS_EXPR : MINUS_EXPR; - else if (token->type == CPP_MOD_EQ || token->type == CPP_XOR_EQ - || token->type == CPP_DIV_EQ || token->type == CPP_AND_EQ - || token->type == CPP_OR_EQ || token->type == CPP_AND_EQ - || token->type == CPP_LSHIFT_EQ || token->type == CPP_RSHIFT_EQ) - { - error_at (token->location, "invalid loop increment operation"); - return error_mark_node; - } - else - { - error_at (token->location, "invalid loop expression"); - return error_mark_node; - } - expr = cp_parser_binary_expression (parser, false, false, PREC_NOT_OPERATOR, - NULL); - if (expr == error_mark_node) - return expr; - - return build2 (MODIFY_EXPR, void_type_node, name, - build2 (t_code, TREE_TYPE (name), name, expr)); -} - -/* Parses the condition for a for-loop with pragma simd or _Cilk_for - loop. */ - -static tree -cp_parser_cilk_for_condition (cp_parser *parser) -{ - tree lhs, rhs; - enum tree_code code = ERROR_MARK; - - lhs = cp_parser_binary_expression (parser, false, false, - PREC_SHIFT_EXPRESSION, NULL); - switch (cp_lexer_peek_token (parser->lexer)->type) - { - case CPP_NOT_EQ: - code = NE_EXPR; - break; - case CPP_LESS: - code = LT_EXPR; - break; - case CPP_LESS_EQ: - code = LE_EXPR; - break; - case CPP_GREATER_EQ: - code = GE_EXPR; - break; - case CPP_GREATER: - code = GT_EXPR; - break; - case CPP_EQ_EQ: - error_at (cp_lexer_peek_token (parser->lexer)->location, - "equality test not permitted in the Cilk_for loop"); - break; - default: - error_at (cp_lexer_peek_token (parser->lexer)->location, - "missing comparison operator in the loop condition"); - } - cp_lexer_consume_token (parser->lexer); - - rhs = cp_parser_binary_expression (parser, false, false, - PREC_SHIFT_EXPRESSION, NULL); - parser->scope = NULL_TREE; - parser->qualifying_scope = NULL_TREE; - parser->object_scope = NULL_TREE; - - if (code == ERROR_MARK || lhs == error_mark_node || rhs == error_mark_node) - return error_mark_node; - - return build2 (code, boolean_type_node, lhs, rhs); -} - /* Top-level function to parse _Cilk_for and for statements. */ static tree @@ -30552,12 +30414,14 @@ cp_parser_cilk_for (cp_parser *parser, enum rid for_keyword, tree clauses) return error_mark_node; if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)) { - error_at (loc, "%s-loop requires a condition", - for_keyword == RID_FOR ? "for" : "_Cilk_for"); + error_at (loc, "missing condition"); cond = error_mark_node; } else - cond = cp_parser_cilk_for_condition (parser); + { + cond = cp_parser_condition (parser); + cond = finish_cilk_for_cond (cond); + } if (cond == error_mark_node) valid = false; @@ -30565,12 +30429,11 @@ cp_parser_cilk_for (cp_parser *parser, enum rid for_keyword, tree clauses) if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN)) { - error_at (loc, "%s-loop requires an increment expression", - for_keyword == RID_FOR ? "for" : "_Cilk_for"); + error_at (loc, "missing increment"); incr_expr = error_mark_node; } else - incr_expr = cp_parser_cilk_for_expression_iterator (parser); + incr_expr = cp_parser_expression (parser, false, NULL); if (incr_expr == error_mark_node) { @@ -30592,10 +30455,8 @@ cp_parser_cilk_for (cp_parser *parser, enum rid for_keyword, tree clauses) if (for_keyword == RID_FOR) { - tree initv, incrv, condv, declv, omp_simd_node, body = NULL_TREE; - parser->in_statement = IN_CILK_P_SIMD_FOR; - body = push_stmt_list (); + tree body = push_stmt_list (); cp_parser_statement (parser, NULL_TREE, false, NULL); body = pop_stmt_list (body); @@ -30604,23 +30465,16 @@ cp_parser_cilk_for (cp_parser *parser, enum rid for_keyword, tree clauses) nodes, just return an error mark node. */ if (!cpp_validate_cilk_plus_loop (body)) return error_mark_node; - - /* Now pass all the information into finish_omp_for. */ - initv = make_tree_vec (1); - condv = make_tree_vec (1); - incrv = make_tree_vec (1); - declv = make_tree_vec (1); - TREE_VEC_ELT (initv, 0) = init; - TREE_VEC_ELT (condv, 0) = cond; - TREE_VEC_ELT (incrv, 0) = incr_expr; - TREE_VEC_ELT (declv, 0) = decl; - omp_simd_node = finish_omp_for (loc, OMP_SIMD, declv, initv, condv, - incrv, body, pre_body, clauses); - return omp_simd_node; + + return c_finish_cilk_simd_loop (loc, decl, init, cond, incr_expr, + body, clauses); } else - /* Fix this when _Cilk_for is added into the mix. */ - return NULL_TREE; + { + /* Handle _Cilk_for here when implemented. */ + gcc_unreachable (); + return NULL_TREE; + } } #include "gt-cp-parser.h" diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 9c5dc74977dbc..16e2472df7e7e 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -6054,6 +6054,13 @@ finish_omp_cancellation_point (tree clauses) finish_expr_stmt (stmt); } +/* Perform any canonicalization of the conditional in a Cilk for loop. */ +tree +finish_cilk_for_cond (tree cond) +{ + return maybe_convert_cond (cond); +} + /* Begin a __transaction_atomic or __transaction_relaxed statement. If PCOMPOUND is non-null, this is for a function-transaction-block, and we should create an extra compound stmt. */ diff --git a/gcc/testsuite/c-c++-common/cilk-plus/PS/for4.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/for4.c new file mode 100644 index 0000000000000..2da8235f3194c --- /dev/null +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/for4.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fcilkplus" } */ + +int *a, *c; + +void foo() +{ + int i, j; + + // Pointers are OK. + #pragma simd + for (int *i=c; i < c; ++i) + *a = '5'; +} diff --git a/gcc/testsuite/c-c++-common/cilk-plus/PS/for5.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/for5.c new file mode 100644 index 0000000000000..7075a44718eb3 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/for5.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fcilkplus" } */ + +int *a, *b; + +void foo() +{ +#pragma simd + for (int i=100; i; --i) + a[i] = b[i]; +} From 9f19698ca42d619c8b92f699bac9e6c74c0954ba Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Mon, 10 Jun 2013 12:11:06 -0500 Subject: [PATCH 43/63] Do not wrap pragma simd for loop condition in a CLEANUP_POINT_EXPR. Instead, use cp_truthvalue_conversion(). --- gcc/cp/parser.c | 5 ++++- gcc/cp/semantics.c | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index c93ea9eb6d8c6..37c1652658f92 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -30379,6 +30379,7 @@ cp_parser_cilk_for (cp_parser *parser, enum rid for_keyword, tree clauses) return error_mark_node; } + /* Parse initialization. */ if (for_keyword == RID_FOR) decl = cp_parser_simd_for_init_statement (parser, &init, &pre_body); @@ -30410,6 +30411,7 @@ cp_parser_cilk_for (cp_parser *parser, enum rid for_keyword, tree clauses) valid = false; } + /* Parse condition. */ if (!cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON)) return error_mark_node; if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)) @@ -30426,7 +30428,8 @@ cp_parser_cilk_for (cp_parser *parser, enum rid for_keyword, tree clauses) if (cond == error_mark_node) valid = false; cp_parser_consume_semicolon_at_end_of_statement (parser); - + + /* Parse increment. */ if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN)) { error_at (loc, "missing increment"); diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 16e2472df7e7e..f8c5d820b657e 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -6058,7 +6058,7 @@ finish_omp_cancellation_point (tree clauses) tree finish_cilk_for_cond (tree cond) { - return maybe_convert_cond (cond); + return cp_truthvalue_conversion (cond); } /* Begin a __transaction_atomic or __transaction_relaxed statement. From ff99e44b2bbcb3ea859b38a0a62bfd1c3df3e9ee Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Mon, 10 Jun 2013 12:16:49 -0500 Subject: [PATCH 44/63] Allow alternate error message for return out of a pragma simd for loop. --- gcc/testsuite/c-c++-common/cilk-plus/PS/body.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gcc/testsuite/c-c++-common/cilk-plus/PS/body.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/body.c index 5ecefd5bea279..fe8b6306a64cb 100644 --- a/gcc/testsuite/c-c++-common/cilk-plus/PS/body.c +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/body.c @@ -12,7 +12,7 @@ void foo() for (int i=0; i < 1000; ++i) { if (c == 5) - return; /* { dg-error "return statments are not allowed" } */ + return; /* { dg-error "\(return statments are not allowed\|invalid exit\)" } */ if (c == 6) __builtin_setjmp (jmpbuf); /* { dg-error "calls to setjmp are not allowed" } */ a[i] = b[i]; From 334963503969ed99f16822169af64ec9394da055 Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Mon, 10 Jun 2013 13:36:56 -0500 Subject: [PATCH 45/63] Error correctly in the C++ FE for invalid storage classes specified in a pragma simd loop. --- gcc/cp/parser.c | 20 +++++++++++++- gcc/testsuite/g++.dg/cilk-plus/for2.C | 26 +++++++++++++++++++ .../cilk-plus/PS => gcc.dg/cilk-plus}/for2.c | 0 3 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/cilk-plus/for2.C rename gcc/testsuite/{c-c++-common/cilk-plus/PS => gcc.dg/cilk-plus}/for2.c (100%) diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 37c1652658f92..d68bdf78de449 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -30236,6 +30236,17 @@ cp_parser_simd_for_init_statement (cp_parser *parser, tree *init, error_at (loc, "expected iteration declaration"); return error_mark_node; } + + if (cp_lexer_next_token_is_keyword (parser->lexer, RID_STATIC) + || cp_lexer_next_token_is_keyword (parser->lexer, RID_REGISTER) + || cp_lexer_next_token_is_keyword (parser->lexer, RID_EXTERN) + || cp_lexer_next_token_is_keyword (parser->lexer, RID_MUTABLE) + || cp_lexer_next_token_is_keyword (parser->lexer, RID_THREAD)) + { + error_at (loc, "storage class is not allowed"); + cp_lexer_consume_token (parser->lexer); + } + cp_parser_parse_tentatively (parser); cp_parser_type_specifier_seq (parser, true, false, &type_specifiers); if (cp_parser_parse_definitely (parser)) @@ -30332,7 +30343,8 @@ cp_parser_simd_for_init_statement (cp_parser *parser, tree *init, } else { - decl = NULL_TREE; + if (decl != error_mark_node) + decl = NULL; cp_parser_abort_tentative_parse (parser); *init = cp_parser_expression (parser, false, NULL); } @@ -30411,6 +30423,12 @@ cp_parser_cilk_for (cp_parser *parser, enum rid for_keyword, tree clauses) valid = false; } + if (!valid) + { + /* Skip to the semicolon ending the init. */ + cp_parser_skip_to_end_of_statement (parser); + } + /* Parse condition. */ if (!cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON)) return error_mark_node; diff --git a/gcc/testsuite/g++.dg/cilk-plus/for2.C b/gcc/testsuite/g++.dg/cilk-plus/for2.C new file mode 100644 index 0000000000000..d30e05787e43c --- /dev/null +++ b/gcc/testsuite/g++.dg/cilk-plus/for2.C @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fcilkplus" } */ + +// Test storage classes in the initialization of a <#pragma simd> for +// loop. + +int *a, *b; + +void foo() +{ +#pragma simd + for (static int tt=5; tt < 10; ++tt) /* { dg-error "storage class is not allowed" } */ + a[tt] = b[tt]; + +#pragma simd + for (extern int var=0; var < 1000; ++var) /* { dg-error "storage class is not allowed" } */ + a[var] = var; + +#pragma simd + for (register int regj = 0; regj < 1000; ++regj) /* { dg-error "storage class is not allowed" } */ + b[regj] = a[regj] * 2; + +#pragma simd + for (volatile int vj=0; vj<1000; ++vj) /* { dg-error "induction variable cannot be volatile" } */ + a[vj] = b[vj]; +} diff --git a/gcc/testsuite/c-c++-common/cilk-plus/PS/for2.c b/gcc/testsuite/gcc.dg/cilk-plus/for2.c similarity index 100% rename from gcc/testsuite/c-c++-common/cilk-plus/PS/for2.c rename to gcc/testsuite/gcc.dg/cilk-plus/for2.c From d3481c1a1d74d5922d79a755d62c3a14d0072cf9 Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Tue, 11 Jun 2013 12:12:10 -0500 Subject: [PATCH 46/63] Handle NE_EXPR in extract_omp_for_data, but only when -fcilkplus is used. --- gcc/ChangeLog.cilkplus | 1 + gcc/omp-low.c | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/gcc/ChangeLog.cilkplus b/gcc/ChangeLog.cilkplus index 96a02c64e2288..6a48ada0fa2ab 100644 --- a/gcc/ChangeLog.cilkplus +++ b/gcc/ChangeLog.cilkplus @@ -3,6 +3,7 @@ * Makefile.in (C_COMMON_OBJS): Depend on c-family/c-cilkplus.o. (c-cilkplus.o): New dependency. + * omp-low.c (extract_omp_for_data): Add case for NE_EXPR. c-family/ * c-cilkplus.c: New. diff --git a/gcc/omp-low.c b/gcc/omp-low.c index b131cde703718..08ed83b6994c6 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -316,6 +316,12 @@ extract_omp_for_data (gimple for_stmt, struct omp_for_data *fd, case LT_EXPR: case GT_EXPR: break; + case NE_EXPR: + if (!flag_enable_cilk) + gcc_unreachable (); + /* NE_EXPR is technically not allowed in OpenMP, but it is + allowed in Cilk Plus, which generates OMP_SIMD constructs. */ + break; case LE_EXPR: if (POINTER_TYPE_P (TREE_TYPE (loop->n2))) loop->n2 = fold_build_pointer_plus_hwi_loc (loc, loop->n2, 1); From 7c108624f7ba55111d9fcd4a58d753cb0a418384 Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Tue, 11 Jun 2013 16:44:47 -0500 Subject: [PATCH 47/63] Add new Cilk Plus pragma simd execution tests. testsuite/c-c++-common/cilk-plus/PS/p_simd_test1.c is currently failing due to missing reduction functionality for OMP_SIMD. --- .../c-c++-common/cilk-plus/PS/p_simd_test1.c | 36 +++++++++++++++++++ .../c-c++-common/cilk-plus/PS/run-1.c | 28 +++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 gcc/testsuite/c-c++-common/cilk-plus/PS/p_simd_test1.c create mode 100644 gcc/testsuite/c-c++-common/cilk-plus/PS/run-1.c diff --git a/gcc/testsuite/c-c++-common/cilk-plus/PS/p_simd_test1.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/p_simd_test1.c new file mode 100644 index 0000000000000..43a359a9442b5 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/p_simd_test1.c @@ -0,0 +1,36 @@ +/* { dg-do run } */ +/* { dg-options "-O3 -fcilkplus" } */ + +#include + +#define ARRAY_SIZE (256) +int a[ARRAY_SIZE]; + +__attribute__((noinline)) +int addit (int *arr, int N) +{ + int s=0; +#pragma simd reduction (+:s) + for (int i = 0; i < N; i++) + s += arr[i]; + return s; +} + +int main () { + int i, s = 0, r = 0; + for (i = 0; i < ARRAY_SIZE; i++) + { + a[i] = i; + } + + s = addit (a, ARRAY_SIZE); + + for (i = 0; i < ARRAY_SIZE; i++) + r += i; + + if (s == r) + return 0; + else + return 1; + return 0; +} diff --git a/gcc/testsuite/c-c++-common/cilk-plus/PS/run-1.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/run-1.c new file mode 100644 index 0000000000000..c8fe1c762bc32 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/run-1.c @@ -0,0 +1,28 @@ +/* { dg-do run } */ +/* { dg-options "-fcilkplus -O3" } */ + +#include + +#define N 4 + +float f1[] = { 2.0, 3.0, 4.0, 5.0 }; +float f2[] = { 1.0, 6.0, -1.0, -2.0 }; +float res[] = { 3.0, 9.0, 3.0, 3.0 }; + +__attribute__((noinline)) +void verify (float *sum) +{ + for (int i=0; i < N; ++i) + if (sum[i] != res[i]) + abort (); +} + +int main() +{ + float sum[N]; +#pragma simd + for (int i=0; i < N; ++i) + sum[i] = f1[i] + f2[i]; + verify (sum); + return 0; +} From a1d8cc8f5e273166e183737cf6c46cac9160d113 Mon Sep 17 00:00:00 2001 From: jakub Date: Wed, 12 Jun 2013 12:24:28 +0000 Subject: [PATCH 48/63] * omp_lib.f90.in (omp_get_dynamic, omp_get_nested, omp_in_parallel, omp_get_max_threads, omp_get_num_procs, omp_get_num_threads, omp_get_thread_num, omp_get_thread_limit, omp_set_max_active_levels, omp_get_max_active_levels, omp_get_level, omp_get_ancestor_thread_num, omp_get_team_size, omp_get_active_level, omp_in_final, omp_get_cancellation, omp_get_default_device, omp_get_num_devices, omp_get_num_teams, omp_get_team_num): Remove useless use omp_lib_kinds. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gomp-4_0-branch@199994 138bc75d-0d04-0410-961f-82ee72b054a4 --- libgomp/ChangeLog.gomp | 12 ++++++++++++ libgomp/omp_lib.f90.in | 23 ----------------------- 2 files changed, 12 insertions(+), 23 deletions(-) diff --git a/libgomp/ChangeLog.gomp b/libgomp/ChangeLog.gomp index e01eaa946d2fc..94935ff346571 100644 --- a/libgomp/ChangeLog.gomp +++ b/libgomp/ChangeLog.gomp @@ -1,3 +1,15 @@ +2013-06-12 Jakub Jelinek + + * omp_lib.f90.in (omp_get_dynamic, omp_get_nested, + omp_in_parallel, omp_get_max_threads, omp_get_num_procs, + omp_get_num_threads, omp_get_thread_num, omp_get_thread_limit, + omp_set_max_active_levels, omp_get_max_active_levels, + omp_get_level, omp_get_ancestor_thread_num, + omp_get_team_size, omp_get_active_level, omp_in_final, + omp_get_cancellation, omp_get_default_device, + omp_get_num_devices, omp_get_num_teams, omp_get_team_num): Remove + useless use omp_lib_kinds. + 2013-04-30 Jakub Jelinek * testsuite/libgomp.c/atomic-17.c: New test. diff --git a/libgomp/omp_lib.f90.in b/libgomp/omp_lib.f90.in index 50bbeaee43be5..eb8b24f9069cd 100644 --- a/libgomp/omp_lib.f90.in +++ b/libgomp/omp_lib.f90.in @@ -129,21 +129,18 @@ interface function omp_get_dynamic () - use omp_lib_kinds logical (4) :: omp_get_dynamic end function omp_get_dynamic end interface interface function omp_get_nested () - use omp_lib_kinds logical (4) :: omp_get_nested end function omp_get_nested end interface interface function omp_in_parallel () - use omp_lib_kinds logical (4) :: omp_in_parallel end function omp_in_parallel end interface @@ -158,28 +155,24 @@ interface function omp_get_max_threads () - use omp_lib_kinds integer (4) :: omp_get_max_threads end function omp_get_max_threads end interface interface function omp_get_num_procs () - use omp_lib_kinds integer (4) :: omp_get_num_procs end function omp_get_num_procs end interface interface function omp_get_num_threads () - use omp_lib_kinds integer (4) :: omp_get_num_threads end function omp_get_num_threads end interface interface function omp_get_thread_num () - use omp_lib_kinds integer (4) :: omp_get_thread_num end function omp_get_thread_num end interface @@ -232,44 +225,37 @@ interface function omp_get_thread_limit () - use omp_lib_kinds integer (4) :: omp_get_thread_limit end function omp_get_thread_limit end interface interface omp_set_max_active_levels subroutine omp_set_max_active_levels (max_levels) - use omp_lib_kinds integer (4), intent (in) :: max_levels end subroutine omp_set_max_active_levels subroutine omp_set_max_active_levels_8 (max_levels) - use omp_lib_kinds integer (8), intent (in) :: max_levels end subroutine omp_set_max_active_levels_8 end interface interface function omp_get_max_active_levels () - use omp_lib_kinds integer (4) :: omp_get_max_active_levels end function omp_get_max_active_levels end interface interface function omp_get_level () - use omp_lib_kinds integer (4) :: omp_get_level end function omp_get_level end interface interface omp_get_ancestor_thread_num function omp_get_ancestor_thread_num (level) - use omp_lib_kinds integer (4), intent (in) :: level integer (4) :: omp_get_ancestor_thread_num end function omp_get_ancestor_thread_num function omp_get_ancestor_thread_num_8 (level) - use omp_lib_kinds integer (8), intent (in) :: level integer (4) :: omp_get_ancestor_thread_num_8 end function omp_get_ancestor_thread_num_8 @@ -277,12 +263,10 @@ interface omp_get_team_size function omp_get_team_size (level) - use omp_lib_kinds integer (4), intent (in) :: level integer (4) :: omp_get_team_size end function omp_get_team_size function omp_get_team_size_8 (level) - use omp_lib_kinds integer (8), intent (in) :: level integer (4) :: omp_get_team_size_8 end function omp_get_team_size_8 @@ -290,21 +274,18 @@ interface function omp_get_active_level () - use omp_lib_kinds integer (4) :: omp_get_active_level end function omp_get_active_level end interface interface function omp_in_final () - use omp_lib_kinds logical (4) :: omp_in_final end function omp_in_final end interface interface function omp_get_cancellation () - use omp_lib_kinds logical (4) :: omp_get_cancellation end function omp_get_cancellation end interface @@ -327,28 +308,24 @@ interface function omp_get_default_device () - use omp_lib_kinds integer (4) :: omp_get_default_device end function omp_get_default_device end interface interface function omp_get_num_devices () - use omp_lib_kinds integer (4) :: omp_get_num_devices end function omp_get_num_devices end interface interface function omp_get_num_teams () - use omp_lib_kinds integer (4) :: omp_get_num_teams end function omp_get_num_teams end interface interface function omp_get_team_num () - use omp_lib_kinds integer (4) :: omp_get_team_num end function omp_get_team_num end interface From 4bfdbc64e0df45d696edd06851bb8db72418d20b Mon Sep 17 00:00:00 2001 From: jakub Date: Wed, 12 Jun 2013 12:25:04 +0000 Subject: [PATCH 49/63] * fortran.c (omp_is_initial_device): Add ialias_redirect. (omp_is_initial_device_): New function. * omp_lib.f90.in (omp_is_initial_device): New interface. * omp.h.in (omp_is_initial_device): New prototype. * libgomp.map (omp_is_initial_device, omp_is_initial_device_): Export @@OMP_4.0. * env.c (omp_is_initial_device): New function. Add ialias for it. * omp_lib.h.in (omp_is_initial_device): New external. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gomp-4_0-branch@199995 138bc75d-0d04-0410-961f-82ee72b054a4 --- libgomp/ChangeLog.gomp | 9 +++++++++ libgomp/env.c | 7 +++++++ libgomp/fortran.c | 7 +++++++ libgomp/libgomp.map | 2 ++ libgomp/omp.h.in | 2 ++ libgomp/omp_lib.f90.in | 6 ++++++ libgomp/omp_lib.h.in | 3 +++ 7 files changed, 36 insertions(+) diff --git a/libgomp/ChangeLog.gomp b/libgomp/ChangeLog.gomp index 94935ff346571..5c3df790645bd 100644 --- a/libgomp/ChangeLog.gomp +++ b/libgomp/ChangeLog.gomp @@ -1,5 +1,14 @@ 2013-06-12 Jakub Jelinek + * fortran.c (omp_is_initial_device): Add ialias_redirect. + (omp_is_initial_device_): New function. + * omp_lib.f90.in (omp_is_initial_device): New interface. + * omp.h.in (omp_is_initial_device): New prototype. + * libgomp.map (omp_is_initial_device, omp_is_initial_device_): + Export @@OMP_4.0. + * env.c (omp_is_initial_device): New function. Add ialias for it. + * omp_lib.h.in (omp_is_initial_device): New external. + * omp_lib.f90.in (omp_get_dynamic, omp_get_nested, omp_in_parallel, omp_get_max_threads, omp_get_num_procs, omp_get_num_threads, omp_get_thread_num, omp_get_thread_limit, diff --git a/libgomp/env.c b/libgomp/env.c index b9c1d140011e8..dbbddbda98f64 100644 --- a/libgomp/env.c +++ b/libgomp/env.c @@ -908,6 +908,12 @@ omp_get_team_num (void) return 0; } +int +omp_is_initial_device (void) +{ + return 1; +} + ialias (omp_set_dynamic) ialias (omp_set_nested) ialias (omp_set_num_threads) @@ -926,3 +932,4 @@ ialias (omp_get_default_device) ialias (omp_get_num_devices) ialias (omp_get_num_teams) ialias (omp_get_team_num) +ialias (omp_is_initial_device) diff --git a/libgomp/fortran.c b/libgomp/fortran.c index 6f1717812b639..38b968a8d3965 100644 --- a/libgomp/fortran.c +++ b/libgomp/fortran.c @@ -72,6 +72,7 @@ ialias_redirect (omp_get_default_device) ialias_redirect (omp_get_num_devices) ialias_redirect (omp_get_num_teams) ialias_redirect (omp_get_team_num) +ialias_redirect (omp_is_initial_device) #endif #ifndef LIBGOMP_GNU_SYMBOL_VERSIONING @@ -485,3 +486,9 @@ omp_get_team_num_ (void) { return omp_get_team_num (); } + +int32_t +omp_is_initial_device_ (void) +{ + return omp_is_initial_device (); +} diff --git a/libgomp/libgomp.map b/libgomp/libgomp.map index 41d083dba2c33..5060a4b94e171 100644 --- a/libgomp/libgomp.map +++ b/libgomp/libgomp.map @@ -130,6 +130,8 @@ OMP_4.0 { omp_get_num_teams_; omp_get_team_num; omp_get_team_num_; + omp_is_initial_device; + omp_is_initial_device_; } OMP_3.1; GOMP_1.0 { diff --git a/libgomp/omp.h.in b/libgomp/omp.h.in index 5d808c1509e91..4fc123669ecad 100644 --- a/libgomp/omp.h.in +++ b/libgomp/omp.h.in @@ -118,6 +118,8 @@ extern int omp_get_num_devices (void) __GOMP_NOTHROW; extern int omp_get_num_teams (void) __GOMP_NOTHROW; extern int omp_get_team_num (void) __GOMP_NOTHROW; +extern int omp_is_initial_device (void) __GOMP_NOTHROW; + #ifdef __cplusplus } #endif diff --git a/libgomp/omp_lib.f90.in b/libgomp/omp_lib.f90.in index eb8b24f9069cd..88ae9abe24965 100644 --- a/libgomp/omp_lib.f90.in +++ b/libgomp/omp_lib.f90.in @@ -330,4 +330,10 @@ end function omp_get_team_num end interface + interface + function omp_is_initial_device () + logical (4) :: omp_is_initial_device + end function omp_is_initial_device + end interface + end module omp_lib diff --git a/libgomp/omp_lib.h.in b/libgomp/omp_lib.h.in index 3d3e7c77fe318..804636df82f29 100644 --- a/libgomp/omp_lib.h.in +++ b/libgomp/omp_lib.h.in @@ -92,3 +92,6 @@ external omp_get_team_num integer(4) omp_get_default_device, omp_get_num_devices integer(4) omp_get_num_teams, omp_get_team_num + + external omp_is_initial_device + logical(4) omp_is_initial_device From 5b912f622c7f645a818636756505d7a450365d45 Mon Sep 17 00:00:00 2001 From: jakub Date: Wed, 12 Jun 2013 13:00:06 +0000 Subject: [PATCH 50/63] * gimplify.c (gimplify_scan_omp_clauses): Handle OMP_CLAUSE_THREAD_LIMIT. * tree-pretty-print.c (dump_omp_clause): Likewise. * tree.c (omp_clause_num_ops, omp_clause_code_name): Add entries for OMP_CLAUSE_THREAD_LIMIT. * tree.h (enum omp_clause_code): Add OMP_CLAUSE_THREAD_LIMIT. (OMP_CLAUSE_THREAD_LIMIT_EXPR): Define. cp/ * semantics.c (finish_omp_clauses): Handle OMP_CLAUSE_THREAD_LIMIT. * parser.c (cp_parser_omp_clause_name): Handle thread_limit clause. (cp_parser_omp_clause_thread_limit): New function. (cp_parser_omp_all_clauses): Handle PRAGMA_OMP_CLAUSE_THREAD_LIMIT. (OMP_TEAMS_CLAUSE_MASK): Replace PRAGMA_OMP_CLAUSE_NUM_THREADS with PRAGMA_OMP_CLAUSE_THREAD_LIMIT. * pt.c (tsubst_omp_clauses): Handle OMP_CLAUSE_THREAD_LIMIT. c-family/ * c-pragma.h (enum pragma_omp_clause): Add PRAGMA_OMP_CLAUSE_THREAD_LIMIT. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gomp-4_0-branch@199997 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog.gomp | 10 ++++++++++ gcc/c-family/ChangeLog.gomp | 5 +++++ gcc/c-family/c-pragma.h | 1 + gcc/cp/ChangeLog.gomp | 10 ++++++++++ gcc/cp/parser.c | 39 ++++++++++++++++++++++++++++++++++++- gcc/cp/pt.c | 1 + gcc/cp/semantics.c | 19 ++++++++++++++++++ gcc/gimplify.c | 1 + gcc/tree-pretty-print.c | 7 +++++++ gcc/tree.c | 3 +++ gcc/tree.h | 7 +++++++ 11 files changed, 102 insertions(+), 1 deletion(-) diff --git a/gcc/ChangeLog.gomp b/gcc/ChangeLog.gomp index a9bf4b4dfcf32..2f0519a3f7304 100644 --- a/gcc/ChangeLog.gomp +++ b/gcc/ChangeLog.gomp @@ -1,3 +1,13 @@ +2013-06-12 Jakub Jelinek + + * gimplify.c (gimplify_scan_omp_clauses): Handle + OMP_CLAUSE_THREAD_LIMIT. + * tree-pretty-print.c (dump_omp_clause): Likewise. + * tree.c (omp_clause_num_ops, omp_clause_code_name): Add entries for + OMP_CLAUSE_THREAD_LIMIT. + * tree.h (enum omp_clause_code): Add OMP_CLAUSE_THREAD_LIMIT. + (OMP_CLAUSE_THREAD_LIMIT_EXPR): Define. + 2013-06-04 Jakub Jelinek * gimplify.c (gimplify_scan_omp_clauses): Handle array diff --git a/gcc/c-family/ChangeLog.gomp b/gcc/c-family/ChangeLog.gomp index 996804f331c40..abc1aae63477f 100644 --- a/gcc/c-family/ChangeLog.gomp +++ b/gcc/c-family/ChangeLog.gomp @@ -1,3 +1,8 @@ +2013-06-12 Jakub Jelinek + + * c-pragma.h (enum pragma_omp_clause): Add + PRAGMA_OMP_CLAUSE_THREAD_LIMIT. + 2013-05-29 Jakub Jelinek * c-common.c (c_common_attribute_table): Add "omp declare target" diff --git a/gcc/c-family/c-pragma.h b/gcc/c-family/c-pragma.h index cd121d46c0008..a104c7ce9e886 100644 --- a/gcc/c-family/c-pragma.h +++ b/gcc/c-family/c-pragma.h @@ -104,6 +104,7 @@ typedef enum pragma_omp_clause { PRAGMA_OMP_CLAUSE_SHARED, PRAGMA_OMP_CLAUSE_SIMDLEN, PRAGMA_OMP_CLAUSE_TASKGROUP, + PRAGMA_OMP_CLAUSE_THREAD_LIMIT, PRAGMA_OMP_CLAUSE_TO, PRAGMA_OMP_CLAUSE_UNIFORM, PRAGMA_OMP_CLAUSE_UNTIED diff --git a/gcc/cp/ChangeLog.gomp b/gcc/cp/ChangeLog.gomp index ab582f5ac97ae..e7f3b24edcc04 100644 --- a/gcc/cp/ChangeLog.gomp +++ b/gcc/cp/ChangeLog.gomp @@ -1,3 +1,13 @@ +2013-06-12 Jakub Jelinek + + * semantics.c (finish_omp_clauses): Handle OMP_CLAUSE_THREAD_LIMIT. + * parser.c (cp_parser_omp_clause_name): Handle thread_limit clause. + (cp_parser_omp_clause_thread_limit): New function. + (cp_parser_omp_all_clauses): Handle PRAGMA_OMP_CLAUSE_THREAD_LIMIT. + (OMP_TEAMS_CLAUSE_MASK): Replace PRAGMA_OMP_CLAUSE_NUM_THREADS + with PRAGMA_OMP_CLAUSE_THREAD_LIMIT. + * pt.c (tsubst_omp_clauses): Handle OMP_CLAUSE_THREAD_LIMIT. + 2013-06-04 Jakub Jelinek * semantics.c (handle_omp_array_sections_1, handle_omp_array_sections): diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 8c3e690879b23..1cea012d7e49d 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -26225,6 +26225,8 @@ cp_parser_omp_clause_name (cp_parser *parser) case 't': if (!strcmp ("taskgroup", p)) result = PRAGMA_OMP_CLAUSE_TASKGROUP; + else if (!strcmp ("thread_limit", p)) + result = PRAGMA_OMP_CLAUSE_THREAD_LIMIT; else if (!strcmp ("to", p)) result = PRAGMA_OMP_CLAUSE_TO; break; @@ -26891,6 +26893,36 @@ cp_parser_omp_clause_num_teams (cp_parser *parser, tree list, return c; } +/* OpenMP 4.0: + thread_limit ( expression ) */ + +static tree +cp_parser_omp_clause_thread_limit (cp_parser *parser, tree list, + location_t location) +{ + tree t, c; + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + return list; + + t = cp_parser_expression (parser, false, NULL); + + if (t == error_mark_node + || !cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + + check_no_duplicate_clause (list, OMP_CLAUSE_THREAD_LIMIT, + "thread_limit", location); + + c = build_omp_clause (location, OMP_CLAUSE_THREAD_LIMIT); + OMP_CLAUSE_THREAD_LIMIT_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + + return c; +} + /* OpenMP 4.0: aligned ( variable-list ) aligned ( variable-list : constant-expression ) */ @@ -27429,6 +27461,11 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask, token->location); c_name = "num_teams"; break; + case PRAGMA_OMP_CLAUSE_THREAD_LIMIT: + clauses = cp_parser_omp_clause_thread_limit (parser, clauses, + token->location); + c_name = "thread_limit"; + break; case PRAGMA_OMP_CLAUSE_ALIGNED: clauses = cp_parser_omp_clause_aligned (parser, clauses); c_name = "aligned"; @@ -29058,7 +29095,7 @@ cp_parser_omp_cancellation_point (cp_parser *parser, cp_token *pragma_tok) | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_TEAMS) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_THREAD_LIMIT) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT)) static tree diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 9583afd51ce76..3eb111aeecfe7 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -12667,6 +12667,7 @@ tsubst_omp_clauses (tree clauses, bool declare_simd, case OMP_CLAUSE_DEVICE: case OMP_CLAUSE_DIST_SCHEDULE: case OMP_CLAUSE_NUM_TEAMS: + case OMP_CLAUSE_THREAD_LIMIT: case OMP_CLAUSE_SAFELEN: case OMP_CLAUSE_SIMDLEN: OMP_CLAUSE_OPERAND (nc, 0) diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 9c5dc74977dbc..f4a6ec87471bd 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -4779,6 +4779,25 @@ finish_omp_clauses (tree clauses) } break; + case OMP_CLAUSE_THREAD_LIMIT: + t = OMP_CLAUSE_THREAD_LIMIT_EXPR (c); + if (t == error_mark_node) + remove = true; + else if (!type_dependent_expression_p (t) + && !INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + error ("% expression must be integral"); + remove = true; + } + else + { + t = mark_rvalue_use (t); + if (!processing_template_decl) + t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + OMP_CLAUSE_THREAD_LIMIT_EXPR (c) = t; + } + break; + case OMP_CLAUSE_DEVICE: t = OMP_CLAUSE_DEVICE_ID (c); if (t == error_mark_node) diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 4caa79c42dc6a..e2c10718aa225 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -6420,6 +6420,7 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, case OMP_CLAUSE_SCHEDULE: case OMP_CLAUSE_NUM_THREADS: case OMP_CLAUSE_NUM_TEAMS: + case OMP_CLAUSE_THREAD_LIMIT: case OMP_CLAUSE_DIST_SCHEDULE: case OMP_CLAUSE_DEVICE: if (gimplify_expr (&OMP_CLAUSE_OPERAND (c, 0), pre_p, NULL, diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c index c42ea336d377e..b67fc937f8906 100644 --- a/gcc/tree-pretty-print.c +++ b/gcc/tree-pretty-print.c @@ -533,6 +533,13 @@ dump_omp_clause (pretty_printer *buffer, tree clause, int spc, int flags) pp_character (buffer, ')'); break; + case OMP_CLAUSE_THREAD_LIMIT: + pp_string (buffer, "thread_limit("); + dump_generic_node (buffer, OMP_CLAUSE_THREAD_LIMIT_EXPR (clause), + spc, flags, false); + pp_character (buffer, ')'); + break; + case OMP_CLAUSE_DEVICE: pp_string (buffer, "device("); dump_generic_node (buffer, OMP_CLAUSE_DEVICE_ID (clause), diff --git a/gcc/tree.c b/gcc/tree.c index d8b5aac4d8e1a..2485d2e7fee1e 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -257,6 +257,7 @@ unsigned const char omp_clause_num_ops[] = 0, /* OMP_CLAUSE_INBRANCH */ 0, /* OMP_CLAUSE_NOTINBRANCH */ 1, /* OMP_CLAUSE_NUM_TEAMS */ + 1, /* OMP_CLAUSE_THREAD_LIMIT */ 0, /* OMP_CLAUSE_PROC_BIND */ 1, /* OMP_CLAUSE_SAFELEN */ 1, /* OMP_CLAUSE_SIMDLEN */ @@ -298,6 +299,7 @@ const char * const omp_clause_code_name[] = "inbranch", "notinbranch", "num_teams", + "thread_limit", "proc_bind", "safelen", "simdlen", @@ -11014,6 +11016,7 @@ walk_tree_1 (tree *tp, walk_tree_fn func, void *data, case OMP_CLAUSE_UNIFORM: case OMP_CLAUSE_DEPEND: case OMP_CLAUSE_NUM_TEAMS: + case OMP_CLAUSE_THREAD_LIMIT: case OMP_CLAUSE_DEVICE: case OMP_CLAUSE_DIST_SCHEDULE: case OMP_CLAUSE_SAFELEN: diff --git a/gcc/tree.h b/gcc/tree.h index fb36e74f7a63e..7f2e173012846 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -431,6 +431,9 @@ enum omp_clause_code /* OpenMP clause: num_teams(integer-expression). */ OMP_CLAUSE_NUM_TEAMS, + /* OpenMP clause: thread_limit(integer-expression). */ + OMP_CLAUSE_THREAD_LIMIT, + /* OpenMP clause: proc_bind ({master,close,spread}). */ OMP_CLAUSE_PROC_BIND, @@ -1978,6 +1981,10 @@ extern void protected_set_expr_location (tree, location_t); #define OMP_CLAUSE_NUM_TEAMS_EXPR(NODE) \ OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_NUM_TEAMS), 0) +#define OMP_CLAUSE_THREAD_LIMIT_EXPR(NODE) \ + OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, \ + OMP_CLAUSE_THREAD_LIMIT), 0) + #define OMP_CLAUSE_DEVICE_ID(NODE) \ OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_DEVICE), 0) From 1a0f2f553ccf6c202f2e3a76bf5921b3fe4c50ed Mon Sep 17 00:00:00 2001 From: jakub Date: Wed, 12 Jun 2013 13:00:45 +0000 Subject: [PATCH 51/63] * semantics.c (finish_omp_clause): Don't mark references addressable. For OMP_CLAUSE_{TO,FROM} detect same decl appearing more than once in motion clauses. * parser.c (cp_parser_omp_var_list_no_open): Handle [ expression ] notation in array section specification. (cp_parser_omp_all_clauses): Don't require to/from clauses to be first. (cp_parser_omp_target_update): Adjust diagnostics. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gomp-4_0-branch@199998 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/cp/ChangeLog.gomp | 9 +++++++++ gcc/cp/parser.c | 26 ++++++++++++++------------ gcc/cp/semantics.c | 10 ++++++++++ 3 files changed, 33 insertions(+), 12 deletions(-) diff --git a/gcc/cp/ChangeLog.gomp b/gcc/cp/ChangeLog.gomp index e7f3b24edcc04..1ca06a9cacadf 100644 --- a/gcc/cp/ChangeLog.gomp +++ b/gcc/cp/ChangeLog.gomp @@ -1,5 +1,14 @@ 2013-06-12 Jakub Jelinek + * semantics.c (finish_omp_clause): Don't mark references addressable. + For OMP_CLAUSE_{TO,FROM} detect same decl appearing more than once + in motion clauses. + * parser.c (cp_parser_omp_var_list_no_open): Handle [ expression ] + notation in array section specification. + (cp_parser_omp_all_clauses): Don't require to/from clauses to be + first. + (cp_parser_omp_target_update): Adjust diagnostics. + * semantics.c (finish_omp_clauses): Handle OMP_CLAUSE_THREAD_LIMIT. * parser.c (cp_parser_omp_clause_name): Handle thread_limit clause. (cp_parser_omp_clause_thread_limit): New function. diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 1cea012d7e49d..9fd0ea444f907 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -26332,13 +26332,19 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, if (!colon) parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p; - /* Look for `:'. */ - if (!cp_parser_require (parser, CPP_COLON, RT_COLON)) - goto skip_comma; - if (!cp_lexer_next_token_is (parser->lexer, - CPP_CLOSE_SQUARE)) - length = cp_parser_expression (parser, /*cast_p=*/false, - NULL); + if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_SQUARE)) + length = integer_one_node; + else + { + /* Look for `:'. */ + if (!cp_parser_require (parser, CPP_COLON, RT_COLON)) + goto skip_comma; + if (!cp_lexer_next_token_is (parser->lexer, + CPP_CLOSE_SQUARE)) + length = cp_parser_expression (parser, + /*cast_p=*/false, + NULL); + } /* Look for the closing `]'. */ if (!cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE)) @@ -27441,15 +27447,11 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask, clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_TO, clauses); c_name = "to"; - if (!first) - goto clause_not_first; break; case PRAGMA_OMP_CLAUSE_FROM: clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_FROM, clauses); c_name = "from"; - if (!first) - goto clause_not_first; break; case PRAGMA_OMP_CLAUSE_UNIFORM: clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_UNIFORM, @@ -29165,7 +29167,7 @@ cp_parser_omp_target_update (cp_parser *parser, cp_token *pragma_tok, && find_omp_clause (clauses, OMP_CLAUSE_FROM) == NULL_TREE) { error_at (pragma_tok->location, - "%<#pragma omp target update must contain either " + "%<#pragma omp target update must contain at least one " "% or % clauses"); return false; } diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index f4a6ec87471bd..a9ebac6b9bb4d 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -4944,8 +4944,18 @@ finish_omp_clauses (tree clauses) remove = true; } else if (!processing_template_decl + && TREE_CODE (TREE_TYPE (t)) != REFERENCE_TYPE && !cxx_mark_addressable (t)) remove = true; + else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP) + break; + else if (bitmap_bit_p (&generic_head, DECL_UID (t))) + { + error ("%qD appears more than once in motion clauses", t); + remove = true; + } + else + bitmap_set_bit (&generic_head, DECL_UID (t)); break; case OMP_CLAUSE_UNIFORM: From 55558fbea21cc20aeaa2886342b452a410475954 Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Fri, 14 Jun 2013 10:42:41 -0500 Subject: [PATCH 52/63] New reduction tests for Cilk Plus pragma simd. --- .../c-c++-common/cilk-plus/PS/p_simd_test2.c | 41 +++++++++++++++++++ .../c-c++-common/cilk-plus/PS/reduction_ex.c | 36 ++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 gcc/testsuite/c-c++-common/cilk-plus/PS/p_simd_test2.c create mode 100644 gcc/testsuite/c-c++-common/cilk-plus/PS/reduction_ex.c diff --git a/gcc/testsuite/c-c++-common/cilk-plus/PS/p_simd_test2.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/p_simd_test2.c new file mode 100644 index 0000000000000..fe51a2916a1d3 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/p_simd_test2.c @@ -0,0 +1,41 @@ +/* { dg-do run } */ +/* { dg-options "-O3 -fcilkplus" } */ + +#define N 256 +#if HAVE_IO +#include +#endif +#include + +int +reduction_simd (int *a) +{ + int s = 0; + +#pragma simd reduction (+:s) + for (int i = 0; i < N; i++) + { + s += a[i]; + } + + return s; +} + +int +main () +{ + int *a = (int *) malloc (N * sizeof (int)); + int i, s = (N - 1) * N / 2; + + for (i = 0; i < N; i++) + { + a[i] = i; + } +#if HAVE_IO + printf ("%d, %d\n", s, reduction_simd (a)); +#endif + if (s == reduction_simd (a)) + return 0; + else + return 1; +} diff --git a/gcc/testsuite/c-c++-common/cilk-plus/PS/reduction_ex.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/reduction_ex.c new file mode 100644 index 0000000000000..920b6db133144 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/reduction_ex.c @@ -0,0 +1,36 @@ +/* { dg-do run } */ +/* { dg-options "-O3 -fcilkplus" } */ + +int argc = 1; + +/* This is a simple vectorization, it checks if check_off_reduction_var works + and it also checks if it can vectorize this loop in func correctly. */ +#define N 1000 + +int func (int *p, int *q) { + int x = 0; +#pragma simd reduction (+:x) + for (int ii = 0; ii < N; ii++) { + x += (q[ii] + p[ii]); + } + return x; + +} + +int main () +{ + int ii = 0, x; + int Array[N], Array2[N]; + + for (ii = 0; ii < N; ii++) + { + Array[ii] = 5 + argc; + Array2[ii] = argc; + } + x = func (Array, Array2); + + if (x != N * 7) + return 1; + return 0; +} + From 7290ab4f242ff6c4c34ff06262780a32f90ce474 Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Fri, 14 Jun 2013 11:16:43 -0500 Subject: [PATCH 53/63] Remove some unneeded FIXMEs. --- gcc/c-family/c-cilkplus.c | 18 ++++-------------- gcc/c/c-parser.c | 15 ++------------- gcc/cp/cp-cilkplus.c | 2 -- gcc/cp/parser.c | 8 ++------ 4 files changed, 8 insertions(+), 35 deletions(-) diff --git a/gcc/c-family/c-cilkplus.c b/gcc/c-family/c-cilkplus.c index c02851eba6d17..7346274579f3a 100644 --- a/gcc/c-family/c-cilkplus.c +++ b/gcc/c-family/c-cilkplus.c @@ -158,11 +158,6 @@ c_validate_cilk_plus_loop (tree *tp, int *walk_subtrees, void *data) break; } - /* FIXME: Perhaps we could do without these OMP tests and defer - to the OMP type checking, since OMP_SIMD cannot have OpenMP - constructs either. From OpenMP 4.0rc2: "No OpenMP construct - can appear in the simd region". Similarly for the call to - setjmp above. */ case OMP_PARALLEL: case OMP_TASK: case OMP_FOR: @@ -372,12 +367,12 @@ c_finish_cilk_simd_loop (location_t loc, TREE_TYPE (t) = void_type_node; OMP_FOR_INIT (t) = initv; - /* FIXME: The spec says "The increment and limit expressions may be + /* ?? The spec says "The increment and limit expressions may be evaluated fewer times than in the serialization. If different evaluations of the same expression yield different values, the - behavior of the program is undefined." This means that the RHS - of the condition and increment could be wrapped in a - SAVE_EXPR. */ + behavior of the program is undefined." Perhaps the RHS of the + condition and increment could be wrapped in a SAVE_EXPR to + evaluate only once. */ OMP_FOR_COND (t) = condv; OMP_FOR_INCR (t) = incrv; @@ -394,11 +389,6 @@ c_finish_cilk_simd_loop (location_t loc, tree c_finish_cilk_clauses (tree clauses) { - /* FIXME: Should we do some minimal type checking of the clauses - here, or at the minimum gcc_asserts? */ - - /* FIXME: Must validate reduction clauses too. Right now we're - ignoring them. */ for (tree c = clauses; c; c = OMP_CLAUSE_CHAIN (c)) { tree prev = clauses; diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index d857f2ab30bfc..7c80b6d1e586a 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -11947,12 +11947,6 @@ c_parser_cilk_all_clauses (c_parser *parser) break; case PRAGMA_CILK_CLAUSE_FIRSTPRIVATE: /* Use the OpenMP counterpart. */ - /* FIXME: Note from the Cilk Plus forum: "For the time - being, assume that firstprivate refers to the vector - lane. (This is what is implemented in the icc compiler.) - As we update the spec, we will harmonize these - definitions with OpenMP 4, possibly deprecating - firstprivate." */ clauses = c_parser_omp_clause_firstprivate (parser, clauses); break; case PRAGMA_CILK_CLAUSE_LASTPRIVATE: @@ -11980,7 +11974,7 @@ c_parser_cilk_all_clauses (c_parser *parser) which have the same syntactic restrictions. FOR_KEYWORD can be either RID_CILK_FOR or RID_FOR, for parsing - _cilk_for or the <#pragma simd> for loop construct respectively. + _Cilk_for or the <#pragma simd> for loop construct respectively. (NOTE: For now, only RID_FOR is handled). @@ -12104,12 +12098,7 @@ c_parser_cilk_for_statement (c_parser *parser, enum rid for_keyword, if (!fail) { - /* - // FIXME: Uncomment when RID_CILK_FOR is implemented. - if (for_keyword == RID_CILK_FOR) - c_finish_cilk_loop (loc, decl, cond, incr, body, grain); - else - */ + if (for_keyword == RID_FOR) c_finish_cilk_simd_loop (loc, decl, init, cond, incr, body, clauses); } diff --git a/gcc/cp/cp-cilkplus.c b/gcc/cp/cp-cilkplus.c index e6bdf8ab80a92..aa803438e5d61 100644 --- a/gcc/cp/cp-cilkplus.c +++ b/gcc/cp/cp-cilkplus.c @@ -60,8 +60,6 @@ cpp_validate_cilk_plus_loop_aux (tree *tp, int *walk_subtrees, void *data) *valid = false; *walk_subtrees = 0; } - /* FIXME: Add a check for TREE_CODE (*tp) == CILK_FOR_STMT and - flag them as invalid when cilk keywords are adopted. */ return NULL_TREE; } diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index a4336b9dc44bc..abfdf618e4e91 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -30396,7 +30396,8 @@ cp_parser_simd_for_init_statement (cp_parser *parser, tree *init, return decl; } -/* Top-level function to parse _Cilk_for and for statements. */ +/* Top-level function to parse _Cilk_for and the for statement + following <#pragma simd>. */ static tree cp_parser_cilk_for (cp_parser *parser, enum rid for_keyword, tree clauses) @@ -30407,11 +30408,6 @@ cp_parser_cilk_for (cp_parser *parser, enum rid for_keyword, tree clauses) tree init = NULL_TREE, pre_body = NULL_TREE, decl; location_t loc = cp_lexer_peek_token (parser->lexer)->location; - /* FIXME: Allow CILK_FOR into this function. That is, use this - function to parse _Cilk_for statments also. To do this - correctly, add another param. called "grain" to hold the - grainsize. */ - gcc_assert (for_keyword == RID_FOR); if (!cp_lexer_next_token_is_keyword (parser->lexer, for_keyword)) From 8616138a777547c7dab2f54c8c79efbe7599af14 Mon Sep 17 00:00:00 2001 From: jakub Date: Fri, 14 Jun 2013 16:46:20 +0000 Subject: [PATCH 54/63] * decl2.c (cp_omp_mappable_type): No longer static. Handle array types and recurse for FIELD_DECL types. * semantics.c (handle_omp_array_sections_1): Call convert_from_reference before testing for pointer_based_p. (finish_omp_clauses): Complain if OMP_CLAUSE_{MAP,TO,FROM} decls or array sections don't have cp_omp_mappable_type. * cp-tree.h (cp_omp_mappable_type): New prototype. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gomp-4_0-branch@200094 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/cp/ChangeLog.gomp | 10 ++++++++++ gcc/cp/cp-tree.h | 1 + gcc/cp/decl2.c | 9 ++++++++- gcc/cp/semantics.c | 24 +++++++++++++++++++++++- 4 files changed, 42 insertions(+), 2 deletions(-) diff --git a/gcc/cp/ChangeLog.gomp b/gcc/cp/ChangeLog.gomp index 1ca06a9cacadf..89c5fce276779 100644 --- a/gcc/cp/ChangeLog.gomp +++ b/gcc/cp/ChangeLog.gomp @@ -1,3 +1,13 @@ +2013-06-14 Jakub Jelinek + + * decl2.c (cp_omp_mappable_type): No longer static. Handle array + types and recurse for FIELD_DECL types. + * semantics.c (handle_omp_array_sections_1): Call + convert_from_reference before testing for pointer_based_p. + (finish_omp_clauses): Complain if OMP_CLAUSE_{MAP,TO,FROM} + decls or array sections don't have cp_omp_mappable_type. + * cp-tree.h (cp_omp_mappable_type): New prototype. + 2013-06-12 Jakub Jelinek * semantics.c (finish_omp_clause): Don't mark references addressable. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 7046713200384..f403068d414b3 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5297,6 +5297,7 @@ extern void note_vague_linkage_fn (tree); extern tree build_artificial_parm (tree, tree); extern bool possibly_inlined_p (tree); extern int parm_index (tree); +extern bool cp_omp_mappable_type (tree); /* in error.c */ extern void init_error (void); diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 667d6b3440062..1aa2142326990 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -1334,12 +1334,15 @@ cp_check_const_attributes (tree attributes) } /* Return true if TYPE is an OpenMP mappable type. */ -static bool +bool cp_omp_mappable_type (tree type) { /* Mappable type has to be complete. */ if (type == error_mark_node || !COMPLETE_TYPE_P (type)) return false; + /* Arrays have mappable type if the elements have mappable type. */ + while (TREE_CODE (type) == ARRAY_TYPE) + type = TREE_TYPE (type); /* A mappable type cannot contain virtual members. */ if (CLASS_TYPE_P (type) && CLASSTYPE_VTABLES (type)) return false; @@ -1350,6 +1353,10 @@ cp_omp_mappable_type (tree type) for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) if (TREE_CODE (field) == VAR_DECL) return false; + /* All fields must have mappable types. */ + else if (TREE_CODE (field) == FIELD_DECL + && !cp_omp_mappable_type (TREE_TYPE (field))) + return false; } return true; } diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index a9ebac6b9bb4d..f6b27bad9419a 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -4122,11 +4122,11 @@ handle_omp_array_sections_1 (tree c, tree t, vec &types, omp_clause_code_name[OMP_CLAUSE_CODE (c)]); return error_mark_node; } + t = convert_from_reference (t); if (!processing_template_decl && POINTER_TYPE_P (TREE_TYPE (t)) && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP) pointer_based_p = true; - t = convert_from_reference (t); return t; } @@ -4921,6 +4921,18 @@ finish_omp_clauses (tree clauses) { if (handle_omp_array_sections (c)) remove = true; + else + { + t = OMP_CLAUSE_DECL (c); + if (!cp_omp_mappable_type (TREE_TYPE (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "array section does not have mappable type " + "in %qs clause", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + } break; } if (t == error_mark_node) @@ -4947,6 +4959,16 @@ finish_omp_clauses (tree clauses) && TREE_CODE (TREE_TYPE (t)) != REFERENCE_TYPE && !cxx_mark_addressable (t)) remove = true; + else if (!cp_omp_mappable_type ((TREE_CODE (TREE_TYPE (t)) + == REFERENCE_TYPE) + ? TREE_TYPE (TREE_TYPE (t)) + : TREE_TYPE (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qD does not have a mappable type in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP) break; else if (bitmap_bit_p (&generic_head, DECL_UID (t))) From 7862439bc0bec7df3fd6d163cebca8ecea9d22cb Mon Sep 17 00:00:00 2001 From: jakub Date: Fri, 14 Jun 2013 16:49:07 +0000 Subject: [PATCH 55/63] * gimple-pretty-print.c (dump_gimple_omp_for): Don't handle GF_OMP_FOR_KIND_FOR_SIMD. * gimple.h (GF_OMP_FOR_KIND_FOR_SIMD): Remove. (GF_OMP_FOR_COMBINED): New. (gimple_omp_for_combined_p, gimple_omp_for_set_combined_p): New inline functions. * gimplify.c (is_gimple_stmt): Don't handle OMP_FOR_SIMD. (find_combined_omp_for): New function. (gimplify_omp_for): Handle combined OMP_DISTRIBUTE and OMP_FOR loops. * Makefile.in (c-family/c-omp.o): Depend on $(C_PRAGMA_H). * omp-low.c (build_outer_var_ref): Fix up simd handling. (check_omp_nesting_restrictions): Don't handle GF_OMP_FOR_KIND_FOR_SIMD. * tree.def (OMP_FOR_SIMD): Remove. * tree-pretty-print.c (dump_generic_node): Don't handle OMP_FOR_SIMD. Handle NULL OMP_FOR_INIT. c/ * c-parser.c (c_parser_omp_for): Comment out OMP_FOR_SIMD uses. (c_parser_omp_parallel): Call c_omp_split_clauses instead of c_split_parallel_clauses, adjust the code for different API of the new function. cp/ * parser.c (cp_parser_omp_all_clauses): Add defaulted finish_p argument. Don't call finish_omp_clauses if it is false. (cp_parser_omp_for_loop): Change last argument to cclauses, and adjust uses to grab parallel clauses from the array of all the split clauses. (cp_omp_split_clauses): New function. (cp_parser_omp_simd): Add p_name, mask and cclauses arguments. Allow the function to be called also when parsing combined constructs. (cp_parser_omp_sections): Likewise. (cp_parser_omp_for): Add p_name, mask and cclauses arguments. Allow the function to be called also when parsing combined constructs, and call cp_parser_omp_simd when parsing for simd. (cp_parser_omp_parallel): Likewise. (cp_parser_omp_distribute): Likewise. (cp_parser_omp_teams): Likewise. (cp_parser_omp_target): If next token is teams, call cp_parser_omp_teams and parse it as combined construct. (cp_parser_omp_declare_simd): Pass false as last argument to cp_parser_omp_all_clauses. (cp_parser_omp_construct): Adjust callers of cp_parser_omp_simd, cp_parser_omp_sections, cp_parser_omp_for, cp_parser_omp_parallel, cp_parser_omp_distribute and cp_parser_omp_teams. * pt.c (tsubst_expr): Don't handle OMP_FOR_SIMD. Handle NULL OMP_FOR_INIT. * semantics.c (finish_omp_for): Don't handle OMP_FOR_SIMD. * cp-tree.h (OMP_FOR_GIMPLIFYING_P): Adjust comment. * cp-gimplify.c (cp_gimplify_expr, cp_genericize_r): Don't handle OMP_FOR_SIMD. c-family/ * c-common.h: Move omp_clause_mask code earlier in the file. (c_omp_split_clauses): New prototype. (c_split_parallel_clauses): Removed. * c-pragma.h (enum pragma_kind): Add PRAGMA_OMP_DISTRIBUTE_PARALLEL_FOR, PRAGMA_OMP_DISTRIBUTE_PARALLEL_FOR_SIMD, PRAGMA_OMP_DISTRIBUTE_SIMD, PRAGMA_OMP_TARGET_TEAMS, PRAGMA_OMP_TARGET_TEAMS_DISTRIBUTE, PRAGMA_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_FOR, PRAGMA_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_FOR_SIMD, PRAGMA_OMP_TEAMS_DISTRIBUTE, PRAGMA_OMP_TEAMS_DISTRIBUTE_PARALLEL_FOR, and PRAGMA_OMP_TEAMS_DISTRIBUTE_PARALLEL_FOR_SIMD. * c-omp.c: Include c-pragma.h. (c_omp_split_clauses): New function. (c_split_parallel_clauses): Remove. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gomp-4_0-branch@200095 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog.gomp | 20 ++ gcc/Makefile.in | 2 +- gcc/c-family/ChangeLog.gomp | 19 ++ gcc/c-family/c-common.h | 225 ++++++++++--------- gcc/c-family/c-omp.c | 281 +++++++++++++++++++++--- gcc/c-family/c-pragma.h | 10 + gcc/c/ChangeLog.gomp | 7 + gcc/c/c-parser.c | 17 +- gcc/cp/ChangeLog.gomp | 29 +++ gcc/cp/cp-gimplify.c | 2 - gcc/cp/cp-tree.h | 3 +- gcc/cp/parser.c | 421 +++++++++++++++++++++++++----------- gcc/cp/pt.c | 39 +++- gcc/cp/semantics.c | 7 +- gcc/gimple-pretty-print.c | 6 - gcc/gimple.h | 29 ++- gcc/gimplify.c | 86 ++++++-- gcc/omp-low.c | 21 +- gcc/tree-pretty-print.c | 41 ++-- gcc/tree.def | 4 - 20 files changed, 933 insertions(+), 336 deletions(-) diff --git a/gcc/ChangeLog.gomp b/gcc/ChangeLog.gomp index 2f0519a3f7304..7f9151d2f40d2 100644 --- a/gcc/ChangeLog.gomp +++ b/gcc/ChangeLog.gomp @@ -1,3 +1,23 @@ +2013-06-14 Jakub Jelinek + + * gimple-pretty-print.c (dump_gimple_omp_for): Don't handle + GF_OMP_FOR_KIND_FOR_SIMD. + * gimple.h (GF_OMP_FOR_KIND_FOR_SIMD): Remove. + (GF_OMP_FOR_COMBINED): New. + (gimple_omp_for_combined_p, gimple_omp_for_set_combined_p): New + inline functions. + * gimplify.c (is_gimple_stmt): Don't handle OMP_FOR_SIMD. + (find_combined_omp_for): New function. + (gimplify_omp_for): Handle combined OMP_DISTRIBUTE and OMP_FOR + loops. + * Makefile.in (c-family/c-omp.o): Depend on $(C_PRAGMA_H). + * omp-low.c (build_outer_var_ref): Fix up simd handling. + (check_omp_nesting_restrictions): Don't handle + GF_OMP_FOR_KIND_FOR_SIMD. + * tree.def (OMP_FOR_SIMD): Remove. + * tree-pretty-print.c (dump_generic_node): Don't handle OMP_FOR_SIMD. + Handle NULL OMP_FOR_INIT. + 2013-06-12 Jakub Jelinek * gimplify.c (gimplify_scan_omp_clauses): Handle diff --git a/gcc/Makefile.in b/gcc/Makefile.in index dd0a44f0a1655..3491160064d37 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1976,7 +1976,7 @@ c-family/c-lex.o : c-family/c-lex.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ $(CPPLIB_H) $(TARGET_H) $(TIMEVAR_H) c-family/c-omp.o : c-family/c-omp.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ - $(TREE_H) $(C_COMMON_H) $(GIMPLE_H) langhooks.h + $(TREE_H) $(C_COMMON_H) $(C_PRAGMA_H) $(GIMPLE_H) langhooks.h CFLAGS-c-family/c-opts.o += @TARGET_SYSTEM_ROOT_DEFINE@ c-family/c-opts.o : c-family/c-opts.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ diff --git a/gcc/c-family/ChangeLog.gomp b/gcc/c-family/ChangeLog.gomp index abc1aae63477f..5a6e3d8d6691e 100644 --- a/gcc/c-family/ChangeLog.gomp +++ b/gcc/c-family/ChangeLog.gomp @@ -1,3 +1,22 @@ +2013-06-14 Jakub Jelinek + + * c-common.h: Move omp_clause_mask code earlier in the file. + (c_omp_split_clauses): New prototype. + (c_split_parallel_clauses): Removed. + * c-pragma.h (enum pragma_kind): Add + PRAGMA_OMP_DISTRIBUTE_PARALLEL_FOR, + PRAGMA_OMP_DISTRIBUTE_PARALLEL_FOR_SIMD, + PRAGMA_OMP_DISTRIBUTE_SIMD, PRAGMA_OMP_TARGET_TEAMS, + PRAGMA_OMP_TARGET_TEAMS_DISTRIBUTE, + PRAGMA_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_FOR, + PRAGMA_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_FOR_SIMD, + PRAGMA_OMP_TEAMS_DISTRIBUTE, + PRAGMA_OMP_TEAMS_DISTRIBUTE_PARALLEL_FOR, + and PRAGMA_OMP_TEAMS_DISTRIBUTE_PARALLEL_FOR_SIMD. + * c-omp.c: Include c-pragma.h. + (c_omp_split_clauses): New function. + (c_split_parallel_clauses): Remove. + 2013-06-12 Jakub Jelinek * c-pragma.h (enum pragma_omp_clause): Add diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index 78ace779cb266..fdbe29f1f0a2f 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -1030,112 +1030,6 @@ extern void pp_dir_change (cpp_reader *, const char *); extern bool check_missing_format_attribute (tree, tree); /* In c-omp.c */ -extern tree c_finish_omp_master (location_t, tree); -extern tree c_finish_omp_critical (location_t, tree, tree); -extern tree c_finish_omp_ordered (location_t, tree); -extern void c_finish_omp_barrier (location_t); -extern tree c_finish_omp_atomic (location_t, enum tree_code, enum tree_code, - tree, tree, tree, tree, tree, bool, bool); -extern void c_finish_omp_flush (location_t); -extern void c_finish_omp_taskwait (location_t); -extern void c_finish_omp_taskyield (location_t); -extern tree c_finish_omp_for (location_t, enum tree_code, tree, tree, tree, - tree, tree, tree); -extern void c_split_parallel_clauses (location_t, tree, tree *, tree *); -extern tree c_omp_declare_simd_clauses_to_numbers (tree, tree); -extern void c_omp_declare_simd_clauses_to_decls (tree, tree); -extern enum omp_clause_default_kind c_omp_predetermined_sharing (tree); - -/* Not in c-omp.c; provided by the front end. */ -extern bool c_omp_sharing_predetermined (tree); -extern tree c_omp_remap_decl (tree, bool); -extern void record_types_used_by_current_var_decl (tree); - -/* Return next tree in the chain for chain_next walking of tree nodes. */ -static inline tree -c_tree_chain_next (tree t) -{ - /* TREE_CHAIN of a type is TYPE_STUB_DECL, which is different - kind of object, never a long chain of nodes. Prefer - TYPE_NEXT_VARIANT for types. */ - if (CODE_CONTAINS_STRUCT (TREE_CODE (t), TS_TYPE_COMMON)) - return TYPE_NEXT_VARIANT (t); - /* Otherwise, if there is TREE_CHAIN, return it. */ - if (CODE_CONTAINS_STRUCT (TREE_CODE (t), TS_COMMON)) - return TREE_CHAIN (t); - return NULL; -} - -/* Mask used by tm_stmt_attr. */ -#define TM_STMT_ATTR_OUTER 2 -#define TM_STMT_ATTR_ATOMIC 4 -#define TM_STMT_ATTR_RELAXED 8 - -extern int parse_tm_stmt_attr (tree, int); - -/* Mask used by tm_attr_to_mask and tm_mask_to_attr. Note that these - are ordered specifically such that more restrictive attributes are - at lower bit positions. This fact is known by the C++ tm attribute - inheritance code such that least bit extraction (mask & -mask) results - in the most restrictive attribute. */ -#define TM_ATTR_SAFE 1 -#define TM_ATTR_CALLABLE 2 -#define TM_ATTR_PURE 4 -#define TM_ATTR_IRREVOCABLE 8 -#define TM_ATTR_MAY_CANCEL_OUTER 16 - -extern int tm_attr_to_mask (tree); -extern tree tm_mask_to_attr (int); -extern tree find_tm_attribute (tree); - -/* A suffix-identifier value doublet that represents user-defined literals - for C++-0x. */ -enum overflow_type { - OT_UNDERFLOW = -1, - OT_NONE, - OT_OVERFLOW -}; - -struct GTY(()) tree_userdef_literal { - struct tree_base base; - tree suffix_id; - tree value; - tree num_string; - enum overflow_type overflow; -}; - -#define USERDEF_LITERAL_SUFFIX_ID(NODE) \ - (((struct tree_userdef_literal *)USERDEF_LITERAL_CHECK (NODE))->suffix_id) - -#define USERDEF_LITERAL_VALUE(NODE) \ - (((struct tree_userdef_literal *)USERDEF_LITERAL_CHECK (NODE))->value) - -#define USERDEF_LITERAL_OVERFLOW(NODE) \ - (((struct tree_userdef_literal *)USERDEF_LITERAL_CHECK (NODE))->overflow) - -#define USERDEF_LITERAL_NUM_STRING(NODE) \ - (((struct tree_userdef_literal *)USERDEF_LITERAL_CHECK (NODE))->num_string) - -#define USERDEF_LITERAL_TYPE(NODE) \ - (TREE_TYPE (USERDEF_LITERAL_VALUE (NODE))) - -extern tree build_userdef_literal (tree suffix_id, tree value, - enum overflow_type overflow, - tree num_string); - -extern void convert_vector_to_pointer_for_subscript (location_t, tree*, tree); - -/* Possibe cases of scalar_to_vector conversion. */ -enum stv_conv { - stv_error, /* Error occured. */ - stv_nothing, /* Nothing happened. */ - stv_firstarg, /* First argument must be expanded. */ - stv_secondarg /* Second argument must be expanded. */ -}; - -extern enum stv_conv scalar_to_vector (location_t loc, enum tree_code code, - tree op0, tree op1, bool); - #if HOST_BITS_PER_WIDE_INT >= 64 typedef unsigned HOST_WIDE_INT omp_clause_mask; # define OMP_CLAUSE_MASK_1 ((omp_clause_mask) 1) @@ -1261,4 +1155,123 @@ omp_clause_mask::operator == (omp_clause_mask b) const # define OMP_CLAUSE_MASK_1 omp_clause_mask (1) #endif +enum c_omp_clause_split +{ + C_OMP_CLAUSE_SPLIT_TARGET = 0, + C_OMP_CLAUSE_SPLIT_TEAMS, + C_OMP_CLAUSE_SPLIT_DISTRIBUTE, + C_OMP_CLAUSE_SPLIT_PARALLEL, + C_OMP_CLAUSE_SPLIT_FOR, + C_OMP_CLAUSE_SPLIT_SIMD, + C_OMP_CLAUSE_SPLIT_COUNT, + C_OMP_CLAUSE_SPLIT_SECTIONS = C_OMP_CLAUSE_SPLIT_FOR +}; + +extern tree c_finish_omp_master (location_t, tree); +extern tree c_finish_omp_critical (location_t, tree, tree); +extern tree c_finish_omp_ordered (location_t, tree); +extern void c_finish_omp_barrier (location_t); +extern tree c_finish_omp_atomic (location_t, enum tree_code, enum tree_code, + tree, tree, tree, tree, tree, bool, bool); +extern void c_finish_omp_flush (location_t); +extern void c_finish_omp_taskwait (location_t); +extern void c_finish_omp_taskyield (location_t); +extern tree c_finish_omp_for (location_t, enum tree_code, tree, tree, tree, + tree, tree, tree); +extern void c_omp_split_clauses (location_t, enum tree_code, omp_clause_mask, + tree, tree *); +extern tree c_omp_declare_simd_clauses_to_numbers (tree, tree); +extern void c_omp_declare_simd_clauses_to_decls (tree, tree); +extern enum omp_clause_default_kind c_omp_predetermined_sharing (tree); + +/* Not in c-omp.c; provided by the front end. */ +extern bool c_omp_sharing_predetermined (tree); +extern tree c_omp_remap_decl (tree, bool); +extern void record_types_used_by_current_var_decl (tree); + +/* Return next tree in the chain for chain_next walking of tree nodes. */ +static inline tree +c_tree_chain_next (tree t) +{ + /* TREE_CHAIN of a type is TYPE_STUB_DECL, which is different + kind of object, never a long chain of nodes. Prefer + TYPE_NEXT_VARIANT for types. */ + if (CODE_CONTAINS_STRUCT (TREE_CODE (t), TS_TYPE_COMMON)) + return TYPE_NEXT_VARIANT (t); + /* Otherwise, if there is TREE_CHAIN, return it. */ + if (CODE_CONTAINS_STRUCT (TREE_CODE (t), TS_COMMON)) + return TREE_CHAIN (t); + return NULL; +} + +/* Mask used by tm_stmt_attr. */ +#define TM_STMT_ATTR_OUTER 2 +#define TM_STMT_ATTR_ATOMIC 4 +#define TM_STMT_ATTR_RELAXED 8 + +extern int parse_tm_stmt_attr (tree, int); + +/* Mask used by tm_attr_to_mask and tm_mask_to_attr. Note that these + are ordered specifically such that more restrictive attributes are + at lower bit positions. This fact is known by the C++ tm attribute + inheritance code such that least bit extraction (mask & -mask) results + in the most restrictive attribute. */ +#define TM_ATTR_SAFE 1 +#define TM_ATTR_CALLABLE 2 +#define TM_ATTR_PURE 4 +#define TM_ATTR_IRREVOCABLE 8 +#define TM_ATTR_MAY_CANCEL_OUTER 16 + +extern int tm_attr_to_mask (tree); +extern tree tm_mask_to_attr (int); +extern tree find_tm_attribute (tree); + +/* A suffix-identifier value doublet that represents user-defined literals + for C++-0x. */ +enum overflow_type { + OT_UNDERFLOW = -1, + OT_NONE, + OT_OVERFLOW +}; + +struct GTY(()) tree_userdef_literal { + struct tree_base base; + tree suffix_id; + tree value; + tree num_string; + enum overflow_type overflow; +}; + +#define USERDEF_LITERAL_SUFFIX_ID(NODE) \ + (((struct tree_userdef_literal *)USERDEF_LITERAL_CHECK (NODE))->suffix_id) + +#define USERDEF_LITERAL_VALUE(NODE) \ + (((struct tree_userdef_literal *)USERDEF_LITERAL_CHECK (NODE))->value) + +#define USERDEF_LITERAL_OVERFLOW(NODE) \ + (((struct tree_userdef_literal *)USERDEF_LITERAL_CHECK (NODE))->overflow) + +#define USERDEF_LITERAL_NUM_STRING(NODE) \ + (((struct tree_userdef_literal *)USERDEF_LITERAL_CHECK (NODE))->num_string) + +#define USERDEF_LITERAL_TYPE(NODE) \ + (TREE_TYPE (USERDEF_LITERAL_VALUE (NODE))) + +extern tree build_userdef_literal (tree suffix_id, tree value, + enum overflow_type overflow, + tree num_string); + +extern void convert_vector_to_pointer_for_subscript (location_t, tree*, tree); + +/* Possibe cases of scalar_to_vector conversion. */ +enum stv_conv { + stv_error, /* Error occured. */ + stv_nothing, /* Nothing happened. */ + stv_firstarg, /* First argument must be expanded. */ + stv_secondarg /* Second argument must be expanded. */ +}; + +extern enum stv_conv scalar_to_vector (location_t loc, enum tree_code code, + tree op0, tree op1, bool); + #endif /* ! GCC_C_COMMON_H */ diff --git a/gcc/c-family/c-omp.c b/gcc/c-family/c-omp.c index 941854bf36725..f80c73b028fff 100644 --- a/gcc/c-family/c-omp.c +++ b/gcc/c-family/c-omp.c @@ -26,6 +26,7 @@ along with GCC; see the file COPYING3. If not see #include "coretypes.h" #include "tree.h" #include "c-common.h" +#include "c-pragma.h" #include "gimple.h" /* For create_tmp_var_raw. */ #include "langhooks.h" @@ -585,21 +586,55 @@ c_finish_omp_for (location_t locus, enum tree_code code, tree declv, } } - -/* Divide CLAUSES into two lists: those that apply to a parallel - construct, and those that apply to a work-sharing construct. Place - the results in *PAR_CLAUSES and *WS_CLAUSES respectively. In - addition, add a nowait clause to the work-sharing list. LOC is the - location of the OMP_PARALLEL*. */ +/* Right now we have 14 different combined constructs, this + function attempts to split or duplicate clauses for combined + constructs. CODE is the innermost construct in the combined construct, + and MASK allows to determine which constructs are combined together, + as every construct has at least one clause that no other construct + has (except for OMP_SECTIONS, but that can be only combined with parallel). + Combined constructs are: + #pragma omp parallel for + #pragma omp parallel sections + #pragma omp parallel for simd + #pragma omp for simd + #pragma omp distribute simd + #pragma omp distribute parallel for + #pragma omp distribute parallel for simd + #pragma omp teams distribute + #pragma omp teams distribute parallel for + #pragma omp teams distribute parallel for simd + #pragma omp target teams + #pragma omp target teams distribute + #pragma omp target teams distribute parallel for + #pragma omp target teams distribute parallel for simd */ void -c_split_parallel_clauses (location_t loc, tree clauses, - tree *par_clauses, tree *ws_clauses) +c_omp_split_clauses (location_t loc, enum tree_code code, + omp_clause_mask mask, tree clauses, tree *cclauses) { - tree next; + tree next, c; + enum c_omp_clause_split s; + int i; - *par_clauses = NULL; - *ws_clauses = build_omp_clause (loc, OMP_CLAUSE_NOWAIT); + for (i = 0; i < C_OMP_CLAUSE_SPLIT_COUNT; i++) + cclauses[i] = NULL; + /* Add implicit nowait clause on + #pragma omp parallel {for,for simd,sections}. */ + if (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS)) + switch (code) + { + case OMP_FOR: + case OMP_SIMD: + cclauses[C_OMP_CLAUSE_SPLIT_FOR] + = build_omp_clause (loc, OMP_CLAUSE_NOWAIT); + break; + case OMP_SECTIONS: + cclauses[C_OMP_CLAUSE_SPLIT_SECTIONS] + = build_omp_clause (loc, OMP_CLAUSE_NOWAIT); + break; + default: + break; + } for (; clauses ; clauses = next) { @@ -607,36 +642,228 @@ c_split_parallel_clauses (location_t loc, tree clauses, switch (OMP_CLAUSE_CODE (clauses)) { - case OMP_CLAUSE_PRIVATE: - case OMP_CLAUSE_SHARED: - case OMP_CLAUSE_FIRSTPRIVATE: - case OMP_CLAUSE_LASTPRIVATE: - case OMP_CLAUSE_REDUCTION: + /* First the clauses that are unique to some constructs. */ + case OMP_CLAUSE_DEVICE: + case OMP_CLAUSE_MAP: + s = C_OMP_CLAUSE_SPLIT_TARGET; + break; + case OMP_CLAUSE_NUM_TEAMS: + case OMP_CLAUSE_THREAD_LIMIT: + s = C_OMP_CLAUSE_SPLIT_TEAMS; + break; + case OMP_CLAUSE_DIST_SCHEDULE: + s = C_OMP_CLAUSE_SPLIT_DISTRIBUTE; + break; case OMP_CLAUSE_COPYIN: - case OMP_CLAUSE_IF: case OMP_CLAUSE_NUM_THREADS: - case OMP_CLAUSE_DEFAULT: case OMP_CLAUSE_PROC_BIND: - OMP_CLAUSE_CHAIN (clauses) = *par_clauses; - *par_clauses = clauses; + s = C_OMP_CLAUSE_SPLIT_PARALLEL; break; - - case OMP_CLAUSE_SCHEDULE: case OMP_CLAUSE_ORDERED: - case OMP_CLAUSE_COLLAPSE: + case OMP_CLAUSE_SCHEDULE: + case OMP_CLAUSE_NOWAIT: + s = C_OMP_CLAUSE_SPLIT_FOR; + break; case OMP_CLAUSE_SAFELEN: - case OMP_CLAUSE_ALIGNED: case OMP_CLAUSE_LINEAR: - OMP_CLAUSE_CHAIN (clauses) = *ws_clauses; - *ws_clauses = clauses; + case OMP_CLAUSE_ALIGNED: + s = C_OMP_CLAUSE_SPLIT_SIMD; + break; + /* Duplicate this to all of distribute, for and simd. */ + case OMP_CLAUSE_COLLAPSE: + if (code == OMP_SIMD) + { + c = build_omp_clause (OMP_CLAUSE_LOCATION (clauses), + OMP_CLAUSE_COLLAPSE); + OMP_CLAUSE_COLLAPSE_EXPR (c) + = OMP_CLAUSE_COLLAPSE_EXPR (clauses); + OMP_CLAUSE_CHAIN (c) = cclauses[C_OMP_CLAUSE_SPLIT_SIMD]; + cclauses[C_OMP_CLAUSE_SPLIT_SIMD] = c; + } + if (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS)) + { + if (mask & (OMP_CLAUSE_MASK_1 + << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)) + { + c = build_omp_clause (OMP_CLAUSE_LOCATION (clauses), + OMP_CLAUSE_COLLAPSE); + OMP_CLAUSE_COLLAPSE_EXPR (c) + = OMP_CLAUSE_COLLAPSE_EXPR (clauses); + OMP_CLAUSE_CHAIN (c) = cclauses[C_OMP_CLAUSE_SPLIT_FOR]; + cclauses[C_OMP_CLAUSE_SPLIT_FOR] = c; + s = C_OMP_CLAUSE_SPLIT_DISTRIBUTE; + } + else + s = C_OMP_CLAUSE_SPLIT_FOR; + } + else + s = C_OMP_CLAUSE_SPLIT_DISTRIBUTE; + break; + /* Private clause is supported on all constructs but target, + it is enough to put it on the innermost one. For + #pragma omp {for,sections} put it on parallel though, + as that's what we did for OpenMP 3.1. */ + case OMP_CLAUSE_PRIVATE: + switch (code) + { + case OMP_SIMD: s = C_OMP_CLAUSE_SPLIT_SIMD; break; + case OMP_FOR: case OMP_SECTIONS: + case OMP_PARALLEL: s = C_OMP_CLAUSE_SPLIT_PARALLEL; break; + case OMP_DISTRIBUTE: s = C_OMP_CLAUSE_SPLIT_DISTRIBUTE; break; + case OMP_TEAMS: s = C_OMP_CLAUSE_SPLIT_TEAMS; break; + default: gcc_unreachable (); + } + break; + /* Firstprivate clause is supported on all constructs but + target and simd. Put it on the outermost of those and + duplicate on parallel. */ + case OMP_CLAUSE_FIRSTPRIVATE: + if (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS)) + { + if (mask & ((OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_TEAMS) + | (OMP_CLAUSE_MASK_1 + << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE))) + { + c = build_omp_clause (OMP_CLAUSE_LOCATION (clauses), + OMP_CLAUSE_FIRSTPRIVATE); + OMP_CLAUSE_DECL (c) = OMP_CLAUSE_DECL (clauses); + OMP_CLAUSE_CHAIN (c) = cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL]; + cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL] = c; + if (mask & (OMP_CLAUSE_MASK_1 + << PRAGMA_OMP_CLAUSE_NUM_TEAMS)) + s = C_OMP_CLAUSE_SPLIT_TEAMS; + else + s = C_OMP_CLAUSE_SPLIT_DISTRIBUTE; + } + else + /* This must be + #pragma omp parallel{, for{, simd}, sections}. */ + s = C_OMP_CLAUSE_SPLIT_PARALLEL; + } + else if (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_TEAMS)) + { + /* This must be #pragma omp {,target }teams distribute. */ + gcc_assert (code == OMP_DISTRIBUTE); + s = C_OMP_CLAUSE_SPLIT_TEAMS; + } + else if (mask & (OMP_CLAUSE_MASK_1 + << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)) + { + /* This must be #pragma omp distribute simd. */ + gcc_assert (code == OMP_SIMD); + s = C_OMP_CLAUSE_SPLIT_TEAMS; + } + else + { + /* This must be #pragma omp for simd. */ + gcc_assert (code == OMP_SIMD); + s = C_OMP_CLAUSE_SPLIT_FOR; + } + break; + /* Lastprivate is allowed on for, sections and simd. In + parallel {for{, simd},sections} we actually want to put it on + parallel rather than for or sections. */ + case OMP_CLAUSE_LASTPRIVATE: + if (code == OMP_FOR || code == OMP_SECTIONS) + { + if (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS)) + s = C_OMP_CLAUSE_SPLIT_PARALLEL; + else + s = C_OMP_CLAUSE_SPLIT_FOR; + break; + } + gcc_assert (code == OMP_SIMD); + if (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SCHEDULE)) + { + c = build_omp_clause (OMP_CLAUSE_LOCATION (clauses), + OMP_CLAUSE_LASTPRIVATE); + OMP_CLAUSE_DECL (c) = OMP_CLAUSE_DECL (clauses); + if (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS)) + s = C_OMP_CLAUSE_SPLIT_PARALLEL; + else + s = C_OMP_CLAUSE_SPLIT_FOR; + OMP_CLAUSE_CHAIN (c) = cclauses[s]; + cclauses[s] = c; + } + s = C_OMP_CLAUSE_SPLIT_SIMD; + break; + /* Shared and default clauses are allowed on private and teams. */ + case OMP_CLAUSE_SHARED: + case OMP_CLAUSE_DEFAULT: + if (code == OMP_TEAMS) + { + s = C_OMP_CLAUSE_SPLIT_TEAMS; + break; + } + if (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_TEAMS)) + { + c = build_omp_clause (OMP_CLAUSE_LOCATION (clauses), + OMP_CLAUSE_CODE (clauses)); + if (OMP_CLAUSE_CODE (clauses) == OMP_CLAUSE_SHARED) + OMP_CLAUSE_DECL (c) = OMP_CLAUSE_DECL (clauses); + else + OMP_CLAUSE_DEFAULT_KIND (c) + = OMP_CLAUSE_DEFAULT_KIND (clauses); + OMP_CLAUSE_CHAIN (c) = cclauses[C_OMP_CLAUSE_SPLIT_TEAMS]; + cclauses[C_OMP_CLAUSE_SPLIT_TEAMS] = c; + + } + s = C_OMP_CLAUSE_SPLIT_PARALLEL; + break; + /* Reduction is allowed on simd, for, parallel, sections and teams. + Duplicate it on all of them, but omit on for or sections if + parallel is present. */ + case OMP_CLAUSE_REDUCTION: + if (code == OMP_SIMD) + { + c = build_omp_clause (OMP_CLAUSE_LOCATION (clauses), + OMP_CLAUSE_REDUCTION); + OMP_CLAUSE_DECL (c) = OMP_CLAUSE_DECL (clauses); + OMP_CLAUSE_REDUCTION_CODE (c) + = OMP_CLAUSE_REDUCTION_CODE (clauses); + OMP_CLAUSE_CHAIN (c) = cclauses[C_OMP_CLAUSE_SPLIT_SIMD]; + cclauses[C_OMP_CLAUSE_SPLIT_SIMD] = c; + } + if (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SCHEDULE)) + { + if (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_TEAMS)) + { + c = build_omp_clause (OMP_CLAUSE_LOCATION (clauses), + OMP_CLAUSE_REDUCTION); + OMP_CLAUSE_DECL (c) = OMP_CLAUSE_DECL (clauses); + OMP_CLAUSE_REDUCTION_CODE (c) + = OMP_CLAUSE_REDUCTION_CODE (clauses); + OMP_CLAUSE_CHAIN (c) = cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL]; + cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL] = c; + s = C_OMP_CLAUSE_SPLIT_TEAMS; + } + else if (mask & (OMP_CLAUSE_MASK_1 + << PRAGMA_OMP_CLAUSE_NUM_THREADS)) + s = C_OMP_CLAUSE_SPLIT_PARALLEL; + else + s = C_OMP_CLAUSE_SPLIT_FOR; + } + else if (code == OMP_SECTIONS) + s = C_OMP_CLAUSE_SPLIT_PARALLEL; + else + s = C_OMP_CLAUSE_SPLIT_TEAMS; + break; + case OMP_CLAUSE_IF: + /* FIXME: This is currently being discussed. */ + if (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS)) + s = C_OMP_CLAUSE_SPLIT_PARALLEL; + else + s = C_OMP_CLAUSE_SPLIT_TARGET; break; - default: gcc_unreachable (); } + OMP_CLAUSE_CHAIN (clauses) = cclauses[s]; + cclauses[s] = clauses; } } + /* qsort callback to compare #pragma omp declare simd clauses. */ static int diff --git a/gcc/c-family/c-pragma.h b/gcc/c-family/c-pragma.h index a104c7ce9e886..ef4c786df06d4 100644 --- a/gcc/c-family/c-pragma.h +++ b/gcc/c-family/c-pragma.h @@ -36,6 +36,9 @@ typedef enum pragma_kind { PRAGMA_OMP_DECLARE_SIMD, PRAGMA_OMP_DECLARE_TARGET, PRAGMA_OMP_DISTRIBUTE, + PRAGMA_OMP_DISTRIBUTE_PARALLEL_FOR, + PRAGMA_OMP_DISTRIBUTE_PARALLEL_FOR_SIMD, + PRAGMA_OMP_DISTRIBUTE_SIMD, PRAGMA_OMP_END_DECLARE_TARGET, PRAGMA_OMP_FLUSH, PRAGMA_OMP_FOR, @@ -52,6 +55,10 @@ typedef enum pragma_kind { PRAGMA_OMP_SINGLE, PRAGMA_OMP_TARGET, PRAGMA_OMP_TARGET_DATA, + PRAGMA_OMP_TARGET_TEAMS, + PRAGMA_OMP_TARGET_TEAMS_DISTRIBUTE, + PRAGMA_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_FOR, + PRAGMA_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_FOR_SIMD, PRAGMA_OMP_TARGET_UPDATE, PRAGMA_OMP_TASK, PRAGMA_OMP_TASKGROUP, @@ -59,6 +66,9 @@ typedef enum pragma_kind { PRAGMA_OMP_TASKYIELD, PRAGMA_OMP_THREADPRIVATE, PRAGMA_OMP_TEAMS, + PRAGMA_OMP_TEAMS_DISTRIBUTE, + PRAGMA_OMP_TEAMS_DISTRIBUTE_PARALLEL_FOR, + PRAGMA_OMP_TEAMS_DISTRIBUTE_PARALLEL_FOR_SIMD, PRAGMA_GCC_PCH_PREPROCESS, diff --git a/gcc/c/ChangeLog.gomp b/gcc/c/ChangeLog.gomp index 816a4acc0149c..463d392ffc105 100644 --- a/gcc/c/ChangeLog.gomp +++ b/gcc/c/ChangeLog.gomp @@ -1,3 +1,10 @@ +2013-06-14 Jakub Jelinek + + * c-parser.c (c_parser_omp_for): Comment out OMP_FOR_SIMD uses. + (c_parser_omp_parallel): Call c_omp_split_clauses instead of + c_split_parallel_clauses, adjust the code for different API + of the new function. + 2013-05-13 Jakub Jelinek * c-tree.h (c_finish_omp_declare_simd): New prototype. diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index dbfaf13c72da7..6f0d0169ebb11 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -11044,7 +11044,7 @@ c_parser_omp_for (location_t loc, c_parser *parser) if (strcmp (p, "simd") == 0) { c_parser_consume_token (parser); - code = OMP_FOR_SIMD; + /* code = OMP_FOR_SIMD; */ mask |= OMP_SIMD_CLAUSE_MASK; p_name = "#pragma omp for simd"; } @@ -11234,6 +11234,7 @@ c_parser_omp_parallel (location_t loc, c_parser *parser) const char *p_name = "#pragma omp parallel"; tree stmt, clauses, par_clause, ws_clause, block; omp_clause_mask mask = OMP_PARALLEL_CLAUSE_MASK; + tree cclauses[C_OMP_CLAUSE_SPLIT_COUNT]; if (c_parser_next_token_is_keyword (parser, RID_FOR)) { @@ -11280,7 +11281,9 @@ c_parser_omp_parallel (location_t loc, c_parser *parser) case PRAGMA_OMP_PARALLEL_FOR: block = c_begin_omp_parallel (); - c_split_parallel_clauses (loc, clauses, &par_clause, &ws_clause); + c_omp_split_clauses (loc, OMP_FOR, mask, clauses, cclauses); + par_clause = cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL]; + ws_clause = cclauses[C_OMP_CLAUSE_SPLIT_FOR]; c_parser_omp_for_loop (loc, parser, OMP_FOR, ws_clause, &par_clause); stmt = c_finish_omp_parallel (loc, par_clause, block); OMP_PARALLEL_COMBINED (stmt) = 1; @@ -11288,8 +11291,10 @@ c_parser_omp_parallel (location_t loc, c_parser *parser) case PRAGMA_OMP_PARALLEL_FOR_SIMD: block = c_begin_omp_parallel (); - c_split_parallel_clauses (loc, clauses, &par_clause, &ws_clause); - c_parser_omp_for_loop (loc, parser, OMP_FOR_SIMD, ws_clause, + c_omp_split_clauses (loc, OMP_FOR, mask, clauses, cclauses); + par_clause = cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL]; + ws_clause = cclauses[C_OMP_CLAUSE_SPLIT_FOR]; + c_parser_omp_for_loop (loc, parser, OMP_FOR /*_SIMD*/, ws_clause, &par_clause); stmt = c_finish_omp_parallel (loc, par_clause, block); OMP_PARALLEL_COMBINED (stmt) = 1; @@ -11297,7 +11302,9 @@ c_parser_omp_parallel (location_t loc, c_parser *parser) case PRAGMA_OMP_PARALLEL_SECTIONS: block = c_begin_omp_parallel (); - c_split_parallel_clauses (loc, clauses, &par_clause, &ws_clause); + c_omp_split_clauses (loc, OMP_SECTIONS, mask, clauses, cclauses); + par_clause = cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL]; + ws_clause = cclauses[C_OMP_CLAUSE_SPLIT_SECTIONS]; stmt = c_parser_omp_sections_scope (loc, parser); if (stmt) OMP_SECTIONS_CLAUSES (stmt) = ws_clause; diff --git a/gcc/cp/ChangeLog.gomp b/gcc/cp/ChangeLog.gomp index 89c5fce276779..08f2ed92daad3 100644 --- a/gcc/cp/ChangeLog.gomp +++ b/gcc/cp/ChangeLog.gomp @@ -1,5 +1,34 @@ 2013-06-14 Jakub Jelinek + * parser.c (cp_parser_omp_all_clauses): Add defaulted finish_p + argument. Don't call finish_omp_clauses if it is false. + (cp_parser_omp_for_loop): Change last argument to cclauses, + and adjust uses to grab parallel clauses from the array of all + the split clauses. + (cp_omp_split_clauses): New function. + (cp_parser_omp_simd): Add p_name, mask and cclauses arguments. + Allow the function to be called also when parsing combined constructs. + (cp_parser_omp_sections): Likewise. + (cp_parser_omp_for): Add p_name, mask and cclauses arguments. + Allow the function to be called also when parsing combined constructs, + and call cp_parser_omp_simd when parsing for simd. + (cp_parser_omp_parallel): Likewise. + (cp_parser_omp_distribute): Likewise. + (cp_parser_omp_teams): Likewise. + (cp_parser_omp_target): If next token is teams, call + cp_parser_omp_teams and parse it as combined construct. + (cp_parser_omp_declare_simd): Pass false as last argument to + cp_parser_omp_all_clauses. + (cp_parser_omp_construct): Adjust callers of cp_parser_omp_simd, + cp_parser_omp_sections, cp_parser_omp_for, cp_parser_omp_parallel, + cp_parser_omp_distribute and cp_parser_omp_teams. + * pt.c (tsubst_expr): Don't handle OMP_FOR_SIMD. Handle NULL + OMP_FOR_INIT. + * semantics.c (finish_omp_for): Don't handle OMP_FOR_SIMD. + * cp-tree.h (OMP_FOR_GIMPLIFYING_P): Adjust comment. + * cp-gimplify.c (cp_gimplify_expr, cp_genericize_r): Don't handle + OMP_FOR_SIMD. + * decl2.c (cp_omp_mappable_type): No longer static. Handle array types and recurse for FIELD_DECL types. * semantics.c (handle_omp_array_sections_1): Call diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c index 5ea7bf18d41a6..0dfa4a2034c3f 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -670,7 +670,6 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) case OMP_FOR: case OMP_SIMD: - case OMP_FOR_SIMD: case OMP_DISTRIBUTE: ret = cp_gimplify_omp_for (expr_p, pre_p); break; @@ -1121,7 +1120,6 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data) genericize_break_stmt (stmt_p); else if (TREE_CODE (stmt) == OMP_FOR || TREE_CODE (stmt) == OMP_SIMD - || TREE_CODE (stmt) == OMP_FOR_SIMD || TREE_CODE (stmt) == OMP_DISTRIBUTE) genericize_omp_for_stmt (stmt_p, walk_subtrees, data); else if (TREE_CODE (stmt) == SIZEOF_EXPR) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index f403068d414b3..df28b951e51e7 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -60,8 +60,7 @@ c-common.h, not after. STMT_EXPR_NO_SCOPE (in STMT_EXPR) BIND_EXPR_TRY_BLOCK (in BIND_EXPR) TYPENAME_IS_ENUM_P (in TYPENAME_TYPE) - OMP_FOR_GIMPLIFYING_P (in OMP_FOR, OMP_SIMD, OMP_FOR_SIMD - and OMP_DISTRIBUTE) + OMP_FOR_GIMPLIFYING_P (in OMP_FOR, OMP_SIMD and OMP_DISTRIBUTE) BASELINK_QUALIFIED_P (in BASELINK) TARGET_EXPR_IMPLICIT_P (in TARGET_EXPR) TEMPLATE_PARM_PARAMETER_PACK (in TEMPLATE_PARM_INDEX) diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 9fd0ea444f907..70d477b48e0e9 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -27299,7 +27299,8 @@ cp_parser_omp_clause_proc_bind (cp_parser *parser, tree list, static tree cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask, - const char *where, cp_token *pragma_tok) + const char *where, cp_token *pragma_tok, + bool finish_p = true) { tree clauses = NULL; bool first = true; @@ -27526,9 +27527,9 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask, } saw_error: cp_parser_skip_to_pragma_eol (parser, pragma_tok); - if (parser->omp_declare_simd_clauses) - return clauses; - return finish_omp_clauses (clauses); + if (finish_p) + return finish_omp_clauses (clauses); + return clauses; } /* OpenMP 2.5: @@ -28202,7 +28203,7 @@ cp_parser_omp_for_incr (cp_parser *parser, tree decl) static tree cp_parser_omp_for_loop (cp_parser *parser, enum tree_code code, tree clauses, - tree *par_clauses) + tree *cclauses) { tree init, cond, incr, body, decl, pre_body = NULL_TREE, ret; tree real_decl, initv, condv, incrv, declv; @@ -28412,10 +28413,12 @@ cp_parser_omp_for_loop (cp_parser *parser, enum tree_code code, tree clauses, if (decl) real_decl = decl; - if (par_clauses != NULL && real_decl != NULL_TREE) + if (cclauses != NULL + && cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL] != NULL + && real_decl != NULL_TREE) { tree *c; - for (c = par_clauses; *c ; ) + for (c = &cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL]; *c ; ) if (OMP_CLAUSE_CODE (*c) == OMP_CLAUSE_FIRSTPRIVATE && OMP_CLAUSE_DECL (*c) == real_decl) { @@ -28594,6 +28597,20 @@ cp_parser_omp_for_loop (cp_parser *parser, enum tree_code code, tree clauses, return ret; } +/* Helper function for OpenMP parsing, split clauses and call + finish_omp_clauses on each of the set of clauses afterwards. */ + +static void +cp_omp_split_clauses (location_t loc, enum tree_code code, + omp_clause_mask mask, tree clauses, tree *cclauses) +{ + int i; + c_omp_split_clauses (loc, code, mask, clauses, cclauses); + for (i = 0; i < C_OMP_CLAUSE_SPLIT_COUNT; i++) + if (cclauses[i]) + cclauses[i] = finish_omp_clauses (cclauses[i]); +} + /* OpenMP 4.0: #pragma omp simd simd-clause[optseq] new-line for-loop */ @@ -28608,18 +28625,29 @@ cp_parser_omp_for_loop (cp_parser *parser, enum tree_code code, tree clauses, | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE)) static tree -cp_parser_omp_simd (cp_parser *parser, cp_token *pragma_tok) +cp_parser_omp_simd (cp_parser *parser, cp_token *pragma_tok, + char *p_name, omp_clause_mask mask, tree *cclauses) { tree clauses, sb, ret; unsigned int save; + location_t loc = cp_lexer_peek_token (parser->lexer)->location; + + strcat (p_name, " simd"); + mask |= OMP_SIMD_CLAUSE_MASK; + mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDERED); - clauses = cp_parser_omp_all_clauses (parser, OMP_SIMD_CLAUSE_MASK, - "#pragma omp simd", pragma_tok); + clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok, + cclauses == NULL); + if (cclauses) + { + cp_omp_split_clauses (loc, OMP_SIMD, mask, clauses, cclauses); + clauses = cclauses[C_OMP_CLAUSE_SPLIT_SIMD]; + } sb = begin_omp_structured_block (); save = cp_parser_begin_omp_structured_block (parser); - ret = cp_parser_omp_for_loop (parser, OMP_SIMD, clauses, NULL); + ret = cp_parser_omp_for_loop (parser, OMP_SIMD, clauses, cclauses); cp_parser_end_omp_structured_block (parser, save); add_stmt (finish_omp_structured_block (sb)); @@ -28646,13 +28674,17 @@ cp_parser_omp_simd (cp_parser *parser, cp_token *pragma_tok) | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE)) static tree -cp_parser_omp_for (cp_parser *parser, cp_token *pragma_tok) +cp_parser_omp_for (cp_parser *parser, cp_token *pragma_tok, + char *p_name, omp_clause_mask mask, tree *cclauses) { tree clauses, sb, ret; unsigned int save; - enum tree_code code = OMP_FOR; - omp_clause_mask mask = OMP_FOR_CLAUSE_MASK; - const char *p_name = "#pragma omp for"; + location_t loc = cp_lexer_peek_token (parser->lexer)->location; + + strcat (p_name, " for"); + mask |= OMP_FOR_CLAUSE_MASK; + if (cclauses) + mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT); if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) { @@ -28661,19 +28693,41 @@ cp_parser_omp_for (cp_parser *parser, cp_token *pragma_tok) if (strcmp (p, "simd") == 0) { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + if (cclauses == NULL) + cclauses = cclauses_buf; + cp_lexer_consume_token (parser->lexer); - code = OMP_FOR_SIMD; - mask |= OMP_SIMD_CLAUSE_MASK; - p_name = "#pragma omp for simd"; + sb = begin_omp_structured_block (); + save = cp_parser_begin_omp_structured_block (parser); + ret = cp_parser_omp_simd (parser, pragma_tok, p_name, mask, + cclauses); + cp_parser_end_omp_structured_block (parser, save); + tree body = finish_omp_structured_block (sb); + if (ret == NULL) + return ret; + ret = make_node (OMP_FOR); + TREE_TYPE (ret) = void_type_node; + OMP_FOR_BODY (ret) = body; + OMP_FOR_CLAUSES (ret) = cclauses[C_OMP_CLAUSE_SPLIT_FOR]; + SET_EXPR_LOCATION (ret, loc); + add_stmt (ret); + return ret; } } - clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok); + clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok, + cclauses == NULL); + if (cclauses) + { + cp_omp_split_clauses (loc, OMP_FOR, mask, clauses, cclauses); + clauses = cclauses[C_OMP_CLAUSE_SPLIT_FOR]; + } sb = begin_omp_structured_block (); save = cp_parser_begin_omp_structured_block (parser); - ret = cp_parser_omp_for_loop (parser, code, clauses, NULL); + ret = cp_parser_omp_for_loop (parser, OMP_FOR, clauses, cclauses); cp_parser_end_omp_structured_block (parser, save); add_stmt (finish_omp_structured_block (sb)); @@ -28800,12 +28854,24 @@ cp_parser_omp_sections_scope (cp_parser *parser) | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) static tree -cp_parser_omp_sections (cp_parser *parser, cp_token *pragma_tok) +cp_parser_omp_sections (cp_parser *parser, cp_token *pragma_tok, + char *p_name, omp_clause_mask mask, tree *cclauses) { tree clauses, ret; + location_t loc = cp_lexer_peek_token (parser->lexer)->location; - clauses = cp_parser_omp_all_clauses (parser, OMP_SECTIONS_CLAUSE_MASK, - "#pragma omp sections", pragma_tok); + strcat (p_name, " sections"); + mask |= OMP_SECTIONS_CLAUSE_MASK; + if (cclauses) + mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT); + + clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok, + cclauses == NULL); + if (cclauses) + { + cp_omp_split_clauses (loc, OMP_SECTIONS, mask, clauses, cclauses); + clauses = cclauses[C_OMP_CLAUSE_SPLIT_SECTIONS]; + } ret = cp_parser_omp_sections_scope (parser); if (ret) @@ -28834,35 +28900,37 @@ cp_parser_omp_sections (cp_parser *parser, cp_token *pragma_tok) | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PROC_BIND)) static tree -cp_parser_omp_parallel (cp_parser *parser, cp_token *pragma_tok) +cp_parser_omp_parallel (cp_parser *parser, cp_token *pragma_tok, + char *p_name, omp_clause_mask mask, tree *cclauses) { - enum pragma_kind p_kind = PRAGMA_OMP_PARALLEL; - const char *p_name = "#pragma omp parallel"; - tree stmt, clauses, par_clause, ws_clause, block; - omp_clause_mask mask = OMP_PARALLEL_CLAUSE_MASK; + tree stmt, clauses, block; unsigned int save; location_t loc = cp_lexer_peek_token (parser->lexer)->location; + strcat (p_name, " parallel"); + mask |= OMP_PARALLEL_CLAUSE_MASK; + if (cp_lexer_next_token_is_keyword (parser->lexer, RID_FOR)) { - cp_lexer_consume_token (parser->lexer); - p_kind = PRAGMA_OMP_PARALLEL_FOR; - p_name = "#pragma omp parallel for"; - mask |= OMP_FOR_CLAUSE_MASK; - mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT); - 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); + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + if (cclauses == NULL) + cclauses = cclauses_buf; - if (strcmp (p, "simd") == 0) - { - cp_lexer_consume_token (parser->lexer); - p_kind = PRAGMA_OMP_PARALLEL_FOR_SIMD; - p_name = "#pragma omp parallel for simd"; - mask |= OMP_SIMD_CLAUSE_MASK; - } - } + cp_lexer_consume_token (parser->lexer); + block = begin_omp_parallel (); + save = cp_parser_begin_omp_structured_block (parser); + cp_parser_omp_for (parser, pragma_tok, p_name, mask, cclauses); + cp_parser_end_omp_structured_block (parser, save); + stmt = finish_omp_parallel (cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL], + block); + OMP_PARALLEL_COMBINED (stmt) = 1; + return stmt; + } + else if (cclauses) + { + error_at (loc, "expected % after %qs", p_name); + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + return NULL_TREE; } else if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) { @@ -28870,50 +28938,28 @@ cp_parser_omp_parallel (cp_parser *parser, cp_token *pragma_tok) const char *p = IDENTIFIER_POINTER (id); if (strcmp (p, "sections") == 0) { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + cclauses = cclauses_buf; + cp_lexer_consume_token (parser->lexer); - p_kind = PRAGMA_OMP_PARALLEL_SECTIONS; - p_name = "#pragma omp parallel sections"; - mask |= OMP_SECTIONS_CLAUSE_MASK; - mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT); + block = begin_omp_parallel (); + save = cp_parser_begin_omp_structured_block (parser); + cp_parser_omp_sections (parser, pragma_tok, p_name, mask, cclauses); + cp_parser_end_omp_structured_block (parser, save); + stmt = finish_omp_parallel (cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL], + block); + OMP_PARALLEL_COMBINED (stmt) = 1; + return stmt; } } clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok); + block = begin_omp_parallel (); save = cp_parser_begin_omp_structured_block (parser); - - switch (p_kind) - { - case PRAGMA_OMP_PARALLEL: - cp_parser_statement (parser, NULL_TREE, false, NULL); - par_clause = clauses; - break; - - case PRAGMA_OMP_PARALLEL_FOR: - c_split_parallel_clauses (loc, clauses, &par_clause, &ws_clause); - cp_parser_omp_for_loop (parser, OMP_FOR, ws_clause, &par_clause); - break; - - case PRAGMA_OMP_PARALLEL_FOR_SIMD: - c_split_parallel_clauses (loc, clauses, &par_clause, &ws_clause); - cp_parser_omp_for_loop (parser, OMP_FOR_SIMD, ws_clause, &par_clause); - break; - - case PRAGMA_OMP_PARALLEL_SECTIONS: - c_split_parallel_clauses (loc, clauses, &par_clause, &ws_clause); - stmt = cp_parser_omp_sections_scope (parser); - if (stmt) - OMP_SECTIONS_CLAUSES (stmt) = ws_clause; - break; - - default: - gcc_unreachable (); - } - + cp_parser_statement (parser, NULL_TREE, false, NULL); cp_parser_end_omp_structured_block (parser, save); - stmt = finish_omp_parallel (par_clause, block); - if (p_kind != PRAGMA_OMP_PARALLEL) - OMP_PARALLEL_COMBINED (stmt) = 1; + stmt = finish_omp_parallel (clauses, block); return stmt; } @@ -29087,6 +29133,92 @@ cp_parser_omp_cancellation_point (cp_parser *parser, cp_token *pragma_tok) finish_omp_cancellation_point (clauses); } +/* OpenMP 4.0: + #pragma omp distribute distribute-clause[optseq] new-line + for-loop */ + +#define OMP_DISTRIBUTE_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)\ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE)) + +static tree +cp_parser_omp_distribute (cp_parser *parser, cp_token *pragma_tok, + char *p_name, omp_clause_mask mask, tree *cclauses) +{ + tree clauses, sb, ret; + unsigned int save; + location_t loc = cp_lexer_peek_token (parser->lexer)->location; + + strcat (p_name, " distribute"); + mask |= OMP_DISTRIBUTE_CLAUSE_MASK; + + 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); + bool simd = false; + bool parallel = false; + + if (strcmp (p, "simd") == 0) + { + simd = true; + if (cclauses) + { + error_at (loc, "% not expected after %qs", p_name); + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + return NULL_TREE; + } + } + else + parallel = strcmp (p, "parallel") == 0; + if (parallel || simd) + { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + if (cclauses == NULL) + cclauses = cclauses_buf; + sb = begin_omp_structured_block (); + save = cp_parser_begin_omp_structured_block (parser); + if (simd) + ret = cp_parser_omp_simd (parser, pragma_tok, p_name, mask, + cclauses); + else + ret = cp_parser_omp_parallel (parser, pragma_tok, p_name, mask, + cclauses); + cp_parser_end_omp_structured_block (parser, save); + tree body = finish_omp_structured_block (sb); + if (ret == NULL) + return ret; + ret = make_node (OMP_DISTRIBUTE); + TREE_TYPE (ret) = void_type_node; + OMP_FOR_BODY (ret) = body; + OMP_FOR_CLAUSES (ret) = cclauses[C_OMP_CLAUSE_SPLIT_DISTRIBUTE]; + SET_EXPR_LOCATION (ret, loc); + add_stmt (ret); + return ret; + } + } + + clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok, + cclauses == NULL); + if (cclauses) + { + cp_omp_split_clauses (loc, OMP_DISTRIBUTE, mask, clauses, cclauses); + clauses = cclauses[C_OMP_CLAUSE_SPLIT_DISTRIBUTE]; + } + + sb = begin_omp_structured_block (); + save = cp_parser_begin_omp_structured_block (parser); + + ret = cp_parser_omp_for_loop (parser, OMP_DISTRIBUTE, clauses, NULL); + + cp_parser_end_omp_structured_block (parser, save); + add_stmt (finish_omp_structured_block (sb)); + + return ret; +} + /* OpenMP 4.0: # pragma omp teams teams-clause[optseq] new-line structured-block */ @@ -29101,14 +29233,55 @@ cp_parser_omp_cancellation_point (cp_parser *parser, cp_token *pragma_tok) | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT)) static tree -cp_parser_omp_teams (cp_parser *parser, cp_token *pragma_tok) +cp_parser_omp_teams (cp_parser *parser, cp_token *pragma_tok, + char *p_name, omp_clause_mask mask, tree *cclauses) { + tree clauses, sb, ret; + unsigned int save; + location_t loc = cp_lexer_peek_token (parser->lexer)->location; + + strcat (p_name, " teams"); + mask |= OMP_TEAMS_CLAUSE_MASK; + + 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, "distribute") == 0) + { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + if (cclauses == NULL) + cclauses = cclauses_buf; + + cp_lexer_consume_token (parser->lexer); + sb = begin_omp_structured_block (); + save = cp_parser_begin_omp_structured_block (parser); + ret = cp_parser_omp_distribute (parser, pragma_tok, p_name, mask, + cclauses); + cp_parser_end_omp_structured_block (parser, save); + tree body = finish_omp_structured_block (sb); + if (ret == NULL) + return ret; + clauses = cclauses[C_OMP_CLAUSE_SPLIT_TEAMS]; + ret = make_node (OMP_TEAMS); + TREE_TYPE (ret) = void_type_node; + OMP_TEAMS_CLAUSES (ret) = clauses; + OMP_TEAMS_BODY (ret) = body; + return add_stmt (ret); + } + } + + clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok, + cclauses == NULL); + if (cclauses) + { + cp_omp_split_clauses (loc, OMP_TEAMS, mask, clauses, cclauses); + clauses = cclauses[C_OMP_CLAUSE_SPLIT_TEAMS]; + } + tree stmt = make_node (OMP_TEAMS); TREE_TYPE (stmt) = void_type_node; - - OMP_TEAMS_CLAUSES (stmt) - = cp_parser_omp_all_clauses (parser, OMP_TEAMS_CLAUSE_MASK, - "#pragma omp teams", pragma_tok); + OMP_TEAMS_CLAUSES (stmt) = clauses; OMP_TEAMS_BODY (stmt) = cp_parser_omp_structured_block (parser); return add_stmt (stmt); @@ -29216,6 +29389,29 @@ cp_parser_omp_target (cp_parser *parser, cp_token *pragma_tok, cp_lexer_consume_token (parser->lexer); return cp_parser_omp_target_update (parser, pragma_tok, context); } + else if (strcmp (p, "teams") == 0) + { + tree cclauses[C_OMP_CLAUSE_SPLIT_COUNT]; + char p_name[sizeof ("#pragma omp target teams distribute " + "parallel for simd")]; + + cp_lexer_consume_token (parser->lexer); + strcpy (p_name, "#pragma omp target"); + tree sb = begin_omp_structured_block (); + unsigned save = cp_parser_begin_omp_structured_block (parser); + tree ret = cp_parser_omp_teams (parser, pragma_tok, p_name, + OMP_TARGET_CLAUSE_MASK, cclauses); + cp_parser_end_omp_structured_block (parser, save); + tree body = finish_omp_structured_block (sb); + if (ret == NULL) + return ret; + tree stmt = make_node (OMP_TARGET); + TREE_TYPE (stmt) = void_type_node; + OMP_TARGET_CLAUSES (stmt) = cclauses[C_OMP_CLAUSE_SPLIT_TARGET]; + OMP_TARGET_BODY (stmt) = body; + add_stmt (stmt); + return true; + } } tree stmt = make_node (OMP_TARGET); @@ -29231,36 +29427,6 @@ cp_parser_omp_target (cp_parser *parser, cp_token *pragma_tok, return true; } -/* OpenMP 4.0: - #pragma omp distribute distribute-clause[optseq] new-line - for-loop */ - -#define OMP_DISTRIBUTE_CLAUSE_MASK \ - ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)\ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE)) - -static tree -cp_parser_omp_distribute (cp_parser *parser, cp_token *pragma_tok) -{ - tree clauses, sb, ret; - unsigned int save; - - clauses = cp_parser_omp_all_clauses (parser, OMP_DISTRIBUTE_CLAUSE_MASK, - "#pragma omp distribute", pragma_tok); - - sb = begin_omp_structured_block (); - save = cp_parser_begin_omp_structured_block (parser); - - ret = cp_parser_omp_for_loop (parser, OMP_DISTRIBUTE, clauses, NULL); - - cp_parser_end_omp_structured_block (parser, save); - add_stmt (finish_omp_structured_block (sb)); - - return ret; -} - /* OpenMP 4.0: # pragma omp declare simd declare-simd-clauses[optseq] new-line */ @@ -29281,7 +29447,8 @@ cp_parser_omp_declare_simd (cp_parser *parser, cp_token *pragma_tok, vec_safe_push (parser->omp_declare_simd_clauses, NULL_TREE); tree clauses = cp_parser_omp_all_clauses (parser, OMP_DECLARE_SIMD_CLAUSE_MASK, - "#pragma omp declare simd", pragma_tok); + "#pragma omp declare simd", pragma_tok, + false); parser->omp_declare_simd_clauses->last () = clauses; if (first_p) { @@ -29382,6 +29549,8 @@ static void cp_parser_omp_construct (cp_parser *parser, cp_token *pragma_tok) { tree stmt; + char p_name[sizeof "#pragma omp teams distribute parallel for simd"]; + omp_clause_mask mask (0); switch (pragma_tok->pragma_kind) { @@ -29392,10 +29561,12 @@ cp_parser_omp_construct (cp_parser *parser, cp_token *pragma_tok) stmt = cp_parser_omp_critical (parser, pragma_tok); break; case PRAGMA_OMP_DISTRIBUTE: - stmt = cp_parser_omp_distribute (parser, pragma_tok); + strcpy (p_name, "#pragma omp"); + stmt = cp_parser_omp_distribute (parser, pragma_tok, p_name, mask, NULL); break; case PRAGMA_OMP_FOR: - stmt = cp_parser_omp_for (parser, pragma_tok); + strcpy (p_name, "#pragma omp"); + stmt = cp_parser_omp_for (parser, pragma_tok, p_name, mask, NULL); break; case PRAGMA_OMP_MASTER: stmt = cp_parser_omp_master (parser, pragma_tok); @@ -29404,13 +29575,16 @@ cp_parser_omp_construct (cp_parser *parser, cp_token *pragma_tok) stmt = cp_parser_omp_ordered (parser, pragma_tok); break; case PRAGMA_OMP_PARALLEL: - stmt = cp_parser_omp_parallel (parser, pragma_tok); + strcpy (p_name, "#pragma omp"); + stmt = cp_parser_omp_parallel (parser, pragma_tok, p_name, mask, NULL); break; case PRAGMA_OMP_SECTIONS: - stmt = cp_parser_omp_sections (parser, pragma_tok); + strcpy (p_name, "#pragma omp"); + stmt = cp_parser_omp_sections (parser, pragma_tok, p_name, mask, NULL); break; case PRAGMA_OMP_SIMD: - stmt = cp_parser_omp_simd (parser, pragma_tok); + strcpy (p_name, "#pragma omp"); + stmt = cp_parser_omp_simd (parser, pragma_tok, p_name, mask, NULL); break; case PRAGMA_OMP_SINGLE: stmt = cp_parser_omp_single (parser, pragma_tok); @@ -29422,7 +29596,8 @@ cp_parser_omp_construct (cp_parser *parser, cp_token *pragma_tok) cp_parser_omp_taskgroup (parser, pragma_tok); return; case PRAGMA_OMP_TEAMS: - stmt = cp_parser_omp_teams (parser, pragma_tok); + strcpy (p_name, "#pragma omp"); + stmt = cp_parser_omp_teams (parser, pragma_tok, p_name, mask, NULL); break; default: gcc_unreachable (); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 3eb111aeecfe7..63d960d238385 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -13293,19 +13293,22 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, case OMP_FOR: case OMP_SIMD: - case OMP_FOR_SIMD: case OMP_DISTRIBUTE: { tree clauses, body, pre_body; - tree declv, initv, condv, incrv; + tree declv = NULL_TREE, initv = NULL_TREE, condv = NULL_TREE; + tree incrv = NULL_TREE; int i; clauses = tsubst_omp_clauses (OMP_FOR_CLAUSES (t), false, args, complain, in_decl); - declv = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (t))); - initv = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (t))); - condv = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (t))); - incrv = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (t))); + if (OMP_FOR_INIT (t) != NULL_TREE) + { + declv = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (t))); + initv = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (t))); + condv = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (t))); + incrv = make_tree_vec (TREE_VEC_LENGTH (OMP_FOR_INIT (t))); + } stmt = begin_omp_structured_block (); @@ -13313,17 +13316,29 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, RECUR (OMP_FOR_PRE_BODY (t)); pre_body = pop_stmt_list (pre_body); - for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (t)); i++) - tsubst_omp_for_iterator (t, i, declv, initv, condv, incrv, - &clauses, args, complain, in_decl, - integral_constant_expression_p); + if (OMP_FOR_INIT (t) != NULL_TREE) + for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (t)); i++) + tsubst_omp_for_iterator (t, i, declv, initv, condv, incrv, + &clauses, args, complain, in_decl, + integral_constant_expression_p); body = push_stmt_list (); RECUR (OMP_FOR_BODY (t)); body = pop_stmt_list (body); - t = finish_omp_for (EXPR_LOCATION (t), TREE_CODE (t), declv, initv, - condv, incrv, body, pre_body, clauses); + if (OMP_FOR_INIT (t) != NULL_TREE) + t = finish_omp_for (EXPR_LOCATION (t), TREE_CODE (t), declv, initv, + condv, incrv, body, pre_body, clauses); + else + { + t = make_node (TREE_CODE (t)); + TREE_TYPE (t) = void_type_node; + OMP_FOR_BODY (t) = body; + OMP_FOR_PRE_BODY (t) = pre_body; + OMP_FOR_CLAUSES (t) = clauses; + SET_EXPR_LOCATION (t, EXPR_LOCATION (t)); + add_stmt (t); + } add_stmt (finish_omp_structured_block (stmt)); } diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index f6b27bad9419a..1ae09a71ca9c9 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -5782,11 +5782,10 @@ finish_omp_for (location_t locus, enum tree_code code, tree declv, tree initv, if (CLASS_TYPE_P (TREE_TYPE (decl))) { - if (code == OMP_SIMD || code == OMP_FOR_SIMD) + if (code == OMP_SIMD) { - error_at (elocus, "%<#pragma omp%s simd%> used with class " - "iteration variable %qE", - code == OMP_FOR_SIMD ? " for" : "", decl); + error_at (elocus, "%<#pragma omp simd%> used with class " + "iteration variable %qE", decl); return NULL; } if (handle_omp_for_class_iterator (i, locus, declv, initv, condv, diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c index ee264e10a8889..ba7993a4cf7e1 100644 --- a/gcc/gimple-pretty-print.c +++ b/gcc/gimple-pretty-print.c @@ -1110,9 +1110,6 @@ dump_gimple_omp_for (pretty_printer *buffer, gimple gs, int spc, int flags) case GF_OMP_FOR_KIND_SIMD: kind = " simd"; break; - case GF_OMP_FOR_KIND_FOR_SIMD: - kind = " for simd"; - break; case GF_OMP_FOR_KIND_DISTRIBUTE: kind = " distribute"; break; @@ -1144,9 +1141,6 @@ dump_gimple_omp_for (pretty_printer *buffer, gimple gs, int spc, int flags) case GF_OMP_FOR_KIND_SIMD: pp_string (buffer, "#pragma omp simd"); break; - case GF_OMP_FOR_KIND_FOR_SIMD: - pp_string (buffer, "#pragma omp for simd"); - break; case GF_OMP_FOR_KIND_DISTRIBUTE: pp_string (buffer, "#pragma omp distribute"); break; diff --git a/gcc/gimple.h b/gcc/gimple.h index 5060b282afdcc..08dacc5c45962 100644 --- a/gcc/gimple.h +++ b/gcc/gimple.h @@ -113,8 +113,8 @@ enum gf_mask { GF_OMP_FOR_KIND_MASK = 3 << 0, GF_OMP_FOR_KIND_FOR = 0 << 0, GF_OMP_FOR_KIND_SIMD = 1 << 0, - GF_OMP_FOR_KIND_FOR_SIMD = 2 << 0, - GF_OMP_FOR_KIND_DISTRIBUTE = 3 << 0, + GF_OMP_FOR_KIND_DISTRIBUTE = 2 << 0, + GF_OMP_FOR_COMBINED = 4 << 0, GF_OMP_TARGET_KIND_MASK = 3 << 0, GF_OMP_TARGET_KIND_REGION = 0 << 0, GF_OMP_TARGET_KIND_DATA = 1 << 0, @@ -4003,6 +4003,31 @@ gimple_omp_for_set_kind (gimple g, int kind) } +/* Return true if OMP for statement G has the + GF_OMP_FOR_COMBINED flag set. */ + +static inline bool +gimple_omp_for_combined_p (const_gimple g) +{ + GIMPLE_CHECK (g, GIMPLE_OMP_FOR); + return (gimple_omp_subcode (g) & GF_OMP_FOR_COMBINED) != 0; +} + + +/* Set the GF_OMP_FOR_COMBINED field in G depending on the boolean + value of COMBINED_P. */ + +static inline void +gimple_omp_for_set_combined_p (gimple g, bool combined_p) +{ + GIMPLE_CHECK (g, GIMPLE_OMP_FOR); + if (combined_p) + g->gsbase.subcode |= GF_OMP_FOR_COMBINED; + else + g->gsbase.subcode &= ~GF_OMP_FOR_COMBINED; +} + + /* Return the clauses associated with OMP_FOR GS. */ static inline tree diff --git a/gcc/gimplify.c b/gcc/gimplify.c index e2c10718aa225..78ba9da2c3945 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -4716,7 +4716,6 @@ is_gimple_stmt (tree t) case OMP_PARALLEL: case OMP_FOR: case OMP_SIMD: - case OMP_FOR_SIMD: case OMP_DISTRIBUTE: case OMP_SECTIONS: case OMP_SECTION: @@ -6826,12 +6825,39 @@ gimplify_omp_task (tree *expr_p, gimple_seq *pre_p) *expr_p = NULL_TREE; } +/* Helper function of gimplify_omp_for, find OMP_FOR resp. OMP_SIMD + with non-NULL OMP_FOR_INIT. */ + +static tree +find_combined_omp_for (tree *tp, int *walk_subtrees, void *) +{ + *walk_subtrees = 0; + switch (TREE_CODE (*tp)) + { + case OMP_FOR: + *walk_subtrees = 1; + /* FALLTHRU */ + case OMP_SIMD: + if (OMP_FOR_INIT (*tp) != NULL_TREE) + return *tp; + break; + case BIND_EXPR: + case STATEMENT_LIST: + case OMP_PARALLEL: + *walk_subtrees = 1; + break; + default: + break; + } + return NULL_TREE; +} + /* Gimplify the gross structure of an OMP_FOR statement. */ static enum gimplify_status gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) { - tree for_stmt, decl, var, t; + tree for_stmt, orig_for_stmt, decl, var, t; enum gimplify_status ret = GS_ALL_DONE; enum gimplify_status tret; gimple gfor; @@ -6840,10 +6866,9 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) bool simd; bitmap has_decl_expr = NULL; - for_stmt = *expr_p; + orig_for_stmt = for_stmt = *expr_p; - simd = TREE_CODE (for_stmt) == OMP_SIMD - || TREE_CODE (for_stmt) == OMP_FOR_SIMD; + simd = TREE_CODE (for_stmt) == OMP_SIMD; gimplify_scan_omp_clauses (&OMP_FOR_CLAUSES (for_stmt), pre_p, TREE_CODE (for_stmt) == OMP_SIMD ? ORT_SIMD : ORT_WORKSHARE); @@ -6876,6 +6901,13 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) gimplify_and_add (OMP_FOR_PRE_BODY (for_stmt), &for_pre_body); OMP_FOR_PRE_BODY (for_stmt) = NULL_TREE; + if (OMP_FOR_INIT (for_stmt) == NULL_TREE) + { + for_stmt = walk_tree (&OMP_FOR_BODY (for_stmt), find_combined_omp_for, + NULL, NULL); + gcc_assert (for_stmt != NULL_TREE); + } + for_body = NULL; gcc_assert (TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)) == TREE_VEC_LENGTH (OMP_FOR_COND (for_stmt))); @@ -6891,12 +6923,14 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) || POINTER_TYPE_P (TREE_TYPE (decl))); /* Make sure the iteration variable is private. */ - bool is_private = omp_is_private (gimplify_omp_ctxp, decl, simd); tree c = NULL_TREE; - if (simd) + if (orig_for_stmt != for_stmt) + /* Do this only on innermost construct for combined ones. */; + else if (simd) { splay_tree_node n = splay_tree_lookup (gimplify_omp_ctxp->variables, (splay_tree_key)decl); + omp_is_private (gimplify_omp_ctxp, decl, simd); if (n != NULL && (n->value & GOVD_DATA_SHARE_CLASS) != 0) omp_notice_variable (gimplify_omp_ctxp, decl, true); else @@ -6913,7 +6947,7 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) GOVD_LINEAR | GOVD_EXPLICIT | GOVD_SEEN); } } - else if (is_private) + else if (omp_is_private (gimplify_omp_ctxp, decl, simd)) omp_notice_variable (gimplify_omp_ctxp, decl, true); else omp_add_variable (gimplify_omp_ctxp, decl, GOVD_PRIVATE | GOVD_SEEN); @@ -6921,7 +6955,9 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) /* If DECL is not a gimple register, create a temporary variable to act as an iteration counter. This is valid, since DECL cannot be modified in the body of the loop. */ - if (!is_gimple_reg (decl)) + if (orig_for_stmt != for_stmt) + var = decl; + else if (!is_gimple_reg (decl)) { var = create_tmp_var (TREE_TYPE (decl), get_name (decl)); TREE_OPERAND (t, 0) = var; @@ -6954,6 +6990,8 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) { case PREINCREMENT_EXPR: case POSTINCREMENT_EXPR: + if (orig_for_stmt != for_stmt) + break; t = build_int_cst (TREE_TYPE (decl), 1); if (c) OMP_CLAUSE_LINEAR_STEP (c) = t; @@ -6964,6 +7002,8 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) case PREDECREMENT_EXPR: case POSTDECREMENT_EXPR: + if (orig_for_stmt != for_stmt) + break; t = build_int_cst (TREE_TYPE (decl), -1); if (c) OMP_CLAUSE_LINEAR_STEP (c) = t; @@ -7020,7 +7060,8 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) gcc_unreachable (); } - if (var != decl || TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)) > 1) + if ((var != decl || TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)) > 1) + && orig_for_stmt == for_stmt) { for (c = OMP_FOR_CLAUSES (for_stmt); c ; c = OMP_CLAUSE_CHAIN (c)) if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE @@ -7045,23 +7086,37 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) BITMAP_FREE (has_decl_expr); - gimplify_and_add (OMP_FOR_BODY (for_stmt), &for_body); + gimplify_and_add (OMP_FOR_BODY (orig_for_stmt), &for_body); + + if (orig_for_stmt != for_stmt) + for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)); i++) + { + t = TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), i); + decl = TREE_OPERAND (t, 0); + var = create_tmp_var (TREE_TYPE (decl), get_name (decl)); + omp_add_variable (gimplify_omp_ctxp, var, GOVD_PRIVATE | GOVD_SEEN); + TREE_OPERAND (t, 0) = var; + t = TREE_VEC_ELT (OMP_FOR_INCR (for_stmt), i); + TREE_OPERAND (t, 1) = copy_node (TREE_OPERAND (t, 1)); + TREE_OPERAND (TREE_OPERAND (t, 1), 0) = var; + } - gimplify_adjust_omp_clauses (&OMP_FOR_CLAUSES (for_stmt)); + gimplify_adjust_omp_clauses (&OMP_FOR_CLAUSES (orig_for_stmt)); int kind; - switch (TREE_CODE (for_stmt)) + switch (TREE_CODE (orig_for_stmt)) { case OMP_FOR: kind = GF_OMP_FOR_KIND_FOR; break; case OMP_SIMD: kind = GF_OMP_FOR_KIND_SIMD; break; - case OMP_FOR_SIMD: kind = GF_OMP_FOR_KIND_FOR_SIMD; break; case OMP_DISTRIBUTE: kind = GF_OMP_FOR_KIND_DISTRIBUTE; break; default: gcc_unreachable (); } - gfor = gimple_build_omp_for (for_body, kind, OMP_FOR_CLAUSES (for_stmt), + gfor = gimple_build_omp_for (for_body, kind, OMP_FOR_CLAUSES (orig_for_stmt), TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)), for_pre_body); + if (orig_for_stmt != for_stmt) + gimple_omp_for_set_combined_p (gfor, true); for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)); i++) { @@ -8057,7 +8112,6 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, case OMP_FOR: case OMP_SIMD: - case OMP_FOR_SIMD: case OMP_DISTRIBUTE: ret = gimplify_omp_for (expr_p, pre_p); break; diff --git a/gcc/omp-low.c b/gcc/omp-low.c index b131cde703718..ca42fcc610d61 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -938,17 +938,25 @@ build_outer_var_ref (tree var, omp_context *ctx) bool by_ref = use_pointer_for_field (var, NULL); x = build_receiver_ref (var, by_ref, ctx); } + else if (gimple_code (ctx->stmt) == GIMPLE_OMP_FOR + && gimple_omp_for_kind (ctx->stmt) == GF_OMP_FOR_KIND_SIMD) + { + /* #pragma omp simd isn't a worksharing construct, and can reference even + private vars in its linear etc. clauses. */ + x = NULL_TREE; + if (ctx->outer && is_taskreg_ctx (ctx)) + x = lookup_decl (var, ctx->outer); + else if (ctx->outer) + x = maybe_lookup_decl (var, ctx->outer); + if (x == NULL_TREE) + x = var; + } else if (ctx->outer) x = lookup_decl (var, ctx->outer); else if (is_reference (var)) /* This can happen with orphaned constructs. If var is reference, it is possible it is shared and as such valid. */ x = var; - else if (gimple_code (ctx->stmt) == GIMPLE_OMP_FOR - && gimple_omp_for_kind (ctx->stmt) == GF_OMP_FOR_KIND_SIMD) - /* #pragma omp simd isn't a worksharing construct, and can reference even - private vars in its linear etc. clauses. */ - x = var; else gcc_unreachable (); @@ -1877,8 +1885,7 @@ check_omp_nesting_restrictions (gimple stmt, omp_context *ctx) if (ctx != NULL) { if (gimple_code (ctx->stmt) == GIMPLE_OMP_FOR - && (gimple_omp_for_kind (ctx->stmt) == GF_OMP_FOR_KIND_SIMD - || gimple_omp_for_kind (ctx->stmt) == GF_OMP_FOR_KIND_FOR_SIMD)) + && gimple_omp_for_kind (ctx->stmt) == GF_OMP_FOR_KIND_SIMD) { error_at (gimple_location (stmt), "OpenMP constructs may not be nested inside simd region"); diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c index b67fc937f8906..9c3d15e1489b1 100644 --- a/gcc/tree-pretty-print.c +++ b/gcc/tree-pretty-print.c @@ -2364,10 +2364,6 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags, pp_string (buffer, "#pragma omp simd"); goto dump_omp_loop; - case OMP_FOR_SIMD: - pp_string (buffer, "#pragma omp for simd"); - goto dump_omp_loop; - case OMP_DISTRIBUTE: pp_string (buffer, "#pragma omp distribute"); goto dump_omp_loop; @@ -2409,21 +2405,27 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags, dump_generic_node (buffer, OMP_FOR_PRE_BODY (node), spc, flags, false); } - spc -= 2; - for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (node)); i++) + if (OMP_FOR_INIT (node)) { - spc += 2; - newline_and_indent (buffer, spc); - pp_string (buffer, "for ("); - dump_generic_node (buffer, TREE_VEC_ELT (OMP_FOR_INIT (node), i), - spc, flags, false); - pp_string (buffer, "; "); - dump_generic_node (buffer, TREE_VEC_ELT (OMP_FOR_COND (node), i), - spc, flags, false); - pp_string (buffer, "; "); - dump_generic_node (buffer, TREE_VEC_ELT (OMP_FOR_INCR (node), i), - spc, flags, false); - pp_string (buffer, ")"); + spc -= 2; + for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (node)); i++) + { + spc += 2; + newline_and_indent (buffer, spc); + pp_string (buffer, "for ("); + dump_generic_node (buffer, + TREE_VEC_ELT (OMP_FOR_INIT (node), i), + spc, flags, false); + pp_string (buffer, "; "); + dump_generic_node (buffer, + TREE_VEC_ELT (OMP_FOR_COND (node), i), + spc, flags, false); + pp_string (buffer, "; "); + dump_generic_node (buffer, + TREE_VEC_ELT (OMP_FOR_INCR (node), i), + spc, flags, false); + pp_string (buffer, ")"); + } } if (OMP_FOR_BODY (node)) { @@ -2435,7 +2437,8 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags, newline_and_indent (buffer, spc + 2); pp_character (buffer, '}'); } - spc -= 2 * TREE_VEC_LENGTH (OMP_FOR_INIT (node)) - 2; + if (OMP_FOR_INIT (node)) + spc -= 2 * TREE_VEC_LENGTH (OMP_FOR_INIT (node)) - 2; if (OMP_FOR_PRE_BODY (node)) { spc -= 4; diff --git a/gcc/tree.def b/gcc/tree.def index a2e53e65f721e..a23d5bfd26f2a 100644 --- a/gcc/tree.def +++ b/gcc/tree.def @@ -1034,10 +1034,6 @@ DEFTREECODE (OMP_FOR, "omp_for", tcc_statement, 6) Operands like for OMP_FOR. */ DEFTREECODE (OMP_SIMD, "omp_simd", tcc_statement, 6) -/* OpenMP - #pragma omp for simd [clause1 ... clauseN] - Operands like for OMP_FOR. */ -DEFTREECODE (OMP_FOR_SIMD, "omp_for_simd", tcc_statement, 6) - /* OpenMP - #pragma omp distribute [clause1 ... clauseN] Operands like for OMP_FOR. */ DEFTREECODE (OMP_DISTRIBUTE, "omp_distribute", tcc_statement, 6) From 849a88aa7f0dd35082d6deac29c63786b74e6b7f Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Fri, 14 Jun 2013 12:19:42 -0500 Subject: [PATCH 56/63] Remove OMP_FOR_SIMD to fix gomp-4_0-branch merge fallout. --- gcc/c-family/c-cilkplus.c | 1 - 1 file changed, 1 deletion(-) diff --git a/gcc/c-family/c-cilkplus.c b/gcc/c-family/c-cilkplus.c index 7346274579f3a..12097e088f647 100644 --- a/gcc/c-family/c-cilkplus.c +++ b/gcc/c-family/c-cilkplus.c @@ -162,7 +162,6 @@ c_validate_cilk_plus_loop (tree *tp, int *walk_subtrees, void *data) case OMP_TASK: case OMP_FOR: case OMP_SIMD: - case OMP_FOR_SIMD: case OMP_DISTRIBUTE: case OMP_SECTIONS: case OMP_SINGLE: From 0d0061a495d9adec95d67eafa0baac2b77396392 Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Thu, 20 Jun 2013 19:26:12 -0500 Subject: [PATCH 57/63] Implement a new CILK_SIMD tree code and gimplify it into GIMPLE_OMP_FOR with an appropriate annotation. --- gcc/ChangeLog.cilkplus | 16 +++++- gcc/c-family/c-cilkplus.c | 30 +---------- gcc/c/c-parser.c | 5 -- gcc/cp/parser.c | 4 -- gcc/gimple-pretty-print.c | 6 +++ gcc/gimple.h | 7 +-- gcc/gimplify.c | 18 ++++++- gcc/omp-low.c | 54 +++++++++++++------ .../c-c++-common/cilk-plus/PS/body.c | 2 - gcc/testsuite/gcc.dg/cilk-plus/jump.c | 27 ++++++++++ gcc/tree-pretty-print.c | 4 ++ gcc/tree.def | 7 +++ 12 files changed, 118 insertions(+), 62 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/cilk-plus/jump.c diff --git a/gcc/ChangeLog.cilkplus b/gcc/ChangeLog.cilkplus index 6a48ada0fa2ab..4ca0c67397cef 100644 --- a/gcc/ChangeLog.cilkplus +++ b/gcc/ChangeLog.cilkplus @@ -1,9 +1,23 @@ -2013-05-13 Aldy Hernandez +2013-06-20 Aldy Hernandez Balaji V. Iyer * Makefile.in (C_COMMON_OBJS): Depend on c-family/c-cilkplus.o. (c-cilkplus.o): New dependency. * omp-low.c (extract_omp_for_data): Add case for NE_EXPR. + (build_outer_var_ref): Check for GF_OMP_FOR_KIND_SIMD bitwise. + (check_omp_nesting_restrictions): Same. + (lower_rec_input_clauses): Same. + (expand_omp_for): Same. + (lower_omp_for): Same. + (diagnose_sb_0): Adjust for Cilk Plus for loops. + * tree.def (CILK_SIMD): New entry. + * tree-pretty-print.c (dump_generic_node): Add case for CILK_SIMD. + * gimple-pretty-print.c (dump_gimple_omp_for): Add case for + GF_OMP_FOR_KIND_CILKSIMD. + * gimplify.c (gimplify_omp_for): Add case for CILK_SIMD. + (gimplify_expr): Same. + (is_gimple_stmt): Same. + (find_combined_omp_for): Same. c-family/ * c-cilkplus.c: New. diff --git a/gcc/c-family/c-cilkplus.c b/gcc/c-family/c-cilkplus.c index 12097e088f647..861bcbc4d704d 100644 --- a/gcc/c-family/c-cilkplus.c +++ b/gcc/c-family/c-cilkplus.c @@ -120,24 +120,8 @@ c_validate_cilk_plus_loop (tree *tp, int *walk_subtrees, void *data) bool *valid = (bool *) data; - /* FIXME: Jumps are disallowed into or out of the body of a - _Cilk_for. We can't just check for GOTO_EXPR here, since - GOTO_EXPR's can also be generated by switches and loops. - - We should check for this case after we have built the CFG, - possibly at OMP expansion (ompexp). However, since by then we - have expanded the _Cilk_for into an OMP_FOR, we should probably - set a tree bit in OMP_FOR differentiating it from the Cilk SIMD - construct and handle it appropriately. */ - switch (TREE_CODE (*tp)) { - case RETURN_EXPR: - error_at (EXPR_LOCATION (*tp), "return statments are not allowed " - "within loops annotated with #pragma simd"); - *valid = false; - *walk_subtrees = 0; - break; case CALL_EXPR: { tree fndecl = CALL_EXPR_FN (*tp); @@ -358,23 +342,11 @@ c_finish_cilk_simd_loop (location_t loc, TREE_VEC_ELT (condv, 0) = cond; TREE_VEC_ELT (incrv, 0) = incr; - /* The OpenMP <#pragma omp simd> construct is exactly the same as - the Cilk Plus one, with the exception of the vectorlength() - clause in Cilk Plus. Emitting an OMP_SIMD simlifies - everything. */ - tree t = make_node (OMP_SIMD); + tree t = make_node (CILK_SIMD); TREE_TYPE (t) = void_type_node; OMP_FOR_INIT (t) = initv; - - /* ?? The spec says "The increment and limit expressions may be - evaluated fewer times than in the serialization. If different - evaluations of the same expression yield different values, the - behavior of the program is undefined." Perhaps the RHS of the - condition and increment could be wrapped in a SAVE_EXPR to - evaluate only once. */ OMP_FOR_COND (t) = condv; OMP_FOR_INCR (t) = incrv; - OMP_FOR_BODY (t) = body; OMP_FOR_PRE_BODY (t) = NULL; OMP_FOR_CLAUSES (t) = adjust_clauses_for_omp (clauses); diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index 3793bd98d0181..c20d91c3b5af3 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -12123,11 +12123,6 @@ c_parser_cilk_simd_construct (c_parser *parser) { tree clauses = c_parser_cilk_all_clauses (parser); - /* For <#pragma simd> we will be generating OMP_SIMD's and let the - OpenMP mechanism handle everything. */ - if (!flag_openmp) - flag_openmp = true; - c_parser_cilk_for_statement (parser, RID_FOR, clauses); } diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index bced6c3d893f0..a4ef58560a2e3 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -30420,10 +30420,6 @@ cp_parser_cilk_simd_construct (cp_parser *parser, cp_token *pragma_token) return; } - /* #pragma simd is built on top of OpenMP 4.0's OMP_SIMD trees. */ - if (!flag_openmp) - flag_openmp = true; - tree sb = begin_omp_structured_block (); int save = cp_parser_begin_omp_structured_block (parser); cp_parser_cilk_for (parser, RID_FOR, clauses); diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c index ba7993a4cf7e1..8c92b5bb18d29 100644 --- a/gcc/gimple-pretty-print.c +++ b/gcc/gimple-pretty-print.c @@ -1110,6 +1110,9 @@ dump_gimple_omp_for (pretty_printer *buffer, gimple gs, int spc, int flags) case GF_OMP_FOR_KIND_SIMD: kind = " simd"; break; + case GF_OMP_FOR_KIND_CILKSIMD: + kind = " cilksimd"; + break; case GF_OMP_FOR_KIND_DISTRIBUTE: kind = " distribute"; break; @@ -1141,6 +1144,9 @@ dump_gimple_omp_for (pretty_printer *buffer, gimple gs, int spc, int flags) case GF_OMP_FOR_KIND_SIMD: pp_string (buffer, "#pragma omp simd"); break; + case GF_OMP_FOR_KIND_CILKSIMD: + pp_string (buffer, "#pragma simd"); + break; case GF_OMP_FOR_KIND_DISTRIBUTE: pp_string (buffer, "#pragma omp distribute"); break; diff --git a/gcc/gimple.h b/gcc/gimple.h index 08dacc5c45962..6987df56625d4 100644 --- a/gcc/gimple.h +++ b/gcc/gimple.h @@ -111,9 +111,10 @@ enum gf_mask { GF_CALL_INTERNAL = 1 << 6, GF_OMP_PARALLEL_COMBINED = 1 << 0, GF_OMP_FOR_KIND_MASK = 3 << 0, - GF_OMP_FOR_KIND_FOR = 0 << 0, - GF_OMP_FOR_KIND_SIMD = 1 << 0, - GF_OMP_FOR_KIND_DISTRIBUTE = 2 << 0, + GF_OMP_FOR_KIND_FOR = 0 << 0, /* #pragma omp for */ + GF_OMP_FOR_KIND_DISTRIBUTE = 1 << 0, /* #pragma omp distribute */ + GF_OMP_FOR_KIND_SIMD = 2 << 0, /* #pragma omp simd */ + GF_OMP_FOR_KIND_CILKSIMD = 3 << 0, /* (Cilk Plus) #pragma simd */ GF_OMP_FOR_COMBINED = 4 << 0, GF_OMP_TARGET_KIND_MASK = 3 << 0, GF_OMP_TARGET_KIND_REGION = 0 << 0, diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 78ba9da2c3945..3d2f385d8ae47 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -4716,6 +4716,7 @@ is_gimple_stmt (tree t) case OMP_PARALLEL: case OMP_FOR: case OMP_SIMD: + case CILK_SIMD: case OMP_DISTRIBUTE: case OMP_SECTIONS: case OMP_SECTION: @@ -6838,6 +6839,8 @@ find_combined_omp_for (tree *tp, int *walk_subtrees, void *) *walk_subtrees = 1; /* FALLTHRU */ case OMP_SIMD: + case CILK_SIMD: + /* ?? Hmmm, is this the right way to handle CILK_SIMD? */ if (OMP_FOR_INIT (*tp) != NULL_TREE) return *tp; break; @@ -6868,9 +6871,11 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) orig_for_stmt = for_stmt = *expr_p; - simd = TREE_CODE (for_stmt) == OMP_SIMD; + simd = TREE_CODE (for_stmt) == OMP_SIMD + || TREE_CODE (for_stmt) == CILK_SIMD; gimplify_scan_omp_clauses (&OMP_FOR_CLAUSES (for_stmt), pre_p, - TREE_CODE (for_stmt) == OMP_SIMD + (TREE_CODE (for_stmt) == OMP_SIMD + || TREE_CODE (for_stmt) == CILK_SIMD) ? ORT_SIMD : ORT_WORKSHARE); /* Handle OMP_FOR_INIT. */ @@ -7108,6 +7113,7 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) { case OMP_FOR: kind = GF_OMP_FOR_KIND_FOR; break; case OMP_SIMD: kind = GF_OMP_FOR_KIND_SIMD; break; + case CILK_SIMD: kind = GF_OMP_FOR_KIND_CILKSIMD; break; case OMP_DISTRIBUTE: kind = GF_OMP_FOR_KIND_DISTRIBUTE; break; default: gcc_unreachable (); @@ -8110,6 +8116,14 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, ret = GS_ALL_DONE; break; + case CILK_SIMD: + /* For <#pragma simd> we will be generating GIMPLE_OMP_FOR + with GF_OMP_FOR_KIND_CILKSIMD and let the OpenMP + mechanism handle everything. */ + if (!flag_openmp) + flag_openmp = true; + /* FALLTHRU */ + case OMP_FOR: case OMP_SIMD: case OMP_DISTRIBUTE: diff --git a/gcc/omp-low.c b/gcc/omp-low.c index 006544399b305..3b889061c78c2 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -223,7 +223,7 @@ extract_omp_for_data (gimple for_stmt, struct omp_for_data *fd, int i; struct omp_for_data_loop dummy_loop; location_t loc = gimple_location (for_stmt); - bool non_ws = gimple_omp_for_kind (for_stmt) == GF_OMP_FOR_KIND_SIMD; + bool non_ws = gimple_omp_for_kind (for_stmt) & GF_OMP_FOR_KIND_SIMD; bool distribute = gimple_omp_for_kind (for_stmt) == GF_OMP_FOR_KIND_DISTRIBUTE; @@ -317,11 +317,12 @@ extract_omp_for_data (gimple for_stmt, struct omp_for_data *fd, case GT_EXPR: break; case NE_EXPR: - if (!flag_enable_cilk) + /* NE_EXPR is only allowed for Cilk Plus loops. */ + if (flag_enable_cilk + && gimple_omp_for_kind (for_stmt) == GF_OMP_FOR_KIND_CILKSIMD) + break; + else gcc_unreachable (); - /* NE_EXPR is technically not allowed in OpenMP, but it is - allowed in Cilk Plus, which generates OMP_SIMD constructs. */ - break; case LE_EXPR: if (POINTER_TYPE_P (TREE_TYPE (loop->n2))) loop->n2 = fold_build_pointer_plus_hwi_loc (loc, loop->n2, 1); @@ -945,7 +946,7 @@ build_outer_var_ref (tree var, omp_context *ctx) x = build_receiver_ref (var, by_ref, ctx); } else if (gimple_code (ctx->stmt) == GIMPLE_OMP_FOR - && gimple_omp_for_kind (ctx->stmt) == GF_OMP_FOR_KIND_SIMD) + && gimple_omp_for_kind (ctx->stmt) & GF_OMP_FOR_KIND_SIMD) { /* #pragma omp simd isn't a worksharing construct, and can reference even private vars in its linear etc. clauses. */ @@ -1891,7 +1892,7 @@ check_omp_nesting_restrictions (gimple stmt, omp_context *ctx) if (ctx != NULL) { if (gimple_code (ctx->stmt) == GIMPLE_OMP_FOR - && gimple_omp_for_kind (ctx->stmt) == GF_OMP_FOR_KIND_SIMD) + && gimple_omp_for_kind (ctx->stmt) & GF_OMP_FOR_KIND_SIMD) { error_at (gimple_location (stmt), "OpenMP constructs may not be nested inside simd region"); @@ -1922,7 +1923,7 @@ check_omp_nesting_restrictions (gimple stmt, omp_context *ctx) switch (gimple_code (stmt)) { case GIMPLE_OMP_FOR: - if (gimple_omp_for_kind (stmt) == GF_OMP_FOR_KIND_SIMD) + if (gimple_omp_for_kind (stmt) & GF_OMP_FOR_KIND_SIMD) return true; if (gimple_omp_for_kind (stmt) == GF_OMP_FOR_KIND_DISTRIBUTE) { @@ -2763,9 +2764,9 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, happens after firstprivate copying in all threads. */ if (copyin_by_ref || lastprivate_firstprivate) { - /* Don't add any barrier for #pragma omp simd. */ + /* Don't add any barrier for #pragma omp simd or #pragma simd. */ if (gimple_code (ctx->stmt) != GIMPLE_OMP_FOR - || gimple_omp_for_kind (ctx->stmt) != GF_OMP_FOR_KIND_SIMD) + || !(gimple_omp_for_kind (ctx->stmt) & GF_OMP_FOR_KIND_SIMD)) gimplify_and_add (build_omp_barrier (), ilist); } } @@ -5511,7 +5512,7 @@ expand_omp_for (struct omp_region *region) original loops from being detected. Fix that up. */ loops_state_set (LOOPS_NEED_FIXUP); - if (gimple_omp_for_kind (fd.for_stmt) == GF_OMP_FOR_KIND_SIMD) + if (gimple_omp_for_kind (fd.for_stmt) & GF_OMP_FOR_KIND_SIMD) expand_omp_simd (region, &fd); else if (fd.sched_kind == OMP_CLAUSE_SCHEDULE_STATIC && !fd.have_ordered @@ -7203,7 +7204,7 @@ lower_omp_for (gimple_stmt_iterator *gsi_p, omp_context *ctx) /* Once lowered, extract the bounds and clauses. */ extract_omp_for_data (stmt, &fd, NULL); - if (gimple_omp_for_kind (fd.for_stmt) != GF_OMP_FOR_KIND_SIMD) + if (!(gimple_omp_for_kind (fd.for_stmt) & GF_OMP_FOR_KIND_SIMD)) lower_omp_for_lastprivate (&fd, &body, &dlist, ctx); gimple_seq_add_stmt (&body, stmt); @@ -7220,7 +7221,7 @@ lower_omp_for (gimple_stmt_iterator *gsi_p, omp_context *ctx) /* Region exit marker goes at the end of the loop body. */ gimple_seq_add_stmt (&body, gimple_build_omp_return (fd.have_nowait)); - if (gimple_omp_for_kind (fd.for_stmt) == GF_OMP_FOR_KIND_SIMD) + if (gimple_omp_for_kind (fd.for_stmt) & GF_OMP_FOR_KIND_SIMD) { dlist = NULL; lower_lastprivate_clauses (gimple_omp_for_clauses (fd.for_stmt), @@ -7888,12 +7889,33 @@ diagnose_sb_0 (gimple_stmt_iterator *gsi_p, error ("invalid entry to OpenMP structured block"); #endif + bool cilkplus_block = false; + if (flag_enable_cilk) + { + if ((branch_ctx + && gimple_code (branch_ctx) == GIMPLE_OMP_FOR + && gimple_omp_for_kind (branch_ctx) & GF_OMP_FOR_KIND_CILKSIMD) + || (gimple_code (label_ctx) == GIMPLE_OMP_FOR + && gimple_omp_for_kind (label_ctx) & GF_OMP_FOR_KIND_CILKSIMD)) + cilkplus_block = true; + } + /* If it's obvious we have an invalid entry, be specific about the error. */ if (branch_ctx == NULL) - error ("invalid entry to OpenMP structured block"); + { + if (cilkplus_block) + error ("invalid entry to Cilk Plus structured block"); + else + error ("invalid entry to OpenMP structured block"); + } else - /* Otherwise, be vague and lazy, but efficient. */ - error ("invalid branch to/from an OpenMP structured block"); + { + /* Otherwise, be vague and lazy, but efficient. */ + if (cilkplus_block) + error ("invalid branch to/from a Cilk Plus structured block"); + else + error ("invalid branch to/from an OpenMP structured block"); + } gsi_replace (gsi_p, gimple_build_nop (), false); return true; diff --git a/gcc/testsuite/c-c++-common/cilk-plus/PS/body.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/body.c index fe8b6306a64cb..e8e2066de4343 100644 --- a/gcc/testsuite/c-c++-common/cilk-plus/PS/body.c +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/body.c @@ -11,8 +11,6 @@ void foo() #pragma simd for (int i=0; i < 1000; ++i) { - if (c == 5) - return; /* { dg-error "\(return statments are not allowed\|invalid exit\)" } */ if (c == 6) __builtin_setjmp (jmpbuf); /* { dg-error "calls to setjmp are not allowed" } */ a[i] = b[i]; diff --git a/gcc/testsuite/gcc.dg/cilk-plus/jump.c b/gcc/testsuite/gcc.dg/cilk-plus/jump.c new file mode 100644 index 0000000000000..9ec3293cc9791 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cilk-plus/jump.c @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-options "-fcilkplus" } */ + +int *a, *b, c; + +void foo() +{ +#pragma simd + for (int i=0; i < 1000; ++i) + { + a[i] = b[i]; + if (c == 5) + return; /* { dg-error "invalid branch to.from a Cilk" } */ + } +} + +void bar() +{ +#pragma simd + for (int i=0; i < 1000; ++i) + { + lab: + a[i] = b[i]; + } + if (c == 6) + goto lab; /* { dg-error "invalid entry to Cilk Plus" } */ +} diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c index 9c3d15e1489b1..9c29a5b069791 100644 --- a/gcc/tree-pretty-print.c +++ b/gcc/tree-pretty-print.c @@ -2364,6 +2364,10 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags, pp_string (buffer, "#pragma omp simd"); goto dump_omp_loop; + case CILK_SIMD: + pp_string (buffer, "#pragma simd"); + goto dump_omp_loop; + case OMP_DISTRIBUTE: pp_string (buffer, "#pragma omp distribute"); goto dump_omp_loop; diff --git a/gcc/tree.def b/gcc/tree.def index a23d5bfd26f2a..75b4d8a491da8 100644 --- a/gcc/tree.def +++ b/gcc/tree.def @@ -1034,6 +1034,13 @@ DEFTREECODE (OMP_FOR, "omp_for", tcc_statement, 6) Operands like for OMP_FOR. */ DEFTREECODE (OMP_SIMD, "omp_simd", tcc_statement, 6) +/* Cilk Plus - #pragma simd [clause1 ... clauseN] + Operands like for OMP_FOR. + + NOTE: This must go between OMP_FOR and OMP_DISTRIBUTE, so + OMP_LOOP_CHECK works as expected. */ +DEFTREECODE (CILK_SIMD, "cilk_simd", tcc_statement, 6) + /* OpenMP - #pragma omp distribute [clause1 ... clauseN] Operands like for OMP_FOR. */ DEFTREECODE (OMP_DISTRIBUTE, "omp_distribute", tcc_statement, 6) From fa9048fa6844633b65143b1bf22d6c4684fb87f5 Mon Sep 17 00:00:00 2001 From: jakub Date: Fri, 21 Jun 2013 06:41:13 +0000 Subject: [PATCH 58/63] gcc/ * gimple.h (enum gf_mask): Adjust GF_OMP_FOR_COMBINED value representation, add GF_OMP_FOR_COMBINED_INTO. (gimple_omp_for_combined_into_p, gimple_omp_for_set_combined_into_p): New inlines. * gimplify.c (enum omp_region_type): Remove outdated ORT_SIMD comment. (struct gimplify_omp_ctx): Add combined_loop field. (gimplify_omp_for): Call gimple_omp_for_set_combined_into_p for inner for/simd constructs combined with an outer loop construct (for or distribute). * tree.c (omp_clause_num_ops): Add OMP_CLAUSE__LOOPTEMP_ entry. (omp_clause_code_name): Likewise. (walk_tree_1): Handle OMP_CLAUSE__LOOPTEMP_. * tree-pretty-print.c (dump_omp_clause): Handle OMP_CLAUSE__LOOPTEMP_. * tree.h (enum omp_clause_code): Add OMP_CLAUSE__LOOPTEMP_. (OMP_CLAUSE_DECL): Allow also on OMP_CLAUSE__LOOPTEMP_. * omp-low.c (extract_omp_for_data): Rename non_ws to simd. Don't set fd->chunk_size for non-chunk OMP_CLAUSE_SCHEDULE_STATIC, unless fd->have_ordered. For OMP_CLAUSE_SCHEDULE_STATIC non-ordered loops compute fd->iter_type the same as for simd. (get_ws_args_for): Add par_stmt argument, if gimple_omp_for_combined_into_p, use first two _looptemp_ clauses temporaries instead of fd->loop.n{1,2}. (determine_parallel_type): Adjust caller. (scan_sharing_clauses): Handle OMP_CLAUSE__LOOPTEMP_. (find_combined_for): New function. (scan_omp_parallel): If gimple_omp_parallel_combined_p and it is combined with gimple_omp_for_combined_into_p OMP_FOR, add OMP_CLAUSE__LOOPTEMP_ clauses to the parallel. (check_omp_nesting_restrictions): Don't insist that the only construct nested in OMP_DISTRIBUTE must be OMP_PARALLEL. (lower_rec_input_clauses, lower_send_clauses): Handle OMP_CLAUSE__LOOPTEMP_. (expand_omp_for_init_counts, expand_omp_for_init_vars, extract_omp_for_update_vars): New functions. (expand_omp_for_generic): Add inner_stmt argument. Use expand_omp_for_{init,update}* helper functions. Handle combined loop constructs. (expand_omp_for_static_nochunk, expand_omp_for_static_chunk): Likewise. Handle fd->collapse > 1 and broken_loop cases. (expand_omp_simd): Use expand_omp_for_init* helper functions. Handle combined loop constructs. (expand_omp_for): Add inner_stmt argument. Pass it through to expand_omp_for_{generic,static_{,no}chunk}. Use expand_omp_for_static* even for fd->collapse > 1 and/or broken_loop cases, just not when fd->have_ordered. (expand_omp): Adjust expand_omp_for caller. (lower_omp_for): If gimple_omp_parallel_combined_p, add OMP_CLAUSE__LOOPTEMP_ clauses to the GIMPLE_FOR stmt. gcc/cp/ * decl2.c (cplus_decl_attributes): Only add attribute to TREE_STATIC vars. * parser.c (cp_parser_omp_distribute): Don't reject #pragma omp teams distribute simd and #pragma omp target teams distribute simd. Consume simd or parallel token. gcc/c-family/ * c-omp.c (c_omp_split_clauses): Fix up OMP_CLAUSE_COLLAPSE handling. libgomp/ * testsuite/libgomp.c/for-1.h: New file. * testsuite/libgomp.c/for-2.h: New file. * testsuite/libgomp.c/for-1.c: New test. * testsuite/libgomp.c/for-2.c: New test. * testsuite/libgomp.c++/for-9.C: New test. * testsuite/libgomp.c++/for-10.C: New test. * testsuite/libgomp.c++/for-11.C: New test. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gomp-4_0-branch@200287 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog.gomp | 53 + gcc/c-family/ChangeLog.gomp | 5 + gcc/c-family/c-omp.c | 2 +- gcc/cp/ChangeLog.gomp | 9 + gcc/cp/decl2.c | 2 +- gcc/cp/parser.c | 11 +- gcc/gimple.h | 28 +- gcc/gimplify.c | 16 +- gcc/omp-low.c | 1467 ++++++++++++++++-------- gcc/tree-pretty-print.c | 3 + gcc/tree.c | 3 + gcc/tree.h | 5 +- libgomp/ChangeLog.gomp | 10 + libgomp/testsuite/libgomp.c++/for-10.C | 44 + libgomp/testsuite/libgomp.c++/for-11.C | 111 ++ libgomp/testsuite/libgomp.c++/for-9.C | 33 + libgomp/testsuite/libgomp.c/for-1.c | 35 + libgomp/testsuite/libgomp.c/for-1.h | 25 + libgomp/testsuite/libgomp.c/for-2.c | 46 + libgomp/testsuite/libgomp.c/for-2.h | 269 +++++ 20 files changed, 1668 insertions(+), 509 deletions(-) create mode 100644 libgomp/testsuite/libgomp.c++/for-10.C create mode 100644 libgomp/testsuite/libgomp.c++/for-11.C create mode 100644 libgomp/testsuite/libgomp.c++/for-9.C create mode 100644 libgomp/testsuite/libgomp.c/for-1.c create mode 100644 libgomp/testsuite/libgomp.c/for-1.h create mode 100644 libgomp/testsuite/libgomp.c/for-2.c create mode 100644 libgomp/testsuite/libgomp.c/for-2.h diff --git a/gcc/ChangeLog.gomp b/gcc/ChangeLog.gomp index 7f9151d2f40d2..1ef47755ac63c 100644 --- a/gcc/ChangeLog.gomp +++ b/gcc/ChangeLog.gomp @@ -1,3 +1,56 @@ +2013-06-21 Jakub Jelinek + + * gimple.h (enum gf_mask): Adjust GF_OMP_FOR_COMBINED + value representation, add GF_OMP_FOR_COMBINED_INTO. + (gimple_omp_for_combined_into_p, + gimple_omp_for_set_combined_into_p): New inlines. + * gimplify.c (enum omp_region_type): Remove outdated + ORT_SIMD comment. + (struct gimplify_omp_ctx): Add combined_loop field. + (gimplify_omp_for): Call gimple_omp_for_set_combined_into_p + for inner for/simd constructs combined with an outer + loop construct (for or distribute). + * tree.c (omp_clause_num_ops): Add OMP_CLAUSE__LOOPTEMP_ + entry. + (omp_clause_code_name): Likewise. + (walk_tree_1): Handle OMP_CLAUSE__LOOPTEMP_. + * tree-pretty-print.c (dump_omp_clause): Handle OMP_CLAUSE__LOOPTEMP_. + * tree.h (enum omp_clause_code): Add OMP_CLAUSE__LOOPTEMP_. + (OMP_CLAUSE_DECL): Allow also on OMP_CLAUSE__LOOPTEMP_. + * omp-low.c (extract_omp_for_data): Rename non_ws to simd. Don't set + fd->chunk_size for non-chunk OMP_CLAUSE_SCHEDULE_STATIC, unless + fd->have_ordered. For OMP_CLAUSE_SCHEDULE_STATIC non-ordered loops + compute fd->iter_type the same as for simd. + (get_ws_args_for): Add par_stmt argument, if + gimple_omp_for_combined_into_p, use first two _looptemp_ clauses + temporaries instead of fd->loop.n{1,2}. + (determine_parallel_type): Adjust caller. + (scan_sharing_clauses): Handle OMP_CLAUSE__LOOPTEMP_. + (find_combined_for): New function. + (scan_omp_parallel): If gimple_omp_parallel_combined_p and + it is combined with gimple_omp_for_combined_into_p OMP_FOR, + add OMP_CLAUSE__LOOPTEMP_ clauses to the parallel. + (check_omp_nesting_restrictions): Don't insist that the only construct + nested in OMP_DISTRIBUTE must be OMP_PARALLEL. + (lower_rec_input_clauses, lower_send_clauses): Handle + OMP_CLAUSE__LOOPTEMP_. + (expand_omp_for_init_counts, expand_omp_for_init_vars, + extract_omp_for_update_vars): New functions. + (expand_omp_for_generic): Add inner_stmt argument. Use + expand_omp_for_{init,update}* helper functions. Handle combined loop + constructs. + (expand_omp_for_static_nochunk, expand_omp_for_static_chunk): + Likewise. Handle fd->collapse > 1 and broken_loop cases. + (expand_omp_simd): Use expand_omp_for_init* helper functions. Handle + combined loop constructs. + (expand_omp_for): Add inner_stmt argument. Pass it through to + expand_omp_for_{generic,static_{,no}chunk}. Use + expand_omp_for_static* even for fd->collapse > 1 and/or broken_loop + cases, just not when fd->have_ordered. + (expand_omp): Adjust expand_omp_for caller. + (lower_omp_for): If gimple_omp_parallel_combined_p, add + OMP_CLAUSE__LOOPTEMP_ clauses to the GIMPLE_FOR stmt. + 2013-06-14 Jakub Jelinek * gimple-pretty-print.c (dump_gimple_omp_for): Don't handle diff --git a/gcc/c-family/ChangeLog.gomp b/gcc/c-family/ChangeLog.gomp index 5a6e3d8d6691e..ce6c8dda44ae7 100644 --- a/gcc/c-family/ChangeLog.gomp +++ b/gcc/c-family/ChangeLog.gomp @@ -1,3 +1,8 @@ +2013-06-21 Jakub Jelinek + + * c-omp.c (c_omp_split_clauses): Fix up OMP_CLAUSE_COLLAPSE + handling. + 2013-06-14 Jakub Jelinek * c-common.h: Move omp_clause_mask code earlier in the file. diff --git a/gcc/c-family/c-omp.c b/gcc/c-family/c-omp.c index f80c73b028fff..75e607c3e55c9 100644 --- a/gcc/c-family/c-omp.c +++ b/gcc/c-family/c-omp.c @@ -680,7 +680,7 @@ c_omp_split_clauses (location_t loc, enum tree_code code, OMP_CLAUSE_CHAIN (c) = cclauses[C_OMP_CLAUSE_SPLIT_SIMD]; cclauses[C_OMP_CLAUSE_SPLIT_SIMD] = c; } - if (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS)) + if (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SCHEDULE)) { if (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)) diff --git a/gcc/cp/ChangeLog.gomp b/gcc/cp/ChangeLog.gomp index 08f2ed92daad3..2eadb071243e2 100644 --- a/gcc/cp/ChangeLog.gomp +++ b/gcc/cp/ChangeLog.gomp @@ -1,3 +1,12 @@ +2013-06-21 Jakub Jelinek + + * decl2.c (cplus_decl_attributes): Only add attribute + to TREE_STATIC vars. + * parser.c (cp_parser_omp_distribute): Don't reject + #pragma omp teams distribute simd and + #pragma omp target teams distribute simd. Consume + simd or parallel token. + 2013-06-14 Jakub Jelinek * parser.c (cp_parser_omp_all_clauses): Add defaulted finish_p diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 1aa2142326990..729fb7adaee63 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -1372,7 +1372,7 @@ cplus_decl_attributes (tree *decl, tree attributes, int flags) /* Add implicit "omp declare target" attribute if requested. */ if (current_omp_declare_target_attribute - && (TREE_CODE (*decl) == VAR_DECL + && ((TREE_CODE (*decl) == VAR_DECL && TREE_STATIC (*decl)) || TREE_CODE (*decl) == FUNCTION_DECL)) { if (TREE_CODE (*decl) == VAR_DECL diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 70d477b48e0e9..aea2ee7d284bc 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -29162,15 +29162,7 @@ cp_parser_omp_distribute (cp_parser *parser, cp_token *pragma_tok, bool parallel = false; if (strcmp (p, "simd") == 0) - { - simd = true; - if (cclauses) - { - error_at (loc, "% not expected after %qs", p_name); - cp_parser_skip_to_pragma_eol (parser, pragma_tok); - return NULL_TREE; - } - } + simd = true; else parallel = strcmp (p, "parallel") == 0; if (parallel || simd) @@ -29178,6 +29170,7 @@ cp_parser_omp_distribute (cp_parser *parser, cp_token *pragma_tok, tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; if (cclauses == NULL) cclauses = cclauses_buf; + cp_lexer_consume_token (parser->lexer); sb = begin_omp_structured_block (); save = cp_parser_begin_omp_structured_block (parser); if (simd) diff --git a/gcc/gimple.h b/gcc/gimple.h index 08dacc5c45962..e8357a57ba51b 100644 --- a/gcc/gimple.h +++ b/gcc/gimple.h @@ -114,7 +114,8 @@ enum gf_mask { GF_OMP_FOR_KIND_FOR = 0 << 0, GF_OMP_FOR_KIND_SIMD = 1 << 0, GF_OMP_FOR_KIND_DISTRIBUTE = 2 << 0, - GF_OMP_FOR_COMBINED = 4 << 0, + GF_OMP_FOR_COMBINED = 1 << 2, + GF_OMP_FOR_COMBINED_INTO = 1 << 3, GF_OMP_TARGET_KIND_MASK = 3 << 0, GF_OMP_TARGET_KIND_REGION = 0 << 0, GF_OMP_TARGET_KIND_DATA = 1 << 0, @@ -4028,6 +4029,31 @@ gimple_omp_for_set_combined_p (gimple g, bool combined_p) } +/* Return true if OMP for statement G has the + GF_OMP_FOR_COMBINED_INTO flag set. */ + +static inline bool +gimple_omp_for_combined_into_p (const_gimple g) +{ + GIMPLE_CHECK (g, GIMPLE_OMP_FOR); + return (gimple_omp_subcode (g) & GF_OMP_FOR_COMBINED_INTO) != 0; +} + + +/* Set the GF_OMP_FOR_COMBINED_INTO field in G depending on the boolean + value of COMBINED_P. */ + +static inline void +gimple_omp_for_set_combined_into_p (gimple g, bool combined_p) +{ + GIMPLE_CHECK (g, GIMPLE_OMP_FOR); + if (combined_p) + g->gsbase.subcode |= GF_OMP_FOR_COMBINED_INTO; + else + g->gsbase.subcode &= ~GF_OMP_FOR_COMBINED_INTO; +} + + /* Return the clauses associated with OMP_FOR GS. */ static inline tree diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 78ba9da2c3945..5fb7cccc656d4 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -71,7 +71,7 @@ enum gimplify_omp_var_data enum omp_region_type { ORT_WORKSHARE = 0, - ORT_SIMD = 1, /* #pragma omp for simd is ORT_WORKSHARE. */ + ORT_SIMD = 1, ORT_PARALLEL = 2, ORT_COMBINED_PARALLEL = 3, ORT_TASK = 4, @@ -89,6 +89,7 @@ struct gimplify_omp_ctx location_t location; enum omp_clause_default_kind default_kind; enum omp_region_type region_type; + bool combined_loop; }; static struct gimplify_ctx *gimplify_ctxp; @@ -6906,6 +6907,7 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) for_stmt = walk_tree (&OMP_FOR_BODY (for_stmt), find_combined_omp_for, NULL, NULL); gcc_assert (for_stmt != NULL_TREE); + gimplify_omp_ctxp->combined_loop = true; } for_body = NULL; @@ -7117,6 +7119,18 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) for_pre_body); if (orig_for_stmt != for_stmt) gimple_omp_for_set_combined_p (gfor, true); + if (gimplify_omp_ctxp + && (gimplify_omp_ctxp->combined_loop + || (gimplify_omp_ctxp->region_type == ORT_COMBINED_PARALLEL + && gimplify_omp_ctxp->outer_context + && gimplify_omp_ctxp->outer_context->combined_loop))) + { + gimple_omp_for_set_combined_into_p (gfor, true); + if (gimplify_omp_ctxp->combined_loop) + gcc_assert (TREE_CODE (orig_for_stmt) == OMP_SIMD); + else + gcc_assert (TREE_CODE (orig_for_stmt) == OMP_FOR); + } for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)); i++) { diff --git a/gcc/omp-low.c b/gcc/omp-low.c index ca42fcc610d61..fa7187f995d63 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -223,7 +223,7 @@ extract_omp_for_data (gimple for_stmt, struct omp_for_data *fd, int i; struct omp_for_data_loop dummy_loop; location_t loc = gimple_location (for_stmt); - bool non_ws = gimple_omp_for_kind (for_stmt) == GF_OMP_FOR_KIND_SIMD; + bool simd = gimple_omp_for_kind (for_stmt) == GF_OMP_FOR_KIND_SIMD; bool distribute = gimple_omp_for_kind (for_stmt) == GF_OMP_FOR_KIND_DISTRIBUTE; @@ -287,8 +287,7 @@ extract_omp_for_data (gimple for_stmt, struct omp_for_data *fd, /* We only need to compute a default chunk size for ordered static loops and dynamic loops. */ if (fd->sched_kind != OMP_CLAUSE_SCHEDULE_STATIC - || fd->have_ordered - || fd->collapse > 1) + || fd->have_ordered) fd->chunk_size = (fd->sched_kind == OMP_CLAUSE_SCHEDULE_STATIC) ? integer_zero_node : integer_one_node; } @@ -358,7 +357,9 @@ extract_omp_for_data (gimple for_stmt, struct omp_for_data *fd, gcc_unreachable (); } - if (non_ws) + if (simd + || (fd->sched_kind == OMP_CLAUSE_SCHEDULE_STATIC + && !fd->have_ordered)) { if (fd->collapse == 1) iter_type = TREE_TYPE (loop->v); @@ -465,7 +466,10 @@ extract_omp_for_data (gimple for_stmt, struct omp_for_data *fd, } } - if (count && !non_ws) + if (count + && !simd + && (fd->sched_kind != OMP_CLAUSE_SCHEDULE_STATIC + || fd->have_ordered)) { if (!tree_int_cst_lt (count, TYPE_MAX_VALUE (long_integer_type_node))) iter_type = long_long_unsigned_type_node; @@ -576,7 +580,7 @@ workshare_safe_to_combine_p (basic_block ws_entry_bb) expanded. */ static vec * -get_ws_args_for (gimple ws_stmt) +get_ws_args_for (gimple par_stmt, gimple ws_stmt) { tree t; location_t loc = gimple_location (ws_stmt); @@ -585,15 +589,31 @@ get_ws_args_for (gimple ws_stmt) if (gimple_code (ws_stmt) == GIMPLE_OMP_FOR) { struct omp_for_data fd; + tree n1, n2; extract_omp_for_data (ws_stmt, &fd, NULL); + n1 = fd.loop.n1; + n2 = fd.loop.n2; + + if (gimple_omp_for_combined_into_p (ws_stmt)) + { + tree innerc + = find_omp_clause (gimple_omp_parallel_clauses (par_stmt), + OMP_CLAUSE__LOOPTEMP_); + gcc_assert (innerc); + n1 = OMP_CLAUSE_DECL (innerc); + innerc = find_omp_clause (OMP_CLAUSE_CHAIN (innerc), + OMP_CLAUSE__LOOPTEMP_); + gcc_assert (innerc); + n2 = OMP_CLAUSE_DECL (innerc); + } vec_alloc (ws_args, 3 + (fd.chunk_size != 0)); - t = fold_convert_loc (loc, long_integer_type_node, fd.loop.n1); + t = fold_convert_loc (loc, long_integer_type_node, n1); ws_args->quick_push (t); - t = fold_convert_loc (loc, long_integer_type_node, fd.loop.n2); + t = fold_convert_loc (loc, long_integer_type_node, n2); ws_args->quick_push (t); t = fold_convert_loc (loc, long_integer_type_node, fd.loop.step); @@ -656,6 +676,7 @@ determine_parallel_type (struct omp_region *region) || (last_and_only_stmt (ws_entry_bb) && last_and_only_stmt (par_exit_bb)))) { + gimple par_stmt = last_stmt (par_entry_bb); gimple ws_stmt = last_stmt (ws_entry_bb); if (region->inner->type == GIMPLE_OMP_FOR) @@ -683,7 +704,7 @@ determine_parallel_type (struct omp_region *region) region->is_combined_parallel = true; region->inner->is_combined_parallel = true; - region->ws_args = get_ws_args_for (ws_stmt); + region->ws_args = get_ws_args_for (par_stmt, ws_stmt); } } @@ -1484,6 +1505,13 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) install_var_local (decl, ctx); break; + case OMP_CLAUSE__LOOPTEMP_: + gcc_assert (is_parallel_ctx (ctx)); + decl = OMP_CLAUSE_DECL (c); + install_var_field (decl, false, 3, ctx); + install_var_local (decl, ctx); + break; + case OMP_CLAUSE_COPYPRIVATE: case OMP_CLAUSE_COPYIN: decl = OMP_CLAUSE_DECL (c); @@ -1577,6 +1605,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) case OMP_CLAUSE_SAFELEN: case OMP_CLAUSE_ALIGNED: case OMP_CLAUSE_DEPEND: + case OMP_CLAUSE__LOOPTEMP_: break; default: @@ -1683,6 +1712,35 @@ create_omp_child_function (omp_context *ctx, bool task_copy) } +/* Callback for walk_gimple_seq. Check if combined parallel + contains gimple_omp_for_combined_into_p OMP_FOR. */ + +static tree +find_combined_for (gimple_stmt_iterator *gsi_p, + bool *handled_ops_p, + struct walk_stmt_info *wi) +{ + gimple stmt = gsi_stmt (*gsi_p); + + *handled_ops_p = true; + switch (gimple_code (stmt)) + { + WALK_SUBSTMTS; + + case GIMPLE_OMP_FOR: + if (gimple_omp_for_combined_into_p (stmt) + && gimple_omp_for_kind (stmt) == GF_OMP_FOR_KIND_FOR) + { + wi->info = stmt; + return integer_zero_node; + } + break; + default: + break; + } + return NULL; +} + /* Scan an OpenMP parallel directive. */ static void @@ -1703,6 +1761,40 @@ scan_omp_parallel (gimple_stmt_iterator *gsi, omp_context *outer_ctx) return; } + if (gimple_omp_parallel_combined_p (stmt)) + { + gimple for_stmt; + struct walk_stmt_info wi; + + memset (&wi, 0, sizeof (wi)); + wi.val_only = true; + walk_gimple_seq (gimple_omp_body (stmt), + find_combined_for, NULL, &wi); + for_stmt = (gimple) wi.info; + if (for_stmt) + { + struct omp_for_data fd; + extract_omp_for_data (for_stmt, &fd, NULL); + /* We need two temporaries with fd.loop.v type (istart/iend) + and then (fd.collapse - 1) temporaries with the same + type for count2 ... countN-1 vars if not constant. */ + size_t count = 2, i; + tree type = fd.iter_type; + if (fd.collapse > 1 + && TREE_CODE (fd.loop.n2) != INTEGER_CST) + count += fd.collapse - 1; + for (i = 0; i < count; i++) + { + tree temp = create_tmp_var (type, NULL); + tree c = build_omp_clause (UNKNOWN_LOCATION, + OMP_CLAUSE__LOOPTEMP_); + OMP_CLAUSE_DECL (c) = temp; + OMP_CLAUSE_CHAIN (c) = gimple_omp_parallel_clauses (stmt); + gimple_omp_parallel_set_clauses (stmt, c); + } + } + } + ctx = new_omp_context (stmt, outer_ctx); if (taskreg_nesting_level > 1) ctx->is_nested = true; @@ -1894,7 +1986,8 @@ check_omp_nesting_restrictions (gimple stmt, omp_context *ctx) else if (gimple_code (ctx->stmt) == GIMPLE_OMP_TEAMS) { if ((gimple_code (stmt) != GIMPLE_OMP_FOR - || gimple_omp_for_kind (ctx->stmt) != GF_OMP_FOR_KIND_DISTRIBUTE) + || (gimple_omp_for_kind (ctx->stmt) + != GF_OMP_FOR_KIND_DISTRIBUTE)) && gimple_code (stmt) != GIMPLE_OMP_PARALLEL) { error_at (gimple_location (stmt), @@ -1903,15 +1996,6 @@ check_omp_nesting_restrictions (gimple stmt, omp_context *ctx) return false; } } - else if (gimple_code (ctx->stmt) == GIMPLE_OMP_FOR - && gimple_omp_for_kind (ctx->stmt) == GF_OMP_FOR_KIND_DISTRIBUTE - && gimple_code (stmt) != GIMPLE_OMP_PARALLEL) - { - error_at (gimple_location (stmt), - "only parallel constructs are allowed to " - "be closely nested inside distribute construct"); - return false; - } } switch (gimple_code (stmt)) { @@ -2469,6 +2553,7 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, case OMP_CLAUSE_COPYIN: case OMP_CLAUSE_REDUCTION: case OMP_CLAUSE_LINEAR: + case OMP_CLAUSE__LOOPTEMP_: break; case OMP_CLAUSE_LASTPRIVATE: if (OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE (c)) @@ -2699,6 +2784,13 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, goto do_dtor; break; + case OMP_CLAUSE__LOOPTEMP_: + gcc_assert (is_parallel_ctx (ctx)); + x = build_outer_var_ref (var, ctx); + x = build2 (MODIFY_EXPR, TREE_TYPE (new_var), new_var, x); + gimplify_and_add (x, ilist); + break; + case OMP_CLAUSE_COPYIN: by_ref = use_pointer_for_field (var, NULL); x = build_receiver_ref (var, by_ref, ctx); @@ -3036,6 +3128,7 @@ lower_send_clauses (tree clauses, gimple_seq *ilist, gimple_seq *olist, case OMP_CLAUSE_COPYIN: case OMP_CLAUSE_LASTPRIVATE: case OMP_CLAUSE_REDUCTION: + case OMP_CLAUSE__LOOPTEMP_: break; default: continue; @@ -3056,6 +3149,7 @@ lower_send_clauses (tree clauses, gimple_seq *ilist, gimple_seq *olist, case OMP_CLAUSE_PRIVATE: case OMP_CLAUSE_FIRSTPRIVATE: case OMP_CLAUSE_COPYIN: + case OMP_CLAUSE__LOOPTEMP_: do_in = true; break; @@ -3892,6 +3986,340 @@ expand_omp_taskreg (struct omp_region *region) } +/* Helper function for expand_omp_{for_*,simd}. If this is the outermost + of the combined collapse > 1 loop constructs, generate code like: + if (__builtin_expect (N32 cond3 N31, 0)) goto ZERO_ITER_BB; + if (cond3 is <) + adj = STEP3 - 1; + else + adj = STEP3 + 1; + count3 = (adj + N32 - N31) / STEP3; + if (__builtin_expect (N22 cond2 N21, 0)) goto ZERO_ITER_BB; + if (cond2 is <) + adj = STEP2 - 1; + else + adj = STEP2 + 1; + count2 = (adj + N22 - N21) / STEP2; + if (__builtin_expect (N12 cond1 N11, 0)) goto ZERO_ITER_BB; + if (cond1 is <) + adj = STEP1 - 1; + else + adj = STEP1 + 1; + count1 = (adj + N12 - N11) / STEP1; + count = count1 * count2 * count3; + Furthermore, if ZERO_ITER_BB is NULL, create a BB which does: + count = 0; + and set ZERO_ITER_BB to that bb. If this isn't the outermost + of the combined loop constructs, just initialize COUNTS array + from the _looptemp_ clauses. */ + +static void +expand_omp_for_init_counts (struct omp_for_data *fd, gimple_stmt_iterator *gsi, + basic_block &entry_bb, tree *counts, + basic_block &zero_iter_bb, int &first_zero_iter, + basic_block &l2_dom_bb) +{ + tree t, type = TREE_TYPE (fd->loop.v); + gimple stmt; + edge e, ne; + int i; + + /* collapsed loops need work for expansion in SSA form. */ + gcc_assert (!gimple_in_ssa_p (cfun)); + + if (gimple_omp_for_combined_into_p (fd->for_stmt) + && TREE_CODE (fd->loop.n2) != INTEGER_CST) + { + /* First two _looptemp_ clauses are for istart/iend, counts[0] + isn't supposed to be handled, as the inner loop doesn't + use it. */ + tree innerc = find_omp_clause (gimple_omp_for_clauses (fd->for_stmt), + OMP_CLAUSE__LOOPTEMP_); + gcc_assert (innerc); + for (i = 0; i < fd->collapse; i++) + { + innerc = find_omp_clause (OMP_CLAUSE_CHAIN (innerc), + OMP_CLAUSE__LOOPTEMP_); + gcc_assert (innerc); + if (i) + counts[i] = OMP_CLAUSE_DECL (innerc); + else + counts[0] = NULL_TREE; + } + return; + } + + for (i = 0; i < fd->collapse; i++) + { + tree itype = TREE_TYPE (fd->loops[i].v); + + if (SSA_VAR_P (fd->loop.n2) + && ((t = fold_binary (fd->loops[i].cond_code, boolean_type_node, + fold_convert (itype, fd->loops[i].n1), + fold_convert (itype, fd->loops[i].n2))) + == NULL_TREE || !integer_onep (t))) + { + tree n1, n2; + n1 = fold_convert (itype, unshare_expr (fd->loops[i].n1)); + n1 = force_gimple_operand_gsi (gsi, n1, true, NULL_TREE, + true, GSI_SAME_STMT); + n2 = fold_convert (itype, unshare_expr (fd->loops[i].n2)); + n2 = force_gimple_operand_gsi (gsi, n2, true, NULL_TREE, + true, GSI_SAME_STMT); + stmt = gimple_build_cond (fd->loops[i].cond_code, n1, n2, + NULL_TREE, NULL_TREE); + gsi_insert_before (gsi, stmt, GSI_SAME_STMT); + if (walk_tree (gimple_cond_lhs_ptr (stmt), + expand_omp_regimplify_p, NULL, NULL) + || walk_tree (gimple_cond_rhs_ptr (stmt), + expand_omp_regimplify_p, NULL, NULL)) + { + *gsi = gsi_for_stmt (stmt); + gimple_regimplify_operands (stmt, gsi); + } + e = split_block (entry_bb, stmt); + if (zero_iter_bb == NULL) + { + first_zero_iter = i; + zero_iter_bb = create_empty_bb (entry_bb); + if (current_loops) + add_bb_to_loop (zero_iter_bb, entry_bb->loop_father); + *gsi = gsi_after_labels (zero_iter_bb); + stmt = gimple_build_assign (fd->loop.n2, + build_zero_cst (type)); + gsi_insert_before (gsi, stmt, GSI_SAME_STMT); + set_immediate_dominator (CDI_DOMINATORS, zero_iter_bb, + entry_bb); + } + ne = make_edge (entry_bb, zero_iter_bb, EDGE_FALSE_VALUE); + ne->probability = REG_BR_PROB_BASE / 2000 - 1; + e->flags = EDGE_TRUE_VALUE; + e->probability = REG_BR_PROB_BASE - ne->probability; + if (l2_dom_bb == NULL) + l2_dom_bb = entry_bb; + entry_bb = e->dest; + *gsi = gsi_last_bb (entry_bb); + } + + if (POINTER_TYPE_P (itype)) + itype = signed_type_for (itype); + t = build_int_cst (itype, (fd->loops[i].cond_code == LT_EXPR + ? -1 : 1)); + t = fold_build2 (PLUS_EXPR, itype, + fold_convert (itype, fd->loops[i].step), t); + t = fold_build2 (PLUS_EXPR, itype, t, + fold_convert (itype, fd->loops[i].n2)); + t = fold_build2 (MINUS_EXPR, itype, t, + fold_convert (itype, fd->loops[i].n1)); + if (TYPE_UNSIGNED (itype) && fd->loops[i].cond_code == GT_EXPR) + t = fold_build2 (TRUNC_DIV_EXPR, itype, + fold_build1 (NEGATE_EXPR, itype, t), + fold_build1 (NEGATE_EXPR, itype, + fold_convert (itype, + fd->loops[i].step))); + else + t = fold_build2 (TRUNC_DIV_EXPR, itype, t, + fold_convert (itype, fd->loops[i].step)); + t = fold_convert (type, t); + if (TREE_CODE (t) == INTEGER_CST) + counts[i] = t; + else + { + counts[i] = create_tmp_reg (type, ".count"); + expand_omp_build_assign (gsi, counts[i], t); + } + if (SSA_VAR_P (fd->loop.n2)) + { + if (i == 0) + t = counts[0]; + else + t = fold_build2 (MULT_EXPR, type, fd->loop.n2, counts[i]); + expand_omp_build_assign (gsi, fd->loop.n2, t); + } + } +} + + +/* Helper function for expand_omp_{for_*,simd}. Generate code like: + T = V; + V3 = N31 + (T % count3) * STEP3; + T = T / count3; + V2 = N21 + (T % count2) * STEP2; + T = T / count2; + V1 = N11 + T * STEP1; + if this loop doesn't have an inner loop construct combined with it. + If it does have an inner loop construct combined with it and the + iteration count isn't known constant, store values from counts array + into its _looptemp_ temporaries instead. */ + +static void +expand_omp_for_init_vars (struct omp_for_data *fd, gimple_stmt_iterator *gsi, + tree *counts, gimple inner_stmt, tree startvar) +{ + int i; + if (gimple_omp_for_combined_p (fd->for_stmt)) + { + /* If fd->loop.n2 is constant, then no propagation of the counts + is needed, they are constant. */ + if (TREE_CODE (fd->loop.n2) == INTEGER_CST) + return; + + tree clauses = gimple_code (inner_stmt) == GIMPLE_OMP_PARALLEL + ? gimple_omp_parallel_clauses (inner_stmt) + : gimple_omp_for_clauses (inner_stmt); + /* First two _looptemp_ clauses are for istart/iend, counts[0] + isn't supposed to be handled, as the inner loop doesn't + use it. */ + tree innerc = find_omp_clause (clauses, OMP_CLAUSE__LOOPTEMP_); + gcc_assert (innerc); + for (i = 0; i < fd->collapse; i++) + { + innerc = find_omp_clause (OMP_CLAUSE_CHAIN (innerc), + OMP_CLAUSE__LOOPTEMP_); + gcc_assert (innerc); + if (i) + { + tree tem = OMP_CLAUSE_DECL (innerc); + tree t = fold_convert (TREE_TYPE (tem), counts[i]); + t = force_gimple_operand_gsi (gsi, t, false, NULL_TREE, + false, GSI_CONTINUE_LINKING); + gimple stmt = gimple_build_assign (tem, t); + gsi_insert_after (gsi, stmt, GSI_CONTINUE_LINKING); + } + } + return; + } + + tree type = TREE_TYPE (fd->loop.v); + tree tem = create_tmp_reg (type, ".tem"); + gimple stmt = gimple_build_assign (tem, startvar); + gsi_insert_after (gsi, stmt, GSI_CONTINUE_LINKING); + + for (i = fd->collapse - 1; i >= 0; i--) + { + tree vtype = TREE_TYPE (fd->loops[i].v), itype, t; + itype = vtype; + if (POINTER_TYPE_P (vtype)) + itype = signed_type_for (vtype); + if (i != 0) + t = fold_build2 (TRUNC_MOD_EXPR, type, tem, counts[i]); + else + t = tem; + t = fold_convert (itype, t); + t = fold_build2 (MULT_EXPR, itype, t, + fold_convert (itype, fd->loops[i].step)); + if (POINTER_TYPE_P (vtype)) + t = fold_build_pointer_plus (fd->loops[i].n1, t); + else + t = fold_build2 (PLUS_EXPR, itype, fd->loops[i].n1, t); + t = force_gimple_operand_gsi (gsi, t, + DECL_P (fd->loops[i].v) + && TREE_ADDRESSABLE (fd->loops[i].v), + NULL_TREE, false, + GSI_CONTINUE_LINKING); + stmt = gimple_build_assign (fd->loops[i].v, t); + gsi_insert_after (gsi, stmt, GSI_CONTINUE_LINKING); + if (i != 0) + { + t = fold_build2 (TRUNC_DIV_EXPR, type, tem, counts[i]); + t = force_gimple_operand_gsi (gsi, t, false, NULL_TREE, + false, GSI_CONTINUE_LINKING); + stmt = gimple_build_assign (tem, t); + gsi_insert_after (gsi, stmt, GSI_CONTINUE_LINKING); + } + } +} + + +/* Helper function for expand_omp_for_*. Generate code like: + L10: + V3 += STEP3; + if (V3 cond3 N32) goto BODY_BB; else goto L11; + L11: + V3 = N31; + V2 += STEP2; + if (V2 cond2 N22) goto BODY_BB; else goto L12; + L12: + V2 = N21; + V1 += STEP1; + goto BODY_BB; */ + +static basic_block +extract_omp_for_update_vars (struct omp_for_data *fd, basic_block cont_bb, + basic_block body_bb) +{ + basic_block last_bb, bb, collapse_bb = NULL; + int i; + gimple_stmt_iterator gsi; + edge e; + tree t; + gimple stmt; + + last_bb = cont_bb; + for (i = fd->collapse - 1; i >= 0; i--) + { + tree vtype = TREE_TYPE (fd->loops[i].v); + + bb = create_empty_bb (last_bb); + if (current_loops) + add_bb_to_loop (bb, last_bb->loop_father); + gsi = gsi_start_bb (bb); + + if (i < fd->collapse - 1) + { + e = make_edge (last_bb, bb, EDGE_FALSE_VALUE); + e->probability = REG_BR_PROB_BASE / 8; + + t = fd->loops[i + 1].n1; + t = force_gimple_operand_gsi (&gsi, t, + DECL_P (fd->loops[i + 1].v) + && TREE_ADDRESSABLE (fd->loops[i + + 1].v), + NULL_TREE, false, + GSI_CONTINUE_LINKING); + stmt = gimple_build_assign (fd->loops[i + 1].v, t); + gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING); + } + else + collapse_bb = bb; + + set_immediate_dominator (CDI_DOMINATORS, bb, last_bb); + + if (POINTER_TYPE_P (vtype)) + t = fold_build_pointer_plus (fd->loops[i].v, fd->loops[i].step); + else + t = fold_build2 (PLUS_EXPR, vtype, fd->loops[i].v, fd->loops[i].step); + t = force_gimple_operand_gsi (&gsi, t, + DECL_P (fd->loops[i].v) + && TREE_ADDRESSABLE (fd->loops[i].v), + NULL_TREE, false, GSI_CONTINUE_LINKING); + stmt = gimple_build_assign (fd->loops[i].v, t); + gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING); + + if (i > 0) + { + t = fd->loops[i].n2; + t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, + false, GSI_CONTINUE_LINKING); + tree v = fd->loops[i].v; + if (DECL_P (v) && TREE_ADDRESSABLE (v)) + v = force_gimple_operand_gsi (&gsi, v, true, NULL_TREE, + false, GSI_CONTINUE_LINKING); + t = fold_build2 (fd->loops[i].cond_code, boolean_type_node, v, t); + stmt = gimple_build_cond_empty (t); + gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING); + e = make_edge (bb, body_bb, EDGE_TRUE_VALUE); + e->probability = REG_BR_PROB_BASE * 7 / 8; + } + else + make_edge (bb, body_bb, EDGE_FALLTHRU); + last_bb = bb; + } + + return collapse_bb; +} + + /* A subroutine of expand_omp_for. Generate code for a parallel loop with any schedule. Given parameters: @@ -3914,6 +4342,10 @@ expand_omp_taskreg (struct omp_region *region) If this is a combined omp parallel loop, instead of the call to GOMP_loop_foo_start, we call GOMP_loop_foo_next. + If this is gimple_omp_for_combined_p loop, then instead of assigning + V and iend in L0 we assign the first two _looptemp_ clause decls of the + inner GIMPLE_OMP_FOR and V += STEP; and + if (V cond iend) goto L1; else goto L2; are removed. For collapsed loops, given parameters: collapse(3) @@ -3983,7 +4415,8 @@ static void expand_omp_for_generic (struct omp_region *region, struct omp_for_data *fd, enum built_in_function start_fn, - enum built_in_function next_fn) + enum built_in_function next_fn, + gimple inner_stmt) { tree type, istart0, iend0, iend; tree t, vmain, vback, bias = NULL_TREE; @@ -4054,105 +4487,14 @@ expand_omp_for_generic (struct omp_region *region, gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR); if (fd->collapse > 1) { - basic_block zero_iter_bb = NULL; int first_zero_iter = -1; + basic_block zero_iter_bb = NULL, l2_dom_bb = NULL; - /* collapsed loops need work for expansion in SSA form. */ - gcc_assert (!gimple_in_ssa_p (cfun)); - counts = (tree *) alloca (fd->collapse * sizeof (tree)); - for (i = 0; i < fd->collapse; i++) - { - tree itype = TREE_TYPE (fd->loops[i].v); + counts = XALLOCAVEC (tree, fd->collapse); + expand_omp_for_init_counts (fd, &gsi, entry_bb, counts, + zero_iter_bb, first_zero_iter, + l2_dom_bb); - if (SSA_VAR_P (fd->loop.n2) - && ((t = fold_binary (fd->loops[i].cond_code, boolean_type_node, - fold_convert (itype, fd->loops[i].n1), - fold_convert (itype, fd->loops[i].n2))) - == NULL_TREE || !integer_onep (t))) - { - tree n1, n2; - n1 = fold_convert (itype, unshare_expr (fd->loops[i].n1)); - n1 = force_gimple_operand_gsi (&gsi, n1, true, NULL_TREE, - true, GSI_SAME_STMT); - n2 = fold_convert (itype, unshare_expr (fd->loops[i].n2)); - n2 = force_gimple_operand_gsi (&gsi, n2, true, NULL_TREE, - true, GSI_SAME_STMT); - stmt = gimple_build_cond (fd->loops[i].cond_code, n1, n2, - NULL_TREE, NULL_TREE); - gsi_insert_before (&gsi, stmt, GSI_SAME_STMT); - if (walk_tree (gimple_cond_lhs_ptr (stmt), - expand_omp_regimplify_p, NULL, NULL) - || walk_tree (gimple_cond_rhs_ptr (stmt), - expand_omp_regimplify_p, NULL, NULL)) - { - gsi = gsi_for_stmt (stmt); - gimple_regimplify_operands (stmt, &gsi); - } - e = split_block (entry_bb, stmt); - if (zero_iter_bb == NULL) - { - first_zero_iter = i; - zero_iter_bb = create_empty_bb (entry_bb); - if (current_loops) - add_bb_to_loop (zero_iter_bb, entry_bb->loop_father); - gsi = gsi_after_labels (zero_iter_bb); - stmt = gimple_build_assign (fd->loop.n2, - build_zero_cst (type)); - gsi_insert_before (&gsi, stmt, GSI_SAME_STMT); - set_immediate_dominator (CDI_DOMINATORS, zero_iter_bb, - entry_bb); - } - ne = make_edge (entry_bb, zero_iter_bb, EDGE_FALSE_VALUE); - ne->probability = REG_BR_PROB_BASE / 2000 - 1; - e->flags = EDGE_TRUE_VALUE; - e->probability = REG_BR_PROB_BASE - ne->probability; - entry_bb = e->dest; - gsi = gsi_last_bb (entry_bb); - } - if (POINTER_TYPE_P (itype)) - itype = signed_type_for (itype); - t = build_int_cst (itype, (fd->loops[i].cond_code == LT_EXPR - ? -1 : 1)); - t = fold_build2 (PLUS_EXPR, itype, - fold_convert (itype, fd->loops[i].step), t); - t = fold_build2 (PLUS_EXPR, itype, t, - fold_convert (itype, fd->loops[i].n2)); - t = fold_build2 (MINUS_EXPR, itype, t, - fold_convert (itype, fd->loops[i].n1)); - if (TYPE_UNSIGNED (itype) && fd->loops[i].cond_code == GT_EXPR) - t = fold_build2 (TRUNC_DIV_EXPR, itype, - fold_build1 (NEGATE_EXPR, itype, t), - fold_build1 (NEGATE_EXPR, itype, - fold_convert (itype, - fd->loops[i].step))); - else - t = fold_build2 (TRUNC_DIV_EXPR, itype, t, - fold_convert (itype, fd->loops[i].step)); - t = fold_convert (type, t); - if (TREE_CODE (t) == INTEGER_CST) - counts[i] = t; - else - { - counts[i] = create_tmp_reg (type, ".count"); - t = force_gimple_operand_gsi (&gsi, t, false, NULL_TREE, - true, GSI_SAME_STMT); - stmt = gimple_build_assign (counts[i], t); - gsi_insert_before (&gsi, stmt, GSI_SAME_STMT); - } - if (SSA_VAR_P (fd->loop.n2)) - { - if (i == 0) - t = counts[0]; - else - { - t = fold_build2 (MULT_EXPR, type, fd->loop.n2, counts[i]); - t = force_gimple_operand_gsi (&gsi, t, false, NULL_TREE, - true, GSI_SAME_STMT); - } - stmt = gimple_build_assign (fd->loop.n2, t); - gsi_insert_before (&gsi, stmt, GSI_SAME_STMT); - } - } if (zero_iter_bb) { /* Some counts[i] vars might be uninitialized if @@ -4187,18 +4529,32 @@ expand_omp_for_generic (struct omp_region *region, t4 = build_fold_addr_expr (iend0); t3 = build_fold_addr_expr (istart0); t2 = fold_convert (fd->iter_type, fd->loop.step); - if (POINTER_TYPE_P (type) - && TYPE_PRECISION (type) != TYPE_PRECISION (fd->iter_type)) + t1 = fd->loop.n2; + t0 = fd->loop.n1; + if (gimple_omp_for_combined_into_p (fd->for_stmt)) + { + tree innerc = find_omp_clause (gimple_omp_for_clauses (fd->for_stmt), + OMP_CLAUSE__LOOPTEMP_); + gcc_assert (innerc); + t0 = OMP_CLAUSE_DECL (innerc); + innerc = find_omp_clause (OMP_CLAUSE_CHAIN (innerc), + OMP_CLAUSE__LOOPTEMP_); + gcc_assert (innerc); + t1 = OMP_CLAUSE_DECL (innerc); + } + if (POINTER_TYPE_P (TREE_TYPE (t0)) + && TYPE_PRECISION (TREE_TYPE (t0)) + != TYPE_PRECISION (fd->iter_type)) { /* Avoid casting pointers to integer of a different size. */ tree itype = signed_type_for (type); - t1 = fold_convert (fd->iter_type, fold_convert (itype, fd->loop.n2)); - t0 = fold_convert (fd->iter_type, fold_convert (itype, fd->loop.n1)); + t1 = fold_convert (fd->iter_type, fold_convert (itype, t1)); + t0 = fold_convert (fd->iter_type, fold_convert (itype, t0)); } else { - t1 = fold_convert (fd->iter_type, fd->loop.n2); - t0 = fold_convert (fd->iter_type, fd->loop.n1); + t1 = fold_convert (fd->iter_type, t1); + t0 = fold_convert (fd->iter_type, t0); } if (bias) { @@ -4253,64 +4609,53 @@ expand_omp_for_generic (struct omp_region *region, gsi_remove (&gsi, true); /* Iteration setup for sequential loop goes in L0_BB. */ + tree startvar = fd->loop.v; + tree endvar = NULL_TREE; + + if (gimple_omp_for_combined_p (fd->for_stmt)) + { + gcc_assert (gimple_code (inner_stmt) == GIMPLE_OMP_FOR + && gimple_omp_for_kind (inner_stmt) + == GF_OMP_FOR_KIND_SIMD); + tree innerc = find_omp_clause (gimple_omp_for_clauses (inner_stmt), + OMP_CLAUSE__LOOPTEMP_); + gcc_assert (innerc); + startvar = OMP_CLAUSE_DECL (innerc); + innerc = find_omp_clause (OMP_CLAUSE_CHAIN (innerc), + OMP_CLAUSE__LOOPTEMP_); + gcc_assert (innerc); + endvar = OMP_CLAUSE_DECL (innerc); + } + gsi = gsi_start_bb (l0_bb); t = istart0; if (bias) t = fold_build2 (MINUS_EXPR, fd->iter_type, t, bias); - if (POINTER_TYPE_P (type)) - t = fold_convert (signed_type_for (type), t); - t = fold_convert (type, t); + if (POINTER_TYPE_P (TREE_TYPE (startvar))) + t = fold_convert (signed_type_for (TREE_TYPE (startvar)), t); + t = fold_convert (TREE_TYPE (startvar), t); t = force_gimple_operand_gsi (&gsi, t, - DECL_P (fd->loop.v) - && TREE_ADDRESSABLE (fd->loop.v), + DECL_P (startvar) + && TREE_ADDRESSABLE (startvar), NULL_TREE, false, GSI_CONTINUE_LINKING); - stmt = gimple_build_assign (fd->loop.v, t); + stmt = gimple_build_assign (startvar, t); gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING); t = iend0; if (bias) t = fold_build2 (MINUS_EXPR, fd->iter_type, t, bias); - if (POINTER_TYPE_P (type)) - t = fold_convert (signed_type_for (type), t); - t = fold_convert (type, t); + if (POINTER_TYPE_P (TREE_TYPE (startvar))) + t = fold_convert (signed_type_for (TREE_TYPE (startvar)), t); + t = fold_convert (TREE_TYPE (startvar), t); iend = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, false, GSI_CONTINUE_LINKING); - if (fd->collapse > 1) + if (endvar) { - tree tem = create_tmp_reg (type, ".tem"); - stmt = gimple_build_assign (tem, fd->loop.v); + stmt = gimple_build_assign (endvar, iend); gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING); - for (i = fd->collapse - 1; i >= 0; i--) - { - tree vtype = TREE_TYPE (fd->loops[i].v), itype; - itype = vtype; - if (POINTER_TYPE_P (vtype)) - itype = signed_type_for (vtype); - t = fold_build2 (TRUNC_MOD_EXPR, type, tem, counts[i]); - t = fold_convert (itype, t); - t = fold_build2 (MULT_EXPR, itype, t, - fold_convert (itype, fd->loops[i].step)); - if (POINTER_TYPE_P (vtype)) - t = fold_build_pointer_plus (fd->loops[i].n1, t); - else - t = fold_build2 (PLUS_EXPR, itype, fd->loops[i].n1, t); - t = force_gimple_operand_gsi (&gsi, t, - DECL_P (fd->loops[i].v) - && TREE_ADDRESSABLE (fd->loops[i].v), - NULL_TREE, false, - GSI_CONTINUE_LINKING); - stmt = gimple_build_assign (fd->loops[i].v, t); - gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING); - if (i != 0) - { - t = fold_build2 (TRUNC_DIV_EXPR, type, tem, counts[i]); - t = force_gimple_operand_gsi (&gsi, t, false, NULL_TREE, - false, GSI_CONTINUE_LINKING); - stmt = gimple_build_assign (tem, t); - gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING); - } - } } + if (fd->collapse > 1) + expand_omp_for_init_vars (fd, &gsi, counts, inner_stmt, startvar); if (!broken_loop) { @@ -4322,93 +4667,31 @@ expand_omp_for_generic (struct omp_region *region, vmain = gimple_omp_continue_control_use (stmt); vback = gimple_omp_continue_control_def (stmt); - if (POINTER_TYPE_P (type)) - t = fold_build_pointer_plus (vmain, fd->loop.step); - else - t = fold_build2 (PLUS_EXPR, type, vmain, fd->loop.step); - t = force_gimple_operand_gsi (&gsi, t, - DECL_P (vback) && TREE_ADDRESSABLE (vback), - NULL_TREE, true, GSI_SAME_STMT); - stmt = gimple_build_assign (vback, t); - gsi_insert_before (&gsi, stmt, GSI_SAME_STMT); - - t = build2 (fd->loop.cond_code, boolean_type_node, - DECL_P (vback) && TREE_ADDRESSABLE (vback) ? t : vback, - iend); - stmt = gimple_build_cond_empty (t); - gsi_insert_before (&gsi, stmt, GSI_SAME_STMT); + if (!gimple_omp_for_combined_p (fd->for_stmt)) + { + if (POINTER_TYPE_P (type)) + t = fold_build_pointer_plus (vmain, fd->loop.step); + else + t = fold_build2 (PLUS_EXPR, type, vmain, fd->loop.step); + t = force_gimple_operand_gsi (&gsi, t, + DECL_P (vback) + && TREE_ADDRESSABLE (vback), + NULL_TREE, true, GSI_SAME_STMT); + stmt = gimple_build_assign (vback, t); + gsi_insert_before (&gsi, stmt, GSI_SAME_STMT); + + t = build2 (fd->loop.cond_code, boolean_type_node, + DECL_P (vback) && TREE_ADDRESSABLE (vback) ? t : vback, + iend); + stmt = gimple_build_cond_empty (t); + gsi_insert_before (&gsi, stmt, GSI_SAME_STMT); + } /* Remove GIMPLE_OMP_CONTINUE. */ gsi_remove (&gsi, true); - if (fd->collapse > 1) - { - basic_block last_bb, bb; - - last_bb = cont_bb; - for (i = fd->collapse - 1; i >= 0; i--) - { - tree vtype = TREE_TYPE (fd->loops[i].v); - - bb = create_empty_bb (last_bb); - if (current_loops) - add_bb_to_loop (bb, last_bb->loop_father); - gsi = gsi_start_bb (bb); - - if (i < fd->collapse - 1) - { - e = make_edge (last_bb, bb, EDGE_FALSE_VALUE); - e->probability = REG_BR_PROB_BASE / 8; - - t = fd->loops[i + 1].n1; - t = force_gimple_operand_gsi (&gsi, t, - DECL_P (fd->loops[i + 1].v) - && TREE_ADDRESSABLE - (fd->loops[i + 1].v), - NULL_TREE, false, - GSI_CONTINUE_LINKING); - stmt = gimple_build_assign (fd->loops[i + 1].v, t); - gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING); - } - else - collapse_bb = bb; - - set_immediate_dominator (CDI_DOMINATORS, bb, last_bb); - - if (POINTER_TYPE_P (vtype)) - t = fold_build_pointer_plus (fd->loops[i].v, fd->loops[i].step); - else - t = fold_build2 (PLUS_EXPR, vtype, fd->loops[i].v, - fd->loops[i].step); - t = force_gimple_operand_gsi (&gsi, t, - DECL_P (fd->loops[i].v) - && TREE_ADDRESSABLE (fd->loops[i].v), - NULL_TREE, false, - GSI_CONTINUE_LINKING); - stmt = gimple_build_assign (fd->loops[i].v, t); - gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING); - - if (i > 0) - { - t = fd->loops[i].n2; - t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, - false, GSI_CONTINUE_LINKING); - tree v = fd->loops[i].v; - if (DECL_P (v) && TREE_ADDRESSABLE (v)) - v = force_gimple_operand_gsi (&gsi, v, true, NULL_TREE, - false, GSI_CONTINUE_LINKING); - t = fold_build2 (fd->loops[i].cond_code, boolean_type_node, - v, t); - stmt = gimple_build_cond_empty (t); - gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING); - e = make_edge (bb, l1_bb, EDGE_TRUE_VALUE); - e->probability = REG_BR_PROB_BASE * 7 / 8; - } - else - make_edge (bb, l1_bb, EDGE_FALLTHRU); - last_bb = bb; - } - } + if (fd->collapse > 1 && !gimple_omp_for_combined_p (fd->for_stmt)) + collapse_bb = extract_omp_for_update_vars (fd, cont_bb, l1_bb); /* Emit code to get the next parallel iteration in L2_BB. */ gsi = gsi_start_bb (l2_bb); @@ -4458,19 +4741,29 @@ expand_omp_for_generic (struct omp_region *region, make_edge (cont_bb, l2_bb, EDGE_FALSE_VALUE); if (current_loops) add_bb_to_loop (l2_bb, cont_bb->loop_father); - if (fd->collapse > 1) + e = find_edge (cont_bb, l1_bb); + if (gimple_omp_for_combined_p (fd->for_stmt)) + { + remove_edge (e); + e = NULL; + } + else if (fd->collapse > 1) { - e = find_edge (cont_bb, l1_bb); remove_edge (e); e = make_edge (cont_bb, collapse_bb, EDGE_TRUE_VALUE); } else + e->flags = EDGE_TRUE_VALUE; + if (e) { - e = find_edge (cont_bb, l1_bb); - e->flags = EDGE_TRUE_VALUE; + e->probability = REG_BR_PROB_BASE * 7 / 8; + find_edge (cont_bb, l2_bb)->probability = REG_BR_PROB_BASE / 8; + } + else + { + e = find_edge (cont_bb, l2_bb); + e->flags = EDGE_FALLTHRU; } - e->probability = REG_BR_PROB_BASE * 7 / 8; - find_edge (cont_bb, l2_bb)->probability = REG_BR_PROB_BASE / 8; make_edge (l2_bb, l0_bb, EDGE_TRUE_VALUE); set_immediate_dominator (CDI_DOMINATORS, l2_bb, @@ -4487,10 +4780,13 @@ expand_omp_for_generic (struct omp_region *region, outer_loop->latch = l2_bb; add_loop (outer_loop, l0_bb->loop_father); - struct loop *loop = alloc_loop (); - loop->header = l1_bb; - /* The loop may have multiple latches. */ - add_loop (loop, outer_loop); + if (!gimple_omp_for_combined_p (fd->for_stmt)) + { + struct loop *loop = alloc_loop (); + loop->header = l1_bb; + /* The loop may have multiple latches. */ + add_loop (loop, outer_loop); + } } } @@ -4534,18 +4830,22 @@ expand_omp_for_generic (struct omp_region *region, static void expand_omp_for_static_nochunk (struct omp_region *region, - struct omp_for_data *fd) + struct omp_for_data *fd, + gimple inner_stmt) { tree n, q, s0, e0, e, t, tt, nthreads, threadid; tree type, itype, vmain, vback; basic_block entry_bb, second_bb, third_bb, exit_bb, seq_start_bb; - basic_block body_bb, cont_bb; + basic_block body_bb, cont_bb, collapse_bb = NULL; basic_block fin_bb; gimple_stmt_iterator gsi; gimple stmt; edge ep; enum built_in_function get_num_threads = BUILT_IN_OMP_GET_NUM_THREADS; enum built_in_function get_thread_num = BUILT_IN_OMP_GET_THREAD_NUM; + bool broken_loop = region->cont == NULL; + tree *counts = NULL; + tree n1, n2, step; itype = type = TREE_TYPE (fd->loop.v); if (POINTER_TYPE_P (type)) @@ -4554,12 +4854,16 @@ expand_omp_for_static_nochunk (struct omp_region *region, entry_bb = region->entry; cont_bb = region->cont; gcc_assert (EDGE_COUNT (entry_bb->succs) == 2); - gcc_assert (BRANCH_EDGE (entry_bb)->dest == FALLTHRU_EDGE (cont_bb)->dest); + fin_bb = BRANCH_EDGE (entry_bb)->dest; + gcc_assert (broken_loop + || (fin_bb == FALLTHRU_EDGE (cont_bb)->dest)); seq_start_bb = split_edge (FALLTHRU_EDGE (entry_bb)); body_bb = single_succ (seq_start_bb); - gcc_assert (BRANCH_EDGE (cont_bb)->dest == body_bb); - gcc_assert (EDGE_COUNT (cont_bb->succs) == 2); - fin_bb = FALLTHRU_EDGE (cont_bb)->dest; + if (!broken_loop) + { + gcc_assert (BRANCH_EDGE (cont_bb)->dest == body_bb); + gcc_assert (EDGE_COUNT (cont_bb->succs) == 2); + } exit_bb = region->exit; /* Iteration space partitioning goes in ENTRY_BB. */ @@ -4572,13 +4876,27 @@ expand_omp_for_static_nochunk (struct omp_region *region, get_thread_num = BUILT_IN_OMP_GET_TEAM_NUM; } - t = fold_binary (fd->loop.cond_code, boolean_type_node, - fold_convert (type, fd->loop.n1), - fold_convert (type, fd->loop.n2)); - if (TYPE_UNSIGNED (type) + if (fd->collapse > 1) + { + int first_zero_iter = -1; + basic_block l2_dom_bb = NULL; + + counts = XALLOCAVEC (tree, fd->collapse); + expand_omp_for_init_counts (fd, &gsi, entry_bb, counts, + fin_bb, first_zero_iter, + l2_dom_bb); + t = NULL_TREE; + } + else if (gimple_omp_for_combined_into_p (fd->for_stmt)) + t = integer_one_node; + else + t = fold_binary (fd->loop.cond_code, boolean_type_node, + fold_convert (type, fd->loop.n1), + fold_convert (type, fd->loop.n2)); + if (fd->collapse == 1 + && TYPE_UNSIGNED (type) && (t == NULL_TREE || !integer_onep (t))) { - tree n1, n2; n1 = fold_convert (type, unshare_expr (fd->loop.n1)); n1 = force_gimple_operand_gsi (&gsi, n1, true, NULL_TREE, true, GSI_SAME_STMT); @@ -4626,26 +4944,37 @@ expand_omp_for_static_nochunk (struct omp_region *region, threadid = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, true, GSI_SAME_STMT); - fd->loop.n1 - = force_gimple_operand_gsi (&gsi, fold_convert (type, fd->loop.n1), - true, NULL_TREE, true, GSI_SAME_STMT); - fd->loop.n2 - = force_gimple_operand_gsi (&gsi, fold_convert (itype, fd->loop.n2), - true, NULL_TREE, true, GSI_SAME_STMT); - fd->loop.step - = force_gimple_operand_gsi (&gsi, fold_convert (itype, fd->loop.step), - true, NULL_TREE, true, GSI_SAME_STMT); + n1 = fd->loop.n1; + n2 = fd->loop.n2; + step = fd->loop.step; + if (gimple_omp_for_combined_into_p (fd->for_stmt)) + { + tree innerc = find_omp_clause (gimple_omp_for_clauses (fd->for_stmt), + OMP_CLAUSE__LOOPTEMP_); + gcc_assert (innerc); + n1 = OMP_CLAUSE_DECL (innerc); + innerc = find_omp_clause (OMP_CLAUSE_CHAIN (innerc), + OMP_CLAUSE__LOOPTEMP_); + gcc_assert (innerc); + n2 = OMP_CLAUSE_DECL (innerc); + } + n1 = force_gimple_operand_gsi (&gsi, fold_convert (type, n1), + true, NULL_TREE, true, GSI_SAME_STMT); + n2 = force_gimple_operand_gsi (&gsi, fold_convert (itype, n2), + true, NULL_TREE, true, GSI_SAME_STMT); + step = force_gimple_operand_gsi (&gsi, fold_convert (itype, step), + true, NULL_TREE, true, GSI_SAME_STMT); t = build_int_cst (itype, (fd->loop.cond_code == LT_EXPR ? -1 : 1)); - t = fold_build2 (PLUS_EXPR, itype, fd->loop.step, t); - t = fold_build2 (PLUS_EXPR, itype, t, fd->loop.n2); - t = fold_build2 (MINUS_EXPR, itype, t, fold_convert (itype, fd->loop.n1)); + t = fold_build2 (PLUS_EXPR, itype, step, t); + t = fold_build2 (PLUS_EXPR, itype, t, n2); + t = fold_build2 (MINUS_EXPR, itype, t, fold_convert (itype, n1)); if (TYPE_UNSIGNED (itype) && fd->loop.cond_code == GT_EXPR) t = fold_build2 (TRUNC_DIV_EXPR, itype, fold_build1 (NEGATE_EXPR, itype, t), - fold_build1 (NEGATE_EXPR, itype, fd->loop.step)); + fold_build1 (NEGATE_EXPR, itype, step)); else - t = fold_build2 (TRUNC_DIV_EXPR, itype, t, fd->loop.step); + t = fold_build2 (TRUNC_DIV_EXPR, itype, t, step); t = fold_convert (itype, t); n = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, true, GSI_SAME_STMT); @@ -4693,56 +5022,93 @@ expand_omp_for_static_nochunk (struct omp_region *region, /* Setup code for sequential iteration goes in SEQ_START_BB. */ gsi = gsi_start_bb (seq_start_bb); + tree startvar = fd->loop.v; + tree endvar = NULL_TREE; + + if (gimple_omp_for_combined_p (fd->for_stmt)) + { + tree clauses = gimple_code (inner_stmt) == GIMPLE_OMP_PARALLEL + ? gimple_omp_parallel_clauses (inner_stmt) + : gimple_omp_for_clauses (inner_stmt); + tree innerc = find_omp_clause (clauses, OMP_CLAUSE__LOOPTEMP_); + gcc_assert (innerc); + startvar = OMP_CLAUSE_DECL (innerc); + innerc = find_omp_clause (OMP_CLAUSE_CHAIN (innerc), + OMP_CLAUSE__LOOPTEMP_); + gcc_assert (innerc); + endvar = OMP_CLAUSE_DECL (innerc); + } t = fold_convert (itype, s0); - t = fold_build2 (MULT_EXPR, itype, t, fd->loop.step); + t = fold_build2 (MULT_EXPR, itype, t, step); if (POINTER_TYPE_P (type)) - t = fold_build_pointer_plus (fd->loop.n1, t); + t = fold_build_pointer_plus (n1, t); else - t = fold_build2 (PLUS_EXPR, type, t, fd->loop.n1); + t = fold_build2 (PLUS_EXPR, type, t, n1); + t = fold_convert (TREE_TYPE (startvar), t); t = force_gimple_operand_gsi (&gsi, t, - DECL_P (fd->loop.v) - && TREE_ADDRESSABLE (fd->loop.v), + DECL_P (startvar) + && TREE_ADDRESSABLE (startvar), NULL_TREE, false, GSI_CONTINUE_LINKING); - stmt = gimple_build_assign (fd->loop.v, t); + stmt = gimple_build_assign (startvar, t); gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING); t = fold_convert (itype, e0); - t = fold_build2 (MULT_EXPR, itype, t, fd->loop.step); + t = fold_build2 (MULT_EXPR, itype, t, step); if (POINTER_TYPE_P (type)) - t = fold_build_pointer_plus (fd->loop.n1, t); + t = fold_build_pointer_plus (n1, t); else - t = fold_build2 (PLUS_EXPR, type, t, fd->loop.n1); + t = fold_build2 (PLUS_EXPR, type, t, n1); + t = fold_convert (TREE_TYPE (startvar), t); e = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, false, GSI_CONTINUE_LINKING); + if (endvar) + { + stmt = gimple_build_assign (endvar, e); + gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING); + } + if (fd->collapse > 1) + expand_omp_for_init_vars (fd, &gsi, counts, inner_stmt, startvar); - /* The code controlling the sequential loop replaces the - GIMPLE_OMP_CONTINUE. */ - gsi = gsi_last_bb (cont_bb); - stmt = gsi_stmt (gsi); - gcc_assert (gimple_code (stmt) == GIMPLE_OMP_CONTINUE); - vmain = gimple_omp_continue_control_use (stmt); - vback = gimple_omp_continue_control_def (stmt); + if (!broken_loop) + { + /* The code controlling the sequential loop replaces the + GIMPLE_OMP_CONTINUE. */ + gsi = gsi_last_bb (cont_bb); + stmt = gsi_stmt (gsi); + gcc_assert (gimple_code (stmt) == GIMPLE_OMP_CONTINUE); + vmain = gimple_omp_continue_control_use (stmt); + vback = gimple_omp_continue_control_def (stmt); - if (POINTER_TYPE_P (type)) - t = fold_build_pointer_plus (vmain, fd->loop.step); - else - t = fold_build2 (PLUS_EXPR, type, vmain, fd->loop.step); - t = force_gimple_operand_gsi (&gsi, t, - DECL_P (vback) && TREE_ADDRESSABLE (vback), - NULL_TREE, true, GSI_SAME_STMT); - stmt = gimple_build_assign (vback, t); - gsi_insert_before (&gsi, stmt, GSI_SAME_STMT); + if (!gimple_omp_for_combined_p (fd->for_stmt)) + { + if (POINTER_TYPE_P (type)) + t = fold_build_pointer_plus (vmain, step); + else + t = fold_build2 (PLUS_EXPR, type, vmain, step); + t = force_gimple_operand_gsi (&gsi, t, + DECL_P (vback) + && TREE_ADDRESSABLE (vback), + NULL_TREE, true, GSI_SAME_STMT); + stmt = gimple_build_assign (vback, t); + gsi_insert_before (&gsi, stmt, GSI_SAME_STMT); + + t = build2 (fd->loop.cond_code, boolean_type_node, + DECL_P (vback) && TREE_ADDRESSABLE (vback) + ? t : vback, e); + gsi_insert_before (&gsi, gimple_build_cond_empty (t), GSI_SAME_STMT); + } - t = build2 (fd->loop.cond_code, boolean_type_node, - DECL_P (vback) && TREE_ADDRESSABLE (vback) ? t : vback, e); - gsi_insert_before (&gsi, gimple_build_cond_empty (t), GSI_SAME_STMT); + /* Remove the GIMPLE_OMP_CONTINUE statement. */ + gsi_remove (&gsi, true); - /* Remove the GIMPLE_OMP_CONTINUE statement. */ - gsi_remove (&gsi, true); + if (fd->collapse > 1 && !gimple_omp_for_combined_p (fd->for_stmt)) + collapse_bb = extract_omp_for_update_vars (fd, cont_bb, body_bb); + } /* Replace the GIMPLE_OMP_RETURN with a barrier, or nothing. */ gsi = gsi_last_bb (exit_bb); - if (!gimple_omp_return_nowait_p (gsi_stmt (gsi))) + if (!gimple_omp_return_nowait_p (gsi_stmt (gsi)) + && gimple_omp_for_kind (fd->for_stmt) == GF_OMP_FOR_KIND_FOR) force_gimple_operand_gsi (&gsi, build_omp_barrier (), false, NULL_TREE, false, GSI_SAME_STMT); gsi_remove (&gsi, true); @@ -4756,21 +5122,42 @@ expand_omp_for_static_nochunk (struct omp_region *region, find_edge (third_bb, seq_start_bb)->flags = EDGE_FALSE_VALUE; find_edge (third_bb, fin_bb)->flags = EDGE_TRUE_VALUE; - find_edge (cont_bb, body_bb)->flags = EDGE_TRUE_VALUE; - find_edge (cont_bb, fin_bb)->flags = EDGE_FALSE_VALUE; + if (!broken_loop) + { + ep = find_edge (cont_bb, body_bb); + if (gimple_omp_for_combined_p (fd->for_stmt)) + { + remove_edge (ep); + ep = NULL; + } + else if (fd->collapse > 1) + { + remove_edge (ep); + ep = make_edge (cont_bb, collapse_bb, EDGE_TRUE_VALUE); + } + else + ep->flags = EDGE_TRUE_VALUE; + find_edge (cont_bb, fin_bb)->flags + = ep ? EDGE_FALSE_VALUE : EDGE_FALLTHRU; + } set_immediate_dominator (CDI_DOMINATORS, second_bb, entry_bb); set_immediate_dominator (CDI_DOMINATORS, third_bb, entry_bb); set_immediate_dominator (CDI_DOMINATORS, seq_start_bb, third_bb); + set_immediate_dominator (CDI_DOMINATORS, body_bb, recompute_dominator (CDI_DOMINATORS, body_bb)); set_immediate_dominator (CDI_DOMINATORS, fin_bb, recompute_dominator (CDI_DOMINATORS, fin_bb)); - struct loop *loop = alloc_loop (); - loop->header = body_bb; - loop->latch = cont_bb; - add_loop (loop, body_bb->loop_father); + if (!broken_loop && !gimple_omp_for_combined_p (fd->for_stmt)) + { + struct loop *loop = alloc_loop (); + loop->header = body_bb; + if (collapse_bb == NULL) + loop->latch = cont_bb; + add_loop (loop, body_bb->loop_father); + } } @@ -4813,18 +5200,22 @@ expand_omp_for_static_nochunk (struct omp_region *region, */ static void -expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd) +expand_omp_for_static_chunk (struct omp_region *region, + struct omp_for_data *fd, gimple inner_stmt) { tree n, s0, e0, e, t; tree trip_var, trip_init, trip_main, trip_back, nthreads, threadid; tree type, itype, v_main, v_back, v_extra; basic_block entry_bb, exit_bb, body_bb, seq_start_bb, iter_part_bb; - basic_block trip_update_bb, cont_bb, fin_bb; + basic_block trip_update_bb = NULL, cont_bb, collapse_bb = NULL, fin_bb; gimple_stmt_iterator si; gimple stmt; edge se; enum built_in_function get_num_threads = BUILT_IN_OMP_GET_NUM_THREADS; enum built_in_function get_thread_num = BUILT_IN_OMP_GET_THREAD_NUM; + bool broken_loop = region->cont == NULL; + tree *counts = NULL; + tree n1, n2, step; itype = type = TREE_TYPE (fd->loop.v); if (POINTER_TYPE_P (type)) @@ -4836,14 +5227,17 @@ expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd) iter_part_bb = se->dest; cont_bb = region->cont; gcc_assert (EDGE_COUNT (iter_part_bb->succs) == 2); - gcc_assert (BRANCH_EDGE (iter_part_bb)->dest - == FALLTHRU_EDGE (cont_bb)->dest); + fin_bb = BRANCH_EDGE (iter_part_bb)->dest; + gcc_assert (broken_loop + || fin_bb == FALLTHRU_EDGE (cont_bb)->dest); seq_start_bb = split_edge (FALLTHRU_EDGE (iter_part_bb)); body_bb = single_succ (seq_start_bb); - gcc_assert (BRANCH_EDGE (cont_bb)->dest == body_bb); - gcc_assert (EDGE_COUNT (cont_bb->succs) == 2); - fin_bb = FALLTHRU_EDGE (cont_bb)->dest; - trip_update_bb = split_edge (FALLTHRU_EDGE (cont_bb)); + if (!broken_loop) + { + gcc_assert (BRANCH_EDGE (cont_bb)->dest == body_bb); + gcc_assert (EDGE_COUNT (cont_bb->succs) == 2); + trip_update_bb = split_edge (FALLTHRU_EDGE (cont_bb)); + } exit_bb = region->exit; /* Trip and adjustment setup goes in ENTRY_BB. */ @@ -4856,13 +5250,27 @@ expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd) get_thread_num = BUILT_IN_OMP_GET_TEAM_NUM; } - t = fold_binary (fd->loop.cond_code, boolean_type_node, - fold_convert (type, fd->loop.n1), - fold_convert (type, fd->loop.n2)); - if (TYPE_UNSIGNED (type) + if (fd->collapse > 1) + { + int first_zero_iter = -1; + basic_block l2_dom_bb = NULL; + + counts = XALLOCAVEC (tree, fd->collapse); + expand_omp_for_init_counts (fd, &si, entry_bb, counts, + fin_bb, first_zero_iter, + l2_dom_bb); + t = NULL_TREE; + } + else if (gimple_omp_for_combined_into_p (fd->for_stmt)) + t = integer_one_node; + else + t = fold_binary (fd->loop.cond_code, boolean_type_node, + fold_convert (type, fd->loop.n1), + fold_convert (type, fd->loop.n2)); + if (fd->collapse == 1 + && TYPE_UNSIGNED (type) && (t == NULL_TREE || !integer_onep (t))) { - tree n1, n2; n1 = fold_convert (type, unshare_expr (fd->loop.n1)); n1 = force_gimple_operand_gsi (&si, n1, true, NULL_TREE, true, GSI_SAME_STMT); @@ -4910,29 +5318,40 @@ expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd) threadid = force_gimple_operand_gsi (&si, t, true, NULL_TREE, true, GSI_SAME_STMT); - fd->loop.n1 - = force_gimple_operand_gsi (&si, fold_convert (type, fd->loop.n1), - true, NULL_TREE, true, GSI_SAME_STMT); - fd->loop.n2 - = force_gimple_operand_gsi (&si, fold_convert (itype, fd->loop.n2), - true, NULL_TREE, true, GSI_SAME_STMT); - fd->loop.step - = force_gimple_operand_gsi (&si, fold_convert (itype, fd->loop.step), - true, NULL_TREE, true, GSI_SAME_STMT); + n1 = fd->loop.n1; + n2 = fd->loop.n2; + step = fd->loop.step; + if (gimple_omp_for_combined_into_p (fd->for_stmt)) + { + tree innerc = find_omp_clause (gimple_omp_for_clauses (fd->for_stmt), + OMP_CLAUSE__LOOPTEMP_); + gcc_assert (innerc); + n1 = OMP_CLAUSE_DECL (innerc); + innerc = find_omp_clause (OMP_CLAUSE_CHAIN (innerc), + OMP_CLAUSE__LOOPTEMP_); + gcc_assert (innerc); + n2 = OMP_CLAUSE_DECL (innerc); + } + n1 = force_gimple_operand_gsi (&si, fold_convert (type, n1), + true, NULL_TREE, true, GSI_SAME_STMT); + n2 = force_gimple_operand_gsi (&si, fold_convert (itype, n2), + true, NULL_TREE, true, GSI_SAME_STMT); + step = force_gimple_operand_gsi (&si, fold_convert (itype, step), + true, NULL_TREE, true, GSI_SAME_STMT); fd->chunk_size = force_gimple_operand_gsi (&si, fold_convert (itype, fd->chunk_size), true, NULL_TREE, true, GSI_SAME_STMT); t = build_int_cst (itype, (fd->loop.cond_code == LT_EXPR ? -1 : 1)); - t = fold_build2 (PLUS_EXPR, itype, fd->loop.step, t); - t = fold_build2 (PLUS_EXPR, itype, t, fd->loop.n2); - t = fold_build2 (MINUS_EXPR, itype, t, fold_convert (itype, fd->loop.n1)); + t = fold_build2 (PLUS_EXPR, itype, step, t); + t = fold_build2 (PLUS_EXPR, itype, t, n2); + t = fold_build2 (MINUS_EXPR, itype, t, fold_convert (itype, n1)); if (TYPE_UNSIGNED (itype) && fd->loop.cond_code == GT_EXPR) t = fold_build2 (TRUNC_DIV_EXPR, itype, fold_build1 (NEGATE_EXPR, itype, t), - fold_build1 (NEGATE_EXPR, itype, fd->loop.step)); + fold_build1 (NEGATE_EXPR, itype, step)); else - t = fold_build2 (TRUNC_DIV_EXPR, itype, t, fd->loop.step); + t = fold_build2 (TRUNC_DIV_EXPR, itype, t, step); t = fold_convert (itype, t); n = force_gimple_operand_gsi (&si, t, true, NULL_TREE, true, GSI_SAME_STMT); @@ -4955,11 +5374,11 @@ expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd) gsi_insert_before (&si, stmt, GSI_SAME_STMT); t = fold_build2 (MULT_EXPR, itype, threadid, fd->chunk_size); - t = fold_build2 (MULT_EXPR, itype, t, fd->loop.step); + t = fold_build2 (MULT_EXPR, itype, t, step); if (POINTER_TYPE_P (type)) - t = fold_build_pointer_plus (fd->loop.n1, t); + t = fold_build_pointer_plus (n1, t); else - t = fold_build2 (PLUS_EXPR, type, t, fd->loop.n1); + t = fold_build2 (PLUS_EXPR, type, t, n1); v_extra = force_gimple_operand_gsi (&si, t, true, NULL_TREE, true, GSI_SAME_STMT); @@ -4986,65 +5405,101 @@ expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd) /* Setup code for sequential iteration goes in SEQ_START_BB. */ si = gsi_start_bb (seq_start_bb); + tree startvar = fd->loop.v; + tree endvar = NULL_TREE; + + if (gimple_omp_for_combined_p (fd->for_stmt)) + { + tree clauses = gimple_code (inner_stmt) == GIMPLE_OMP_PARALLEL + ? gimple_omp_parallel_clauses (inner_stmt) + : gimple_omp_for_clauses (inner_stmt); + tree innerc = find_omp_clause (clauses, OMP_CLAUSE__LOOPTEMP_); + gcc_assert (innerc); + startvar = OMP_CLAUSE_DECL (innerc); + innerc = find_omp_clause (OMP_CLAUSE_CHAIN (innerc), + OMP_CLAUSE__LOOPTEMP_); + gcc_assert (innerc); + endvar = OMP_CLAUSE_DECL (innerc); + } + t = fold_convert (itype, s0); - t = fold_build2 (MULT_EXPR, itype, t, fd->loop.step); + t = fold_build2 (MULT_EXPR, itype, t, step); if (POINTER_TYPE_P (type)) - t = fold_build_pointer_plus (fd->loop.n1, t); + t = fold_build_pointer_plus (n1, t); else - t = fold_build2 (PLUS_EXPR, type, t, fd->loop.n1); + t = fold_build2 (PLUS_EXPR, type, t, n1); + t = fold_convert (TREE_TYPE (startvar), t); t = force_gimple_operand_gsi (&si, t, - DECL_P (fd->loop.v) - && TREE_ADDRESSABLE (fd->loop.v), + DECL_P (startvar) + && TREE_ADDRESSABLE (startvar), NULL_TREE, false, GSI_CONTINUE_LINKING); - stmt = gimple_build_assign (fd->loop.v, t); + stmt = gimple_build_assign (startvar, t); gsi_insert_after (&si, stmt, GSI_CONTINUE_LINKING); t = fold_convert (itype, e0); - t = fold_build2 (MULT_EXPR, itype, t, fd->loop.step); + t = fold_build2 (MULT_EXPR, itype, t, step); if (POINTER_TYPE_P (type)) - t = fold_build_pointer_plus (fd->loop.n1, t); + t = fold_build_pointer_plus (n1, t); else - t = fold_build2 (PLUS_EXPR, type, t, fd->loop.n1); + t = fold_build2 (PLUS_EXPR, type, t, n1); + t = fold_convert (TREE_TYPE (startvar), t); e = force_gimple_operand_gsi (&si, t, true, NULL_TREE, false, GSI_CONTINUE_LINKING); + if (endvar) + { + stmt = gimple_build_assign (endvar, e); + gsi_insert_after (&si, stmt, GSI_CONTINUE_LINKING); + } + if (fd->collapse > 1) + expand_omp_for_init_vars (fd, &si, counts, inner_stmt, startvar); - /* The code controlling the sequential loop goes in CONT_BB, - replacing the GIMPLE_OMP_CONTINUE. */ - si = gsi_last_bb (cont_bb); - stmt = gsi_stmt (si); - gcc_assert (gimple_code (stmt) == GIMPLE_OMP_CONTINUE); - v_main = gimple_omp_continue_control_use (stmt); - v_back = gimple_omp_continue_control_def (stmt); + if (!broken_loop) + { + /* The code controlling the sequential loop goes in CONT_BB, + replacing the GIMPLE_OMP_CONTINUE. */ + si = gsi_last_bb (cont_bb); + stmt = gsi_stmt (si); + gcc_assert (gimple_code (stmt) == GIMPLE_OMP_CONTINUE); + v_main = gimple_omp_continue_control_use (stmt); + v_back = gimple_omp_continue_control_def (stmt); - if (POINTER_TYPE_P (type)) - t = fold_build_pointer_plus (v_main, fd->loop.step); - else - t = fold_build2 (PLUS_EXPR, type, v_main, fd->loop.step); - if (DECL_P (v_back) && TREE_ADDRESSABLE (v_back)) - t = force_gimple_operand_gsi (&si, t, true, NULL_TREE, - true, GSI_SAME_STMT); - stmt = gimple_build_assign (v_back, t); - gsi_insert_before (&si, stmt, GSI_SAME_STMT); + if (!gimple_omp_for_combined_p (fd->for_stmt)) + { + if (POINTER_TYPE_P (type)) + t = fold_build_pointer_plus (v_main, step); + else + t = fold_build2 (PLUS_EXPR, type, v_main, step); + if (DECL_P (v_back) && TREE_ADDRESSABLE (v_back)) + t = force_gimple_operand_gsi (&si, t, true, NULL_TREE, + true, GSI_SAME_STMT); + stmt = gimple_build_assign (v_back, t); + gsi_insert_before (&si, stmt, GSI_SAME_STMT); - t = build2 (fd->loop.cond_code, boolean_type_node, - DECL_P (v_back) && TREE_ADDRESSABLE (v_back) - ? t : v_back, e); - gsi_insert_before (&si, gimple_build_cond_empty (t), GSI_SAME_STMT); + t = build2 (fd->loop.cond_code, boolean_type_node, + DECL_P (v_back) && TREE_ADDRESSABLE (v_back) + ? t : v_back, e); + gsi_insert_before (&si, gimple_build_cond_empty (t), GSI_SAME_STMT); + } - /* Remove GIMPLE_OMP_CONTINUE. */ - gsi_remove (&si, true); + /* Remove GIMPLE_OMP_CONTINUE. */ + gsi_remove (&si, true); - /* Trip update code goes into TRIP_UPDATE_BB. */ - si = gsi_start_bb (trip_update_bb); + if (fd->collapse > 1 && !gimple_omp_for_combined_p (fd->for_stmt)) + collapse_bb = extract_omp_for_update_vars (fd, cont_bb, body_bb); - t = build_int_cst (itype, 1); - t = build2 (PLUS_EXPR, itype, trip_main, t); - stmt = gimple_build_assign (trip_back, t); - gsi_insert_after (&si, stmt, GSI_CONTINUE_LINKING); + /* Trip update code goes into TRIP_UPDATE_BB. */ + si = gsi_start_bb (trip_update_bb); + + t = build_int_cst (itype, 1); + t = build2 (PLUS_EXPR, itype, trip_main, t); + stmt = gimple_build_assign (trip_back, t); + gsi_insert_after (&si, stmt, GSI_CONTINUE_LINKING); + } /* Replace the GIMPLE_OMP_RETURN with a barrier, or nothing. */ si = gsi_last_bb (exit_bb); - if (!gimple_omp_return_nowait_p (gsi_stmt (si))) + if (!gimple_omp_return_nowait_p (gsi_stmt (si)) + && gimple_omp_for_kind (fd->for_stmt) == GF_OMP_FOR_KIND_FOR) force_gimple_operand_gsi (&si, build_omp_barrier (), false, NULL_TREE, false, GSI_SAME_STMT); gsi_remove (&si, true); @@ -5053,10 +5508,26 @@ expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd) find_edge (iter_part_bb, seq_start_bb)->flags = EDGE_TRUE_VALUE; find_edge (iter_part_bb, fin_bb)->flags = EDGE_FALSE_VALUE; - find_edge (cont_bb, body_bb)->flags = EDGE_TRUE_VALUE; - find_edge (cont_bb, trip_update_bb)->flags = EDGE_FALSE_VALUE; + if (!broken_loop) + { + se = find_edge (cont_bb, body_bb); + if (gimple_omp_for_combined_p (fd->for_stmt)) + { + remove_edge (se); + se = NULL; + } + else if (fd->collapse > 1) + { + remove_edge (se); + se = make_edge (cont_bb, collapse_bb, EDGE_TRUE_VALUE); + } + else + se->flags = EDGE_TRUE_VALUE; + find_edge (cont_bb, trip_update_bb)->flags + = se ? EDGE_FALSE_VALUE : EDGE_FALLTHRU; - redirect_edge_and_branch (single_succ_edge (trip_update_bb), iter_part_bb); + redirect_edge_and_branch (single_succ_edge (trip_update_bb), iter_part_bb); + } if (gimple_in_ssa_p (cfun)) { @@ -5067,6 +5538,8 @@ expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd) edge_var_map *vm; size_t i; + gcc_assert (fd->collapse == 1 && !broken_loop); + /* When we redirect the edge from trip_update_bb to iter_part_bb, we remove arguments of the phi nodes in fin_bb. We need to create appropriate phi nodes in iter_part_bb instead. */ @@ -5116,7 +5589,8 @@ expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd) UNKNOWN_LOCATION); } - set_immediate_dominator (CDI_DOMINATORS, trip_update_bb, cont_bb); + if (!broken_loop) + set_immediate_dominator (CDI_DOMINATORS, trip_update_bb, cont_bb); set_immediate_dominator (CDI_DOMINATORS, iter_part_bb, recompute_dominator (CDI_DOMINATORS, iter_part_bb)); set_immediate_dominator (CDI_DOMINATORS, fin_bb, @@ -5126,15 +5600,21 @@ expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd) set_immediate_dominator (CDI_DOMINATORS, body_bb, recompute_dominator (CDI_DOMINATORS, body_bb)); - struct loop *trip_loop = alloc_loop (); - trip_loop->header = iter_part_bb; - trip_loop->latch = trip_update_bb; - add_loop (trip_loop, iter_part_bb->loop_father); + if (!broken_loop) + { + struct loop *trip_loop = alloc_loop (); + trip_loop->header = iter_part_bb; + trip_loop->latch = trip_update_bb; + add_loop (trip_loop, iter_part_bb->loop_father); - struct loop *loop = alloc_loop (); - loop->header = body_bb; - loop->latch = cont_bb; - add_loop (loop, trip_loop); + if (!gimple_omp_for_combined_p (fd->for_stmt)) + { + struct loop *loop = alloc_loop (); + loop->header = body_bb; + loop->latch = cont_bb; + add_loop (loop, trip_loop); + } + } } @@ -5211,6 +5691,7 @@ expand_omp_simd (struct omp_region *region, struct omp_for_data *fd) int i; tree safelen = find_omp_clause (gimple_omp_for_clauses (fd->for_stmt), OMP_CLAUSE_SAFELEN); + tree n1, n2; type = TREE_TYPE (fd->loop.v); entry_bb = region->entry; @@ -5233,7 +5714,7 @@ expand_omp_simd (struct omp_region *region, struct omp_for_data *fd) l2_bb = single_succ (l1_bb); } exit_bb = region->exit; - l2_dom_bb = l1_bb; + l2_dom_bb = NULL; gsi = gsi_last_bb (entry_bb); @@ -5242,92 +5723,51 @@ expand_omp_simd (struct omp_region *region, struct omp_for_data *fd) gcc_assert (!gimple_in_ssa_p (cfun)); if (fd->collapse > 1) { + int first_zero_iter = -1; + basic_block zero_iter_bb = l2_bb; + counts = XALLOCAVEC (tree, fd->collapse); - for (i = 0; i < fd->collapse; i++) + expand_omp_for_init_counts (fd, &gsi, entry_bb, counts, + zero_iter_bb, first_zero_iter, + l2_dom_bb); + } + if (l2_dom_bb == NULL) + l2_dom_bb = l1_bb; + + n1 = fd->loop.n1; + n2 = fd->loop.n2; + if (gimple_omp_for_combined_into_p (fd->for_stmt)) + { + tree innerc = find_omp_clause (gimple_omp_for_clauses (fd->for_stmt), + OMP_CLAUSE__LOOPTEMP_); + gcc_assert (innerc); + n1 = OMP_CLAUSE_DECL (innerc); + innerc = find_omp_clause (OMP_CLAUSE_CHAIN (innerc), + OMP_CLAUSE__LOOPTEMP_); + gcc_assert (innerc); + n2 = OMP_CLAUSE_DECL (innerc); + expand_omp_build_assign (&gsi, fd->loop.v, + fold_convert (type, n1)); + if (fd->collapse > 1) { - tree itype = TREE_TYPE (fd->loops[i].v); - - if (SSA_VAR_P (fd->loop.n2) - && ((t = fold_binary (fd->loops[i].cond_code, boolean_type_node, - fold_convert (itype, fd->loops[i].n1), - fold_convert (itype, fd->loops[i].n2))) - == NULL_TREE || !integer_onep (t))) - { - tree n1, n2; - n1 = fold_convert (itype, unshare_expr (fd->loops[i].n1)); - n1 = force_gimple_operand_gsi (&gsi, n1, true, NULL_TREE, - true, GSI_SAME_STMT); - n2 = fold_convert (itype, unshare_expr (fd->loops[i].n2)); - n2 = force_gimple_operand_gsi (&gsi, n2, true, NULL_TREE, - true, GSI_SAME_STMT); - stmt = gimple_build_cond (fd->loops[i].cond_code, n1, n2, - NULL_TREE, NULL_TREE); - gsi_insert_before (&gsi, stmt, GSI_SAME_STMT); - if (walk_tree (gimple_cond_lhs_ptr (stmt), - expand_omp_regimplify_p, NULL, NULL) - || walk_tree (gimple_cond_rhs_ptr (stmt), - expand_omp_regimplify_p, NULL, NULL)) - { - gsi = gsi_for_stmt (stmt); - gimple_regimplify_operands (stmt, &gsi); - } - e = split_block (entry_bb, stmt); - ne = make_edge (entry_bb, l2_bb, EDGE_FALSE_VALUE); - ne->probability = REG_BR_PROB_BASE / 2000 - 1; - e->flags = EDGE_TRUE_VALUE; - e->probability = REG_BR_PROB_BASE - ne->probability; - if (l2_dom_bb == l1_bb) - l2_dom_bb = entry_bb; - entry_bb = e->dest; - e = BRANCH_EDGE (entry_bb); - gsi = gsi_last_bb (entry_bb); - } - if (POINTER_TYPE_P (itype)) - itype = signed_type_for (itype); - t = build_int_cst (itype, (fd->loops[i].cond_code == LT_EXPR - ? -1 : 1)); - t = fold_build2 (PLUS_EXPR, itype, - fold_convert (itype, fd->loops[i].step), t); - t = fold_build2 (PLUS_EXPR, itype, t, - fold_convert (itype, fd->loops[i].n2)); - t = fold_build2 (MINUS_EXPR, itype, t, - fold_convert (itype, fd->loops[i].n1)); - if (TYPE_UNSIGNED (itype) && fd->loops[i].cond_code == GT_EXPR) - t = fold_build2 (TRUNC_DIV_EXPR, itype, - fold_build1 (NEGATE_EXPR, itype, t), - fold_build1 (NEGATE_EXPR, itype, - fold_convert (itype, - fd->loops[i].step))); - else - t = fold_build2 (TRUNC_DIV_EXPR, itype, t, - fold_convert (itype, fd->loops[i].step)); - t = fold_convert (type, t); - if (TREE_CODE (t) == INTEGER_CST) - counts[i] = t; - else - { - counts[i] = create_tmp_reg (type, ".count"); - expand_omp_build_assign (&gsi, counts[i], t); - } - if (SSA_VAR_P (fd->loop.n2)) - { - if (i == 0) - t = counts[0]; - else - t = fold_build2 (MULT_EXPR, type, fd->loop.n2, counts[i]); - expand_omp_build_assign (&gsi, fd->loop.n2, t); - } + gsi_prev (&gsi); + expand_omp_for_init_vars (fd, &gsi, counts, NULL, n1); + gsi_next (&gsi); } } - expand_omp_build_assign (&gsi, fd->loop.v, fold_convert (type, fd->loop.n1)); - if (fd->collapse > 1) - for (i = 0; i < fd->collapse; i++) - { - tree itype = TREE_TYPE (fd->loops[i].v); - if (POINTER_TYPE_P (itype)) - itype = signed_type_for (itype); - t = fold_convert (TREE_TYPE (fd->loops[i].v), fd->loops[i].n1); - expand_omp_build_assign (&gsi, fd->loops[i].v, t); + else + { + expand_omp_build_assign (&gsi, fd->loop.v, + fold_convert (type, fd->loop.n1)); + if (fd->collapse > 1) + for (i = 0; i < fd->collapse; i++) + { + tree itype = TREE_TYPE (fd->loops[i].v); + if (POINTER_TYPE_P (itype)) + itype = signed_type_for (itype); + t = fold_convert (TREE_TYPE (fd->loops[i].v), fd->loops[i].n1); + expand_omp_build_assign (&gsi, fd->loops[i].v, t); + } } /* Remove the GIMPLE_OMP_FOR statement. */ @@ -5351,7 +5791,7 @@ expand_omp_simd (struct omp_region *region, struct omp_for_data *fd) i = fd->collapse - 1; if (POINTER_TYPE_P (TREE_TYPE (fd->loops[i].v))) { - t = fold_convert (sizetype, fd->loop.step); + t = fold_convert (sizetype, fd->loops[i].step); t = fold_build_pointer_plus (fd->loops[i].v, t); } else @@ -5398,7 +5838,7 @@ expand_omp_simd (struct omp_region *region, struct omp_for_data *fd) /* Emit the condition in L1_BB. */ gsi = gsi_start_bb (l1_bb); - t = fold_convert (type, fd->loop.n2); + t = fold_convert (type, n2); t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, false, GSI_CONTINUE_LINKING); t = build2 (fd->loop.cond_code, boolean_type_node, fd->loop.v, t); @@ -5478,7 +5918,7 @@ expand_omp_simd (struct omp_region *region, struct omp_for_data *fd) /* Expand the OpenMP loop defined by REGION. */ static void -expand_omp_for (struct omp_region *region) +expand_omp_for (struct omp_region *region, gimple inner_stmt) { struct omp_for_data fd; struct omp_for_data_loop *loops; @@ -5508,23 +5948,19 @@ expand_omp_for (struct omp_region *region) if (gimple_omp_for_kind (fd.for_stmt) == GF_OMP_FOR_KIND_SIMD) expand_omp_simd (region, &fd); else if (fd.sched_kind == OMP_CLAUSE_SCHEDULE_STATIC - && !fd.have_ordered - && fd.collapse == 1 - && region->cont != NULL) + && !fd.have_ordered) { if (fd.chunk_size == NULL) - expand_omp_for_static_nochunk (region, &fd); + expand_omp_for_static_nochunk (region, &fd, inner_stmt); else - expand_omp_for_static_chunk (region, &fd); + expand_omp_for_static_chunk (region, &fd, inner_stmt); } else { int fn_index, start_ix, next_ix; - /* FIXME: expand_omp_for_static_*chunk needs to handle - collapse > 1 for distribute. */ gcc_assert (gimple_omp_for_kind (fd.for_stmt) - != GF_OMP_FOR_KIND_DISTRIBUTE); + == GF_OMP_FOR_KIND_FOR); if (fd.chunk_size == NULL && fd.sched_kind == OMP_CLAUSE_SCHEDULE_STATIC) fd.chunk_size = integer_zero_node; @@ -5542,7 +5978,7 @@ expand_omp_for (struct omp_region *region) - (int)BUILT_IN_GOMP_LOOP_STATIC_NEXT); } expand_omp_for_generic (region, &fd, (enum built_in_function) start_ix, - (enum built_in_function) next_ix); + (enum built_in_function) next_ix, inner_stmt); } if (gimple_in_ssa_p (cfun)) @@ -6419,12 +6855,17 @@ expand_omp (struct omp_region *region) while (region) { location_t saved_location; + gimple inner_stmt = NULL; /* First, determine whether this is a combined parallel+workshare region. */ if (region->type == GIMPLE_OMP_PARALLEL) determine_parallel_type (region); + if (region->type == GIMPLE_OMP_FOR + && gimple_omp_for_combined_p (last_stmt (region->entry))) + inner_stmt = last_stmt (region->inner->entry); + if (region->inner) expand_omp (region->inner); @@ -6440,7 +6881,7 @@ expand_omp (struct omp_region *region) break; case GIMPLE_OMP_FOR: - expand_omp_for (region); + expand_omp_for (region, inner_stmt); break; case GIMPLE_OMP_SECTIONS: @@ -7197,6 +7638,42 @@ lower_omp_for (gimple_stmt_iterator *gsi_p, omp_context *ctx) /* Once lowered, extract the bounds and clauses. */ extract_omp_for_data (stmt, &fd, NULL); + if (gimple_omp_for_combined_into_p (stmt)) + { + /* We need two temporaries with fd.loop.v type (istart/iend) + and then (fd.collapse - 1) temporaries with the same + type for count2 ... countN-1 vars if not constant. */ + size_t count = 2; + tree type = fd.iter_type; + if (fd.collapse > 1 + && TREE_CODE (fd.loop.n2) != INTEGER_CST) + count += fd.collapse - 1; + bool parallel_for = gimple_omp_for_kind (stmt) == GF_OMP_FOR_KIND_FOR; + tree outerc = NULL, *pc = gimple_omp_for_clauses_ptr (stmt); + tree clauses = *pc; + if (parallel_for) + outerc + = find_omp_clause (gimple_omp_parallel_clauses (ctx->outer->stmt), + OMP_CLAUSE__LOOPTEMP_); + for (i = 0; i < count; i++) + { + tree temp; + if (parallel_for) + { + gcc_assert (outerc); + temp = lookup_decl (OMP_CLAUSE_DECL (outerc), ctx->outer); + outerc = find_omp_clause (OMP_CLAUSE_CHAIN (outerc), + OMP_CLAUSE__LOOPTEMP_); + } + else + temp = create_tmp_var (type, NULL); + *pc = build_omp_clause (UNKNOWN_LOCATION, OMP_CLAUSE__LOOPTEMP_); + OMP_CLAUSE_DECL (*pc) = temp; + pc = &OMP_CLAUSE_CHAIN (*pc); + } + *pc = clauses; + } + if (gimple_omp_for_kind (fd.for_stmt) != GF_OMP_FOR_KIND_SIMD) lower_omp_for_lastprivate (&fd, &body, &dlist, ctx); diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c index 9c3d15e1489b1..7711a9b0123e3 100644 --- a/gcc/tree-pretty-print.c +++ b/gcc/tree-pretty-print.c @@ -317,6 +317,9 @@ dump_omp_clause (pretty_printer *buffer, tree clause, int spc, int flags) case OMP_CLAUSE_UNIFORM: name = "uniform"; goto print_remap; + case OMP_CLAUSE__LOOPTEMP_: + name = "_looptemp_"; + goto print_remap; print_remap: pp_string (buffer, name); pp_character (buffer, '('); diff --git a/gcc/tree.c b/gcc/tree.c index 2485d2e7fee1e..e88b290a82165 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -242,6 +242,7 @@ unsigned const char omp_clause_num_ops[] = 2, /* OMP_CLAUSE_FROM */ 2, /* OMP_CLAUSE_TO */ 2, /* OMP_CLAUSE_MAP */ + 1, /* OMP_CLAUSE__LOOPTEMP_ */ 1, /* OMP_CLAUSE_IF */ 1, /* OMP_CLAUSE_NUM_THREADS */ 1, /* OMP_CLAUSE_SCHEDULE */ @@ -284,6 +285,7 @@ const char * const omp_clause_code_name[] = "from", "to", "map", + "_looptemp_", "if", "num_threads", "schedule", @@ -11021,6 +11023,7 @@ walk_tree_1 (tree *tp, walk_tree_fn func, void *data, case OMP_CLAUSE_DIST_SCHEDULE: case OMP_CLAUSE_SAFELEN: case OMP_CLAUSE_SIMDLEN: + case OMP_CLAUSE__LOOPTEMP_: WALK_SUBTREE (OMP_CLAUSE_OPERAND (*tp, 0)); /* FALLTHRU */ diff --git a/gcc/tree.h b/gcc/tree.h index 7f2e173012846..d438e913ef5ec 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -386,6 +386,9 @@ enum omp_clause_code /* OpenMP clause: map ({alloc:,to:,from:,tofrom:,}variable-list). */ OMP_CLAUSE_MAP, + /* Internal clause: temporary for combined loops expansion. */ + OMP_CLAUSE__LOOPTEMP_, + /* OpenMP clause: if (scalar-expression). */ OMP_CLAUSE_IF, @@ -1889,7 +1892,7 @@ extern void protected_set_expr_location (tree, location_t); #define OMP_CLAUSE_DECL(NODE) \ OMP_CLAUSE_OPERAND (OMP_CLAUSE_RANGE_CHECK (OMP_CLAUSE_CHECK (NODE), \ OMP_CLAUSE_PRIVATE, \ - OMP_CLAUSE_MAP), 0) + OMP_CLAUSE__LOOPTEMP_), 0) #define OMP_CLAUSE_HAS_LOCATION(NODE) \ (LOCATION_LOCUS ((OMP_CLAUSE_CHECK (NODE))->omp_clause.locus) \ != UNKNOWN_LOCATION) diff --git a/libgomp/ChangeLog.gomp b/libgomp/ChangeLog.gomp index 5c3df790645bd..025d4b3941367 100644 --- a/libgomp/ChangeLog.gomp +++ b/libgomp/ChangeLog.gomp @@ -1,3 +1,13 @@ +2013-06-21 Jakub Jelinek + + * testsuite/libgomp.c/for-1.h: New file. + * testsuite/libgomp.c/for-2.h: New file. + * testsuite/libgomp.c/for-1.c: New test. + * testsuite/libgomp.c/for-2.c: New test. + * testsuite/libgomp.c++/for-9.C: New test. + * testsuite/libgomp.c++/for-10.C: New test. + * testsuite/libgomp.c++/for-11.C: New test. + 2013-06-12 Jakub Jelinek * fortran.c (omp_is_initial_device): Add ialias_redirect. diff --git a/libgomp/testsuite/libgomp.c++/for-10.C b/libgomp/testsuite/libgomp.c++/for-10.C new file mode 100644 index 0000000000000..fb1a3e952b177 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/for-10.C @@ -0,0 +1,44 @@ +extern "C" void abort (); + +#define M(x, y, z) O(x, y, z) +#define O(x, y, z) x ## _ ## y ## _ ## z + +#define F simd +#define G simd +#define S +#define N(x) M(x, G, normal) +#include "../libgomp.c/for-2.h" +#undef S +#undef N +#undef F +#undef G + +#define F parallel for simd +#define G pf_simd +#include "../libgomp.c/for-1.h" +#undef F +#undef G + +#define F for simd +#define G f_simd +#include "../libgomp.c/for-1.h" +#undef F +#undef G + +int +main () +{ + if (test_simd_normal () + || test_pf_simd_static () + || test_pf_simd_static32 () + || test_pf_simd_auto () + || test_pf_simd_guided32 () + || test_pf_simd_runtime () + || test_f_simd_static () + || test_f_simd_static32 () + || test_f_simd_auto () + || test_f_simd_guided32 () + || test_f_simd_runtime ()) + abort (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/for-11.C b/libgomp/testsuite/libgomp.c++/for-11.C new file mode 100644 index 0000000000000..848fc04d81ced --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/for-11.C @@ -0,0 +1,111 @@ +extern "C" void abort (); + +#define M(x, y, z) O(x, y, z) +#define O(x, y, z) x ## _ ## y ## _ ## z + +#pragma omp declare target + +#define F distribute +#define G d +#define S +#define N(x) M(x, G, normal) +#include "../libgomp.c/for-2.h" +#undef S +#undef N +#undef F +#undef G + +#define F distribute +#define G d_ds128 +#define S dist_schedule(static, 128) +#define N(x) M(x, G, normal) +#include "../libgomp.c/for-2.h" +#undef S +#undef N +#undef F +#undef G + +#define F distribute simd +#define G ds +#define S +#define N(x) M(x, G, normal) +#include "../libgomp.c/for-2.h" +#undef S +#undef N +#undef F +#undef G + +#define F distribute simd +#define G ds_ds128 +#define S dist_schedule(static, 128) +#define N(x) M(x, G, normal) +#include "../libgomp.c/for-2.h" +#undef S +#undef N +#undef F +#undef G + +#define F distribute parallel for +#define G dpf +#include "../libgomp.c/for-1.h" +#undef F +#undef G + +#define F distribute parallel for dist_schedule(static, 128) +#define G dpf_ds128 +#include "../libgomp.c/for-1.h" +#undef F +#undef G + +#define F distribute parallel for simd +#define G dpfs +#include "../libgomp.c/for-1.h" +#undef F +#undef G + +#define F distribute parallel for simd dist_schedule(static, 128) +#define G dpfs_ds128 +#include "../libgomp.c/for-1.h" +#undef F +#undef G + +#pragma omp end declare target + +int +main () +{ + int err = 0; +// FIXME: distribute construct must be closely nested +// in teams region, but we don't handle target expansions +// yet. Enable when it works. +// #pragma omp target teams reduction(|:err) + { + err |= test_d_normal (); + err |= test_d_ds128_normal (); + err |= test_ds_normal (); + err |= test_ds_ds128_normal (); + err |= test_dpf_static (); + err |= test_dpf_static32 (); + err |= test_dpf_auto (); + err |= test_dpf_guided32 (); + err |= test_dpf_runtime (); + err |= test_dpf_ds128_static (); + err |= test_dpf_ds128_static32 (); + err |= test_dpf_ds128_auto (); + err |= test_dpf_ds128_guided32 (); + err |= test_dpf_ds128_runtime (); + err |= test_dpfs_static (); + err |= test_dpfs_static32 (); + err |= test_dpfs_auto (); + err |= test_dpfs_guided32 (); + err |= test_dpfs_runtime (); + err |= test_dpfs_ds128_static (); + err |= test_dpfs_ds128_static32 (); + err |= test_dpfs_ds128_auto (); + err |= test_dpfs_ds128_guided32 (); + err |= test_dpfs_ds128_runtime (); + } + if (err) + abort (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/for-9.C b/libgomp/testsuite/libgomp.c++/for-9.C new file mode 100644 index 0000000000000..86b9d9318cb9f --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/for-9.C @@ -0,0 +1,33 @@ +extern "C" void abort (); + +#define M(x, y, z) O(x, y, z) +#define O(x, y, z) x ## _ ## y ## _ ## z + +#define F parallel for +#define G pf +#include "../libgomp.c/for-1.h" +#undef F +#undef G + +#define F for +#define G f +#include "../libgomp.c/for-1.h" +#undef F +#undef G + +int +main () +{ + if (test_pf_static () + || test_pf_static32 () + || test_pf_auto () + || test_pf_guided32 () + || test_pf_runtime () + || test_f_static () + || test_f_static32 () + || test_f_auto () + || test_f_guided32 () + || test_f_runtime ()) + abort (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c/for-1.c b/libgomp/testsuite/libgomp.c/for-1.c new file mode 100644 index 0000000000000..e702453fb1a63 --- /dev/null +++ b/libgomp/testsuite/libgomp.c/for-1.c @@ -0,0 +1,35 @@ +/* { dg-options "-std=gnu99 -fopenmp" } */ + +extern void abort (void); + +#define M(x, y, z) O(x, y, z) +#define O(x, y, z) x ## _ ## y ## _ ## z + +#define F parallel for +#define G pf +#include "for-1.h" +#undef F +#undef G + +#define F for +#define G f +#include "for-1.h" +#undef F +#undef G + +int +main () +{ + if (test_pf_static () + || test_pf_static32 () + || test_pf_auto () + || test_pf_guided32 () + || test_pf_runtime () + || test_f_static () + || test_f_static32 () + || test_f_auto () + || test_f_guided32 () + || test_f_runtime ()) + abort (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c/for-1.h b/libgomp/testsuite/libgomp.c/for-1.h new file mode 100644 index 0000000000000..fa82c5b20d743 --- /dev/null +++ b/libgomp/testsuite/libgomp.c/for-1.h @@ -0,0 +1,25 @@ +#define S +#define N(x) M(x, G, static) +#include "for-2.h" +#undef S +#undef N +#define S schedule(static, 32) +#define N(x) M(x, G, static32) +#include "for-2.h" +#undef S +#undef N +#define S schedule(auto) +#define N(x) M(x, G, auto) +#include "for-2.h" +#undef S +#undef N +#define S schedule(guided, 32) +#define N(x) M(x, G, guided32) +#include "for-2.h" +#undef S +#undef N +#define S schedule(runtime) +#define N(x) M(x, G, runtime) +#include "for-2.h" +#undef S +#undef N diff --git a/libgomp/testsuite/libgomp.c/for-2.c b/libgomp/testsuite/libgomp.c/for-2.c new file mode 100644 index 0000000000000..f5a01ab05ec32 --- /dev/null +++ b/libgomp/testsuite/libgomp.c/for-2.c @@ -0,0 +1,46 @@ +/* { dg-options "-std=gnu99 -fopenmp" } */ + +extern void abort (void); + +#define M(x, y, z) O(x, y, z) +#define O(x, y, z) x ## _ ## y ## _ ## z + +#define F simd +#define G simd +#define S +#define N(x) M(x, G, normal) +#include "for-2.h" +#undef S +#undef N +#undef F +#undef G + +#define F parallel for simd +#define G pf_simd +#include "for-1.h" +#undef F +#undef G + +#define F for simd +#define G f_simd +#include "for-1.h" +#undef F +#undef G + +int +main () +{ + if (test_simd_normal () + || test_pf_simd_static () + || test_pf_simd_static32 () + || test_pf_simd_auto () + || test_pf_simd_guided32 () + || test_pf_simd_runtime () + || test_f_simd_static () + || test_f_simd_static32 () + || test_f_simd_auto () + || test_f_simd_guided32 () + || test_f_simd_runtime ()) + abort (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c/for-2.h b/libgomp/testsuite/libgomp.c/for-2.h new file mode 100644 index 0000000000000..57c385ec87640 --- /dev/null +++ b/libgomp/testsuite/libgomp.c/for-2.h @@ -0,0 +1,269 @@ +#ifndef VARS +#define VARS +int a[1500]; +float b[10][15][10]; +__attribute__((noreturn)) void +noreturn (void) +{ + for (;;); +} +#endif + +__attribute__((noinline, noclone)) void +N(f0) (void) +{ + int i; +#pragma omp F S + for (i = 0; i < 1500; i++) + a[i] += 2; +} + +__attribute__((noinline, noclone)) void +N(f1) (void) +{ +#pragma omp F S + for (unsigned int i = __INT_MAX__; i < 3000U + __INT_MAX__; i += 2) + a[(i - __INT_MAX__) >> 1] -= 2; +} + +__attribute__((noinline, noclone)) void +N(f2) (void) +{ + unsigned long long i; +#pragma omp F S + for (i = __LONG_LONG_MAX__ + 4500ULL - 27; + i > __LONG_LONG_MAX__ - 27ULL; i -= 3) + a[(i + 26LL - __LONG_LONG_MAX__) / 3] -= 4; +} + +__attribute__((noinline, noclone)) void +N(f3) (long long n1, long long n2, long long s3) +{ +#pragma omp F S + for (long long i = n1 + 23; i > n2 - 25; i -= s3) + a[i + 48] += 7; +} + +__attribute__((noinline, noclone)) void +N(f4) (void) +{ + unsigned int i; +#pragma omp F S + for (i = 30; i < 20; i += 2) + a[i] += 10; +} + +__attribute__((noinline, noclone)) void +N(f5) (int n11, int n12, int n21, int n22, int n31, int n32, + int s1, int s2, int s3) +{ + int v1, v2, v3; +#pragma omp F S collapse(3) + for (v1 = n11; v1 < n12; v1 += s1) + for (v2 = n21; v2 < n22; v2 += s2) + for (v3 = n31; v3 < n32; v3 += s3) + b[v1][v2][v3] += 2.5; +} + +__attribute__((noinline, noclone)) void +N(f6) (int n11, int n12, int n21, int n22, long long n31, long long n32, + int s1, int s2, long long int s3) +{ + int v1, v2; + long long v3; +#pragma omp F S collapse(3) + for (v1 = n11; v1 > n12; v1 += s1) + for (v2 = n21; v2 > n22; v2 += s2) + for (v3 = n31; v3 > n32; v3 += s3) + b[v1][v2 / 2][v3] -= 4.5; +} + +__attribute__((noinline, noclone)) void +N(f7) (void) +{ + unsigned int v1, v3; + unsigned long long v2; +#pragma omp F S collapse(3) + for (v1 = 0; v1 < 20; v1 += 2) + for (v2 = __LONG_LONG_MAX__ + 16ULL; + v2 > __LONG_LONG_MAX__ - 29ULL; v2 -= 3) + for (v3 = 10; v3 > 0; v3--) + b[v1 >> 1][(v2 - __LONG_LONG_MAX__ + 64) / 3 - 12][v3 - 1] += 5.5; +} + +__attribute__((noinline, noclone)) void +N(f8) (void) +{ + long long v1, v2, v3; +#pragma omp F S collapse(3) + for (v1 = 0; v1 < 20; v1 += 2) + for (v2 = 30; v2 < 20; v2++) + for (v3 = 10; v3 < 0; v3--) + b[v1][v2][v3] += 5.5; +} + +__attribute__((noinline, noclone)) void +N(f9) (void) +{ + int i; +#pragma omp F S + for (i = 20; i < 10; i++) + { + a[i] += 2; + noreturn (); + a[i] -= 4; + } +} + +__attribute__((noinline, noclone)) void +N(f10) (void) +{ + int i; +#pragma omp F S collapse(3) + for (i = 0; i < 10; i++) + for (int j = 10; j < 8; j++) + for (long k = -10; k < 10; k++) + { + b[i][j][k] += 4; + noreturn (); + b[i][j][k] -= 8; + } +} + +__attribute__((noinline, noclone)) void +N(f11) (int n) +{ + int i; +#pragma omp F S + for (i = 20; i < n; i++) + { + a[i] += 8; + noreturn (); + a[i] -= 16; + } +} + +__attribute__((noinline, noclone)) void +N(f12) (int n) +{ + int i; +#pragma omp F S collapse(3) + for (i = 0; i < 10; i++) + for (int j = n; j < 8; j++) + for (long k = -10; k < 10; k++) + { + b[i][j][k] += 16; + noreturn (); + b[i][j][k] -= 32; + } +} + +__attribute__((noinline, noclone)) void +N(f13) (void) +{ + int *i; +#pragma omp F S + for (i = a; i < &a[1500]; i++) + i[0] += 2; +} + +__attribute__((noinline, noclone)) void +N(f14) (void) +{ + float *i; +#pragma omp F S collapse(3) + for (i = &b[0][0][0]; i < &b[0][0][10]; i++) + for (float *j = &b[0][15][0]; j > &b[0][0][0]; j -= 10) + for (float *k = &b[0][0][10]; k > &b[0][0][0]; --k) + b[i - &b[0][0][0]][(j - &b[0][0][0]) / 10 - 1][(k - &b[0][0][0]) - 1] + -= 3.5; +} + +__attribute__((noinline, noclone)) int +N(test) (void) +{ + int i, j, k; + for (i = 0; i < 1500; i++) + a[i] = i - 25; + N(f0) (); + for (i = 0; i < 1500; i++) + if (a[i] != i - 23) + return 1; + N(f1) (); + for (i = 0; i < 1500; i++) + if (a[i] != i - 25) + return 1; + N(f2) (); + for (i = 0; i < 1500; i++) + if (a[i] != i - 29) + return 1; + N(f3) (1500LL - 1 - 23 - 48, -1LL + 25 - 48, 1LL); + for (i = 0; i < 1500; i++) + if (a[i] != i - 22) + return 1; + N(f3) (1500LL - 1 - 23 - 48, 1500LL - 1, 7LL); + for (i = 0; i < 1500; i++) + if (a[i] != i - 22) + return 1; + N(f4) (); + for (i = 0; i < 1500; i++) + if (a[i] != i - 22) + return 1; + for (i = 0; i < 10; i++) + for (j = 0; j < 15; j++) + for (k = 0; k < 10; k++) + b[i][j][k] = i - 2.5 + 1.5 * j - 1.5 * k; + N(f5) (0, 10, 0, 15, 0, 10, 1, 1, 1); + for (i = 0; i < 10; i++) + for (j = 0; j < 15; j++) + for (k = 0; k < 10; k++) + if (b[i][j][k] != i + 1.5 * j - 1.5 * k) + return 1; + N(f5) (0, 10, 30, 15, 0, 10, 4, 5, 6); + for (i = 0; i < 10; i++) + for (j = 0; j < 15; j++) + for (k = 0; k < 10; k++) + if (b[i][j][k] != i + 1.5 * j - 1.5 * k) + return 1; + N(f6) (9, -1, 29, 0, 9, -1, -1, -2, -1); + for (i = 0; i < 10; i++) + for (j = 0; j < 15; j++) + for (k = 0; k < 10; k++) + if (b[i][j][k] != i - 4.5 + 1.5 * j - 1.5 * k) + return 1; + N(f7) (); + for (i = 0; i < 10; i++) + for (j = 0; j < 15; j++) + for (k = 0; k < 10; k++) + if (b[i][j][k] != i + 1.0 + 1.5 * j - 1.5 * k) + return 1; + N(f8) (); + for (i = 0; i < 10; i++) + for (j = 0; j < 15; j++) + for (k = 0; k < 10; k++) + if (b[i][j][k] != i + 1.0 + 1.5 * j - 1.5 * k) + return 1; + N(f9) (); + N(f10) (); + N(f11) (10); + N(f12) (12); + for (i = 0; i < 1500; i++) + if (a[i] != i - 22) + return 1; + for (i = 0; i < 10; i++) + for (j = 0; j < 15; j++) + for (k = 0; k < 10; k++) + if (b[i][j][k] != i + 1.0 + 1.5 * j - 1.5 * k) + return 1; + N(f13) (); + N(f14) (); + for (i = 0; i < 1500; i++) + if (a[i] != i - 20) + return 1; + for (i = 0; i < 10; i++) + for (j = 0; j < 15; j++) + for (k = 0; k < 10; k++) + if (b[i][j][k] != i - 2.5 + 1.5 * j - 1.5 * k) + return 1; + return 0; +} From 0e01eaefa20d2a8657d63910ef1706f15b26e8f6 Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Fri, 21 Jun 2013 13:07:37 -0500 Subject: [PATCH 59/63] CILK_SIMD tree code followup and cleanups. --- gcc/ChangeLog.cilkplus | 1 - gcc/gimplify.c | 6 +----- gcc/omp-low.c | 13 +++++-------- 3 files changed, 6 insertions(+), 14 deletions(-) diff --git a/gcc/ChangeLog.cilkplus b/gcc/ChangeLog.cilkplus index 4ca0c67397cef..279bccb5adc4e 100644 --- a/gcc/ChangeLog.cilkplus +++ b/gcc/ChangeLog.cilkplus @@ -17,7 +17,6 @@ * gimplify.c (gimplify_omp_for): Add case for CILK_SIMD. (gimplify_expr): Same. (is_gimple_stmt): Same. - (find_combined_omp_for): Same. c-family/ * c-cilkplus.c: New. diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 3d2f385d8ae47..73c71c8d50e87 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -6839,8 +6839,6 @@ find_combined_omp_for (tree *tp, int *walk_subtrees, void *) *walk_subtrees = 1; /* FALLTHRU */ case OMP_SIMD: - case CILK_SIMD: - /* ?? Hmmm, is this the right way to handle CILK_SIMD? */ if (OMP_FOR_INIT (*tp) != NULL_TREE) return *tp; break; @@ -6874,9 +6872,7 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) simd = TREE_CODE (for_stmt) == OMP_SIMD || TREE_CODE (for_stmt) == CILK_SIMD; gimplify_scan_omp_clauses (&OMP_FOR_CLAUSES (for_stmt), pre_p, - (TREE_CODE (for_stmt) == OMP_SIMD - || TREE_CODE (for_stmt) == CILK_SIMD) - ? ORT_SIMD : ORT_WORKSHARE); + simd ? ORT_SIMD : ORT_WORKSHARE); /* Handle OMP_FOR_INIT. */ for_pre_body = NULL; diff --git a/gcc/omp-low.c b/gcc/omp-low.c index 3b889061c78c2..73d4c64ad591c 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -317,12 +317,9 @@ extract_omp_for_data (gimple for_stmt, struct omp_for_data *fd, case GT_EXPR: break; case NE_EXPR: - /* NE_EXPR is only allowed for Cilk Plus loops. */ - if (flag_enable_cilk - && gimple_omp_for_kind (for_stmt) == GF_OMP_FOR_KIND_CILKSIMD) - break; - else - gcc_unreachable (); + gcc_assert (gimple_omp_for_kind (for_stmt) + == GF_OMP_FOR_KIND_CILKSIMD); + break; case LE_EXPR: if (POINTER_TYPE_P (TREE_TYPE (loop->n2))) loop->n2 = fold_build_pointer_plus_hwi_loc (loc, loop->n2, 1); @@ -7894,9 +7891,9 @@ diagnose_sb_0 (gimple_stmt_iterator *gsi_p, { if ((branch_ctx && gimple_code (branch_ctx) == GIMPLE_OMP_FOR - && gimple_omp_for_kind (branch_ctx) & GF_OMP_FOR_KIND_CILKSIMD) + && gimple_omp_for_kind (branch_ctx) == GF_OMP_FOR_KIND_CILKSIMD) || (gimple_code (label_ctx) == GIMPLE_OMP_FOR - && gimple_omp_for_kind (label_ctx) & GF_OMP_FOR_KIND_CILKSIMD)) + && gimple_omp_for_kind (label_ctx) == GF_OMP_FOR_KIND_CILKSIMD)) cilkplus_block = true; } From eed3deae5a17364c3d4f9b2b0cb34554dab34188 Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Fri, 21 Jun 2013 13:15:45 -0500 Subject: [PATCH 60/63] Do not set flag_openmp for Cilk Plus. Instead, check flag_enable_cilk in various places. --- gcc/ChangeLog.cilkplus | 3 +++ gcc/gimplify.c | 9 +-------- gcc/omp-low.c | 6 +++--- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/gcc/ChangeLog.cilkplus b/gcc/ChangeLog.cilkplus index 279bccb5adc4e..352d724927271 100644 --- a/gcc/ChangeLog.cilkplus +++ b/gcc/ChangeLog.cilkplus @@ -10,6 +10,9 @@ (expand_omp_for): Same. (lower_omp_for): Same. (diagnose_sb_0): Adjust for Cilk Plus for loops. + (gate_expand_omp): Check for Cilk Plus. + (execute_lower_omp): Same. + (gate_diagnose_omp_blocks): Same. * tree.def (CILK_SIMD): New entry. * tree-pretty-print.c (dump_generic_node): Add case for CILK_SIMD. * gimple-pretty-print.c (dump_gimple_omp_for): Add case for diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 73c71c8d50e87..b4cddb020e8e2 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -8112,16 +8112,9 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, ret = GS_ALL_DONE; break; - case CILK_SIMD: - /* For <#pragma simd> we will be generating GIMPLE_OMP_FOR - with GF_OMP_FOR_KIND_CILKSIMD and let the OpenMP - mechanism handle everything. */ - if (!flag_openmp) - flag_openmp = true; - /* FALLTHRU */ - case OMP_FOR: case OMP_SIMD: + case CILK_SIMD: case OMP_DISTRIBUTE: ret = gimplify_omp_for (expr_p, pre_p); break; diff --git a/gcc/omp-low.c b/gcc/omp-low.c index 73d4c64ad591c..45831cfbb0323 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -6626,7 +6626,7 @@ execute_expand_omp (void) static bool gate_expand_omp (void) { - return (flag_openmp != 0 && !seen_error ()); + return ((flag_openmp || flag_enable_cilk) && !seen_error ()); } struct gimple_opt_pass pass_expand_omp = @@ -7783,7 +7783,7 @@ execute_lower_omp (void) /* This pass always runs, to provide PROP_gimple_lomp. But there is nothing to do unless -fopenmp is given. */ - if (flag_openmp == 0) + if (!flag_openmp && !flag_enable_cilk) return 0; all_contexts = splay_tree_new (splay_tree_compare_pointers, 0, @@ -8095,7 +8095,7 @@ diagnose_omp_structured_block_errors (void) static bool gate_diagnose_omp_blocks (void) { - return flag_openmp != 0; + return flag_openmp || flag_enable_cilk; } struct gimple_opt_pass pass_diagnose_omp_blocks = From db2127098137dea6c246041e0d763a57a174fa3c Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Wed, 26 Jun 2013 09:29:27 -0500 Subject: [PATCH 61/63] Handle CILK_SIMD tree code in C++. --- gcc/cp/ChangeLog.cilkplus | 7 +++++++ gcc/cp/cp-gimplify.c | 2 ++ gcc/cp/pt.c | 1 + gcc/cp/semantics.c | 2 +- 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/gcc/cp/ChangeLog.cilkplus b/gcc/cp/ChangeLog.cilkplus index e7f7596ea89df..f0ee3ee6ed877 100644 --- a/gcc/cp/ChangeLog.cilkplus +++ b/gcc/cp/ChangeLog.cilkplus @@ -1,3 +1,10 @@ +2013-06-26 Aldy Hernandez + + * cp-gimplify.c (cp_gimplify_expr): Add case for CILK_SIMD. + (cp_genericize_r): Same. + * pt.c (tsubst_expr): Same. + * semantics.c (finish_omp_for): Same. + 2013-05-21 Balaji V. Iyer Aldy Hernandez diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c index 0dfa4a2034c3f..52ce57baa000b 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -670,6 +670,7 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) case OMP_FOR: case OMP_SIMD: + case CILK_SIMD: case OMP_DISTRIBUTE: ret = cp_gimplify_omp_for (expr_p, pre_p); break; @@ -1120,6 +1121,7 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data) genericize_break_stmt (stmt_p); else if (TREE_CODE (stmt) == OMP_FOR || TREE_CODE (stmt) == OMP_SIMD + || TREE_CODE (stmt) == CILK_SIMD || TREE_CODE (stmt) == OMP_DISTRIBUTE) genericize_omp_for_stmt (stmt_p, walk_subtrees, data); else if (TREE_CODE (stmt) == SIZEOF_EXPR) diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 63d960d238385..d0fa491bf221b 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -13293,6 +13293,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, case OMP_FOR: case OMP_SIMD: + case CILK_SIMD: case OMP_DISTRIBUTE: { tree clauses, body, pre_body; diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index ee83462c8e0ec..722a99613f199 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -5782,7 +5782,7 @@ finish_omp_for (location_t locus, enum tree_code code, tree declv, tree initv, if (CLASS_TYPE_P (TREE_TYPE (decl))) { - if (code == OMP_SIMD) + if (code == OMP_SIMD || code == CILK_SIMD) { error_at (elocus, "%<#pragma omp simd%> used with class " "iteration variable %qE", decl); From 2814409c2f46b5f71706f08358f395dddc9d8a81 Mon Sep 17 00:00:00 2001 From: jakub Date: Fri, 28 Jun 2013 15:58:06 +0000 Subject: [PATCH 62/63] * internal-fn.def (GOMP_SIMD_LANE, GOMP_SIMD_VF, GOMP_SIMD_LAST_LANE): New internal functions. * omp-low.c (omp_max_vf, lower_rec_simd_input_clauses): New functions. (lower_rec_input_clauses): Add fd argument. Enforce max_vf = 1 if any data sharing clauses mention VLAs or for array reductions. Handle OMP_CLAUSE__LOOPTEMP_ clause. For OMP_CLAUSE_{{FIRST,LAST,}PRIVATE,LINEAR,REDUCTION} on SIMD constructs use "omp simd array" temporaries. For OMP_CLAUSE_LINEAR adjust initial value in combined constructs. Don't emit any barriers for #pragma omp distribute. If max_vf is lower than current safelen, prepend an OMP_CLAUSE_SAFELEN clause. (lower_lastprivate_clauses): Handle "omp simd array" temporaries. (lower_reduction_clauses): Exit early for #pragma omp simd. (expand_omp_simd): Set loop->simduid from OMP_CLAUSE__SIMDUID_ and cfun->has_simduid_loops if set. If OMP_CLAUSE_SAFELEN (1) is present, don't set loop->safelen nor loop->force_vect. (lower_omp_sections, lower_omp_single, lower_omp_taskreg): Adjust lower_rec_input_clauses callers. (lower_omp_for_lastprivate): Unshare vinit. (lower_omp_for): Add OMP_CLAUSE__LOOPTEMP_ clauses before calling lower_rec_input_clauses. Adjust lower_rec_input_clauses caller. Always call lower_omp_for_lastprivate at the same place, even for #pragma omp simd. * tree.h (enum clause_code): Add OMP_CLAUSE__SIMDUID_. (OMP_CLAUSE__SIMDUID__DECL): Define. * tree-vectorizer.c: Include hash-table.h and tree-ssa-propagate.h. (simduid_to_vf, decl_to_simduid): New classes. (simduid_to_vf::hash, simduid_to_vf::equal, decl_to_simduid::hash, decl_to_simduid::equal): New methods. (note_simd_array_uses_struct): New struct. (adjust_simduid_builtins, note_simd_array_uses_cb, note_simd_array_uses): New functions. (vectorize_loops): Adjust "omp simd array" temporary array sizes and fold GOMP_SIMD_{LANE,VF,LAST_LANE} builtins. * tree-vectorizer.h (struct _stmt_vec_info): Add simd_lane_access_p field. (STMT_VINFO_SIMD_LANE_ACCESS_P): Define. * tree-data-ref.c (get_references_in_stmt): Allow GOMP_SIMD_LANE builtins in their own loops. * tree-inline.c (copy_cfg_body): Propagate has_force_vect_loops and has_simduid_loops. * function.h (struct function): Add has_simduid_loops field. * tree-ssa-ccp.c (likely_value): For GOMP_SIMD_{LANE,LAST_LANE,VF} builtins ignore the undefined magic argument. * tree-pretty-print.c (dump_omp_clause): Handle OMP_CLAUSE__SIMDUID_ clause. * cfgloop.h (struct loop): Add simduid field. * Makefile.in (tree-vectorizer.o): Depend on $(HASH_TABLE_H) and tree-ssa-propagate.h. * tree-vect-data-refs.c (vect_analyze_data_refs): Check for SIMD lane access. * gimplify.c (omp_add_variable): Handle combination of aligned clause and some data sharing clause for the same decl. (gimplify_omp_for): For collapse (2) and above simd loops predetermine loop iteration vars as lastprivate instead of linear. * tree.c (omp_clause_num_ops, omp_clause_code_name): Add entries for OMP_CLAUSE__SIMDUID_. (walk_tree_1): Handle OMP_CLAUSE__SIMDUID_. * tree-vect-loop.c (vectorizable_live_operation): Handle live GOMP_SIMD_LANE result. * tree-vect-stmts.c (vectorizable_call): Vectorize GOMP_SIMD_LANE builtin. (vectorizable_store, vectorizable_load): Handle STMT_VINFO_SIMD_LANE_ACCESS_P. * internal-fn.c (expand_GOMP_SIMD_LANE, expand_GOMP_SIMD_VF, expand_GOMP_SIMD_LAST_LANE): New functions. * testsuite/libgomp.c++/simd-1.C: New test. * testsuite/libgomp.c++/simd-2.C: New test. * testsuite/libgomp.c++/simd-3.C: New test. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gomp-4_0-branch@200536 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog.gomp | 73 ++++ gcc/Makefile.in | 2 +- gcc/cfgloop.h | 5 + gcc/function.h | 4 + gcc/gimplify.c | 27 +- gcc/internal-fn.c | 24 ++ gcc/internal-fn.def | 3 + gcc/omp-low.c | 454 ++++++++++++++++++++++--- gcc/tree-data-ref.c | 23 +- gcc/tree-inline.c | 2 + gcc/tree-pretty-print.c | 7 + gcc/tree-ssa-ccp.c | 16 + gcc/tree-vect-data-refs.c | 86 ++++- gcc/tree-vect-loop.c | 38 ++- gcc/tree-vect-stmts.c | 145 ++++++-- gcc/tree-vectorizer.c | 252 +++++++++++++- gcc/tree-vectorizer.h | 4 + gcc/tree.c | 7 +- gcc/tree.h | 8 +- libgomp/ChangeLog.gomp | 6 + libgomp/testsuite/libgomp.c++/simd-1.C | 79 +++++ libgomp/testsuite/libgomp.c++/simd-2.C | 36 ++ libgomp/testsuite/libgomp.c++/simd-3.C | 131 +++++++ 23 files changed, 1323 insertions(+), 109 deletions(-) create mode 100644 libgomp/testsuite/libgomp.c++/simd-1.C create mode 100644 libgomp/testsuite/libgomp.c++/simd-2.C create mode 100644 libgomp/testsuite/libgomp.c++/simd-3.C diff --git a/gcc/ChangeLog.gomp b/gcc/ChangeLog.gomp index 1ef47755ac63c..afd5677310624 100644 --- a/gcc/ChangeLog.gomp +++ b/gcc/ChangeLog.gomp @@ -1,3 +1,76 @@ +2013-06-28 Jakub Jelinek + Aldy Hernandez + + * internal-fn.def (GOMP_SIMD_LANE, GOMP_SIMD_VF, + GOMP_SIMD_LAST_LANE): New internal functions. + * omp-low.c (omp_max_vf, lower_rec_simd_input_clauses): New + functions. + (lower_rec_input_clauses): Add fd argument. Enforce max_vf = 1 + if any data sharing clauses mention VLAs or for array reductions. + Handle OMP_CLAUSE__LOOPTEMP_ clause. For + OMP_CLAUSE_{{FIRST,LAST,}PRIVATE,LINEAR,REDUCTION} on SIMD + constructs use "omp simd array" temporaries. For OMP_CLAUSE_LINEAR + adjust initial value in combined constructs. Don't emit any + barriers for #pragma omp distribute. If max_vf is lower than + current safelen, prepend an OMP_CLAUSE_SAFELEN clause. + (lower_lastprivate_clauses): Handle "omp simd array" temporaries. + (lower_reduction_clauses): Exit early for #pragma omp simd. + (expand_omp_simd): Set loop->simduid from OMP_CLAUSE__SIMDUID_ + and cfun->has_simduid_loops if set. + If OMP_CLAUSE_SAFELEN (1) is present, don't set loop->safelen + nor loop->force_vect. + (lower_omp_sections, lower_omp_single, lower_omp_taskreg): Adjust + lower_rec_input_clauses callers. + (lower_omp_for_lastprivate): Unshare vinit. + (lower_omp_for): Add OMP_CLAUSE__LOOPTEMP_ clauses before calling + lower_rec_input_clauses. Adjust lower_rec_input_clauses caller. + Always call lower_omp_for_lastprivate at the same place, even for + #pragma omp simd. + * tree.h (enum clause_code): Add OMP_CLAUSE__SIMDUID_. + (OMP_CLAUSE__SIMDUID__DECL): Define. + * tree-vectorizer.c: Include hash-table.h and tree-ssa-propagate.h. + (simduid_to_vf, decl_to_simduid): New classes. + (simduid_to_vf::hash, simduid_to_vf::equal, decl_to_simduid::hash, + decl_to_simduid::equal): New methods. + (note_simd_array_uses_struct): New struct. + (adjust_simduid_builtins, note_simd_array_uses_cb, + note_simd_array_uses): New functions. + (vectorize_loops): Adjust "omp simd array" temporary array sizes + and fold GOMP_SIMD_{LANE,VF,LAST_LANE} builtins. + * tree-vectorizer.h (struct _stmt_vec_info): Add simd_lane_access_p + field. + (STMT_VINFO_SIMD_LANE_ACCESS_P): Define. + * tree-data-ref.c (get_references_in_stmt): Allow GOMP_SIMD_LANE + builtins in their own loops. + * tree-inline.c (copy_cfg_body): Propagate has_force_vect_loops + and has_simduid_loops. + * function.h (struct function): Add has_simduid_loops field. + * tree-ssa-ccp.c (likely_value): For GOMP_SIMD_{LANE,LAST_LANE,VF} + builtins ignore the undefined magic argument. + * tree-pretty-print.c (dump_omp_clause): Handle OMP_CLAUSE__SIMDUID_ + clause. + * cfgloop.h (struct loop): Add simduid field. + * Makefile.in (tree-vectorizer.o): Depend on $(HASH_TABLE_H) + and tree-ssa-propagate.h. + * tree-vect-data-refs.c (vect_analyze_data_refs): Check for SIMD + lane access. + * gimplify.c (omp_add_variable): Handle combination of aligned + clause and some data sharing clause for the same decl. + (gimplify_omp_for): For collapse (2) and above simd loops + predetermine loop iteration vars as lastprivate instead of + linear. + * tree.c (omp_clause_num_ops, omp_clause_code_name): Add + entries for OMP_CLAUSE__SIMDUID_. + (walk_tree_1): Handle OMP_CLAUSE__SIMDUID_. + * tree-vect-loop.c (vectorizable_live_operation): Handle live + GOMP_SIMD_LANE result. + * tree-vect-stmts.c (vectorizable_call): Vectorize GOMP_SIMD_LANE + builtin. + (vectorizable_store, vectorizable_load): Handle + STMT_VINFO_SIMD_LANE_ACCESS_P. + * internal-fn.c (expand_GOMP_SIMD_LANE, expand_GOMP_SIMD_VF, + expand_GOMP_SIMD_LAST_LANE): New functions. + 2013-06-21 Jakub Jelinek * gimple.h (enum gf_mask): Adjust GF_OMP_FOR_COMBINED diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 13dc0a21609ce..e367f4ee67b9d 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -2637,7 +2637,7 @@ tree-vect-data-refs.o: tree-vect-data-refs.c $(CONFIG_H) $(SYSTEM_H) \ tree-vectorizer.o: tree-vectorizer.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ $(DUMPFILE_H) $(TM_H) $(GGC_H) $(TREE_H) $(TREE_FLOW_H) \ $(CFGLOOP_H) $(TREE_PASS_H) $(TREE_VECTORIZER_H) \ - $(TREE_PRETTY_PRINT_H) + $(TREE_PRETTY_PRINT_H) $(HASH_TABLE_H) tree-ssa-propagate.h tree-loop-distribution.o: tree-loop-distribution.c $(CONFIG_H) $(SYSTEM_H) \ coretypes.h $(TREE_FLOW_H) $(CFGLOOP_H) $(TREE_DATA_REF_H) $(TREE_PASS_H) tree-parloops.o: tree-parloops.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ diff --git a/gcc/cfgloop.h b/gcc/cfgloop.h index 5536e60c20c07..cd2f527bb4710 100644 --- a/gcc/cfgloop.h +++ b/gcc/cfgloop.h @@ -177,6 +177,11 @@ struct GTY ((chain_next ("%h.next"))) loop { /* True if we should try harder to vectorize this loop. */ bool force_vect; + /* For SIMD loops, this is a unique identifier of the loop, referenced + by IFN_GOMP_SIMD_VF, IFN_GOMP_SIMD_LANE and IFN_GOMP_SIMD_LAST_LANE + builtins. */ + tree simduid; + /* Upper bound on number of iterations of a loop. */ struct nb_iter_bound *bounds; diff --git a/gcc/function.h b/gcc/function.h index c35ac46c7e976..d1f4ffc1fd4cc 100644 --- a/gcc/function.h +++ b/gcc/function.h @@ -654,6 +654,10 @@ struct GTY(()) function { /* Nonzero if the current function contains any loops with loop->force_vect set. */ unsigned int has_force_vect_loops : 1; + + /* Nonzero if the current function contains any loops with + nonzero value in loop->simduid. */ + unsigned int has_simduid_loops : 1; }; /* Add the decl D to the local_decls list of FUN. */ diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 5fb7cccc656d4..511e6176d71e0 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -5814,7 +5814,7 @@ omp_add_variable (struct gimplify_omp_ctx *ctx, tree decl, unsigned int flags) flags |= GOVD_SEEN; n = splay_tree_lookup (ctx->variables, (splay_tree_key)decl); - if (n != NULL) + if (n != NULL && n->value != GOVD_ALIGNED) { /* We shouldn't be re-adding the decl with the same data sharing class. */ @@ -5823,7 +5823,8 @@ omp_add_variable (struct gimplify_omp_ctx *ctx, tree decl, unsigned int flags) FIRSTPRIVATE and LASTPRIVATE. */ nflags = n->value | flags; gcc_assert ((nflags & GOVD_DATA_SHARE_CLASS) - == (GOVD_FIRSTPRIVATE | GOVD_LASTPRIVATE)); + == (GOVD_FIRSTPRIVATE | GOVD_LASTPRIVATE) + || (flags & GOVD_DATA_SHARE_CLASS) == 0); n->value = nflags; return; } @@ -5893,7 +5894,10 @@ omp_add_variable (struct gimplify_omp_ctx *ctx, tree decl, unsigned int flags) } } - splay_tree_insert (ctx->variables, (splay_tree_key)decl, flags); + if (n != NULL) + n->value |= flags; + else + splay_tree_insert (ctx->variables, (splay_tree_key)decl, flags); } /* Notice a threadprivate variable DECL used in OpenMP context CTX. @@ -6935,7 +6939,7 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) omp_is_private (gimplify_omp_ctxp, decl, simd); if (n != NULL && (n->value & GOVD_DATA_SHARE_CLASS) != 0) omp_notice_variable (gimplify_omp_ctxp, decl, true); - else + else if (TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)) == 1) { c = build_omp_clause (input_location, OMP_CLAUSE_LINEAR); OMP_CLAUSE_LINEAR_NO_COPYIN (c) = 1; @@ -6948,6 +6952,21 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) omp_add_variable (gimplify_omp_ctxp, decl, GOVD_LINEAR | GOVD_EXPLICIT | GOVD_SEEN); } + else + { + bool lastprivate + = (!has_decl_expr + || !bitmap_bit_p (has_decl_expr, DECL_UID (decl))); + c = build_omp_clause (input_location, + lastprivate ? OMP_CLAUSE_LASTPRIVATE + : OMP_CLAUSE_PRIVATE); + OMP_CLAUSE_DECL (c) = decl; + OMP_CLAUSE_CHAIN (c) = OMP_FOR_CLAUSES (for_stmt); + omp_add_variable (gimplify_omp_ctxp, decl, + (lastprivate ? GOVD_LASTPRIVATE : GOVD_PRIVATE) + | GOVD_SEEN); + c = NULL_TREE; + } } else if (omp_is_private (gimplify_omp_ctxp, decl, simd)) omp_notice_variable (gimplify_omp_ctxp, decl, true); diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c index b841abd328ebb..983efeb751b33 100644 --- a/gcc/internal-fn.c +++ b/gcc/internal-fn.c @@ -109,6 +109,30 @@ expand_STORE_LANES (gimple stmt) expand_insn (get_multi_vector_move (type, vec_store_lanes_optab), 2, ops); } +/* This should get expanded in adjust_simduid_builtins. */ + +static void +expand_GOMP_SIMD_LANE (gimple stmt ATTRIBUTE_UNUSED) +{ + gcc_unreachable (); +} + +/* This should get expanded in adjust_simduid_builtins. */ + +static void +expand_GOMP_SIMD_VF (gimple stmt ATTRIBUTE_UNUSED) +{ + gcc_unreachable (); +} + +/* This should get expanded in adjust_simduid_builtins. */ + +static void +expand_GOMP_SIMD_LAST_LANE (gimple stmt ATTRIBUTE_UNUSED) +{ + gcc_unreachable (); +} + /* Routines to expand each internal function, indexed by function number. Each routine has the prototype: diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def index 8900d90dc22f9..5427664b8e3c5 100644 --- a/gcc/internal-fn.def +++ b/gcc/internal-fn.def @@ -40,3 +40,6 @@ along with GCC; see the file COPYING3. If not see DEF_INTERNAL_FN (LOAD_LANES, ECF_CONST | ECF_LEAF) DEF_INTERNAL_FN (STORE_LANES, ECF_CONST | ECF_LEAF) +DEF_INTERNAL_FN (GOMP_SIMD_LANE, ECF_NOVOPS | ECF_LEAF | ECF_NOTHROW) +DEF_INTERNAL_FN (GOMP_SIMD_VF, ECF_CONST | ECF_LEAF | ECF_NOTHROW) +DEF_INTERNAL_FN (GOMP_SIMD_LAST_LANE, ECF_CONST | ECF_LEAF | ECF_NOTHROW) diff --git a/gcc/omp-low.c b/gcc/omp-low.c index 578a2c6e894f6..ba076e0487e2e 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -2508,6 +2508,73 @@ omp_clause_aligned_alignment (tree clause) return build_int_cst (integer_type_node, al); } +/* Return maximum possible vectorization factor for the target. */ + +static int +omp_max_vf (void) +{ + if (!optimize + || optimize_debug + || (!flag_tree_vectorize + && global_options_set.x_flag_tree_vectorize)) + return 1; + + int vs = targetm.vectorize.autovectorize_vector_sizes (); + if (vs) + { + vs = 1 << floor_log2 (vs); + return vs; + } + enum machine_mode vqimode = targetm.vectorize.preferred_simd_mode (QImode); + if (GET_MODE_CLASS (vqimode) == MODE_VECTOR_INT) + return GET_MODE_NUNITS (vqimode); + return 1; +} + +/* Helper function of lower_rec_input_clauses, used for #pragma omp simd + privatization. */ + +static bool +lower_rec_simd_input_clauses (tree new_var, omp_context *ctx, int &max_vf, + tree &idx, tree &lane, tree &ivar, tree &lvar) +{ + if (max_vf == 0) + { + max_vf = omp_max_vf (); + if (max_vf > 1) + { + tree c = find_omp_clause (gimple_omp_for_clauses (ctx->stmt), + OMP_CLAUSE_SAFELEN); + if (c + && compare_tree_int (OMP_CLAUSE_SAFELEN_EXPR (c), max_vf) == -1) + max_vf = tree_low_cst (OMP_CLAUSE_SAFELEN_EXPR (c), 0); + } + if (max_vf > 1) + { + idx = create_tmp_var (unsigned_type_node, NULL); + lane = create_tmp_var (unsigned_type_node, NULL); + } + } + if (max_vf == 1) + return false; + + tree atype = build_array_type_nelts (TREE_TYPE (new_var), max_vf); + tree avar = create_tmp_var_raw (atype, NULL); + if (TREE_ADDRESSABLE (new_var)) + TREE_ADDRESSABLE (avar) = 1; + DECL_ATTRIBUTES (avar) + = tree_cons (get_identifier ("omp simd array"), NULL, + DECL_ATTRIBUTES (avar)); + gimple_add_tmp_var (avar); + ivar = build4 (ARRAY_REF, TREE_TYPE (new_var), avar, idx, + NULL_TREE, NULL_TREE); + lvar = build4 (ARRAY_REF, TREE_TYPE (new_var), avar, lane, + NULL_TREE, NULL_TREE); + SET_DECL_VALUE_EXPR (new_var, lvar); + DECL_HAS_VALUE_EXPR_P (new_var) = 1; + return true; +} + /* Generate code to implement the input clauses, FIRSTPRIVATE and COPYIN, from the receiver (aka child) side and initializers for REFERENCE_TYPE private variables. Initialization statements go in ILIST, while calls @@ -2515,15 +2582,43 @@ omp_clause_aligned_alignment (tree clause) static void lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, - omp_context *ctx) + omp_context *ctx, struct omp_for_data *fd) { tree c, dtor, copyin_seq, x, ptr; bool copyin_by_ref = false; bool lastprivate_firstprivate = false; int pass; + bool is_simd = (gimple_code (ctx->stmt) == GIMPLE_OMP_FOR + && gimple_omp_for_kind (ctx->stmt) == GF_OMP_FOR_KIND_SIMD); + int max_vf = 0; + tree lane = NULL_TREE, idx = NULL_TREE; + tree ivar = NULL_TREE, lvar = NULL_TREE; + gimple_seq llist[2] = { NULL, NULL }; copyin_seq = NULL; + /* Enforce simdlen 1 in simd loops with data sharing clauses referencing + variable sized vars. That is unnecessarily hard to support and very + unlikely to result in vectorized code anyway. */ + if (is_simd) + for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c)) + switch (OMP_CLAUSE_CODE (c)) + { + case OMP_CLAUSE_REDUCTION: + if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c)) + max_vf = 1; + /* FALLTHRU */ + case OMP_CLAUSE_PRIVATE: + case OMP_CLAUSE_FIRSTPRIVATE: + case OMP_CLAUSE_LASTPRIVATE: + case OMP_CLAUSE_LINEAR: + if (is_variable_sized (OMP_CLAUSE_DECL (c))) + max_vf = 1; + break; + default: + continue; + } + /* Do all the fixed sized types in the first pass, and the variable sized types in the second pass. This makes sure that the scalar arguments to the variable sized types are processed before we use them in the @@ -2553,7 +2648,11 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, case OMP_CLAUSE_COPYIN: case OMP_CLAUSE_REDUCTION: case OMP_CLAUSE_LINEAR: + break; case OMP_CLAUSE__LOOPTEMP_: + /* Handle _looptemp_ clauses only on parallel. */ + if (fd) + continue; break; case OMP_CLAUSE_LASTPRIVATE: if (OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE (c)) @@ -2737,6 +2836,34 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, x = NULL; do_private: x = lang_hooks.decls.omp_clause_default_ctor (c, new_var, x); + if (is_simd) + { + tree y = lang_hooks.decls.omp_clause_dtor (c, new_var); + if ((TREE_ADDRESSABLE (new_var) || x || y + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE) + && lower_rec_simd_input_clauses (new_var, ctx, max_vf, + idx, lane, ivar, lvar)) + { + if (x) + x = lang_hooks.decls.omp_clause_default_ctor + (c, unshare_expr (ivar), x); + if (x) + gimplify_and_add (x, &llist[0]); + if (y) + { + y = lang_hooks.decls.omp_clause_dtor (c, ivar); + if (y) + { + gimple_seq tseq = NULL; + + dtor = y; + gimplify_stmt (&dtor, &tseq); + gimple_seq_add_seq (&llist[1], tseq); + } + } + break; + } + } if (x) gimplify_and_add (x, ilist); /* FALLTHRU */ @@ -2779,10 +2906,92 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, } do_firstprivate: x = build_outer_var_ref (var, ctx); + if (is_simd) + { + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR + && gimple_omp_for_combined_into_p (ctx->stmt)) + { + tree stept = POINTER_TYPE_P (TREE_TYPE (x)) + ? sizetype : TREE_TYPE (x); + tree t = fold_convert (stept, + OMP_CLAUSE_LINEAR_STEP (c)); + tree c = find_omp_clause (clauses, + OMP_CLAUSE__LOOPTEMP_); + gcc_assert (c); + tree l = OMP_CLAUSE_DECL (c); + if (fd->collapse == 1) + { + tree n1 = fd->loop.n1; + tree step = fd->loop.step; + tree itype = TREE_TYPE (l); + if (POINTER_TYPE_P (itype)) + itype = signed_type_for (itype); + l = fold_build2 (MINUS_EXPR, itype, l, n1); + if (TYPE_UNSIGNED (itype) + && fd->loop.cond_code == GT_EXPR) + l = fold_build2 (TRUNC_DIV_EXPR, itype, + fold_build1 (NEGATE_EXPR, + itype, l), + fold_build1 (NEGATE_EXPR, + itype, step)); + else + l = fold_build2 (TRUNC_DIV_EXPR, itype, l, step); + } + t = fold_build2 (MULT_EXPR, stept, + fold_convert (stept, l), t); + if (POINTER_TYPE_P (TREE_TYPE (x))) + x = fold_build2 (POINTER_PLUS_EXPR, + TREE_TYPE (x), x, t); + else + x = fold_build2 (PLUS_EXPR, TREE_TYPE (x), x, t); + } + + if ((OMP_CLAUSE_CODE (c) != OMP_CLAUSE_LINEAR + || TREE_ADDRESSABLE (new_var)) + && lower_rec_simd_input_clauses (new_var, ctx, max_vf, + idx, lane, ivar, lvar)) + { + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR) + { + tree iv = create_tmp_var (TREE_TYPE (new_var), NULL); + x = lang_hooks.decls.omp_clause_copy_ctor (c, iv, x); + gimplify_and_add (x, ilist); + gimple_stmt_iterator gsi + = gsi_start_1 (gimple_omp_body_ptr (ctx->stmt)); + gimple g + = gimple_build_assign (unshare_expr (lvar), iv); + gsi_insert_before_without_update (&gsi, g, + GSI_SAME_STMT); + tree stept = POINTER_TYPE_P (TREE_TYPE (x)) + ? sizetype : TREE_TYPE (x); + tree t = fold_convert (stept, + OMP_CLAUSE_LINEAR_STEP (c)); + enum tree_code code = PLUS_EXPR; + if (POINTER_TYPE_P (TREE_TYPE (new_var))) + code = POINTER_PLUS_EXPR; + g = gimple_build_assign_with_ops (code, iv, iv, t); + gsi_insert_before_without_update (&gsi, g, + GSI_SAME_STMT); + break; + } + x = lang_hooks.decls.omp_clause_copy_ctor + (c, unshare_expr (ivar), x); + gimplify_and_add (x, &llist[0]); + x = lang_hooks.decls.omp_clause_dtor (c, ivar); + if (x) + { + gimple_seq tseq = NULL; + + dtor = x; + gimplify_stmt (&dtor, &tseq); + gimple_seq_add_seq (&llist[1], tseq); + } + break; + } + } x = lang_hooks.decls.omp_clause_copy_ctor (c, new_var, x); gimplify_and_add (x, ilist); goto do_dtor; - break; case OMP_CLAUSE__LOOPTEMP_: gcc_assert (is_parallel_ctx (ctx)); @@ -2805,6 +3014,8 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, tree placeholder = OMP_CLAUSE_REDUCTION_PLACEHOLDER (c); x = build_outer_var_ref (var, ctx); + /* FIXME: Not handled yet. */ + gcc_assert (!is_simd); if (is_reference (var)) x = build_fold_addr_expr_loc (clause_loc, x); SET_DECL_VALUE_EXPR (placeholder, x); @@ -2819,7 +3030,31 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, { x = omp_reduction_init (c, TREE_TYPE (new_var)); gcc_assert (TREE_CODE (TREE_TYPE (new_var)) != ARRAY_TYPE); - gimplify_assign (new_var, x, ilist); + if (is_simd + && lower_rec_simd_input_clauses (new_var, ctx, max_vf, + idx, lane, ivar, lvar)) + { + enum tree_code code = OMP_CLAUSE_REDUCTION_CODE (c); + tree ref = build_outer_var_ref (var, ctx); + + gimplify_assign (unshare_expr (ivar), x, &llist[0]); + + /* reduction(-:var) sums up the partial results, so it + acts identically to reduction(+:var). */ + if (code == MINUS_EXPR) + code = PLUS_EXPR; + + x = build2 (code, TREE_TYPE (ref), ref, ivar); + ref = build_outer_var_ref (var, ctx); + gimplify_assign (ref, x, &llist[1]); + } + else + { + gimplify_assign (new_var, x, ilist); + if (is_simd) + gimplify_assign (build_outer_var_ref (var, ctx), + new_var, dlist); + } } break; @@ -2829,6 +3064,49 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, } } + if (lane) + { + tree uid = create_tmp_var (ptr_type_node, "simduid"); + gimple g + = gimple_build_call_internal (IFN_GOMP_SIMD_LANE, 1, uid); + gimple_call_set_lhs (g, lane); + gimple_stmt_iterator gsi = gsi_start_1 (gimple_omp_body_ptr (ctx->stmt)); + gsi_insert_before_without_update (&gsi, g, GSI_SAME_STMT); + c = build_omp_clause (UNKNOWN_LOCATION, OMP_CLAUSE__SIMDUID_); + OMP_CLAUSE__SIMDUID__DECL (c) = uid; + OMP_CLAUSE_CHAIN (c) = gimple_omp_for_clauses (ctx->stmt); + gimple_omp_for_set_clauses (ctx->stmt, c); + g = gimple_build_assign_with_ops (INTEGER_CST, lane, + build_int_cst (unsigned_type_node, 0), + NULL_TREE); + gimple_seq_add_stmt (ilist, g); + for (int i = 0; i < 2; i++) + if (llist[i]) + { + tree vf = create_tmp_var (unsigned_type_node, NULL); + g = gimple_build_call_internal (IFN_GOMP_SIMD_VF, 1, uid); + gimple_call_set_lhs (g, vf); + gimple_seq *seq = i == 0 ? ilist : dlist; + gimple_seq_add_stmt (seq, g); + tree t = build_int_cst (unsigned_type_node, 0); + g = gimple_build_assign_with_ops (INTEGER_CST, idx, t, NULL_TREE); + gimple_seq_add_stmt (seq, g); + tree body = create_artificial_label (UNKNOWN_LOCATION); + tree header = create_artificial_label (UNKNOWN_LOCATION); + tree end = create_artificial_label (UNKNOWN_LOCATION); + gimple_seq_add_stmt (seq, gimple_build_goto (header)); + gimple_seq_add_stmt (seq, gimple_build_label (body)); + gimple_seq_add_seq (seq, llist[i]); + t = build_int_cst (unsigned_type_node, 1); + g = gimple_build_assign_with_ops (PLUS_EXPR, idx, idx, t); + gimple_seq_add_stmt (seq, g); + gimple_seq_add_stmt (seq, gimple_build_label (header)); + g = gimple_build_cond (LT_EXPR, idx, vf, body, end); + gimple_seq_add_stmt (seq, g); + gimple_seq_add_stmt (seq, gimple_build_label (end)); + } + } + /* The copyin sequence is not to be executed by the main thread, since that would result in self-copies. Perhaps not visible to scalars, but it certainly is to C++ operator=. */ @@ -2849,11 +3127,30 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, happens after firstprivate copying in all threads. */ if (copyin_by_ref || lastprivate_firstprivate) { - /* Don't add any barrier for #pragma omp simd. */ + /* Don't add any barrier for #pragma omp simd or + #pragma omp distribute. */ if (gimple_code (ctx->stmt) != GIMPLE_OMP_FOR - || gimple_omp_for_kind (ctx->stmt) != GF_OMP_FOR_KIND_SIMD) + || gimple_omp_for_kind (ctx->stmt) == GF_OMP_FOR_KIND_FOR) gimplify_and_add (build_omp_barrier (), ilist); } + + /* If max_vf is non-NULL, then we can use only vectorization factor + up to the max_vf we chose. So stick it into safelen clause. */ + if (max_vf) + { + tree c = find_omp_clause (gimple_omp_for_clauses (ctx->stmt), + OMP_CLAUSE_SAFELEN); + if (c == NULL_TREE + || compare_tree_int (OMP_CLAUSE_SAFELEN_EXPR (c), + max_vf) == 1) + { + c = build_omp_clause (UNKNOWN_LOCATION, OMP_CLAUSE_SAFELEN); + OMP_CLAUSE_SAFELEN_EXPR (c) = build_int_cst (integer_type_node, + max_vf); + OMP_CLAUSE_CHAIN (c) = gimple_omp_for_clauses (ctx->stmt); + gimple_omp_for_set_clauses (ctx->stmt, c); + } + } } @@ -2865,8 +3162,9 @@ static void lower_lastprivate_clauses (tree clauses, tree predicate, gimple_seq *stmt_list, omp_context *ctx) { - tree x, c, label = NULL; + tree x, c, label = NULL, orig_clauses = clauses; bool par_clauses = false; + tree simduid = NULL, lastlane = NULL; /* Early exit if there are no lastprivate or linear clauses. */ for (; clauses ; clauses = OMP_CLAUSE_CHAIN (clauses)) @@ -2910,6 +3208,14 @@ lower_lastprivate_clauses (tree clauses, tree predicate, gimple_seq *stmt_list, gimple_seq_add_stmt (stmt_list, gimple_build_label (label_true)); } + if (gimple_code (ctx->stmt) == GIMPLE_OMP_FOR + && gimple_omp_for_kind (ctx->stmt) == GF_OMP_FOR_KIND_SIMD) + { + simduid = find_omp_clause (orig_clauses, OMP_CLAUSE__SIMDUID_); + if (simduid) + simduid = OMP_CLAUSE__SIMDUID__DECL (simduid); + } + for (c = clauses; c ;) { tree var, new_var; @@ -2922,6 +3228,31 @@ lower_lastprivate_clauses (tree clauses, tree predicate, gimple_seq *stmt_list, var = OMP_CLAUSE_DECL (c); new_var = lookup_decl (var, ctx); + if (simduid && DECL_HAS_VALUE_EXPR_P (new_var)) + { + tree val = DECL_VALUE_EXPR (new_var); + if (TREE_CODE (val) == ARRAY_REF + && VAR_P (TREE_OPERAND (val, 0)) + && lookup_attribute ("omp simd array", + DECL_ATTRIBUTES (TREE_OPERAND (val, + 0)))) + { + if (lastlane == NULL) + { + lastlane = create_tmp_var (unsigned_type_node, NULL); + gimple g + = gimple_build_call_internal (IFN_GOMP_SIMD_LAST_LANE, + 2, simduid, + TREE_OPERAND (val, 1)); + gimple_call_set_lhs (g, lastlane); + gimple_seq_add_stmt (stmt_list, g); + } + new_var = build4 (ARRAY_REF, TREE_TYPE (val), + TREE_OPERAND (val, 0), lastlane, + NULL_TREE, NULL_TREE); + } + } + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE && OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c)) { @@ -2971,6 +3302,11 @@ lower_reduction_clauses (tree clauses, gimple_seq *stmt_seqp, omp_context *ctx) tree x, c; int count = 0; + /* SIMD reductions are handled in lower_rec_input_clauses. */ + if (gimple_code (ctx->stmt) == GIMPLE_OMP_FOR + && gimple_omp_for_kind (ctx->stmt) == GF_OMP_FOR_KIND_SIMD) + return; + /* First see if there is exactly one reduction clause. Use OMP_ATOMIC update in that case, otherwise use a lock. */ for (c = clauses; c && count < 2; c = OMP_CLAUSE_CHAIN (c)) @@ -5691,6 +6027,8 @@ expand_omp_simd (struct omp_region *region, struct omp_for_data *fd) int i; tree safelen = find_omp_clause (gimple_omp_for_clauses (fd->for_stmt), OMP_CLAUSE_SAFELEN); + tree simduid = find_omp_clause (gimple_omp_for_clauses (fd->for_stmt), + OMP_CLAUSE__SIMDUID_); tree n1, n2; type = TREE_TYPE (fd->loop.v); @@ -5902,11 +6240,19 @@ expand_omp_simd (struct omp_region *region, struct omp_for_data *fd) loop->safelen = INT_MAX; else loop->safelen = tree_low_cst (safelen, 1); + if (loop->safelen == 1) + loop->safelen = 0; + } + if (simduid) + { + loop->simduid = OMP_CLAUSE__SIMDUID__DECL (simduid); + cfun->has_simduid_loops = true; } /* If not -fno-tree-vectorize, hint that we want to vectorize the loop. */ - if (flag_tree_vectorize - || !global_options_set.x_flag_tree_vectorize) + if ((flag_tree_vectorize + || !global_options_set.x_flag_tree_vectorize) + && loop->safelen > 1) { loop->force_vect = true; cfun->has_force_vect_loops = true; @@ -7107,7 +7453,7 @@ lower_omp_sections (gimple_stmt_iterator *gsi_p, omp_context *ctx) dlist = NULL; ilist = NULL; lower_rec_input_clauses (gimple_omp_sections_clauses (stmt), - &ilist, &dlist, ctx); + &ilist, &dlist, ctx, NULL); new_body = gimple_omp_body (stmt); gimple_omp_set_body (stmt, NULL); @@ -7315,7 +7661,7 @@ lower_omp_single (gimple_stmt_iterator *gsi_p, omp_context *ctx) bind_body = NULL; dlist = NULL; lower_rec_input_clauses (gimple_omp_single_clauses (single_stmt), - &bind_body, &dlist, ctx); + &bind_body, &dlist, ctx, NULL); lower_omp (gimple_omp_body_ptr (single_stmt), ctx); gimple_seq_add_stmt (&bind_body, single_stmt); @@ -7564,6 +7910,8 @@ lower_omp_for_lastprivate (struct omp_for_data *fd, gimple_seq *body_p, && host_integerp (fd->loop.n2, 0) && ! integer_zerop (fd->loop.n2)) vinit = build_int_cst (TREE_TYPE (fd->loop.v), 0); + else + vinit = unshare_expr (vinit); /* Initialize the iterator variable, so that threads that don't execute any iterations don't execute the lastprivate clauses by accident. */ @@ -7578,7 +7926,7 @@ static void lower_omp_for (gimple_stmt_iterator *gsi_p, omp_context *ctx) { tree *rhs_p, block; - struct omp_for_data fd; + struct omp_for_data fd, *fdp = NULL; gimple stmt = gsi_stmt (*gsi_p), new_stmt; gimple_seq omp_for_body, body, dlist; size_t i; @@ -7605,41 +7953,11 @@ lower_omp_for (gimple_stmt_iterator *gsi_p, omp_context *ctx) gimple_bind_append_vars (new_stmt, vars); } - /* The pre-body and input clauses go before the lowered GIMPLE_OMP_FOR. */ - dlist = NULL; - body = NULL; - lower_rec_input_clauses (gimple_omp_for_clauses (stmt), &body, &dlist, ctx); - gimple_seq_add_seq (&body, gimple_omp_for_pre_body (stmt)); - - lower_omp (gimple_omp_body_ptr (stmt), ctx); - - /* Lower the header expressions. At this point, we can assume that - the header is of the form: - - #pragma omp for (V = VAL1; V {<|>|<=|>=} VAL2; V = V [+-] VAL3) - - We just need to make sure that VAL1, VAL2 and VAL3 are lowered - using the .omp_data_s mapping, if needed. */ - for (i = 0; i < gimple_omp_for_collapse (stmt); i++) - { - rhs_p = gimple_omp_for_initial_ptr (stmt, i); - if (!is_gimple_min_invariant (*rhs_p)) - *rhs_p = get_formal_tmp_var (*rhs_p, &body); - - rhs_p = gimple_omp_for_final_ptr (stmt, i); - if (!is_gimple_min_invariant (*rhs_p)) - *rhs_p = get_formal_tmp_var (*rhs_p, &body); - - rhs_p = &TREE_OPERAND (gimple_omp_for_incr (stmt, i), 1); - if (!is_gimple_min_invariant (*rhs_p)) - *rhs_p = get_formal_tmp_var (*rhs_p, &body); - } - - /* Once lowered, extract the bounds and clauses. */ - extract_omp_for_data (stmt, &fd, NULL); - if (gimple_omp_for_combined_into_p (stmt)) { + extract_omp_for_data (stmt, &fd, NULL); + fdp = &fd; + /* We need two temporaries with fd.loop.v type (istart/iend) and then (fd.collapse - 1) temporaries with the same type for count2 ... countN-1 vars if not constant. */ @@ -7674,8 +7992,41 @@ lower_omp_for (gimple_stmt_iterator *gsi_p, omp_context *ctx) *pc = clauses; } - if (gimple_omp_for_kind (fd.for_stmt) != GF_OMP_FOR_KIND_SIMD) - lower_omp_for_lastprivate (&fd, &body, &dlist, ctx); + /* The pre-body and input clauses go before the lowered GIMPLE_OMP_FOR. */ + dlist = NULL; + body = NULL; + lower_rec_input_clauses (gimple_omp_for_clauses (stmt), &body, &dlist, ctx, + fdp); + gimple_seq_add_seq (&body, gimple_omp_for_pre_body (stmt)); + + lower_omp (gimple_omp_body_ptr (stmt), ctx); + + /* Lower the header expressions. At this point, we can assume that + the header is of the form: + + #pragma omp for (V = VAL1; V {<|>|<=|>=} VAL2; V = V [+-] VAL3) + + We just need to make sure that VAL1, VAL2 and VAL3 are lowered + using the .omp_data_s mapping, if needed. */ + for (i = 0; i < gimple_omp_for_collapse (stmt); i++) + { + rhs_p = gimple_omp_for_initial_ptr (stmt, i); + if (!is_gimple_min_invariant (*rhs_p)) + *rhs_p = get_formal_tmp_var (*rhs_p, &body); + + rhs_p = gimple_omp_for_final_ptr (stmt, i); + if (!is_gimple_min_invariant (*rhs_p)) + *rhs_p = get_formal_tmp_var (*rhs_p, &body); + + rhs_p = &TREE_OPERAND (gimple_omp_for_incr (stmt, i), 1); + if (!is_gimple_min_invariant (*rhs_p)) + *rhs_p = get_formal_tmp_var (*rhs_p, &body); + } + + /* Once lowered, extract the bounds and clauses. */ + extract_omp_for_data (stmt, &fd, NULL); + + lower_omp_for_lastprivate (&fd, &body, &dlist, ctx); gimple_seq_add_stmt (&body, stmt); gimple_seq_add_seq (&body, gimple_omp_body (stmt)); @@ -7685,20 +8036,13 @@ lower_omp_for (gimple_stmt_iterator *gsi_p, omp_context *ctx) /* After the loop, add exit clauses. */ lower_reduction_clauses (gimple_omp_for_clauses (stmt), &body, ctx); + gimple_seq_add_seq (&body, dlist); body = maybe_catch_exception (body); /* Region exit marker goes at the end of the loop body. */ gimple_seq_add_stmt (&body, gimple_build_omp_return (fd.have_nowait)); - if (gimple_omp_for_kind (fd.for_stmt) == GF_OMP_FOR_KIND_SIMD) - { - dlist = NULL; - lower_lastprivate_clauses (gimple_omp_for_clauses (fd.for_stmt), - NULL_TREE, &dlist, ctx); - gimple_seq_add_seq (&body, dlist); - } - pop_gimplify_context (new_stmt); gimple_bind_append_vars (new_stmt, ctx->block_vars); @@ -8057,7 +8401,7 @@ lower_omp_taskreg (gimple_stmt_iterator *gsi_p, omp_context *ctx) par_olist = NULL; par_ilist = NULL; - lower_rec_input_clauses (clauses, &par_ilist, &par_olist, ctx); + lower_rec_input_clauses (clauses, &par_ilist, &par_olist, ctx, NULL); lower_omp (&par_body, ctx); if (gimple_code (stmt) == GIMPLE_OMP_PARALLEL) lower_reduction_clauses (clauses, &par_olist, ctx); diff --git a/gcc/tree-data-ref.c b/gcc/tree-data-ref.c index 10431c092371f..5bd7719516b33 100644 --- a/gcc/tree-data-ref.c +++ b/gcc/tree-data-ref.c @@ -4331,10 +4331,25 @@ get_references_in_stmt (gimple stmt, vec *references) /* ASM_EXPR and CALL_EXPR may embed arbitrary side effects. As we cannot model data-references to not spelled out accesses give up if they may occur. */ - if ((stmt_code == GIMPLE_CALL - && !(gimple_call_flags (stmt) & ECF_CONST)) - || (stmt_code == GIMPLE_ASM - && (gimple_asm_volatile_p (stmt) || gimple_vuse (stmt)))) + if (stmt_code == GIMPLE_CALL + && !(gimple_call_flags (stmt) & ECF_CONST)) + { + /* Allow IFN_GOMP_SIMD_LANE in their own loops. */ + if (gimple_call_internal_p (stmt) + && gimple_call_internal_fn (stmt) == IFN_GOMP_SIMD_LANE) + { + struct loop *loop = gimple_bb (stmt)->loop_father; + tree uid = gimple_call_arg (stmt, 0); + gcc_assert (TREE_CODE (uid) == SSA_NAME); + if (loop == NULL + || loop->simduid != SSA_NAME_VAR (uid)) + clobbers_memory = true; + } + else + clobbers_memory = true; + } + else if (stmt_code == GIMPLE_ASM + && (gimple_asm_volatile_p (stmt) || gimple_vuse (stmt))) clobbers_memory = true; if (!gimple_vuse (stmt)) diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index 7691c13abbb3c..6ff3e03b49e31 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -2345,6 +2345,8 @@ copy_cfg_body (copy_body_data * id, gcov_type count, int frequency_scale, get_loop (src_cfun, 0)); /* Defer to cfgcleanup to update loop-father fields of basic-blocks. */ loops_state_set (LOOPS_NEED_FIXUP); + cfun->has_force_vect_loops |= src_cfun->has_force_vect_loops; + cfun->has_simduid_loops |= src_cfun->has_simduid_loops; } /* If the loop tree in the source function needed fixup, mark the diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c index 7711a9b0123e3..bb93e390be36f 100644 --- a/gcc/tree-pretty-print.c +++ b/gcc/tree-pretty-print.c @@ -595,6 +595,13 @@ dump_omp_clause (pretty_printer *buffer, tree clause, int spc, int flags) pp_character (buffer, ')'); break; + case OMP_CLAUSE__SIMDUID_: + pp_string (buffer, "_simduid_("); + dump_generic_node (buffer, OMP_CLAUSE__SIMDUID__DECL (clause), + spc, flags, false); + pp_character (buffer, ')'); + break; + case OMP_CLAUSE_INBRANCH: pp_string (buffer, "inbranch"); break; diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c index 1bc4c2fb7b5d7..7f66bdaf54f62 100644 --- a/gcc/tree-ssa-ccp.c +++ b/gcc/tree-ssa-ccp.c @@ -626,6 +626,22 @@ likely_value (gimple stmt) if (has_constant_operand) all_undefined_operands = false; + if (has_undefined_operand + && code == GIMPLE_CALL + && gimple_call_internal_p (stmt)) + switch (gimple_call_internal_fn (stmt)) + { + /* These 3 builtins use the first argument just as a magic + way how to find out a decl uid. */ + case IFN_GOMP_SIMD_LANE: + case IFN_GOMP_SIMD_VF: + case IFN_GOMP_SIMD_LAST_LANE: + has_undefined_operand = false; + break; + default: + break; + } + /* If the operation combines operands like COMPLEX_EXPR make sure to not mark the result UNDEFINED if only one part of the result is undefined. */ diff --git a/gcc/tree-vect-data-refs.c b/gcc/tree-vect-data-refs.c index c11a1468b3b42..f6e21315ed5a4 100644 --- a/gcc/tree-vect-data-refs.c +++ b/gcc/tree-vect-data-refs.c @@ -2877,6 +2877,7 @@ vect_analyze_data_refs (loop_vec_info loop_vinfo, stmt_vec_info stmt_info; tree base, offset, init; bool gather = false; + bool simd_lane_access = false; int vf; again: @@ -2908,12 +2909,17 @@ vect_analyze_data_refs (loop_vec_info loop_vinfo, if (!DR_BASE_ADDRESS (dr) || !DR_OFFSET (dr) || !DR_INIT (dr) || !DR_STEP (dr)) { - /* If target supports vector gather loads, see if they can't - be used. */ - if (loop_vinfo - && DR_IS_READ (dr) + bool maybe_gather + = DR_IS_READ (dr) && !TREE_THIS_VOLATILE (DR_REF (dr)) - && targetm.vectorize.builtin_gather != NULL + && targetm.vectorize.builtin_gather != NULL; + bool maybe_simd_lane_access + = loop_vinfo && loop->simduid; + + /* If target supports vector gather loads, or if this might be + a SIMD lane access, see if they can't be used. */ + if (loop_vinfo + && (maybe_gather || maybe_simd_lane_access) && !nested_in_vect_loop_p (loop, stmt)) { struct data_reference *newdr @@ -2926,14 +2932,59 @@ vect_analyze_data_refs (loop_vec_info loop_vinfo, && DR_STEP (newdr) && integer_zerop (DR_STEP (newdr))) { - dr = newdr; - gather = true; + if (maybe_simd_lane_access) + { + tree off = DR_OFFSET (newdr); + STRIP_NOPS (off); + if (TREE_CODE (DR_INIT (newdr)) == INTEGER_CST + && TREE_CODE (off) == MULT_EXPR + && host_integerp (TREE_OPERAND (off, 1), 1)) + { + tree step = TREE_OPERAND (off, 1); + off = TREE_OPERAND (off, 0); + STRIP_NOPS (off); + if (CONVERT_EXPR_P (off) + && TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (off, + 0))) + < TYPE_PRECISION (TREE_TYPE (off))) + off = TREE_OPERAND (off, 0); + if (TREE_CODE (off) == SSA_NAME) + { + gimple def = SSA_NAME_DEF_STMT (off); + tree reft = TREE_TYPE (DR_REF (newdr)); + if (gimple_call_internal_p (def) + && gimple_call_internal_fn (def) + == IFN_GOMP_SIMD_LANE) + { + tree arg = gimple_call_arg (def, 0); + gcc_assert (TREE_CODE (arg) == SSA_NAME); + arg = SSA_NAME_VAR (arg); + if (arg == loop->simduid + /* For now. */ + && tree_int_cst_equal + (TYPE_SIZE_UNIT (reft), + step)) + { + DR_OFFSET (newdr) = ssize_int (0); + DR_STEP (newdr) = step; + dr = newdr; + simd_lane_access = true; + } + } + } + } + } + if (!simd_lane_access && maybe_gather) + { + dr = newdr; + gather = true; + } } - else + if (!gather && !simd_lane_access) free_data_ref (newdr); } - if (!gather) + if (!gather && !simd_lane_access) { if (dump_enabled_p ()) { @@ -2960,7 +3011,7 @@ vect_analyze_data_refs (loop_vec_info loop_vinfo, if (bb_vinfo) break; - if (gather) + if (gather || simd_lane_access) free_data_ref (dr); return false; } @@ -2993,7 +3044,7 @@ vect_analyze_data_refs (loop_vec_info loop_vinfo, if (bb_vinfo) break; - if (gather) + if (gather || simd_lane_access) free_data_ref (dr); return false; } @@ -3012,7 +3063,7 @@ vect_analyze_data_refs (loop_vec_info loop_vinfo, if (bb_vinfo) break; - if (gather) + if (gather || simd_lane_access) free_data_ref (dr); return false; } @@ -3033,7 +3084,7 @@ vect_analyze_data_refs (loop_vec_info loop_vinfo, if (bb_vinfo) break; - if (gather) + if (gather || simd_lane_access) free_data_ref (dr); return false; } @@ -3168,12 +3219,17 @@ vect_analyze_data_refs (loop_vec_info loop_vinfo, if (bb_vinfo) break; - if (gather) + if (gather || simd_lane_access) free_data_ref (dr); return false; } STMT_VINFO_DATA_REF (stmt_info) = dr; + if (simd_lane_access) + { + STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) = true; + datarefs[i] = dr; + } /* Set vectype for STMT. */ scalar_type = TREE_TYPE (DR_REF (dr)); @@ -3194,7 +3250,7 @@ vect_analyze_data_refs (loop_vec_info loop_vinfo, if (bb_vinfo) break; - if (gather) + if (gather || simd_lane_access) { STMT_VINFO_DATA_REF (stmt_info) = NULL; free_data_ref (dr); diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c index c9b102132578f..3346dbf84333a 100644 --- a/gcc/tree-vect-loop.c +++ b/gcc/tree-vect-loop.c @@ -5361,7 +5361,7 @@ vectorizable_induction (gimple phi, gimple_stmt_iterator *gsi ATTRIBUTE_UNUSED, bool vectorizable_live_operation (gimple stmt, gimple_stmt_iterator *gsi ATTRIBUTE_UNUSED, - gimple *vec_stmt ATTRIBUTE_UNUSED) + gimple *vec_stmt) { stmt_vec_info stmt_info = vinfo_for_stmt (stmt); loop_vec_info loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_info); @@ -5381,7 +5381,41 @@ vectorizable_live_operation (gimple stmt, return false; if (!is_gimple_assign (stmt)) - return false; + { + if (gimple_call_internal_p (stmt) + && gimple_call_internal_fn (stmt) == IFN_GOMP_SIMD_LANE + && gimple_call_lhs (stmt) + && loop->simduid + && TREE_CODE (gimple_call_arg (stmt, 0)) == SSA_NAME + && loop->simduid + == SSA_NAME_VAR (gimple_call_arg (stmt, 0))) + { + edge e = single_exit (loop); + basic_block merge_bb = e->dest; + imm_use_iterator imm_iter; + use_operand_p use_p; + tree lhs = gimple_call_lhs (stmt); + + FOR_EACH_IMM_USE_FAST (use_p, imm_iter, lhs) + { + gimple use_stmt = USE_STMT (use_p); + if (gimple_code (use_stmt) == GIMPLE_PHI + || gimple_bb (use_stmt) == merge_bb) + { + if (vec_stmt) + { + tree vfm1 + = build_int_cst (unsigned_type_node, + loop_vinfo->vectorization_factor - 1); + SET_PHI_ARG_DEF (use_stmt, e->dest_idx, vfm1); + } + return true; + } + } + } + + return false; + } if (TREE_CODE (gimple_assign_lhs (stmt)) != SSA_NAME) return false; diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c index 0580f7dfadca4..3768dcd114bc0 100644 --- a/gcc/tree-vect-stmts.c +++ b/gcc/tree-vect-stmts.c @@ -1755,6 +1755,14 @@ vectorizable_call (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt, if (nargs == 0 || nargs > 3) return false; + /* Ignore the argument of IFN_GOMP_SIMD_LANE, it is magic. */ + if (gimple_call_internal_p (stmt) + && gimple_call_internal_fn (stmt) == IFN_GOMP_SIMD_LANE) + { + nargs = 0; + rhs_type = unsigned_type_node; + } + for (i = 0; i < nargs; i++) { tree opvectype; @@ -1830,11 +1838,26 @@ vectorizable_call (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt, fndecl = vectorizable_function (stmt, vectype_out, vectype_in); if (fndecl == NULL_TREE) { - if (dump_enabled_p ()) - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, - "function is not vectorizable."); - - return false; + if (gimple_call_internal_p (stmt) + && gimple_call_internal_fn (stmt) == IFN_GOMP_SIMD_LANE + && !slp_node + && loop_vinfo + && LOOP_VINFO_LOOP (loop_vinfo)->simduid + && TREE_CODE (gimple_call_arg (stmt, 0)) == SSA_NAME + && LOOP_VINFO_LOOP (loop_vinfo)->simduid + == SSA_NAME_VAR (gimple_call_arg (stmt, 0))) + { + /* We can handle IFN_GOMP_SIMD_LANE by returning a + { 0, 1, 2, ... vf - 1 } vector. */ + gcc_assert (nargs == 0); + } + else + { + if (dump_enabled_p ()) + dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, + "function is not vectorizable."); + return false; + } } gcc_assert (!gimple_vuse (stmt)); @@ -1932,9 +1955,30 @@ vectorizable_call (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt, vargs.quick_push (vec_oprnd0); } - new_stmt = gimple_build_call_vec (fndecl, vargs); - new_temp = make_ssa_name (vec_dest, new_stmt); - gimple_call_set_lhs (new_stmt, new_temp); + if (gimple_call_internal_p (stmt) + && gimple_call_internal_fn (stmt) == IFN_GOMP_SIMD_LANE) + { + tree *v = XALLOCAVEC (tree, nunits_out); + int k; + for (k = 0; k < nunits_out; ++k) + v[k] = build_int_cst (unsigned_type_node, j * nunits_out + k); + tree cst = build_vector (vectype_out, v); + tree new_var + = vect_get_new_vect_var (vectype_out, vect_simple_var, "cst_"); + gimple init_stmt = gimple_build_assign (new_var, cst); + new_temp = make_ssa_name (new_var, init_stmt); + gimple_assign_set_lhs (init_stmt, new_temp); + vect_init_vector_1 (stmt, init_stmt, NULL); + new_temp = make_ssa_name (vec_dest, NULL); + new_stmt = gimple_build_assign (new_temp, + gimple_assign_lhs (init_stmt)); + } + else + { + new_stmt = gimple_build_call_vec (fndecl, vargs); + new_temp = make_ssa_name (vec_dest, new_stmt); + gimple_call_set_lhs (new_stmt, new_temp); + } vect_finish_stmt_generation (stmt, new_stmt, gsi); if (j == 0) @@ -3796,6 +3840,7 @@ vectorizable_store (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt, enum vect_def_type dt; stmt_vec_info prev_stmt_info = NULL; tree dataref_ptr = NULL_TREE; + tree dataref_offset = NULL_TREE; gimple ptr_incr = NULL; int nunits = TYPE_VECTOR_SUBPARTS (vectype); int ncopies; @@ -4085,9 +4130,26 @@ vectorizable_store (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt, /* We should have catched mismatched types earlier. */ gcc_assert (useless_type_conversion_p (vectype, TREE_TYPE (vec_oprnd))); - dataref_ptr = vect_create_data_ref_ptr (first_stmt, aggr_type, NULL, - NULL_TREE, &dummy, gsi, - &ptr_incr, false, &inv_p); + bool simd_lane_access_p + = STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info); + if (simd_lane_access_p + && TREE_CODE (DR_BASE_ADDRESS (first_dr)) == ADDR_EXPR + && VAR_P (TREE_OPERAND (DR_BASE_ADDRESS (first_dr), 0)) + && integer_zerop (DR_OFFSET (first_dr)) + && integer_zerop (DR_INIT (first_dr)) + && alias_sets_conflict_p (get_alias_set (aggr_type), + get_alias_set (DR_REF (first_dr)))) + { + dataref_ptr = unshare_expr (DR_BASE_ADDRESS (first_dr)); + dataref_offset = build_int_cst (reference_alias_ptr_type + (DR_REF (first_dr)), 0); + } + else + dataref_ptr + = vect_create_data_ref_ptr (first_stmt, aggr_type, + simd_lane_access_p ? loop : NULL, + NULL_TREE, &dummy, gsi, &ptr_incr, + simd_lane_access_p, &inv_p); gcc_assert (bb_vinfo || !inv_p); } else @@ -4108,8 +4170,13 @@ vectorizable_store (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt, dr_chain[i] = vec_oprnd; oprnds[i] = vec_oprnd; } - dataref_ptr = bump_vector_ptr (dataref_ptr, ptr_incr, gsi, stmt, - TYPE_SIZE_UNIT (aggr_type)); + if (dataref_offset) + dataref_offset + = int_const_binop (PLUS_EXPR, dataref_offset, + TYPE_SIZE_UNIT (aggr_type)); + else + dataref_ptr = bump_vector_ptr (dataref_ptr, ptr_incr, gsi, stmt, + TYPE_SIZE_UNIT (aggr_type)); } if (store_lanes_p) @@ -4161,8 +4228,10 @@ vectorizable_store (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt, vec_oprnd = result_chain[i]; data_ref = build2 (MEM_REF, TREE_TYPE (vec_oprnd), dataref_ptr, - build_int_cst (reference_alias_ptr_type - (DR_REF (first_dr)), 0)); + dataref_offset + ? dataref_offset + : build_int_cst (reference_alias_ptr_type + (DR_REF (first_dr)), 0)); align = TYPE_ALIGN_UNIT (vectype); if (aligned_access_p (first_dr)) misalign = 0; @@ -4181,8 +4250,9 @@ vectorizable_store (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt, TYPE_ALIGN (elem_type)); misalign = DR_MISALIGNMENT (first_dr); } - set_ptr_info_alignment (get_ptr_info (dataref_ptr), align, - misalign); + if (dataref_offset == NULL_TREE) + set_ptr_info_alignment (get_ptr_info (dataref_ptr), align, + misalign); /* Arguments are ready. Create the new vector stmt. */ new_stmt = gimple_build_assign (data_ref, vec_oprnd); @@ -4314,6 +4384,7 @@ vectorizable_load (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt, tree dummy; enum dr_alignment_support alignment_support_scheme; tree dataref_ptr = NULL_TREE; + tree dataref_offset = NULL_TREE; gimple ptr_incr = NULL; int nunits = TYPE_VECTOR_SUBPARTS (vectype); int ncopies; @@ -4947,9 +5018,32 @@ vectorizable_load (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt, { /* 1. Create the vector or array pointer update chain. */ if (j == 0) - dataref_ptr = vect_create_data_ref_ptr (first_stmt, aggr_type, at_loop, - offset, &dummy, gsi, - &ptr_incr, false, &inv_p); + { + bool simd_lane_access_p + = STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info); + if (simd_lane_access_p + && TREE_CODE (DR_BASE_ADDRESS (first_dr)) == ADDR_EXPR + && VAR_P (TREE_OPERAND (DR_BASE_ADDRESS (first_dr), 0)) + && integer_zerop (DR_OFFSET (first_dr)) + && integer_zerop (DR_INIT (first_dr)) + && alias_sets_conflict_p (get_alias_set (aggr_type), + get_alias_set (DR_REF (first_dr))) + && (alignment_support_scheme == dr_aligned + || alignment_support_scheme == dr_unaligned_supported)) + { + dataref_ptr = unshare_expr (DR_BASE_ADDRESS (first_dr)); + dataref_offset = build_int_cst (reference_alias_ptr_type + (DR_REF (first_dr)), 0); + } + else + dataref_ptr + = vect_create_data_ref_ptr (first_stmt, aggr_type, at_loop, + offset, &dummy, gsi, &ptr_incr, + simd_lane_access_p, &inv_p); + } + else if (dataref_offset) + dataref_offset = int_const_binop (PLUS_EXPR, dataref_offset, + TYPE_SIZE_UNIT (aggr_type)); else dataref_ptr = bump_vector_ptr (dataref_ptr, ptr_incr, gsi, stmt, TYPE_SIZE_UNIT (aggr_type)); @@ -4999,8 +5093,10 @@ vectorizable_load (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt, data_ref = build2 (MEM_REF, vectype, dataref_ptr, - build_int_cst (reference_alias_ptr_type - (DR_REF (first_dr)), 0)); + dataref_offset + ? dataref_offset + : build_int_cst (reference_alias_ptr_type + (DR_REF (first_dr)), 0)); align = TYPE_ALIGN_UNIT (vectype); if (alignment_support_scheme == dr_aligned) { @@ -5022,8 +5118,9 @@ vectorizable_load (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt, TYPE_ALIGN (elem_type)); misalign = DR_MISALIGNMENT (first_dr); } - set_ptr_info_alignment (get_ptr_info (dataref_ptr), - align, misalign); + if (dataref_offset == NULL_TREE) + set_ptr_info_alignment (get_ptr_info (dataref_ptr), + align, misalign); break; } case dr_explicit_realign: diff --git a/gcc/tree-vectorizer.c b/gcc/tree-vectorizer.c index ea15cfd2da125..6de914f73f285 100644 --- a/gcc/tree-vectorizer.c +++ b/gcc/tree-vectorizer.c @@ -66,13 +66,209 @@ along with GCC; see the file COPYING3. If not see #include "cfgloop.h" #include "tree-vectorizer.h" #include "tree-pass.h" +#include "hash-table.h" +#include "tree-ssa-propagate.h" /* Loop or bb location. */ LOC vect_location; /* Vector mapping GIMPLE stmt to stmt_vec_info. */ vec stmt_vec_info_vec; + +/* For mapping simduid to vectorization factor. */ + +struct simduid_to_vf : typed_free_remove +{ + unsigned int simduid; + int vf; + + /* hash_table support. */ + typedef simduid_to_vf value_type; + typedef simduid_to_vf compare_type; + static inline hashval_t hash (const value_type *); + static inline int equal (const value_type *, const compare_type *); +}; + +inline hashval_t +simduid_to_vf::hash (const value_type *p) +{ + return p->simduid; +} + +inline int +simduid_to_vf::equal (const value_type *p1, const value_type *p2) +{ + return p1->simduid == p2->simduid; +} + +/* For mapping decl to simduid. */ + +struct decl_to_simduid : typed_free_remove +{ + tree decl; + unsigned int simduid; + + /* hash_table support. */ + typedef decl_to_simduid value_type; + typedef decl_to_simduid compare_type; + static inline hashval_t hash (const value_type *); + static inline int equal (const value_type *, const compare_type *); +}; + +inline hashval_t +decl_to_simduid::hash (const value_type *p) +{ + return DECL_UID (p->decl); +} + +inline int +decl_to_simduid::equal (const value_type *p1, const value_type *p2) +{ + return p1->decl == p2->decl; +} + +/* Fold IFN_GOMP_SIMD_LANE, IFN_GOMP_SIMD_VF and IFN_GOMP_SIMD_LAST_LANE + into their corresponding constants. */ + +static void +adjust_simduid_builtins (hash_table &htab) +{ + basic_block bb; + + FOR_EACH_BB (bb) + { + gimple_stmt_iterator i; + + for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i)) + { + unsigned int vf = 1; + enum internal_fn ifn; + gimple stmt = gsi_stmt (i); + tree t; + if (!is_gimple_call (stmt) + || !gimple_call_internal_p (stmt)) + continue; + ifn = gimple_call_internal_fn (stmt); + switch (ifn) + { + case IFN_GOMP_SIMD_LANE: + case IFN_GOMP_SIMD_VF: + case IFN_GOMP_SIMD_LAST_LANE: + break; + default: + continue; + } + tree arg = gimple_call_arg (stmt, 0); + gcc_assert (arg != NULL_TREE); + gcc_assert (TREE_CODE (arg) == SSA_NAME); + simduid_to_vf *p = NULL, data; + data.simduid = DECL_UID (SSA_NAME_VAR (arg)); + if (htab.is_created ()) + p = htab.find (&data); + if (p) + vf = p->vf; + switch (ifn) + { + case IFN_GOMP_SIMD_VF: + t = build_int_cst (unsigned_type_node, vf); + break; + case IFN_GOMP_SIMD_LANE: + t = build_int_cst (unsigned_type_node, 0); + break; + case IFN_GOMP_SIMD_LAST_LANE: + t = gimple_call_arg (stmt, 1); + break; + default: + gcc_unreachable (); + } + update_call_from_tree (&i, t); + } + } +} +/* Helper structure for note_simd_array_uses. */ + +struct note_simd_array_uses_struct +{ + hash_table *htab; + unsigned int simduid; +}; + +/* Callback for note_simd_array_uses, called through walk_gimple_op. */ + +static tree +note_simd_array_uses_cb (tree *tp, int *walk_subtrees, void *data) +{ + struct walk_stmt_info *wi = (struct walk_stmt_info *) data; + struct note_simd_array_uses_struct *ns + = (struct note_simd_array_uses_struct *) wi->info; + + if (TYPE_P (*tp)) + *walk_subtrees = 0; + else if (VAR_P (*tp) + && lookup_attribute ("omp simd array", DECL_ATTRIBUTES (*tp)) + && DECL_CONTEXT (*tp) == current_function_decl) + { + decl_to_simduid data; + if (!ns->htab->is_created ()) + ns->htab->create (15); + data.decl = *tp; + data.simduid = ns->simduid; + decl_to_simduid **slot = ns->htab->find_slot (&data, INSERT); + if (*slot == NULL) + { + decl_to_simduid *p = XNEW (decl_to_simduid); + *p = data; + *slot = p; + } + else if ((*slot)->simduid != ns->simduid) + (*slot)->simduid = -1U; + *walk_subtrees = 0; + } + return NULL_TREE; +} + +/* Find "omp simd array" temporaries and map them to corresponding + simduid. */ + +static void +note_simd_array_uses (hash_table *htab) +{ + basic_block bb; + gimple_stmt_iterator gsi; + struct walk_stmt_info wi; + struct note_simd_array_uses_struct ns; + + memset (&wi, 0, sizeof (wi)); + wi.info = &ns; + ns.htab = htab; + + FOR_EACH_BB (bb) + for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) + { + gimple stmt = gsi_stmt (gsi); + if (!is_gimple_call (stmt) || !gimple_call_internal_p (stmt)) + continue; + switch (gimple_call_internal_fn (stmt)) + { + case IFN_GOMP_SIMD_LANE: + case IFN_GOMP_SIMD_VF: + case IFN_GOMP_SIMD_LAST_LANE: + break; + default: + continue; + } + tree lhs = gimple_call_lhs (stmt); + if (lhs == NULL_TREE) + continue; + imm_use_iterator use_iter; + gimple use_stmt; + ns.simduid = DECL_UID (SSA_NAME_VAR (gimple_call_arg (stmt, 0))); + FOR_EACH_IMM_USE_STMT (use_stmt, use_iter, lhs) + if (!is_gimple_debug (use_stmt)) + walk_gimple_op (use_stmt, note_simd_array_uses_cb, &wi); + } +} /* Function vectorize_loops. @@ -86,12 +282,21 @@ vectorize_loops (void) unsigned int vect_loops_num; loop_iterator li; struct loop *loop; + hash_table simduid_to_vf_htab; + hash_table decl_to_simduid_htab; vect_loops_num = number_of_loops (cfun); /* Bail out if there are no loops. */ if (vect_loops_num <= 1) - return 0; + { + if (cfun->has_simduid_loops) + adjust_simduid_builtins (simduid_to_vf_htab); + return 0; + } + + if (cfun->has_simduid_loops) + note_simd_array_uses (&decl_to_simduid_htab); init_stmt_vec_info_vec (); @@ -126,6 +331,17 @@ vectorize_loops (void) /* Now that the loop has been vectorized, allow it to be unrolled etc. */ loop->force_vect = false; + + if (loop->simduid) + { + simduid_to_vf *simduid_to_vf_data = XNEW (simduid_to_vf); + if (!simduid_to_vf_htab.is_created ()) + simduid_to_vf_htab.create (15); + simduid_to_vf_data->simduid = DECL_UID (loop->simduid); + simduid_to_vf_data->vf = loop_vinfo->vectorization_factor; + *simduid_to_vf_htab.find_slot (simduid_to_vf_data, INSERT) + = simduid_to_vf_data; + } } vect_location = UNKNOWN_LOC; @@ -153,6 +369,40 @@ vectorize_loops (void) free_stmt_vec_info_vec (); + /* Fold IFN_GOMP_SIMD_{VF,LANE,LAST_LANE} builtins. */ + if (cfun->has_simduid_loops) + adjust_simduid_builtins (simduid_to_vf_htab); + + /* Shrink any "omp array simd" temporary arrays to the + actual vectorization factors. */ + if (decl_to_simduid_htab.is_created ()) + { + for (hash_table ::iterator iter + = decl_to_simduid_htab.begin (); + iter != decl_to_simduid_htab.end (); ++iter) + if ((*iter).simduid != -1U) + { + tree decl = (*iter).decl; + int vf = 1; + if (simduid_to_vf_htab.is_created ()) + { + simduid_to_vf *p = NULL, data; + data.simduid = (*iter).simduid; + p = simduid_to_vf_htab.find (&data); + if (p) + vf = p->vf; + } + tree atype + = build_array_type_nelts (TREE_TYPE (TREE_TYPE (decl)), vf); + TREE_TYPE (decl) = atype; + relayout_decl (decl); + } + + decl_to_simduid_htab.dispose (); + } + if (simduid_to_vf_htab.is_created ()) + simduid_to_vf_htab.dispose (); + if (num_vectorized_loops > 0) { /* If we vectorized any loop only virtual SSA form needs to be updated. diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h index 7c5dfe884dfb6..3570dc9d76adb 100644 --- a/gcc/tree-vectorizer.h +++ b/gcc/tree-vectorizer.h @@ -576,6 +576,9 @@ typedef struct _stmt_vec_info { /* For loads only, true if this is a gather load. */ bool gather_p; bool stride_load_p; + + /* For both loads and stores. */ + bool simd_lane_access_p; } *stmt_vec_info; /* Access Functions. */ @@ -591,6 +594,7 @@ typedef struct _stmt_vec_info { #define STMT_VINFO_DATA_REF(S) (S)->data_ref_info #define STMT_VINFO_GATHER_P(S) (S)->gather_p #define STMT_VINFO_STRIDE_LOAD_P(S) (S)->stride_load_p +#define STMT_VINFO_SIMD_LANE_ACCESS_P(S) (S)->simd_lane_access_p #define STMT_VINFO_DR_BASE_ADDRESS(S) (S)->dr_base_address #define STMT_VINFO_DR_INIT(S) (S)->dr_init diff --git a/gcc/tree.c b/gcc/tree.c index 5725f80b2afe3..69d7a0897cb53 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -266,7 +266,8 @@ unsigned const char omp_clause_num_ops[] = 0, /* OMP_CLAUSE_FOR */ 0, /* OMP_CLAUSE_PARALLEL */ 0, /* OMP_CLAUSE_SECTIONS */ - 0 /* OMP_CLAUSE_TASKGROUP */ + 0, /* OMP_CLAUSE_TASKGROUP */ + 1, /* OMP_CLAUSE__SIMDUID_ */ }; const char * const omp_clause_code_name[] = @@ -309,7 +310,8 @@ const char * const omp_clause_code_name[] = "for", "parallel", "sections", - "taskgroup" + "taskgroup", + "_simduid_" }; @@ -11133,6 +11135,7 @@ walk_tree_1 (tree *tp, walk_tree_fn func, void *data, case OMP_CLAUSE_SAFELEN: case OMP_CLAUSE_SIMDLEN: case OMP_CLAUSE__LOOPTEMP_: + case OMP_CLAUSE__SIMDUID_: WALK_SUBTREE (OMP_CLAUSE_OPERAND (*tp, 0)); /* FALLTHRU */ diff --git a/gcc/tree.h b/gcc/tree.h index 761c0bb40a29c..60d47ae19e2ef 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -456,7 +456,10 @@ enum omp_clause_code OMP_CLAUSE_SECTIONS, /* OpenMP clause: taskgroup. */ - OMP_CLAUSE_TASKGROUP + OMP_CLAUSE_TASKGROUP, + + /* Internally used only clause, holding SIMD uid. */ + OMP_CLAUSE__SIMDUID_ }; /* The definition of tree nodes fills the next several pages. */ @@ -2001,6 +2004,9 @@ extern void protected_set_expr_location (tree, location_t); #define OMP_CLAUSE_SIMDLEN_EXPR(NODE) \ OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_SIMDLEN), 0) +#define OMP_CLAUSE__SIMDUID__DECL(NODE) \ + OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE__SIMDUID_), 0) + enum omp_clause_schedule_kind { OMP_CLAUSE_SCHEDULE_STATIC, diff --git a/libgomp/ChangeLog.gomp b/libgomp/ChangeLog.gomp index 025d4b3941367..375801c5315f4 100644 --- a/libgomp/ChangeLog.gomp +++ b/libgomp/ChangeLog.gomp @@ -1,3 +1,9 @@ +2013-06-28 Jakub Jelinek + + * testsuite/libgomp.c++/simd-1.C: New test. + * testsuite/libgomp.c++/simd-2.C: New test. + * testsuite/libgomp.c++/simd-3.C: New test. + 2013-06-21 Jakub Jelinek * testsuite/libgomp.c/for-1.h: New file. diff --git a/libgomp/testsuite/libgomp.c++/simd-1.C b/libgomp/testsuite/libgomp.c++/simd-1.C new file mode 100644 index 0000000000000..16ef159b82747 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/simd-1.C @@ -0,0 +1,79 @@ +// { dg-do run } +// { dg-options "-O2" } +// { dg-additional-options "-msse2" { target sse2_runtime } } +// { dg-additional-options "-mavx" { target avx_runtime } } + +extern "C" void abort (); +int a[1024] __attribute__((aligned (32))) = { 1 }; +int b[1024] __attribute__((aligned (32))) = { 1 }; +int k, m; +struct U { U (); ~U (); int u; }; +struct V +{ + V () : v (8) {} + ~V () + { + if (v > 38 + 4 + 3 * 1024 + 1) + abort (); + } + V &operator= (const V &x) { v = x.v + 1; return *this; } + int v; +}; + +__attribute__((noinline, noclone)) +U::U () : u (6) +{ +} + +__attribute__((noinline, noclone)) +U::~U () +{ + if (u > 38 + 4 + 3 * 1023) + abort (); +} + +__attribute__((noinline, noclone)) int +foo (int *p) +{ + int i, s = 0; + U u; + V v; + #pragma omp simd aligned(a, p : 32) linear(k: m + 1) \ + reduction(+:s) lastprivate(u, v) + for (i = 0; i < 1024; i++) + { + a[i] *= p[i]; + u.u = p[i] + k; + k += m + 1; + v.v = p[i] + k; + s += p[i] + k; + } + if (u.u != 36 + 4 + 3 * 1023 || v.v != 36 + 4 + 3 * 1024 + 1) + abort (); + return s; +} + +int +main () +{ +#if __SIZEOF_INT__ >= 4 + int i; + k = 4; + m = 2; + for (i = 0; i < 1024; i++) + { + a[i] = i - 512; + b[i] = (i - 51) % 39; + } + int s = foo (b); + for (i = 0; i < 1024; i++) + { + if (b[i] != (i - 51) % 39 + || a[i] != (i - 512) * b[i]) + abort (); + } + if (k != 4 + 3 * 1024 || s != 1596127) + abort (); +#endif + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/simd-2.C b/libgomp/testsuite/libgomp.c++/simd-2.C new file mode 100644 index 0000000000000..6b12415bdceb1 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/simd-2.C @@ -0,0 +1,36 @@ +// { dg-do run } +// { dg-options "-O2" } +// { dg-additional-options "-msse2" { target sse2_runtime } } +// { dg-additional-options "-mavx" { target avx_runtime } } + +extern "C" void abort (); +__UINTPTR_TYPE__ arr[1027]; + +__attribute__((noinline, noclone)) void +foo () +{ + int i, v; + #pragma omp simd private (v) safelen(16) + for (i = 0; i < 1027; i++) + arr[i] = (__UINTPTR_TYPE__) &v; +} + +int +main () +{ + int i, j, cnt = 0; + __UINTPTR_TYPE__ arr2[16]; + foo (); + for (i = 0; i < 1027; i++) + { + for (j = 0; j < cnt; j++) + if (arr[i] == arr2[j]) + break; + if (j != cnt) + continue; + if (cnt == 16) + abort (); + arr2[cnt++] = arr[i]; + } + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/simd-3.C b/libgomp/testsuite/libgomp.c++/simd-3.C new file mode 100644 index 0000000000000..1c6d8e01af908 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/simd-3.C @@ -0,0 +1,131 @@ +// { dg-do run } +// { dg-options "-O2" } +// { dg-additional-options "-msse2" { target sse2_runtime } } +// { dg-additional-options "-mavx" { target avx_runtime } } + +extern "C" void abort (); +int a[1024] __attribute__((aligned (32))) = { 1 }; +int b[1024] __attribute__((aligned (32))) = { 1 }; +unsigned char c[1024] __attribute__((aligned (32))) = { 1 }; +int k, m; +__UINTPTR_TYPE__ u, u2, u3; + +__attribute__((noinline, noclone)) int +foo (int *p) +{ + int i, s = 0, s2 = 0, t, t2; + #pragma omp simd aligned(a, b, p : 32) linear(k: m + 1) reduction(+:s) \ + lastprivate (t2) + for (i = 0; i < 512; i++) + { + a[i] *= p[i]; + t2 = k + p[i]; + k += m + 1; + s += p[i] + k; + c[i]++; + } + #pragma omp simd aligned(a, b, p : 32) linear(k: m + 1) reduction(+:s2) \ + lastprivate (t, u, u2, u3) + for (i = 512; i < 1024; i++) + { + a[i] *= p[i]; + k += m + 1; + t = k + p[i]; + u = (__UINTPTR_TYPE__) &k; + u2 = (__UINTPTR_TYPE__) &s2; + u3 = (__UINTPTR_TYPE__) &t; + s2 += t; + c[i]++; + } + return s + s2 + t + t2; +} + +__attribute__((noinline, noclone)) long int +bar (int *p, long int n, long int o) +{ + long int i, s = 0, s2 = 0, t, t2; + #pragma omp simd aligned(a, b, p : 32) linear(k: m + 1) reduction(+:s) \ + lastprivate (t2) + for (i = 0; i < n; i++) + { + a[i] *= p[i]; + t2 = k + p[i]; + k += m + 1; + s += p[i] + k; + c[i]++; + } + #pragma omp simd aligned(a, b, p : 32) linear(k: m + 1) reduction(+:s2) \ + lastprivate (t, u, u2, u3) + for (i = n; i < o; i++) + { + a[i] *= p[i]; + k += m + 1; + t = k + p[i]; + u = (__UINTPTR_TYPE__) &k; + u2 = (__UINTPTR_TYPE__) &s2; + u3 = (__UINTPTR_TYPE__) &t; + s2 += t; + c[i]++; + } + return s + s2 + t + t2; +} + +int +main () +{ +#if __SIZEOF_INT__ >= 4 + int i; + k = 4; + m = 2; + for (i = 0; i < 1024; i++) + { + a[i] = i - 512; + b[i] = (i - 51) % 39; + c[i] = (unsigned char) i; + } + int s = foo (b); + for (i = 0; i < 1024; i++) + { + if (b[i] != (i - 51) % 39 + || a[i] != (i - 512) * b[i] + || c[i] != (unsigned char) (i + 1)) + abort (); + a[i] = i - 512; + } + if (k != 4 + 3 * 1024 + || s != 1596127 + (4 + 3 * 511 + b[511]) + (4 + 3 * 1024 + b[1023])) + abort (); + k = 4; + s = bar (b, 512, 1024); + for (i = 0; i < 1024; i++) + { + if (b[i] != (i - 51) % 39 + || a[i] != (i - 512) * b[i] + || c[i] != (unsigned char) (i + 2)) + abort (); + a[i] = i - 512; + } + if (k != 4 + 3 * 1024 + || s != 1596127 + (4 + 3 * 511 + b[511]) + (4 + 3 * 1024 + b[1023])) + abort (); + k = 4; + s = bar (b, 511, 1021); + for (i = 0; i < 1021; i++) + { + if (b[i] != (i - 51) % 39 + || a[i] != (i - 512) * b[i] + || c[i] != (unsigned char) (i + 3)) + abort (); + a[i] = i - 512; + } + for (i = 1021; i < 1024; i++) + if (b[i] != (i - 51) % 39 + || a[i] != i - 512 + || c[i] != (unsigned char) (i + 2)) + abort (); + if (k != 4 + 3 * 1021 + || s != 1586803 + (4 + 3 * 510 + b[510]) + (4 + 3 * 1021 + b[1020])) + abort (); +#endif + return 0; +} From 5ca05cc513c2a141e2636957ed60a9e3d3e75bd6 Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Fri, 28 Jun 2013 10:23:50 -0700 Subject: [PATCH 63/63] Fix merge fallout. Use flag_enable_cilkplus instead of flag_enable_cilk. --- gcc/c-family/c-pragma.c | 2 +- gcc/c-family/c.opt | 4 ---- gcc/c/c-parser.c | 2 +- gcc/omp-low.c | 8 ++++---- 4 files changed, 6 insertions(+), 10 deletions(-) diff --git a/gcc/c-family/c-pragma.c b/gcc/c-family/c-pragma.c index 635c20ca85b41..cdc92d53b9a5a 100644 --- a/gcc/c-family/c-pragma.c +++ b/gcc/c-family/c-pragma.c @@ -1358,7 +1358,7 @@ init_pragma (void) omp_pragmas[i].id, true, true); } - if (flag_enable_cilk && !flag_preprocess_only) + if (flag_enable_cilkplus && !flag_preprocess_only) { cpp_register_deferred_pragma (parse_in, NULL, "simd", PRAGMA_CILK_SIMD, true, false); diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index 57966692714df..857813474c9a3 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -839,10 +839,6 @@ Recognize built-in functions fbuiltin- C ObjC C++ ObjC++ Joined -fcilkplus -C ObjC C++ ObjC++ LTO Report Var(flag_enable_cilk) Init(0) -Enable Cilk - fcanonical-system-headers C ObjC C++ ObjC++ Where shorter, use canonicalized paths to systems headers. diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index 6588a51df4227..e064b32aeec8c 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -11864,7 +11864,7 @@ static bool c_parser_cilk_verify_simd (c_parser *parser, enum pragma_context context) { - if (!flag_enable_cilk) + if (!flag_enable_cilkplus) { warning (0, "pragma simd ignored because -fcilkplus is not enabled"); c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); diff --git a/gcc/omp-low.c b/gcc/omp-low.c index cb304add917cd..f5d1735964a55 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -7413,7 +7413,7 @@ execute_expand_omp (void) static bool gate_expand_omp (void) { - return ((flag_openmp || flag_enable_cilk) && !seen_error ()); + return ((flag_openmp || flag_enable_cilkplus) && !seen_error ()); } struct gimple_opt_pass pass_expand_omp = @@ -8604,7 +8604,7 @@ execute_lower_omp (void) /* This pass always runs, to provide PROP_gimple_lomp. But there is nothing to do unless -fopenmp is given. */ - if (!flag_openmp && !flag_enable_cilk) + if (!flag_openmp && !flag_enable_cilkplus) return 0; all_contexts = splay_tree_new (splay_tree_compare_pointers, 0, @@ -8708,7 +8708,7 @@ diagnose_sb_0 (gimple_stmt_iterator *gsi_p, #endif bool cilkplus_block = false; - if (flag_enable_cilk) + if (flag_enable_cilkplus) { if ((branch_ctx && gimple_code (branch_ctx) == GIMPLE_OMP_FOR @@ -8916,7 +8916,7 @@ diagnose_omp_structured_block_errors (void) static bool gate_diagnose_omp_blocks (void) { - return flag_openmp || flag_enable_cilk; + return flag_openmp || flag_enable_cilkplus; } struct gimple_opt_pass pass_diagnose_omp_blocks =