diff mbox

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

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

Commit Message

Iyer, Balaji V Dec. 1, 2013, 4:38 a.m. UTC
Hello Aldy,
	Some of the middle end changes I made in the previous patch was not flying for the C++. Here is a fixed patch where the middle-end changes will work for both C and C++.
	With this email, I am attaching the patch for C along with the middle end changes. Is this Ok for the branch?

Here are the ChangeLog entries:
gcc/ChangeLog
2013-11-30  Balaji V. Iyer  <balaji.v.iyer@intel.com>

        * omp-low.c (expand_simd_clones): Added a new parameter called "type."
        (ipa_omp_simd_clone): Added a call to expand_simd_clones when Cilk Plus
        is enabled.

gcc/c-family/ChangeLog
2013-11-30  Balaji V. Iyer  <balaji.v.iyer@intel.com>

        * c-common.c (c_common_attribute_table): Added "cilk plus elemental"
        attribute.

gcc/c/ChangeLog
2013-11-30  Balaji V. Iyer  <balaji.v.iyer@intel.com>

        * c-parser.c (struct c_parser::elem_fn_tokens): Added new field.
        (c_parser_declaration_or_fndef): Added a check if elem_fn_tokens
        field in parser is not empty.  If not-empty, call the function
        c_parser_finish_omp_declare_simd.
        (c_parser_elem_fn_vectorlength): New function.
        (c_parser_elem_fn_expr_list): Likewise.
        (c_finish_elem_fn_tokens): Likewise.
        (c_parser_attributes): Added a elem_fn_tokens parameter.  Added a
        check for vector attribute and if so call c_parser_elem_fn_expr_list.
        Also, called c_finish_elem_fn_tokens when Cilk Plus is enabled.
        (c_finish_omp_declare_simd): Added a check if elem_fn_tokens in
        parser field is non-empty.  If so, parse them as you would parse
        the omp declare simd pragma.

gcc/testsuite/ChangeLog
2013-11-30  Balaji V. Iyer  <balaji.v.iyer@intel.com>

        * c-c++-common/cilk-plus/EF/ef_test.c: New test.
        * c-c++-common/cilk-plus/EF/ef_test2.c: Likewise.
        * c-c++-common/cilk-plus/EF/vlength_errors.c: Likewise.
        * c-c++-common/cilk-plus/EF/ef_error.c: Likewise.
        * c-c++-common/cilk-plus/EF/ef_error2.c: Likewise.
        * gcc.dg/cilk-plus/cilk-plus.exp: Added calls for the above tests.

Thanks,

Balaji V. Iyer.


