diff mbox

[PING] : [GOMP4] [PATCH] SIMD-Enabled Functions (formerly Elemental functions) for C

Message ID BF230D13CA30DD48930C31D4099330003A4B2B7F@FMSMSX101.amr.corp.intel.com
State New
Headers show

Commit Message

Iyer, Balaji V Dec. 17, 2013, 11:38 p.m. UTC
> -----Original Message-----
> From: gcc-patches-owner@gcc.gnu.org [mailto:gcc-patches-
> owner@gcc.gnu.org] On Behalf Of Jakub Jelinek
> Sent: Tuesday, December 17, 2013 4:26 PM
> To: Iyer, Balaji V
> Cc: Joseph S. Myers; Aldy Hernandez (aldyh@redhat.com); 'gcc-
> patches@gcc.gnu.org'
> Subject: Re: [PING]: [GOMP4] [PATCH] SIMD-Enabled Functions (formerly
> Elemental functions) for C
> 
> On Tue, Dec 17, 2013 at 09:13:05PM +0000, Iyer, Balaji V wrote:
> > @@ -10418,6 +10528,12 @@
> >        step = c_parser_expression (parser).value;
> >        mark_exp_read (step);
> >        step = c_fully_fold (step, false, NULL);
> > +      if (is_cilk_simd_fn && TREE_CODE (step) == PARM_DECL)
> > +	{
> > +	  sorry ("using parameters for %<linear%> step is not supported yet "
> > +		 "in this release");
> 
> I meant actually
> 	sorry ("using parameters for %<linear%> step is not supported yet");
> 
> > @@ -10933,8 +11051,14 @@
> >  	  c_name = "aligned";
> >  	  break;
> >  	case PRAGMA_OMP_CLAUSE_LINEAR:
> > -	  clauses = c_parser_omp_clause_linear (parser, clauses);
> > -	  c_name = "linear";
> > +	  {
> > +	    bool is_cilk_simd_fn = false;
> > +	    if ((mask & PRAGMA_CILK_CLAUSE_VECTORLENGTH) == 0)
> > +	      is_cilk_simd_fn = true;
> 
> I don't think this will work.  PRAGMA_CILK_CLAUSE_VECTORLENGTH is
> something like 40 I think, so testing whether the mask doesn't include copyin
> and default clauses is not what you wanted probably.
> What I meant is
>   if (((mask >> PRAGMA_CILK_CLAUSE_VECTORLENGTH) & 1) != 0)
>     is_cilk_simd_fn = true;
> (note, for 32-bit HWI targets, omp_clause_mask is a class and not all
> arithmetic is actually supported on it, so better limit yourself to forms used
> elsewhere already).
> 

I have a better idea.. The where string, if it is "SIMD-enabled functions attribute" will indicate that it is a Cilk Plus SIMD-enabled function.  So, if I do a check for that, then I don't have to do any of this mask anding.

This is what I am talking about:

  if (where && !strcmp (where, "SIMD-enabled functions attribute"))
    is_cilk_simd_fn = false;



> > @@ -12754,10 +12882,20 @@
> >  c_finish_omp_declare_simd (c_parser *parser, tree fndecl, tree parms,
> >  			   vec<c_token> clauses)
> >  {
> > +
> 
> Please remove this extra vertical space.
> 
> Otherwise looks good to me, just not sure where do you handle processor
> clause (or how Cilk+ simd clones specify the ISA they want to use).

Processor clause is an ICC only clause and thus GCC won't have it. The ISA clause (renamed to architecture), I am planning to handle in the next release along with parameters for step-size for linear


Can I install this? If so, can I push it to trunk? From what I understood, all the #pragma omp declare simd work are pushed into trunk right?

> 
> 	Jakub

Comments

Jakub Jelinek Dec. 18, 2013, 6:30 a.m. UTC | #1
On Tue, Dec 17, 2013 at 11:38:48PM +0000, Iyer, Balaji V wrote:
> > What I meant is
> >   if (((mask >> PRAGMA_CILK_CLAUSE_VECTORLENGTH) & 1) != 0)
> >     is_cilk_simd_fn = true;
> > (note, for 32-bit HWI targets, omp_clause_mask is a class and not all
> > arithmetic is actually supported on it, so better limit yourself to forms used
> > elsewhere already).
> > 
> 
> I have a better idea.. The where string, if it is "SIMD-enabled functions
> attribute" will indicate that it is a Cilk Plus SIMD-enabled function. 
> So, if I do a check for that, then I don't have to do any of this mask
> anding.
> 
> This is what I am talking about:
> 
>   if (where && !strcmp (where, "SIMD-enabled functions attribute"))
>     is_cilk_simd_fn = false;

But this is more expensive and the string really is meant for diagnostics
messages, so I'd strongly prefer the above mask check instead.
Ok with that change.

> From what I understood, all the #pragma omp declare simd work are pushed into trunk right?

Yes, though I still want to optimize it a little bit (generate thunks
and/or aliases when desirable/possible), but that only affects exported
entry-points for OpenMP, for Cilk+ the code matches more the Intel ABI
paper and generates only one ISA variant (and expects to parse processor
clause for other ISA variants), rather than emitting all 3.

	Jakub
Iyer, Balaji V Dec. 18, 2013, 2:32 p.m. UTC | #2
> -----Original Message-----
> From: Jakub Jelinek [mailto:jakub@zalov.cz]
> Sent: Wednesday, December 18, 2013 1:31 AM
> To: Iyer, Balaji V
> Cc: Joseph S. Myers; Aldy Hernandez (aldyh@redhat.com); 'gcc-
> patches@gcc.gnu.org'
> Subject: Re: [PING]: [GOMP4] [PATCH] SIMD-Enabled Functions (formerly
> Elemental functions) for C
> 
> On Tue, Dec 17, 2013 at 11:38:48PM +0000, Iyer, Balaji V wrote:
> > > What I meant is
> > >   if (((mask >> PRAGMA_CILK_CLAUSE_VECTORLENGTH) & 1) != 0)
> > >     is_cilk_simd_fn = true;
> > > (note, for 32-bit HWI targets, omp_clause_mask is a class and not
> > > all arithmetic is actually supported on it, so better limit yourself
> > > to forms used elsewhere already).
> > >
> >
> > I have a better idea.. The where string, if it is "SIMD-enabled
> > functions attribute" will indicate that it is a Cilk Plus SIMD-enabled function.
> > So, if I do a check for that, then I don't have to do any of this mask
> > anding.
> >
> > This is what I am talking about:
> >
> >   if (where && !strcmp (where, "SIMD-enabled functions attribute"))
> >     is_cilk_simd_fn = false;
> 
> But this is more expensive and the string really is meant for diagnostics
> messages, so I'd strongly prefer the above mask check instead.
> Ok with that change.
> 

OK, will make this fix.

> > From what I understood, all the #pragma omp declare simd work are
> pushed into trunk right?
> 
> Yes, though I still want to optimize it a little bit (generate thunks and/or
> aliases when desirable/possible), but that only affects exported entry-points
> for OpenMP, for Cilk+ the code matches more the Intel ABI paper and
> generates only one ISA variant (and expects to parse processor clause for
> other ISA variants), rather than emitting all 3.

So, install it into gomp4 branch then?

> 
> 	Jakub
Jakub Jelinek Dec. 18, 2013, 2:35 p.m. UTC | #3
On Wed, Dec 18, 2013 at 02:32:54PM +0000, Iyer, Balaji V wrote:
> > Yes, though I still want to optimize it a little bit (generate thunks and/or
> > aliases when desirable/possible), but that only affects exported entry-points
> > for OpenMP, for Cilk+ the code matches more the Intel ABI paper and
> > generates only one ISA variant (and expects to parse processor clause for
> > other ISA variants), rather than emitting all 3.
> 
> So, install it into gomp4 branch then?

No, please test against trunk and commit there.

	Jakub
diff mbox

Patch

Index: gcc/c-family/c-common.c
===================================================================
--- gcc/c-family/c-common.c	(revision 205759)
+++ gcc/c-family/c-common.c	(working copy)
@@ -771,6 +771,8 @@ 
 			      handle_returns_nonnull_attribute, false },
   { "omp declare simd",       0, -1, true,  false, false,
 			      handle_omp_declare_simd_attribute, false },
+  { "cilk simd function",     0, -1, true,  false, false,
+			      handle_omp_declare_simd_attribute, false },
   { "omp declare target",     0, 0, true, false, false,
 			      handle_omp_declare_target_attribute, false },
   { "bnd_variable_size",      0, 0, true,  false, false,
Index: gcc/c-family/c-pragma.h
===================================================================
--- gcc/c-family/c-pragma.h	(revision 205759)
+++ gcc/c-family/c-pragma.h	(working copy)
@@ -104,20 +104,21 @@ 
   PRAGMA_OMP_CLAUSE_THREAD_LIMIT,
   PRAGMA_OMP_CLAUSE_TO,
   PRAGMA_OMP_CLAUSE_UNIFORM,
-  PRAGMA_OMP_CLAUSE_UNTIED
+  PRAGMA_OMP_CLAUSE_UNTIED,
+  
+  /* Clauses for Cilk Plus SIMD-enabled function.  */
+  PRAGMA_CILK_CLAUSE_NOMASK,
+  PRAGMA_CILK_CLAUSE_MASK,
+  PRAGMA_CILK_CLAUSE_VECTORLENGTH,
+  PRAGMA_CILK_CLAUSE_NONE = PRAGMA_OMP_CLAUSE_NONE,
+  PRAGMA_CILK_CLAUSE_LINEAR = PRAGMA_OMP_CLAUSE_LINEAR,
+  PRAGMA_CILK_CLAUSE_PRIVATE = PRAGMA_OMP_CLAUSE_PRIVATE,
+  PRAGMA_CILK_CLAUSE_FIRSTPRIVATE = PRAGMA_OMP_CLAUSE_FIRSTPRIVATE,
+  PRAGMA_CILK_CLAUSE_LASTPRIVATE = PRAGMA_OMP_CLAUSE_LASTPRIVATE,
+  PRAGMA_CILK_CLAUSE_REDUCTION = PRAGMA_OMP_CLAUSE_REDUCTION,
+  PRAGMA_CILK_CLAUSE_UNIFORM = PRAGMA_OMP_CLAUSE_UNIFORM
 } pragma_omp_clause;
 
-/* All Cilk Plus #pragma omp clauses.  */
-typedef enum pragma_cilk_clause {
-  PRAGMA_CILK_CLAUSE_NONE = 0,
-  PRAGMA_CILK_CLAUSE_VECTORLENGTH,
-  PRAGMA_CILK_CLAUSE_LINEAR,
-  PRAGMA_CILK_CLAUSE_PRIVATE,
-  PRAGMA_CILK_CLAUSE_FIRSTPRIVATE,
-  PRAGMA_CILK_CLAUSE_LASTPRIVATE,
-  PRAGMA_CILK_CLAUSE_REDUCTION
-} pragma_cilk_clause;
-
 extern struct cpp_reader* parse_in;
 
 /* It's safe to always leave visibility pragma enabled as if
Index: gcc/c/c-parser.c
===================================================================
--- gcc/c/c-parser.c	(revision 205759)
+++ gcc/c/c-parser.c	(working copy)
@@ -208,6 +208,12 @@ 
   /* True if we are in a context where the Objective-C "Property attribute"
      keywords are valid.  */
   BOOL_BITFIELD objc_property_attr_context : 1;
+
+  /* Cilk Plus specific parser/lexer information.  */
+
+  /* Buffer to hold all the tokens from parsing the vector attribute for the
+     SIMD-enabled functions (formerly known as elemental functions).  */
+  vec <c_token, va_gc> *cilk_simd_fn_tokens;
 } c_parser;
 
 
@@ -1246,6 +1252,7 @@ 
 static void c_parser_cilk_simd (c_parser *);
 static bool c_parser_cilk_verify_simd (c_parser *, enum pragma_context);
 static tree c_parser_array_notation (location_t, c_parser *, tree, tree);
+static tree c_parser_cilk_clause_vectorlength (c_parser *, tree, bool);
 
 /* Parse a translation unit (C90 6.7, C99 6.9).
 
@@ -1647,7 +1654,8 @@ 
 					C_DTR_NORMAL, &dummy);
       if (declarator == NULL)
 	{
-	  if (omp_declare_simd_clauses.exists ())
+	  if (omp_declare_simd_clauses.exists ()
+	      || !vec_safe_is_empty (parser->cilk_simd_fn_tokens))
 	    c_finish_omp_declare_simd (parser, NULL_TREE, NULL_TREE,
 				       omp_declare_simd_clauses);
 	  c_parser_skip_to_end_of_block_or_statement (parser);
@@ -1734,7 +1742,8 @@ 
 				  chainon (postfix_attrs, all_prefix_attrs));
 		  if (!d)
 		    d = error_mark_node;
-		  if (omp_declare_simd_clauses.exists ())
+		  if (omp_declare_simd_clauses.exists ()
+		      || !vec_safe_is_empty (parser->cilk_simd_fn_tokens))
 		    c_finish_omp_declare_simd (parser, d, NULL_TREE,
 					       omp_declare_simd_clauses);
 		}
@@ -1746,7 +1755,8 @@ 
 				  chainon (postfix_attrs, all_prefix_attrs));
 		  if (!d)
 		    d = error_mark_node;
-		  if (omp_declare_simd_clauses.exists ())
+		  if (omp_declare_simd_clauses.exists ()
+		      || !vec_safe_is_empty (parser->cilk_simd_fn_tokens))
 		    c_finish_omp_declare_simd (parser, d, NULL_TREE,
 					       omp_declare_simd_clauses);
 		  start_init (d, asm_name, global_bindings_p ());
@@ -1774,7 +1784,8 @@ 
 	      tree d = start_decl (declarator, specs, false,
 				   chainon (postfix_attrs,
 					    all_prefix_attrs));
-	      if (omp_declare_simd_clauses.exists ())
+	      if (omp_declare_simd_clauses.exists ()
+		  || !vec_safe_is_empty (parser->cilk_simd_fn_tokens))
 		{
 		  tree parms = NULL_TREE;
 		  if (d && TREE_CODE (d) == FUNCTION_DECL)
@@ -1902,7 +1913,8 @@ 
 	c_parser_declaration_or_fndef (parser, false, false, false,
 				       true, false, NULL, vNULL);
       store_parm_decls ();
-      if (omp_declare_simd_clauses.exists ())
+      if (omp_declare_simd_clauses.exists ()
+	  || !vec_safe_is_empty (parser->cilk_simd_fn_tokens))
 	c_finish_omp_declare_simd (parser, current_function_decl, NULL_TREE,
 				   omp_declare_simd_clauses);
       DECL_STRUCT_FUNCTION (current_function_decl)->function_start_locus
@@ -3765,6 +3777,87 @@ 
   return attr_name;
 }
 
+/* Returns true of NAME is an IDENTIFIER_NODE with identiifer "vector,"
+   "__vector" or "__vector__."  */
+
+static inline bool
+is_cilkplus_vector_p (tree name)
+{ 
+  if (flag_enable_cilkplus && is_attribute_p ("vector", name)) 
+    return true;
+  return false;
+}
+
+#define CILK_SIMD_FN_CLAUSE_MASK				  \
+	((OMP_CLAUSE_MASK_1 << PRAGMA_CILK_CLAUSE_VECTORLENGTH)	  \
+	 | (OMP_CLAUSE_MASK_1 << PRAGMA_CILK_CLAUSE_LINEAR)	  \
+	 | (OMP_CLAUSE_MASK_1 << PRAGMA_CILK_CLAUSE_UNIFORM)	  \
+	 | (OMP_CLAUSE_MASK_1 << PRAGMA_CILK_CLAUSE_MASK)	  \
+	 | (OMP_CLAUSE_MASK_1 << PRAGMA_CILK_CLAUSE_NOMASK))
+
+/* Parses the vector attribute of SIMD enabled functions in Cilk Plus.
+   VEC_TOKEN is the "vector" token that is replaced with "simd" and
+   pushed into the token list. 
+   Syntax:
+   vector
+   vector (<vector attributes>).  */
+
+static void
+c_parser_cilk_simd_fn_vector_attrs (c_parser *parser, c_token vec_token)
+{
+  gcc_assert (is_cilkplus_vector_p (vec_token.value));
+  
+  int paren_scope = 0;
+  vec_safe_push (parser->cilk_simd_fn_tokens, vec_token);
+  /* Consume the "vector" token.  */
+  c_parser_consume_token (parser);
+
+  if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+    {
+      c_parser_consume_token (parser);
+      paren_scope++;
+    }
+  while (paren_scope > 0)
+    {
+      c_token *token = c_parser_peek_token (parser);
+      if (token->type == CPP_OPEN_PAREN)
+        paren_scope++;
+      else if (token->type == CPP_CLOSE_PAREN)
+        paren_scope--;
+      /* Do not push the last ')' since we are not pushing the '('.  */
+      if (!(token->type == CPP_CLOSE_PAREN && paren_scope == 0))
+	vec_safe_push (parser->cilk_simd_fn_tokens, *token);
+      c_parser_consume_token (parser);
+    }
+  
+  /* Since we are converting an attribute to a pragma, we need to end the
+     attribute with PRAGMA_EOL.  */
+  c_token eol_token;
+  memset (&eol_token, 0, sizeof (eol_token));
+  eol_token.type = CPP_PRAGMA_EOL;
+  vec_safe_push (parser->cilk_simd_fn_tokens, eol_token);
+}
+
+/* Add 2 CPP_EOF at the end of PARSER->ELEM_FN_TOKENS vector.  */
+
+static void
+c_finish_cilk_simd_fn_tokens (c_parser *parser)
+{
+  c_token last_token = parser->cilk_simd_fn_tokens->last ();
+
+  /* c_parser_attributes is called in several places, so if these EOF
+     tokens are already inserted, then don't do them again.  */
+  if (last_token.type == CPP_EOF)
+    return;
+  
+  /* Two CPP_EOF token are added as a safety net since the normal C
+     front-end has two token look-ahead.  */
+  c_token eof_token;
+  eof_token.type = CPP_EOF;
+  vec_safe_push (parser->cilk_simd_fn_tokens, eof_token);
+  vec_safe_push (parser->cilk_simd_fn_tokens, eof_token);
+}
+
 /* Parse (possibly empty) attributes.  This is a GNU extension.
 
    attributes:
@@ -3829,6 +3922,12 @@ 
 	  attr_name = c_parser_attribute_any_word (parser);
 	  if (attr_name == NULL)
 	    break;
+	  if (is_cilkplus_vector_p (attr_name))		  
+	    {
+	      c_token *v_token = c_parser_peek_token (parser);
+	      c_parser_cilk_simd_fn_vector_attrs (parser, *v_token);
+	      continue;
+	    }
 	  c_parser_consume_token (parser);
 	  if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN))
 	    {
@@ -3909,6 +4008,9 @@ 
 	}
       parser->lex_untranslated_string = false;
     }
+
+  if (flag_enable_cilkplus && !vec_safe_is_empty (parser->cilk_simd_fn_tokens))
+    c_finish_cilk_simd_fn_tokens (parser);
   return attrs;
 }
 
@@ -9532,6 +9634,8 @@ 
 	    result = PRAGMA_OMP_CLAUSE_MAP;
 	  else if (!strcmp ("mergeable", p))
 	    result = PRAGMA_OMP_CLAUSE_MERGEABLE;
+	  else if (flag_enable_cilkplus && !strcmp ("mask", p))
+	    result = PRAGMA_CILK_CLAUSE_MASK;
 	  break;
 	case 'n':
 	  if (!strcmp ("notinbranch", p))
@@ -9542,6 +9646,8 @@ 
 	    result = PRAGMA_OMP_CLAUSE_NUM_TEAMS;
 	  else if (!strcmp ("num_threads", p))
 	    result = PRAGMA_OMP_CLAUSE_NUM_THREADS;
+	  else if (flag_enable_cilkplus && !strcmp ("nomask", p))
+	    result = PRAGMA_CILK_CLAUSE_NOMASK;
 	  break;
 	case 'o':
 	  if (!strcmp ("ordered", p))
@@ -9585,6 +9691,10 @@ 
 	  else if (!strcmp ("untied", p))
 	    result = PRAGMA_OMP_CLAUSE_UNTIED;
 	  break;
+	case 'v':
+	  if (flag_enable_cilkplus && !strcmp ("vectorlength", p))
+	    result = PRAGMA_CILK_CLAUSE_VECTORLENGTH;
+	  break;
 	}
     }
 
@@ -10401,7 +10511,7 @@ 
    linear ( variable-list : expression ) */
 
 static tree
-c_parser_omp_clause_linear (c_parser *parser, tree list)
+c_parser_omp_clause_linear (c_parser *parser, tree list, bool is_cilk_simd_fn)
 {
   location_t clause_loc = c_parser_peek_token (parser)->location;
   tree nl, c, step;
@@ -10418,6 +10528,11 @@ 
       step = c_parser_expression (parser).value;
       mark_exp_read (step);
       step = c_fully_fold (step, false, NULL);
+      if (is_cilk_simd_fn && TREE_CODE (step) == PARM_DECL)
+	{
+	  sorry ("using parameters for %<linear%> step is not supported yet");
+	  step = integer_one_node;
+	}
       if (!INTEGRAL_TYPE_P (TREE_TYPE (step)))
 	{
 	  error_at (clause_loc, "%<linear%> clause step expression must "
@@ -10776,8 +10891,11 @@ 
 			  const char *where, bool finish_p = true)
 {
   tree clauses = NULL;
-  bool first = true;
-
+  bool first = true, cilk_simd_fn = false;
+  
+  if (where && !strcmp (where, "SIMD-enabled functions attribute"))
+    cilk_simd_fn = true;
+ 
   while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
     {
       location_t here;
@@ -10862,11 +10980,13 @@ 
 	  c_name = "untied";
 	  break;
 	case PRAGMA_OMP_CLAUSE_INBRANCH:
+	case PRAGMA_CILK_CLAUSE_MASK:
 	  clauses = c_parser_omp_clause_branch (parser, OMP_CLAUSE_INBRANCH,
 						clauses);
 	  c_name = "inbranch";
 	  break;
 	case PRAGMA_OMP_CLAUSE_NOTINBRANCH:
+	case PRAGMA_CILK_CLAUSE_NOMASK:
 	  clauses = c_parser_omp_clause_branch (parser, OMP_CLAUSE_NOTINBRANCH,
 						clauses);
 	  c_name = "notinbranch";
@@ -10932,8 +11052,8 @@ 
 	  clauses = c_parser_omp_clause_aligned (parser, clauses);
 	  c_name = "aligned";
 	  break;
-	case PRAGMA_OMP_CLAUSE_LINEAR:
-	  clauses = c_parser_omp_clause_linear (parser, clauses);
+	case PRAGMA_OMP_CLAUSE_LINEAR: 
+	  clauses = c_parser_omp_clause_linear (parser, clauses, cilk_simd_fn); 
 	  c_name = "linear";
 	  break;
 	case PRAGMA_OMP_CLAUSE_DEPEND:
@@ -10960,6 +11080,10 @@ 
 	  clauses = c_parser_omp_clause_safelen (parser, clauses);
 	  c_name = "safelen";
 	  break;
+	case PRAGMA_CILK_CLAUSE_VECTORLENGTH:
+	  clauses = c_parser_cilk_clause_vectorlength (parser, clauses, true);
+	  c_name = "simdlen";
+	  break;
 	case PRAGMA_OMP_CLAUSE_SIMDLEN:
 	  clauses = c_parser_omp_clause_simdlen (parser, clauses);
 	  c_name = "simdlen";
@@ -12754,10 +12878,19 @@ 
 c_finish_omp_declare_simd (c_parser *parser, tree fndecl, tree parms,
 			   vec<c_token> clauses)
 {
+  if (flag_enable_cilkplus
+      && clauses.exists () && !vec_safe_is_empty (parser->cilk_simd_fn_tokens))
+    {
+      error ("%<#pragma omp declare simd%> cannot be used in the same "
+	     "function marked as a Cilk Plus SIMD-enabled function");
+      vec_free (parser->cilk_simd_fn_tokens);
+      return;
+    }
+  
   /* Normally first token is CPP_NAME "simd".  CPP_EOF there indicates
      error has been reported and CPP_PRAGMA that c_finish_omp_declare_simd
      has already processed the tokens.  */
-  if (clauses[0].type == CPP_EOF)
+  if (clauses.exists () && clauses[0].type == CPP_EOF)
     return;
   if (fndecl == NULL_TREE || TREE_CODE (fndecl) != FUNCTION_DECL)
     {
@@ -12766,7 +12899,7 @@ 
       clauses[0].type = CPP_EOF;
       return;
     }
-  if (clauses[0].type != CPP_NAME)
+  if (clauses.exists () && clauses[0].type != CPP_NAME)
     {
       error_at (DECL_SOURCE_LOCATION (fndecl),
 		"%<#pragma omp declare simd%> not immediately followed by "
@@ -12780,23 +12913,49 @@ 
 
   unsigned int tokens_avail = parser->tokens_avail;
   gcc_assert (parser->tokens == &parser->tokens_buf[0]);
-  parser->tokens = clauses.address ();
-  parser->tokens_avail = clauses.length ();
-
+  bool is_cilkplus_cilk_simd_fn = false;
+  
+  if (flag_enable_cilkplus && !vec_safe_is_empty (parser->cilk_simd_fn_tokens))
+    {
+      parser->tokens = parser->cilk_simd_fn_tokens->address ();
+      parser->tokens_avail = vec_safe_length (parser->cilk_simd_fn_tokens);
+      is_cilkplus_cilk_simd_fn = true;
+    }
+  else
+    {
+      parser->tokens = clauses.address ();
+      parser->tokens_avail = clauses.length ();
+    }
+  
   /* c_parser_omp_declare_simd pushed 2 extra CPP_EOF tokens at the end.  */
   while (parser->tokens_avail > 3)
     {
       c_token *token = c_parser_peek_token (parser);
-      gcc_assert (token->type == CPP_NAME
-		  && strcmp (IDENTIFIER_POINTER (token->value), "simd") == 0);
+      if (!is_cilkplus_cilk_simd_fn) 
+	gcc_assert (token->type == CPP_NAME 
+		    && strcmp (IDENTIFIER_POINTER (token->value), "simd") == 0);
+      else
+	gcc_assert (token->type == CPP_NAME
+		    && is_cilkplus_vector_p (token->value));
       c_parser_consume_token (parser);
       parser->in_pragma = true;
 
-      tree c = c_parser_omp_all_clauses (parser, OMP_DECLARE_SIMD_CLAUSE_MASK,
-					 "#pragma omp declare simd");
+      tree c = NULL_TREE;
+      if (is_cilkplus_cilk_simd_fn) 
+	c = c_parser_omp_all_clauses (parser, CILK_SIMD_FN_CLAUSE_MASK,
+				      "SIMD-enabled functions attribute");
+      else 
+	c = c_parser_omp_all_clauses (parser, OMP_DECLARE_SIMD_CLAUSE_MASK,
+				      "#pragma omp declare simd");
       c = c_omp_declare_simd_clauses_to_numbers (parms, c);
       if (c != NULL_TREE)
 	c = tree_cons (NULL_TREE, c, NULL_TREE);
+      if (is_cilkplus_cilk_simd_fn) 
+	{ 
+	  tree k = build_tree_list (get_identifier ("cilk simd function"), c);
+	  TREE_CHAIN (k) = DECL_ATTRIBUTES (fndecl);
+	  DECL_ATTRIBUTES (fndecl) = k;
+	} 
       c = build_tree_list (get_identifier ("omp declare simd"), c);
       TREE_CHAIN (c) = DECL_ATTRIBUTES (fndecl);
       DECL_ATTRIBUTES (fndecl) = c;
@@ -12804,7 +12963,11 @@ 
 
   parser->tokens = &parser->tokens_buf[0];
   parser->tokens_avail = tokens_avail;
-  clauses[0].type = CPP_PRAGMA;
+  if (clauses.exists ())
+    clauses[0].type = CPP_PRAGMA;
+
+  if (!vec_safe_is_empty (parser->cilk_simd_fn_tokens))
+    vec_free (parser->cilk_simd_fn_tokens);
 }
 
 
@@ -13400,14 +13563,26 @@ 
 }
 
 /* Cilk Plus:
-   vectorlength ( constant-expression ) */
+   This function is shared by SIMD-enabled functions and #pragma simd.  
+   If IS_SIMD_FN is true then it is parsing a SIMD-enabled function and 
+   CLAUSES is unused.  The main purpose of this function is to parse a
+   vectorlength attribute or clause and check for parse errors.
+   When IS_SIMD_FN is true then the function is merely caching the tokens
+   in PARSER->CILK_SIMD_FN_TOKENS.  If errors are found then the token
+   cache is cleared since there is no reason to continue.
+   Syntax:
+   vectorlength ( constant-expression )  */
 
 static tree
-c_parser_cilk_clause_vectorlength (c_parser *parser, tree clauses)
+c_parser_cilk_clause_vectorlength (c_parser *parser, tree clauses, 
+				   bool is_simd_fn)
 {
+  if (is_simd_fn)
+    check_no_duplicate_clause (clauses, OMP_CLAUSE_SIMDLEN, "vectorlength");
+  else
   /* The vectorlength clause behaves exactly like OpenMP's safelen
      clause.  Represent it in OpenMP terms.  */
-  check_no_duplicate_clause (clauses, OMP_CLAUSE_SAFELEN, "vectorlength");
+    check_no_duplicate_clause (clauses, OMP_CLAUSE_SAFELEN, "vectorlength");
 
   if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
     return clauses;
@@ -13416,18 +13591,33 @@ 
   tree expr = c_parser_expr_no_commas (parser, NULL).value;
   expr = c_fully_fold (expr, false, NULL);
 
-  if (!TREE_TYPE (expr)
-      || !TREE_CONSTANT (expr)
-      || !INTEGRAL_TYPE_P (TREE_TYPE (expr)))
-    error_at (loc, "vectorlength must be an integer constant");
+  /* If expr is an error_mark_node then the above function would have
+     emitted an error.  No reason to do it twice.  */
+  if (expr == error_mark_node)
+    ;
+  else if (!TREE_TYPE (expr)
+	   || !TREE_CONSTANT (expr)
+	   || !INTEGRAL_TYPE_P (TREE_TYPE (expr)))
+  
+    error_at (loc, "vectorlength must be an integer constant");  
   else if (exact_log2 (TREE_INT_CST_LOW (expr)) == -1)
     error_at (loc, "vectorlength must be a power of 2");
   else
     {
-      tree u = build_omp_clause (loc, OMP_CLAUSE_SAFELEN);
-      OMP_CLAUSE_SAFELEN_EXPR (u) = expr;
-      OMP_CLAUSE_CHAIN (u) = clauses;
-      clauses = u;
+      if (is_simd_fn)
+	{
+	  tree u = build_omp_clause (loc, OMP_CLAUSE_SIMDLEN);
+	  OMP_CLAUSE_SIMDLEN_EXPR (u) = expr;
+	  OMP_CLAUSE_CHAIN (u) = clauses;
+	  clauses = u;
+	}
+      else
+	{
+	  tree u = build_omp_clause (loc, OMP_CLAUSE_SAFELEN);
+	  OMP_CLAUSE_SAFELEN_EXPR (u) = expr;
+	  OMP_CLAUSE_CHAIN (u) = clauses;
+	  clauses = u;
+	}
     }
 
   c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>");
@@ -13524,10 +13714,10 @@ 
    not consumed.  Otherwise, the appropriate pragma_simd_clause is
    returned and the token is consumed.  */
 
-static pragma_cilk_clause
+static pragma_omp_clause
 c_parser_cilk_clause_name (c_parser *parser)
 {
-  pragma_cilk_clause result;
+  pragma_omp_clause result;
   c_token *token = c_parser_peek_token (parser);
 
   if (!token->value || token->type != CPP_NAME)
@@ -13564,14 +13754,14 @@ 
 
   while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
     {
-      pragma_cilk_clause c_kind;
+      pragma_omp_clause c_kind;
 
       c_kind = c_parser_cilk_clause_name (parser);
 
       switch (c_kind)
 	{
 	case PRAGMA_CILK_CLAUSE_VECTORLENGTH:
-	  clauses = c_parser_cilk_clause_vectorlength (parser, clauses);
+	  clauses = c_parser_cilk_clause_vectorlength (parser, clauses, false);
 	  break;
 	case PRAGMA_CILK_CLAUSE_LINEAR:
 	  clauses = c_parser_cilk_clause_linear (parser, clauses);
Index: gcc/omp-low.c
===================================================================
--- gcc/omp-low.c	(revision 205759)
+++ gcc/omp-low.c	(working copy)
@@ -11300,7 +11300,7 @@ 
      declare simd".  */
   bool cilk_clone
     = (flag_enable_cilkplus
-       && lookup_attribute ("cilk plus elemental",
+       && lookup_attribute ("cilk simd function",
 			    DECL_ATTRIBUTES (node->decl)));
 
   /* Allocate one more than needed just in case this is an in-branch
Index: gcc/testsuite/gcc.dg/cilk-plus/cilk-plus.exp
===================================================================
--- gcc/testsuite/gcc.dg/cilk-plus/cilk-plus.exp	(revision 205759)
+++ gcc/testsuite/gcc.dg/cilk-plus/cilk-plus.exp	(working copy)
@@ -59,6 +59,10 @@ 
     dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/CK/*.c]] " -O3 -flto -g -fcilkplus" " "
 }
 
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/SE/*.c]] " -g" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/SE/*.c]] " -O3 -std=c99" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/SE/*.c]] " -O3 -g" " "
+
 dg-finish
 
 unset TEST_EXTRA_LIBS
Index: gcc/testsuite/c-c++-common/cilk-plus/SE/ef_error.c
===================================================================
--- gcc/testsuite/c-c++-common/cilk-plus/SE/ef_error.c	(revision 0)
+++ gcc/testsuite/c-c++-common/cilk-plus/SE/ef_error.c	(revision 0)
@@ -0,0 +1,32 @@ 
+/* { dg-do compile } */
+/* { dg-options "-fcilkplus -fopenmp" } */
+
+#pragma omp declare simd linear(y:1) simdlen(4) 
+__attribute__((vector (linear (y:1), vectorlength(4))))
+int func (int x, int y) { /* { dg-error "cannot be used in the same function marked as a Cilk Plus SIMD-enabled" } */ 
+  return (x+y);
+}
+__attribute__((vector (linear (y:1), private (x)))) /* { dg-error "is not valid for" } */
+int func2 (int x, int y) {
+  return (x+y);
+}
+
+__attribute__((vector (linear (y:1), simdlen (4)))) /* { dg-error "is not valid for" } */
+int func2_1 (int x, int y) {
+  return (x+y);
+}
+
+__attribute__((vector (linear (y:1), inbranch))) /* { dg-error "is not valid for" } */
+int func2_3 (int x, int y) {
+  return (x+y);
+}
+
+__attribute__((vector (notinbranch, vectorlength (4)))) /* { dg-error "is not valid for" } */
+int func2_2 (int x, int y) {
+  return (x+y);
+}
+
+int main (void)
+{
+  return (func (5,6));
+}
Index: gcc/testsuite/c-c++-common/cilk-plus/SE/vlength_errors.c
===================================================================
--- gcc/testsuite/c-c++-common/cilk-plus/SE/vlength_errors.c	(revision 0)
+++ gcc/testsuite/c-c++-common/cilk-plus/SE/vlength_errors.c	(revision 0)
@@ -0,0 +1,56 @@ 
+/* { dg-do compile } */
+/* { dg-options "-fcilkplus -Wunknown-pragmas" } */
+
+#define Q 4
+
+int z = Q;
+
+__attribute__ ((vector (uniform(x), vectorlength (), linear (y:1) ))) /* { dg-error "expected expression" } */
+int func2 (int x, int y)
+{
+  int zq = 5;
+  return x + (y*zq);
+}
+
+__attribute__ ((vector (uniform(x), linear (y:1), vectorlength (4.5) ))) /* { dg-error "vectorlength must be an integer" } */
+int func3 (int x, int y)
+{
+  int zq = 5;
+  return x + (y*zq);
+}
+
+__attribute__ ((vector (uniform(x), linear (y:1), vectorlength (z) ))) /* { dg-error "vectorlength must be an integer" } */
+int func4 (int x, int y)
+{
+  int zq = 5;
+  return x + (y*zq);
+}
+
+__attribute__ ((vector (uniform(x), linear (y:1), vectorlength (Q) ))) /* This is OK!  */
+int func5 (int x, int y)
+{
+  int zq = 5;
+  return x + (y*zq);
+}
+
+__attribute__ ((vector (uniform(x), vectorlength (z), linear (y:1)))) /* { dg-error "vectorlength must be an integer" } */
+int func6 (int x, int y)
+{
+  int zq = 5;
+  return x + (y*zq);
+}
+
+__attribute__ ((vector (uniform(x), linear (y:1), vectorlength (sizeof (int)) ))) /* This is OK too!  */
+int func7 (int x, int y)
+{
+  int zq = 5;
+  return x + (y*zq);
+}
+
+int main (void)
+{
+  int ii = 0, q = 5;
+  for (ii = 0; ii < 10; ii++)
+    q += func2 (z, ii);
+  return q;
+}
Index: gcc/testsuite/c-c++-common/cilk-plus/SE/ef_error2.c
===================================================================
--- gcc/testsuite/c-c++-common/cilk-plus/SE/ef_error2.c	(revision 0)
+++ gcc/testsuite/c-c++-common/cilk-plus/SE/ef_error2.c	(revision 0)
@@ -0,0 +1,14 @@ 
+/* { dg-do compile { target { i?86-*-* x86_64-*-* } } } */
+/* { dg-options "-fcilkplus -Wall" } */
+
+__attribute__((vector (vectorlength(32)))) 
+//#pragma omp simd simdlen (32)
+int func2 (int x, int y)  /* { dg-warning "unsupported simdlen" } */
+{
+  return (x+y);
+}
+
+int main (void)
+{
+  return (func2 (5,6));
+}
Index: gcc/testsuite/c-c++-common/cilk-plus/SE/ef_error3.c
===================================================================
--- gcc/testsuite/c-c++-common/cilk-plus/SE/ef_error3.c	(revision 0)
+++ gcc/testsuite/c-c++-common/cilk-plus/SE/ef_error3.c	(revision 0)
@@ -0,0 +1,13 @@ 
+/* { dg-do compile { target { i?86-*-* x86_64-*-* } } } */
+/* { dg-options "-fcilkplus -Wall" } */
+
+__attribute__((vector (linear (x:y))))
+int func2 (int x, int y) 
+{ /* { dg-message "using parameters for" } */
+  return (x+y);
+}
+
+int main (void)
+{
+  return (func2 (5,6));
+}
Index: gcc/testsuite/c-c++-common/cilk-plus/SE/ef_test.c
===================================================================
--- gcc/testsuite/c-c++-common/cilk-plus/SE/ef_test.c	(revision 0)
+++ gcc/testsuite/c-c++-common/cilk-plus/SE/ef_test.c	(revision 0)
@@ -0,0 +1,78 @@ 
+/* { dg-do compile } */
+/* { dg-options "-fcilkplus -Wunknown-pragmas" } */
+
+/* Tests the clauses in several combinations put in different locations.  */
+/* This is mostly a parser test.  */
+#define Q 4
+
+int z = Q;
+
+ __attribute__ ((vector (uniform(x), linear (y:1), vectorlength (4) )))
+int func (int x, int y)
+{
+  int zq = 5;
+  return x + (y*zq);
+}
+ __attribute__ ((__vector__ (uniform(x), vectorlength (2), linear (y:1) )))
+int func2 (int x, int y)
+{
+  int zq = 5;
+  return x + (y*zq);
+}
+
+__attribute__ ((vector (uniform(y), linear (x), vectorlength (4) )))
+int func3 (int x, int y)
+{
+  int zq = 5;
+  return x + (y*zq);
+}
+
+__attribute__ ((vector (uniform(x), linear (y:1), mask)))
+int func4 (int x, int y)
+{
+  int zq = 5;
+  return x + (y*zq);
+}
+
+__attribute__ ((vector (uniform(x), linear (y:1), nomask)))
+int func5 (int x, int y)
+{
+  int zq = 5;
+  return x + (y*zq);
+}
+
+__attribute__ ((vector (uniform(x), mask, linear (y:1)))) 
+int func6 (int x, int y)
+{
+  int zq = 5;
+  return x + (y*zq);
+}
+
+__attribute__ ((vector (uniform (x), mask, linear (y:1)), vector))
+int func7 (int x, int y)
+{
+  int zq = 5;
+  return x + (y*zq);
+}
+
+__attribute__ ((vector (uniform (x), mask, linear (y:1)), vector (uniform (y), mask)))
+int func8 (int x, int y)
+{
+  int zq = 5;
+  return x + (y*zq);
+}
+
+__attribute__ ((vector, vector (uniform (y), mask)))
+int func9 (int x, int y)
+{
+  int zq = 5;
+  return x + (y*zq);
+}
+
+int main (int argc, char *argv[])
+{
+  int ii = 0, q = 5;
+  for (ii = 0; ii < 10; ii++)
+    q += func (argc, ii);
+  return q;
+}
Index: gcc/testsuite/c-c++-common/cilk-plus/SE/ef_test2.c
===================================================================
--- gcc/testsuite/c-c++-common/cilk-plus/SE/ef_test2.c	(revision 0)
+++ gcc/testsuite/c-c++-common/cilk-plus/SE/ef_test2.c	(revision 0)
@@ -0,0 +1,16 @@ 
+/* { dg-do compile } */
+/* { dg-options "-fcilkplus" } */
+void func (int x, int y) __attribute__((vector(linear(x:1), uniform (y)),
+					vector));
+
+int q;
+int main (void)
+{
+  int ii = 0;
+  q = 5; 
+  for (ii = 0; ii < 100; ii++) 
+    func (ii, q);
+
+  return 0;
+}
+
Index: gcc/cp/parser.c
===================================================================
--- gcc/cp/parser.c	(revision 205759)
+++ gcc/cp/parser.c	(working copy)
@@ -31411,10 +31411,10 @@ 
    token is not consumed.  Otherwise, the appropriate enum from the
    pragma_simd_clause is returned and the token is consumed.  */
 
-static pragma_cilk_clause
+static pragma_omp_clause
 cp_parser_cilk_simd_clause_name (cp_parser *parser)
 {
-  pragma_cilk_clause clause_type;
+  pragma_omp_clause clause_type;
   cp_token *token = cp_lexer_peek_token (parser->lexer);
 
   if (token->keyword == RID_PRIVATE)
@@ -31448,7 +31448,7 @@ 
   while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL)
 	 && clauses != error_mark_node)
     {
-      pragma_cilk_clause c_kind;
+      pragma_omp_clause c_kind;
       c_kind = cp_parser_cilk_simd_clause_name (parser);
       if (c_kind == PRAGMA_CILK_CLAUSE_VECTORLENGTH)
 	clauses = cp_parser_cilk_simd_vectorlength (parser, clauses);