111 changes: 107 additions & 4 deletions clang/lib/Sema/SemaOpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,20 +57,23 @@ class DSAStackTy {
DeclRefExpr *RefExpr;
};
typedef llvm::SmallDenseMap<VarDecl *, DSAInfo, 64> DeclSAMapTy;
typedef llvm::SmallDenseMap<VarDecl *, DeclRefExpr *, 64> AlignedMapTy;

struct SharingMapTy {
DeclSAMapTy SharingMap;
AlignedMapTy AlignedMap;
DefaultDataSharingAttributes DefaultAttr;
OpenMPDirectiveKind Directive;
DeclarationNameInfo DirectiveName;
Scope *CurScope;
SharingMapTy(OpenMPDirectiveKind DKind, DeclarationNameInfo Name,
Scope *CurScope)
: SharingMap(), DefaultAttr(DSA_unspecified), Directive(DKind),
DirectiveName(std::move(Name)), CurScope(CurScope) {}
: SharingMap(), AlignedMap(), DefaultAttr(DSA_unspecified),
Directive(DKind), DirectiveName(std::move(Name)), CurScope(CurScope) {
}
SharingMapTy()
: SharingMap(), DefaultAttr(DSA_unspecified), Directive(OMPD_unknown),
DirectiveName(), CurScope(nullptr) {}
: SharingMap(), AlignedMap(), DefaultAttr(DSA_unspecified),
Directive(OMPD_unknown), DirectiveName(), CurScope(nullptr) {}
};

typedef SmallVector<SharingMapTy, 64> StackTy;
Expand Down Expand Up @@ -99,6 +102,11 @@ class DSAStackTy {
Stack.pop_back();
}

/// \brief If 'aligned' declaration for given variable \a D was not seen yet,
/// add it and return NULL; otherwise return previous occurence's expression
/// for diagnostics.
DeclRefExpr *addUniqueAligned(VarDecl *D, DeclRefExpr *NewDE);

/// \brief Adds explicit data sharing attribute to the specified declaration.
void addDSA(VarDecl *D, DeclRefExpr *E, OpenMPClauseKind A);

Expand Down Expand Up @@ -242,6 +250,20 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter,
return getDSA(std::next(Iter), D);
}

DeclRefExpr *DSAStackTy::addUniqueAligned(VarDecl *D, DeclRefExpr *NewDE) {
assert(Stack.size() > 1 && "Data sharing attributes stack is empty");
auto It = Stack.back().AlignedMap.find(D);
if (It == Stack.back().AlignedMap.end()) {
assert(NewDE && "Unexpected nullptr expr to be added into aligned map");
Stack.back().AlignedMap[D] = NewDE;
return nullptr;
} else {
assert(It->second && "Unexpected nullptr expr in the aligned map");
return It->second;
}
return nullptr;
}

