Patchwork [gomp4] Some further little steps towards #pragma omp simd support

login
register
mail settings
Submitter Jakub Jelinek
Date April 23, 2013, 2:48 p.m.
Message ID <20130423144840.GP12880@tucnak.redhat.com>
Download mbox | patch
Permalink /patch/238933/
State New
Headers show

Comments

Jakub Jelinek - April 23, 2013, 2:48 p.m.
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  <jakub@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.


	Jakub

Patch

--- 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 ();
+}