Hi! This patch fixes handling of #pragma omp simd with pointer vars, or noreturn bodies, expands some aligned clauses into __builtin_assume_aligned (though, had to limit that to a few hopefully common cases so far, namely pointer automatic vars that aren't shared in outer context (because otherwise it can lead into ptr = ptr assignments) and array type global vars, not sure what to do about other aligned clauses, right now they are dropped on the floor). The patch also fixes a few ICEs and missed checks.
Tested on x86_64-linux, committed to gomp-4_0-branch. 2013-04-23 Jakub Jelinek <ja...@redhat.com> * 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. --- gcc/Makefile.in.jj 2013-03-20 10:08:27.000000000 +0100 +++ gcc/Makefile.in 2013-04-22 16:22:37.131008342 +0200 @@ -2535,7 +2535,7 @@ omp-low.o : omp-low.c $(CONFIG_H) $(SYST $(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 \ --- gcc/gimplify.c.jj 2013-04-19 14:51:38.000000000 +0200 +++ gcc/gimplify.c 2013-04-22 18:14:43.519471249 +0200 @@ -6473,24 +6473,28 @@ gimplify_adjust_omp_clauses (tree *list_ } 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_ { 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; --- gcc/omp-low.c.jj 2013-04-19 14:51:38.000000000 +0200 +++ gcc/omp-low.c 2013-04-23 15:05:29.763583104 +0200 @@ -42,6 +42,7 @@ along with GCC; see the file COPYING3. #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_ 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 ty } } +/* 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, g 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 } } +/* 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 *regi 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 *regi 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 *regi 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 *regi 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 *regi 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 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 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: --- gcc/cp/semantics.c.jj 2013-04-19 14:51:38.000000000 +0200 +++ gcc/cp/semantics.c 2013-04-23 15:19:27.529086777 +0200 @@ -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) --- gcc/testsuite/c-c++-common/gomp/simd3.c.jj 2013-04-23 14:36:42.839827496 +0200 +++ gcc/testsuite/c-c++-common/gomp/simd3.c 2013-04-22 19:41:58.000000000 +0200 @@ -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]]; +} --- gcc/testsuite/c-c++-common/gomp/simd4.c.jj 2013-04-23 14:40:26.431515790 +0200 +++ gcc/testsuite/c-c++-common/gomp/simd4.c 2013-04-23 14:44:17.550158780 +0200 @@ -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 } */ --- gcc/testsuite/c-c++-common/gomp/simd5.c.jj 2013-04-23 15:08:28.876696297 +0200 +++ gcc/testsuite/c-c++-common/gomp/simd5.c 2013-04-23 14:52:04.000000000 +0200 @@ -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 (); +} Jakub