> -----Original Message-----
> From: Iyer, Balaji V
> Sent: Wednesday, November 27, 2013 1:15 PM
> To: aldyh@redhat.com
> Cc: Jakub Jelinek; gcc-patches@gcc.gnu.org
> Subject: RE: [PING]: [GOMP4] [PATCH] SIMD-Enabled Functions (formerly
> Elemental functions) for C
> 
> HI Aldy and Jakub,
> 	Attached, please find a fixed patch. I have fixed all the changes you
> have mentioned below. Is this OK to install?
> 
> Here are the ChangeLog entries:
> gcc/ChangeLog
> 2013-11-27  Balaji V. Iyer  <balaji.v.iyer@intel.com>
> 
>         * config/i386/i386.c (ix86_simd_clone_compute_vecsize_and_simdlen):
>         Removed a carriage return from the warning string.
>         * omp-low.c (simd_clone_clauses_extract): Added a check for cilk plus
>         SIMD-enabled function attributes.
> 
> gcc/c/ChangeLog
> 2013-11-27  Balaji V. Iyer  <balaji.v.iyer@intel.com>
> 
>         * c-parser.c (struct c_parser::elem_fn_tokens): Added new field.
>         (c_parser_declaration_or_fndef): Added a check if elem_fn_tokens
>         field in parser is not empty.  If not-empty, call the function
>         c_parser_finish_omp_declare_simd.
>         (c_parser_elem_fn_vectorlength): New function.
>         (c_parser_elem_fn_expr_list): Likewise.
>         (c_finish_elem_fn_tokens): Likewise.
>         (c_parser_attributes): Added a elem_fn_tokens parameter.  Added a
>         check for vector attribute and if so call c_parser_elem_fn_expr_list.
>         Also, called c_finish_elem_fn_tokens when Cilk Plus is enabled.
>         (c_finish_omp_declare_simd): Added a check if elem_fn_tokens in
>         parser field is non-empty.  If so, parse them as you would parse
>         the omp declare simd pragma.
> 
> gcc/testsuite/ChangeLog
> 2013-11-27  Balaji V. Iyer  <balaji.v.iyer@intel.com>
> 
>         * c-c++-common/cilk-plus/EF/ef_test.c: New test.
>         * c-c++-common/cilk-plus/EF/ef_test2.c: Likewise.
>         * c-c++-common/cilk-plus/EF/vlength_errors.c: Likewise.
>         * c-c++-common/cilk-plus/EF/ef_error.c: Likewise.
>         * c-c++-common/cilk-plus/EF/ef_error2.c: Likewise.
>         * gcc.dg/cilk-plus/cilk-plus.exp: Added calls for the above tests.
> 
> 
> Thanks,
> 
> Balaji V. Iyer.
> 
> > -----Original Message-----
> > From: Aldy Hernandez [mailto:aldyh@redhat.com]
> > Sent: Wednesday, November 27, 2013 10:52 AM
> > To: Iyer, Balaji V
> > Cc: Jakub Jelinek; gcc-patches@gcc.gnu.org
> > Subject: Re: [PING]: [GOMP4] [PATCH] SIMD-Enabled Functions (formerly
> > Elemental functions) for C
> >
> > "Iyer, Balaji V" <balaji.v.iyer@intel.com> writes:
> >
> > >  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-
> > >elem_fn_tokens))
> > > +    {
> > > +      error ("%<#pragma omp declare simd%> cannot be used in the
> same"
> > > +	     "function marked as a SIMD-enabled function");
> > > +      vec_free (parser->elem_fn_tokens);
> > > +      return;
> > > +    }
> >
> > I see Cilk Plus elementals are handled as omp declare simd in the
> > above function.  This function sets an "omp declare simd" attribute here:
> >
> >      if (c != NULL_TREE)
> >         c = tree_cons (NULL_TREE, c, NULL_TREE);
> >       c = build_tree_list (get_identifier ("omp declare simd"), c);
> >       TREE_CHAIN (c) = DECL_ATTRIBUTES (fndecl);
> >       DECL_ATTRIBUTES (fndecl) = c;
> >
> > but you also need a "cilk plus elemental" attribute so the rest of the
> > compiler can differentiate Cilk Plus elementals from omp declare simds.
> >
> 
> Fixed.
> 
> > See simd_clone_clauses_extract():
> >
> > +  /* To distinguish from an OpenMP simd clone, Cilk Plus functions to
> > +     be cloned have a distinctive artificial label in addition to "omp
> > +     declare simd".  */
> > +  bool cilk_clone
> > +    = (flag_enable_cilkplus
> > +       && lookup_attribute ("cilk plus elemental",
> > +                           DECL_ATTRIBUTES (node->decl)));
> >
> > Also you probably want some kind of test for this, so test for
> > whatever cilk_elemental is doing.  In trunk, the only use of
> > cilk_elemental is in ix86_simd_clone_compute_vecsize_and_simdlen(), so
> > come up with some
> > x86 specific test for cilk_elemental==true.
> >
> 
> Fixed.
> 
> > Aldy

Comments

Aldy Hernandez Dec. 5, 2013, 8:20 p.m. UTC | #1
On 11/30/13 20:38, Iyer, Balaji V wrote:
> Hello Aldy,
> 	Some of the middle end changes I made in the previous patch was not flying for the C++. Here is a fixed patch where the middle-end changes will work for both C and C++.
> 	With this email, I am attaching the patch for C along with the middle end changes. Is this Ok for the branch?

Jakub and company ultimately have to approve your patch, but here are a 
few things.

