diff mbox

[C,C++,OpenMP] Add support for -fopenmp-simd

Message ID 526D8995.8060203@net-b.de
State New
Headers show

Commit Message

Tobias Burnus Oct. 27, 2013, 9:45 p.m. UTC
This patch add the new option "-fopenmp-simd", which allows to use 
OpenMP 4.0's "simd" pragmas without enabling OpenMP's threading or 
target features - and, thus, it also doesn't require linking of libgomp.

The purpose is to permit a fine-tuning of vectorization without adding 
the additional library dependency and makes it easier to compile a code 
to a single-thread program, which additionally uses OpenMP for 
thread/target parallelization. Looking at other compilers, also the 
Intel compiler has such a flag (-openmp-simd).

The code is written such that when "-fopenmp" is used, 
-f(no-)openmp-simd has no effect. The following "simd" pragmas are 
listed in OpenMP 4.0 - and will all get translated into "#pragma omp 
simd", only, with -fopenmp-simd:
#pragma omp simd
#pragma omp for simd
#pragma omp distribute simd
#pragma omp distribute parallel for simd
#pragma omp parallel for simd
#pragma omp teams distribute simd
#pragma omp target teams distribute simd
#pragma omp teams distribute parallel for simd
#pragma omp target teams distribute parallel for simd

I did an all-language bootstrap, followed by regtesting on x86-64-gnu-linux.
(I did a minor change before sending this patch and will have to repeat it.)

Do you have any comments or suggestions? If not, OK for the trunk?

Tobias

Comments

Jakub Jelinek Oct. 31, 2013, 4:40 p.m. UTC | #1
On Sun, Oct 27, 2013 at 10:45:57PM +0100, Tobias Burnus wrote:
> The code is written such that when "-fopenmp" is used,
> -f(no-)openmp-simd has no effect. The following "simd" pragmas are
> listed in OpenMP 4.0 - and will all get translated into "#pragma omp
> simd", only, with -fopenmp-simd:
> #pragma omp simd
> #pragma omp for simd
> #pragma omp distribute simd
> #pragma omp distribute parallel for simd
> #pragma omp parallel for simd
> #pragma omp teams distribute simd
> #pragma omp target teams distribute simd
> #pragma omp teams distribute parallel for simd
> #pragma omp target teams distribute parallel for simd
> 
> I did an all-language bootstrap, followed by regtesting on x86-64-gnu-linux.
> (I did a minor change before sending this patch and will have to repeat it.)

I think we should also parse
#pragma omp declare reduction
even for -fopenmp-simd, that is something that if not used in reduction
clauses will not do anything except diagnosing errors, and it may be used
in #pragma omp simd (and the combined constructs too).

Also, it would be nice if the testcases for this option included also
some clauses (both valid clauses for the simd itself and clauses valid
for the other combined constructs together with simd that they are parsed
but then thrown away).

Otherwise it looks good to me.  Thanks for working on it.

	Jakub
diff mbox

Patch

2013-10-27  Tobias Burnus  <burnus@net-b.de>

gcc/
	* doc/invoke.texi (-fopenmp-simd): Document new option.
	* gimplify.c (gimplify_body): Accept -fopenmp-simd.
	* omp-low.c (execute_expand_omp, execute_lower_omp): Ditto.
	* tree.c (attribute_value_equal): Ditto.

gcc/fortran/
	* lang.opt (fopenmp-simd): New option.
	* gfortran.h (gfc_option_t): Add gfc_flag_openmp_simd.
	* options.c (gfc_handle_option): Handle it.

gcc/c-family/
	* c.opt (fopenmp-simd): New option.
	* c-pragma.c (omp_pragmas): Move pragmas which can contain simd to ...
	(omp_pragmas): ... this new struct.
	(c_pp_lookup_pragma): Also walk omp_pragmas.
	(init_pragma): Init pragmas for -fopenmp-simd.

gcc/c
	* c-parser.c (c_parser_omp_for, c_parser_omp_parallel,
	c_parser_omp_distribute, c_parser_omp_teams,
	c_parser_omp_target, c_parser_omp_declare): Handle
	-fopenmp-simd.