void DSAStackTy::addDSA(VarDecl *D, DeclRefExpr *E, OpenMPClauseKind A) {
if (A == OMPC_threadprivate) {
Stack[0].SharingMap[D].Attributes = A;
Expand Down Expand Up @@ -855,6 +877,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
case OMPC_firstprivate:
case OMPC_shared:
case OMPC_linear:
case OMPC_aligned:
case OMPC_copyin:
case OMPC_threadprivate:
case OMPC_unknown:
Expand Down Expand Up @@ -1025,6 +1048,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(
case OMPC_firstprivate:
case OMPC_shared:
case OMPC_linear:
case OMPC_aligned:
case OMPC_copyin:
case OMPC_threadprivate:
case OMPC_unknown:
Expand Down Expand Up @@ -1128,6 +1152,10 @@ Sema::ActOnOpenMPVarListClause(OpenMPClauseKind Kind, ArrayRef<Expr *> VarList,
Res = ActOnOpenMPLinearClause(VarList, TailExpr, StartLoc, LParenLoc,
ColonLoc, EndLoc);
break;
case OMPC_aligned:
Res = ActOnOpenMPAlignedClause(VarList, TailExpr, StartLoc, LParenLoc,
ColonLoc, EndLoc);
break;
case OMPC_copyin:
Res = ActOnOpenMPCopyinClause(VarList, StartLoc, LParenLoc, EndLoc);
break;
Expand Down Expand Up @@ -1641,6 +1669,81 @@ OMPClause *Sema::ActOnOpenMPLinearClause(ArrayRef<Expr *> VarList, Expr *Step,
Vars, StepExpr);
}

OMPClause *Sema::ActOnOpenMPAlignedClause(
ArrayRef<Expr *> VarList, Expr *Alignment, SourceLocation StartLoc,
SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc) {

SmallVector<Expr *, 8> Vars;
for (auto &RefExpr : VarList) {
assert(RefExpr && "NULL expr in OpenMP aligned clause.");
if (isa<DependentScopeDeclRefExpr>(RefExpr)) {
// It will be analyzed later.
Vars.push_back(RefExpr);
continue;
}

SourceLocation ELoc = RefExpr->getExprLoc();
// OpenMP [2.1, C/C++]
// A list item is a variable name.
DeclRefExpr *DE = dyn_cast<DeclRefExpr>(RefExpr);
if (!DE || !isa<VarDecl>(DE->getDecl())) {
Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange();
continue;
}

VarDecl *VD = cast<VarDecl>(DE->getDecl());

// OpenMP [2.8.1, simd construct, Restrictions]
// The type of list items appearing in the aligned clause must be
// array, pointer, reference to array, or reference to pointer.
QualType QType = DE->getType()
.getNonReferenceType()
.getUnqualifiedType()
.getCanonicalType();
const Type *Ty = QType.getTypePtrOrNull();
if (!Ty || (!Ty->isDependentType() && !Ty->isArrayType() &&
!Ty->isPointerType())) {
Diag(ELoc, diag::err_omp_aligned_expected_array_or_ptr)
<< QType << getLangOpts().CPlusPlus << RefExpr->getSourceRange();
bool IsDecl =
VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
Diag(VD->getLocation(),
IsDecl ? diag::note_previous_decl : diag::note_defined_here)
<< VD;
continue;
}

// OpenMP [2.8.1, simd construct, Restrictions]
// A list-item cannot appear in more than one aligned clause.
if (DeclRefExpr *PrevRef = DSAStack->addUniqueAligned(VD, DE)) {
Diag(ELoc, diag::err_omp_aligned_twice) << RefExpr->getSourceRange();
Diag(PrevRef->getExprLoc(), diag::note_omp_explicit_dsa)
<< getOpenMPClauseName(OMPC_aligned);
continue;
}

Vars.push_back(DE);
}

// OpenMP [2.8.1, simd construct, Description]
// The parameter of the aligned clause, alignment, must be a constant
// positive integer expression.
// If no optional parameter is specified, implementation-defined default
// alignments for SIMD instructions on the target platforms are assumed.
if (Alignment != nullptr) {
ExprResult AlignResult =
VerifyPositiveIntegerConstantInClause(Alignment, OMPC_aligned);
if (AlignResult.isInvalid())
return nullptr;
Alignment = AlignResult.get();
}
if (Vars.empty())
return nullptr;

return OMPAlignedClause::Create(Context, StartLoc, LParenLoc, ColonLoc,
EndLoc, Vars, Alignment);
}

OMPClause *Sema::ActOnOpenMPCopyinClause(ArrayRef<Expr *> VarList,
SourceLocation StartLoc,
SourceLocation LParenLoc,
Expand Down
32 changes: 32 additions & 0 deletions clang/lib/Sema/TreeTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -1419,6 +1419,19 @@ class TreeTransform {
ColonLoc, EndLoc);
}

/// \brief Build a new OpenMP 'aligned' clause.
///
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
OMPClause *RebuildOMPAlignedClause(ArrayRef<Expr *> VarList, Expr *Alignment,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation ColonLoc,
SourceLocation EndLoc) {
return getSema().ActOnOpenMPAlignedClause(VarList, Alignment, StartLoc,
LParenLoc, ColonLoc, EndLoc);
}

/// \brief Build a new OpenMP 'copyin' clause.
///
/// By default, performs semantic analysis to build the new statement.
Expand Down Expand Up @@ -6506,6 +6519,25 @@ TreeTransform<Derived>::TransformOMPLinearClause(OMPLinearClause *C) {
C->getLocEnd());
}

template<typename Derived>
OMPClause *
TreeTransform<Derived>::TransformOMPAlignedClause(OMPAlignedClause *C) {
llvm::SmallVector<Expr *, 16> Vars;
Vars.reserve(C->varlist_size());
for (auto *VE : C->varlists()) {
ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE));
if (EVar.isInvalid())
return nullptr;
Vars.push_back(EVar.get());
}
ExprResult Alignment = getDerived().TransformExpr(C->getAlignment());
if (Alignment.isInvalid())
return nullptr;
return getDerived().RebuildOMPAlignedClause(
Vars, Alignment.get(), C->getLocStart(), C->getLParenLoc(),
C->getColonLoc(), C->getLocEnd());
}

