diff mbox

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

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

Commit Message

Iyer, Balaji V Nov. 18, 2013, 10:35 p.m. UTC
Hello Everyone,	
	Attached, please find a patch that will implement SIMD enabled functions for C targeting the gomp-4_0-branch. Here are the ChangeLog entries. Is this OK to install?

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

        * c-parser.c (c_parser_declaration_or_fndef): Added a check for
        attribute keyword before the function name.  If so, call the function
        to parse attributes.  Added a NULL parameter for c_parser_attributes.
        (c_parser_declspecs): Added a NULL parameter for c_parser_attributes.
        (c_parser_enum_specifier): Likewise.
        (c_parser_struct_or_union_specifier): Likewise.
        (c_parser_struct_declaration): Likewise.
        (c_parser_direct_declarator): Likewise.
        (c_parser_direct_declarator_inner): Likewise.
        (c_parser_parms_list_declarator): Likewise.
        (c_parser_parameter_declaration): Likewise.
        (c_parser_label): Likewise.
        (c_parser_objc_maybe_method_attributes): Likewise.
        (c_parser_objc_method_decl): Likewise.
        (c_parser_transaction_attributes): Likewise.
        (c_parser_elem_fn_vectorlength): New function.
        (c_parser_elem_fn_expr_list): Likewise.
        (c_finish_elem_fn_tokens): Likewise.
        (c_parser_elem_fn_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.

testsuite/ChangeLog
2013-11-18  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/vlength_errors.c: Likewise.
        * gcc.dg/cilk-plus/cilk-plus.exp: Added calls for the above tests.


Thanks,

Balaji V. Iyer.

Comments

Jakub Jelinek Nov. 19, 2013, 9:10 a.m. UTC | #1
On Mon, Nov 18, 2013 at 10:35:50PM +0000, Iyer, Balaji V wrote:
> Attached, please find a patch that will implement SIMD enabled functions
> for C targeting the gomp-4_0-branch.  Here are the ChangeLog entries.  Is
> this OK to install?

Have you tested say:
int func9 (int x, int y) __attribute__ ((vector (uniform (y), mask)));
?  I mean, mostly you pass NULL to c_parser_attributes as the new argument,
but then dereference it unconditionally.

You should error out if a function has
#pragma omp declare simd
and
vector attribute, defining what it means doesn't make sense.

Also, I'm not sure I like doing the transformation from Cilk+ to OpenMP
syntax through rewriting tokens, rather than at the parsing level.
After all, the Cilk+ syntax is quite different, even when the patch pretends
it is the same, consider e.g. the linear clause, which in Cilk+ allows
to refer to an argument, in OpenMP doesn't.

Also, I wonder if you couldn't save the tokens wrapped into some tree
temporarily into the attribute, rather than having to adjust
c_parser_attribute callers.  Joseph, what do you prefer here?

> @@ -1502,9 +1502,17 @@
>        c_parser_peek_token (parser)->value = error_mark_node;
>        fndef_ok = !nested;
>      }
> +  /* In Cilk Plus SIMD-enabled functions (formerly known as Elemental
> +     Functions), attributes are used right above the functoin declaration or
> +     the function itself.  */

Spelling.

> +  tree attrs = NULL_TREE;
> +  if (flag_enable_cilkplus
> +      && c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
> +    attrs = c_parser_attributes (parser, &omp_declare_simd_clauses);

This looks wrong, parsing of the attributes is supposed to be done
in c_parser_declspecs and can be intermixed with various other tokens
(e.g. static, extern, etc.).

>    c_parser_declspecs (parser, specs, true, true, start_attr_ok,
>  		      true, true, cla_nonabstract_decl);
> +  specs->attrs = chainon (attrs, specs->attrs);
>    if (parser->error)
>      {
>        c_parser_skip_to_end_of_block_or_statement (parser);
> +    /* Since we are converting an attribute to a pragma, we need to end the
> +     attribute with PRAGMA_EOL.  OpenMP guys would like to have 2 CPP_EOF
> +     at the end, and so we insert that also.  */

Comment wrongly indented.  It isn't about me who likes to have there
2 CPP_EOF, but just a safety net, because normally C FE has two tokens
look-ahead.

	Jakub
Iyer, Balaji V Nov. 19, 2013, 3:13 p.m. UTC | #2
> Also, I'm not sure I like doing the transformation from Cilk+ to OpenMP
> syntax through rewriting tokens, rather than at the parsing level.
> After all, the Cilk+ syntax is quite different, even when the patch pretends it
> is the same, consider e.g. the linear clause, which in Cilk+ allows to refer to an
> argument, in OpenMP doesn't.
> 

Actually, that is the only thing that I can think of that Cilk Plus elemental function is different from OpenMP. At this release, we are not planning to support it..
Joseph Myers Nov. 19, 2013, 4:13 p.m. UTC | #3
On Tue, 19 Nov 2013, Jakub Jelinek wrote:

> Also, I wonder if you couldn't save the tokens wrapped into some tree
> temporarily into the attribute, rather than having to adjust
> c_parser_attribute callers.  Joseph, what do you prefer here?

I think including whatever parsed data is relevant to this attribute in 
the structure returned by c_parser_attributes (which is currently a tree) 
would indeed be better.  (If you don't want to put it in a tree, you get 
to deal with converting attributes away from TREE_LISTs to a better 
structure, which is certainly desirable - as a separate self-contained 
patch - but probably a fair amount of work.  A very old (2004) attempt at 
changing how attributes are represented is on static-tree-branch, but I 
think it's old enough it would only give ideas rather than particularly 
useful patches.)

Note that in any case you should use is_attribute_p for a test for whether 
an identifier matches a particular attribute.
Jakub Jelinek Nov. 19, 2013, 4:31 p.m. UTC | #4
On Tue, Nov 19, 2013 at 04:13:34PM +0000, Joseph S. Myers wrote:
> On Tue, 19 Nov 2013, Jakub Jelinek wrote:
> 
> > Also, I wonder if you couldn't save the tokens wrapped into some tree
> > temporarily into the attribute, rather than having to adjust
> > c_parser_attribute callers.  Joseph, what do you prefer here?
> 
> I think including whatever parsed data is relevant to this attribute in 
> the structure returned by c_parser_attributes (which is currently a tree) 

Well, it has to have an array of tokens, because it can't be parsed
until the arguments of the function (which may come afterwards) are parsed.
But IMHO it can be just created as vec<..., va_gc> of the tokens and pointer
to that added to some magic tree code, or could be kept in an on-the-size
data structure (say, put in an INTEGER_CST index into some vector inside of
c_parser into the vector attribute argument temporarily, push the tokens
into that vector and release it from the vector after parsing the function
parameters (where OpenMP #pragma omp declare simd is parsed right now).
That parsing then transforms it into a normal tree arguments.

	Jakub
Iyer, Balaji V Nov. 19, 2013, 4:54 p.m. UTC | #5
> -----Original Message-----
> From: Jakub Jelinek [mailto:jakub@redhat.com]
> Sent: Tuesday, November 19, 2013 11:31 AM
> To: Joseph S. Myers
> Cc: Iyer, Balaji V; gcc-patches@gcc.gnu.org; Aldy Hernandez
> (aldyh@redhat.com); Jeff Law
> Subject: Re: [GOMP4] [PATCH] SIMD-Enabled Functions (formerly Elemental
> functions) for C
> 
> On Tue, Nov 19, 2013 at 04:13:34PM +0000, Joseph S. Myers wrote:
> > On Tue, 19 Nov 2013, Jakub Jelinek wrote:
> >
> > > Also, I wonder if you couldn't save the tokens wrapped into some
> > > tree temporarily into the attribute, rather than having to adjust
> > > c_parser_attribute callers.  Joseph, what do you prefer here?
> >
> > I think including whatever parsed data is relevant to this attribute
> > in the structure returned by c_parser_attributes (which is currently a
> > tree)
> 
> Well, it has to have an array of tokens, because it can't be parsed until the
> arguments of the function (which may come afterwards) are parsed.
> But IMHO it can be just created as vec<..., va_gc> of the tokens and pointer
> to that added to some magic tree code, or could be kept in an on-the-size
> data structure (say, put in an INTEGER_CST index into some vector inside of
> c_parser into the vector attribute argument temporarily, push the tokens
> into that vector and release it from the vector after parsing the function
> parameters (where OpenMP #pragma omp declare simd is parsed right
> now).
> That parsing then transforms it into a normal tree arguments.
> 

I just need a clarification, so I am sorry if I am making you repeat:

Right now, the array of tokens (vec<c_token> elem_fn_tokens) is passed in as a parameter and then passed back to the c_parser_declaration_or_fndef function.

Instead of that, you would like this information to be stored in parser->specs (using the c_parser_declspecs function) and then have my own routine that will go through these tokens and store them in the DECL_ATTRIBUTES (very similar to what c_finish_omp_declare_simd does).

Am I correct? Did I mistake anything?

Thanks,

Balaji V. Iyer.

> 	Jakub
Jakub Jelinek Nov. 19, 2013, 4:59 p.m. UTC | #6
On Tue, Nov 19, 2013 at 04:54:29PM +0000, Iyer, Balaji V wrote:
> I just need a clarification, so I am sorry if I am making you repeat:
> 
> Right now, the array of tokens (vec<c_token> elem_fn_tokens) is passed in
> as a parameter and then passed back to the c_parser_declaration_or_fndef
> function.
> 
> Instead of that, you would like this information to be stored in
> parser->specs (using the c_parser_declspecs function) and then have my own

No, somewhere in *parser, it can be a new field with vector of the
vec<c_token, va_gc> vectors or similar and store something that can be
used to find that out into vector attribute argument.  Then at the spot
where the #pragma omp declare simd tokens are parsed right now (when
arguments are finally available) you could look up the vector attribute
and parse the corresponding tokens.

	Jakub
Iyer, Balaji V Nov. 19, 2013, 5:24 p.m. UTC | #7
> -----Original Message-----
> From: Jakub Jelinek [mailto:jakub@redhat.com]
> Sent: Tuesday, November 19, 2013 12:00 PM
> To: Iyer, Balaji V
> Cc: Joseph S. Myers; gcc-patches@gcc.gnu.org; Aldy Hernandez
> (aldyh@redhat.com); Jeff Law
> Subject: Re: [GOMP4] [PATCH] SIMD-Enabled Functions (formerly Elemental
> functions) for C
> 
> On Tue, Nov 19, 2013 at 04:54:29PM +0000, Iyer, Balaji V wrote:
> > I just need a clarification, so I am sorry if I am making you repeat:
> >
> > Right now, the array of tokens (vec<c_token> elem_fn_tokens) is passed
> > in as a parameter and then passed back to the
> > c_parser_declaration_or_fndef function.
> >
> > Instead of that, you would like this information to be stored in
> > parser->specs (using the c_parser_declspecs function) and then have my
> > parser->own
> 
> No, somewhere in *parser, it can be a new field with vector of the
> vec<c_token, va_gc> vectors or similar and store something that can be used
> to find that out into vector attribute argument.  Then at the spot where the
> #pragma omp declare simd tokens are parsed right now (when arguments
> are finally available) you could look up the vector attribute and parse the
> corresponding tokens.
> 

Thanks for helping me with this! I guess this is similar to what you are doing in C++.

Is it OK if I store the entire token list of vectors? It is not a lot of tokens and it is only there for a short period of time, and will release it as soon as I am done with it.

-Balaji V. Iyer.


> 	Jakub
diff mbox

Patch

Index: gcc/c/c-parser.c
===================================================================
--- gcc/c/c-parser.c	(revision 204981)
+++ gcc/c/c-parser.c	(working copy)
@@ -1148,7 +1148,7 @@ 
 							  tree);
 static struct c_parm *c_parser_parameter_declaration (c_parser *, tree);
 static tree c_parser_simple_asm_expr (c_parser *);
-static tree c_parser_attributes (c_parser *);
+static tree c_parser_attributes (c_parser *, vec <c_token> *);
 static struct c_type_name *c_parser_type_name (c_parser *);
 static struct c_expr c_parser_initializer (c_parser *);
 static struct c_expr c_parser_braced_init (c_parser *, tree, bool);
@@ -1502,9 +1502,17 @@ 
       c_parser_peek_token (parser)->value = error_mark_node;
       fndef_ok = !nested;
     }
+  /* In Cilk Plus SIMD-enabled functions (formerly known as Elemental
+     Functions), attributes are used right above the functoin declaration or
+     the function itself.  */
+  tree attrs = NULL_TREE;
+  if (flag_enable_cilkplus
+      && c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
+    attrs = c_parser_attributes (parser, &omp_declare_simd_clauses);
 
   c_parser_declspecs (parser, specs, true, true, start_attr_ok,
 		      true, true, cla_nonabstract_decl);
+  specs->attrs = chainon (attrs, specs->attrs);
   if (parser->error)
     {
       c_parser_skip_to_end_of_block_or_statement (parser);
@@ -1676,7 +1684,7 @@ 
 	  if (c_parser_next_token_is_keyword (parser, RID_ASM))
 	    asm_name = c_parser_simple_asm_expr (parser);
 	  if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
-	    postfix_attrs = c_parser_attributes (parser);
+	    postfix_attrs = c_parser_attributes (parser, NULL);
 	  if (c_parser_next_token_is (parser, CPP_EQ))
 	    {
 	      tree d;
@@ -1815,7 +1823,7 @@ 
 		}
 	      c_parser_consume_token (parser);
 	      if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
-		all_prefix_attrs = chainon (c_parser_attributes (parser),
+		all_prefix_attrs = chainon (c_parser_attributes (parser, NULL),
 					    prefix_attrs);
 	      else
 		all_prefix_attrs = prefix_attrs;
@@ -2403,7 +2411,7 @@ 
 	case RID_ATTRIBUTE:
 	  if (!attrs_ok)
 	    goto out;
-	  attrs = c_parser_attributes (parser);
+	  attrs = c_parser_attributes (parser, NULL);
 	  declspecs_add_attrs (loc, specs, attrs);
 	  break;
 	case RID_ALIGNAS:
@@ -2452,7 +2460,7 @@ 
   gcc_assert (c_parser_next_token_is_keyword (parser, RID_ENUM));
   enum_loc = c_parser_peek_token (parser)->location;
   c_parser_consume_token (parser);
-  attrs = c_parser_attributes (parser);
+  attrs = c_parser_attributes (parser, NULL);
   enum_loc = c_parser_peek_token (parser)->location;
   /* Set the location in case we create a decl now.  */
   c_parser_set_source_position_from_token (c_parser_peek_token (parser));
@@ -2532,7 +2540,7 @@ 
 	      break;
 	    }
 	}
-      postfix_attrs = c_parser_attributes (parser);
+      postfix_attrs = c_parser_attributes (parser, NULL);
       ret.spec = finish_enum (type, nreverse (values),
 			      chainon (attrs, postfix_attrs));
       ret.kind = ctsk_tagdef;
@@ -2623,7 +2631,7 @@ 
     }
   struct_loc = c_parser_peek_token (parser)->location;
   c_parser_consume_token (parser);
-  attrs = c_parser_attributes (parser);
+  attrs = c_parser_attributes (parser, NULL);
 
   /* Set the location in case we create a decl now.  */
   c_parser_set_source_position_from_token (c_parser_peek_token (parser));
@@ -2735,7 +2743,7 @@ 
 	         recovered already.  Go on with the next field. */
 	    }
 	}
-      postfix_attrs = c_parser_attributes (parser);
+      postfix_attrs = c_parser_attributes (parser, NULL);
       ret.spec = finish_struct (struct_loc, type, nreverse (contents),
 				chainon (attrs, postfix_attrs), struct_info);
       ret.kind = ctsk_tagdef;
@@ -2904,7 +2912,7 @@ 
 	      width = c_parser_expr_no_commas (parser, NULL).value;
 	    }
 	  if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
-	    postfix_attrs = c_parser_attributes (parser);
+	    postfix_attrs = c_parser_attributes (parser, NULL);
 	  d = grokfield (c_parser_peek_token (parser)->location,
 			 declarator, specs, width, &all_prefix_attrs);
 	  decl_attributes (&d, chainon (postfix_attrs,
@@ -2912,7 +2920,7 @@ 
 	  DECL_CHAIN (d) = decls;
 	  decls = d;
 	  if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
-	    all_prefix_attrs = chainon (c_parser_attributes (parser),
+	    all_prefix_attrs = chainon (c_parser_attributes (parser, NULL),
 					prefix_attrs);
 	  else
 	    all_prefix_attrs = prefix_attrs;
@@ -3226,7 +3234,7 @@ 
       tree attrs;
       struct c_declarator *inner;
       c_parser_consume_token (parser);
-      attrs = c_parser_attributes (parser);
+      attrs = c_parser_attributes (parser, NULL);
       if (kind != C_DTR_NORMAL
 	  && (c_parser_next_token_starts_declspecs (parser)
 	      || c_parser_next_token_is (parser, CPP_CLOSE_PAREN)))
@@ -3382,7 +3390,7 @@ 
       tree attrs;
       struct c_arg_info *args;
       c_parser_consume_token (parser);
-      attrs = c_parser_attributes (parser);
+      attrs = c_parser_attributes (parser, NULL);
       args = c_parser_parms_declarator (parser, id_present, attrs);
       if (args == NULL)
 	return NULL;
@@ -3529,7 +3537,7 @@ 
 	  tree new_attrs;
 	  c_parser_consume_token (parser);
 	  mark_forward_parm_decls ();
-	  new_attrs = c_parser_attributes (parser);
+	  new_attrs = c_parser_attributes (parser, NULL);
 	  return c_parser_parms_list_declarator (parser, new_attrs, expr);
 	}
       if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
@@ -3623,7 +3631,7 @@ 
       return NULL;
     }
   if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
-    postfix_attrs = c_parser_attributes (parser);
+    postfix_attrs = c_parser_attributes (parser, NULL);
   return build_c_parm (specs, chainon (postfix_attrs, prefix_attrs),
 		       declarator);
 }
@@ -3760,6 +3768,148 @@ 
   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, vec <c_token> *token_list)
+{
+  c_token *token = c_parser_peek_token (parser);
+  gcc_assert (simple_cst_equal (token->value,
+                                get_identifier ("vectorlength")) == 1);
+  token->value = get_identifier ("simdlen");
+  token_list->safe_push (*token);
+
+  c_parser_consume_token (parser);
+
+  token = c_parser_peek_token (parser);
+  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    return false;
+
+  token_list->safe_push (*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;
+    }
+  token_list->safe_push (*token);
+
+  token = c_parser_peek_token (parser);
+  if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
+    return false;
+  token_list->safe_push (*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,
+                            vec <c_token> *elem_fn_tokens)
+{
+  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");
+  elem_fn_tokens->safe_push (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, elem_fn_tokens))
+                {
+                  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+                  /* No reason to keep any of these tokens if the
+                     vectorlength is messed up.  */
+                  elem_fn_tokens->release ();
+                  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))
+        elem_fn_tokens->safe_push (*token);
+      c_parser_consume_token (parser);
+    }
+  c_token eol_token;
+  memset (&eol_token, 0, sizeof (eol_token));
+  eol_token.type = CPP_PRAGMA_EOL;
+  elem_fn_tokens->safe_push (eol_token);
+  return;
+}
+
+/* Add 2 CPP_EOF at the end of ELEM_FN_TOKENS vector.  */
+
+static void
+c_finish_elem_fn_tokens (vec <c_token> *elem_fn_tokens)
+{
+  /* If the token is a CPP_EOF, then there is no reason to stuff it again
+     with 2 EOF.  If it is NULL, then we didn't find any vector keywords.  */
+  if (!elem_fn_tokens || *elem_fn_tokens == vNULL 
+      || (*elem_fn_tokens)[0].type == CPP_EOF)
+    return;
+    /* Since we are converting an attribute to a pragma, we need to end the
+     attribute with PRAGMA_EOL.  OpenMP guys would like to have 2 CPP_EOF
+     at the end, and so we insert that also.  */
+  c_token eof_token;
+  memset (&eof_token, 0, sizeof (eof_token));
+  eof_token.type = CPP_PRAGMA_EOL;
+  elem_fn_tokens->safe_push (eof_token);
+  eof_token.type = CPP_EOF;
+  elem_fn_tokens->safe_push (eof_token);
+  elem_fn_tokens->safe_push (eof_token);
+}
+
 /* Parse (possibly empty) attributes.  This is a GNU extension.
 
    attributes:
@@ -3788,7 +3938,7 @@ 
    allow identifiers declared as types to start the arguments?  */
 
 static tree
-c_parser_attributes (c_parser *parser)
+c_parser_attributes (c_parser *parser, vec <c_token> *elem_fn_tokens)
 {
   tree attrs = NULL_TREE;
   while (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
@@ -3824,6 +3974,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, elem_fn_tokens);
+	      continue;
+	    }
 	  c_parser_consume_token (parser);
 	  if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN))
 	    {
@@ -3904,6 +4061,9 @@ 
 	}
       parser->lex_untranslated_string = false;
     }
+
+  if (flag_enable_cilkplus)
+    c_finish_elem_fn_tokens (elem_fn_tokens);
   return attrs;
 }
 
@@ -4588,7 +4748,7 @@ 
       c_parser_consume_token (parser);
       gcc_assert (c_parser_next_token_is (parser, CPP_COLON));
       c_parser_consume_token (parser);
-      attrs = c_parser_attributes (parser);
+      attrs = c_parser_attributes (parser, NULL);
       tlab = define_label (loc2, name);
       if (tlab)
 	{
@@ -8386,7 +8546,7 @@ 
     }
 
   if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
-    *attributes = c_parser_attributes (parser);
+    *attributes = c_parser_attributes (parser, NULL);
 
   /* If there were no attributes here, just report any earlier error.  */
   if (*attributes == NULL_TREE || bad)
@@ -8475,7 +8635,7 @@ 
 	    }
 	  /* New ObjC allows attributes on method parameters.  */
 	  if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
-	    param_attr = c_parser_attributes (parser);
+	    param_attr = c_parser_attributes (parser, NULL);
 	  if (c_parser_next_token_is_not (parser, CPP_NAME))
 	    {
 	      c_parser_error (parser, "expected identifier");
@@ -13630,7 +13790,7 @@ 
   tree attr_name, attr = NULL;
 
   if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
-    return c_parser_attributes (parser);
+    return c_parser_attributes (parser, NULL);
 
   if (!c_parser_next_token_is (parser, CPP_OPEN_SQUARE))
     return NULL_TREE;
Index: gcc/testsuite/gcc.dg/cilk-plus/cilk-plus.exp
===================================================================
--- gcc/testsuite/gcc.dg/cilk-plus/cilk-plus.exp	(revision 204981)
+++ 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_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;
+}