> +
> +  /* 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> *elem_fn_tokens;

If the name "elementals" is being phased out, then perhaps you need to 
come up with another name here.  Perhaps "cilk_simd_clone_tokens" or 
something that looks similar to the OpenMP variant 
"cilk_declare_simd_tokens" (akin to omp_declare_simd_clauses) in the 
rest of the patch.

Also, "Enabled" should not be capitalized.

> +/* Parses the vectorlength vector attribute for the SIMD Enabled functions
> +   in Cilk Plus.
> +   Syntax:
> +   vectorlength (<integer constant expression>)  */
> +
> +static bool
> +c_parser_elem_fn_vectorlength (c_parser *parser)

Similarly here.  Let's get rid of *elem* nomenclature throughout. 
Perhaps c_parser_cilk_declare_simd_vectorlength and similarly throughout 
the other parsing routines in the patch.  This will make it clearer that 
*cilk_declare_simd* is related to OpenMP's declare simd.

> +  if (TREE_CODE (value) != INTEGER_CST)
> +    {
> +      error_at (token->location, "vectorlength must be a constant integer");
> +      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
> +      return false;
> +    }

I thought integer constant expressions were allowed here.  Shouldn't 
things like "sizeof (int)" be allowed?  See what is done in 
c_parser_cilk_clause_vectorlength() which handles constant expressions. 
  Also, you will need a corresponding test.

For that matter... can't we combine the above function with 
c_parser_cilk_clause_vectorlength().  It doesn't make much sense having 
two functions parsing the exact same clause.  Perhaps add a flag to it 
and have it work in two modes: one mode to create OMP_CLAUSE_SAFELEN and 
one mode to fill the token vector.

