diff mbox

[gomp4] Some progress on #pragma omp simd

Message ID 5175B40F.7040709@redhat.com
State New
Headers show

Commit Message

Aldy Hernandez April 22, 2013, 10:05 p.m. UTC
On 04/19/13 08:29, Jakub Jelinek wrote:
> Hi!
>
> I've committed the following patch to gomp4 branch.
> #pragma omp simd loops now are handled with all its clauses from parsing up
> to and including omp expansion, so should actually run correctly, though
> haven't added any runtime testcases yet.

I like it.  Thanks for working on this.

I've been working on rewriting the <#pragma simd> support on the 
cilkplus branch to use a similar approach to what you do for openmp, 
especially since both constructs seem to behave similarly, with the 
exception of the "vectorlength" clause in Cilk Plus.  Attached is a 
patch against yours, doing so.

The idea is that <#prama omp simd> and <#pragma simd> are pretty much 
the same thing, so we can probably get away with outputting the same 
OMP_SIMD tree code and letting omp do it's thing.

I am also ignoring the "vectorlength" clause as you have done with 
safelen, waiting for Richi's loop preservation patch.

It seems that the Cilk Plus folk have not finalized the assert clause, 
and it's currently missing from the current spec.  I have left the 
assert clause in, as it seems they'll include something similar with a 
different syntax.

Otherwise, I'm using the same OMP_SIMD codes, as well as reusing your 
OMP_CLAUSE_LINEAR*.  For the firstprivate, lastprivate, private, and 
reduction clauses, I'm reusing even the parsing bits for OMP since the 
Cilk Plus spec uses the same exact syntax.  Perhaps eventually we could 
use some bits on the OMP_SIMD tree to differentiate an OMP_SIMD from a 
Cilk SIMD variant, and then use those to typecheck that the vectorlength 
and assert clauses are only used for Cilk Plus' #pragma simd.

I am missing a few minor things (some typechecking restrictions for 
longjmp() inside for-loop bodies, etc), but the parsing is basically 
done.  See the plethora of tests :).

How does this look, or do would you prefer another approach?
commit b2270ce0ab7ee4eb37b68b706fcf2e15941eb6ef
Author: Aldy Hernandez <aldyh@redhat.com>
Date:   Mon Apr 22 13:54:42 2013 -0500

    Rewrite Cilk Plus <#pragma simd> parsing and rewrite to use gomp4's
    OMP_SIMD infrastructure.

Comments

Jakub Jelinek April 23, 2013, 1:54 p.m. UTC | #1
On Mon, Apr 22, 2013 at 05:05:03PM -0500, Aldy Hernandez wrote:
> On 04/19/13 08:29, Jakub Jelinek wrote:
> >I've committed the following patch to gomp4 branch.
> >#pragma omp simd loops now are handled with all its clauses from parsing up
> >to and including omp expansion, so should actually run correctly, though
> >haven't added any runtime testcases yet.
> 
> I like it.  Thanks for working on this.
> 
> I've been working on rewriting the <#pragma simd> support on the
> cilkplus branch to use a similar approach to what you do for openmp,
> especially since both constructs seem to behave similarly, with the
> exception of the "vectorlength" clause in Cilk Plus.  Attached is a
> patch against yours, doing so.
> 
> The idea is that <#prama omp simd> and <#pragma simd> are pretty
> much the same thing, so we can probably get away with outputting the
> same OMP_SIMD tree code and letting omp do it's thing.

I don't think you can use OMP_SIMD resp. GF_OMP_FOR_KIND_SIMD for
#pragma simd, given that it has different semantics wrt. aliasing.

Like:
void
foo (int *p, int *q)
{
  int i;
  #pragma omp simd
  for (i = 0; i < 1024; i++)
    p[i] = q[i] + 1;
}
vs.
void
bar (int *p, int *q)
{
  int i;
  #pragma simd
  for (i = 0; i < 1024; i++)
    p[i] = q[i] + 1;
}

It is a user error if one calls foo say with int arr[1028]; ... foo (arr + 4, arr);
because through #pragma omp simd without safelen the programmer has asserted
that all iterations can be executed in the same simd chunk (think about 4096
bytes long vectors in this case).  So, #pragma omp simd expansion should be
able to tell the vectorizer that it can ignore all inter-iteration
dependencies during analysis.

If I understood right, vectorlength isn't anything close to it, it is just a
hint, if you vectorize, prefer this vector length, but the compiler is still
responsible for doing the analysis, and punting if it can't prove there is
no aliasing (or go for runtime checks).

There is #pragma ivdep in ICC, but it's definition is vague - the compiler
is still supposed to do analysis, but if some dependency isn't certain, it
can assume it doesn't happen (which is the fuzzy thing about it, if the
compiler can prove there is some dependency, then the code is valid and
vectorization can't be done).

So, IMHO you want CILK_SIMD tree (but it can use OMP and CILK clauses etc.),
and GF_OMP_FOR_KIND_CILK_SIMD or so, and perhaps it can be expanded etc.
exactly the same as #pragma omp simd, except for not telling the loop
optimizers that it should imply safelen(+infinity).  Or another option
is let the C/C++ FEs, when seeing #pragma omp simd without safelen clause
just add one with some very large value (unsigned TYPE_MAX_VALUE of
a type with precision > precision of the loop iterator?).

BTW, what restrictions has Cilk+ on the for stmt after the pragma?
OpenMP has lots of restrictions, it doesn't allow arbitrary for stmt there.

Like is
int i, j, k;
#pragma simd
for (i = 0, j = 4, k = 5; i < 10 && j < 12; i++, j += 2, k += 3)
  ...
valid Cilk+?  It isn't valid with #pragma omp simd...

	Jakub
Aldy Hernandez April 23, 2013, 9:02 p.m. UTC | #2
[Balaji, see below]

On 04/23/13 08:54, Jakub Jelinek wrote:
> On Mon, Apr 22, 2013 at 05:05:03PM -0500, Aldy Hernandez wrote:
>> On 04/19/13 08:29, Jakub Jelinek wrote:

> If I understood right, vectorlength isn't anything close to it, it is just a
> hint, if you vectorize, prefer this vector length, but the compiler is still
> responsible for doing the analysis, and punting if it can't prove there is
> no aliasing (or go for runtime checks).

Are you sure it's just a hint?  (My legalese is very bad).  The spec 
says "If the vectorlength clause is used, the VL is selected from among 
the values of its arguments."

I guess it's not clear what happens if the compiler can't use the 
vectorlength argument.  Balaji, would this be a hard error?  Is this 
merely a hint as Jakub says?

> So, IMHO you want CILK_SIMD tree (but it can use OMP and CILK clauses etc.),
> and GF_OMP_FOR_KIND_CILK_SIMD or so, and perhaps it can be expanded etc.
> exactly the same as #pragma omp simd, except for not telling the loop
> optimizers that it should imply safelen(+infinity).  Or another option
> is let the C/C++ FEs, when seeing #pragma omp simd without safelen clause
> just add one with some very large value (unsigned TYPE_MAX_VALUE of
> a type with precision > precision of the loop iterator?).

Actually, if it's all the same to you, I would prefer the latter.  It 
seems the easier approach is to have Cilk use OMP_SIMD, and set a 
safelen of 0 or something at parse time.  Would this be ok, or would you 
prefer a separate CILK_SIMD tree which gets expanded into OMP_FOR with a 
GF_OMP_FOR_KIND_CILK_SIMD?

>
> BTW, what restrictions has Cilk+ on the for stmt after the pragma?
> OpenMP has lots of restrictions, it doesn't allow arbitrary for stmt there.
>
> Like is
> int i, j, k;
> #pragma simd
> for (i = 0, j = 4, k = 5; i < 10 && j < 12; i++, j += 2, k += 3)
>    ...
> valid Cilk+?  It isn't valid with #pragma omp simd...

You obviously didn't look at the plethora of testcases I included with 
my patch :).  There are quite a few restrictions, thus the need in my 
patch to provide a separate parser for the for loop (not totally unlike 
what is done for gomp).  See c_check_cilk_loop(), but basically...

1. Initialization is required and can only include one variable. 
Variable cannot be volatile, extern, global, register (have any storage 
class specifiers).

2. Condition is required and can only be of the form:
	DECL <comparison_op> EXPR
	EXPR <comparison_op> DECL
    Where comparison_op is one of !=, <, <=, >, >=.  (== is not allowed).

3. Increment is a simple expression on the induction variable.  It is 
required, and can only be one of:

	++var, var++, --var, var--, var += incr, var -= incr.

Where incr is a conditional-expression with integral (or enum) type.

Can you take a peek at the patch?  Are we in agreement wrt the general 
approach here-- lest I go too far down the wrong rabbit hole?

Thanks.
Iyer, Balaji V April 23, 2013, 9:32 p.m. UTC | #3
> -----Original Message-----
> From: Jakub Jelinek [mailto:jakub@redhat.com]
> Sent: Tuesday, April 23, 2013 9:55 AM
> To: Aldy Hernandez
> Cc: Richard Henderson; gcc-patches@gcc.gnu.org; Iyer, Balaji V
> Subject: Re: [gomp4] Some progress on #pragma omp simd
> 
> On Mon, Apr 22, 2013 at 05:05:03PM -0500, Aldy Hernandez wrote:
> > On 04/19/13 08:29, Jakub Jelinek wrote:
> > >I've committed the following patch to gomp4 branch.
> > >#pragma omp simd loops now are handled with all its clauses from
> > >parsing up to and including omp expansion, so should actually run
> > >correctly, though haven't added any runtime testcases yet.
> >
> > I like it.  Thanks for working on this.
> >
> > I've been working on rewriting the <#pragma simd> support on the
> > cilkplus branch to use a similar approach to what you do for openmp,
> > especially since both constructs seem to behave similarly, with the
> > exception of the "vectorlength" clause in Cilk Plus.  Attached is a
> > patch against yours, doing so.
> >
> > The idea is that <#prama omp simd> and <#pragma simd> are pretty much
> > the same thing, so we can probably get away with outputting the same
> > OMP_SIMD tree code and letting omp do it's thing.
> 
> I don't think you can use OMP_SIMD resp. GF_OMP_FOR_KIND_SIMD for
> #pragma simd, given that it has different semantics wrt. aliasing.
> 
> Like:
> void
> foo (int *p, int *q)
> {
>   int i;
>   #pragma omp simd
>   for (i = 0; i < 1024; i++)
>     p[i] = q[i] + 1;
> }
> vs.
> void
> bar (int *p, int *q)
> {
>   int i;
>   #pragma simd
>   for (i = 0; i < 1024; i++)
>     p[i] = q[i] + 1;
> }
> 
> It is a user error if one calls foo say with int arr[1028]; ... foo (arr + 4, arr);
> because through #pragma omp simd without safelen the programmer has
> asserted that all iterations can be executed in the same simd chunk (think about
> 4096 bytes long vectors in this case).  So, #pragma omp simd expansion should
> be able to tell the vectorizer that it can ignore all inter-iteration dependencies
> during analysis.
> 
> If I understood right, vectorlength isn't anything close to it, it is just a hint, if you
> vectorize, prefer this vector length, but the compiler is still responsible for doing
> the analysis, and punting if it can't prove there is no aliasing (or go for runtime
> checks).

Hi Jakub,
	My apologies if the documentation did not explain this correctly. It was written by compiler developers and not language developers. #pragma simd is the guarantee the user gives the compiler that the inter-iteration dependencies do not matter. So, if the user omits the vectorlength the clause then the compiler can, in effect, choose N, where N is the number of loop iterations. 

Thanks,

Balaji V. Iyer.


