diff --git a/clang/include/clang/AST/StmtOpenMP.h b/clang/include/clang/AST/StmtOpenMP.h index e37f5b1e0004..c9efe3238715 100644 --- a/clang/include/clang/AST/StmtOpenMP.h +++ b/clang/include/clang/AST/StmtOpenMP.h @@ -448,7 +448,8 @@ class OMPLoopDirective : public OMPExecutableDirective { PreInitsOffset = 8, // The '...End' enumerators do not correspond to child expressions - they // specify the offset to the end (and start of the following counters/ - // updates/finals arrays). + // updates/finals/dependent_counters/dependent_inits/finals_conditions + // arrays). DefaultEnd = 9, // The following 8 exprs are used by worksharing and distribute loops only. IsLastIterVariableOffset = 9, @@ -474,7 +475,8 @@ class OMPLoopDirective : public OMPExecutableDirective { CombinedNextUpperBoundOffset = 27, CombinedDistConditionOffset = 28, CombinedParForInDistConditionOffset = 29, - // Offset to the end (and start of the following counters/updates/finals + // Offset to the end (and start of the following + // counters/updates/finals/dependent_counters/dependent_inits/finals_conditions // arrays) for combined distribute loop directives. CombinedDistributeEnd = 30, }; @@ -517,6 +519,30 @@ class OMPLoopDirective : public OMPExecutableDirective { return MutableArrayRef(Storage, CollapsedNum); } + /// Get the dependent counters storage. + MutableArrayRef getDependentCounters() { + Expr **Storage = reinterpret_cast( + &*std::next(child_begin(), + getArraysOffset(getDirectiveKind()) + 5 * CollapsedNum)); + return MutableArrayRef(Storage, CollapsedNum); + } + + /// Get the dependent inits storage. + MutableArrayRef getDependentInits() { + Expr **Storage = reinterpret_cast( + &*std::next(child_begin(), + getArraysOffset(getDirectiveKind()) + 6 * CollapsedNum)); + return MutableArrayRef(Storage, CollapsedNum); + } + + /// Get the finals conditions storage. + MutableArrayRef getFinalsConditions() { + Expr **Storage = reinterpret_cast( + &*std::next(child_begin(), + getArraysOffset(getDirectiveKind()) + 7 * CollapsedNum)); + return MutableArrayRef(Storage, CollapsedNum); + } + protected: /// Build instance of loop directive of class \a Kind. /// @@ -551,9 +577,10 @@ protected: /// Children number. static unsigned numLoopChildren(unsigned CollapsedNum, OpenMPDirectiveKind Kind) { - return getArraysOffset(Kind) + 5 * CollapsedNum; // Counters, - // PrivateCounters, Inits, - // Updates and Finals + return getArraysOffset(Kind) + + 8 * CollapsedNum; // Counters, PrivateCounters, Inits, + // Updates, Finals, DependentCounters, + // DependentInits, FinalsConditions. } void setIterationVariable(Expr *IV) { @@ -703,6 +730,9 @@ protected: void setInits(ArrayRef A); void setUpdates(ArrayRef A); void setFinals(ArrayRef A); + void setDependentCounters(ArrayRef A); + void setDependentInits(ArrayRef A); + void setFinalsConditions(ArrayRef A); public: /// The expressions built to support OpenMP loops in combined/composite @@ -798,6 +828,15 @@ public: SmallVector Updates; /// Final loop counter values for GodeGen. SmallVector Finals; + /// List of counters required for the generation of the non-rectangular + /// loops. + SmallVector DependentCounters; + /// List of initializers required for the generation of the non-rectangular + /// loops. + SmallVector DependentInits; + /// List of final conditions required for the generation of the + /// non-rectangular loops. + SmallVector FinalsConditions; /// Init statement for all captured expressions. Stmt *PreInits; @@ -813,7 +852,9 @@ public: } /// Initialize all the fields to null. - /// \param Size Number of elements in the counters/finals/updates arrays. + /// \param Size Number of elements in the + /// counters/finals/updates/dependent_counters/dependent_inits/finals_conditions + /// arrays. void clear(unsigned Size) { IterationVarRef = nullptr; LastIteration = nullptr; @@ -839,12 +880,18 @@ public: Inits.resize(Size); Updates.resize(Size); Finals.resize(Size); + DependentCounters.resize(Size); + DependentInits.resize(Size); + FinalsConditions.resize(Size); for (unsigned i = 0; i < Size; ++i) { Counters[i] = nullptr; PrivateCounters[i] = nullptr; Inits[i] = nullptr; Updates[i] = nullptr; Finals[i] = nullptr; + DependentCounters[i] = nullptr; + DependentInits[i] = nullptr; + FinalsConditions[i] = nullptr; } PreInits = nullptr; DistCombinedFields.LB = nullptr; @@ -1078,6 +1125,24 @@ public: return const_cast(this)->getFinals(); } + ArrayRef dependent_counters() { return getDependentCounters(); } + + ArrayRef dependent_counters() const { + return const_cast(this)->getDependentCounters(); + } + + ArrayRef dependent_inits() { return getDependentInits(); } + + ArrayRef dependent_inits() const { + return const_cast(this)->getDependentInits(); + } + + ArrayRef finals_conditions() { return getFinalsConditions(); } + + ArrayRef finals_conditions() const { + return const_cast(this)->getFinalsConditions(); + } + static bool classof(const Stmt *T) { return T->getStmtClass() == OMPSimdDirectiveClass || T->getStmtClass() == OMPForDirectiveClass || diff --git a/clang/lib/AST/StmtOpenMP.cpp b/clang/lib/AST/StmtOpenMP.cpp index 4e829897cebe..7fda574bae0e 100644 --- a/clang/lib/AST/StmtOpenMP.cpp +++ b/clang/lib/AST/StmtOpenMP.cpp @@ -72,6 +72,25 @@ void OMPLoopDirective::setFinals(ArrayRef A) { std::copy(A.begin(), A.end(), getFinals().begin()); } +void OMPLoopDirective::setDependentCounters(ArrayRef A) { + assert( + A.size() == getCollapsedNumber() && + "Number of dependent counters is not the same as the collapsed number"); + llvm::copy(A, getDependentCounters().begin()); +} + +void OMPLoopDirective::setDependentInits(ArrayRef A) { + assert(A.size() == getCollapsedNumber() && + "Number of dependent inits is not the same as the collapsed number"); + llvm::copy(A, getDependentInits().begin()); +} + +void OMPLoopDirective::setFinalsConditions(ArrayRef A) { + assert(A.size() == getCollapsedNumber() && + "Number of finals conditions is not the same as the collapsed number"); + llvm::copy(A, getFinalsConditions().begin()); +} + OMPParallelDirective *OMPParallelDirective::Create( const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, ArrayRef Clauses, Stmt *AssociatedStmt, bool HasCancel) { @@ -122,6 +141,9 @@ OMPSimdDirective::Create(const ASTContext &C, SourceLocation StartLoc, Dir->setInits(Exprs.Inits); Dir->setUpdates(Exprs.Updates); Dir->setFinals(Exprs.Finals); + Dir->setDependentCounters(Exprs.DependentCounters); + Dir->setDependentInits(Exprs.DependentInits); + Dir->setFinalsConditions(Exprs.FinalsConditions); Dir->setPreInits(Exprs.PreInits); return Dir; } @@ -170,6 +192,9 @@ OMPForDirective::Create(const ASTContext &C, SourceLocation StartLoc, Dir->setInits(Exprs.Inits); Dir->setUpdates(Exprs.Updates); Dir->setFinals(Exprs.Finals); + Dir->setDependentCounters(Exprs.DependentCounters); + Dir->setDependentInits(Exprs.DependentInits); + Dir->setFinalsConditions(Exprs.FinalsConditions); Dir->setPreInits(Exprs.PreInits); Dir->setHasCancel(HasCancel); return Dir; @@ -220,6 +245,9 @@ OMPForSimdDirective::Create(const ASTContext &C, SourceLocation StartLoc, Dir->setInits(Exprs.Inits); Dir->setUpdates(Exprs.Updates); Dir->setFinals(Exprs.Finals); + Dir->setDependentCounters(Exprs.DependentCounters); + Dir->setDependentInits(Exprs.DependentInits); + Dir->setFinalsConditions(Exprs.FinalsConditions); Dir->setPreInits(Exprs.PreInits); return Dir; } @@ -383,6 +411,9 @@ OMPParallelForDirective *OMPParallelForDirective::Create( Dir->setInits(Exprs.Inits); Dir->setUpdates(Exprs.Updates); Dir->setFinals(Exprs.Finals); + Dir->setDependentCounters(Exprs.DependentCounters); + Dir->setDependentInits(Exprs.DependentInits); + Dir->setFinalsConditions(Exprs.FinalsConditions); Dir->setPreInits(Exprs.PreInits); Dir->setHasCancel(HasCancel); return Dir; @@ -432,6 +463,9 @@ OMPParallelForSimdDirective *OMPParallelForSimdDirective::Create( Dir->setInits(Exprs.Inits); Dir->setUpdates(Exprs.Updates); Dir->setFinals(Exprs.Finals); + Dir->setDependentCounters(Exprs.DependentCounters); + Dir->setDependentInits(Exprs.DependentInits); + Dir->setFinalsConditions(Exprs.FinalsConditions); Dir->setPreInits(Exprs.PreInits); return Dir; } @@ -772,6 +806,9 @@ OMPTargetParallelForDirective *OMPTargetParallelForDirective::Create( Dir->setInits(Exprs.Inits); Dir->setUpdates(Exprs.Updates); Dir->setFinals(Exprs.Finals); + Dir->setDependentCounters(Exprs.DependentCounters); + Dir->setDependentInits(Exprs.DependentInits); + Dir->setFinalsConditions(Exprs.FinalsConditions); Dir->setPreInits(Exprs.PreInits); Dir->setHasCancel(HasCancel); return Dir; @@ -914,6 +951,9 @@ OMPTaskLoopDirective *OMPTaskLoopDirective::Create( Dir->setInits(Exprs.Inits); Dir->setUpdates(Exprs.Updates); Dir->setFinals(Exprs.Finals); + Dir->setDependentCounters(Exprs.DependentCounters); + Dir->setDependentInits(Exprs.DependentInits); + Dir->setFinalsConditions(Exprs.FinalsConditions); Dir->setPreInits(Exprs.PreInits); return Dir; } @@ -963,6 +1003,9 @@ OMPTaskLoopSimdDirective *OMPTaskLoopSimdDirective::Create( Dir->setInits(Exprs.Inits); Dir->setUpdates(Exprs.Updates); Dir->setFinals(Exprs.Finals); + Dir->setDependentCounters(Exprs.DependentCounters); + Dir->setDependentInits(Exprs.DependentInits); + Dir->setFinalsConditions(Exprs.FinalsConditions); Dir->setPreInits(Exprs.PreInits); return Dir; } @@ -1011,6 +1054,9 @@ OMPDistributeDirective *OMPDistributeDirective::Create( Dir->setInits(Exprs.Inits); Dir->setUpdates(Exprs.Updates); Dir->setFinals(Exprs.Finals); + Dir->setDependentCounters(Exprs.DependentCounters); + Dir->setDependentInits(Exprs.DependentInits); + Dir->setFinalsConditions(Exprs.FinalsConditions); Dir->setPreInits(Exprs.PreInits); return Dir; } @@ -1089,6 +1135,9 @@ OMPDistributeParallelForDirective *OMPDistributeParallelForDirective::Create( Dir->setInits(Exprs.Inits); Dir->setUpdates(Exprs.Updates); Dir->setFinals(Exprs.Finals); + Dir->setDependentCounters(Exprs.DependentCounters); + Dir->setDependentInits(Exprs.DependentInits); + Dir->setFinalsConditions(Exprs.FinalsConditions); Dir->setPreInits(Exprs.PreInits); Dir->setCombinedLowerBoundVariable(Exprs.DistCombinedFields.LB); Dir->setCombinedUpperBoundVariable(Exprs.DistCombinedFields.UB); @@ -1157,6 +1206,9 @@ OMPDistributeParallelForSimdDirective::Create( Dir->setInits(Exprs.Inits); Dir->setUpdates(Exprs.Updates); Dir->setFinals(Exprs.Finals); + Dir->setDependentCounters(Exprs.DependentCounters); + Dir->setDependentInits(Exprs.DependentInits); + Dir->setFinalsConditions(Exprs.FinalsConditions); Dir->setPreInits(Exprs.PreInits); Dir->setCombinedLowerBoundVariable(Exprs.DistCombinedFields.LB); Dir->setCombinedUpperBoundVariable(Exprs.DistCombinedFields.UB); @@ -1219,6 +1271,9 @@ OMPDistributeSimdDirective *OMPDistributeSimdDirective::Create( Dir->setInits(Exprs.Inits); Dir->setUpdates(Exprs.Updates); Dir->setFinals(Exprs.Finals); + Dir->setDependentCounters(Exprs.DependentCounters); + Dir->setDependentInits(Exprs.DependentInits); + Dir->setFinalsConditions(Exprs.FinalsConditions); Dir->setPreInits(Exprs.PreInits); return Dir; } @@ -1271,6 +1326,9 @@ OMPTargetParallelForSimdDirective *OMPTargetParallelForSimdDirective::Create( Dir->setInits(Exprs.Inits); Dir->setUpdates(Exprs.Updates); Dir->setFinals(Exprs.Finals); + Dir->setDependentCounters(Exprs.DependentCounters); + Dir->setDependentInits(Exprs.DependentInits); + Dir->setFinalsConditions(Exprs.FinalsConditions); Dir->setPreInits(Exprs.PreInits); return Dir; } @@ -1315,6 +1373,9 @@ OMPTargetSimdDirective::Create(const ASTContext &C, SourceLocation StartLoc, Dir->setInits(Exprs.Inits); Dir->setUpdates(Exprs.Updates); Dir->setFinals(Exprs.Finals); + Dir->setDependentCounters(Exprs.DependentCounters); + Dir->setDependentInits(Exprs.DependentInits); + Dir->setFinalsConditions(Exprs.FinalsConditions); Dir->setPreInits(Exprs.PreInits); return Dir; } @@ -1363,6 +1424,9 @@ OMPTeamsDistributeDirective *OMPTeamsDistributeDirective::Create( Dir->setInits(Exprs.Inits); Dir->setUpdates(Exprs.Updates); Dir->setFinals(Exprs.Finals); + Dir->setDependentCounters(Exprs.DependentCounters); + Dir->setDependentInits(Exprs.DependentInits); + Dir->setFinalsConditions(Exprs.FinalsConditions); Dir->setPreInits(Exprs.PreInits); return Dir; } @@ -1414,6 +1478,9 @@ OMPTeamsDistributeSimdDirective *OMPTeamsDistributeSimdDirective::Create( Dir->setInits(Exprs.Inits); Dir->setUpdates(Exprs.Updates); Dir->setFinals(Exprs.Finals); + Dir->setDependentCounters(Exprs.DependentCounters); + Dir->setDependentInits(Exprs.DependentInits); + Dir->setFinalsConditions(Exprs.FinalsConditions); Dir->setPreInits(Exprs.PreInits); return Dir; } @@ -1471,6 +1538,9 @@ OMPTeamsDistributeParallelForSimdDirective::Create( Dir->setInits(Exprs.Inits); Dir->setUpdates(Exprs.Updates); Dir->setFinals(Exprs.Finals); + Dir->setDependentCounters(Exprs.DependentCounters); + Dir->setDependentInits(Exprs.DependentInits); + Dir->setFinalsConditions(Exprs.FinalsConditions); Dir->setPreInits(Exprs.PreInits); Dir->setCombinedLowerBoundVariable(Exprs.DistCombinedFields.LB); Dir->setCombinedUpperBoundVariable(Exprs.DistCombinedFields.UB); @@ -1540,6 +1610,9 @@ OMPTeamsDistributeParallelForDirective::Create( Dir->setInits(Exprs.Inits); Dir->setUpdates(Exprs.Updates); Dir->setFinals(Exprs.Finals); + Dir->setDependentCounters(Exprs.DependentCounters); + Dir->setDependentInits(Exprs.DependentInits); + Dir->setFinalsConditions(Exprs.FinalsConditions); Dir->setPreInits(Exprs.PreInits); Dir->setCombinedLowerBoundVariable(Exprs.DistCombinedFields.LB); Dir->setCombinedUpperBoundVariable(Exprs.DistCombinedFields.UB); @@ -1628,6 +1701,9 @@ OMPTargetTeamsDistributeDirective *OMPTargetTeamsDistributeDirective::Create( Dir->setInits(Exprs.Inits); Dir->setUpdates(Exprs.Updates); Dir->setFinals(Exprs.Finals); + Dir->setDependentCounters(Exprs.DependentCounters); + Dir->setDependentInits(Exprs.DependentInits); + Dir->setFinalsConditions(Exprs.FinalsConditions); Dir->setPreInits(Exprs.PreInits); return Dir; } @@ -1688,6 +1764,9 @@ OMPTargetTeamsDistributeParallelForDirective::Create( Dir->setInits(Exprs.Inits); Dir->setUpdates(Exprs.Updates); Dir->setFinals(Exprs.Finals); + Dir->setDependentCounters(Exprs.DependentCounters); + Dir->setDependentInits(Exprs.DependentInits); + Dir->setFinalsConditions(Exprs.FinalsConditions); Dir->setPreInits(Exprs.PreInits); Dir->setCombinedLowerBoundVariable(Exprs.DistCombinedFields.LB); Dir->setCombinedUpperBoundVariable(Exprs.DistCombinedFields.UB); @@ -1761,6 +1840,9 @@ OMPTargetTeamsDistributeParallelForSimdDirective::Create( Dir->setInits(Exprs.Inits); Dir->setUpdates(Exprs.Updates); Dir->setFinals(Exprs.Finals); + Dir->setDependentCounters(Exprs.DependentCounters); + Dir->setDependentInits(Exprs.DependentInits); + Dir->setFinalsConditions(Exprs.FinalsConditions); Dir->setPreInits(Exprs.PreInits); Dir->setCombinedLowerBoundVariable(Exprs.DistCombinedFields.LB); Dir->setCombinedUpperBoundVariable(Exprs.DistCombinedFields.UB); @@ -1826,6 +1908,9 @@ OMPTargetTeamsDistributeSimdDirective::Create( Dir->setInits(Exprs.Inits); Dir->setUpdates(Exprs.Updates); Dir->setFinals(Exprs.Finals); + Dir->setDependentCounters(Exprs.DependentCounters); + Dir->setDependentInits(Exprs.DependentInits); + Dir->setFinalsConditions(Exprs.FinalsConditions); Dir->setPreInits(Exprs.PreInits); return Dir; } diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp index e8fbca5108ad..2ca7ebc6b0da 100644 --- a/clang/lib/CodeGen/CGStmtOpenMP.cpp +++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp @@ -1324,6 +1324,16 @@ void CodeGenFunction::EmitOMPLoopBody(const OMPLoopDirective &D, // On a continue in the body, jump to the end. JumpDest Continue = getJumpDestInCurrentScope("omp.body.continue"); BreakContinueStack.push_back(BreakContinue(LoopExit, Continue)); + for (const Expr *E : D.finals_conditions()) { + if (!E) + continue; + // Check that loop counter in non-rectangular nest fits into the iteration + // space. + llvm::BasicBlock *NextBB = createBasicBlock("omp.body.next"); + EmitBranchOnBoolExpr(E, NextBB, Continue.getBlock(), + getProfileCount(D.getBody())); + EmitBlock(NextBB); + } // Emit loop body. EmitStmt(D.getBody()); // The end (updates/cleanups). @@ -1553,8 +1563,28 @@ static void emitPreCond(CodeGenFunction &CGF, const OMPLoopDirective &S, CGF.EmitIgnoredExpr(I); } } + // Create temp loop control variables with their init values to support + // non-rectangular loops. + CodeGenFunction::OMPMapVars PreCondVars; + for (const Expr * E: S.dependent_counters()) { + if (!E) + continue; + assert(!E->getType().getNonReferenceType()->isRecordType() && + "dependent counter must not be an iterator."); + const auto *VD = cast(cast(E)->getDecl()); + Address CounterAddr = + CGF.CreateMemTemp(VD->getType().getNonReferenceType()); + (void)PreCondVars.setVarAddr(CGF, VD, CounterAddr); + } + (void)PreCondVars.apply(CGF); + for (const Expr *E : S.dependent_inits()) { + if (!E) + continue; + CGF.EmitIgnoredExpr(E); + } // Check that loop is executed at least one time. CGF.EmitBranchOnBoolExpr(Cond, TrueBlock, FalseBlock, TrueCount); + PreCondVars.restore(CGF); } void CodeGenFunction::EmitOMPLinearClause( diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index 49c7c3aca144..3c23e43a20a4 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -4709,6 +4709,54 @@ StmtResult Sema::ActOnOpenMPParallelDirective(ArrayRef Clauses, } namespace { +/// Iteration space of a single for loop. +struct LoopIterationSpace final { + /// True if the condition operator is the strict compare operator (<, > or + /// !=). + bool IsStrictCompare = false; + /// Condition of the loop. + Expr *PreCond = nullptr; + /// This expression calculates the number of iterations in the loop. + /// It is always possible to calculate it before starting the loop. + Expr *NumIterations = nullptr; + /// The loop counter variable. + Expr *CounterVar = nullptr; + /// Private loop counter variable. + Expr *PrivateCounterVar = nullptr; + /// This is initializer for the initial value of #CounterVar. + Expr *CounterInit = nullptr; + /// This is step for the #CounterVar used to generate its update: + /// #CounterVar = #CounterInit + #CounterStep * CurrentIteration. + Expr *CounterStep = nullptr; + /// Should step be subtracted? + bool Subtract = false; + /// Source range of the loop init. + SourceRange InitSrcRange; + /// Source range of the loop condition. + SourceRange CondSrcRange; + /// Source range of the loop increment. + SourceRange IncSrcRange; + /// Minimum value that can have the loop control variable. Used to support + /// non-rectangular loops. Applied only for LCV with the non-iterator types, + /// since only such variables can be used in non-loop invariant expressions. + Expr *MinValue = nullptr; + /// Maximum value that can have the loop control variable. Used to support + /// non-rectangular loops. Applied only for LCV with the non-iterator type, + /// since only such variables can be used in non-loop invariant expressions. + Expr *MaxValue = nullptr; + /// true, if the lower bound depends on the outer loop control var. + bool IsNonRectangularLB = false; + /// true, if the upper bound depends on the outer loop control var. + bool IsNonRectangularUB = false; + /// Index of the loop this loop depends on and forms non-rectangular loop + /// nest. + unsigned LoopDependentIdx = 0; + /// Final condition for the non-rectangular loop nest support. It is used to + /// check that the number of iterations for this particular counter must be + /// finished. + Expr *FinalCondition = nullptr; +}; + /// Helper class for checking canonical form of the OpenMP loops and /// extracting iteration space of each loop in the loop nest, that will be used /// for IR generation. @@ -4758,6 +4806,9 @@ class OpenMPIterationSpaceChecker { Optional CondDependOnLC; /// Checks if the provide statement depends on the loop counter. Optional doesDependOnLoopCounter(const Stmt *S, bool IsInitializer); + /// Original condition required for checking of the exit condition for + /// non-rectangular loop. + Expr *Condition = nullptr; public: OpenMPIterationSpaceChecker(Sema &SemaRef, DSAStackTy &Stack, @@ -4789,7 +4840,7 @@ public: bool isStrictTestOp() const { return TestIsStrictOp; } /// Build the expression to calculate the number of iterations. Expr *buildNumIterations( - Scope *S, const bool LimitedType, + Scope *S, ArrayRef ResultIterSpaces, bool LimitedType, llvm::MapVector &Captures) const; /// Build the precondition expression for the loops. Expr * @@ -4813,8 +4864,21 @@ public: llvm::MapVector &Captures, SourceLocation Loc, Expr *Inc = nullptr, OverloadedOperatorKind OOK = OO_Amp); + /// Builds the minimum value for the loop counter. + std::pair buildMinMaxValues( + Scope *S, llvm::MapVector &Captures) const; + /// Builds final condition for the non-rectangular loops. + Expr *buildFinalCondition(Scope *S) const; /// Return true if any expression is dependent. bool dependent() const; + /// Returns true if the initializer forms non-rectangular loop. + bool doesInitDependOnLC() const { return InitDependOnLC.hasValue(); } + /// Returns true if the condition forms non-rectangular loop. + bool doesCondDependOnLC() const { return CondDependOnLC.hasValue(); } + /// Returns index of the loop we depend on (starting from 1), or 0 otherwise. + unsigned getLoopDependentIdx() const { + return InitDependOnLC.getValueOr(CondDependOnLC.getValueOr(0)); + } private: /// Check the right-hand side of an assignment in the increment @@ -5013,9 +5077,9 @@ public: return false; } bool VisitStmt(const Stmt *S) { - bool Res = true; + bool Res = false; for (const Stmt *Child : S->children()) - Res = Child && Visit(Child) && Res; + Res = (Child && Visit(Child)) || Res; return Res; } explicit LoopCounterRefChecker(Sema &SemaRef, DSAStackTy &Stack, @@ -5165,6 +5229,7 @@ bool OpenMPIterationSpaceChecker::checkAndSetCond(Expr *S) { SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_cond) << LCDecl; return true; } + Condition = S; S = getExprAsWritten(S); SourceLocation CondLoc = S->getBeginLoc(); if (auto *BO = dyn_cast(S)) { @@ -5351,15 +5416,177 @@ tryBuildCapture(Sema &SemaRef, Expr *Capture, /// Build the expression to calculate the number of iterations. Expr *OpenMPIterationSpaceChecker::buildNumIterations( - Scope *S, const bool LimitedType, + Scope *S, ArrayRef ResultIterSpaces, bool LimitedType, llvm::MapVector &Captures) const { ExprResult Diff; QualType VarType = LCDecl->getType().getNonReferenceType(); if (VarType->isIntegerType() || VarType->isPointerType() || SemaRef.getLangOpts().CPlusPlus) { + Expr *LBVal = LB; + Expr *UBVal = UB; + // LB = TestIsLessOp.getValue() ? min(LB(MinVal), LB(MaxVal)) : + // max(LB(MinVal), LB(MaxVal)) + if (InitDependOnLC) { + const LoopIterationSpace &IS = + ResultIterSpaces[ResultIterSpaces.size() - 1 - + InitDependOnLC.getValueOr( + CondDependOnLC.getValueOr(0))]; + if (!IS.MinValue || !IS.MaxValue) + return nullptr; + // OuterVar = Min + ExprResult MinValue = + SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MinValue); + if (!MinValue.isUsable()) + return nullptr; + + ExprResult LBMinVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign, + IS.CounterVar, MinValue.get()); + if (!LBMinVal.isUsable()) + return nullptr; + // OuterVar = Min, LBVal + LBMinVal = + SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, LBMinVal.get(), LBVal); + if (!LBMinVal.isUsable()) + return nullptr; + // (OuterVar = Min, LBVal) + LBMinVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, LBMinVal.get()); + if (!LBMinVal.isUsable()) + return nullptr; + + // OuterVar = Max + ExprResult MaxValue = + SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MaxValue); + if (!MaxValue.isUsable()) + return nullptr; + + ExprResult LBMaxVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign, + IS.CounterVar, MaxValue.get()); + if (!LBMaxVal.isUsable()) + return nullptr; + // OuterVar = Max, LBVal + LBMaxVal = + SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, LBMaxVal.get(), LBVal); + if (!LBMaxVal.isUsable()) + return nullptr; + // (OuterVar = Max, LBVal) + LBMaxVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, LBMaxVal.get()); + if (!LBMaxVal.isUsable()) + return nullptr; + + Expr *LBMin = tryBuildCapture(SemaRef, LBMinVal.get(), Captures).get(); + Expr *LBMax = tryBuildCapture(SemaRef, LBMaxVal.get(), Captures).get(); + if (!LBMin || !LBMax) + return nullptr; + // LB(MinVal) < LB(MaxVal) + ExprResult MinLessMaxRes = + SemaRef.BuildBinOp(S, DefaultLoc, BO_LT, LBMin, LBMax); + if (!MinLessMaxRes.isUsable()) + return nullptr; + Expr *MinLessMax = + tryBuildCapture(SemaRef, MinLessMaxRes.get(), Captures).get(); + if (!MinLessMax) + return nullptr; + if (TestIsLessOp.getValue()) { + // LB(MinVal) < LB(MaxVal) ? LB(MinVal) : LB(MaxVal) - min(LB(MinVal), + // LB(MaxVal)) + ExprResult MinLB = SemaRef.ActOnConditionalOp(DefaultLoc, DefaultLoc, + MinLessMax, LBMin, LBMax); + if (!MinLB.isUsable()) + return nullptr; + LBVal = MinLB.get(); + } else { + // LB(MinVal) < LB(MaxVal) ? LB(MaxVal) : LB(MinVal) - max(LB(MinVal), + // LB(MaxVal)) + ExprResult MaxLB = SemaRef.ActOnConditionalOp(DefaultLoc, DefaultLoc, + MinLessMax, LBMax, LBMin); + if (!MaxLB.isUsable()) + return nullptr; + LBVal = MaxLB.get(); + } + } + // UB = TestIsLessOp.getValue() ? max(UB(MinVal), UB(MaxVal)) : + // min(UB(MinVal), UB(MaxVal)) + if (CondDependOnLC) { + const LoopIterationSpace &IS = + ResultIterSpaces[ResultIterSpaces.size() - 1 - + InitDependOnLC.getValueOr( + CondDependOnLC.getValueOr(0))]; + if (!IS.MinValue || !IS.MaxValue) + return nullptr; + // OuterVar = Min + ExprResult MinValue = + SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MinValue); + if (!MinValue.isUsable()) + return nullptr; + + ExprResult UBMinVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign, + IS.CounterVar, MinValue.get()); + if (!UBMinVal.isUsable()) + return nullptr; + // OuterVar = Min, UBVal + UBMinVal = + SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, UBMinVal.get(), UBVal); + if (!UBMinVal.isUsable()) + return nullptr; + // (OuterVar = Min, UBVal) + UBMinVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, UBMinVal.get()); + if (!UBMinVal.isUsable()) + return nullptr; + + // OuterVar = Max + ExprResult MaxValue = + SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MaxValue); + if (!MaxValue.isUsable()) + return nullptr; + + ExprResult UBMaxVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign, + IS.CounterVar, MaxValue.get()); + if (!UBMaxVal.isUsable()) + return nullptr; + // OuterVar = Max, UBVal + UBMaxVal = + SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, UBMaxVal.get(), UBVal); + if (!UBMaxVal.isUsable()) + return nullptr; + // (OuterVar = Max, UBVal) + UBMaxVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, UBMaxVal.get()); + if (!UBMaxVal.isUsable()) + return nullptr; + + Expr *UBMin = tryBuildCapture(SemaRef, UBMinVal.get(), Captures).get(); + Expr *UBMax = tryBuildCapture(SemaRef, UBMaxVal.get(), Captures).get(); + if (!UBMin || !UBMax) + return nullptr; + // UB(MinVal) > UB(MaxVal) + ExprResult MinGreaterMaxRes = + SemaRef.BuildBinOp(S, DefaultLoc, BO_GT, UBMin, UBMax); + if (!MinGreaterMaxRes.isUsable()) + return nullptr; + Expr *MinGreaterMax = + tryBuildCapture(SemaRef, MinGreaterMaxRes.get(), Captures).get(); + if (!MinGreaterMax) + return nullptr; + if (TestIsLessOp.getValue()) { + // UB(MinVal) > UB(MaxVal) ? UB(MinVal) : UB(MaxVal) - max(UB(MinVal), + // UB(MaxVal)) + ExprResult MaxUB = SemaRef.ActOnConditionalOp( + DefaultLoc, DefaultLoc, MinGreaterMax, UBMin, UBMax); + if (!MaxUB.isUsable()) + return nullptr; + UBVal = MaxUB.get(); + } else { + // UB(MinVal) > UB(MaxVal) ? UB(MaxVal) : UB(MinVal) - min(UB(MinVal), + // UB(MaxVal)) + ExprResult MinUB = SemaRef.ActOnConditionalOp( + DefaultLoc, DefaultLoc, MinGreaterMax, UBMax, UBMin); + if (!MinUB.isUsable()) + return nullptr; + UBVal = MinUB.get(); + } + } // Upper - Lower - Expr *UBExpr = TestIsLessOp.getValue() ? UB : LB; - Expr *LBExpr = TestIsLessOp.getValue() ? LB : UB; + Expr *UBExpr = TestIsLessOp.getValue() ? UBVal : LBVal; + Expr *LBExpr = TestIsLessOp.getValue() ? LBVal : UBVal; Expr *Upper = tryBuildCapture(SemaRef, UBExpr, Captures).get(); Expr *Lower = tryBuildCapture(SemaRef, LBExpr, Captures).get(); if (!Upper || !Lower) @@ -5446,6 +5673,127 @@ Expr *OpenMPIterationSpaceChecker::buildNumIterations( return Diff.get(); } +std::pair OpenMPIterationSpaceChecker::buildMinMaxValues( + Scope *S, llvm::MapVector &Captures) const { + // Do not build for iterators, they cannot be used in non-rectangular loop + // nests. + if (LCDecl->getType()->isRecordType()) + return std::make_pair(nullptr, nullptr); + // If we subtract, the min is in the condition, otherwise the min is in the + // init value. + Expr *MinExpr = nullptr; + Expr *MaxExpr = nullptr; + Expr *LBExpr = TestIsLessOp.getValue() ? LB : UB; + Expr *UBExpr = TestIsLessOp.getValue() ? UB : LB; + bool LBNonRect = TestIsLessOp.getValue() ? InitDependOnLC.hasValue() + : CondDependOnLC.hasValue(); + bool UBNonRect = TestIsLessOp.getValue() ? CondDependOnLC.hasValue() + : InitDependOnLC.hasValue(); + Expr *Lower = + LBNonRect ? LBExpr : tryBuildCapture(SemaRef, LBExpr, Captures).get(); + Expr *Upper = + UBNonRect ? UBExpr : tryBuildCapture(SemaRef, UBExpr, Captures).get(); + if (!Upper || !Lower) + return std::make_pair(nullptr, nullptr); + + if (TestIsLessOp.getValue()) + MinExpr = Lower; + else + MaxExpr = Upper; + + // Build minimum/maximum value based on number of iterations. + ExprResult Diff; + QualType VarType = LCDecl->getType().getNonReferenceType(); + + Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Sub, Upper, Lower); + if (!Diff.isUsable()) + return std::make_pair(nullptr, nullptr); + + // Upper - Lower [- 1] + if (TestIsStrictOp) + Diff = SemaRef.BuildBinOp( + S, DefaultLoc, BO_Sub, Diff.get(), + SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get()); + if (!Diff.isUsable()) + return std::make_pair(nullptr, nullptr); + + // Upper - Lower [- 1] + Step + ExprResult NewStep = tryBuildCapture(SemaRef, Step, Captures); + if (!NewStep.isUsable()) + return std::make_pair(nullptr, nullptr); + + // Parentheses (for dumping/debugging purposes only). + Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get()); + if (!Diff.isUsable()) + return std::make_pair(nullptr, nullptr); + + // (Upper - Lower [- 1]) / Step + Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Div, Diff.get(), NewStep.get()); + if (!Diff.isUsable()) + return std::make_pair(nullptr, nullptr); + + // ((Upper - Lower [- 1]) / Step) * Step + // Parentheses (for dumping/debugging purposes only). + Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get()); + if (!Diff.isUsable()) + return std::make_pair(nullptr, nullptr); + + Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Mul, Diff.get(), NewStep.get()); + if (!Diff.isUsable()) + return std::make_pair(nullptr, nullptr); + + // Convert to the original type or ptrdiff_t, if original type is pointer. + if (!VarType->isAnyPointerType() && + !SemaRef.Context.hasSameType(Diff.get()->getType(), VarType)) { + Diff = SemaRef.PerformImplicitConversion( + Diff.get(), VarType, Sema::AA_Converting, /*AllowExplicit=*/true); + } else if (VarType->isAnyPointerType() && + !SemaRef.Context.hasSameType( + Diff.get()->getType(), + SemaRef.Context.getUnsignedPointerDiffType())) { + Diff = SemaRef.PerformImplicitConversion( + Diff.get(), SemaRef.Context.getUnsignedPointerDiffType(), + Sema::AA_Converting, /*AllowExplicit=*/true); + } + if (!Diff.isUsable()) + return std::make_pair(nullptr, nullptr); + + // Parentheses (for dumping/debugging purposes only). + Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get()); + if (!Diff.isUsable()) + return std::make_pair(nullptr, nullptr); + + if (TestIsLessOp.getValue()) { + // MinExpr = Lower; + // MaxExpr = Lower + (((Upper - Lower [- 1]) / Step) * Step) + Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Add, Lower, Diff.get()); + if (!Diff.isUsable()) + return std::make_pair(nullptr, nullptr); + Diff = SemaRef.ActOnFinishFullExpr(Diff.get(), /*DiscardedValue*/ false); + if (!Diff.isUsable()) + return std::make_pair(nullptr, nullptr); + MaxExpr = Diff.get(); + } else { + // MaxExpr = Upper; + // MinExpr = Upper - (((Upper - Lower [- 1]) / Step) * Step) + Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Sub, Upper, Diff.get()); + if (!Diff.isUsable()) + return std::make_pair(nullptr, nullptr); + Diff = SemaRef.ActOnFinishFullExpr(Diff.get(), /*DiscardedValue*/ false); + if (!Diff.isUsable()) + return std::make_pair(nullptr, nullptr); + MinExpr = Diff.get(); + } + + return std::make_pair(MinExpr, MaxExpr); +} + +Expr *OpenMPIterationSpaceChecker::buildFinalCondition(Scope *S) const { + if (InitDependOnLC || CondDependOnLC) + return Condition; + return nullptr; +} + Expr *OpenMPIterationSpaceChecker::buildPreCond( Scope *S, Expr *Cond, llvm::MapVector &Captures) const { @@ -5453,8 +5801,10 @@ Expr *OpenMPIterationSpaceChecker::buildPreCond( bool Suppress = SemaRef.getDiagnostics().getSuppressAllDiagnostics(); SemaRef.getDiagnostics().setSuppressAllDiagnostics(/*Val=*/true); - ExprResult NewLB = tryBuildCapture(SemaRef, LB, Captures); - ExprResult NewUB = tryBuildCapture(SemaRef, UB, Captures); + ExprResult NewLB = + InitDependOnLC ? LB : tryBuildCapture(SemaRef, LB, Captures); + ExprResult NewUB = + CondDependOnLC ? UB : tryBuildCapture(SemaRef, UB, Captures); if (!NewLB.isUsable() || !NewUB.isUsable()) return nullptr; @@ -5576,36 +5926,6 @@ Expr *OpenMPIterationSpaceChecker::buildOrderedLoopData( return Diff.get(); } - -/// Iteration space of a single for loop. -struct LoopIterationSpace final { - /// True if the condition operator is the strict compare operator (<, > or - /// !=). - bool IsStrictCompare = false; - /// Condition of the loop. - Expr *PreCond = nullptr; - /// This expression calculates the number of iterations in the loop. - /// It is always possible to calculate it before starting the loop. - Expr *NumIterations = nullptr; - /// The loop counter variable. - Expr *CounterVar = nullptr; - /// Private loop counter variable. - Expr *PrivateCounterVar = nullptr; - /// This is initializer for the initial value of #CounterVar. - Expr *CounterInit = nullptr; - /// This is step for the #CounterVar used to generate its update: - /// #CounterVar = #CounterInit + #CounterStep * CurrentIteration. - Expr *CounterStep = nullptr; - /// Should step be subtracted? - bool Subtract = false; - /// Source range of the loop init. - SourceRange InitSrcRange; - /// Source range of the loop condition. - SourceRange CondSrcRange; - /// Source range of the loop increment. - SourceRange IncSrcRange; -}; - } // namespace void Sema::ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init) { @@ -5696,7 +6016,7 @@ static bool checkOpenMPIterationSpace( unsigned TotalNestedLoopCount, Expr *CollapseLoopCountExpr, Expr *OrderedLoopCountExpr, Sema::VarsWithInheritedDSAType &VarsWithImplicitDSA, - LoopIterationSpace &ResultIterSpace, + llvm::MutableArrayRef ResultIterSpaces, llvm::MapVector &Captures) { // OpenMP [2.6, Canonical Loop Form] // for (init-expr; test-expr; incr-expr) structured-block @@ -5774,37 +6094,57 @@ static bool checkOpenMPIterationSpace( return HasErrors; // Build the loop's iteration space representation. - ResultIterSpace.PreCond = + ResultIterSpaces[CurrentNestedLoopCount].PreCond = ISC.buildPreCond(DSA.getCurScope(), For->getCond(), Captures); - ResultIterSpace.NumIterations = ISC.buildNumIterations( - DSA.getCurScope(), - (isOpenMPWorksharingDirective(DKind) || - isOpenMPTaskLoopDirective(DKind) || isOpenMPDistributeDirective(DKind)), - Captures); - ResultIterSpace.CounterVar = ISC.buildCounterVar(Captures, DSA); - ResultIterSpace.PrivateCounterVar = ISC.buildPrivateCounterVar(); - ResultIterSpace.CounterInit = ISC.buildCounterInit(); - ResultIterSpace.CounterStep = ISC.buildCounterStep(); - ResultIterSpace.InitSrcRange = ISC.getInitSrcRange(); - ResultIterSpace.CondSrcRange = ISC.getConditionSrcRange(); - ResultIterSpace.IncSrcRange = ISC.getIncrementSrcRange(); - ResultIterSpace.Subtract = ISC.shouldSubtractStep(); - ResultIterSpace.IsStrictCompare = ISC.isStrictTestOp(); + ResultIterSpaces[CurrentNestedLoopCount].NumIterations = + ISC.buildNumIterations(DSA.getCurScope(), ResultIterSpaces, + (isOpenMPWorksharingDirective(DKind) || + isOpenMPTaskLoopDirective(DKind) || + isOpenMPDistributeDirective(DKind)), + Captures); + ResultIterSpaces[CurrentNestedLoopCount].CounterVar = + ISC.buildCounterVar(Captures, DSA); + ResultIterSpaces[CurrentNestedLoopCount].PrivateCounterVar = + ISC.buildPrivateCounterVar(); + ResultIterSpaces[CurrentNestedLoopCount].CounterInit = ISC.buildCounterInit(); + ResultIterSpaces[CurrentNestedLoopCount].CounterStep = ISC.buildCounterStep(); + ResultIterSpaces[CurrentNestedLoopCount].InitSrcRange = ISC.getInitSrcRange(); + ResultIterSpaces[CurrentNestedLoopCount].CondSrcRange = + ISC.getConditionSrcRange(); + ResultIterSpaces[CurrentNestedLoopCount].IncSrcRange = + ISC.getIncrementSrcRange(); + ResultIterSpaces[CurrentNestedLoopCount].Subtract = ISC.shouldSubtractStep(); + ResultIterSpaces[CurrentNestedLoopCount].IsStrictCompare = + ISC.isStrictTestOp(); + std::tie(ResultIterSpaces[CurrentNestedLoopCount].MinValue, + ResultIterSpaces[CurrentNestedLoopCount].MaxValue) = + ISC.buildMinMaxValues(DSA.getCurScope(), Captures); + ResultIterSpaces[CurrentNestedLoopCount].FinalCondition = + ISC.buildFinalCondition(DSA.getCurScope()); + ResultIterSpaces[CurrentNestedLoopCount].IsNonRectangularLB = + ISC.doesInitDependOnLC(); + ResultIterSpaces[CurrentNestedLoopCount].IsNonRectangularUB = + ISC.doesCondDependOnLC(); + ResultIterSpaces[CurrentNestedLoopCount].LoopDependentIdx = + ISC.getLoopDependentIdx(); - HasErrors |= (ResultIterSpace.PreCond == nullptr || - ResultIterSpace.NumIterations == nullptr || - ResultIterSpace.CounterVar == nullptr || - ResultIterSpace.PrivateCounterVar == nullptr || - ResultIterSpace.CounterInit == nullptr || - ResultIterSpace.CounterStep == nullptr); + HasErrors |= + (ResultIterSpaces[CurrentNestedLoopCount].PreCond == nullptr || + ResultIterSpaces[CurrentNestedLoopCount].NumIterations == nullptr || + ResultIterSpaces[CurrentNestedLoopCount].CounterVar == nullptr || + ResultIterSpaces[CurrentNestedLoopCount].PrivateCounterVar == nullptr || + ResultIterSpaces[CurrentNestedLoopCount].CounterInit == nullptr || + ResultIterSpaces[CurrentNestedLoopCount].CounterStep == nullptr); if (!HasErrors && DSA.isOrderedRegion()) { if (DSA.getOrderedRegionParam().second->getNumForLoops()) { if (CurrentNestedLoopCount < DSA.getOrderedRegionParam().second->getLoopNumIterations().size()) { DSA.getOrderedRegionParam().second->setLoopNumIterations( - CurrentNestedLoopCount, ResultIterSpace.NumIterations); + CurrentNestedLoopCount, + ResultIterSpaces[CurrentNestedLoopCount].NumIterations); DSA.getOrderedRegionParam().second->setLoopCounter( - CurrentNestedLoopCount, ResultIterSpace.CounterVar); + CurrentNestedLoopCount, + ResultIterSpaces[CurrentNestedLoopCount].CounterVar); } } for (auto &Pair : DSA.getDoacrossDependClauses()) { @@ -5821,11 +6161,13 @@ static bool checkOpenMPIterationSpace( Expr *CntValue; if (Pair.first->getDependencyKind() == OMPC_DEPEND_source) CntValue = ISC.buildOrderedLoopData( - DSA.getCurScope(), ResultIterSpace.CounterVar, Captures, + DSA.getCurScope(), + ResultIterSpaces[CurrentNestedLoopCount].CounterVar, Captures, Pair.first->getDependencyLoc()); else CntValue = ISC.buildOrderedLoopData( - DSA.getCurScope(), ResultIterSpace.CounterVar, Captures, + DSA.getCurScope(), + ResultIterSpaces[CurrentNestedLoopCount].CounterVar, Captures, Pair.first->getDependencyLoc(), Pair.second[CurrentNestedLoopCount].first, Pair.second[CurrentNestedLoopCount].second); @@ -5839,10 +6181,12 @@ static bool checkOpenMPIterationSpace( /// Build 'VarRef = Start. static ExprResult buildCounterInit(Sema &SemaRef, Scope *S, SourceLocation Loc, ExprResult VarRef, - ExprResult Start, + ExprResult Start, bool IsNonRectangularLB, llvm::MapVector &Captures) { // Build 'VarRef = Start. - ExprResult NewStart = tryBuildCapture(SemaRef, Start.get(), Captures); + ExprResult NewStart = IsNonRectangularLB + ? Start.get() + : tryBuildCapture(SemaRef, Start.get(), Captures); if (!NewStart.isUsable()) return ExprError(); if (!SemaRef.Context.hasSameType(NewStart.get()->getType(), @@ -5863,6 +6207,7 @@ buildCounterInit(Sema &SemaRef, Scope *S, SourceLocation Loc, ExprResult VarRef, static ExprResult buildCounterUpdate( Sema &SemaRef, Scope *S, SourceLocation Loc, ExprResult VarRef, ExprResult Start, ExprResult Iter, ExprResult Step, bool Subtract, + bool IsNonRectangularLB, llvm::MapVector *Captures = nullptr) { // Add parentheses (for debugging purposes only). Iter = SemaRef.ActOnParenExpr(Loc, Loc, Iter.get()); @@ -5882,8 +6227,12 @@ static ExprResult buildCounterUpdate( // Try to build 'VarRef = Start, VarRef (+|-)= Iter * Step' or // 'VarRef = Start (+|-) Iter * Step'. - ExprResult NewStart = Start; - if (Captures) + if (!Start.isUsable()) + return ExprError(); + ExprResult NewStart = SemaRef.ActOnParenExpr(Loc, Loc, Start.get()); + if (!NewStart.isUsable()) + return ExprError(); + if (Captures && !IsNonRectangularLB) NewStart = tryBuildCapture(SemaRef, Start.get(), *Captures); if (NewStart.isInvalid()) return ExprError(); @@ -6054,8 +6403,7 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, if (checkOpenMPIterationSpace( DKind, CurStmt, SemaRef, DSA, Cnt, NestedLoopCount, std::max(OrderedLoopCount, NestedLoopCount), CollapseLoopCountExpr, - OrderedLoopCountExpr, VarsWithImplicitDSA, IterSpaces[Cnt], - Captures)) + OrderedLoopCountExpr, VarsWithImplicitDSA, IterSpaces, Captures)) return 0; // Move on to the next nested for loop, or to the loop body. // OpenMP [2.8.1, simd construct, Restrictions] @@ -6068,8 +6416,7 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, if (checkOpenMPIterationSpace( DKind, CurStmt, SemaRef, DSA, Cnt, NestedLoopCount, std::max(OrderedLoopCount, NestedLoopCount), CollapseLoopCountExpr, - OrderedLoopCountExpr, VarsWithImplicitDSA, IterSpaces[Cnt], - Captures)) + OrderedLoopCountExpr, VarsWithImplicitDSA, IterSpaces, Captures)) return 0; if (Cnt > 0 && IterSpaces[Cnt].CounterVar) { // Handle initialization of captured loop iterator variables. @@ -6530,6 +6877,9 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, Built.Inits.resize(NestedLoopCount); Built.Updates.resize(NestedLoopCount); Built.Finals.resize(NestedLoopCount); + Built.DependentCounters.resize(NestedLoopCount); + Built.DependentInits.resize(NestedLoopCount); + Built.FinalsConditions.resize(NestedLoopCount); { // We implement the following algorithm for obtaining the // original loop iteration variable values based on the @@ -6589,24 +6939,26 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, DeclRefExpr *CounterVar = buildDeclRefExpr( SemaRef, VD, IS.CounterVar->getType(), IS.CounterVar->getExprLoc(), /*RefersToCapture=*/true); - ExprResult Init = buildCounterInit(SemaRef, CurScope, UpdLoc, CounterVar, - IS.CounterInit, Captures); + ExprResult Init = + buildCounterInit(SemaRef, CurScope, UpdLoc, CounterVar, + IS.CounterInit, IS.IsNonRectangularLB, Captures); if (!Init.isUsable()) { HasErrors = true; break; } ExprResult Update = buildCounterUpdate( SemaRef, CurScope, UpdLoc, CounterVar, IS.CounterInit, Iter, - IS.CounterStep, IS.Subtract, &Captures); + IS.CounterStep, IS.Subtract, IS.IsNonRectangularLB, &Captures); if (!Update.isUsable()) { HasErrors = true; break; } // Build final: IS.CounterVar = IS.Start + IS.NumIters * IS.Step - ExprResult Final = buildCounterUpdate( - SemaRef, CurScope, UpdLoc, CounterVar, IS.CounterInit, - IS.NumIterations, IS.CounterStep, IS.Subtract, &Captures); + ExprResult Final = + buildCounterUpdate(SemaRef, CurScope, UpdLoc, CounterVar, + IS.CounterInit, IS.NumIterations, IS.CounterStep, + IS.Subtract, IS.IsNonRectangularLB, &Captures); if (!Final.isUsable()) { HasErrors = true; break; @@ -6622,6 +6974,16 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, Built.Inits[Cnt] = Init.get(); Built.Updates[Cnt] = Update.get(); Built.Finals[Cnt] = Final.get(); + Built.DependentCounters[Cnt] = nullptr; + Built.DependentInits[Cnt] = nullptr; + Built.FinalsConditions[Cnt] = nullptr; + if (IS.IsNonRectangularLB) { + Built.DependentCounters[Cnt] = + Built.Counters[NestedLoopCount - 1 - IS.LoopDependentIdx]; + Built.DependentInits[Cnt] = + Built.Inits[NestedLoopCount - 1 - IS.LoopDependentIdx]; + Built.FinalsConditions[Cnt] = IS.FinalCondition; + } } } @@ -6634,7 +6996,7 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, Built.NumIterations = NumIterations.get(); Built.CalcLastIteration = SemaRef .ActOnFinishFullExpr(CalcLastIteration.get(), - /*DiscardedValue*/ false) + /*DiscardedValue=*/false) .get(); Built.PreCond = PreCond.get(); Built.PreInits = buildPreInits(C, Captures); @@ -12778,9 +13140,9 @@ static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV, // Build update: Var = InitExpr + IV * Step ExprResult Update; if (!Info.first) - Update = - buildCounterUpdate(SemaRef, S, RefExpr->getExprLoc(), *CurPrivate, - InitExpr, IV, Step, /* Subtract */ false); + Update = buildCounterUpdate( + SemaRef, S, RefExpr->getExprLoc(), *CurPrivate, InitExpr, IV, Step, + /*Subtract=*/false, /*IsNonRectangularLB=*/false); else Update = *CurPrivate; Update = SemaRef.ActOnFinishFullExpr(Update.get(), DE->getBeginLoc(), @@ -12791,7 +13153,8 @@ static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV, if (!Info.first) Final = buildCounterUpdate(SemaRef, S, RefExpr->getExprLoc(), CapturedRef, - InitExpr, NumIterations, Step, /*Subtract=*/false); + InitExpr, NumIterations, Step, /*Subtract=*/false, + /*IsNonRectangularLB=*/false); else Final = *CurPrivate; Final = SemaRef.ActOnFinishFullExpr(Final.get(), DE->getBeginLoc(), diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index afaaa543bb27..8ab0845d151e 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -2060,6 +2060,18 @@ void ASTStmtReader::VisitOMPLoopDirective(OMPLoopDirective *D) { for (unsigned i = 0; i < CollapsedNum; ++i) Sub.push_back(Record.readSubExpr()); D->setFinals(Sub); + Sub.clear(); + for (unsigned i = 0; i < CollapsedNum; ++i) + Sub.push_back(Record.readSubExpr()); + D->setDependentCounters(Sub); + Sub.clear(); + for (unsigned i = 0; i < CollapsedNum; ++i) + Sub.push_back(Record.readSubExpr()); + D->setDependentInits(Sub); + Sub.clear(); + for (unsigned i = 0; i < CollapsedNum; ++i) + Sub.push_back(Record.readSubExpr()); + D->setFinalsConditions(Sub); } void ASTStmtReader::VisitOMPParallelDirective(OMPParallelDirective *D) { diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index 4fbcbaabe74b..a6927f32c0ee 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -1995,6 +1995,12 @@ void ASTStmtWriter::VisitOMPLoopDirective(OMPLoopDirective *D) { for (auto I : D->finals()) { Record.AddStmt(I); } + for (Stmt *S : D->dependent_counters()) + Record.AddStmt(S); + for (Stmt *S : D->dependent_inits()) + Record.AddStmt(S); + for (Stmt *S : D->finals_conditions()) + Record.AddStmt(S); } void ASTStmtWriter::VisitOMPParallelDirective(OMPParallelDirective *D) { diff --git a/clang/test/OpenMP/for_codegen.cpp b/clang/test/OpenMP/for_codegen.cpp index 47c5be9becfc..80afa1c94525 100644 --- a/clang/test/OpenMP/for_codegen.cpp +++ b/clang/test/OpenMP/for_codegen.cpp @@ -25,10 +25,176 @@ // CHECK-LABEL: loop_with_counter_collapse void loop_with_counter_collapse() { + // Captured initializations. + // CHECK: store i32 0, i32* [[I_TMP:%.+]], + // CHECK: [[VAL:%.+]] = load i32, i32* [[I_TMP]], + // CHECK: store i32 [[VAL]], i32* [[J_LB_MIN:%.+]], + // CHECK: store i32 3, i32* [[I_TMP]], + // CHECK: [[VAL:%.+]] = load i32, i32* [[I_TMP]], + // CHECK: store i32 [[VAL]], i32* [[J_LB_MAX:%.+]], + // CHECK: [[J_LB_MIN_VAL:%.+]] = load i32, i32* [[J_LB_MIN]], + // CHECK: [[J_LB_MAX_VAL:%.+]] = load i32, i32* [[J_LB_MAX]], + // CHECK: [[CMP:%.+]] = icmp slt i32 [[J_LB_MIN_VAL]], [[J_LB_MAX_VAL]] + // CHECK: [[BOOL:%.+]] = zext i1 [[CMP]] to i8 + // CHECK: store i8 [[BOOL]], i8* [[J_LB_CMP:%.+]], + // CHECK: store i32 0, i32* [[I_TMP]], + // CHECK: [[VAL:%.+]] = load i32, i32* [[I_TMP]], + // CHECK: [[J_UB_MIN_VAL:%.+]] = add nsw i32 4, [[VAL]] + // CHECK: store i32 [[J_UB_MIN_VAL]], i32* [[J_UB_MIN:%.+]], + // CHECK: store i32 3, i32* [[I_TMP]], + // CHECK: [[VAL:%.+]] = load i32, i32* [[I_TMP]], + // CHECK: [[J_UB_MAX_VAL:%.+]] = add nsw i32 4, [[VAL]] + // CHECK: store i32 [[J_UB_MAX_VAL]], i32* [[J_UB_MAX:%.+]], + // CHECK: [[J_UB_MIN_VAL:%.+]] = load i32, i32* [[J_UB_MIN]], + // CHECK: [[J_UB_MAX_VAL:%.+]] = load i32, i32* [[J_UB_MAX]], + // CHECK: [[CMP:%.+]] = icmp sgt i32 [[J_UB_MIN_VAL]], [[J_UB_MAX_VAL]] + // CHECK: [[BOOL:%.+]] = zext i1 [[CMP]] to i8 + // CHECK: store i8 [[BOOL]], i8* [[J_UB_CMP:%.+]], + // CHECK: [[J_UB_CMP_VAL:%.+]] = load i8, i8* [[J_UB_CMP]], + // CHECK: [[BOOL:%.+]] = trunc i8 [[J_UB_CMP_VAL]] to i1 + // CHECK: br i1 [[BOOL]], label %[[TRUE:[^,]+]], label %[[FALSE:[^,]+]] + // CHECK: [[TRUE]]: + // CHECK: [[J_UB_MIN_VAL:%.+]] = load i32, i32* [[J_UB_MIN]], + // CHECK: br label %[[EXIT:[^,]+]] + // CHECK: [[FALSE]]: + // CHECK: [[J_UB_MAX_VAL:%.+]] = load i32, i32* [[J_UB_MAX]], + // CHECK: br label %[[EXIT]] + // CHECK: [[EXIT]]: + // CHECK: [[J_UB_VAL:%.+]] = phi i32 [ [[J_UB_MIN_VAL]], %[[TRUE]] ], [ [[J_UB_MAX_VAL]], %[[FALSE]] ] + // CHECK: store i32 [[J_UB_VAL]], i32* [[J_UB:%.+]], + // CHECK: [[J_LB_CMP_VAL:%.+]] = load i8, i8* [[J_LB_CMP]], + // CHECK: [[BOOL:%.+]] = trunc i8 [[J_LB_CMP_VAL]] to i1 + // CHECK: br i1 [[BOOL]], label %[[TRUE:[^,]+]], label %[[FALSE:[^,]+]] + // CHECK: [[TRUE]]: + // CHECK: [[J_LB_MIN_VAL:%.+]] = load i32, i32* [[J_LB_MIN]], + // CHECK: br label %[[EXIT:[^,]+]] + // CHECK: [[FALSE]]: + // CHECK: [[J_LB_MAX_VAL:%.+]] = load i32, i32* [[J_LB_MAX]], + // CHECK: br label %[[EXIT]] + // CHECK: [[EXIT]]: + // CHECK: [[J_LB_VAL:%.+]] = phi i32 [ [[J_LB_MIN_VAL]], %[[TRUE]] ], [ [[J_LB_MAX_VAL]], %[[FALSE]] ] + // CHECK: store i32 [[J_LB_VAL]], i32* [[J_LB:%.+]], + // CHECK: [[J_UB_VAL:%.+]] = load i32, i32* [[J_UB]], + // CHECK: [[J_LB_VAL:%.+]] = load i32, i32* [[J_LB]], + // CHECK: [[SUB:%.+]] = sub nsw i32 [[J_UB_VAL]], [[J_LB_VAL]] + // CHECK: [[SUB_ST:%.+]] = sub nsw i32 [[SUB]], 1 + // CHECK: [[ADD_ST:%.+]] = add nsw i32 [[SUB_ST]], 1 + // CHECK: [[DIV_ST:%.+]] = sdiv i32 [[ADD_ST]], 1 + // CHECK: [[CAST:%.+]] = sext i32 [[DIV_ST]] to i64 + // CHECK: [[MUL:%.+]] = mul nsw i64 4, [[CAST]] + // CHECK: [[NUM_ITERS_VAL:%.+]] = sub nsw i64 [[MUL]], 1 + // CHECK: store i64 [[NUM_ITERS_VAL]], i64* [[NUM_ITERS:%.+]], + + // Initialization + // CHECK: store i32 0, i32* [[I:%.+]], + // CHECK: [[I_INIT:%.+]] = load i32, i32* [[I]], + // CHECK: store i32 [[I_INIT]], i32* [[J:%.+]], + // LIFETIME: call void @llvm.lifetime.end // LIFETIME: call void @llvm.lifetime.end - // CHECK: call void @__kmpc_for_static_init_8(%struct.ident_t* @ - // CHECK: call void @__kmpc_for_static_fini(%struct.ident_t* @ + + // Precondition for j counter + // CHECK: store i32 0, i32* [[TMP_I:%.+]], + // CHECK: [[J_LB_VAL:%.+]] = load i32, i32* [[TMP_I]], + // CHECK: [[I_VAL:%.+]] = load i32, i32* [[TMP_I]], + // CHECK: [[J_UB_VAL:%.+]] = add nsw i32 4, [[I_VAL]] + // CHECK: [[CMP:%.+]] = icmp slt i32 [[J_LB_VAL]], [[J_UB_VAL]] + // CHECK: br i1 [[CMP]], label %[[THEN:[^,]+]], label %[[ELSE:[^,]+]] + + // CHECK: [[THEN]]: + // CHECK: store i64 0, i64* [[LB:%.+]], + // CHECK: [[NUM_ITERS_VAL:%.+]] = load i64, i64* [[NUM_ITERS]], + // CHECK: store i64 [[NUM_ITERS_VAL]], i64* [[UB:%.+]], + // CHECK: store i64 1, i64* [[STRIDE:%.+]], + // CHECK: store i32 0, i32* [[IS_LAST:%.+]], + // CHECK: call void @__kmpc_for_static_init_8(%struct.ident_t* @{{.+}}, i32 %{{.+}}, i32 34, i32* [[IS_LAST]], i64* [[LB]], i64* [[UB]], i64* [[STRIDE]], i64 1, i64 1) + // CHECK: [[UB_VAL:%.+]] = load i64, i64* [[UB]], + // CHECK: [[NUM_ITERS_VAL:%.+]] = load i64, i64* [[NUM_ITERS]], + // CHECK: [[CMP:%.+]] = icmp sgt i64 [[UB_VAL]], [[NUM_ITERS_VAL]] + // CHECK: br i1 [[CMP]], label %[[TRUE:[^,]+]], label %[[FALSE:[^,]+]] + // CHECK: [[TRUE]]: + // CHECK: [[NUM_ITERS_VAL:%.+]] = load i64, i64* [[NUM_ITERS]], + // CHECK: br label %[[DONE:[^,]+]] + // CHECK: [[FALSE]]: + // CHECK: [[UB_VAL:%.+]] = load i64, i64* [[UB]], + // CHECK: br label %[[DONE]] + // CHECK: [[DONE]]: + // CHECK: [[TOP:%.+]] = phi i64 [ [[NUM_ITERS_VAL]], %[[TRUE]] ], [ [[UB_VAL]], %[[FALSE]] ] + // CHECK: store i64 [[TOP]], i64* [[UB]], + // CHECK: [[LB_VAL:%.+]] = load i64, i64* [[LB]], + // CHECK: store i64 [[LB_VAL]], i64* [[IV:%.+]], + // CHECK: br label %[[COND:[^,]+]] + // CHECK: [[COND]]: + // CHECK: [[IV_VAL:%.+]] = load i64, i64* [[IV]], + // CHECK: [[UB_VAL:%.+]] = load i64, i64* [[UB]], + // CHECK: [[CMP:%.+]] = icmp sle i64 [[IV_VAL]], [[UB_VAL]] + // CHECK: br i1 [[CMP]], label %[[BODY:[^,]+]], label %[[CLEANUP:[^,]+]] + // LIFETIME: [[CLEANUP]]: + // LIFETIME: br label %[[CLEANUP:[^,]+]] + // CHECK: [[BODY]]: + // CHECK: [[IV_VAL:%.+]] = load i64, i64* [[IV]], + // CHECK: [[J_UB_VAL:%.+]] = load i32, i32* [[J_UB]], + // CHECK: [[J_LB_VAL:%.+]] = load i32, i32* [[J_LB]], + // CHECK: [[SUB:%.+]] = sub nsw i32 [[J_UB_VAL]], [[J_LB_VAL]] + // CHECK: [[SUB_ST:%.+]] = sub nsw i32 [[SUB]], 1 + // CHECK: [[ADD_ST:%.+]] = add nsw i32 [[SUB_ST]], 1 + // CHECK: [[DIV_ST:%.+]] = sdiv i32 [[ADD_ST]], 1 + // CHECK: [[MUL:%.+]] = mul nsw i32 1, [[DIV_ST]] + // CHECK: [[CAST:%.+]] = sext i32 [[MUL]] to i64 + // CHECK: [[DIV:%.+]] = sdiv i64 [[IV_VAL]], [[CAST]] + // CHECK: [[MUL:%.+]] = mul nsw i64 [[DIV]], 1 + // CHECK: [[ADD:%.+]] = add nsw i64 0, [[MUL]] + // CHECK: [[CAST:%.+]] = trunc i64 [[ADD]] to i32 + // CHECK: store i32 [[CAST]], i32* [[I_PRIV:%.+]], + // CHECK: [[I_VAL:%.+]] = load i32, i32* [[I_PRIV]], + // CHECK: [[CONV:%.+]] = sext i32 [[I_VAL]] to i64 + // CHECK: [[IV_VAL:%.+]] = load i64, i64* [[IV]], + // CHECK: [[IV_VAL1:%.+]] = load i64, i64* [[IV]], + // CHECK: [[J_UB_VAL:%.+]] = load i32, i32* [[J_UB]], + // CHECK: [[J_LB_VAL:%.+]] = load i32, i32* [[J_LB]], + // CHECK: [[SUB:%.+]] = sub nsw i32 [[J_UB_VAL]], [[J_LB_VAL]] + // CHECK: [[SUB_ST:%.+]] = sub nsw i32 [[SUB]], 1 + // CHECK: [[ADD_ST:%.+]] = add nsw i32 [[SUB_ST]], 1 + // CHECK: [[DIV_ST:%.+]] = sdiv i32 [[ADD_ST]], 1 + // CHECK: [[MUL:%.+]] = mul nsw i32 1, [[DIV_ST]] + // CHECK: [[CAST:%.+]] = sext i32 [[MUL]] to i64 + // CHECK: [[DIV:%.+]] = sdiv i64 [[IV_VAL1]], [[CAST]] + // CHECK: [[J_UB_VAL:%.+]] = load i32, i32* [[J_UB]], + // CHECK: [[J_LB_VAL:%.+]] = load i32, i32* [[J_LB]], + // CHECK: [[SUB:%.+]] = sub nsw i32 [[J_UB_VAL]], [[J_LB_VAL]] + // CHECK: [[SUB_ST:%.+]] = sub nsw i32 [[SUB]], 1 + // CHECK: [[ADD_ST:%.+]] = add nsw i32 [[SUB_ST]], 1 + // CHECK: [[DIV_ST:%.+]] = sdiv i32 [[ADD_ST]], 1 + // CHECK: [[MUL:%.+]] = mul nsw i32 1, [[DIV_ST]] + // CHECK: [[CAST:%.+]] = sext i32 [[MUL]] to i64 + // CHECK: [[MUL:%.+]] = mul nsw i64 [[DIV]], [[CAST]] + // CHECK: [[SUB:%.+]] = sub nsw i64 [[IV_VAL]], [[MUL]] + // CHECK: [[MUL:%.+]] = mul nsw i64 [[SUB:%.+]], 1 + // CHECK: [[ADD:%.+]] = add nsw i64 [[CONV]], [[MUL]] + // CHECK: [[CAST:%.+]] = trunc i64 [[ADD]] to i32 + // CHECK: store i32 [[CAST]], i32* [[J_PRIV:%.+]], + + // Check that the loop variable is not out of its boundaries. + // CHECK: [[J_VAL:%.+]] = load i32, i32* [[J_PRIV]], + // CHECK: [[I_VAL:%.+]] = load i32, i32* [[I_PRIV]], + // CHECK: [[J_COND:%.+]] = add nsw i32 4, [[I_VAL]] + // CHECK: [[CMP:%.+]] = icmp slt i32 [[J_VAL]], [[J_COND]] + // CHECK: br i1 [[CMP]], label %[[NEXT:[^,]+]], label %[[BODY_CONT:[^,]+]] + // CHECK: [[NEXT]]: + + // Main body is empty. + // CHECK: br label %[[BODY_CONT]] + // CHECK: [[BODY_CONT]]: + // CHECK: br label %[[INC:[^,]+]] + // CHECK: [[INC]]: + // CHECK: [[IV_VAL:%.+]] = load i64, i64* [[IV]], + // CHECK: [[ADD:%.+]] = add nsw i64 [[IV_VAL]], 1 + // CHECK: store i64 [[ADD]], i64* [[IV]], + // CHECK: br label %[[COND]] + // CHECK: [[CLEANUP]]: + // CHECK: br label %[[EXIT:[^,]+]] + // CHECK: [[EXIT]]: + // CHECK: call void @__kmpc_for_static_fini(%struct.ident_t* @{{.+}}, i32 %{{.+}}) // LIFETIME: call void @llvm.lifetime.end // LIFETIME: call void @llvm.lifetime.end // LIFETIME: call void @llvm.lifetime.end @@ -40,7 +206,7 @@ void loop_with_counter_collapse() { // LIFETIME: call void @llvm.lifetime.end #pragma omp for collapse(2) for (int i = 0; i < 4; i++) { - for (int j = i; j < 4; j++) { + for (int j = i; j < 4 + i; j++) { } } } @@ -449,13 +615,14 @@ void for_with_references() { // CHECK: [[I:%.+]] = alloca i8, // CHECK: [[CNT:%.+]] = alloca i8*, // CHECK: [[CNT_PRIV:%.+]] = alloca i8, -// CHECK: call void @__kmpc_for_static_init_4( +// CHECK: call void @__kmpc_for_static_init_8( // CHECK-NOT: load i8, i8* [[CNT]], // CHECK: call void @__kmpc_for_static_fini( char i = 0; char &cnt = i; -#pragma omp for +#pragma omp for collapse(2) for (cnt = 0; cnt < 2; ++cnt) + for (int j = cnt; j < 4 + cnt; j++) k = cnt; } @@ -528,13 +695,14 @@ void loop_with_It_plus(It begin, It end) { // CHECK: call void @__kmpc_for_static_fini( void loop_with_stmt_expr() { -#pragma omp for +#pragma omp for collapse(2) for (int i = __extension__({float b = 0;b; }); i < __extension__({double c = 1;c; }); i += __extension__({char d = 1; d; })) + for (int j = i; j < 4 + i; j++) ; } // CHECK-LABEL: loop_with_stmt_expr // CHECK: call i32 @__kmpc_global_thread_num( -// CHECK: call void @__kmpc_for_static_init_4( +// CHECK: call void @__kmpc_for_static_init_8( // CHECK: call void @__kmpc_for_static_fini( diff --git a/clang/test/OpenMP/for_loop_messages.cpp b/clang/test/OpenMP/for_loop_messages.cpp index f5f6d0b70313..37c81123e435 100644 --- a/clang/test/OpenMP/for_loop_messages.cpp +++ b/clang/test/OpenMP/for_loop_messages.cpp @@ -651,10 +651,9 @@ public: ; #pragma omp parallel -// expected-error@+6 2 {{expected loop invariant expression or ' * ii + ' kind of expression}} -// expected-error@+5 {{expected loop invariant expression or ' * TC::ii + ' kind of expression}} // expected-error@+5 2 {{expected loop invariant expression or ' * ii + ' kind of expression}} // expected-error@+4 {{expected loop invariant expression or ' * TC::ii + ' kind of expression}} +// expected-error@+4 {{expected loop invariant expression or ' * TC::ii + ' kind of expression}} #pragma omp for collapse(3) for (ii = 10 + 25; ii < 1000; ii += 1) for (iii = ii * 10 + 25; iii < ii / ii - 23; iii += 1) diff --git a/clang/test/OpenMP/parallel_messages.cpp b/clang/test/OpenMP/parallel_messages.cpp index ac8869fff9d2..c9b6dbc98f0b 100644 --- a/clang/test/OpenMP/parallel_messages.cpp +++ b/clang/test/OpenMP/parallel_messages.cpp @@ -102,6 +102,6 @@ struct h { h operator<(h, h); void g::j() { #pragma omp parallel for default(none) if(a::b) - for (auto a = blocks.cbegin; a < blocks; ++a) // expected-error {{invalid operands to binary expression ('f' and 'int')}} + for (auto a = blocks.cbegin; a < blocks; ++a) // expected-error 2 {{invalid operands to binary expression ('f' and 'int')}} ; }