diff mbox

[gomp4.5] Partial support for Fortran OpenMP doacross loops

Message ID 20160527152159.GH28550@tucnak.redhat.com
State New
Headers show

Commit Message

Jakub Jelinek May 27, 2016, 3:21 p.m. UTC
Hi!

I've committed the following patch to gomp-4_5-branch, which contains
initial version of doacross Fortran support.  No testcase yet,
as only simple loops (ones with constant 1 or -1 step) work right now,
for non-simple ones (variable step or non-1/-1 step) I'll need to add some
middle-end support, because for those we emit to the middle-end
a loop starting at 0 and with step 1 and thus need to adjust the
depend(sink:) expansion.

2016-05-27  Jakub Jelinek  <jakub@redhat.com>

	* gfortran.h (enum gfc_statement): Add ST_OMP_ORDERED_DEPEND.
	(enum gfc_omp_depend_op): Add OMP_DEPEND_SINK_FIRST and
	OMP_DEPEND_SINK.
	(struct gfc_omp_clauses): Add depend_source field.
	* parse.c (decode_omp_directive): If ordered directive has
	depend clause as the first of the clauses, use
	gfc_match_omp_ordered_depend and ST_OMP_ORDERED_DEPEND instead of
	gfc_match_omp_ordered and ST_OMP_ORDERED.
	(case_executable): Add ST_OMP_ORDERED_DEPEND case.
	(gfc_ascii_statement): Handle ST_OMP_ORDERED_DEPEND.
	* st.c (gfc_free_statement): Free omp clauses even for
	EXEC_OMP_ORDERED.
	* dump-parse-tree.c (show_omp_namelist): Handle OMP_DEPEND_SINK_FIRST
	depend_op.
	(show_omp_clauses): Handle depend_source.
	(show_omp_node): Print clauses for EXEC_OMP_ORDERED.  Allow NULL
	c->block for EXEC_OMP_ORDERED.
	* trans-openmp.c (gfc_trans_omp_clauses): Handle OMP_DEPEND_SINK_FIRST
	depend_op.  Handle orderedc and depend_source.
	(gfc_trans_omp_do): Set collapse to orderedc if non-zero.  Fill in
	OMP_FOR_ORIG_DECLS for doacross loops.
	(gfc_trans_omp_ordered): Translate omp clauses, allow NULL
	code->block.
	(gfc_split_omp_clauses): Copy orderedc together with ordered.
	* frontend-passes.c (gfc_code_walker): Handle EXEC_OMP_ORDERED.
	* openmp.c (gfc_match_omp_depend_sink): New function.
	(gfc_match_omp_clauses): Parse depend(source) and depend(sink: ...).
	(OMP_ORDERED_CLAUSES): Define.
	(gfc_match_omp_ordered): Parse clauses.
	(gfc_match_omp_ordered_depend): New function.
	(resolve_omp_clauses): Require orderedc >= collapse if specified.
	Handle depend(sink:) and depend(source) restrictions.  Disallow linear
	clause when orderedc is non-zero.
	(gfc_resolve_omp_do_blocks): Set omp_current_do_collapse to orderedc
	if non-zero.
	(resolve_omp_do): Set collapse to orderedc if non-zero.
	* match.h (gfc_match_omp_ordered_depend): New prototype.
	* match.c (match_exit_cycle): Rename collapse variable to count,
	set it to orderedc if non-zero, instead of collapse.


	Jakub
diff mbox

Patch

--- gcc/fortran/gfortran.h.jj	2016-05-23 17:20:09.000000000 +0200
+++ gcc/fortran/gfortran.h	2016-05-25 18:23:54.740764529 +0200
@@ -246,7 +246,7 @@  enum gfc_statement
   ST_OMP_TARGET_ENTER_DATA, ST_OMP_TARGET_EXIT_DATA,
   ST_OMP_TARGET_SIMD, ST_OMP_END_TARGET_SIMD,
   ST_OMP_TASKLOOP, ST_OMP_END_TASKLOOP,
-  ST_OMP_TASKLOOP_SIMD, ST_OMP_END_TASKLOOP_SIMD,
+  ST_OMP_TASKLOOP_SIMD, ST_OMP_END_TASKLOOP_SIMD, ST_OMP_ORDERED_DEPEND,
   ST_PROCEDURE, ST_GENERIC, ST_CRITICAL, ST_END_CRITICAL,
   ST_GET_FCN_CHARACTERISTICS, ST_LOCK, ST_UNLOCK, ST_EVENT_POST,
   ST_EVENT_WAIT,ST_NONE
@@ -1110,7 +1110,9 @@  enum gfc_omp_depend_op
 {
   OMP_DEPEND_IN,
   OMP_DEPEND_OUT,
-  OMP_DEPEND_INOUT
+  OMP_DEPEND_INOUT,
+  OMP_DEPEND_SINK_FIRST,
+  OMP_DEPEND_SINK
 };
 
 enum gfc_omp_map_op
@@ -1255,7 +1257,7 @@  typedef struct gfc_omp_clauses
   bool nowait, ordered, untied, mergeable;
   bool inbranch, notinbranch, defaultmap, nogroup;
   bool sched_simd, sched_monotonic, sched_nonmonotonic;
-  bool simd, threads;
+  bool simd, threads, depend_source;
   enum gfc_omp_cancel_kind cancel;
   enum gfc_omp_proc_bind_kind proc_bind;
   struct gfc_expr *safelen_expr;
--- gcc/fortran/parse.c.jj	2016-05-13 11:49:47.000000000 +0200
+++ gcc/fortran/parse.c	2016-05-25 16:06:33.694148119 +0200
@@ -831,7 +831,14 @@  decode_omp_directive (void)
       matcho ("master", gfc_match_omp_master, ST_OMP_MASTER);
       break;
     case 'o':
-      matcho ("ordered", gfc_match_omp_ordered, ST_OMP_ORDERED);
+      if (flag_openmp && gfc_match ("ordered depend (") == MATCH_YES)
+	{
+	  gfc_current_locus = old_locus;
+	  matcho ("ordered", gfc_match_omp_ordered_depend,
+		  ST_OMP_ORDERED_DEPEND);
+	}
+      else
+	matcho ("ordered", gfc_match_omp_ordered, ST_OMP_ORDERED);
       break;
     case 'p':
       matchs ("parallel do simd", gfc_match_omp_parallel_do_simd,
@@ -1373,7 +1380,8 @@  next_statement (void)
   case ST_OMP_BARRIER: case ST_OMP_TASKWAIT: case ST_OMP_TASKYIELD: \
   case ST_OMP_CANCEL: case ST_OMP_CANCELLATION_POINT: \
   case ST_OMP_TARGET_UPDATE: case ST_OMP_TARGET_ENTER_DATA: \
-  case ST_OMP_TARGET_EXIT_DATA: case ST_ERROR_STOP: case ST_SYNC_ALL: \
+  case ST_OMP_TARGET_EXIT_DATA: case ST_OMP_ORDERED_DEPEND: \
+  case ST_ERROR_STOP: case ST_SYNC_ALL: \
   case ST_SYNC_IMAGES: case ST_SYNC_MEMORY: case ST_LOCK: case ST_UNLOCK: \
   case ST_EVENT_POST: case ST_EVENT_WAIT: \
   case ST_OACC_UPDATE: case ST_OACC_WAIT: case ST_OACC_CACHE: \
@@ -2149,6 +2157,7 @@  gfc_ascii_statement (gfc_statement st)
       p = "!$OMP MASTER";
       break;
     case ST_OMP_ORDERED:
+    case ST_OMP_ORDERED_DEPEND:
       p = "!$OMP ORDERED";
       break;
     case ST_OMP_PARALLEL:
--- gcc/fortran/st.c.jj	2016-05-13 11:58:31.000000000 +0200
+++ gcc/fortran/st.c	2016-05-25 18:25:56.446163720 +0200
@@ -215,6 +215,7 @@  gfc_free_statement (gfc_code *p)
     case EXEC_OMP_DO:
     case EXEC_OMP_DO_SIMD:
     case EXEC_OMP_END_SINGLE:
+    case EXEC_OMP_ORDERED:
     case EXEC_OMP_PARALLEL:
     case EXEC_OMP_PARALLEL_DO:
     case EXEC_OMP_PARALLEL_DO_SIMD:
@@ -261,7 +262,6 @@  gfc_free_statement (gfc_code *p)
     case EXEC_OMP_ATOMIC:
     case EXEC_OMP_BARRIER:
     case EXEC_OMP_MASTER:
-    case EXEC_OMP_ORDERED:
     case EXEC_OMP_END_NOWAIT:
     case EXEC_OMP_TASKGROUP:
     case EXEC_OMP_TASKWAIT:
--- gcc/fortran/dump-parse-tree.c.jj	2016-05-23 17:57:14.000000000 +0200
+++ gcc/fortran/dump-parse-tree.c	2016-05-27 11:14:20.507763580 +0200
@@ -1050,6 +1050,27 @@  show_omp_namelist (int list_type, gfc_om
 	  case OMP_DEPEND_IN: fputs ("in:", dumpfile); break;
 	  case OMP_DEPEND_OUT: fputs ("out:", dumpfile); break;
 	  case OMP_DEPEND_INOUT: fputs ("inout:", dumpfile); break;
+	  case OMP_DEPEND_SINK_FIRST:
+	    fputs ("sink:", dumpfile);
+	    while (1)
+	      {
+		fprintf (dumpfile, "%s", n->sym->name);
+		if (n->expr)
+		  {
+		    fputc ('+', dumpfile);
+		    show_expr (n->expr);
+		  }
+		if (n->next == NULL)
+		  break;
+		else if (n->next->u.depend_op != OMP_DEPEND_SINK)
+		  {
+		    fputs (") DEPEND(", dumpfile);
+		    break;
+		  }
+		fputc (',', dumpfile);
+		n = n->next;
+	      }
+	    continue;
 	  default: break;
 	  }
       else if (list_type == OMP_LIST_MAP)
@@ -1423,6 +1444,8 @@  show_omp_clauses (gfc_omp_clauses *omp_c
       show_expr (omp_clauses->if_exprs[i]);
       fputc (')', dumpfile);
     }
+  if (omp_clauses->depend_source)
+    fputs (" DEPEND(source)", dumpfile);
 }
 
 /* Show a single OpenMP or OpenACC directive node and everything underneath it
@@ -1533,6 +1556,7 @@  show_omp_node (int level, gfc_code *c)
     case EXEC_OMP_DISTRIBUTE_SIMD:
     case EXEC_OMP_DO:
     case EXEC_OMP_DO_SIMD:
+    case EXEC_OMP_ORDERED:
     case EXEC_OMP_PARALLEL:
     case EXEC_OMP_PARALLEL_DO:
     case EXEC_OMP_PARALLEL_DO_SIMD:
@@ -1594,7 +1618,8 @@  show_omp_node (int level, gfc_code *c)
   if (c->op == EXEC_OACC_CACHE || c->op == EXEC_OACC_UPDATE
       || c->op == EXEC_OACC_ENTER_DATA || c->op == EXEC_OACC_EXIT_DATA
       || c->op == EXEC_OMP_TARGET_UPDATE || c->op == EXEC_OMP_TARGET_ENTER_DATA
-      || c->op == EXEC_OMP_TARGET_EXIT_DATA)
+      || c->op == EXEC_OMP_TARGET_EXIT_DATA
+      || (c->op == EXEC_OMP_ORDERED && c->block == NULL))
     return;
   if (c->op == EXEC_OMP_SECTIONS || c->op == EXEC_OMP_PARALLEL_SECTIONS)
     {
--- gcc/fortran/trans-openmp.c.jj	2016-05-24 19:07:23.000000000 +0200
+++ gcc/fortran/trans-openmp.c	2016-05-27 11:45:55.654240826 +0200
@@ -1927,6 +1927,47 @@  gfc_trans_omp_clauses (stmtblock_t *bloc
 	case OMP_LIST_DEPEND:
 	  for (; n != NULL; n = n->next)
 	    {
+	      if (n->u.depend_op == OMP_DEPEND_SINK_FIRST)
+		{
+		  tree vec = NULL_TREE;
+		  while (1)
+		    {
+		      tree addend = integer_zero_node, t;
+		      bool neg = false;
+		      if (n->expr)
+			{
+			  addend = gfc_conv_constant_to_tree (n->expr);
+			  if (TREE_CODE (addend) == INTEGER_CST
+			      && tree_int_cst_sgn (addend) == -1)
+			    {
+			      neg = true;
+			      addend = const_unop (NEGATE_EXPR,
+						   TREE_TYPE (addend), addend);
+			    }
+			}
+		      t = gfc_trans_omp_variable (n->sym, false);
+		      if (t != error_mark_node)
+			{
+			  vec = tree_cons (addend, t, vec);
+			  if (neg)
+			    OMP_CLAUSE_DEPEND_SINK_NEGATIVE (vec) = 1;
+			}
+		      if (n->next == NULL
+			  || n->next->u.depend_op != OMP_DEPEND_SINK)
+			break;
+		      n = n->next;
+		    }
+		  if (vec == NULL_TREE)
+		    continue;
+
+		  tree node = build_omp_clause (input_location,
+						OMP_CLAUSE_DEPEND);
+		  OMP_CLAUSE_DEPEND_KIND (node) = OMP_CLAUSE_DEPEND_SINK;
+		  OMP_CLAUSE_DECL (node) = nreverse (vec);
+		  omp_clauses = gfc_trans_add_clause (node, omp_clauses);
+		  continue;
+		}
+
 	      if (!n->sym->attr.referenced)
 		continue;
 
@@ -2490,7 +2531,9 @@  gfc_trans_omp_clauses (stmtblock_t *bloc
   if (clauses->ordered)
     {
       c = build_omp_clause (where.lb->location, OMP_CLAUSE_ORDERED);
-      OMP_CLAUSE_ORDERED_EXPR (c) = NULL_TREE;
+      OMP_CLAUSE_ORDERED_EXPR (c)
+	= clauses->orderedc ? build_int_cst (integer_type_node,
+					     clauses->orderedc) : NULL_TREE;
       omp_clauses = gfc_trans_add_clause (c, omp_clauses);
     }
 
@@ -2750,6 +2793,12 @@  gfc_trans_omp_clauses (stmtblock_t *bloc
       c = build_omp_clause (where.lb->location, OMP_CLAUSE_DEFAULTMAP);
       omp_clauses = gfc_trans_add_clause (c, omp_clauses);
     }
+  if (clauses->depend_source)
+    {
+      c = build_omp_clause (where.lb->location, OMP_CLAUSE_DEPEND);
+      OMP_CLAUSE_DEPEND_KIND (c) = OMP_CLAUSE_DEPEND_SOURCE;
+      omp_clauses = gfc_trans_add_clause (c, omp_clauses);
+    }
 
   if (clauses->async)
     {
@@ -3373,7 +3422,7 @@  gfc_trans_omp_do (gfc_code *code, gfc_ex
 		  gfc_omp_clauses *do_clauses, tree par_clauses)
 {
   gfc_se se;
-  tree dovar, stmt, from, to, step, type, init, cond, incr;
+  tree dovar, stmt, from, to, step, type, init, cond, incr, orig_decls;
   tree count = NULL_TREE, cycle_label, tmp, omp_clauses;
   stmtblock_t block;
   stmtblock_t body;
@@ -3383,6 +3432,8 @@  gfc_trans_omp_do (gfc_code *code, gfc_ex
   dovar_init *di;
   unsigned ix;
 
+  if (clauses->orderedc)
+    collapse = clauses->orderedc;
   if (collapse <= 0)
     collapse = 1;
 
@@ -3392,6 +3443,7 @@  gfc_trans_omp_do (gfc_code *code, gfc_ex
   init = make_tree_vec (collapse);
   cond = make_tree_vec (collapse);
   incr = make_tree_vec (collapse);
+  orig_decls = clauses->orderedc ? make_tree_vec (collapse) : NULL_TREE;
 
   if (pblock == NULL)
     {
@@ -3517,6 +3569,8 @@  gfc_trans_omp_do (gfc_code *code, gfc_ex
 	  dovar_init e = {dovar, tmp};
 	  inits.safe_push (e);
 	}
+      if (orig_decls)
+	TREE_VEC_ELT (orig_decls, i) = dovar_decl;
 
       if (dovar_found == 2
 	  && op == EXEC_OMP_SIMD
@@ -3670,6 +3724,8 @@  gfc_trans_omp_do (gfc_code *code, gfc_ex
   OMP_FOR_INIT (stmt) = init;
   OMP_FOR_COND (stmt) = cond;
   OMP_FOR_INCR (stmt) = incr;
+  if (orig_decls)
+    OMP_FOR_ORIG_DECLS (stmt) = orig_decls;
   gfc_add_expr_to_block (&block, stmt);
 
   return gfc_finish_block (&block);
@@ -3773,8 +3829,11 @@  gfc_trans_omp_master (gfc_code *code)
 static tree
 gfc_trans_omp_ordered (gfc_code *code)
 {
+  tree omp_clauses = gfc_trans_omp_clauses (NULL, code->ext.omp_clauses,
+					    code->loc);
   return build2_loc (input_location, OMP_ORDERED, void_type_node,
-		     gfc_trans_code (code->block->next), NULL_TREE);
+		     code->block ? gfc_trans_code (code->block->next)
+		     : NULL_TREE, omp_clauses);
 }
 
 static tree
@@ -4011,6 +4070,8 @@  gfc_split_omp_clauses (gfc_code *code,
 	  /* First the clauses that are unique to some constructs.  */
 	  clausesa[GFC_OMP_SPLIT_DO].ordered
 	    = code->ext.omp_clauses->ordered;
