This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[gomp] Handle 'if' and 'num_threads' clauses
- From: Diego Novillo <dnovillo at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Fri, 23 Sep 2005 01:58:29 -0400
- Subject: [gomp] Handle 'if' and 'num_threads' clauses
Adds handling for 'if' and 'num_threads' and some basic error
checking. The new test in gcc.dg/gomp should start passing once
rth fixes the DEFAULT_CFLAGS problem.
* c-parser.c (c_parser_pragma_omp_clause): Fix dangling if().
(c_parser_pragma_omp_clause_if): Remove printf.
Check that only one clause 'if' is specified.
Call add_new_clause.
(c_parser_pragma_omp_clause_num_threads): Remove printf.
Check that only one clause 'num_threads' is specified.
Call add_new_clause.
* gimple-low.c (emit_num_threads_setup_code): New.
(lower_gomp_parallel): Call it.
Add new argument DATA. Modify all callers.
* tree-pretty-print.c (dump_generic_node): Handle
GOMP_CLAUSE_IF and GOMP_CLAUSE_NUM_THREADS.
* tree.def (GOMP_CLAUSE_IF, GOMP_CLAUSE_NUM_THREADS): Define.
* tree.h (GOMP_IF_EXPR, GOMP_NUM_THREADS_EXPR): Define.
testsuite/
* gcc.dg/gomp/omp-parallel-if.c: New test.
libgomp/
* testsuite/libgomp.dg/omp-parallel-if.c: New test.
Index: gcc/c-parser.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-parser.c,v
retrieving revision 2.17.4.13
diff -d -u -p -r2.17.4.13 c-parser.c
--- gcc/c-parser.c 23 Sep 2005 04:32:19 -0000 2.17.4.13
+++ gcc/c-parser.c 23 Sep 2005 05:32:26 -0000
@@ -6801,7 +6801,7 @@ c_parser_pragma_omp_clause (c_parser *pa
{
result = PRAGMA_OMP_CLAUSE_IF;
}
- if (c_parser_next_token_is_keyword (parser, RID_DEFAULT))
+ else if (c_parser_next_token_is_keyword (parser, RID_DEFAULT))
{
result = PRAGMA_OMP_CLAUSE_DEFAULT;
}
@@ -6992,13 +6992,18 @@ c_parser_pragma_omp_clause_firstprivate
static void
c_parser_pragma_omp_clause_if (c_parser *parser)
{
- printf ("if: ");
-
if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
{
tree t = c_parser_paren_condition (parser);
- print_generic_expr (stdout, t, 0);
- printf ("\n");
+ tree c;
+
+ /* At most one 'if' clause may appear in the directive. */
+ for (c = curr_clause_set; c; c = TREE_CHAIN (c))
+ if (TREE_CODE (TREE_VALUE (c)) == GOMP_CLAUSE_IF)
+ error ("at most one %<if%> clause may appear in a parallel "
+ "directive");
+
+ add_new_clause (build (GOMP_CLAUSE_IF, NULL_TREE, t));
}
else
{
@@ -7035,23 +7040,27 @@ c_parser_pragma_omp_clause_nowait (c_par
static void
c_parser_pragma_omp_clause_num_threads (c_parser *parser)
{
- printf ("num_threads: ");
-
if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
{
tree t = c_parser_expression (parser).value;
- if (TREE_CODE (TREE_TYPE (t)) == INTEGER_TYPE)
- {
- print_generic_expr (stdout, t, 0);
- }
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (t)))
+ c_parser_error (parser, "expected integer expression");
else
{
- c_parser_error (parser, "expected integer expression");
+ tree c;
+
+ /* At most one 'num_threads' clause may appear in the directive. */
+ for (c = curr_clause_set; c; c = TREE_CHAIN (c))
+ if (TREE_CODE (TREE_VALUE (c)) == GOMP_CLAUSE_NUM_THREADS)
+ error ("at most one %<num_threads%> clause may appear "
+ "in a parallel directive");
+
+ add_new_clause (build (GOMP_CLAUSE_NUM_THREADS, TREE_TYPE (t), t));
}
+
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
}
- printf ("\n");
}
/* OpenMP 2.5:
Index: gcc/gimple-low.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/gimple-low.c,v
retrieving revision 2.24.4.9
diff -d -u -p -r2.24.4.9 gimple-low.c
--- gcc/gimple-low.c 22 Sep 2005 14:30:48 -0000 2.24.4.9
+++ gcc/gimple-low.c 23 Sep 2005 05:32:26 -0000
@@ -683,12 +683,98 @@ emit_gomp_data_setup_code (tree_stmt_ite
}
+/* Static emit code to specify the number of threads to use in the
+ runtime.
+
+ TSI points to where the code should be emitted.
+
+ RI_P points to the remap structure holding clause information.
+
+ DATA points to GIMPLE lowering information.
+
+ Returns the argument that should be passed to GOMP_parallel_start. */
+
+static tree
+emit_num_threads_setup_code (tree_stmt_iterator *tsi, struct remap_info_d *ri_p,
+ struct lower_data *data)
+{
+ tree val, cond, c;
+ tree clauses = ri_p->clauses;
+
+ /* By default, the value of NUM_THREADS is zero (selected at run
+ time) and there is no conditional. */
+ cond = NULL_TREE;
+ val = integer_zero_node;
+
+ for (c = clauses; c; c = TREE_CHAIN (c))
+ {
+ tree clause = TREE_VALUE (c);
+
+ if (TREE_CODE (clause) == GOMP_CLAUSE_IF)
+ cond = GOMP_IF_EXPR (clause);
+ else if (TREE_CODE (clause) == GOMP_CLAUSE_NUM_THREADS)
+ val = GOMP_NUM_THREADS_EXPR (clause);
+ }
+
+ /* If we found either of 'if (expr)' or 'num_threads (expr)',
+ create a local variable and prepare a list of statements to be
+ inserted. */
+ if (cond || val != integer_zero_node)
+ {
+ tree t;
+ tree num_threads = create_tmp_var (unsigned_type_node, ".num_threads");
+ tree stmt_list = alloc_stmt_list ();
+
+ if (cond)
+ {
+ /* If we found the clause 'if (cond)', build the
+ conditional:
+
+ if (cond)
+ .num_threads = val
+ else
+ .num_threads = 1 */
+ t = build (COND_EXPR, void_type_node, cond,
+ build (MODIFY_EXPR, void_type_node, num_threads, val),
+ build (MODIFY_EXPR, void_type_node, num_threads,
+ integer_one_node));
+ append_to_statement_list (t, &stmt_list);
+ }
+ else
+ {
+ gcc_assert (val != integer_zero_node);
+
+ /* Otherwise, if we found a num_threads clause with anything
+ other than zero, assign that value to .num_threads:
+ .num_threads = val */
+ t = build (MODIFY_EXPR, unsigned_type_node, num_threads, val);
+ append_to_statement_list (t, &stmt_list);
+ }
+
+ /* Gimplify and lower the emitted code. This is necessary
+ mostly for COND and VAL, which can be arbitrary expressions. */
+ push_gimplify_context ();
+ gimplify_stmt (&stmt_list);
+ pop_gimplify_context (NULL);
+ lower_stmt_body (stmt_list, data);
+
+ tsi_link_after (tsi, stmt_list, TSI_CONTINUE_LINKING);
+
+ return num_threads;
+ }
+
+ /* Otherwise, just return zero to specify that the number of threads
+ should be selected at runtime. */
+ return integer_zero_node;
+}
+
+
/* Lower the OpenMP parallel directive pointed by TSI. Build a new
function with the body of the pragma and emit the appropriate
runtime call. DATA contains locus and scope information for TSI. */
static void
-lower_gomp_parallel (tree_stmt_iterator *tsi)
+lower_gomp_parallel (tree_stmt_iterator *tsi, struct lower_data *data)
{
tree par_stmt, fn, call, args, num_threads, addr_data_arg;
tree_stmt_iterator orig_tsi;
@@ -738,10 +824,12 @@ lower_gomp_parallel (tree_stmt_iterator
else
addr_data_arg = null_pointer_node;
- /* Emit GOMP_parallel_start (__gomp_fn.XXXX ...) to PRE_P. FIXME,
- num_threads should only be integer_zero_node if the clause
- num_threads is not present. */
- num_threads = integer_zero_node;
+ /* Emit code to set up the number of threads to use according to the
+ IF and NUM_THREADS clauses. If both are missing, set it to 0 so
+ that it is dynamically selected by the runtime. */
+ num_threads = emit_num_threads_setup_code (tsi, ri_p, data);
+
+ /* Emit GOMP_parallel_start (__gomp_fn.XXXX ...). */
call = create_gomp_parallel_start (fn, addr_data_arg, num_threads);
tsi_link_after (tsi, call, TSI_CONTINUE_LINKING);
@@ -1062,7 +1150,7 @@ lower_stmt (tree_stmt_iterator *tsi, str
break;
case GOMP_PARALLEL:
- lower_gomp_parallel (tsi);
+ lower_gomp_parallel (tsi, data);
break;
case GOMP_FOR:
Index: tree-pretty-print.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-pretty-print.c,v
retrieving revision 2.61.4.6
diff -d -u -p -r2.61.4.6 tree-pretty-print.c
--- tree-pretty-print.c 20 Sep 2005 21:19:24 -0000 2.61.4.6
+++ tree-pretty-print.c 23 Sep 2005 05:51:58 -0000
@@ -1598,6 +1598,19 @@ dump_generic_node (pretty_printer *buffe
pp_string (buffer, ")");
break;
+ case GOMP_CLAUSE_IF:
+ pp_string (buffer, "if (");
+ dump_generic_node (buffer, GOMP_IF_EXPR (node), spc, flags, false);
+ pp_string (buffer, ")");
+ break;
+
+ case GOMP_CLAUSE_NUM_THREADS:
+ pp_string (buffer, "num_threads (");
+ dump_generic_node (buffer, GOMP_NUM_THREADS_EXPR (node), spc, flags,
+ false);
+ pp_string (buffer, ")");
+ break;
+
case REDUC_MAX_EXPR:
pp_string (buffer, " REDUC_MAX_EXPR < ");
dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false);
Index: gcc/tree.def
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.def,v
retrieving revision 1.116.4.7
diff -d -u -p -r1.116.4.7 tree.def
--- gcc/tree.def 20 Sep 2005 21:19:25 -0000 1.116.4.7
+++ gcc/tree.def 23 Sep 2005 05:32:27 -0000
@@ -1021,6 +1021,12 @@ DEFTREECODE (GOMP_CLAUSE_COPYIN, "copyin
/* OpenMP clause: copyprivate (variable_list). */
DEFTREECODE (GOMP_CLAUSE_COPYPRIVATE, "copyprivate", tcc_expression, 1)
+/* OpenMP clause: if (scalar-expression). */
+DEFTREECODE (GOMP_CLAUSE_IF, "if", tcc_expression, 1)
+
+/* OpenMP clause: num_threads (integer-expression). */
+DEFTREECODE (GOMP_CLAUSE_NUM_THREADS, "num_threads", tcc_expression, 1)
+
/* Reduction operations.
Operations that take a vector of elements and "reduce" it to a scalar
result (e.g. summing the elements of the vector, finding the minimum over
Index: gcc/tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.h,v
retrieving revision 1.735.4.8
diff -d -u -p -r1.735.4.8 tree.h
--- gcc/tree.h 22 Sep 2005 14:30:49 -0000 1.735.4.8
+++ gcc/tree.h 23 Sep 2005 05:32:27 -0000
@@ -1412,6 +1412,10 @@ struct tree_constructor GTY(())
TREE_OPERAND (GOMP_CLAUSE_COPYIN_CHECK (NODE), 0)
#define GOMP_COPYPRIVATE_VARS(NODE) \
TREE_OPERAND (GOMP_CLAUSE_COPYPRIVATE_CHECK (NODE), 0)
+#define GOMP_IF_EXPR(NODE) \
+ TREE_OPERAND (GOMP_CLAUSE_IF_CHECK (NODE), 0)
+#define GOMP_NUM_THREADS_EXPR(NODE) \
+ TREE_OPERAND (GOMP_CLAUSE_NUM_THREADS_CHECK (NODE), 0)
struct tree_exp GTY(())
Index: gcc/testsuite/gcc.dg/gomp/omp-parallel-if.c
===================================================================
RCS file: gcc/testsuite/gcc.dg/gomp/omp-parallel-if.c
diff -N gcc/testsuite/gcc.dg/gomp/omp-parallel-if.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gcc/testsuite/gcc.dg/gomp/omp-parallel-if.c 23 Sep 2005 05:32:30 -0000
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+
+#include <omp.h>
+
+int
+foo (void)
+{
+ return 10;
+}
+
+main ()
+{
+ int A = 0;
+
+ /* Malformed uses of 'if' and 'num_threads'. */
+ #pragma omp parallel if (foo () > 10) shared (A) if (foo () == 3) /* { dg-error "at most one 'if'" } */
+ {
+ A = omp_get_num_threads ();
+ }
+
+ #pragma omp parallel if (foo () == 10) num_threads (3) shared (A) num_threads (20) /* { dg-error "at most one 'num_threads'" } */
+ {
+ A = omp_get_num_threads ();
+ }
+
+ /* Valid uses of 'if' and 'num_threads'. */
+ #pragma omp parallel if (foo () == 10) num_threads (foo ()) shared (A)
+ {
+ A = omp_get_num_threads ();
+ }
+}
Index: libgomp/testsuite/libgomp.dg/omp-parallel-if.c
===================================================================
RCS file: libgomp/testsuite/libgomp.dg/omp-parallel-if.c
diff -N libgomp/testsuite/libgomp.dg/omp-parallel-if.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libgomp/testsuite/libgomp.dg/omp-parallel-if.c 23 Sep 2005 05:32:30 -0000
@@ -0,0 +1,40 @@
+#include <omp.h>
+
+extern void abort (void);
+
+int
+foo (void)
+{
+ return 10;
+}
+
+main ()
+{
+ int A = 0;
+
+ #pragma omp parallel if (foo () > 10) shared (A)
+ {
+ A = omp_get_num_threads ();
+ }
+
+ if (A != 1)
+ abort ();
+
+ #pragma omp parallel if (foo () == 10) num_threads (3) shared (A)
+ {
+ A = omp_get_num_threads ();
+ }
+
+ if (A != 3)
+ abort ();
+
+ #pragma omp parallel if (foo () == 10) num_threads (foo ()) shared (A)
+ {
+ A = omp_get_num_threads ();
+ }
+
+ if (A != 10)
+ abort ();
+
+ return 0;
+}