gcc/cp
	* parser.c (cp_parser_omp_for, cp_parser_omp_parallel,
	cp_parser_omp_distribute, cp_parser_omp_teams, cp_parser_omp_target,
	cp_parser_omp_declare): Handle
	-fopenmp-simd.

gcc/testsuite/
	* g++.dg/gomp/openmp-simd-1.C: New.
	* gcc.dg/gomp/openmp-simd-1.c: New.

diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 4b4eb4c..c19c8c6 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -8812,7 +8812,7 @@  gimplify_body (tree fndecl, bool do_parms)
       nonlocal_vlas = NULL;
     }
 
-  if (flag_openmp && gimplify_omp_ctxp)
+  if ((flag_openmp || flag_openmp_simd) && gimplify_omp_ctxp)
     {
       delete_omp_context (gimplify_omp_ctxp);
       gimplify_omp_ctxp = NULL;
diff --git a/gcc/omp-low.c b/gcc/omp-low.c
index a5b9210..7874ff1 100644
--- a/gcc/omp-low.c
+++ b/gcc/omp-low.c
@@ -8232,7 +8232,7 @@  execute_expand_omp (void)
 static bool
 gate_expand_omp (void)
 {
-  return (flag_openmp != 0 && !seen_error ());
+  return ((flag_openmp != 0 || flag_openmp_simd != 0) && !seen_error ());
 }
 
 namespace {
@@ -10053,7 +10053,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 == 0 && flag_openmp_simd == 0)
     return 0;
 
   all_contexts = splay_tree_new (splay_tree_compare_pointers, 0,
diff --git a/gcc/tree.c b/gcc/tree.c
index 0a42109..e7d197a 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -4701,7 +4701,7 @@  attribute_value_equal (const_tree attr1, const_tree attr2)
     return (simple_cst_list_equal (TREE_VALUE (attr1),
 				   TREE_VALUE (attr2)) == 1);
 
-  if (flag_openmp
+  if ((flag_openmp || flag_openmp_simd)
       && TREE_VALUE (attr1) && TREE_VALUE (attr2)
       && TREE_CODE (TREE_VALUE (attr1)) == OMP_CLAUSE
       && TREE_CODE (TREE_VALUE (attr2)) == OMP_CLAUSE)
diff --git a/gcc/fortran/lang.opt b/gcc/fortran/lang.opt
index 4f79934..f3dd348 100644
--- a/gcc/fortran/lang.opt
+++ b/gcc/fortran/lang.opt
@@ -517,6 +521,10 @@  fopenmp
 Fortran
 ; Documented in C
 
+fopenmp-simd
+Fortran
+; Documented in C
+
 fpack-derived
 Fortran
 Try to lay out derived types as compactly as possible
diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index b28edd8..af5e68c 100644
--- a/gcc/fortran/gfortran.h
+++ b/gcc/fortran/gfortran.h
@@ -2286,6 +2286,7 @@  typedef struct
   int flag_cray_pointer;
   int flag_d_lines;
   int gfc_flag_openmp;
+  int gfc_flag_openmp_simd;
   int flag_sign_zero;
   int flag_stack_arrays;
   int flag_module_private;
diff --git a/gcc/fortran/options.c b/gcc/fortran/options.c
index 6e4e7c1..e05528a 100644
--- a/gcc/fortran/options.c
+++ b/gcc/fortran/options.c
@@ -836,6 +836,10 @@  gfc_handle_option (size_t scode, const char *arg, int value,
       gfc_option.gfc_flag_openmp = value;
       break;
 
+    case OPT_fopenmp_simd:
+      gfc_option.gfc_flag_openmp_simd = value;
+      break;
+
     case OPT_ffree_line_length_none:
       gfc_option.free_line_length = 0;
       break;
diff --git a/gcc/c-family/c-pragma.c b/gcc/c-family/c-pragma.c
index 1656000..a6a24b8 100644
--- a/gcc/c-family/c-pragma.c
+++ b/gcc/c-family/c-pragma.c
@@ -1170,31 +1170,35 @@  static const struct omp_pragma_def omp_pragmas[] = {
   { "cancel", PRAGMA_OMP_CANCEL },
   { "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 },
   { "master", PRAGMA_OMP_MASTER },
   { "ordered", PRAGMA_OMP_ORDERED },
-  { "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 }
 };
+static const struct omp_pragma_def omp_pragmas_simd[] = {
+  { "declare", PRAGMA_OMP_DECLARE_REDUCTION },
+  { "distribute", PRAGMA_OMP_DISTRIBUTE },
+  { "for", PRAGMA_OMP_FOR },
+  { "parallel", PRAGMA_OMP_PARALLEL },
+  { "simd", PRAGMA_OMP_SIMD },
+  { "target", PRAGMA_OMP_TARGET },
+  { "task", PRAGMA_OMP_TASK },
+  { "teams", PRAGMA_OMP_TEAMS },
+};
 
 void
 c_pp_lookup_pragma (unsigned int id, const char **space, const char **name)
 {
   const int n_omp_pragmas = sizeof (omp_pragmas) / sizeof (*omp_pragmas);
+  const int n_omp_pragmas_simd = sizeof (omp_pragmas_simd)
+				 / sizeof (*omp_pragmas);
   int i;
 
   for (i = 0; i < n_omp_pragmas; ++i)
@@ -1205,6 +1209,14 @@  c_pp_lookup_pragma (unsigned int id, const char **space, const char **name)
 	return;
       }
 
+  for (i = 0; i < n_omp_pragmas_simd; ++i)
+    if (omp_pragmas_simd[i].id == id)
+      {
+	*space = "omp";
+	*name = omp_pragmas_simd[i].name;
+	return;
+      }
+
   if (id >= PRAGMA_FIRST_EXTERNAL
       && (id < PRAGMA_FIRST_EXTERNAL + registered_pp_pragmas.length ()))
     {
@@ -1357,6 +1369,16 @@  init_pragma (void)
 	cpp_register_deferred_pragma (parse_in, "omp", omp_pragmas[i].name,
 				      omp_pragmas[i].id, true, true);
     }
+  if (flag_openmp || flag_openmp_simd)
+    {
+      const int n_omp_pragmas_simd = sizeof (omp_pragmas_simd)
+				     / sizeof (*omp_pragmas);
+      int i;
+
+      for (i = 0; i < n_omp_pragmas_simd; ++i)
+	cpp_register_deferred_pragma (parse_in, "omp", omp_pragmas_simd[i].name,
+				      omp_pragmas_simd[i].id, true, true);
+    }
 
   if (!flag_preprocess_only)
     cpp_register_deferred_pragma (parse_in, "GCC", "pch_preprocess",
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index b862eb9..22f8939 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -1069,6 +1069,10 @@  fopenmp
 C ObjC C++ ObjC++ Var(flag_openmp)
 Enable OpenMP (implies -frecursive in Fortran)
 
+fopenmp-simd
+C ObjC C++ ObjC++ Var(flag_openmp_simd)
+Enable OpenMP's SIMD directives
+
 foperator-names
 C++ ObjC++
 Recognize C++ keywords like \"compl\" and \"xor\"
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index 9ccae3b..4d97e93 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -11584,6 +11584,8 @@  c_parser_omp_for (location_t loc, c_parser *parser,
 	    cclauses = cclauses_buf;
 
 	  c_parser_consume_token (parser);
+	  if (!flag_openmp)  /* flag_openmp_simd  */
+	    return c_parser_omp_simd (loc, parser, p_name, mask, cclauses);
 	  block = c_begin_compound_stmt (true);
 	  ret = c_parser_omp_simd (loc, parser, p_name, mask, cclauses);
 	  block = c_end_compound_stmt (loc, block, true);
@@ -11598,6 +11600,8 @@  c_parser_omp_for (location_t loc, c_parser *parser,
 	  return ret;
 	}
     }
+  if (!flag_openmp)  /* flag_openmp_simd  */
+    return NULL_TREE;
 
   clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL);
   if (cclauses)
@@ -11793,6 +11797,8 @@  c_parser_omp_parallel (location_t loc, c_parser *parser,
 	cclauses = cclauses_buf;
 
       c_parser_consume_token (parser);
+      if (!flag_openmp)  /* flag_openmp_simd  */
+	return c_parser_omp_for (loc, parser, p_name, mask, cclauses);
       block = c_begin_omp_parallel ();
       c_parser_omp_for (loc, parser, p_name, mask, cclauses);
       stmt
@@ -11807,6 +11813,8 @@  c_parser_omp_parallel (location_t loc, c_parser *parser,
       c_parser_skip_to_pragma_eol (parser);
       return NULL_TREE;
     }
+  else if (!flag_openmp)  /* flag_openmp_simd  */
+    return NULL_TREE;
   else if (c_parser_next_token_is (parser, CPP_NAME))
     {
       const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
@@ -12037,6 +12045,14 @@  c_parser_omp_distribute (location_t loc, c_parser *parser,
 	  if (cclauses == NULL)
 	    cclauses = cclauses_buf;
 	  c_parser_consume_token (parser);
+	  if (!flag_openmp)  /* flag_openmp_simd  */
+	    {
+	      if (simd)
+		return c_parser_omp_simd (loc, parser, p_name, mask, cclauses);
+	      else
+		return c_parser_omp_parallel (loc, parser, p_name, mask,
+					      cclauses);
+	    }
 	  block = c_begin_compound_stmt (true);
 	  if (simd)
 	    ret = c_parser_omp_simd (loc, parser, p_name, mask, cclauses);
@@ -12054,6 +12070,8 @@  c_parser_omp_distribute (location_t loc, c_parser *parser,
 	  return ret;
 	}
     }
+  if (!flag_openmp)  /* flag_openmp_simd  */
+    return NULL_TREE;
 
   clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL);
   if (cclauses)
@@ -12102,6 +12120,8 @@  c_parser_omp_teams (location_t loc, c_parser *parser,
 	    cclauses = cclauses_buf;
 
 	  c_parser_consume_token (parser);
+	  if (!flag_openmp)  /* flag_openmp_simd  */
+	    return c_parser_omp_distribute (loc, parser, p_name, mask, cclauses);
 	  block = c_begin_compound_stmt (true);
 	  ret = c_parser_omp_distribute (loc, parser, p_name, mask, cclauses);
 	  block = c_end_compound_stmt (loc, block, true);
@@ -12115,6 +12135,8 @@  c_parser_omp_teams (location_t loc, c_parser *parser,
 	  return add_stmt (ret);
 	}
     }
+  if (!flag_openmp)  /* flag_openmp_simd  */
+    return NULL_TREE;
 
   clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL);
   if (cclauses)
@@ -12226,24 +12248,16 @@  c_parser_omp_target (c_parser *parser, enum pragma_context context)
     {
       const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
 
-      if (strcmp (p, "data") == 0)
-	{
-	  c_parser_consume_token (parser);
-	  c_parser_omp_target_data (loc, parser);
-	  return true;
-	}
-      else if (strcmp (p, "update") == 0)
-	{
-	  c_parser_consume_token (parser);
-	  return c_parser_omp_target_update (loc, parser, context);
-	}
-      else if (strcmp (p, "teams") == 0)
+      if (strcmp (p, "teams") == 0)
 	{
 	  tree cclauses[C_OMP_CLAUSE_SPLIT_COUNT];
 	  char p_name[sizeof ("#pragma omp target teams distribute "
 			      "parallel for simd")];
 
 	  c_parser_consume_token (parser);
+	  if (!flag_openmp)  /* flag_openmp_simd  */
+	    return c_parser_omp_teams (loc, parser, p_name,
+				       OMP_TARGET_CLAUSE_MASK, cclauses);
 	  strcpy (p_name, "#pragma omp target");
 	  keep_next_level ();
 	  tree block = c_begin_compound_stmt (true);
@@ -12259,6 +12273,19 @@  c_parser_omp_target (c_parser *parser, enum pragma_context context)
 	  add_stmt (stmt);
 	  return true;
 	}
+      else if (!flag_openmp)  /* flag_openmp_simd  */
+	return NULL_TREE;
+      else if (strcmp (p, "data") == 0)
+	{
+	  c_parser_consume_token (parser);
+	  c_parser_omp_target_data (loc, parser);
+	  return true;
+	}
+      else if (strcmp (p, "update") == 0)
+	{
+	  c_parser_consume_token (parser);
+	  return c_parser_omp_target_update (loc, parser, context);
+	}
     }
 
   tree stmt = make_node (OMP_TARGET);
@@ -12880,6 +12907,8 @@  c_parser_omp_declare (c_parser *parser, enum pragma_context context)
 	  c_parser_omp_declare_simd (parser, context);
 	  return;
 	}
+      if (!flag_openmp)  /* flag_openmp_simd  */
+	return;
       if (strcmp (p, "reduction") == 0)
 	{
 	  c_parser_consume_token (parser);
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 8deffc3..d5df07f 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -29077,6 +29077,9 @@  cp_parser_omp_for (cp_parser *parser, cp_token *pragma_tok,
 	    cclauses = cclauses_buf;
 
 	  cp_lexer_consume_token (parser->lexer);
+	  if (!flag_openmp)  /* flag_openmp_simd  */
+	    return cp_parser_omp_simd (parser, pragma_tok, p_name, mask,
+				       cclauses);
 	  sb = begin_omp_structured_block ();
 	  save = cp_parser_begin_omp_structured_block (parser);
 	  ret = cp_parser_omp_simd (parser, pragma_tok, p_name, mask,
@@ -29094,6 +29097,8 @@  cp_parser_omp_for (cp_parser *parser, cp_token *pragma_tok,
 	  return ret;
 	}
     }
+  if (!flag_openmp)  /* flag_openmp_simd  */
+    return NULL_TREE;
 
   clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok,
 				       cclauses == NULL);
@@ -29277,6 +29282,8 @@  cp_parser_omp_parallel (cp_parser *parser, cp_token *pragma_tok,
 	cclauses = cclauses_buf;
 
       cp_lexer_consume_token (parser->lexer);
+      if (!flag_openmp)  /* flag_openmp_simd  */
+	return cp_parser_omp_for (parser, pragma_tok, p_name, mask, cclauses);
       block = begin_omp_parallel ();
       save = cp_parser_begin_omp_structured_block (parser);
       cp_parser_omp_for (parser, pragma_tok, p_name, mask, cclauses);
@@ -29292,6 +29299,8 @@  cp_parser_omp_parallel (cp_parser *parser, cp_token *pragma_tok,
       cp_parser_skip_to_pragma_eol (parser, pragma_tok);
       return NULL_TREE;
     }
+  else if (!flag_openmp)  /* flag_openmp_simd  */
+    return NULL_TREE;
   else if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
     {
       tree id = cp_lexer_peek_token (parser->lexer)->u.value;
@@ -29520,6 +29529,15 @@  cp_parser_omp_distribute (cp_parser *parser, cp_token *pragma_tok,
 	  if (cclauses == NULL)
 	    cclauses = cclauses_buf;
 	  cp_lexer_consume_token (parser->lexer);
+	  if (!flag_openmp)  /* flag_openmp_simd  */
+	    {
+	      if (simd)
+		return cp_parser_omp_simd (parser, pragma_tok, p_name, mask,
+					   cclauses);
+	      else
+		return cp_parser_omp_parallel (parser, pragma_tok, p_name, mask,
+					       cclauses);
+	    }
 	  sb = begin_omp_structured_block ();
 	  save = cp_parser_begin_omp_structured_block (parser);
 	  if (simd)
@@ -29541,6 +29559,8 @@  cp_parser_omp_distribute (cp_parser *parser, cp_token *pragma_tok,
 	  return ret;
 	}
     }
+  if (!flag_openmp)  /* flag_openmp_simd  */
+    return NULL_TREE;
 
   clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok,
 				       cclauses == NULL);
@@ -29596,6 +29616,9 @@  cp_parser_omp_teams (cp_parser *parser, cp_token *pragma_tok,
 	    cclauses = cclauses_buf;
 
 	  cp_lexer_consume_token (parser->lexer);
+	  if (!flag_openmp)  /* flag_openmp_simd  */
+	    return cp_parser_omp_distribute (parser, pragma_tok, p_name, mask,
+					     cclauses);
 	  sb = begin_omp_structured_block ();
 	  save = cp_parser_begin_omp_structured_block (parser);
 	  ret = cp_parser_omp_distribute (parser, pragma_tok, p_name, mask,
@@ -29612,6 +29635,8 @@  cp_parser_omp_teams (cp_parser *parser, cp_token *pragma_tok,
 	  return add_stmt (ret);
 	}
     }
+  if (!flag_openmp)  /* flag_openmp_simd  */
+    return NULL_TREE;
 
   clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok,
 				       cclauses == NULL);
@@ -29721,18 +29746,7 @@  cp_parser_omp_target (cp_parser *parser, cp_token *pragma_tok,
       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);
-	}
-      else if (strcmp (p, "teams") == 0)
+      if (strcmp (p, "teams") == 0)
 	{
 	  tree cclauses[C_OMP_CLAUSE_SPLIT_COUNT];
 	  char p_name[sizeof ("#pragma omp target teams distribute "
@@ -29741,6 +29755,9 @@  cp_parser_omp_target (cp_parser *parser, cp_token *pragma_tok,
 	  cp_lexer_consume_token (parser->lexer);
 	  strcpy (p_name, "#pragma omp target");
 	  keep_next_level (true);
+	  if (!flag_openmp)  /* flag_openmp_simd  */
+	    return cp_parser_omp_teams (parser, pragma_tok, p_name,
+					OMP_TARGET_CLAUSE_MASK, cclauses);
 	  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,
@@ -29756,6 +29773,19 @@  cp_parser_omp_target (cp_parser *parser, cp_token *pragma_tok,
 	  add_stmt (stmt);
 	  return true;
 	}
+      else if (!flag_openmp)  /* flag_openmp_simd  */
+        return NULL_TREE;
+      else 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);
@@ -30347,6 +30377,8 @@  cp_parser_omp_declare (cp_parser *parser, cp_token *pragma_tok,
 				      context);
 	  return;
 	}
+      if (!flag_openmp)  /* flag_openmp_simd  */
+	return;
       cp_ensure_no_omp_declare_simd (parser);
       if (strcmp (p, "reduction") == 0)
 	{
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index ab25922..0f213ec 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -168,8 +168,8 @@  in the following sections.
 @gccoptlist{-ansi  -std=@var{standard}  -fgnu89-inline @gol
 -aux-info @var{filename} -fallow-parameterless-variadic-functions @gol
 -fno-asm  -fno-builtin  -fno-builtin-@var{function} @gol
--fhosted  -ffreestanding -fopenmp -fms-extensions -fplan9-extensions @gol
--trigraphs  -traditional  -traditional-cpp @gol
+-fhosted  -ffreestanding -fopenmp -fopenmp-simd -fms-extensions @gol
+-fplan9-extensions -trigraphs  -traditional  -traditional-cpp @gol
 -fallow-single-precision  -fcond-mismatch -flax-vector-conversions @gol
 -fsigned-bitfields  -fsigned-char @gol
 -funsigned-bitfields  -funsigned-char}
@@ -1826,7 +1826,16 @@  Enable handling of OpenMP directives @code{#pragma omp} in C/C++ and
 compiler generates parallel code according to the OpenMP Application
 Program Interface v4.0 @w{@uref{http://www.openmp.org/}}.  This option
 implies @option{-pthread}, and thus is only supported on targets that
-have support for @option{-pthread}.
+have support for @option{-pthread}. @option{-fopenmp} implies
+@option{-fopenmp-simd}.
+
+@item -fopenmp-simd
+@opindex fopenmp-simd
+@cindex OpenMP SIMD
+@cindex SIMD
+Enable handling of OpenMP's SIMD directives with @code{#pragma omp}
+in C/C++ and @code{!$omp} in Fortran. Other OpenMP directives
+are ignored.
 
 @item -fcilkplus
 @opindex fcilkplus
diff --git a/gcc/testsuite/g++.dg/gomp/openmp-simd-1.C b/gcc/testsuite/g++.dg/gomp/openmp-simd-1.C
new file mode 100644
index 0000000..8f8f140
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/openmp-simd-1.C
@@ -0,0 +1,46 @@ 
+/* { dg-do compile } */
+/* { dg-options "-fopenmp-simd -fdump-tree-original" } */
+
+#pragma omp declare simd
+float bar(float b) {
+  return b*b;
+}
+
+void foo(int n, float *a, float *b)
+{
+  int i; 
+#pragma omp simd
+  for (i = 0; i < n ; i++)
+    a[i] = b[i];
+#pragma omp for simd
+  for (i = 0; i < n ; i++)
+    a[i] = b[i];
+#pragma omp distribute simd
+  for (i = 0; i < n ; i++)
+    a[i] = b[i];
+#pragma omp distribute parallel for simd
+  for (i = 0; i < n ; i++)
+    a[i] = b[i];
+#pragma omp parallel for simd
+  for (i = 0; i < n ; i++)
+    a[i] = b[i];
+#pragma omp teams distribute simd
+  for (i = 0; i < n ; i++)
+    a[i] = b[i];
+#pragma omp target teams distribute simd
+  for (i = 0; i < n ; i++)
+    a[i] = b[i];
+#pragma omp teams distribute parallel for simd
+  for (i = 0; i < n ; i++)
+    a[i] = b[i];
+#pragma omp target teams distribute parallel for simd
+  for (i = 0; i < n ; i++)
+    a[i] = b[i];
+}
+
+/* { dg-final { scan-tree-dump-times "pragma omp simd" 9 "original" } } */
+/* { dg-final { scan-tree-dump-not "omp omp for" "original" } } */
+/* { dg-final { scan-tree-dump-not "omp distribute" "original" } } */
+/* { dg-final { scan-tree-dump-not "omp teams" "original" } } */
+/* { dg-final { scan-tree-dump-not "omp target" "original" } } */
+/* { dg-final { scan-tree-dump-not "omp parallel" "original" } } */
diff --git a/gcc/testsuite/gcc.dg/gomp/openmp-simd-1.c b/gcc/testsuite/gcc.dg/gomp/openmp-simd-1.c
new file mode 100644
index 0000000..8f8f140
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/gomp/openmp-simd-1.c
@@ -0,0 +1,46 @@ 
+/* { dg-do compile } */
+/* { dg-options "-fopenmp-simd -fdump-tree-original" } */
+
+#pragma omp declare simd
+float bar(float b) {
+  return b*b;
+}
+
+void foo(int n, float *a, float *b)
+{
+  int i; 
+#pragma omp simd
+  for (i = 0; i < n ; i++)
+    a[i] = b[i];
+#pragma omp for simd
+  for (i = 0; i < n ; i++)
+    a[i] = b[i];
+#pragma omp distribute simd
+  for (i = 0; i < n ; i++)
+    a[i] = b[i];
+#pragma omp distribute parallel for simd
+  for (i = 0; i < n ; i++)
+    a[i] = b[i];
+#pragma omp parallel for simd
+  for (i = 0; i < n ; i++)
+    a[i] = b[i];
+#pragma omp teams distribute simd
+  for (i = 0; i < n ; i++)
+    a[i] = b[i];
+#pragma omp target teams distribute simd
+  for (i = 0; i < n ; i++)
+    a[i] = b[i];
+#pragma omp teams distribute parallel for simd
+  for (i = 0; i < n ; i++)
+    a[i] = b[i];
+#pragma omp target teams distribute parallel for simd
+  for (i = 0; i < n ; i++)
+    a[i] = b[i];
+}
+
+/* { dg-final { scan-tree-dump-times "pragma omp simd" 9 "original" } } */
+/* { dg-final { scan-tree-dump-not "omp omp for" "original" } } */
+/* { dg-final { scan-tree-dump-not "omp distribute" "original" } } */
+/* { dg-final { scan-tree-dump-not "omp teams" "original" } } */
+/* { dg-final { scan-tree-dump-not "omp target" "original" } } */
+/* { dg-final { scan-tree-dump-not "omp parallel" "original" } } */