+	  clausesa[GFC_OMP_SPLIT_DO].orderedc
+	    = code->ext.omp_clauses->orderedc;
 	  clausesa[GFC_OMP_SPLIT_DO].sched_kind
 	    = code->ext.omp_clauses->sched_kind;
 	  if (innermost == GFC_OMP_SPLIT_SIMD)
--- gcc/fortran/frontend-passes.c.jj	2016-05-13 11:51:54.000000000 +0200
+++ gcc/fortran/frontend-passes.c	2016-05-25 18:23:36.081009964 +0200
@@ -3593,6 +3593,7 @@  gfc_code_walker (gfc_code **c, walk_code
 	    case EXEC_OMP_DISTRIBUTE_SIMD:
 	    case EXEC_OMP_DO:
 	    case EXEC_OMP_DO_SIMD:
+	    case EXEC_OMP_ORDERED:
 	    case EXEC_OMP_SECTIONS:
 	    case EXEC_OMP_SINGLE:
 	    case EXEC_OMP_END_SINGLE:
--- gcc/fortran/openmp.c.jj	2016-05-24 17:40:34.000000000 +0200
+++ gcc/fortran/openmp.c	2016-05-26 10:53:06.598921074 +0200
@@ -340,6 +340,80 @@  cleanup:
   return MATCH_ERROR;
 }
 