> 
> There is #pragma ivdep in ICC, but it's definition is vague - the compiler is still
> supposed to do analysis, but if some dependency isn't certain, it can assume it
> doesn't happen (which is the fuzzy thing about it, if the compiler can prove there
> is some dependency, then the code is valid and vectorization can't be done).
> 
> So, IMHO you want CILK_SIMD tree (but it can use OMP and CILK clauses etc.),
> and GF_OMP_FOR_KIND_CILK_SIMD or so, and perhaps it can be expanded etc.
> exactly the same as #pragma omp simd, except for not telling the loop
> optimizers that it should imply safelen(+infinity).  Or another option is let the
> C/C++ FEs, when seeing #pragma omp simd without safelen clause just add one
> with some very large value (unsigned TYPE_MAX_VALUE of a type with precision
> > precision of the loop iterator?).
> 
> BTW, what restrictions has Cilk+ on the for stmt after the pragma?
> OpenMP has lots of restrictions, it doesn't allow arbitrary for stmt there.
> 
> Like is
> int i, j, k;
> #pragma simd
> for (i = 0, j = 4, k = 5; i < 10 && j < 12; i++, j += 2, k += 3)
>   ...
> valid Cilk+?  It isn't valid with #pragma omp simd...
> 
> 	Jakub
Jakub Jelinek April 24, 2013, 6:01 a.m. UTC | #4
On Tue, Apr 23, 2013 at 09:32:29PM +0000, Iyer, Balaji V wrote:
> 	My apologies if the documentation did not explain this correctly. It
> was written by compiler developers and not language developers.  #pragma
> simd is the guarantee the user gives the compiler that the inter-iteration
> dependencies do not matter.  So, if the user omits the vectorlength the
> clause then the compiler can, in effect, choose N, where N is the number
> of loop iterations.

The documentation doesn't suggest that.  Anyway, so
#pragma simd
should be equivalent to
#pragma omp simd
wrt. inter-iteration dependencies, and
#pragma simd vectorlength(a, b, c)
to
#pragma omp simd safelen(max (a, b, c))
?  If so, then the FE could emit OMP_SIMD for #pragma simd, and if
vectorlength is present, add OMP_CLAUSE_SAFELEN with the maximum of the
values in all vectorlength clauses, and keep the vectorlength clauses around
too as CILK_CLAUSE_VECTORLENGTH as hints to the vectorizer?

Also, Aldy said that #pragma simd loops allow != condition, how do you
compute number of iterations in that case if the increment isn't constant?
As conditional depending on whether increment is positive or negative?
!= condition isn't allowed in OpenMP, so there it is always obvious which
direction it should iterate, and the expansion code will assume if it sees
NE_EXPR that it is just folded border test (comparison with maximum or
minimum value).

	Jakub
Jakub Jelinek April 24, 2013, 6:25 a.m. UTC | #5
On Wed, Apr 24, 2013 at 08:01:17AM +0200, Jakub Jelinek wrote:
> On Tue, Apr 23, 2013 at 09:32:29PM +0000, Iyer, Balaji V wrote:
> The documentation doesn't suggest that.  Anyway, so
> #pragma simd
> should be equivalent to
> #pragma omp simd
> wrt. inter-iteration dependencies, and
> #pragma simd vectorlength(a, b, c)
> to
> #pragma omp simd safelen(max (a, b, c))
> ?  If so, then the FE could emit OMP_SIMD for #pragma simd, and if
> vectorlength is present, add OMP_CLAUSE_SAFELEN with the maximum of the
> values in all vectorlength clauses, and keep the vectorlength clauses around
> too as CILK_CLAUSE_VECTORLENGTH as hints to the vectorizer?
> 
> Also, Aldy said that #pragma simd loops allow != condition, how do you
> compute number of iterations in that case if the increment isn't constant?
> As conditional depending on whether increment is positive or negative?
> != condition isn't allowed in OpenMP, so there it is always obvious which
> direction it should iterate, and the expansion code will assume if it sees
> NE_EXPR that it is just folded border test (comparison with maximum or
> minimum value).

BTW, the semantics of private/firstprivate/lastprivate desribed in
http://software.intel.com/sites/products/documentation/studio/composer/en-us/2011Update/compiler_c/cref_cls/common/cppref_pragma_simd.htm
doesn't seem to match the semantics of those in #pragma omp simd.
private in OpenMP I understand is private to the whole loop (or SIMD lane?;
at least, that was the semantics of #pragma omp for too and there is no wording
to suggest otherwise for #pragma omp simd or #pragma omp for simd), while the above
html suggests in Cilk+ it is private to each iteration.  #pragma omp simd
doesn't support firstprivate.  The lastprivate semantics wrt. returning the
last iteration's value is the same.

	Jakub
Jakub Jelinek April 24, 2013, 6:40 a.m. UTC | #6
On Wed, Apr 24, 2013 at 08:25:36AM +0200, Jakub Jelinek wrote:
> BTW, the semantics of private/firstprivate/lastprivate desribed in
> http://software.intel.com/sites/products/documentation/studio/composer/en-us/2011Update/compiler_c/cref_cls/common/cppref_pragma_simd.htm
> doesn't seem to match the semantics of those in #pragma omp simd.
> private in OpenMP I understand is private to the whole loop (or SIMD lane?;

SIMD lane apparently.  Guess that is going to be quite difficult, because
at the point of omp lowering or expansion we are nowhere close to knowing
what vectorization factor we are going to choose, all we have is an
upper bound on that based on the target ISA and safelen clause.
If say private clause is used with C++ classes with non-trivial ctors/dtors
that would make a difference.  Plus how to represent this in the IL.

struct A { A (); ~A (); A (const A &); int i; };

void
foo ()
{
  A a, b;
  #pragma omp simd private (a) lastprivate (b)
  for (int i = 0; i < 10; i++)
    {
      a.i++;
      b.i++;
    }
}

Right now what gomp4 branch does is that it will just construct private
vars around the whole loop, as in:
void
foo ()
{
  A a, b;
  {
    A a', b';
    int i;
    for (i = 0; i < 10; i++)
      {
	a'.i++;
	b'.i++;
	if (i == 9)
	  b = b';
      }
  }
}

	Jakub
Aldy Hernandez April 24, 2013, 11:22 p.m. UTC | #7
[Balaji, see below].

Ok, this is confusing.  While the document in the link you posted (the 
ICC manual?) says so, the document I'm following says otherwise.

I'm following this (which, until a few days was a link accessible from 
the cilk plus web page, though I no longer see it):

http://software.intel.com/sites/default/files/m/4/e/7/3/1/40297-Intel_Cilk_plus_lang_spec_2.htm

The document above is for version 1.1 of the Cilk Plus language 
extension specification, which I was told was the latest.  There it 
explicitly says that the clauses behave exactly like in OpenMP:

"The syntax and semantics of the various simd-openmp-data-clauses are 
detailed in the OpenMP specification. 
(http://www.openmp.org/mp-documents/spec30.pdf, Section 2.9.3)."

Balaji, can you verify which is correct?  For that matter, which are the 
official specs from which we should be basing this work?

Aldy


On 04/24/13 01:40, Jakub Jelinek wrote:
> On Wed, Apr 24, 2013 at 08:25:36AM +0200, Jakub Jelinek wrote:
>> BTW, the semantics of private/firstprivate/lastprivate desribed in
>> http://software.intel.com/sites/products/documentation/studio/composer/en-us/2011Update/compiler_c/cref_cls/common/cppref_pragma_simd.htm
>> doesn't seem to match the semantics of those in #pragma omp simd.
>> private in OpenMP I understand is private to the whole loop (or SIMD lane?;
>
> SIMD lane apparently.  Guess that is going to be quite difficult, because
> at the point of omp lowering or expansion we are nowhere close to knowing
> what vectorization factor we are going to choose, all we have is an
> upper bound on that based on the target ISA and safelen clause.
> If say private clause is used with C++ classes with non-trivial ctors/dtors
> that would make a difference.  Plus how to represent this in the IL.
>
> struct A { A (); ~A (); A (const A &); int i; };
>
> void
> foo ()
> {
>    A a, b;
>    #pragma omp simd private (a) lastprivate (b)
>    for (int i = 0; i < 10; i++)
>      {
>        a.i++;
>        b.i++;
>      }
> }
>
> Right now what gomp4 branch does is that it will just construct private
> vars around the whole loop, as in:
> void
> foo ()
> {
>    A a, b;
>    {
>      A a', b';
>      int i;
>      for (i = 0; i < 10; i++)
>        {
> 	a'.i++;
> 	b'.i++;
> 	if (i == 9)
> 	  b = b';
>        }
>    }
> }
>
> 	Jakub
>
Aldy Hernandez April 25, 2013, 12:05 a.m. UTC | #8
On 04/24/13 18:22, Aldy Hernandez wrote:

Hmmm, furthermore, even if the simd + private semantics in Cilk Plus 
have the same semantics of the OpenMP standard, is it the OpenMP 3.0 
semantics like the openmp link suggests (private to task), or is it the 
OpenMP 4.0 rc 2 semantics which you suggest (private to SIMD lane)?

Lemme ask icc.

> [Balaji, see below].
>
> Ok, this is confusing.  While the document in the link you posted (the
> ICC manual?) says so, the document I'm following says otherwise.
>
> I'm following this (which, until a few days was a link accessible from
> the cilk plus web page, though I no longer see it):
>
> http://software.intel.com/sites/default/files/m/4/e/7/3/1/40297-Intel_Cilk_plus_lang_spec_2.htm
>
>
> The document above is for version 1.1 of the Cilk Plus language
> extension specification, which I was told was the latest.  There it
> explicitly says that the clauses behave exactly like in OpenMP:
>
> "The syntax and semantics of the various simd-openmp-data-clauses are
> detailed in the OpenMP specification.
> (http://www.openmp.org/mp-documents/spec30.pdf, Section 2.9.3)."
>
> Balaji, can you verify which is correct?  For that matter, which are the
> official specs from which we should be basing this work?
>
> Aldy
>
>
> On 04/24/13 01:40, Jakub Jelinek wrote:
>> On Wed, Apr 24, 2013 at 08:25:36AM +0200, Jakub Jelinek wrote:
>>> BTW, the semantics of private/firstprivate/lastprivate desribed in
>>> http://software.intel.com/sites/products/documentation/studio/composer/en-us/2011Update/compiler_c/cref_cls/common/cppref_pragma_simd.htm
>>>
>>> doesn't seem to match the semantics of those in #pragma omp simd.
>>> private in OpenMP I understand is private to the whole loop (or SIMD
>>> lane?;
>>
>> SIMD lane apparently.  Guess that is going to be quite difficult, because
>> at the point of omp lowering or expansion we are nowhere close to knowing
>> what vectorization factor we are going to choose, all we have is an
>> upper bound on that based on the target ISA and safelen clause.
>> If say private clause is used with C++ classes with non-trivial
>> ctors/dtors
>> that would make a difference.  Plus how to represent this in the IL.
>>
>> struct A { A (); ~A (); A (const A &); int i; };
>>
>> void
>> foo ()
>> {
>>    A a, b;
>>    #pragma omp simd private (a) lastprivate (b)
>>    for (int i = 0; i < 10; i++)
>>      {
>>        a.i++;
>>        b.i++;
>>      }
>> }
>>
>> Right now what gomp4 branch does is that it will just construct private
>> vars around the whole loop, as in:
>> void
>> foo ()
>> {
>>    A a, b;
>>    {
>>      A a', b';
>>      int i;
>>      for (i = 0; i < 10; i++)
>>        {
>>     a'.i++;
>>     b'.i++;
>>     if (i == 9)
>>       b = b';
>>        }
>>    }
>> }
>>
>>     Jakub
>>
>
Aldy Hernandez April 25, 2013, 12:08 a.m. UTC | #9
On 04/24/13 01:01, Jakub Jelinek wrote:

> The documentation doesn't suggest that.  Anyway, so
> #pragma simd
> should be equivalent to
> #pragma omp simd
> wrt. inter-iteration dependencies, and
> #pragma simd vectorlength(a, b, c)
> to
> #pragma omp simd safelen(max (a, b, c))
> ?  If so, then the FE could emit OMP_SIMD for #pragma simd, and if
> vectorlength is present, add OMP_CLAUSE_SAFELEN with the maximum of the
> values in all vectorlength clauses, and keep the vectorlength clauses around
> too as CILK_CLAUSE_VECTORLENGTH as hints to the vectorizer?

I can make these changes to the Cilk Plus code.

>
> Also, Aldy said that #pragma simd loops allow != condition, how do you
> compute number of iterations in that case if the increment isn't constant?
> As conditional depending on whether increment is positive or negative?
> != condition isn't allowed in OpenMP, so there it is always obvious which
> direction it should iterate, and the expansion code will assume if it sees
> NE_EXPR that it is just folded border test (comparison with maximum or
> minimum value).

Perhaps it is an oversight in the documentation, because icc disallows 
both == and !=.  Disallowing != makes it a lot easier :).
Iyer, Balaji V April 27, 2013, 12:34 a.m. UTC | #10
Hello Aldy and Jakub,
 	Please see my response below.

Thanks,

Balaji V. Iyer.

> -----Original Message-----
> From: Aldy Hernandez [mailto:aldyh@redhat.com]
> Sent: Wednesday, April 24, 2013 7:22 PM
> To: Jakub Jelinek
> Cc: Iyer, Balaji V; Richard Henderson; gcc-patches@gcc.gnu.org
> Subject: Re: [gomp4] Some progress on #pragma omp simd
> 
> [Balaji, see below].
> 
> Ok, this is confusing.  While the document in the link you posted (the ICC
> manual?) says so, the document I'm following says otherwise.
> 
> I'm following this (which, until a few days was a link accessible from the cilk plus
> web page, though I no longer see it):

Yes, I am aware of the missing link. We are currently looking into it.

> 
> http://software.intel.com/sites/default/files/m/4/e/7/3/1/40297-
> Intel_Cilk_plus_lang_spec_2.htm
> 
> The document above is for version 1.1 of the Cilk Plus language extension
> specification, which I was told was the latest.  There it explicitly says that the
> clauses behave exactly like in OpenMP:
> 
> "The syntax and semantics of the various simd-openmp-data-clauses are
> detailed in the OpenMP specification.
> (http://www.openmp.org/mp-documents/spec30.pdf, Section 2.9.3)."
> 
> Balaji, can you verify which is correct?  For that matter, which are the official
> specs from which we should be basing this work?

Privatization clause makes a variable private for the simd lane. In general,  I would follow the spec. If you have further questions, please feel free to ask.

Thanks,

Balaji V. Iyer.

> 
> Aldy
> 
> 
> On 04/24/13 01:40, Jakub Jelinek wrote:
> > On Wed, Apr 24, 2013 at 08:25:36AM +0200, Jakub Jelinek wrote:
> >> BTW, the semantics of private/firstprivate/lastprivate desribed in
> >> http://software.intel.com/sites/products/documentation/studio/compose
> >> r/en-
> us/2011Update/compiler_c/cref_cls/common/cppref_pragma_simd.htm
> >> doesn't seem to match the semantics of those in #pragma omp simd.
> >> private in OpenMP I understand is private to the whole loop (or SIMD
> >> lane?;
> >
> > SIMD lane apparently.  Guess that is going to be quite difficult,
> > because at the point of omp lowering or expansion we are nowhere close
> > to knowing what vectorization factor we are going to choose, all we
> > have is an upper bound on that based on the target ISA and safelen clause.
> > If say private clause is used with C++ classes with non-trivial
> > ctors/dtors that would make a difference.  Plus how to represent this in the IL.
> >
> > struct A { A (); ~A (); A (const A &); int i; };
> >
> > void
> > foo ()
> > {
> >    A a, b;
> >    #pragma omp simd private (a) lastprivate (b)
> >    for (int i = 0; i < 10; i++)
> >      {
> >        a.i++;
> >        b.i++;
> >      }
> > }
> >
> > Right now what gomp4 branch does is that it will just construct
> > private vars around the whole loop, as in:
> > void
> > foo ()
> > {
> >    A a, b;
> >    {
> >      A a', b';
> >      int i;
> >      for (i = 0; i < 10; i++)
> >        {
> > 	a'.i++;
> > 	b'.i++;
> > 	if (i == 9)
> > 	  b = b';
> >        }
> >    }
> > }
> >
> > 	Jakub
> >
Aldy Hernandez April 27, 2013, 5:30 p.m. UTC | #11
Hi Balaji.

>> "The syntax and semantics of the various simd-openmp-data-clauses
>> are detailed in the OpenMP specification.
>> (http://www.openmp.org/mp-documents/spec30.pdf, Section 2.9.3)."
>>
>> Balaji, can you verify which is correct?  For that matter, which
>> are the official specs from which we should be basing this work?
>
> Privatization clause makes a variable private for the simd lane. In
> general,  I would follow the spec. If you have further questions,
> please feel free to ask.

Ok, so the Cilk Plus 1.1 spec is incorrectly pointing to the OpenMP 3.0 
spec, because the OpenMP 3.0 spec has the private clause being 
task/thread private.  Since the OpenMP 4.0rc2 explicitly says that the 
private clause is for the SIMD lane (as you've stated), can we assume 
that when the Cilk Plus 1.1 spec mentions OpenMP, it is talking about 
the OpenMP 4.0 spec?

One more question Balaji, the Cilk Plus spec says that for #pragma simd, 
the private, firstprivate, lastprivate, and reduction clauses are as 
OpenMP.  However, for <#omp simd>, there is no firstprivate in the 
OpenMP 4.0rc2 spec.  Is the firstprivate clause valid for Cilk Plus' 
<#pragma simd>?

Thanks.
Aldy
Jakub Jelinek April 27, 2013, 6:17 p.m. UTC | #12
On Sat, Apr 27, 2013 at 12:30:28PM -0500, Aldy Hernandez wrote:
> >>"The syntax and semantics of the various simd-openmp-data-clauses
> >>are detailed in the OpenMP specification.
> >>(http://www.openmp.org/mp-documents/spec30.pdf, Section 2.9.3)."
> >>
> >>Balaji, can you verify which is correct?  For that matter, which
> >>are the official specs from which we should be basing this work?
> >
> >Privatization clause makes a variable private for the simd lane. In
> >general,  I would follow the spec. If you have further questions,
> >please feel free to ask.
> 
> Ok, so the Cilk Plus 1.1 spec is incorrectly pointing to the OpenMP
> 3.0 spec, because the OpenMP 3.0 spec has the private clause being
> task/thread private.  Since the OpenMP 4.0rc2 explicitly says that
> the private clause is for the SIMD lane (as you've stated), can we
> assume that when the Cilk Plus 1.1 spec mentions OpenMP, it is
> talking about the OpenMP 4.0 spec?

One way we could implement the SIMD private/lastprivate/reduction
vars and for Cilk+ also firstprivate ones might be:
- query the target what the maximum possible vectorization factor for the
  loop is (and min that with simdlen if any), let's call it MAXVF

for say
struct S { S (); ~S (); int x; };
...
int a, b;
S s;
#pragma omp simd private (a, s) reduction (+:b)
for (int i = 0; i < N; i++)
  { foo (&a, &s); b += a; }
we'd then emit something like:
int a_[MAXVF], b_[MAXVF];
S s_[MAXVF];
for (tmp = 0; tmp < __builtin_omp.simd_vf (simd_uid); tmp++)
  {
    b_[tmp] = 0;
    S::S (&s_[tmp]);
  }
# loop simd_uid with safelen(MAXVF)
for (i = 0; i < N; i++)
  {
    tmp = __builtin_omp.simd_lane (simd_uid);
    foo (&a_[tmp], &s_[tmp]);
    b_[tmp] += a_[tmp];
  }
for (tmp = 0; tmp < __builtin_omp.simd_vf (simd_uid); tmp++)
  {
    S::~S (&s[tmp]);
    b += b_[tmp];
  }

where simd_uid would be some say integer constant, unique to the simd loop
(at least unique within the same function, and perhaps inlining/LTO would
need to remap).  The loop simd_uid would be stored by ompexp pass into
the loop structure.  Then the vectorizer (ideally, we'd enable vectorization
even when not explicitly disabled through -fno-tree-vectorize for -fopenmp
or -fcilk+, though in that case only for the explicit simd loops) would
treat arrays indexed by __builtin_omp.simd_lane (simd_uid) (dot in the name just
to make it impossible to be used by users) (or marked with some special
hidden attribute or something) specially, allow promoting them to just
vector vars if not addressable, etc., and would record the chosen
vectorization factor in the loop structure, and __builtin_omp.simd_vf
would then expand to the vectorization factor and __builtin_omp.simd_lane to
the number of the lane.  If vectorization couldn't be performed on some loop,
__builtin_omp.simd_vf would just be folded into 1 and
__builtin_omp.simd_lane into 0 say by some ompsimd pass run soon after the
vectorization.

Thoughts on this?  Or do you see better IL representation of this stuff
from the omp expansion till vectorization?  I mean, e.g. for floating point
or user defined reductions it might be important in what order they are
performed (unless -ffast-math for the former).

	Jakub
Iyer, Balaji V April 28, 2013, 2:45 p.m. UTC | #13
> -----Original Message-----
> From: gcc-patches-owner@gcc.gnu.org [mailto:gcc-patches-
> owner@gcc.gnu.org] On Behalf Of Aldy Hernandez
> Sent: Saturday, April 27, 2013 1:30 PM
> To: Iyer, Balaji V
> Cc: Jakub Jelinek; Richard Henderson; gcc-patches@gcc.gnu.org
> Subject: Re: [gomp4] Some progress on #pragma omp simd
> 
> Hi Balaji.
> 
> >> "The syntax and semantics of the various simd-openmp-data-clauses are
> >> detailed in the OpenMP specification.
> >> (http://www.openmp.org/mp-documents/spec30.pdf, Section 2.9.3)."
> >>
> >> Balaji, can you verify which is correct?  For that matter, which are
> >> the official specs from which we should be basing this work?
> >
> > Privatization clause makes a variable private for the simd lane. In
> > general,  I would follow the spec. If you have further questions,
> > please feel free to ask.
> 
> Ok, so the Cilk Plus 1.1 spec is incorrectly pointing to the OpenMP 3.0 spec,
> because the OpenMP 3.0 spec has the private clause being task/thread private.
> Since the OpenMP 4.0rc2 explicitly says that the private clause is for the SIMD
> lane (as you've stated), can we assume that when the Cilk Plus 1.1 spec mentions
> OpenMP, it is talking about the OpenMP 4.0 spec?

I don't know of all the references to the OMP manual in the spec, so I will be a bit hesitant to make a blanket assumption like that. In this case, I think you can assume that it behaves in the same way as 4.0. If you have further questions, please feel free to ask. In general, #pragma simd, array notation and elemental functions deal with vectorization, not threading. But, Cilk part (Cilk keywords and reducers) deal with threading. All these parts can be mixed and matched (with restrictions) to take advantage of both threading and vectorization.

> 
> One more question Balaji, the Cilk Plus spec says that for #pragma simd, the
> private, firstprivate, lastprivate, and reduction clauses are as OpenMP.
> However, for <#omp simd>, there is no firstprivate in the OpenMP 4.0rc2 spec.
> Is the firstprivate clause valid for Cilk Plus'
> <#pragma simd>?



> 
> Thanks.
> Aldy
Aldy Hernandez May 1, 2013, 2:58 p.m. UTC | #14
On 04/28/13 09:45, Iyer, Balaji V wrote:

>> One more question Balaji, the Cilk Plus spec says that for #pragma simd, the
>> private, firstprivate, lastprivate, and reduction clauses are as OpenMP.
>> However, for <#omp simd>, there is no firstprivate in the OpenMP 4.0rc2 spec.
>> Is the firstprivate clause valid for Cilk Plus'
>> <#pragma simd>?

Well, it looks like the Cilk Plus folks are looking into possibly 
deprecating the firstprivate clause for the next revision of the spec. 
This would bring things in harmony with OpenMP 4.0.
Aldy Hernandez May 1, 2013, 3:51 p.m. UTC | #15
On 04/24/13 01:01, Jakub Jelinek wrote:
> On Tue, Apr 23, 2013 at 09:32:29PM +0000, Iyer, Balaji V wrote:
>> 	My apologies if the documentation did not explain this correctly. It
>> was written by compiler developers and not language developers.  #pragma
>> simd is the guarantee the user gives the compiler that the inter-iteration
>> dependencies do not matter.  So, if the user omits the vectorlength the
>> clause then the compiler can, in effect, choose N, where N is the number
>> of loop iterations.
>
> The documentation doesn't suggest that.  Anyway, so
> #pragma simd
> should be equivalent to
> #pragma omp simd
> wrt. inter-iteration dependencies, and
> #pragma simd vectorlength(a, b, c)
> to
> #pragma omp simd safelen(max (a, b, c))
> ?  If so, then the FE could emit OMP_SIMD for #pragma simd, and if
> vectorlength is present, add OMP_CLAUSE_SAFELEN with the maximum of the
> values in all vectorlength clauses, and keep the vectorlength clauses around
> too as CILK_CLAUSE_VECTORLENGTH as hints to the vectorizer?

Well, it looks like things are bit simpler than expected.

Multiple vectorlength clauses are being deprecated or eliminated in the 
upcoming spec.  So it looks like vectorlength is the same thing as the 
safelen clause.

If you agree then I can get rid of OMP_CLAUSE_CILK_VECTORLENGTH and just 
emit an OMP_CLAUSE_SAFELEN.

Agreed?

>
> Also, Aldy said that #pragma simd loops allow != condition, how do you
> compute number of iterations in that case if the increment isn't constant?
> As conditional depending on whether increment is positive or negative?
> != condition isn't allowed in OpenMP, so there it is always obvious which
> direction it should iterate, and the expansion code will assume if it sees
> NE_EXPR that it is just folded border test (comparison with maximum or
> minimum value).

I verified with the Cilk Plus folks, and the number of iterations is 
calculated with a conditional.  So to evaluate something like this:

// incr = -1
for (i=N; i != limit; i += incr)
   [body]

We would generate something like this:

if (incr > 0) count =  (limit - N) / incr;
else count = (N - limit) / -incr;
for (i=N; count > 0; --count)
   [body]
Iyer, Balaji V May 1, 2013, 3:58 p.m. UTC | #16
> -----Original Message-----
> From: gcc-patches-owner@gcc.gnu.org [mailto:gcc-patches-
> owner@gcc.gnu.org] On Behalf Of Aldy Hernandez
> Sent: Wednesday, May 01, 2013 11:52 AM
> To: Jakub Jelinek
> Cc: Iyer, Balaji V; Richard Henderson; gcc-patches@gcc.gnu.org
> Subject: Re: [gomp4] Some progress on #pragma omp simd
> 
> On 04/24/13 01:01, Jakub Jelinek wrote:
> > On Tue, Apr 23, 2013 at 09:32:29PM +0000, Iyer, Balaji V wrote:
> >> 	My apologies if the documentation did not explain this correctly. It
> >> was written by compiler developers and not language developers.
> >> #pragma simd is the guarantee the user gives the compiler that the
> >> inter-iteration dependencies do not matter.  So, if the user omits
> >> the vectorlength the clause then the compiler can, in effect, choose
> >> N, where N is the number of loop iterations.
> >
> > The documentation doesn't suggest that.  Anyway, so #pragma simd
> > should be equivalent to #pragma omp simd wrt. inter-iteration
> > dependencies, and #pragma simd vectorlength(a, b, c) to #pragma omp
> > simd safelen(max (a, b, c)) ?  If so, then the FE could emit OMP_SIMD
> > for #pragma simd, and if vectorlength is present, add
> > OMP_CLAUSE_SAFELEN with the maximum of the values in all vectorlength
> > clauses, and keep the vectorlength clauses around too as
> > CILK_CLAUSE_VECTORLENGTH as hints to the vectorizer?
> 
> Well, it looks like things are bit simpler than expected.
> 
> Multiple vectorlength clauses are being deprecated or eliminated in the
> upcoming spec.  So it looks like vectorlength is the same thing as the safelen
> clause.
> 
> If you agree then I can get rid of OMP_CLAUSE_CILK_VECTORLENGTH and just
> emit an OMP_CLAUSE_SAFELEN.
> 
> Agreed?

To my best knowledge, Yes. I believe safelen requires/allows only 1 value, so we should do what Jakub mentioned (vectorlength (a, b, c)) should be converted to safelen (max(a,b,c))

> 
> >
> > Also, Aldy said that #pragma simd loops allow != condition, how do you
> > compute number of iterations in that case if the increment isn't constant?
> > As conditional depending on whether increment is positive or negative?
> > != condition isn't allowed in OpenMP, so there it is always obvious
> > which direction it should iterate, and the expansion code will assume
> > if it sees NE_EXPR that it is just folded border test (comparison with
> > maximum or minimum value).
> 
> I verified with the Cilk Plus folks, and the number of iterations is calculated with
> a conditional.  So to evaluate something like this:
> 
> // incr = -1
> for (i=N; i != limit; i += incr)
>    [body]
> 
> We would generate something like this:
> 
> if (incr > 0) count =  (limit - N) / incr; else count = (N - limit) / -incr; for (i=N; count
> > 0; --count)
>    [body]

Sounds OK.
Aldy Hernandez May 1, 2013, 4:01 p.m. UTC | #17
On 05/01/13 10:58, Iyer, Balaji V wrote:
>>
>> Well, it looks like things are bit simpler than expected.
>>
>> Multiple vectorlength clauses are being deprecated or eliminated
>> in the upcoming spec.  So it looks like vectorlength is the same
>> thing as the safelen clause.
>>
>> If you agree then I can get rid of OMP_CLAUSE_CILK_VECTORLENGTH
>> and just emit an OMP_CLAUSE_SAFELEN.
>>
>> Agreed?
>
> To my best knowledge, Yes. I believe safelen requires/allows only 1
> value, so we should do what Jakub mentioned (vectorlength (a, b, c))
> should be converted to safelen (max(a,b,c))

Well, we don't even need to do max(a,b,c) because according to the Cilk
Plus forum, the upcoming spec does not allow multiple vectorlength 
clauses (or arguments), so only vectorlength(const_expr) is allowed.

Did I misunderstand something here?
Iyer, Balaji V May 1, 2013, 7:13 p.m. UTC | #18
> -----Original Message-----
> From: gcc-patches-owner@gcc.gnu.org [mailto:gcc-patches-
> owner@gcc.gnu.org] On Behalf Of Aldy Hernandez
> Sent: Wednesday, May 01, 2013 12:02 PM
> To: Iyer, Balaji V
> Cc: Jakub Jelinek; Richard Henderson; gcc-patches@gcc.gnu.org
> Subject: Re: [gomp4] Some progress on #pragma omp simd
> 
> On 05/01/13 10:58, Iyer, Balaji V wrote:
> >>
> >> Well, it looks like things are bit simpler than expected.
> >>
> >> Multiple vectorlength clauses are being deprecated or eliminated in
> >> the upcoming spec.  So it looks like vectorlength is the same thing
> >> as the safelen clause.
> >>
> >> If you agree then I can get rid of OMP_CLAUSE_CILK_VECTORLENGTH and
> >> just emit an OMP_CLAUSE_SAFELEN.
> >>
> >> Agreed?
> >
> > To my best knowledge, Yes. I believe safelen requires/allows only 1
> > value, so we should do what Jakub mentioned (vectorlength (a, b, c))
> > should be converted to safelen (max(a,b,c))
> 
> Well, we don't even need to do max(a,b,c) because according to the Cilk Plus
> forum, the upcoming spec does not allow multiple vectorlength clauses (or
> arguments), so only vectorlength(const_expr) is allowed.
> 
> Did I misunderstand something here?

I am not sure about the upcoming spec, but as per today's spec vectorlength in pragma simd can have multiple parameters and so I think it would be a good idea to use a max.

Thanks,

Balaji V. Iyer.
Aldy Hernandez May 1, 2013, 7:53 p.m. UTC | #19
> I am not sure about the upcoming spec, but as per today's spec
> vectorlength in pragma simd can have multiple parameters and so I
> think it would be a good idea to use a max.

As discussed here:

http://software.intel.com/en-us/forums/topic/391056

"The use of multiple vectorlength arguments is being removed (or at 
least deprecated) in the next revision of the spec., since it carries no 
semantic meaning and is not even a very good hint to the compiler."

If/when we merge into mainline, I am pretty sure the latest spec will be 
out, so there's little sense in spending time on implementing things 
that will be obsolete by the time we release.  Disallowing multiple 
vectorlengths makes it trivial to just use OpenMP's safelen clause 
without any additional code.

Aldy
Jeff Law May 1, 2013, 7:55 p.m. UTC | #20
On 05/01/2013 01:53 PM, Aldy Hernandez wrote:
>
>> I am not sure about the upcoming spec, but as per today's spec
>> vectorlength in pragma simd can have multiple parameters and so I
>> think it would be a good idea to use a max.
>
> As discussed here:
>
> http://software.intel.com/en-us/forums/topic/391056
>
> "The use of multiple vectorlength arguments is being removed (or at
> least deprecated) in the next revision of the spec., since it carries no
> semantic meaning and is not even a very good hint to the compiler."
>
> If/when we merge into mainline, I am pretty sure the latest spec will be
> out, so there's little sense in spending time on implementing things
> that will be obsolete by the time we release.  Disallowing multiple
> vectorlengths makes it trivial to just use OpenMP's safelen clause
> without any additional code.
Agreed.  If it's being deprecated, let's just not bother ever 
implementing it in GCC.  The fact that doing so allows OpenMP & Cilk to 
share implementation bits is just icing on the cake.
jeff
Richard Henderson June 12, 2013, 5:21 p.m. UTC | #21
On 04/27/2013 11:17 AM, Jakub Jelinek wrote:
> where simd_uid would be some say integer constant, unique to the simd loop
> (at least unique within the same function, and perhaps inlining/LTO would
> need to remap).

If all we need is uniqueness, then perhaps an otherwise unused decl would do?
We're already prepared to remap those during inlining/LTO...

> treat arrays indexed by __builtin_omp.simd_lane (simd_uid) (dot in the name just
> to make it impossible to be used by users) (or marked with some special
> hidden attribute or something)

I see

/* This file specifies a list of internal "functions".  These functions
   differ from built-in functions in that they have no linkage and cannot
   be called directly by the user.  They represent operations that are only
   synthesised by GCC itself.

and think that may be more applicable than adding dots to regular builtins.


r~
Jakub Jelinek June 12, 2013, 5:30 p.m. UTC | #22
On Wed, Jun 12, 2013 at 10:21:53AM -0700, Richard Henderson wrote:
> On 04/27/2013 11:17 AM, Jakub Jelinek wrote:
> > where simd_uid would be some say integer constant, unique to the simd loop
> > (at least unique within the same function, and perhaps inlining/LTO would
> > need to remap).
> 
> If all we need is uniqueness, then perhaps an otherwise unused decl would do?
> We're already prepared to remap those during inlining/LTO...

So the built-ins would take address of this decl, something else?
Then there is the _simduid_ clause (also can hold address of the decl), and
after lowering it lives only in loop structure (so perhaps
remove_unused_locals would need to mark the decls referenced from loop
structure as used?).

> > treat arrays indexed by __builtin_omp.simd_lane (simd_uid) (dot in the name just
> > to make it impossible to be used by users) (or marked with some special
> > hidden attribute or something)
> 
> I see
> 
> /* This file specifies a list of internal "functions".  These functions
>    differ from built-in functions in that they have no linkage and cannot
>    be called directly by the user.  They represent operations that are only
>    synthesised by GCC itself.
> 
> and think that may be more applicable than adding dots to regular builtins.

I can certainly try to use internal function instead of builtin with dot in
name, will report later if it is possible and how much changes would it
need.

	Jakub
Richard Henderson June 12, 2013, 5:38 p.m. UTC | #23
On 06/12/2013 10:30 AM, Jakub Jelinek wrote:
> So the built-ins would take address of this decl, something else?

Perhaps address, perhaps just referenced uninitialized?

> Then there is the _simduid_ clause (also can hold address of the decl), and
> after lowering it lives only in loop structure (so perhaps
> remove_unused_locals would need to mark the decls referenced from loop
> structure as used?).

But that simd_uid clause refers to the same decl as the builtins, so the
builtins should keep the decl around, at least until they themselves are
transformed.  At which point the decl is no longer needed, no?

Indeed, I am really hoping that the decl vanishes completely before rtl.


r~
Jakub Jelinek June 12, 2013, 9:36 p.m. UTC | #24
On Wed, Jun 12, 2013 at 10:38:00AM -0700, Richard Henderson wrote:
> On 06/12/2013 10:30 AM, Jakub Jelinek wrote:
> > So the built-ins would take address of this decl, something else?
> 
> Perhaps address, perhaps just referenced uninitialized?

True, assuming no pass would actually want to change that SSA_NAME of the
magic decl just because it is undefined (coalesce with some other undefined
SSA_NAME or something similar).  I hope nothing does that, it would be
problematic for the uninitialized warning pass too I bet.

> But that simd_uid clause refers to the same decl as the builtins, so the
> builtins should keep the decl around, at least until they themselves are
> transformed.  At which point the decl is no longer needed, no?
> 
> Indeed, I am really hoping that the decl vanishes completely before rtl.

Sure, it certainly should go away at the end of vectorization (and, when we
know vectorization won't happen we just should assume safelen will be 1).

	Jakub
Aldy Hernandez June 13, 2013, 8:21 p.m. UTC | #25
On 06/12/13 16:36, Jakub Jelinek wrote:
> On Wed, Jun 12, 2013 at 10:38:00AM -0700, Richard Henderson wrote:
>> On 06/12/2013 10:30 AM, Jakub Jelinek wrote:
>>> So the built-ins would take address of this decl, something else?
>>
>> Perhaps address, perhaps just referenced uninitialized?
>
> True, assuming no pass would actually want to change that SSA_NAME of the
> magic decl just because it is undefined (coalesce with some other undefined
> SSA_NAME or something similar).  I hope nothing does that, it would be
> problematic for the uninitialized warning pass too I bet.

Boo hiss!  I've seen uninitialized variables cause all sorts of grief 
when cleaning up SSA.
diff mbox

Patch

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 54ea04f..e0d6092 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1137,6 +1137,7 @@  C_COMMON_OBJS = c-family/c-common.o c-family/c-cppbuiltin.o c-family/c-dump.o \
   c-family/c-format.o c-family/c-gimplify.o c-family/c-lex.o \
   c-family/c-omp.o c-family/c-opts.o c-family/c-pch.o \
   c-family/c-ppoutput.o c-family/c-pragma.o c-family/c-pretty-print.o \
+  c-family/c-cilkplus.o \
   c-family/c-semantics.o c-family/c-ada-spec.o tree-mudflap.o
 
 # Language-independent object files.
@@ -1966,6 +1967,9 @@  c-family/c-lex.o : c-family/c-lex.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
 c-family/c-omp.o : c-family/c-omp.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
 	$(TREE_H) $(C_COMMON_H) $(GIMPLE_H) langhooks.h
 
+c-family/c-cilkplus.o : c-family/c-cilkplus.c $(CONFIG_H) $(SYSTEM_H) \
+	coretypes.h $(TREE_H) $(C_COMMON_H) langhooks.h
+
 CFLAGS-c-family/c-opts.o += @TARGET_SYSTEM_ROOT_DEFINE@
 c-family/c-opts.o : c-family/c-opts.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
         $(TREE_H) $(C_PRAGMA_H) $(FLAGS_H) toplev.h langhooks.h \
diff --git a/gcc/c-family/c-cilkplus.c b/gcc/c-family/c-cilkplus.c
new file mode 100644
index 0000000..d5f069f
--- /dev/null
+++ b/gcc/c-family/c-cilkplus.c
@@ -0,0 +1,278 @@ 
+/* This file contains routines to construct and validate Cilk Plus
+   constructs within the C and C++ front ends.
+
+   Copyright (C) 2011-2013  Free Software Foundation, Inc.
+   Contributed by Balaji V. Iyer <balaji.v.iyer@intel.com>,
+		  Aldy Hernandez <aldyh@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "c-common.h"
+
+/* Helper function for c_check_cilk_loop.
+
+   Validate the increment in a _Cilk_for construct or a <#pragma simd>
+   for loop.
+
+   LOC is the location of the `for' keyword.  DECL is the induction
+   variable.  INCR is the original increment expression.
+
+   Returns the canonicalized increment expression for an OMP_FOR_INCR.
+   If there is a validation error, returns error_mark_node.  */
+
+static tree
+c_check_cilk_loop_incr (location_t loc, tree decl, tree incr)
+{
+  if (EXPR_HAS_LOCATION (incr))
+    loc = EXPR_LOCATION (incr);
+
+  if (!incr)
+    {
+      error_at (loc, "missing increment");
+      return error_mark_node;
+    }
+
+  switch (TREE_CODE (incr))
+    {
+    case POSTINCREMENT_EXPR:
+    case PREINCREMENT_EXPR:
+    case POSTDECREMENT_EXPR:
+    case PREDECREMENT_EXPR:
+      if (TREE_OPERAND (incr, 0) != decl)
+	break;
+
+      // Bah... canonicalize into whatever OMP_FOR_INCR needs.
+      if (POINTER_TYPE_P (TREE_TYPE (decl))
+	  && TREE_OPERAND (incr, 1))
+	{
+	  tree t = fold_convert_loc (loc,
+				     sizetype, TREE_OPERAND (incr, 1));
+
+	  if (TREE_CODE (incr) == POSTDECREMENT_EXPR
+	      || TREE_CODE (incr) == PREDECREMENT_EXPR)
+	    t = fold_build1_loc (loc, NEGATE_EXPR, sizetype, t);
+	  t = fold_build_pointer_plus (decl, t);
+	  incr = build2 (MODIFY_EXPR, void_type_node, decl, t);
+	}
+      return incr;
+
+    case MODIFY_EXPR:
+      {
+	tree rhs;
+
+	if (TREE_OPERAND (incr, 0) != decl)
+	  break;
+
+	rhs = TREE_OPERAND (incr, 1);
+	if (TREE_CODE (rhs) == PLUS_EXPR
+	    && (TREE_OPERAND (rhs, 0) == decl
+		|| TREE_OPERAND (rhs, 1) == decl)
+	    && INTEGRAL_TYPE_P (TREE_TYPE (rhs)))
+	  return incr;
+	else if (TREE_CODE (rhs) == MINUS_EXPR
+		 && TREE_OPERAND (rhs, 0) == decl
+		 && INTEGRAL_TYPE_P (TREE_TYPE (rhs)))
+	  return incr;
+	// Otherwise fail because only PLUS_EXPR and MINUS_EXPR are
+	// allowed.
+	break;
+      }
+
+    default:
+      break;
+    }
+
+  error_at (loc, "invalid increment expression");
+  return error_mark_node;
+}
+
+/* Validate a _Cilk_for construct (or a #pragma simd for loop, which
+   has the same syntactic restrictions).  Returns TRUE if there were
+   no errors, FALSE otherwise.  LOC is the location of the for.  DECL
+   is the controlling variable.  COND is the condition.  INCR is the
+   increment expression.  BODY is the body of the LOOP.  */
+
+static bool
+c_check_cilk_loop (location_t loc, tree decl, tree cond, tree incr, tree body)
+{
+  if (decl == error_mark_node
+      || cond == error_mark_node 
+      || incr == error_mark_node
+      || body == error_mark_node)
+    return false;
+
+  /* Validate the initialization.  */
+  gcc_assert (decl != NULL);
+  if (TREE_THIS_VOLATILE (decl))
+    {
+      error_at (loc, "induction variable cannot be volatile");
+      return false;
+    }
+  if (DECL_EXTERNAL (decl))
+    {
+      error_at (loc, "induction variable cannot be extern");
+      return false;
+    }
+  if (TREE_STATIC (decl))
+    {
+      error_at (loc, "induction variable cannot be static");
+      return false;
+    }
+  if (DECL_REGISTER (decl))
+    {
+      error_at (loc, "induction variable cannot be declared register");
+      return false;
+    }
+  if (!INTEGRAL_TYPE_P (TREE_TYPE (decl))
+      && !POINTER_TYPE_P (TREE_TYPE (decl)))
+    {
+      error_at (loc, "initialization variable must be of integral "
+		"or pointer type");
+      return false;
+    }
+
+  /* Validate the condition.  */
+  if (!cond)
+    {
+      error_at (loc, "missing condition");
+      return false;
+    }
+  bool cond_ok = false;
+  if (TREE_CODE (cond) == NE_EXPR
+      || TREE_CODE (cond) == LT_EXPR
+      || TREE_CODE (cond) == LE_EXPR
+      || TREE_CODE (cond) == GT_EXPR
+      || TREE_CODE (cond) == GE_EXPR)
+    {
+      /* Comparison must either be:
+	   DECL <comparison_operator> EXPR
+	   EXPR <comparison_operator> DECL
+      */
+      if (decl == TREE_OPERAND (cond, 0))
+	cond_ok = true;
+      else if (decl == TREE_OPERAND (cond, 1))
+	{
+	  /* Canonicalize the comparison so the DECL is on the LHS.  */
+	  TREE_SET_CODE (cond,
+			 swap_tree_comparison (TREE_CODE (cond)));
+	  TREE_OPERAND (cond, 1) = TREE_OPERAND (cond, 0);
+	  TREE_OPERAND (cond, 0) = decl;
+	  cond_ok = true;
+	}
+    }
+  if (!cond_ok)
+    {
+      error_at (loc, "invalid controlling predicate");
+      return false;
+    }
+
+  /* Validate the increment.  */
+  incr = c_check_cilk_loop_incr (loc, decl, incr);
+  if (incr == error_mark_node)
+    return false;
+
+  return true;
+ }
+
+/* Validate and emit code for the FOR loop following a #<pragma simd>
+   construct.
+
+   LOC is the location of the location of the FOR.
+   DECL is the iteration variable.
+   INIT is the initialization expression.
+   COND is the controlling predicate.
+   INCR is the increment expression.
+   BODY is the body of the loop.
+   CLAUSES are the clauses associated with the pragma simd loop.
+
+   Returns the generated statement.  */
+
+tree
+c_finish_cilk_simd_loop (location_t loc,
+			 tree decl,
+			 tree init, tree cond, tree incr,
+			 tree body,
+			 tree clauses)
+{
+  location_t rhs_loc;
+
+  if (!c_check_cilk_loop (loc, decl, cond, incr, body))
+    return NULL;
+
+  /* In the case of "for (int i = 0...)", init will be a decl.  It should
+     have a DECL_INITIAL that we can turn into an assignment.  */
+  if (init == decl)
+    {
+      rhs_loc = DECL_SOURCE_LOCATION (decl);
+
+      init = DECL_INITIAL (decl);
+      if (init == NULL)
+	{
+	  error_at (rhs_loc, "%qE is not initialized", decl);
+	  init = integer_zero_node;
+	  return NULL;
+	}
+
+      init = build_modify_expr (loc, decl, NULL_TREE, NOP_EXPR, rhs_loc,
+				init, NULL_TREE);
+    }
+  gcc_assert (TREE_CODE (init) == MODIFY_EXPR);
+  gcc_assert (TREE_OPERAND (init, 0) == decl);
+
+  tree initv = make_tree_vec (1);
+  tree condv = make_tree_vec (1);
+  tree incrv = make_tree_vec (1);
+  TREE_VEC_ELT (initv, 0) = init;
+  TREE_VEC_ELT (condv, 0) = cond;
+  TREE_VEC_ELT (incrv, 0) = incr;
+
+  // FIXME: What should we do about nested loops?  Look at specs.
+
+  /* The OpenMP <#pragma omp simd> construct is exactly the same as
+     the Cilk Plus one, with the exception of the vectorlength()
+     clause in Cilk Plus.  Emitting an OMP_SIMD simlifies
+     everything.  */
+  tree t = make_node (OMP_SIMD);
+  TREE_TYPE (t) = void_type_node;
+  OMP_FOR_INIT (t) = initv;
+  OMP_FOR_COND (t) = condv;
+  OMP_FOR_INCR (t) = incrv;
+  OMP_FOR_BODY (t) = body;
+  OMP_FOR_PRE_BODY (t) = NULL;
+  OMP_FOR_CLAUSES (t) = clauses;
+
+  SET_EXPR_LOCATION (t, loc);
+  return add_stmt (t);
+}
+
+/* Validate and emit code for <#pragma simd> clauses.  */
+
+tree
+c_finish_cilk_clauses (tree clauses)
+{
+  // FIXME: "...no variable shall be the subject of more than one
+  // linear clause".  Verify and check for this.
+
+  // FIXME: Also, do whatever we were doing before in
+  // same_var_in_multiple_lists_p, but rewrite to use OMP_CLAUSEs.
+
+  return clauses;
+}
diff --git a/gcc/c-family/c-pragma.c b/gcc/c-family/c-pragma.c
index b03ddc1..c05b8d0 100644
--- a/gcc/c-family/c-pragma.c
+++ b/gcc/c-family/c-pragma.c
@@ -1352,6 +1352,12 @@  init_pragma (void)
 				      omp_pragmas[i].id, true, true);
     }
 
+  if (flag_enable_cilk && !flag_preprocess_only)
+    {
+      cpp_register_deferred_pragma (parse_in, NULL, "simd", 
+				    PRAGMA_CILK_SIMD, true, false);
+    }
+
   if (!flag_preprocess_only)
     cpp_register_deferred_pragma (parse_in, "GCC", "pch_preprocess",
 				  PRAGMA_GCC_PCH_PREPROCESS, false, false);
diff --git a/gcc/c-family/c-pragma.h b/gcc/c-family/c-pragma.h
index cd121d4..2ff5a00 100644
--- a/gcc/c-family/c-pragma.h
+++ b/gcc/c-family/c-pragma.h
@@ -60,6 +60,9 @@  typedef enum pragma_kind {
   PRAGMA_OMP_THREADPRIVATE,
   PRAGMA_OMP_TEAMS,
 
+  /* Top level clause to handle all Cilk Plus pragma simd clauses.  */
+  PRAGMA_CILK_SIMD,
+
   PRAGMA_GCC_PCH_PREPROCESS,
 
   PRAGMA_FIRST_EXTERNAL
@@ -109,6 +112,19 @@  typedef enum pragma_omp_clause {
   PRAGMA_OMP_CLAUSE_UNTIED
 } pragma_omp_clause;
 
+/* All Cilk Plus #pragma omp clauses.  */
+typedef enum pragma_cilk_clause {
+  PRAGMA_CILK_CLAUSE_NONE = 0,
+  PRAGMA_CILK_CLAUSE_NOASSERT,
+  PRAGMA_CILK_CLAUSE_ASSERT,
+  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
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 10ae84d..e502b3f 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -839,6 +839,10 @@  Recognize built-in functions
 fbuiltin-
 C ObjC C++ ObjC++ Joined
 
+fcilkplus
+C ObjC C++ ObjC++ LTO Report Var(flag_enable_cilk) Init(0)
+Enable Cilk
+
 fcanonical-system-headers
 C ObjC C++ ObjC++
 Where shorter, use canonicalized paths to systems headers.
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index 5b06803..41d44a4 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -1217,6 +1217,11 @@  static void c_parser_objc_at_dynamic_declaration (c_parser *);
 static bool c_parser_objc_diagnose_bad_element_prefix
   (c_parser *, struct c_declspecs *);
 
+/* Cilk Plus supporting routines.  */
+static void c_parser_cilk_for_statement (c_parser *, enum rid, tree);
+static void c_parser_cilk_simd_construct (c_parser *);
+static bool c_parser_cilk_verify_simd (c_parser *, enum pragma_context);
+
 /* Parse a translation unit (C90 6.7, C99 6.9).
 
    translation-unit:
@@ -8622,6 +8627,13 @@  c_parser_pragma (c_parser *parser, enum pragma_context context)
       c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL);
       return false;
 
+    case PRAGMA_CILK_SIMD:
+      if (!c_parser_cilk_verify_simd (parser, context))
+	return false;
+      c_parser_consume_pragma (parser);
+      c_parser_cilk_simd_construct (parser);
+      return false;
+
     default:
       if (id < PRAGMA_FIRST_EXTERNAL)
 	{
@@ -10664,7 +10676,457 @@  c_parser_omp_threadprivate (c_parser *parser)
 
   c_parser_skip_to_pragma_eol (parser);
 }
+
+/* Cilk Plus <#pragma simd> parsing routines.  */
+
+/* Helper function for c_parser_pragma.  Perform some sanity checking
+   for <#pragma simd> constructs.  Returns FALSE if there was a
+   problem.  */
+
+static bool
+c_parser_cilk_verify_simd (c_parser *parser,
+				  enum pragma_context context)
+{
+  if (!flag_enable_cilk)
+    {
+      warning (0, "pragma simd ignored because -fcilkplus is not enabled");
+      c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL);
+      return false;
+    }
+  if (!flag_tree_vectorize)
+    {
+      warning (0, "pragma simd is useless without -ftree-vectorize");
+      c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL);
+      return false;
+    }
+  if (context == pragma_external)
+    {
+      c_parser_error (parser,"pragma simd must be inside a function");
+      c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL);
+      return false;
+    }
+  return true;
+}
+
+/* Cilk Plus:
+   assert */
+
+static tree
+c_parser_cilk_clause_assert (c_parser *parser, tree clauses)
+{
+  check_no_duplicate_clause (clauses, OMP_CLAUSE_CILK_ASSERT, "assert");
+
+  location_t loc = c_parser_peek_token (parser)->location;
+  tree c = build_omp_clause (loc, OMP_CLAUSE_CILK_ASSERT);
+  OMP_CLAUSE_CHAIN (c) = clauses;
+  return c;
+}
+
+/* Cilk Plus:
+   noassert */
+
+static tree
+c_parser_cilk_clause_noassert (c_parser *parser ATTRIBUTE_UNUSED,
+			       tree clauses)
+{
+  /* Only check that we don't already have an assert clause.  */
+  check_no_duplicate_clause (clauses, OMP_CLAUSE_CILK_ASSERT, "assert");
+
+  return clauses;
+}
+
+/* Cilk Plus:
+   vectorlength (constant-expression-list )
+
+   constant-expression-list:
+     constant-expression
+     constant-expression-list , constant-expression */
+
+static tree
+c_parser_cilk_clause_vectorlength (c_parser *parser, tree clauses)
+{
+  check_no_duplicate_clause (clauses, OMP_CLAUSE_CILK_VECTORLENGTH,
+			     "vectorlength");
+
+  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    return clauses;
+
+  location_t loc = c_parser_peek_token (parser)->location;
+  while (true)
+    {
+      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");
+      else
+	{
+	  tree u = build_omp_clause (loc, OMP_CLAUSE_CILK_VECTORLENGTH);
+	  OMP_CLAUSE_CILK_VECTORLENGTH_EXPR (u) = expr;
+	  OMP_CLAUSE_CHAIN (u) = clauses;
+	  clauses = u;
+	}
+
+      if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+	{
+	  c_parser_consume_token (parser);
+	  return clauses;
+	}
+      if (c_parser_next_token_is (parser, CPP_COMMA))
+	c_parser_consume_token (parser);
+    }
+
+  return clauses;
+}
+
+/* Cilk Plus:
+   linear ( simd-linear-variable-list )
+
+   simd-linear-variable-list:
+     simd-linear-variable
+     simd-linear-variable-list , simd-linear-variable
+
+   simd-linear-variable:
+     id-expression
+     id-expression : simd-linear-step
+
+   simd-linear-step:
+   conditional-expression */
+
+static tree
+c_parser_cilk_clause_linear (c_parser *parser, tree clauses)
+{
+  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    return clauses;
+
+  location_t loc = c_parser_peek_token (parser)->location;
 
+  if (c_parser_next_token_is_not (parser, CPP_NAME)
+      || c_parser_peek_token (parser)->id_kind != C_ID_ID)
+    c_parser_error (parser, "expected identifier");
+
+  while (c_parser_next_token_is (parser, CPP_NAME)
+	 && c_parser_peek_token (parser)->id_kind == C_ID_ID)
+    {
+      tree var = lookup_name (c_parser_peek_token (parser)->value);
+
+      if (var == NULL)
+	{
+	  undeclared_variable (c_parser_peek_token (parser)->location,
+			       c_parser_peek_token (parser)->value);
+	c_parser_consume_token (parser);
+	}
+      else if (var == error_mark_node)
+	c_parser_consume_token (parser);
+      else
+	{
+	  tree step = integer_one_node;
+
+	  /* Parse the linear step if present.  */
+	  if (c_parser_peek_2nd_token (parser)->type == CPP_COLON)
+	    {
+	      c_parser_consume_token (parser);
+	      c_parser_consume_token (parser);
+
+	      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)))
+		c_parser_error (parser,
+				"step size must be an integer constant");
+	      else
+		step = expr;
+	    }
+	  else
+	    c_parser_consume_token (parser);
+
+	  /* Use OMP_CLAUSE_LINEAR, which has the same semantics.  */
+	  tree u = build_omp_clause (loc, OMP_CLAUSE_LINEAR);
+	  OMP_CLAUSE_DECL (u) = var;
+	  OMP_CLAUSE_LINEAR_STEP (u) = step;
+	  OMP_CLAUSE_CHAIN (u) = clauses;
+	  clauses = u;
+	}
+
+      if (c_parser_next_token_is_not (parser, CPP_COMMA))
+	break;
+
+      c_parser_consume_token (parser);
+    }
+
+  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+
+  return clauses;
+}
+
+/* Returns the name of the next clause.  If the clause is not
+   recognized SIMD_OMP_CLAUSE_NONE is returned and the next token is
+   not consumed.  Otherwise, the appropriate pragma_simd_clause is
+   returned and the token is consumed.  */
+
+static pragma_cilk_clause
+c_parser_cilk_clause_name (c_parser *parser)
+{
+  pragma_cilk_clause result;
+  c_token *token = c_parser_peek_token (parser);
+
+  if (!token->value || token->type != CPP_NAME)
+    return PRAGMA_CILK_CLAUSE_NONE;
+
+  const char *p = IDENTIFIER_POINTER (token->value);
+
+  if (!strcmp (p, "noassert"))
+    result = PRAGMA_CILK_CLAUSE_NOASSERT;
+  else if (!strcmp (p, "assert"))
+    result = PRAGMA_CILK_CLAUSE_ASSERT;
+  else if (!strcmp (p, "vectorlength"))
+    result = PRAGMA_CILK_CLAUSE_VECTORLENGTH;
+  else if (!strcmp (p, "linear"))
+    result = PRAGMA_CILK_CLAUSE_LINEAR;
+  else if (!strcmp (p, "private"))
+    result = PRAGMA_CILK_CLAUSE_PRIVATE;
+  else if (!strcmp (p, "firstprivate"))
+    result = PRAGMA_CILK_CLAUSE_FIRSTPRIVATE;
+  else if (!strcmp (p, "lastprivate"))
+    result = PRAGMA_CILK_CLAUSE_LASTPRIVATE;
+  else if (!strcmp (p, "reduction"))
+    result = PRAGMA_CILK_CLAUSE_REDUCTION;
+  else
+    return PRAGMA_CILK_CLAUSE_NONE;
+
+  c_parser_consume_token (parser);
+  return result;
+}
+
+/* Parse all #<pragma simd> clauses.  Return the list of clauses
+   found.  */
+
+static tree
+c_parser_cilk_all_clauses (c_parser *parser)
+{
+  tree clauses = NULL;
+
+  while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
+    {
+      pragma_cilk_clause c_kind;
+
+      c_kind = c_parser_cilk_clause_name (parser);
+
+      switch (c_kind)
+	{
+	case PRAGMA_CILK_CLAUSE_NOASSERT:
+	  clauses = c_parser_cilk_clause_noassert (parser, clauses);
+	  break;
+	case PRAGMA_CILK_CLAUSE_ASSERT:
+	  clauses = c_parser_cilk_clause_assert (parser, clauses);
+	  break;
+	case PRAGMA_CILK_CLAUSE_VECTORLENGTH:
+	  clauses = c_parser_cilk_clause_vectorlength (parser, clauses);
+	  break;
+	case PRAGMA_CILK_CLAUSE_LINEAR:
+	  clauses = c_parser_cilk_clause_linear (parser, clauses);
+	  break;
+	case PRAGMA_CILK_CLAUSE_PRIVATE:
+	  /* Use the OpenMP counterpart.  */
+	  clauses = c_parser_omp_clause_private (parser, clauses);
+	  break;
+	case PRAGMA_CILK_CLAUSE_FIRSTPRIVATE:
+	  /* Use the OpenMP counterpart.  */
+	  clauses = c_parser_omp_clause_firstprivate (parser, clauses);
+	  break;
+	case PRAGMA_CILK_CLAUSE_LASTPRIVATE:
+	  /* Use the OpenMP counterpart.  */
+	  clauses = c_parser_omp_clause_lastprivate (parser, clauses);
+	  break;
+	case PRAGMA_CILK_CLAUSE_REDUCTION:
+	  /* Use the OpenMP counterpart.  */
+	  clauses = c_parser_omp_clause_reduction (parser, clauses);
+	  break;
+	default:
+	  c_parser_error (parser, "expected %<#pragma simd%> clause");
+	  goto saw_error;
+	}
+    }
+
+ saw_error:
+  c_parser_skip_to_pragma_eol (parser);
+  return c_finish_cilk_clauses (clauses);
+}
+
+/* Parse the restriction form of the for statement allowed by
+   Cilk Plus.  This function parses both the _CILK_FOR construct as
+   well as the for loop following a <#pragma simd> construct, both of
+   which have the same syntactic restrictions.
+
+   FOR_KEYWORD can be either RID_CILK_FOR or RID_FOR, for parsing
+   _cilk_for or the <#pragma simd> for loop construct respectively.
+
+   (NOTE: For now, only RID_FOR is handled).
+
+   For a <#pragma simd>, CLAUSES are the clauses that should have been
+   previously parsed.  If there are none, or if we are parsing a
+   _Cilk_for instead, this will be NULL.  */
+   
+static void
+c_parser_cilk_for_statement (c_parser *parser, enum rid for_keyword,
+			     tree clauses)
+{
+  tree init, decl,  cond, stmt;
+  tree block, incr, save_break, save_cont, body;
+  location_t loc;
+  bool fail = false;
+
+  gcc_assert (/*for_keyword == RID_CILK_FOR || */for_keyword == RID_FOR);
+
+  if (!c_parser_next_token_is_keyword (parser, for_keyword))
+    {
+      if (for_keyword == RID_FOR)
+	c_parser_error (parser, "for statement expected");
+      else
+	c_parser_error (parser, "_Cilk_for statement expected");
+      return;
+    }
+
+  loc = c_parser_peek_token (parser)->location;
+  c_parser_consume_token (parser);
+
+  block = c_begin_compound_stmt (true);
+
+  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    {
+      add_stmt (c_end_compound_stmt (loc, block, true));
+      return;
+    }
+
+  /* Parse the initialization declaration.  */
+  if (c_parser_next_tokens_start_declaration (parser))
+    {
+      c_parser_declaration_or_fndef (parser, true, false, false,
+				     false, false, NULL);
+      decl = check_for_loop_decls (loc, flag_isoc99);
+      if (decl == NULL)
+	goto error_init;
+      if (DECL_INITIAL (decl) == error_mark_node)
+	decl = error_mark_node;
+      init = decl;
+    }
+  else if (c_parser_next_token_is (parser, CPP_NAME)
+	   && c_parser_peek_2nd_token (parser)->type == CPP_EQ)
+    {
+      struct c_expr decl_exp;
+      struct c_expr init_exp;
+      location_t init_loc;
+
+      decl_exp = c_parser_postfix_expression (parser);
+      decl = decl_exp.value;
+
+      c_parser_require (parser, CPP_EQ, "expected %<=%>");
+
+      init_loc = c_parser_peek_token (parser)->location;
+      init_exp = c_parser_expr_no_commas (parser, NULL);
+      init_exp = default_function_array_read_conversion (init_loc,
+							 init_exp);
+      init = build_modify_expr (init_loc, decl, decl_exp.original_type,
+				NOP_EXPR, init_loc, init_exp.value,
+				init_exp.original_type);
+      init = c_process_expr_stmt (init_loc, init);
+
+      c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+    }
+  else
+    {
+    error_init:
+      c_parser_error (parser,
+		      "expected iteration declaration or initialization");
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+				 "expected %<)%>");
+      return;
+    }
+
+  /* Parse the loop condition.  */
+  cond = NULL_TREE;
+  if (c_parser_next_token_is_not (parser, CPP_SEMICOLON))
+    {
+      location_t cond_loc = c_parser_peek_token (parser)->location;
+      struct c_expr cond_expr = c_parser_binary_expression (parser, NULL,
+							    NULL);
+
+      cond = cond_expr.value;
+      cond = c_objc_common_truthvalue_conversion (cond_loc, cond);
+      cond = c_fully_fold (cond, false, NULL);
+    }
+  c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+
+  /* Parse the increment expression.  */
+  incr = NULL_TREE;
+  if (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN))
+    {
+      location_t incr_loc = c_parser_peek_token (parser)->location;
+      incr = c_process_expr_stmt (incr_loc,
+				  c_parser_expression (parser).value);
+    }
+  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+
+  if (decl == NULL || decl == error_mark_node || init == error_mark_node)
+    fail = true;
+
+  save_break = c_break_label;
+  /* Magic number to inform c_finish_bc_stmt() that we are within a
+     Cilk for construct.  */
+  c_break_label = build_int_cst (size_type_node, 2);
+
+  save_cont = c_cont_label;
+  c_cont_label = NULL_TREE;
+  body = c_parser_c99_block_statement (parser);
+  c_break_label = save_break;
+  c_cont_label = save_cont;
+
+  // FIXME: Disallow the following constructs within a SIMD loop:
+  //
+  // RETURN
+  // GOTO
+  // _Cilk_spawn
+  // _Cilk_for
+  // OpenMP directive or construct
+  // Calls to setjmp()
+
+  if (!fail)
+    {
+      /*
+      // FIXME: Uncomment when RID_CILK_FOR is implemented.
+      if (for_keyword == RID_CILK_FOR)
+	c_finish_cilk_loop (loc, decl, cond, incr, body, grain);
+      else
+      */
+	c_finish_cilk_simd_loop (loc, decl, init, cond, incr, body, clauses);
+    }
+
+  stmt = c_end_compound_stmt (loc, block, true);
+  add_stmt (stmt);
+  c_break_label = save_break;
+  c_cont_label = save_cont;
+}
+
+/* Main entry point for parsing Cilk Plus <#pragma simd> for
+   loops.  */
+
+static void
+c_parser_cilk_simd_construct (c_parser *parser)
+{
+  tree clauses = c_parser_cilk_all_clauses (parser);
+
+  /* For <#pragma simd> we will be generating OMP_SIMD's and let the
+     OpenMP mechanism handle everything.  */
+  if (!flag_openmp)
+    flag_openmp = true;
+
+  c_parser_cilk_for_statement (parser, RID_FOR, clauses);
+}
+
 /* Parse a transaction attribute (GCC Extension).
 
    transaction-attribute:
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index c4210a5..0fd9cc6 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -642,6 +642,11 @@  extern tree c_build_va_arg (location_t, tree, tree);
 extern tree c_finish_transaction (location_t, tree, int);
 extern bool c_tree_equal (tree, tree);
 
+/* In c-cilkplus.c */
+extern tree c_finish_cilk_simd_loop (location_t, tree, tree, tree, tree,
+				     tree, tree);
+extern tree c_finish_cilk_clauses (tree);
+
 /* Set to 0 at beginning of a function definition, set to 1 if
    a return statement that specifies a return value is seen.  */
 
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index f6b6717..013fe43 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -6337,6 +6337,8 @@  gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p,
 	case OMP_CLAUSE_MERGEABLE:
 	case OMP_CLAUSE_PROC_BIND:
 	case OMP_CLAUSE_SAFELEN:
+	case OMP_CLAUSE_CILK_ASSERT:
+	case OMP_CLAUSE_CILK_VECTORLENGTH:
 	  break;
 
 	case OMP_CLAUSE_ALIGNED:
@@ -6528,6 +6530,8 @@  gimplify_adjust_omp_clauses (tree *list_p)
 	case OMP_CLAUSE_MERGEABLE:
 	case OMP_CLAUSE_PROC_BIND:
 	case OMP_CLAUSE_SAFELEN:
+	case OMP_CLAUSE_CILK_ASSERT:
+	case OMP_CLAUSE_CILK_VECTORLENGTH:
 	  break;
 
 	default:
diff --git a/gcc/omp-low.c b/gcc/omp-low.c
index 58117d9..b38ed9b 100644
--- a/gcc/omp-low.c
+++ b/gcc/omp-low.c
@@ -1491,6 +1491,8 @@  scan_sharing_clauses (tree clauses, omp_context *ctx)
 	case OMP_CLAUSE_PROC_BIND:
 	case OMP_CLAUSE_SAFELEN:
 	case OMP_CLAUSE_ALIGNED:
+	case OMP_CLAUSE_CILK_ASSERT:
+	case OMP_CLAUSE_CILK_VECTORLENGTH:
 	  break;
 
 	default:
@@ -1547,6 +1549,8 @@  scan_sharing_clauses (tree clauses, omp_context *ctx)
 	case OMP_CLAUSE_PROC_BIND:
 	case OMP_CLAUSE_SAFELEN:
 	case OMP_CLAUSE_ALIGNED:
+	case OMP_CLAUSE_CILK_ASSERT:
+	case OMP_CLAUSE_CILK_VECTORLENGTH:
 	  break;
 
 	default:
diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/cilk-simd-compile.exp b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/cilk-simd-compile.exp
new file mode 100644
index 0000000..154bb8c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/cilk-simd-compile.exp
@@ -0,0 +1,23 @@ 
+#   Copyright (C) 2013 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+load_lib gcc-dg.exp
+
+set OPTS "-fcilkplus -c -ftree-vectorize"
+
+dg-init
+dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.c]] " $OPTS" " "
+dg-finish
diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/clauses1.c b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/clauses1.c
new file mode 100644
index 0000000..ae01db3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/clauses1.c
@@ -0,0 +1,84 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O3 -std=c99 -fcilkplus" } */
+
+volatile int *a, *b;
+
+void foo()
+{
+  int i, j, k;
+
+#pragma simd assert aoeu /* { dg-error "expected '#pragma simd' clause" } */
+  for (int i=0; i < 1000; ++i)
+    a[i] = b[j];
+
+#pragma simd noassert aoeu /* { dg-error "expected '#pragma simd' clause" } */
+  for (int i=0; i < 1000; ++i)
+    a[i] = b[j];
+
+#pragma simd assert noassert /* { dg-error "too many 'assert' clauses" } */
+  for (int i=0; i < 1000; ++i)
+    a[i] = b[j];
+
+#pragma simd vectorlength /* { dg-error "expected '\\('" } */
+  for (int i=0; i < 1000; ++i)
+    a[i] = b[j];
+
+#pragma simd vectorlength /* { dg-error "expected '\\('" } */
+  for (int i=0; i < 1000; ++i)
+    a[i] = b[j];
+
+#pragma simd vectorlength(sizeof (a) == sizeof (float) ? 4 : 8)
+  for (int i=0; i < 1000; ++i)
+    a[i] = b[j];
+
+#pragma simd vectorlength(4,8)
+  for (int i=0; i < 1000; ++i)
+    a[i] = b[j];
+
+#pragma simd vectorlength(i) /* { dg-error "vectorlength must be an integer" } */
+  for (int i=0; i < 1000; ++i)
+    a[i] = b[j];
+
+#pragma simd linear(35) /* { dg-error "expected identifier" } */
+  for (int i=0; i < 1000; ++i)
+    a[i] = b[j];
+
+#pragma simd linear(blah) /* { dg-error "'blah' undeclared" } */
+  for (int i=0; i < 1000; ++i)
+    a[i] = b[j];
+
+#pragma simd linear(blah2, 36)
+  /* { dg-error "'blah2' undeclared" "undeclared" { target *-*-* } 50 } */
+  /* { dg-error "expected '\\)'" "expected" { target *-*-* } 50 } */
+  for (int i=0; i < 1000; ++i)
+    a[i] = b[j];
+
+#pragma simd linear(j, 36, k) /* { dg-error "expected '\\)'" } */
+  for (int i=0; i < 1000; ++i)
+    a[i] = b[j];
+
+#pragma simd linear(i, j)
+  for (int i=0; i < 1000; ++i)
+    a[i] = b[j];
+
+#pragma simd linear(i)
+  for (int i=0; i < 1000; ++i)
+    a[i] = b[j];
+
+#pragma simd linear(i : 4)
+  for (int i=0; i < 1000; ++i)
+    a[i] = b[j];
+
+#pragma simd linear(i : 2, j : 4, k)
+  for (int i=0; i < 1000; ++i)
+    a[i] = b[j];
+
+#pragma simd linear(j : sizeof (a) == sizeof (float) ? 4 : 8)
+  for (int i=0; i < 1000; ++i)
+    a[i] = b[j];
+
+  // And now everyone in unison!
+#pragma simd assert linear(j : 4) vectorlength(4)
+  for (i=0; i < 1000; ++i)
+    a[i] = b[j];
+}
diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/clauses2.c b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/clauses2.c
new file mode 100644
index 0000000..6be6085
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/clauses2.c
@@ -0,0 +1,19 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O3 -std=c99 -fcilkplus -fdump-tree-original" } */
+
+volatile int *a, *b;
+
+void foo()
+{
+  int i, j, k;
+
+#pragma simd assert linear(j : 4, k) vectorlength(4)
+  for (i=0; i < 1000; ++i)
+    a[i] = b[j];
+}
+
+/* { dg-final { scan-tree-dump-times "linear\\(j:4\\)" 1 "original" } } */
+/* { dg-final { scan-tree-dump-times "linear\\(k:1\\)" 1 "original" } } */
+/* { dg-final { scan-tree-dump-times "cilk_vectorlength\\(4\\)" 1 "original" } } */
+/* { dg-final { scan-tree-dump-times "cilk_assert" 1 "original" } } */
+/* { dg-final { cleanup-tree-dump "original" } } */
diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for1.c b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for1.c
new file mode 100644
index 0000000..38700e4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for1.c
@@ -0,0 +1,135 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O3 -std=c99 -fcilkplus" } */
+
+int *a, *b, *c;
+
+void foo()
+{
+  int i, j;
+
+  // The initialization shall declare or initialize a *SINGLE* variable.
+#pragma simd
+  for (i=0, j=5; i < 1000; i++) // { dg-error "expected ';' before ','" }
+    a[i] = b[j];
+
+  // Declaration and initialization is allowed.
+#pragma simd
+  for (int i=0; i < 1000; i++)
+    a[i] = b[j];
+
+  // Empty initialization is not allowed.
+#pragma simd
+  for (; i < 5; ++i)		// { dg-error "expected iteration decl" }
+    a[i] = i;
+
+  // Empty condition is not allowed.
+#pragma simd
+  for (i=0; ; ++i)		/* { dg-error "missing condition" } */
+    a[i] = i;
+
+  // Empty increment is not allowed.
+#pragma simd
+  for (i=0; i < 1234; )		/* { dg-error "missing increment" } */
+    a[i] = i*2;
+
+#pragma simd
+  i = 5; /* { dg-error "for statement expected" } */
+
+  // Initialization variables must be either integral or pointer types.
+  struct S {
+    int i;
+  };
+#pragma simd
+  for (struct S ss = { 0 }; ss.i <= 1000; ++ss.i) /* { dg-error "initialization variable must be of integral or pointer type" } */
+    a[ss.i] = b[ss.i];
+
+  #pragma simd
+  for (float f=0.0; f < 15.0; ++f) /* { dg-error "must be of integral" } */
+    a[(int)f] = (int) f;
+
+  // Pointers are OK.
+  #pragma simd
+  for (int *i=c; i < &c[100]; ++i)
+    *a = '5';
+
+  // Condition of '==' is not allowed.
+#pragma simd
+  for (i=j; i == 5; ++i) /* { dg-error "invalid controlling predicate" } */
+    a[i] = b[i];
+
+  // The LHS or RHS of the condition must be the initialization variable.
+#pragma simd
+  for (i=0; i+j < 1234; ++i) /* { dg-error "invalid controlling predicate" } */
+    a[i] = b[i];  
+
+  // Likewise.
+#pragma simd
+  for (i=0; 1234 < i + j; ++i) /* { dg-error "invalid controlling predicate" } */
+    a[i] = b[i];  
+
+  // Likewise, this is ok.
+#pragma simd
+  for (i=0; 1234 + j < i; ++i)
+    a[i] = b[i];
+
+  // According to the CilkPlus forum, casts are not allowed, even if
+  // they are no-ops.
+#pragma simd
+  for (i=0; (char)i < 1234; ++i) /* { dg-error "invalid controlling predicate" } */
+    a[i] = b[i];
+
+  // ?? This condition gets folded into "i != 0" by
+  // c_parser_cilk_for_statement().  Does this count as a "!=", or is
+  // this disallowed?  Assume it is allowed.
+#pragma simd
+  for (i=100; i; --i)
+    a[i] = b[i];
+
+  // Increment must be on the induction variable.
+#pragma simd
+  for (i=0; i < 100; j++) /* { dg-error "invalid increment expression" } */
+    a[i] = b[i];
+
+  // Likewise.
+#pragma simd
+  for (i=0; i < 100; j = i + 1) /* { dg-error "invalid increment expression" } */
+    a[i] = b[i];
+
+  // Likewise.
+#pragma simd
+  for (i=0; i < 100; i = j + 1) /* { dg-error "invalid increment expression" } */
+    a[i] = b[i];
+
+#pragma simd
+  for (i=0; i < 100; i = i + 5)
+    a[i] = b[i];
+
+  // Only PLUS and MINUS increments are allowed.
+#pragma simd
+  for (i=0; i < 100; i *= 5) /* { dg-error "invalid increment expression" } */
+    a[i] = b[i];
+
+#pragma simd
+  for (i=0; i < 100; i -= j)
+    a[i] = b[i];
+
+#pragma simd
+  for (i=0; i < 100; i = i + j)
+    a[i] = b[i];
+
+#pragma simd
+  for (i=0; i < 100; i = j + i)
+    a[i] = b[i];
+
+#pragma simd
+  for (i=0; i < 100; ++i, ++j) /* { dg-error "invalid increment expression" } */
+    a[i] = b[i];
+
+#pragma simd
+  for (int *point=0; point < b; ++point)
+    *point = 555;
+
+#pragma simd
+  for (int *point=0; point > b; --point)
+    *point = 555;
+}
diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for2.c b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for2.c
new file mode 100644
index 0000000..2d09ae8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for2.c
@@ -0,0 +1,66 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O3 -std=c99 -fcilkplus" } */
+
+// Test storage classes in the initialization of a <#pragma simd> for
+// loop.
+
+int *a, *b;
+
+void foo()
+{
+#pragma simd
+  for (static int foo=5; foo < 10; ++foo)
+    a[foo] = b[foo];
+  /* { dg-error "declaration of static variable" "storage class1" { target *-*-* } 12 } */
+  /* { dg-error "induction variable cannot be static" "storage class2" { target *-*-* } 12 } */
+
+  static int bar;
+#pragma simd
+  for (bar=0; bar < 1000; ++bar) /* { dg-error "induction variable cannot be static" } */
+    a[bar] = bar;
+
+#pragma simd
+  for (extern int var=0; var < 1000; ++var)
+    a[var] = var;
+  /* { dg-error "has both 'extern' and initializer" "extern" { target *-*-* } 23 } */
+  /* { dg-error "declaration of static variable" "" { target *-*-* } 23 } */
+  /* { dg-error "induction variable cannot be static" "" { target *-*-* } 23 } */
+
+  extern int extvar;
+#pragma simd
+  for (extvar = 0; extvar < 1000; ++extvar) /* { dg-error "induction variable cannot be extern" } */
+    b[extvar] = a[extvar];
+
+  // This seems like it should be ok.
+  // Must check with standards people.
+#pragma simd
+  for (auto int autoi = 0; autoi < 1000; ++autoi)
+    b[autoi] = a[autoi] * 2;
+  // Similarly here.
+  auto int autoj;
+#pragma simd
+  for (auto int autoj = 0; autoj < 1000; ++autoj)
+    b[autoj] = a[autoj] * 2;
+
+  register int regi;
+#pragma simd
+  for (regi = 0; regi < 1000; ++regi) /* { dg-error "induction variable cannot be declared register" } */
+    b[regi] = a[regi] * 2;
+
+#pragma simd
+  for (register int regj = 0; regj < 1000; ++regj) /* { dg-error "induction variable cannot be declared register" } */
+    b[regj] = a[regj] * 2;
+
+  volatile int vi;
+#pragma simd
+  for (vi=0; vi<1000; ++vi) /* { dg-error "induction variable cannot be volatile" } */
+    a[vi] = b[vi];
+
+#pragma simd
+  for (volatile int vj=0; vj<1000; ++vj) /* { dg-error "induction variable cannot be volatile" } */
+    a[vj] = b[vj];
+
+#pragma simd
+  for (const int ci=0; ci<1000; ++ci) /* { dg-error "increment of read-only var" } */
+    a[ci] = b[ci];
+}
diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for3.c b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for3.c
new file mode 100644
index 0000000..8660627
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for3.c
@@ -0,0 +1,8 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O3 -fcilkplus" } */
+
+#pragma simd		/* { dg-error "must be inside a function" } */
+
+void foo()
+{
+}
diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c
index f3de68c..8d1f06e9 100644
--- a/gcc/tree-pretty-print.c
+++ b/gcc/tree-pretty-print.c
@@ -586,6 +586,17 @@  dump_omp_clause (pretty_printer *buffer, tree clause, int spc, int flags)
       pp_string (buffer, "taskgroup");
       break;
 
+    case OMP_CLAUSE_CILK_ASSERT:
+      pp_string (buffer, "cilk_assert");
+      break;
+
+    case OMP_CLAUSE_CILK_VECTORLENGTH:
+      pp_string (buffer, "cilk_vectorlength(");
+      dump_generic_node (buffer, OMP_CLAUSE_CILK_VECTORLENGTH_EXPR (clause),
+			 spc, flags, false);
+      pp_character (buffer, ')');
+      break;
+
     default:
       /* Should never happen.  */
       dump_generic_node (buffer, clause, spc, flags, false);
diff --git a/gcc/tree.c b/gcc/tree.c
index 36fadff..2bc6131 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -264,6 +264,8 @@  unsigned const char omp_clause_num_ops[] =
   0, /* OMP_CLAUSE_PARALLEL  */
   0, /* OMP_CLAUSE_SECTIONS  */
   0  /* OMP_CLAUSE_TASKGROUP  */
+  , 0, /* OMP_CLAUSE_CILK_ASSERT  */
+  1, /* OMP_CLAUSE_CILK_VECTORLENGTH  */
 };
 
 const char * const omp_clause_code_name[] =
@@ -305,6 +307,8 @@  const char * const omp_clause_code_name[] =
   "parallel",
   "sections",
   "taskgroup"
+  , "cilk_assert",
+  "cilk_vectorlength",
 };
 
 
@@ -10809,6 +10813,7 @@  walk_tree_1 (tree *tp, walk_tree_fn func, void *data,
 	case OMP_CLAUSE_DIST_SCHEDULE:
 	case OMP_CLAUSE_SAFELEN:
 	case OMP_CLAUSE_SIMDLEN:
+	case OMP_CLAUSE_CILK_VECTORLENGTH:
 	  WALK_SUBTREE (OMP_CLAUSE_OPERAND (*tp, 0));
 	  /* FALLTHRU */
 
@@ -10853,6 +10858,9 @@  walk_tree_1 (tree *tp, walk_tree_fn func, void *data,
 	    WALK_SUBTREE_TAIL (OMP_CLAUSE_CHAIN (*tp));
 	  }
 
+	case OMP_CLAUSE_CILK_ASSERT:
+	  break;
+
 	default:
 	  gcc_unreachable ();
 	}
diff --git a/gcc/tree.h b/gcc/tree.h
index b4bd6c4..75fbebf 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -446,7 +446,13 @@  enum omp_clause_code
   OMP_CLAUSE_SECTIONS,
 
   /* OpenMP clause: taskgroup.  */
-  OMP_CLAUSE_TASKGROUP
+  OMP_CLAUSE_TASKGROUP,
+
+  /* Cilk Plus clause: assert.  */
+  OMP_CLAUSE_CILK_ASSERT,
+
+  /* Cilk Plus clause: vectorlength (constant-expression-list).  */
+  OMP_CLAUSE_CILK_VECTORLENGTH
 };
 
 /* The definition of tree nodes fills the next several pages.  */
@@ -1857,6 +1863,13 @@  extern void protected_set_expr_location (tree, location_t);
   OMP_CLAUSE_OPERAND (OMP_CLAUSE_RANGE_CHECK (OMP_CLAUSE_CHECK (NODE),	\
 					      OMP_CLAUSE_PRIVATE,	\
 					      OMP_CLAUSE_MAP), 0)
+
+/* In an OMP_SIMD_CLAUSE_CILK_VECTORLENGTH, one vectorlength
+   expression.  */
+#define OMP_CLAUSE_CILK_VECTORLENGTH_EXPR(NODE) \
+  OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK \
+		      (NODE, OMP_CLAUSE_CILK_VECTORLENGTH), 0)
+
 #define OMP_CLAUSE_HAS_LOCATION(NODE) \
   (LOCATION_LOCUS ((OMP_CLAUSE_CHECK (NODE))->omp_clause.locus)		\
   != UNKNOWN_LOCATION)