> +              if (!c_parser_elem_fn_vectorlength (parser))
> +                {
> +                  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
> +                  /* NO reason to keep any of these tokens if the
> +                     vectorlength is messed up.  */
> +		  vec_free (parser->elem_fn_tokens);
> +                  return;

It may be cleaner to make the caller free the vector.

> +          /* linear and uniform are the same between SIMD
> +             enabled functions and #pragma omp declare simd.  */

Capitalize first word.

> +      /* Do not push the last ')'  */
> +      if (!(token->type == CPP_CLOSE_PAREN && paren_scope == 0))
> +	vec_safe_push (parser->elem_fn_tokens, *token);

You're documenting the obvious.  Perhaps a better comment would be to 
explain why you do not push the last ')'.

> +/* Parses the vector attribute of SIMD enabled functions in Cilk Plus.
> +   Syntax:
> +   vector
> +   vector (<vector attributes>).  */
> +
> +static void
> +c_parser_elem_fn_expr_list (c_parser *parser, c_token vec_token)

Please document the second argument.


> +  /* 2 EOF_token is added as a safety-net since the normal C front-end has
> +     two token look-ahead.  */

"Two EOF tokens are added..."

>  static void
> -expand_simd_clones (struct cgraph_node *node)
> +expand_simd_clones (struct cgraph_node *node, const char *type)

Document second argument, but perhaps we don't even need the second 
argument.  See below.

> @@ -12337,7 +12336,10 @@
>  {
>    struct cgraph_node *node;
>    FOR_EACH_FUNCTION (node)
> -    expand_simd_clones (node);
> +    expand_simd_clones (node, "omp declare simd");
> +  if (flag_enable_cilkplus)
> +    FOR_EACH_FUNCTION (node)
> +      expand_simd_clones (node, "cilk plus elemental");

First of all, it's a really bad idea to scan all the functions twice. 
You should have adapted expand_simd_clones() to do the work for both.

But even so, I don't think you need to do this at all.  Aren't Cilk Plus 
elementals supposed to be tagged as "omp declare simd" as well?  In 
which case expand_simd_clones() will DTRT.  It should...and then 
simd_clone_clauses_extract() already has the smarts to differentiate 
between the both variants.

Both OpenMP and Cilk Plus simd clones should have the "omp declare simd" 
attribute, and then Cilk Plus clones should *also* have the "cilk plus 
elemental" attribute.

Speak of which, we should probably rename the "cilk plus elemental" 
attribute throughout to "cilk plus declare simd" as I described earlier, 
but this is not your fault.  Bonus points if you want to do it as part 
of this patch :).

> +dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/EF/*.c]] " -g" " "
> +dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/EF/*.c]] " -O1" " "
> +dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/EF/*.c]] " -O2 -std=c99" " "
> +dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/EF/*.c]] " -O2 -ftree-vectorize" " "
> +dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/EF/*.c]] " -O3 -g" " "
> +

As I've mentioned before, I am really against running Cilk tests with 
all these variants.  It's time consuming for all developers and the 
chances of catching an error that is not caught with say... "-O0" are 
pretty close to 0.  Do you have any particular errors you think will be 
better checked by trying all these variants?  The time spent doesn't 
seem to be worth it.  If you have a particular test in mind, perhaps you 
should add that flag to the test itself.

For that matter, we should probably get rid of all the variant testing 
in the rest of Cilk Plus.

Furthermore, rename "EF" to something more readable and less dependent 
on "elementals" which is deprecated.  Perhaps "simd-clones" or something 
similar?

Aldy
diff mbox

Patch

Index: gcc/c-family/c-common.c
===================================================================
--- gcc/c-family/c-common.c	(revision 205560)
+++ 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 plus elemental",    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/c-parser.c
===================================================================
--- gcc/c/c-parser.c	(revision 205560)
+++ 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> *elem_fn_tokens;
 } c_parser;
 
 
@@ -1647,7 +1653,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->elem_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 +1741,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->elem_fn_tokens))
 		    c_finish_omp_declare_simd (parser, d, NULL_TREE,
 					       omp_declare_simd_clauses);
 		}
@@ -1746,7 +1754,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->elem_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 +1783,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->elem_fn_tokens))
 		{
 		  tree parms = NULL_TREE;
 		  if (d && TREE_CODE (d) == FUNCTION_DECL)
@@ -1902,7 +1912,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->elem_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 +3776,147 @@ 
   return attr_name;
 }
 
+/* Parses the vectorlength vector attribute for the SIMD Enabled functions
+   in Cilk Plus.
+   Syntax:
+   vectorlength (<integer constant expression>)  */
+
+static bool
+c_parser_elem_fn_vectorlength (c_parser *parser)
+{
+  c_token *token = c_parser_peek_token (parser);
+  gcc_assert (simple_cst_equal (token->value,
+                                get_identifier ("vectorlength")) == 1);
+  token->value = get_identifier ("simdlen");
+  vec_safe_push (parser->elem_fn_tokens, *token);
+
+  c_parser_consume_token (parser);
+
+  token = c_parser_peek_token (parser);
+  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    return false;
+
+  vec_safe_push (parser->elem_fn_tokens, *token);
+  token = c_parser_peek_token (parser);
+  tree value = token->value;
+  if (!value)
+    {
+      error_at (token->location, "expected vectorlength value");
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+      return false;
+    }
+  c_parser_consume_token (parser);
+  if (TREE_CODE (value) != INTEGER_CST)
+    {
+      error_at (token->location, "vectorlength must be a constant integer");
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+      return false;
+    }
+  if (!integer_pow2p (value))
+    {
+      error_at (token->location, "vectorlength must be a power of 2");
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+      return false;
+    }
+  vec_safe_push (parser->elem_fn_tokens, *token);
+
+  token = c_parser_peek_token (parser);
+  if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
+    return false;
+  vec_safe_push (parser->elem_fn_tokens, *token);
+  return true;
+}
+
+/* Parses the vector attribute of SIMD enabled functions in Cilk Plus.
+   Syntax:
+   vector
+   vector (<vector attributes>).  */
+
+static void
+c_parser_elem_fn_expr_list (c_parser *parser, c_token vec_token)
+{
+  gcc_assert (simple_cst_equal (vec_token.value,
+                                get_identifier ("vector")) == 1);
+  int paren_scope = 0;
+  /* Replace the vector keyword with SIMD.  */
+  vec_token.value = get_identifier ("simd");
+  vec_safe_push (parser->elem_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--;
+      if (token->type == CPP_NAME
+          && TREE_CODE (token->value) == IDENTIFIER_NODE)
+        {
+          tree value = token->value;
+          if (simple_cst_equal (value, get_identifier ("mask")) == 1)
+            token->value = get_identifier ("inbranch");
+          else if (simple_cst_equal (value, get_identifier ("nomask")) == 1)
+            token->value = get_identifier ("notinbranch");
+          else if (simple_cst_equal (value,
+                                     get_identifier ("vectorlength")) == 1)
+            {
+              if (!c_parser_elem_fn_vectorlength (parser))
+                {
+                  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+                  /* NO reason to keep any of these tokens if the
+                     vectorlength is messed up.  */
+		  vec_free (parser->elem_fn_tokens);
+                  return;
+                }
+              else
+                continue;
+            }
+          /* linear and uniform are the same between SIMD
+             enabled functions and #pragma omp declare simd.  */
+        }
+      /* Do not push the last ')'  */
+      if (!(token->type == CPP_CLOSE_PAREN && paren_scope == 0))
+	vec_safe_push (parser->elem_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->elem_fn_tokens, eol_token);
+  return;
+}
+
+/* Add 2 CPP_EOF at the end of PARSER->ELEM_FN_TOKENS vector.  */
+
+static void
+c_finish_elem_fn_tokens (c_parser *parser)
+{
+  c_token last_token = parser->elem_fn_tokens->last ();
+
+  /* c_parser_attributes is called in several places, and so if these EOF
+     tokens are already inserted, then don't do them again.  */
+  if (last_token.type == CPP_EOF)
+    return;
+  
+  /* 2 EOF_token is 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->elem_fn_tokens, eof_token);
+  vec_safe_push (parser->elem_fn_tokens, eof_token);
+}
+
 /* Parse (possibly empty) attributes.  This is a GNU extension.
 
    attributes:
@@ -3829,6 +3981,13 @@ 
 	  attr_name = c_parser_attribute_any_word (parser);
 	  if (attr_name == NULL)
 	    break;
+	  if (flag_enable_cilkplus
+	      && simple_cst_equal (attr_name, get_identifier ("vector")) == 1)
+	    {
+	      c_token *v_token = c_parser_peek_token (parser);
+	      c_parser_elem_fn_expr_list (parser, *v_token);
+	      continue;
+	    }
 	  c_parser_consume_token (parser);
 	  if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN))
 	    {
@@ -3909,6 +4068,9 @@ 
 	}
       parser->lex_untranslated_string = false;
     }
+
+  if (flag_enable_cilkplus && !vec_safe_is_empty (parser->elem_fn_tokens))
+    c_finish_elem_fn_tokens (parser);
   return attrs;
 }
 
@@ -12754,10 +12916,20 @@ 
 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->elem_fn_tokens))
+    {
+      error ("%<#pragma omp declare simd%> cannot be used in the same "
+	     "function marked as a SIMD-enabled function");
+      vec_free (parser->elem_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 +12938,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,9 +12952,20 @@ 
 
   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_elem_fn = false;
+  
+  if (flag_enable_cilkplus && !vec_safe_is_empty (parser->elem_fn_tokens))
+    {
+      parser->tokens = parser->elem_fn_tokens->address ();
+      parser->tokens_avail = vec_safe_length (parser->elem_fn_tokens);
+      is_cilkplus_elem_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)
     {
@@ -12792,19 +12975,31 @@ 
       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_elem_fn) 
+	c = c_parser_omp_all_clauses (parser, OMP_DECLARE_SIMD_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);
-      c = build_tree_list (get_identifier ("omp declare simd"), c);
+      if (is_cilkplus_elem_fn)
+	c = build_tree_list (get_identifier ("cilk plus elemental"), c);
+      else
+	c = build_tree_list (get_identifier ("omp declare simd"), c);
       TREE_CHAIN (c) = DECL_ATTRIBUTES (fndecl);
       DECL_ATTRIBUTES (fndecl) = c;
     }
 
   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->elem_fn_tokens))
+    vec_free (parser->elem_fn_tokens);
 }
 
 
Index: gcc/omp-low.c
===================================================================
--- gcc/omp-low.c	(revision 205560)
+++ gcc/omp-low.c	(working copy)
@@ -12241,13 +12241,12 @@ 
    create the appropriate SIMD clones.  */
 
 static void
-expand_simd_clones (struct cgraph_node *node)
+expand_simd_clones (struct cgraph_node *node, const char *type)
 {
   if (lookup_attribute ("noclone", DECL_ATTRIBUTES (node->decl)))
     return;
 
-  tree attr = lookup_attribute ("omp declare simd",
-				DECL_ATTRIBUTES (node->decl));
+  tree attr = lookup_attribute (type, DECL_ATTRIBUTES (node->decl));
   if (!attr || targetm.simd_clone.compute_vecsize_and_simdlen == NULL)
     return;
   /* Ignore
@@ -12327,7 +12326,7 @@ 
 	    }
 	}
     }
-  while ((attr = lookup_attribute ("omp declare simd", TREE_CHAIN (attr))));
+  while ((attr = lookup_attribute (type, TREE_CHAIN (attr))));
 }
 
 /* Entry point for IPA simd clone creation pass.  */
@@ -12337,7 +12336,10 @@ 
 {
   struct cgraph_node *node;
   FOR_EACH_FUNCTION (node)
-    expand_simd_clones (node);
+    expand_simd_clones (node, "omp declare simd");
+  if (flag_enable_cilkplus)
+    FOR_EACH_FUNCTION (node)
+      expand_simd_clones (node, "cilk plus elemental");
   return 0;
 }
 
Index: gcc/testsuite/gcc.dg/cilk-plus/cilk-plus.exp
===================================================================
--- gcc/testsuite/gcc.dg/cilk-plus/cilk-plus.exp	(revision 205560)
+++ gcc/testsuite/gcc.dg/cilk-plus/cilk-plus.exp	(working copy)
@@ -59,6 +59,12 @@ 
     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/EF/*.c]] " -g" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/EF/*.c]] " -O1" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/EF/*.c]] " -O2 -std=c99" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/EF/*.c]] " -O2 -ftree-vectorize" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/EF/*.c]] " -O3 -g" " "
+
 dg-finish
 
 unset TEST_EXTRA_LIBS
Index: gcc/testsuite/c-c++-common/cilk-plus/EF/vlength_errors.c
===================================================================
--- gcc/testsuite/c-c++-common/cilk-plus/EF/vlength_errors.c	(revision 0)
+++ gcc/testsuite/c-c++-common/cilk-plus/EF/vlength_errors.c	(revision 0)
@@ -0,0 +1,49 @@ 
+/* { 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 vectorlength value" } */
+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 a constant 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 a constant 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 a constant integer" } */
+int func6 (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/EF/ef_error.c
===================================================================
--- gcc/testsuite/c-c++-common/cilk-plus/EF/ef_error.c	(revision 0)
+++ gcc/testsuite/c-c++-common/cilk-plus/EF/ef_error.c	(revision 0)
@@ -0,0 +1,18 @@ 
+/* { 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 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);
+}
+
+
+int main (void)
+{
+  return (func (5,6));
+}
Index: gcc/testsuite/c-c++-common/cilk-plus/EF/ef_error2.c
===================================================================
--- gcc/testsuite/c-c++-common/cilk-plus/EF/ef_error2.c	(revision 0)
+++ gcc/testsuite/c-c++-common/cilk-plus/EF/ef_error2.c	(revision 0)
@@ -0,0 +1,13 @@ 
+/* { dg-do compile { target { i?86-*-* x86_64-*-* } } } */
+/* { dg-options "-fcilkplus -Wall" } */
+
+__attribute__((vector (vectorlength(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/EF/ef_test.c
===================================================================
--- gcc/testsuite/c-c++-common/cilk-plus/EF/ef_test.c	(revision 0)
+++ gcc/testsuite/c-c++-common/cilk-plus/EF/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/EF/ef_test2.c
===================================================================
--- gcc/testsuite/c-c++-common/cilk-plus/EF/ef_test2.c	(revision 0)
+++ gcc/testsuite/c-c++-common/cilk-plus/EF/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;
+}
+