+/* Match depend(sink : ...) construct a namelist from it.  */
+
+static match
+gfc_match_omp_depend_sink (gfc_omp_namelist **list)
+{
+  gfc_omp_namelist *head, *tail, *p;
+  locus old_loc, cur_loc;
+  gfc_symbol *sym;
+
+  head = tail = NULL;
+
+  old_loc = gfc_current_locus;
+
+  for (;;)
+    {
+      cur_loc = gfc_current_locus;
+      switch (gfc_match_symbol (&sym, 1))
+	{
+	case MATCH_YES:
+	  gfc_set_sym_referenced (sym);
+	  p = gfc_get_omp_namelist ();
+	  if (head == NULL)
+	    {
+	      head = tail = p;
+	      head->u.depend_op = OMP_DEPEND_SINK_FIRST;
+	    }
+	  else
+	    {
+	      tail->next = p;
+	      tail = tail->next;
+	      tail->u.depend_op = OMP_DEPEND_SINK;
+	    }
+	  tail->sym = sym;
+	  tail->expr = NULL;
+	  tail->where = cur_loc;
+	  if (gfc_match_char ('+') == MATCH_YES)
+	    {
+	      if (gfc_match_literal_constant (&tail->expr, 0) != MATCH_YES)
+		goto syntax;
+	    }
+	  else if (gfc_match_char ('-') == MATCH_YES)
+	    {
+	      if (gfc_match_literal_constant (&tail->expr, 0) != MATCH_YES)
+		goto syntax;
+	      tail->expr = gfc_uminus (tail->expr);
+	    }
+	  break;
+	case MATCH_NO:
+	  goto syntax;
+	case MATCH_ERROR:
+	  goto cleanup;
+	}
+
+      if (gfc_match_char (')') == MATCH_YES)
+	break;
+      if (gfc_match_char (',') != MATCH_YES)
+	goto syntax;
+    }
+
+  while (*list)
+    list = &(*list)->next;
+
+  *list = head;
+  return MATCH_YES;
+
+syntax:
+  gfc_error ("Syntax error in OpenMP DEPEND SINK list at %C");
+
+cleanup:
+  gfc_free_omp_namelist (head);
+  gfc_current_locus = old_loc;
+  return MATCH_ERROR;
+}
+
 static match
 match_oacc_expr_list (const char *str, gfc_expr_list **list,
 		      bool allow_asterisk)
@@ -923,6 +997,19 @@  gfc_match_omp_clauses (gfc_omp_clauses *
 		depend_op = OMP_DEPEND_IN;
 	      else if (gfc_match ("out") == MATCH_YES)
 		depend_op = OMP_DEPEND_OUT;
+	      else if (!c->depend_source
+		       && gfc_match ("source )") == MATCH_YES)
+		{
+		  c->depend_source = true;
+		  continue;
+		}
+	      else if (gfc_match ("sink : ") == MATCH_YES)
+		{
+		  if (gfc_match_omp_depend_sink (&c->lists[OMP_LIST_DEPEND])
+		      == MATCH_YES)
+		    continue;
+		  m = MATCH_NO;
+		}
 	      else
 		m = MATCH_NO;
 	      head = NULL;
@@ -2235,6 +2322,8 @@  cleanup:
    | OMP_CLAUSE_COLLAPSE | OMP_CLAUSE_DIST_SCHEDULE)
 #define OMP_SINGLE_CLAUSES \
   (omp_mask (OMP_CLAUSE_PRIVATE) | OMP_CLAUSE_FIRSTPRIVATE)
+#define OMP_ORDERED_CLAUSES \
+  (omp_mask (OMP_CLAUSE_THREADS) | OMP_CLAUSE_SIMD)
 
 
 static match
@@ -3252,14 +3341,14 @@  gfc_match_omp_master (void)
 match
 gfc_match_omp_ordered (void)
 {
-  if (gfc_match_omp_eos () != MATCH_YES)
-    {
-      gfc_error ("Unexpected junk after $OMP ORDERED statement at %C");
-      return MATCH_ERROR;
-    }
-  new_st.op = EXEC_OMP_ORDERED;
-  new_st.ext.omp_clauses = NULL;
-  return MATCH_YES;
+  return match_omp (EXEC_OMP_ORDERED, OMP_ORDERED_CLAUSES);
+}
+
+
+match
+gfc_match_omp_ordered_depend (void)
+{
+  return match_omp (EXEC_OMP_ORDERED, omp_mask (OMP_CLAUSE_DEPEND));
 }
 
 
@@ -3691,6 +3780,10 @@  resolve_omp_clauses (gfc_code *code, gfc
   if (omp_clauses == NULL)
     return;
 
+  if (omp_clauses->orderedc && omp_clauses->orderedc < omp_clauses->collapse)
+    gfc_error ("ORDERED clause parameter is less than COLLAPSE at %L",
+	       &code->loc);
+
   if (omp_clauses->if_expr)
     {
       gfc_expr *expr = omp_clauses->if_expr;
@@ -4035,6 +4128,36 @@  resolve_omp_clauses (gfc_code *code, gfc
 	  case OMP_LIST_CACHE:
 	    for (; n != NULL; n = n->next)
 	      {
+		if (list == OMP_LIST_DEPEND)
+		  {
+		    if (n->u.depend_op == OMP_DEPEND_SINK_FIRST
+			|| n->u.depend_op == OMP_DEPEND_SINK)
+		      {
+			if (code->op != EXEC_OMP_ORDERED)
+			  gfc_error ("SINK dependence type only allowed "
+				     "on ORDERED directive at %L", &n->where);
+			else if (omp_clauses->depend_source)
+			  {
+			    gfc_error ("DEPEND SINK used together with "
+				       "DEPEND SOURCE on the same construct "
+				       "at %L", &n->where);
+			    omp_clauses->depend_source = false;
+			  }
+			else if (n->expr)
+			  {
+			    if (!gfc_resolve_expr (n->expr)
+				|| n->expr->ts.type != BT_INTEGER
+				|| n->expr->rank != 0)
+			      gfc_error ("SINK addend not a constant integer"
+					 "at %L", &n->where);
+			  }
+			continue;
+		      }
+		    else if (code->op == EXEC_OMP_ORDERED)
+		      gfc_error ("Only SOURCE or SINK dependence types "
+				 "are allowed on ORDERED directive at %L",
+				 &n->where);
+		  }
 		if (n->expr)
 		  {
 		    if (!gfc_resolve_expr (n->expr)
@@ -4274,6 +4397,10 @@  resolve_omp_clauses (gfc_code *code, gfc
 				   " construct at %L", &n->where);
 			linear_op = n->u.linear_op;
 		      }
+		    else if (omp_clauses->orderedc)
+		      gfc_error ("LINEAR clause specified together with"
+				 "ORDERED clause with argument at %L",
+				 &n->where);
 		    else if (n->u.linear_op != OMP_LINEAR_REF
 			     && n->sym->ts.type != BT_INTEGER)
 		      gfc_error ("LINEAR variable %qs must be INTEGER "
@@ -4399,6 +4526,9 @@  resolve_omp_clauses (gfc_code *code, gfc
     if (omp_clauses->wait_list)
       for (el = omp_clauses->wait_list; el; el = el->next)
 	resolve_scalar_int_expr (el->expr, "WAIT");
+  if (omp_clauses->depend_source && code->op != EXEC_OMP_ORDERED)
+    gfc_error ("SOURCE dependence type only allowed "
+	       "on ORDERED directive at %L", &code->loc);
 }
 
 
@@ -4880,7 +5010,10 @@  gfc_resolve_omp_do_blocks (gfc_code *cod
       gfc_code *c;
 
       omp_current_do_code = code->block->next;
-      omp_current_do_collapse = code->ext.omp_clauses->collapse;
+      if (code->ext.omp_clauses->orderedc)
+	omp_current_do_collapse = code->ext.omp_clauses->orderedc;
+      else
+	omp_current_do_collapse = code->ext.omp_clauses->collapse;
       for (i = 1, c = omp_current_do_code; i < omp_current_do_collapse; i++)
 	{
 	  c = c->block;
@@ -5108,9 +5241,14 @@  resolve_omp_do (gfc_code *code)
     resolve_omp_clauses (code, code->ext.omp_clauses, NULL);
 
   do_code = code->block->next;
-  collapse = code->ext.omp_clauses->collapse;
-  if (collapse <= 0)
-    collapse = 1;
+  if (code->ext.omp_clauses->orderedc)
+    collapse = code->ext.omp_clauses->orderedc;
+  else
+    {
+      collapse = code->ext.omp_clauses->collapse;
+      if (collapse <= 0)
+	collapse = 1;
+    }
   for (i = 1; i <= collapse; i++)
     {
       if (do_code->op == EXEC_DO_WHILE)
--- gcc/fortran/match.h.jj	2016-05-13 10:56:57.000000000 +0200
+++ gcc/fortran/match.h	2016-05-25 18:25:31.697489243 +0200
@@ -161,6 +161,7 @@  match gfc_match_omp_do_simd (void);
 match gfc_match_omp_flush (void);
 match gfc_match_omp_master (void);
 match gfc_match_omp_ordered (void);
+match gfc_match_omp_ordered_depend (void);
 match gfc_match_omp_parallel (void);
 match gfc_match_omp_parallel_do (void);
 match gfc_match_omp_parallel_do_simd (void);
--- gcc/fortran/match.c.jj	2016-05-04 18:37:34.000000000 +0200
+++ gcc/fortran/match.c	2016-05-25 17:46:29.413643217 +0200
@@ -2554,21 +2554,25 @@  match_exit_cycle (gfc_statement st, gfc_
 	  || o->head->op == EXEC_OMP_DO_SIMD
 	  || o->head->op == EXEC_OMP_PARALLEL_DO_SIMD))
     {
-      int collapse = 1;
+      int count = 1;
       gcc_assert (o->head->next != NULL
 		  && (o->head->next->op == EXEC_DO
 		      || o->head->next->op == EXEC_DO_WHILE)
 		  && o->previous != NULL
 		  && o->previous->tail->op == o->head->op);
-      if (o->previous->tail->ext.omp_clauses != NULL
-	  && o->previous->tail->ext.omp_clauses->collapse > 1)
-	collapse = o->previous->tail->ext.omp_clauses->collapse;
-      if (st == ST_EXIT && cnt <= collapse)
+      if (o->previous->tail->ext.omp_clauses != NULL)
+	{
+	  if (o->previous->tail->ext.omp_clauses->collapse > 1)
+	    count = o->previous->tail->ext.omp_clauses->collapse;
+	  if (o->previous->tail->ext.omp_clauses->orderedc)
+	    count = o->previous->tail->ext.omp_clauses->orderedc;
+	}
+      if (st == ST_EXIT && cnt <= count)
 	{
 	  gfc_error ("EXIT statement at %C terminating !$OMP DO loop");
 	  return MATCH_ERROR;
 	}
-      if (st == ST_CYCLE && cnt < collapse)
+      if (st == ST_CYCLE && cnt < count)
 	{
 	  gfc_error ("CYCLE statement at %C to non-innermost collapsed"
 		     " !$OMP DO loop");