template<typename Derived>
OMPClause *
TreeTransform<Derived>::TransformOMPCopyinClause(OMPCopyinClause *C) {
Expand Down
15 changes: 15 additions & 0 deletions clang/lib/Serialization/ASTReaderStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1703,6 +1703,9 @@ OMPClause *OMPClauseReader::readClause() {
case OMPC_linear:
C = OMPLinearClause::CreateEmpty(Context, Record[Idx++]);
break;
case OMPC_aligned:
C = OMPAlignedClause::CreateEmpty(Context, Record[Idx++]);
break;
case OMPC_copyin:
C = OMPCopyinClause::CreateEmpty(Context, Record[Idx++]);
break;
Expand Down Expand Up @@ -1790,6 +1793,18 @@ void OMPClauseReader::VisitOMPLinearClause(OMPLinearClause *C) {
C->setStep(Reader->Reader.ReadSubExpr());
}

void OMPClauseReader::VisitOMPAlignedClause(OMPAlignedClause *C) {
C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
C->setColonLoc(Reader->ReadSourceLocation(Record, Idx));
unsigned NumVars = C->varlist_size();
SmallVector<Expr *, 16> Vars;
Vars.reserve(NumVars);
for (unsigned i = 0; i != NumVars; ++i)
Vars.push_back(Reader->Reader.ReadSubExpr());
C->setVarRefs(Vars);
C->setAlignment(Reader->Reader.ReadSubExpr());
}

void OMPClauseReader::VisitOMPCopyinClause(OMPCopyinClause *C) {
C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
unsigned NumVars = C->varlist_size();
Expand Down
9 changes: 9 additions & 0 deletions clang/lib/Serialization/ASTWriterStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1737,6 +1737,15 @@ void OMPClauseWriter::VisitOMPLinearClause(OMPLinearClause *C) {
Writer->Writer.AddStmt(C->getStep());
}

void OMPClauseWriter::VisitOMPAlignedClause(OMPAlignedClause *C) {
Record.push_back(C->varlist_size());
Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
Writer->Writer.AddSourceLocation(C->getColonLoc(), Record);
for (auto *VE : C->varlists())
Writer->Writer.AddStmt(VE);
Writer->Writer.AddStmt(C->getAlignment());
}

void OMPClauseWriter::VisitOMPCopyinClause(OMPCopyinClause *C) {
Record.push_back(C->varlist_size());
Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
Expand Down
200 changes: 200 additions & 0 deletions clang/test/OpenMP/simd_aligned_messages.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
// RUN: %clang_cc1 -x c++ -std=c++11 -verify -fopenmp=libiomp5 %s

struct B {
static int ib[20]; // expected-note 0 {{'B::ib' declared here}}
static constexpr int bfoo() { return 8; }
};
namespace X {
B x; // expected-note {{'x' defined here}}
};
constexpr int bfoo() { return 4; }

int **z;
const int C1 = 1;
const int C2 = 2;
void test_aligned_colons(int *&rp)
{
int *B = 0;
#pragma omp simd aligned(B:bfoo())
for (int i = 0; i < 10; ++i) ;
// expected-error@+1 {{unexpected ':' in nested name specifier; did you mean '::'}}
#pragma omp simd aligned(B::ib:B:bfoo())
for (int i = 0; i < 10; ++i) ;
#pragma omp simd aligned(B:B::bfoo())
for (int i = 0; i < 10; ++i) ;
// expected-error@+1 {{unexpected ':' in nested name specifier; did you mean '::'?}}
#pragma omp simd aligned(z:B:bfoo())
for (int i = 0; i < 10; ++i) ;
#pragma omp simd aligned(B:B::bfoo())
for (int i = 0; i < 10; ++i) ;
// expected-error@+2 {{integral constant expression must have integral or unscoped enumeration type, not 'int **'}}
// expected-error@+1 {{argument of aligned clause should be array, pointer, reference to array or reference to pointer, not 'B'}}
#pragma omp simd aligned(X::x : ::z)
for (int i = 0; i < 10; ++i) ;
// expected-error@+1 {{integral constant expression must have integral or unscoped enumeration type, not 'B'}}
#pragma omp simd aligned(B,rp,::z: X::x)
for (int i = 0; i < 10; ++i) ;
#pragma omp simd aligned(::z)
for (int i = 0; i < 10; ++i) ;
// expected-error@+1 {{expected variable name}}
#pragma omp simd aligned(B::bfoo())
for (int i = 0; i < 10; ++i) ;
#pragma omp simd aligned(B::ib,B:C1+C2)
for (int i = 0; i < 10; ++i) ;
}

// expected-note@+1 {{'num' defined here}}
template<int L, class T, class N> T test_template(T* arr, N num) {
N i;
T sum = (T)0;
T ind2 = - num * L;
// Negative number is passed as L.
// expected-error@+1 {{argument to 'aligned' clause must be a positive integer value}}
#pragma omp simd aligned(arr:L)
for (i = 0; i < num; ++i) {
T cur = arr[ind2];
ind2 += L;
sum += cur;
}
// expected-error@+1 {{argument of aligned clause should be array, pointer, reference to array or reference to pointer, not 'int'}}
#pragma omp simd aligned(num:4)
for (i = 0; i < num; ++i);
}

template<int LEN> int test_warn() {
int *ind2 = 0;
// expected-error@+1 {{argument to 'aligned' clause must be a positive integer value}}
#pragma omp simd aligned(ind2:LEN)
for (int i = 0; i < 100; i++) {
ind2 += LEN;
}
return 0;
}

struct S1; // expected-note 2 {{declared here}}
extern S1 a; // expected-note {{'a' declared here}}
class S2 {
mutable int a;
public:
S2():a(0) { }
};
const S2 b; // expected-note 1 {{'b' defined here}}
const S2 ba[5];
class S3 {
int a;
public:
S3():a(0) { }
};
const S3 ca[5];
class S4 {
int a;
S4();
public:
S4(int v):a(v) { }
};
class S5 {
int a;
S5():a(0) {}
public:
S5(int v):a(v) { }
};

S3 h; // expected-note 2 {{'h' defined here}}
#pragma omp threadprivate(h)

template<class I, class C> int foomain(I argc, C **argv) {
I e(argc);
I g(argc);
int i; // expected-note {{declared here}} expected-note {{'i' defined here}}
// expected-note@+2 {{declared here}}
// expected-note@+1 {{reference to 'i' is not a constant expression}}
int &j = i;
#pragma omp simd aligned // expected-error {{expected '(' after 'aligned'}}
for (I k = 0; k < argc; ++k) ++k;
#pragma omp simd aligned ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
for (I k = 0; k < argc; ++k) ++k;
#pragma omp simd aligned () // expected-error {{expected expression}}
for (I k = 0; k < argc; ++k) ++k;
#pragma omp simd aligned (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (I k = 0; k < argc; ++k) ++k;
#pragma omp simd aligned (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
for (I k = 0; k < argc; ++k) ++k;
#pragma omp simd aligned (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
for (I k = 0; k < argc; ++k) ++k;
#pragma omp simd aligned (argc : 5)
for (I k = 0; k < argc; ++k) ++k;
#pragma omp simd aligned (S1) // expected-error {{'S1' does not refer to a value}}
for (I k = 0; k < argc; ++k) ++k;
#pragma omp simd aligned (argv[1]) // expected-error {{expected variable name}}
for (I k = 0; k < argc; ++k) ++k;
#pragma omp simd aligned(e, g)
for (I k = 0; k < argc; ++k) ++k;
// expected-error@+1 {{argument of aligned clause should be array, pointer, reference to array or reference to pointer, not 'S3'}}
#pragma omp simd aligned(h)
for (I k = 0; k < argc; ++k) ++k;
// expected-error@+1 {{argument of aligned clause should be array, pointer, reference to array or reference to pointer, not 'int'}}
#pragma omp simd aligned(i)
for (I k = 0; k < argc; ++k) ++k;
#pragma omp parallel
{
int *v = 0;
I i;
#pragma omp simd aligned(v:16)
for (I k = 0; k < argc; ++k) { i = k; v += 2; }
}
float *f;
#pragma omp simd aligned(f)
for (I k = 0; k < argc; ++k) ++k;
int v = 0;
// expected-note@+2 {{initializer of 'j' is not a constant expression}}
// expected-error@+1 {{expression is not an integral constant expression}}
#pragma omp simd aligned(f:j)
for (I k = 0; k < argc; ++k) { ++k; v += j; }
#pragma omp simd aligned(f)
for (I k = 0; k < argc; ++k) ++k;
return 0;
}

// expected-note@+1 2 {{'argc' defined here}}
int main(int argc, char **argv) {
double darr[100];
// expected-note@+1 {{in instantiation of function template specialization 'test_template<-4, double, int>' requested here}}
test_template<-4>(darr, 4);
test_warn<4>(); // ok
// expected-note@+1 {{in instantiation of function template specialization 'test_warn<0>' requested here}}
test_warn<0>();

int i;
int &j = i;
#pragma omp simd aligned // expected-error {{expected '(' after 'aligned'}}
for (int k = 0; k < argc; ++k) ++k;
#pragma omp simd aligned ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int k = 0; k < argc; ++k) ++k;
#pragma omp simd aligned () // expected-error {{expected expression}}
for (int k = 0; k < argc; ++k) ++k;
#pragma omp simd aligned (argv // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int k = 0; k < argc; ++k) ++k;
// expected-error@+1 {{argument of aligned clause should be array, pointer, reference to array or reference to pointer, not 'int'}}
#pragma omp simd aligned (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int k = 0; k < argc; ++k) ++k;
#pragma omp simd aligned (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
for (int k = 0; k < argc; ++k) ++k;
// expected-error@+1 {{argument of aligned clause should be array, pointer, reference to array or reference to pointer, not 'int'}}
#pragma omp simd aligned (argc)
for (int k = 0; k < argc; ++k) ++k;
#pragma omp simd aligned (S1) // expected-error {{'S1' does not refer to a value}}
for (int k = 0; k < argc; ++k) ++k;
// expected-error@+2 {{argument of aligned clause should be array, pointer, reference to array or reference to pointer, not 'S1'}}
// expected-error@+1 {{argument of aligned clause should be array, pointer, reference to array or reference to pointer, not 'S2'}}
#pragma omp simd aligned (a, b)
for (int k = 0; k < argc; ++k) ++k;
#pragma omp simd aligned (argv[1]) // expected-error {{expected variable name}}
for (int k = 0; k < argc; ++k) ++k;
// expected-error@+1 {{argument of aligned clause should be array, pointer, reference to array or reference to pointer, not 'S3'}}
#pragma omp simd aligned(h)
for (int k = 0; k < argc; ++k) ++k;
int *pargc = &argc;
foomain<int*,char>(pargc,argv);
return 0;
}

16 changes: 8 additions & 8 deletions clang/test/OpenMP/simd_ast_print.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ template<class T, class N> T reduct(T* arr, N num) {
N myind;
T sum = (T)0;
// CHECK: T sum = (T)0;
#pragma omp simd private(myind, g_ind), linear(ind)
// CHECK-NEXT: #pragma omp simd private(myind,g_ind) linear(ind)
#pragma omp simd private(myind, g_ind), linear(ind), aligned(arr)
// CHECK-NEXT: #pragma omp simd private(myind,g_ind) linear(ind) aligned(arr)
for (i = 0; i < num; ++i) {
myind = ind;
T cur = arr[myind];
Expand Down Expand Up @@ -62,7 +62,7 @@ template<class T> struct S {
template<int LEN> struct S2 {
static void func(int n, float *a, float *b, float *c) {
int k1 = 0, k2 = 0;
#pragma omp simd safelen(LEN) linear(k1,k2:LEN)
#pragma omp simd safelen(LEN) linear(k1,k2:LEN) aligned(a:LEN)
for(int i = 0; i < n; i++) {
c[i] = a[i] + b[i];
c[k1] = a[k1] + b[k1];
Expand All @@ -77,7 +77,7 @@ template<int LEN> struct S2 {
// CHECK: template <int LEN = 4> struct S2 {
// CHECK-NEXT: static void func(int n, float *a, float *b, float *c) {
// CHECK-NEXT: int k1 = 0, k2 = 0;
// CHECK-NEXT: #pragma omp simd safelen(4) linear(k1,k2: 4)
// CHECK-NEXT: #pragma omp simd safelen(4) linear(k1,k2: 4) aligned(a: 4)
// CHECK-NEXT: for (int i = 0; i < n; i++) {
// CHECK-NEXT: c[i] = a[i] + b[i];
// CHECK-NEXT: c[k1] = a[k1] + b[k1];
Expand All @@ -97,10 +97,10 @@ int main (int argc, char **argv) {
for (int i=0; i < 2; ++i)*a=2;
// CHECK-NEXT: for (int i = 0; i < 2; ++i)
// CHECK-NEXT: *a = 2;
#pragma omp simd private(argc, b) collapse(2)
#pragma omp simd private(argc, b) collapse(2) aligned(a : 4)
for (int i = 0; i < 10; ++i)
for (int j = 0; j < 10; ++j) {foo(); k1 += 8; k2 += 8;}
// CHECK-NEXT: #pragma omp simd private(argc,b) collapse(2)
// CHECK-NEXT: #pragma omp simd private(argc,b) collapse(2) aligned(a: 4)
// CHECK-NEXT: for (int i = 0; i < 10; ++i)
// CHECK-NEXT: for (int j = 0; j < 10; ++j) {
// CHECK-NEXT: foo();
Expand All @@ -112,8 +112,8 @@ int main (int argc, char **argv) {
// CHECK-NEXT: foo();
const int CLEN = 4;
// CHECK-NEXT: const int CLEN = 4;
#pragma omp simd linear(a:CLEN) safelen(CLEN) collapse( 1 )
// CHECK-NEXT: #pragma omp simd linear(a: CLEN) safelen(CLEN) collapse(1)
#pragma omp simd aligned(a:CLEN) linear(a:CLEN) safelen(CLEN) collapse( 1 )
// CHECK-NEXT: #pragma omp simd aligned(a: CLEN) linear(a: CLEN) safelen(CLEN) collapse(1)
for (int i = 0; i < 10; ++i)foo();
// CHECK-NEXT: for (int i = 0; i < 10; ++i)
// CHECK-NEXT: foo();
Expand Down
77 changes: 77 additions & 0 deletions clang/test/OpenMP/simd_misc_messages.c
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,83 @@ void test_linear()
for (i = 0; i < 16; ++i) ;
}

void test_aligned()
{
int i;
// expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
#pragma omp simd aligned(
for (i = 0; i < 16; ++i) ;
// expected-error@+2 {{expected expression}}
// expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
#pragma omp simd aligned(,
for (i = 0; i < 16; ++i) ;
// expected-error@+2 {{expected expression}}
// expected-error@+1 {{expected expression}}
#pragma omp simd aligned(,)
for (i = 0; i < 16; ++i) ;
// expected-error@+1 {{expected expression}}
#pragma omp simd aligned()
for (i = 0; i < 16; ++i) ;
// expected-error@+1 {{expected expression}}
#pragma omp simd aligned(int)
for (i = 0; i < 16; ++i) ;
// expected-error@+1 {{expected variable name}}
#pragma omp simd aligned(0)
for (i = 0; i < 16; ++i) ;
// expected-error@+1 {{use of undeclared identifier 'x'}}
#pragma omp simd aligned(x)
for (i = 0; i < 16; ++i) ;
// expected-error@+2 {{use of undeclared identifier 'x'}}
// expected-error@+1 {{use of undeclared identifier 'y'}}
#pragma omp simd aligned(x, y)
for (i = 0; i < 16; ++i) ;
// expected-error@+3 {{use of undeclared identifier 'x'}}
// expected-error@+2 {{use of undeclared identifier 'y'}}
// expected-error@+1 {{use of undeclared identifier 'z'}}
#pragma omp simd aligned(x, y, z)
for (i = 0; i < 16; ++i) ;

int *x, y, z[25]; // expected-note 4 {{'y' defined here}}
#pragma omp simd aligned(x)
for (i = 0; i < 16; ++i) ;
#pragma omp simd aligned(z)
for (i = 0; i < 16; ++i) ;
// expected-error@+1 {{expected expression}}
#pragma omp simd aligned(x:)
for (i = 0; i < 16; ++i) ;
// expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
#pragma omp simd aligned(x:,)
for (i = 0; i < 16; ++i) ;
#pragma omp simd aligned(x:1)
for (i = 0; i < 16; ++i) ;
#pragma omp simd aligned(x:2*2)
for (i = 0; i < 16; ++i) ;
// expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
#pragma omp simd aligned(x:1,y)
for (i = 0; i < 16; ++i) ;
// expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
#pragma omp simd aligned(x:1,y,z:1)
for (i = 0; i < 16; ++i) ;

// expected-error@+1 {{argument of aligned clause should be array or pointer, not 'int'}}
#pragma omp simd aligned(x, y)
for (i = 0; i < 16; ++i) ;
// expected-error@+1 {{argument of aligned clause should be array or pointer, not 'int'}}
#pragma omp simd aligned(x, y, z)
for (i = 0; i < 16; ++i) ;

// expected-note@+2 {{defined as aligned}}
// expected-error@+1 {{a variable cannot appear in more than one aligned clause}}
#pragma omp simd aligned(x) aligned(z,x)
for (i = 0; i < 16; ++i) ;

// expected-note@+3 {{defined as aligned}}
// expected-error@+2 {{a variable cannot appear in more than one aligned clause}}
// expected-error@+1 2 {{argument of aligned clause should be array or pointer, not 'int'}}
#pragma omp simd aligned(x,y,z) aligned(y,z)
for (i = 0; i < 16; ++i) ;
}

void test_private()
{
int i;
Expand Down
4 changes: 4 additions & 0 deletions clang/tools/libclang/CIndex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1963,6 +1963,10 @@ void OMPClauseEnqueue::VisitOMPLinearClause(const OMPLinearClause *C) {
VisitOMPClauseList(C);
Visitor->AddStmt(C->getStep());
}
void OMPClauseEnqueue::VisitOMPAlignedClause(const OMPAlignedClause *C) {
VisitOMPClauseList(C);
Visitor->AddStmt(C->getAlignment());
}
void OMPClauseEnqueue::VisitOMPCopyinClause(const OMPCopyinClause *C) {
VisitOMPClauseList(C);
}
Expand Down