#include "clang/AST/Type.h"
#include "clang/Basic/AttrKinds.h"
#include "clang/Basic/LLVM.h"
+#include "clang/Basic/OpenMPKinds.h"
#include "clang/Basic/Sanitizers.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/VersionTuple.h"
[ "", "inbranch", "notinbranch" ],
[ "BS_Undefined", "BS_Inbranch", "BS_Notinbranch" ]>,
ExprArgument<"Simdlen">, VariadicExprArgument<"Uniforms">,
- VariadicExprArgument<"Aligneds">, VariadicExprArgument<"Alignments">
+ VariadicExprArgument<"Aligneds">, VariadicExprArgument<"Alignments">,
+ VariadicExprArgument<"Linears">, VariadicUnsignedArgument<"Modifiers">,
+ VariadicExprArgument<"Steps">
];
let AdditionalMembers = [{
void printPrettyPragma(raw_ostream & OS, const PrintingPolicy &Policy)
OS << ") ";
}
alignments_iterator NI = alignments_begin();
- for (auto E : aligneds()) {
+ for (auto *E : aligneds()) {
OS << "aligned(";
E->printPretty(OS, nullptr, Policy);
if (*NI) {
OS << ") ";
++NI;
}
+ steps_iterator I = steps_begin();
+ modifiers_iterator MI = modifiers_begin();
+ for (auto *E : linears()) {
+ OS << "linear(";
+ if (*MI != OMPC_LINEAR_unknown)
+ OS << getOpenMPSimpleClauseTypeName(OMPC_linear, *MI) << "(";
+ E->printPretty(OS, nullptr, Policy);
+ if (*MI != OMPC_LINEAR_unknown)
+ OS << ")";
+ if (*I) {
+ OS << ": ";
+ (*I)->printPretty(OS, nullptr, Policy);
+ }
+ OS << ") ";
+ ++I;
+ ++MI;
+ }
}
}];
}
"%0 variable cannot be in a map clause in '#pragma omp %1' directive">;
def err_omp_param_or_this_in_clause : Error<
"expected reference to one of the parameters of function %0%select{| or 'this'}1">;
+def err_omp_expected_uniform_param : Error<
+ "expected a reference to a parameter specified in a 'uniform' clause">;
+def err_omp_expected_int_param : Error<
+ "expected a reference to an integer-typed parameter">;
} // end of OpenMP category
let CategoryName = "Related Result Type Issue" in {
SourceLocation EndLoc,
llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA);
+ /// Checks correctness of linear modifiers.
+ bool CheckOpenMPLinearModifier(OpenMPLinearClauseKind LinKind,
+ SourceLocation LinLoc);
+ /// Checks that the specified declaration matches requirements for the linear
+ /// decls.
+ bool CheckOpenMPLinearDecl(ValueDecl *D, SourceLocation ELoc,
+ OpenMPLinearClauseKind LinKind, QualType Type);
+
/// \brief Called on well-formed '\#pragma omp declare simd' after parsing of
/// the associated method/function.
DeclGroupPtrTy ActOnOpenMPDeclareSimdDirective(
DeclGroupPtrTy DG, OMPDeclareSimdDeclAttr::BranchStateTy BS,
Expr *Simdlen, ArrayRef<Expr *> Uniforms, ArrayRef<Expr *> Aligneds,
- ArrayRef<Expr *> Alignments, SourceRange SR);
+ ArrayRef<Expr *> Alignments, ArrayRef<Expr *> Linears,
+ ArrayRef<unsigned> LinModifiers, ArrayRef<Expr *> Steps, SourceRange SR);
OMPClause *ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind,
Expr *Expr,
/// 'simdlen' '(' <expr> ')'
/// { 'uniform' '(' <argument_list> ')' }
/// { 'aligned '(' <argument_list> [ ':' <alignment> ] ')' }
-static bool parseDeclareSimdClauses(Parser &P,
- OMPDeclareSimdDeclAttr::BranchStateTy &BS,
- ExprResult &SimdLen,
- SmallVectorImpl<Expr *> &Uniforms,
- SmallVectorImpl<Expr *> &Aligneds,
- SmallVectorImpl<Expr *> &Alignments) {
+/// { 'linear '(' <argument_list> [ ':' <step> ] ')' }
+static bool parseDeclareSimdClauses(
+ Parser &P, OMPDeclareSimdDeclAttr::BranchStateTy &BS, ExprResult &SimdLen,
+ SmallVectorImpl<Expr *> &Uniforms, SmallVectorImpl<Expr *> &Aligneds,
+ SmallVectorImpl<Expr *> &Alignments, SmallVectorImpl<Expr *> &Linears,
+ SmallVectorImpl<unsigned> &LinModifiers, SmallVectorImpl<Expr *> &Steps) {
SourceRange BSRange;
const Token &Tok = P.getCurToken();
bool IsError = false;
IsError = true;
} else {
OpenMPClauseKind CKind = getOpenMPClauseKind(ClauseName);
- if (CKind == OMPC_uniform || CKind == OMPC_aligned) {
+ if (CKind == OMPC_uniform || CKind == OMPC_aligned ||
+ CKind == OMPC_linear) {
Parser::OpenMPVarListDataTy Data;
auto *Vars = &Uniforms;
- if (CKind == OMPC_aligned) {
+ if (CKind == OMPC_aligned)
Vars = &Aligneds;
- }
+ else if (CKind == OMPC_linear)
+ Vars = &Linears;
P.ConsumeToken();
if (P.ParseOpenMPVarList(OMPD_declare_simd,
IsError = true;
if (CKind == OMPC_aligned)
Alignments.append(Aligneds.size() - Alignments.size(), Data.TailExpr);
+ else if (CKind == OMPC_linear) {
+ if (P.getActions().CheckOpenMPLinearModifier(Data.LinKind,
+ Data.DepLinMapLoc))
+ Data.LinKind = OMPC_LINEAR_val;
+ LinModifiers.append(Linears.size() - LinModifiers.size(),
+ Data.LinKind);
+ Steps.append(Linears.size() - Steps.size(), Data.TailExpr);
+ }
} else
// TODO: add parsing of other clauses.
break;
SmallVector<Expr *, 4> Uniforms;
SmallVector<Expr *, 4> Aligneds;
SmallVector<Expr *, 4> Alignments;
- bool IsError = parseDeclareSimdClauses(*this, BS, Simdlen, Uniforms, Aligneds,
- Alignments);
+ SmallVector<Expr *, 4> Linears;
+ SmallVector<unsigned, 4> LinModifiers;
+ SmallVector<Expr *, 4> Steps;
+ bool IsError =
+ parseDeclareSimdClauses(*this, BS, Simdlen, Uniforms, Aligneds,
+ Alignments, Linears, LinModifiers, Steps);
// Need to check for extra tokens.
if (Tok.isNot(tok::annot_pragma_openmp_end)) {
Diag(Tok, diag::warn_omp_extra_tokens_at_eol)
SourceLocation EndLoc = ConsumeToken();
if (!IsError) {
return Actions.ActOnOpenMPDeclareSimdDirective(
- Ptr, BS, Simdlen.get(), Uniforms, Aligneds, Alignments,
- SourceRange(Loc, EndLoc));
+ Ptr, BS, Simdlen.get(), Uniforms, Aligneds, Alignments, Linears,
+ LinModifiers, Steps, SourceRange(Loc, EndLoc));
}
return Ptr;
}
Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareSimdDirective(
DeclGroupPtrTy DG, OMPDeclareSimdDeclAttr::BranchStateTy BS, Expr *Simdlen,
ArrayRef<Expr *> Uniforms, ArrayRef<Expr *> Aligneds,
- ArrayRef<Expr *> Alignments, SourceRange SR) {
+ ArrayRef<Expr *> Alignments, ArrayRef<Expr *> Linears,
+ ArrayRef<unsigned> LinModifiers, ArrayRef<Expr *> Steps, SourceRange SR) {
assert(Aligneds.size() == Alignments.size());
+ assert(Linears.size() == LinModifiers.size());
+ assert(Linears.size() == Steps.size());
if (!DG || DG.get().isNull())
return DeclGroupPtrTy();
// The uniform clause declares one or more arguments to have an invariant
// value for all concurrent invocations of the function in the execution of a
// single SIMD loop.
+ llvm::DenseMap<Decl *, Expr *> UniformedArgs;
+ Expr *UniformedLinearThis = nullptr;
for (auto *E : Uniforms) {
E = E->IgnoreParenImpCasts();
if (auto *DRE = dyn_cast<DeclRefExpr>(E))
if (auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl()))
if (FD->getNumParams() > PVD->getFunctionScopeIndex() &&
FD->getParamDecl(PVD->getFunctionScopeIndex())
- ->getCanonicalDecl() == PVD->getCanonicalDecl())
+ ->getCanonicalDecl() == PVD->getCanonicalDecl()) {
+ UniformedArgs.insert(std::make_pair(PVD->getCanonicalDecl(), E));
continue;
- if (isa<CXXThisExpr>(E))
+ }
+ if (isa<CXXThisExpr>(E)) {
+ UniformedLinearThis = E;
continue;
+ }
Diag(E->getExprLoc(), diag::err_omp_param_or_this_in_clause)
<< FD->getDeclName() << (isa<CXXMethodDecl>(ADecl) ? 1 : 0);
}
Align = VerifyPositiveIntegerConstantInClause(E, OMPC_aligned);
NewAligns.push_back(Align.get());
}
+ // OpenMP [2.8.2, declare simd construct, Description]
+ // The linear clause declares one or more list items to be private to a SIMD
+ // lane and to have a linear relationship with respect to the iteration space
+ // of a loop.
+ // The special this pointer can be used as if was one of the arguments to the
+ // function in any of the linear, aligned, or uniform clauses.
+ // When a linear-step expression is specified in a linear clause it must be
+ // either a constant integer expression or an integer-typed parameter that is
+ // specified in a uniform clause on the directive.
+ llvm::DenseMap<Decl *, Expr *> LinearArgs;
+ const bool IsUniformedThis = UniformedLinearThis != nullptr;
+ auto MI = LinModifiers.begin();
+ for (auto *E : Linears) {
+ auto LinKind = static_cast<OpenMPLinearClauseKind>(*MI);
+ ++MI;
+ E = E->IgnoreParenImpCasts();
+ if (auto *DRE = dyn_cast<DeclRefExpr>(E))
+ if (auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) {
+ auto *CanonPVD = PVD->getCanonicalDecl();
+ if (FD->getNumParams() > PVD->getFunctionScopeIndex() &&
+ FD->getParamDecl(PVD->getFunctionScopeIndex())
+ ->getCanonicalDecl() == CanonPVD) {
+ // OpenMP [2.15.3.7, linear Clause, Restrictions]
+ // A list-item cannot appear in more than one linear clause.
+ if (LinearArgs.count(CanonPVD) > 0) {
+ Diag(E->getExprLoc(), diag::err_omp_wrong_dsa)
+ << getOpenMPClauseName(OMPC_linear)
+ << getOpenMPClauseName(OMPC_linear) << E->getSourceRange();
+ Diag(LinearArgs[CanonPVD]->getExprLoc(),
+ diag::note_omp_explicit_dsa)
+ << getOpenMPClauseName(OMPC_linear);
+ continue;
+ }
+ // Each argument can appear in at most one uniform or linear clause.
+ if (UniformedArgs.count(CanonPVD) > 0) {
+ Diag(E->getExprLoc(), diag::err_omp_wrong_dsa)
+ << getOpenMPClauseName(OMPC_linear)
+ << getOpenMPClauseName(OMPC_uniform) << E->getSourceRange();
+ Diag(UniformedArgs[CanonPVD]->getExprLoc(),
+ diag::note_omp_explicit_dsa)
+ << getOpenMPClauseName(OMPC_uniform);
+ continue;
+ }
+ LinearArgs[CanonPVD] = E;
+ if (E->isValueDependent() || E->isTypeDependent() ||
+ E->isInstantiationDependent() ||
+ E->containsUnexpandedParameterPack())
+ continue;
+ (void)CheckOpenMPLinearDecl(CanonPVD, E->getExprLoc(), LinKind,
+ PVD->getOriginalType());
+ continue;
+ }
+ }
+ if (isa<CXXThisExpr>(E)) {
+ if (UniformedLinearThis) {
+ Diag(E->getExprLoc(), diag::err_omp_wrong_dsa)
+ << getOpenMPClauseName(OMPC_linear)
+ << getOpenMPClauseName(IsUniformedThis ? OMPC_uniform : OMPC_linear)
+ << E->getSourceRange();
+ Diag(UniformedLinearThis->getExprLoc(), diag::note_omp_explicit_dsa)
+ << getOpenMPClauseName(IsUniformedThis ? OMPC_uniform
+ : OMPC_linear);
+ continue;
+ }
+ UniformedLinearThis = E;
+ if (E->isValueDependent() || E->isTypeDependent() ||
+ E->isInstantiationDependent() || E->containsUnexpandedParameterPack())
+ continue;
+ (void)CheckOpenMPLinearDecl(/*D=*/nullptr, E->getExprLoc(), LinKind,
+ E->getType());
+ continue;
+ }
+ Diag(E->getExprLoc(), diag::err_omp_param_or_this_in_clause)
+ << FD->getDeclName() << (isa<CXXMethodDecl>(ADecl) ? 1 : 0);
+ }
+ Expr *Step = nullptr;
+ Expr *NewStep = nullptr;
+ SmallVector<Expr *, 4> NewSteps;
+ for (auto *E : Steps) {
+ // Skip the same step expression, it was checked already.
+ if (Step == E || !E) {
+ NewSteps.push_back(E ? NewStep : nullptr);
+ continue;
+ }
+ Step = E;
+ if (auto *DRE = dyn_cast<DeclRefExpr>(Step))
+ if (auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) {
+ auto *CanonPVD = PVD->getCanonicalDecl();
+ if (UniformedArgs.count(CanonPVD) == 0) {
+ Diag(Step->getExprLoc(), diag::err_omp_expected_uniform_param)
+ << Step->getSourceRange();
+ } else if (E->isValueDependent() || E->isTypeDependent() ||
+ E->isInstantiationDependent() ||
+ E->containsUnexpandedParameterPack() ||
+ CanonPVD->getType()->hasIntegerRepresentation())
+ NewSteps.push_back(Step);
+ else {
+ Diag(Step->getExprLoc(), diag::err_omp_expected_int_param)
+ << Step->getSourceRange();
+ }
+ continue;
+ }
+ NewStep = Step;
+ if (Step && !Step->isValueDependent() && !Step->isTypeDependent() &&
+ !Step->isInstantiationDependent() &&
+ !Step->containsUnexpandedParameterPack()) {
+ NewStep = PerformOpenMPImplicitIntegerConversion(Step->getExprLoc(), Step)
+ .get();
+ if (NewStep)
+ NewStep = VerifyIntegerConstantExpression(NewStep).get();
+ }
+ NewSteps.push_back(NewStep);
+ }
auto *NewAttr = OMPDeclareSimdDeclAttr::CreateImplicit(
Context, BS, SL.get(), const_cast<Expr **>(Uniforms.data()),
Uniforms.size(), const_cast<Expr **>(Aligneds.data()), Aligneds.size(),
- const_cast<Expr **>(NewAligns.data()), NewAligns.size(), SR);
+ const_cast<Expr **>(NewAligns.data()), NewAligns.size(),
+ const_cast<Expr **>(Linears.data()), Linears.size(),
+ const_cast<unsigned *>(LinModifiers.data()), LinModifiers.size(),
+ NewSteps.data(), NewSteps.size(), SR);
ADecl->addAttr(NewAttr);
return ConvertDeclToDeclGroup(ADecl);
}
buildPostUpdate(*this, ExprPostUpdates));
}
+bool Sema::CheckOpenMPLinearModifier(OpenMPLinearClauseKind LinKind,
+ SourceLocation LinLoc) {
+ if ((!LangOpts.CPlusPlus && LinKind != OMPC_LINEAR_val) ||
+ LinKind == OMPC_LINEAR_unknown) {
+ Diag(LinLoc, diag::err_omp_wrong_linear_modifier) << LangOpts.CPlusPlus;
+ return true;
+ }
+ return false;
+}
+
+bool Sema::CheckOpenMPLinearDecl(ValueDecl *D, SourceLocation ELoc,
+ OpenMPLinearClauseKind LinKind,
+ QualType Type) {
+ auto *VD = dyn_cast_or_null<VarDecl>(D);
+ // A variable must not have an incomplete type or a reference type.
+ if (RequireCompleteType(ELoc, Type, diag::err_omp_linear_incomplete_type))
+ return true;
+ if ((LinKind == OMPC_LINEAR_uval || LinKind == OMPC_LINEAR_ref) &&
+ !Type->isReferenceType()) {
+ Diag(ELoc, diag::err_omp_wrong_linear_modifier_non_reference)
+ << Type << getOpenMPSimpleClauseTypeName(OMPC_linear, LinKind);
+ return true;
+ }
+ Type = Type.getNonReferenceType();
+
+ // A list item must not be const-qualified.
+ if (Type.isConstant(Context)) {
+ Diag(ELoc, diag::err_omp_const_variable)
+ << getOpenMPClauseName(OMPC_linear);
+ if (D) {
+ bool IsDecl =
+ !VD ||
+ VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
+ Diag(D->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ << D;
+ }
+ return true;
+ }
+
+ // A list item must be of integral or pointer type.
+ Type = Type.getUnqualifiedType().getCanonicalType();
+ const auto *Ty = Type.getTypePtrOrNull();
+ if (!Ty || (!Ty->isDependentType() && !Ty->isIntegralType(Context) &&
+ !Ty->isPointerType())) {
+ Diag(ELoc, diag::err_omp_linear_expected_int_or_ptr) << Type;
+ if (D) {
+ bool IsDecl =
+ !VD ||
+ VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
+ Diag(D->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ << D;
+ }
+ return true;
+ }
+ return false;
+}
+
OMPClause *Sema::ActOnOpenMPLinearClause(
ArrayRef<Expr *> VarList, Expr *Step, SourceLocation StartLoc,
SourceLocation LParenLoc, OpenMPLinearClauseKind LinKind,
SmallVector<Expr *, 8> Inits;
SmallVector<Decl *, 4> ExprCaptures;
SmallVector<Expr *, 4> ExprPostUpdates;
- if ((!LangOpts.CPlusPlus && LinKind != OMPC_LINEAR_val) ||
- LinKind == OMPC_LINEAR_unknown) {
- Diag(LinLoc, diag::err_omp_wrong_linear_modifier) << LangOpts.CPlusPlus;
+ if (CheckOpenMPLinearModifier(LinKind, LinLoc))
LinKind = OMPC_LINEAR_val;
- }
for (auto &RefExpr : VarList) {
assert(RefExpr && "NULL expr in OpenMP linear clause.");
SourceLocation ELoc;
continue;
}
- // A variable must not have an incomplete type or a reference type.
- if (RequireCompleteType(ELoc, Type,
- diag::err_omp_linear_incomplete_type))
+ if (CheckOpenMPLinearDecl(D, ELoc, LinKind, Type))
continue;
- if ((LinKind == OMPC_LINEAR_uval || LinKind == OMPC_LINEAR_ref) &&
- !Type->isReferenceType()) {
- Diag(ELoc, diag::err_omp_wrong_linear_modifier_non_reference)
- << Type << getOpenMPSimpleClauseTypeName(OMPC_linear, LinKind);
- continue;
- }
- Type = Type.getNonReferenceType();
-
- // A list item must not be const-qualified.
- if (Type.isConstant(Context)) {
- Diag(ELoc, diag::err_omp_const_variable)
- << getOpenMPClauseName(OMPC_linear);
- bool IsDecl =
- !VD ||
- VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
- Diag(D->getLocation(),
- IsDecl ? diag::note_previous_decl : diag::note_defined_here)
- << D;
- continue;
- }
-
- // A list item must be of integral or pointer type.
- Type = Type.getUnqualifiedType().getCanonicalType();
- const auto *Ty = Type.getTypePtrOrNull();
- if (!Ty || (!Ty->isDependentType() && !Ty->isIntegralType(Context) &&
- !Ty->isPointerType())) {
- Diag(ELoc, diag::err_omp_linear_expected_int_or_ptr) << Type;
- bool IsDecl =
- !VD ||
- VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
- Diag(D->getLocation(),
- IsDecl ? diag::note_previous_decl : diag::note_defined_here)
- << D;
- continue;
- }
+ Type = Type.getNonReferenceType().getUnqualifiedType().getCanonicalType();
// Build private copy of original var.
auto *Private = buildVarDecl(*this, ELoc, Type, D->getName(),
static void instantiateOMPDeclareSimdDeclAttr(
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
const OMPDeclareSimdDeclAttr &Attr, Decl *New) {
- ExprResult Simdlen;
- if (auto *E = Attr.getSimdlen())
- Simdlen = S.SubstExpr(E, TemplateArgs);
// Allow 'this' in clauses with varlists.
if (auto *FTD = dyn_cast<FunctionTemplateDecl>(New))
New = FTD->getTemplatedDecl();
auto *FD = cast<FunctionDecl>(New);
auto *ThisContext = dyn_cast_or_null<CXXRecordDecl>(FD->getDeclContext());
- SmallVector<Expr *, 4> Uniforms, Aligneds, Alignments;
+ SmallVector<Expr *, 4> Uniforms, Aligneds, Alignments, Linears, Steps;
+ SmallVector<unsigned, 4> LinModifiers;
auto &&Subst = [&](Expr *E) -> ExprResult {
if (auto *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts()))
return S.SubstExpr(E, TemplateArgs);
};
+ ExprResult Simdlen;
+ if (auto *E = Attr.getSimdlen())
+ Simdlen = Subst(E);
+
if (Attr.uniforms_size() > 0) {
for(auto *E : Attr.uniforms()) {
ExprResult Inst = Subst(E);
Alignments.push_back(Inst.get());
++AI;
}
+
+ auto SI = Attr.steps_begin();
+ for (auto *E : Attr.linears()) {
+ ExprResult Inst = Subst(E);
+ if (Inst.isInvalid())
+ continue;
+ Linears.push_back(Inst.get());
+ Inst = ExprEmpty();
+ if (*SI)
+ Inst = S.SubstExpr(*SI, TemplateArgs);
+ Steps.push_back(Inst.get());
+ ++SI;
+ }
+ LinModifiers.append(Attr.modifiers_begin(), Attr.modifiers_end());
(void)S.ActOnOpenMPDeclareSimdDirective(
S.ConvertDeclToDeclGroup(New), Attr.getBranchState(), Simdlen.get(),
- Uniforms, Aligneds, Alignments, Attr.getRange());
+ Uniforms, Aligneds, Alignments, Linears, LinModifiers, Steps,
+ Attr.getRange());
}
void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
#define HEADER
#pragma omp declare simd aligned(b : 64)
-#pragma omp declare simd simdlen(32) aligned(d, s1)
-#pragma omp declare simd inbranch, uniform(d)
-#pragma omp declare simd notinbranch simdlen(2), uniform(s1, s2)
-void add_1(float *d, float *s1, float *s2, double b[]) __attribute__((cold));
+#pragma omp declare simd simdlen(32) aligned(d, b)
+#pragma omp declare simd inbranch, uniform(d) linear(val(s1, s2) : 32)
+#pragma omp declare simd notinbranch simdlen(2), uniform(s1, s2) linear(d: s1)
+void add_1(float *d, int s1, float *s2, double b[]) __attribute__((cold));
-// CHECK: #pragma omp declare simd notinbranch simdlen(2) uniform(s1, s2)
-// CHECK-NEXT: #pragma omp declare simd inbranch uniform(d)
-// CHECK-NEXT: #pragma omp declare simd simdlen(32) aligned(d) aligned(s1)
+// CHECK: #pragma omp declare simd notinbranch simdlen(2) uniform(s1, s2) linear(val(d): s1)
+// CHECK-NEXT: #pragma omp declare simd inbranch uniform(d) linear(val(s1): 32) linear(val(s2): 32)
+// CHECK-NEXT: #pragma omp declare simd simdlen(32) aligned(d) aligned(b)
// CHECK-NEXT: #pragma omp declare simd aligned(b: 64)
-// CHECK-NEXT: void add_1(float *d, float *s1, float *s2, double b[]) __attribute__((cold))
+// CHECK-NEXT: void add_1(float *d, int s1, float *s2, double b[]) __attribute__((cold))
#endif
#ifndef HEADER
#define HEADER
-#pragma omp declare simd
+#pragma omp declare simd linear(d: 8)
#pragma omp declare simd inbranch simdlen(32)
#pragma omp declare simd notinbranch
void add_1(float *d) __attribute__((cold));
// CHECK: #pragma omp declare simd notinbranch
// CHECK-NEXT: #pragma omp declare simd inbranch simdlen(32)
-// CHECK-NEXT: #pragma omp declare simd
+// CHECK-NEXT: #pragma omp declare simd linear(val(d): 8)
// CHECK-NEXT: void add_1(float *d) __attribute__((cold));
//
}
class VV {
- // CHECK: #pragma omp declare simd uniform(this, a)
+ // CHECK: #pragma omp declare simd uniform(this, a) linear(val(b): a)
// CHECK-NEXT: int add(int a, int b) __attribute__((cold)) {
// CHECK-NEXT: return a + b;
// CHECK-NEXT: }
- #pragma omp declare simd uniform(this, a)
+ #pragma omp declare simd uniform(this, a) linear(val(b): a)
int add(int a, int b) __attribute__((cold)) { return a + b; }
- // CHECK: #pragma omp declare simd aligned(b: 4) aligned(a)
+ // CHECK: #pragma omp declare simd aligned(b: 4) aligned(a) linear(ref(b): 4) linear(val(this)) linear(val(a))
// CHECK-NEXT: float taddpf(float *a, float *&b) {
// CHECK-NEXT: return *a + *b;
// CHECK-NEXT: }
- #pragma omp declare simd aligned (b: 4) aligned(a)
+ #pragma omp declare simd aligned (b: 4) aligned(a) linear(ref(b): 4) linear(this, a)
float taddpf(float *a, float *&b) { return *a + *b; }
// CHECK: #pragma omp declare simd aligned(b: 8)
-// CHECK-NEXT: #pragma omp declare simd
-// CHECK-NEXT: int tadd(int (&b)[]) {
+// CHECK-NEXT: #pragma omp declare simd linear(uval(c): 8)
+// CHECK-NEXT: int tadd(int (&b)[], int &c) {
// CHECK-NEXT: return this->x[b[0]] + b[0];
// CHECK-NEXT: }
- #pragma omp declare simd
+ #pragma omp declare simd linear(uval(c): 8)
#pragma omp declare simd aligned(b : 8)
- int tadd(int (&b)[]) { return x[b[0]] + b[0]; }
+ int tadd(int (&b)[], int &c) { return x[b[0]] + b[0]; }
private:
int x[10];
// CHECK: template <int X = 16, typename T = float> class TVV {
// CHECK: #pragma omp declare simd
// CHECK-NEXT: int tadd(int a, int b);
-// CHECK: #pragma omp declare simd aligned(a: 16 * 2) aligned(b)
+// CHECK: #pragma omp declare simd aligned(a: 16 * 2) aligned(b) linear(ref(b): 16)
// CHECK-NEXT: float taddpf(float *a, float *&b) {
// CHECK-NEXT: return *a + *b;
// CHECK-NEXT: }
// CHECK-NEXT: return a + b;
// CHECK-NEXT: }
- #pragma omp declare simd aligned(a : X * 2) aligned(b)
+ #pragma omp declare simd aligned(a : X * 2) aligned(b) linear(ref(b): X)
float taddpf(float *a, T *&b) { return *a + *b; }
// CHECK: #pragma omp declare simd aligned(a: X * 2) aligned(b)
};
// CHECK: };
-// CHECK: #pragma omp declare simd simdlen(64) aligned(b: 64 * 2)
-// CHECK: template <int N = 64> void foo(int (&b)[64])
-// CHECK: #pragma omp declare simd simdlen(N) aligned(b: N * 2)
-// CHECK: template <int N> void foo(int (&b)[N])
-#pragma omp declare simd simdlen(N) aligned(b : N * 2)
+// CHECK: #pragma omp declare simd simdlen(64) aligned(b: 64 * 2) linear(uval(c): 64)
+// CHECK: template <int N = 64> void foo(int (&b)[64], float *&c)
+// CHECK: #pragma omp declare simd simdlen(N) aligned(b: N * 2) linear(uval(c): N)
+// CHECK: template <int N> void foo(int (&b)[N], float *&c)
+#pragma omp declare simd simdlen(N) aligned(b : N * 2) linear(uval(c): N)
template <int N>
-void foo(int (&b)[N]);
+void foo(int (&b)[N], float *&c);
// CHECK: TVV<16, float> t16;
TVV<16, float> t16;
float r = t16.taddpf(&a, p);
int res = t16.tadd(b);
int c[64];
- foo(c);
+ foo(c, p);
}
#endif
#pragma omp declare simd aligned(b: -1)
// expected-warning@+1 {{aligned clause will be ignored because the requested alignment is not a power of 2}}
#pragma omp declare simd aligned(b: 3)
+// expected-error@+1 {{expected '(' after 'linear'}}
+#pragma omp declare simd linear
+// expected-note@+3 {{to match this '('}}
+// expected-error@+2 {{expected ')'}}
+// expected-error@+1 {{expected expression}}
+#pragma omp declare simd linear(
+// expected-error@+1 {{expected expression}}
+#pragma omp declare simd linear()
+// expected-note@+3 {{to match this '('}}
+// expected-error@+2 {{expected ')'}}
+// expected-error@+1 {{expected expression}}
+#pragma omp declare simd linear(a:
+// expected-error@+1 {{expected expression}}
+#pragma omp declare simd linear(a:)
+// expected-warning@+2 {{extra tokens at the end of '#pragma omp declare simd' are ignored}}
+// expected-error@+1 {{expected '(' after 'linear'}}
+#pragma omp declare simd linear :)
+// expected-note@+3 {{to match this '('}}
+// expected-error@+2 {{expected ')'}}
+// expected-error@+1 {{invalid use of 'this' outside of a non-static member function}}
+#pragma omp declare simd linear(this
+// expected-note@+3 {{to match this '('}}
+// expected-error@+2 {{expected ')'}}
+// expected-error@+1 {{invalid use of 'this' outside of a non-static member function}}
+#pragma omp declare simd linear(this,b
+// expected-error@+1 {{expected expression}}
+#pragma omp declare simd linear(, b)
+// expected-note@+4 {{defined as linear}}
+// expected-error@+3 {{linear variable cannot be linear}}
+// expected-error@+2 {{expected expression}}
+// expected-error@+1 {{expected ',' or ')' in 'linear' clause}}
+#pragma omp declare simd linear(b) linear(b ; 64)
+// expected-note@+2 {{defined as linear}}
+// expected-error@+1 {{linear variable cannot be linear}}
+#pragma omp declare simd linear(b) linear(b: 64)
+#pragma omp declare simd linear(b: -1)
+#pragma omp declare simd linear(b: 3)
+// expected-error@+1 {{expected a reference to a parameter specified in a 'uniform' clause}}
+#pragma omp declare simd linear(b: a)
+// expected-note@+2 {{defined as uniform}}
+// expected-error@+1 {{linear variable cannot be uniform}}
+#pragma omp declare simd uniform(a), linear(a: 4)
+// expected-note@+2 {{defined as uniform}}
+// expected-error@+1 {{linear variable cannot be uniform}}
+#pragma omp declare simd linear(a: 4) uniform(a)
+// expected-error@+1 {{variable of non-reference type 'int *' can be used only with 'val' modifier, but used with 'uval'}}
+#pragma omp declare simd linear(uval(b))
+// expected-error@+1 {{variable of non-reference type 'int *' can be used only with 'val' modifier, but used with 'ref'}}
+#pragma omp declare simd linear(ref(b))
+// expected-error@+1 {{expected one of 'ref', val' or 'uval' modifiers}}
+#pragma omp declare simd linear(uref(b))
void bar(int a, int *b);
template <class T>
#pragma init_seg(compiler)
#pragma omp declare simd
#pragma init_seg(compiler)
+// expected-note@+7 {{defined as uniform}}
+// expected-error@+6 {{expected a reference to a parameter specified in a 'uniform' clause}}
+// expected-error@+5 {{linear variable cannot be uniform}}
// expected-note@+4 {{defined as aligned}}
// expected-error@+3 {{argument to 'aligned' clause must be a strictly positive integer value}}
// expected-error@+2 {{'this' cannot appear in more than one aligned clause}}
// expected-error@+1 {{use of undeclared identifier 't'}}
-#pragma omp declare simd uniform(this, t) aligned(this: 4) aligned(this: -4)
+#pragma omp declare simd uniform(this, t) aligned(this: 4) aligned(this: -4) linear(this: hp)
void h(T *hp) {
// expected-error@+1 {{unexpected OpenMP directive '#pragma omp declare simd'}}
#pragma omp declare simd