Commit f743bcdd authored by Jenkins CI's avatar Jenkins CI
Browse files

Merge remote-tracking branch 'downstream/master' into EPI

parents d8ea6a50 8634df47
......@@ -2588,7 +2588,11 @@ enum CXCursorKind {
*/
CXCursor_OMPMaskedDirective = 292,
CXCursor_LastStmt = CXCursor_OMPMaskedDirective,
/** OpenMP unroll directive.
*/
CXCursor_OMPUnrollDirective = 293,
CXCursor_LastStmt = CXCursor_OMPUnrollDirective,
/**
* Cursor that represents the translation unit itself.
......
......@@ -888,6 +888,114 @@ public:
}
};
/// Representation of the 'full' clause of the '#pragma omp unroll' directive.
///
/// \code
/// #pragma omp unroll full
/// for (int i = 0; i < 64; ++i)
/// \endcode
class OMPFullClause final : public OMPClause {
friend class OMPClauseReader;
/// Build an empty clause.
explicit OMPFullClause() : OMPClause(llvm::omp::OMPC_full, {}, {}) {}
public:
/// Build an AST node for a 'full' clause.
///
/// \param C Context of the AST.
/// \param StartLoc Starting location of the clause.
/// \param EndLoc Ending location of the clause.
static OMPFullClause *Create(const ASTContext &C, SourceLocation StartLoc,
SourceLocation EndLoc);
/// Build an empty 'full' AST node for deserialization.
///
/// \param C Context of the AST.
static OMPFullClause *CreateEmpty(const ASTContext &C);
child_range children() { return {child_iterator(), child_iterator()}; }
const_child_range children() const {
return {const_child_iterator(), const_child_iterator()};
}
child_range used_children() {
return child_range(child_iterator(), child_iterator());
}
const_child_range used_children() const {
return const_child_range(const_child_iterator(), const_child_iterator());
}
static bool classof(const OMPClause *T) {
return T->getClauseKind() == llvm::omp::OMPC_full;
}
};
/// Representation of the 'partial' clause of the '#pragma omp unroll'
/// directive.
///
/// \code
/// #pragma omp unroll partial(4)
/// for (int i = start; i < end; ++i)
/// \endcode
class OMPPartialClause final : public OMPClause {
friend class OMPClauseReader;
/// Location of '('.
SourceLocation LParenLoc;
/// Optional argument to the clause (unroll factor).
Stmt *Factor;
/// Build an empty clause.
explicit OMPPartialClause() : OMPClause(llvm::omp::OMPC_partial, {}, {}) {}
/// Set the unroll factor.
void setFactor(Expr *E) { Factor = E; }
/// Sets the location of '('.
void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; }
public:
/// Build an AST node for a 'partial' clause.
///
/// \param C Context of the AST.
/// \param StartLoc Location of the 'partial' identifier.
/// \param LParenLoc Location of '('.
/// \param EndLoc Location of ')'.
/// \param Factor Clause argument.
static OMPPartialClause *Create(const ASTContext &C, SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc, Expr *Factor);
/// Build an empty 'partial' AST node for deserialization.
///
/// \param C Context of the AST.
static OMPPartialClause *CreateEmpty(const ASTContext &C);
/// Returns the location of '('.
SourceLocation getLParenLoc() const { return LParenLoc; }
/// Returns the argument of the clause or nullptr if not set.
Expr *getFactor() const { return cast_or_null<Expr>(Factor); }
child_range children() { return child_range(&Factor, &Factor + 1); }
const_child_range children() const {
return const_child_range(&Factor, &Factor + 1);
}
child_range used_children() {
return child_range(child_iterator(), child_iterator());
}
const_child_range used_children() const {
return const_child_range(const_child_iterator(), const_child_iterator());
}
static bool classof(const OMPClause *T) {
return T->getClauseKind() == llvm::omp::OMPC_partial;
}
};
/// This represents 'collapse' clause in the '#pragma omp ...'
/// directive.
///
......
......@@ -2841,6 +2841,9 @@ DEF_TRAVERSE_STMT(OMPSimdDirective,
DEF_TRAVERSE_STMT(OMPTileDirective,
{ TRY_TO(TraverseOMPExecutableDirective(S)); })
DEF_TRAVERSE_STMT(OMPUnrollDirective,
{ TRY_TO(TraverseOMPExecutableDirective(S)); })
DEF_TRAVERSE_STMT(OMPForDirective,
{ TRY_TO(TraverseOMPExecutableDirective(S)); })
......@@ -3097,6 +3100,17 @@ bool RecursiveASTVisitor<Derived>::VisitOMPSizesClause(OMPSizesClause *C) {
return true;
}
template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPFullClause(OMPFullClause *C) {
return true;
}
template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPPartialClause(OMPPartialClause *C) {
TRY_TO(TraverseStmt(C->getFactor()));
return true;
}
template <typename Derived>
bool
RecursiveASTVisitor<Derived>::VisitOMPCollapseClause(OMPCollapseClause *C) {
......
......@@ -5067,6 +5067,78 @@ public:
}
};
/// This represents the '#pragma omp unroll' loop transformation directive.
///
/// \code
/// #pragma omp unroll
/// for (int i = 0; i < 64; ++i)
/// \endcode
class OMPUnrollDirective final : public OMPLoopBasedDirective {
friend class ASTStmtReader;
friend class OMPExecutableDirective;
/// Default list of offsets.
enum {
PreInitsOffset = 0,
TransformedStmtOffset,
};
explicit OMPUnrollDirective(SourceLocation StartLoc, SourceLocation EndLoc)
: OMPLoopBasedDirective(OMPUnrollDirectiveClass, llvm::omp::OMPD_unroll,
StartLoc, EndLoc, 1) {}
/// Set the pre-init statements.
void setPreInits(Stmt *PreInits) {
Data->getChildren()[PreInitsOffset] = PreInits;
}
/// Set the de-sugared statement.
void setTransformedStmt(Stmt *S) {
Data->getChildren()[TransformedStmtOffset] = S;
}
public:
/// Create a new AST node representation for '#pragma omp unroll'.
///
/// \param C Context of the AST.
/// \param StartLoc Location of the introducer (e.g. the 'omp' token).
/// \param EndLoc Location of the directive's end (e.g. the tok::eod).
/// \param Clauses The directive's clauses.
/// \param AssociatedStmt The outermost associated loop.
/// \param TransformedStmt The loop nest after tiling, or nullptr in
/// dependent contexts.
/// \param PreInits Helper preinits statements for the loop nest.
static OMPUnrollDirective *
Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt,
Stmt *TransformedStmt, Stmt *PreInits);
/// Build an empty '#pragma omp unroll' AST node for deserialization.
///
/// \param C Context of the AST.
/// \param NumClauses Number of clauses to allocate.
static OMPUnrollDirective *CreateEmpty(const ASTContext &C,
unsigned NumClauses);
/// Get the de-sugared associated loops after unrolling.
///
/// This is only used if the unrolled loop becomes an associated loop of
/// another directive, otherwise the loop is emitted directly using loop
/// transformation metadata. When the unrolled loop cannot be used by another
/// directive (e.g. because of the full clause), the transformed stmt can also
/// be nullptr.
Stmt *getTransformedStmt() const {
return Data->getChildren()[TransformedStmtOffset];
}
/// Return the pre-init statements.
Stmt *getPreInits() const { return Data->getChildren()[PreInitsOffset]; }
static bool classof(const Stmt *T) {
return T->getStmtClass() == OMPUnrollDirectiveClass;
}
};
/// This represents '#pragma omp scan' directive.
///
/// \code
......
......@@ -10748,6 +10748,9 @@ def err_omp_interop_var_multiple_actions : Error<
def err_omp_dispatch_statement_call
: Error<"statement after '#pragma omp dispatch' must be a direct call"
" to a target function or an assignment to one">;
def err_omp_unroll_full_variable_trip_count : Error<
"loop to be fully unrolled must have a constant trip count">;
def note_omp_directive_here : Note<"'%0' directive found here">;
} // end of OpenMP category
 
let CategoryName = "Related Result Type Issue" in {
......
......@@ -224,6 +224,7 @@ def OMPLoopDirective : StmtNode<OMPLoopBasedDirective, 1>;
def OMPParallelDirective : StmtNode<OMPExecutableDirective>;
def OMPSimdDirective : StmtNode<OMPLoopDirective>;
def OMPTileDirective : StmtNode<OMPLoopBasedDirective>;
def OMPUnrollDirective : StmtNode<OMPLoopBasedDirective>;
def OMPForDirective : StmtNode<OMPLoopDirective>;
def OMPForSimdDirective : StmtNode<OMPLoopDirective>;
def OMPSectionsDirective : StmtNode<OMPExecutableDirective>;
......
......@@ -32,6 +32,7 @@
#include "clang/AST/NSAPI.h"
#include "clang/AST/PrettyPrinter.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtOpenMP.h"
#include "clang/AST/TypeLoc.h"
#include "clang/AST/TypeOrdering.h"
#include "clang/Basic/BitmaskEnum.h"
......@@ -3454,12 +3455,6 @@ public:
bool DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType);
bool isSameOrCompatibleFunctionType(CanQualType Param, CanQualType Arg);
 
ExprResult PerformMoveOrCopyInitialization(const InitializedEntity &Entity,
const VarDecl *NRVOCandidate,
QualType ResultType,
Expr *Value,
bool AllowNRVO = true);
bool CanPerformAggregateInitializationForOverloadResolution(
const InitializedEntity &Entity, InitListExpr *From);
 
......@@ -4759,28 +4754,30 @@ public:
SourceLocation Loc,
unsigned NumParams);
 
enum CopyElisionSemanticsKind {
CES_Strict = 0,
CES_AllowParameters = 1,
CES_AllowDifferentTypes = 2,
CES_AllowExceptionVariables = 4,
CES_AllowRValueReferenceType = 8,
CES_ImplicitlyMovableCXX11CXX14CXX17 =
(CES_AllowParameters | CES_AllowDifferentTypes),
CES_ImplicitlyMovableCXX20 =
(CES_AllowParameters | CES_AllowDifferentTypes |
CES_AllowExceptionVariables | CES_AllowRValueReferenceType),
struct NamedReturnInfo {
const VarDecl *Candidate;
enum Status : uint8_t { None, MoveEligible, MoveEligibleAndCopyElidable };
Status S;
bool isMoveEligible() const { return S != None; };
bool isCopyElidable() const { return S == MoveEligibleAndCopyElidable; }
};
NamedReturnInfo getNamedReturnInfo(const Expr *E, bool ForceCXX20 = false);
NamedReturnInfo getNamedReturnInfo(const VarDecl *VD,
bool ForceCXX20 = false);
const VarDecl *getCopyElisionCandidate(NamedReturnInfo &Info,
QualType ReturnType);
 
VarDecl *getCopyElisionCandidate(QualType ReturnType, Expr *E,
CopyElisionSemanticsKind CESK);
bool isCopyElisionCandidate(QualType ReturnType, const VarDecl *VD,
CopyElisionSemanticsKind CESK);
ExprResult PerformMoveOrCopyInitialization(const InitializedEntity &Entity,
const NamedReturnInfo &NRInfo,
Expr *Value);
 
StmtResult ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp,
Scope *CurScope);
StmtResult BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp);
StmtResult ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp);
StmtResult ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp,
NamedReturnInfo &NRInfo);
 
StmtResult ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
bool IsVolatile, unsigned NumOutputs,
......@@ -10220,7 +10217,8 @@ private:
void DestroyDataSharingAttributesStack();
ExprResult
VerifyPositiveIntegerConstantInClause(Expr *Op, OpenMPClauseKind CKind,
bool StrictlyPositive = true);
bool StrictlyPositive = true,
bool SuppressExprDiags = false);
/// Returns OpenMP nesting level for current directive.
unsigned getOpenMPNestingLevel() const;
 
......@@ -10238,6 +10236,25 @@ private:
/// Pop OpenMP function region for non-capturing function.
void popOpenMPFunctionRegion(const sema::FunctionScopeInfo *OldFSI);
 
/// Analyzes and checks a loop nest for use by a loop transformation.
///
/// \param Kind The loop transformation directive kind.
/// \param NumLoops How many nested loops the directive is expecting.
/// \param AStmt Associated statement of the transformation directive.
/// \param LoopHelpers [out] The loop analysis result.
/// \param Body [out] The body code nested in \p NumLoops loop.
/// \param OriginalInits [out] Collection of statements and declarations that
/// must have been executed/declared before entering the
/// loop.
///
/// \return Whether there was any error.
bool checkTransformableLoopNest(
OpenMPDirectiveKind Kind, Stmt *AStmt, int NumLoops,
SmallVectorImpl<OMPLoopBasedDirective::HelperExprs> &LoopHelpers,
Stmt *&Body,
SmallVectorImpl<SmallVector<llvm::PointerUnion<Stmt *, Decl *>, 0>>
&OriginalInits);
/// Helper to keep information about the current `omp begin/end declare
/// variant` nesting.
struct OMPDeclareVariantScope {
......@@ -10543,6 +10560,11 @@ public:
StmtResult ActOnOpenMPTileDirective(ArrayRef<OMPClause *> Clauses,
Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc);
/// Called on well-formed '#pragma omp unroll' after parsing of its clauses
/// and the associated statement.
StmtResult ActOnOpenMPUnrollDirective(ArrayRef<OMPClause *> Clauses,
Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc);
/// Called on well-formed '\#pragma omp for' after parsing
/// of the associated statement.
StmtResult
......@@ -10898,6 +10920,13 @@ public:
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc);
/// Called on well-form 'full' clauses.
OMPClause *ActOnOpenMPFullClause(SourceLocation StartLoc,
SourceLocation EndLoc);
/// Called on well-form 'partial' clauses.
OMPClause *ActOnOpenMPPartialClause(Expr *FactorExpr, SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc);
/// Called on well-formed 'collapse' clause.
OMPClause *ActOnOpenMPCollapseClause(Expr *NumForLoops,
SourceLocation StartLoc,
......
......@@ -1894,6 +1894,7 @@ enum StmtCode {
STMT_OMP_PARALLEL_DIRECTIVE,
STMT_OMP_SIMD_DIRECTIVE,
STMT_OMP_TILE_DIRECTIVE,
STMT_OMP_UNROLL_DIRECTIVE,
STMT_OMP_FOR_DIRECTIVE,
STMT_OMP_FOR_SIMD_DIRECTIVE,
STMT_OMP_SECTIONS_DIRECTIVE,
......
......@@ -942,6 +942,36 @@ OMPSizesClause *OMPSizesClause::CreateEmpty(const ASTContext &C,
return new (Mem) OMPSizesClause(NumSizes);
}
OMPFullClause *OMPFullClause::Create(const ASTContext &C,
SourceLocation StartLoc,
SourceLocation EndLoc) {
OMPFullClause *Clause = CreateEmpty(C);
Clause->setLocStart(StartLoc);
Clause->setLocEnd(EndLoc);
return Clause;
}
OMPFullClause *OMPFullClause::CreateEmpty(const ASTContext &C) {
return new (C) OMPFullClause();
}
OMPPartialClause *OMPPartialClause::Create(const ASTContext &C,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc,
Expr *Factor) {
OMPPartialClause *Clause = CreateEmpty(C);
Clause->setLocStart(StartLoc);
Clause->setLParenLoc(LParenLoc);
Clause->setLocEnd(EndLoc);
Clause->setFactor(Factor);
return Clause;
}
OMPPartialClause *OMPPartialClause::CreateEmpty(const ASTContext &C) {
return new (C) OMPPartialClause();
}
OMPAllocateClause *
OMPAllocateClause::Create(const ASTContext &C, SourceLocation StartLoc,
SourceLocation LParenLoc, Expr *Allocator,
......@@ -1602,6 +1632,18 @@ void OMPClausePrinter::VisitOMPSizesClause(OMPSizesClause *Node) {
OS << ")";
}
void OMPClausePrinter::VisitOMPFullClause(OMPFullClause *Node) { OS << "full"; }
void OMPClausePrinter::VisitOMPPartialClause(OMPPartialClause *Node) {
OS << "partial";
if (Expr *Factor = Node->getFactor()) {
OS << '(';
Factor->printPretty(OS, nullptr, Policy, 0);
OS << ')';
}
}
void OMPClausePrinter::VisitOMPAllocatorClause(OMPAllocatorClause *Node) {
OS << "allocator(";
Node->getAllocator()->printPretty(OS, nullptr, Policy, 0);
......
......@@ -129,9 +129,24 @@ bool OMPLoopBasedDirective::doForAllLoops(
OnTransformationCallback) {
CurStmt = CurStmt->IgnoreContainers();
for (unsigned Cnt = 0; Cnt < NumLoops; ++Cnt) {
while (auto *Dir = dyn_cast<OMPTileDirective>(CurStmt)) {
OnTransformationCallback(Dir);
CurStmt = Dir->getTransformedStmt();
while (true) {
auto *OrigStmt = CurStmt;
if (auto *Dir = dyn_cast<OMPTileDirective>(OrigStmt)) {
OnTransformationCallback(Dir);
CurStmt = Dir->getTransformedStmt();
} else if (auto *Dir = dyn_cast<OMPUnrollDirective>(OrigStmt)) {
OnTransformationCallback(Dir);
CurStmt = Dir->getTransformedStmt();
} else {
break;
}
if (!CurStmt) {
// May happen if the loop transformation does not result in a generated
// loop (such as full unrolling).
CurStmt = OrigStmt;
break;
}
}
if (auto *CanonLoop = dyn_cast<OMPCanonicalLoop>(CurStmt))
CurStmt = CanonLoop->getLoopStmt();
......@@ -359,6 +374,25 @@ OMPTileDirective *OMPTileDirective::CreateEmpty(const ASTContext &C,
SourceLocation(), SourceLocation(), NumLoops);
}
OMPUnrollDirective *
OMPUnrollDirective::Create(const ASTContext &C, SourceLocation StartLoc,
SourceLocation EndLoc, ArrayRef<OMPClause *> Clauses,
Stmt *AssociatedStmt, Stmt *TransformedStmt,
Stmt *PreInits) {
auto *Dir = createDirective<OMPUnrollDirective>(
C, Clauses, AssociatedStmt, TransformedStmtOffset + 1, StartLoc, EndLoc);
Dir->setTransformedStmt(TransformedStmt);
Dir->setPreInits(PreInits);
return Dir;
}
OMPUnrollDirective *OMPUnrollDirective::CreateEmpty(const ASTContext &C,
unsigned NumClauses) {
return createEmptyDirective<OMPUnrollDirective>(
C, NumClauses, /*HasAssociatedStmt=*/true, TransformedStmtOffset + 1,
SourceLocation(), SourceLocation());
}
OMPForSimdDirective *
OMPForSimdDirective::Create(const ASTContext &C, SourceLocation StartLoc,
SourceLocation EndLoc, unsigned CollapsedNum,
......
......@@ -668,6 +668,11 @@ void StmtPrinter::VisitOMPTileDirective(OMPTileDirective *Node) {
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPUnrollDirective(OMPUnrollDirective *Node) {
Indent() << "#pragma omp unroll";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPForDirective(OMPForDirective *Node) {
Indent() << "#pragma omp for";
PrintOMPExecutableDirective(Node);
......
......@@ -468,6 +468,13 @@ void OMPClauseProfiler::VisitOMPSizesClause(const OMPSizesClause *C) {
Profiler->VisitExpr(E);
}
void OMPClauseProfiler::VisitOMPFullClause(const OMPFullClause *C) {}
void OMPClauseProfiler::VisitOMPPartialClause(const OMPPartialClause *C) {
if (const Expr *Factor = C->getFactor())
Profiler->VisitExpr(Factor);
}
void OMPClauseProfiler::VisitOMPAllocatorClause(const OMPAllocatorClause *C) {
if (C->getAllocator())
Profiler->VisitStmt(C->getAllocator());
......@@ -908,6 +915,10 @@ void StmtProfiler::VisitOMPTileDirective(const OMPTileDirective *S) {
VisitOMPLoopBasedDirective(S);
}
void StmtProfiler::VisitOMPUnrollDirective(const OMPUnrollDirective *S) {
VisitOMPLoopBasedDirective(S);
}
void StmtProfiler::VisitOMPForDirective(const OMPForDirective *S) {
VisitOMPLoopDirective(S);
}
......
......@@ -452,7 +452,8 @@ bool clang::isOpenMPLoopDirective(OpenMPDirectiveKind DKind) {
DKind == OMPD_target_teams_distribute ||
DKind == OMPD_target_teams_distribute_parallel_for ||
DKind == OMPD_target_teams_distribute_parallel_for_simd ||
DKind == OMPD_target_teams_distribute_simd || DKind == OMPD_tile;
DKind == OMPD_target_teams_distribute_simd || DKind == OMPD_tile ||
DKind == OMPD_unroll;
}
bool clang::isOpenMPWorksharingDirective(OpenMPDirectiveKind DKind) {
......@@ -580,7 +581,7 @@ bool clang::isOpenMPLoopBoundSharingDirective(OpenMPDirectiveKind Kind) {
}
bool clang::isOpenMPLoopTransformationDirective(OpenMPDirectiveKind DKind) {
return DKind == OMPD_tile;
return DKind == OMPD_tile || DKind == OMPD_unroll;
}
void clang::getOpenMPCaptureRegions(
......@@ -668,6 +669,7 @@ void clang::getOpenMPCaptureRegions(
CaptureRegions.push_back(OMPD_unknown);
break;
case OMPD_tile:
case OMPD_unroll:
// loop transformations do not introduce captures.
break;
case OMPD_threadprivate:
......
......@@ -6678,6 +6678,7 @@ emitNumTeamsForTargetDirective(CodeGenFunction &CGF,
case OMPD_task:
case OMPD_simd:
case OMPD_tile:
case OMPD_unroll:
case OMPD_sections:
case OMPD_section:
case OMPD_single:
......@@ -6996,6 +6997,7 @@ emitNumThreadsForTargetDirective(CodeGenFunction &CGF,
case OMPD_task:
case OMPD_simd:
case OMPD_tile:
case OMPD_unroll:
case OMPD_sections:
case OMPD_section:
case OMPD_single:
......@@ -9603,6 +9605,7 @@ getNestedDistributeDirective(ASTContext &Ctx, const OMPExecutableDirective &D) {
case OMPD_task:
case OMPD_simd:
case OMPD_tile:
case OMPD_unroll:
case OMPD_sections:
case OMPD_section:
case OMPD_single:
......@@ -10432,6 +10435,7 @@ void CGOpenMPRuntime::scanForTargetRegionsFunctions(const Stmt *S,
case OMPD_task:
case OMPD_simd:
case OMPD_tile:
case OMPD_unroll:
case OMPD_sections:
case OMPD_section:
case OMPD_single:
......@@ -11144,6 +11148,7 @@ void CGOpenMPRuntime::emitTargetDataStandAloneCall(
case OMPD_task:
case OMPD_simd:
case OMPD_tile:
case OMPD_unroll:
case OMPD_sections:
case OMPD_section: