[OPENMP]Support for non-rectangular loops.

Added basic support for non-rectangular loops. It requires an additional
analysis of min/max boundaries for non-rectangular loops. Since only
linear dependency is allowed, we can do this analysis.

llvm-svn: 368903
This commit is contained in:
Alexey Bataev 2019-08-14 19:30:06 +00:00
parent c264992853
commit f8be476f0c
9 changed files with 827 additions and 99 deletions

View File

@ -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<Expr *>(Storage, CollapsedNum);
}
/// Get the dependent counters storage.
MutableArrayRef<Expr *> getDependentCounters() {
Expr **Storage = reinterpret_cast<Expr **>(
&*std::next(child_begin(),
getArraysOffset(getDirectiveKind()) + 5 * CollapsedNum));
return MutableArrayRef<Expr *>(Storage, CollapsedNum);
}
/// Get the dependent inits storage.
MutableArrayRef<Expr *> getDependentInits() {
Expr **Storage = reinterpret_cast<Expr **>(
&*std::next(child_begin(),
getArraysOffset(getDirectiveKind()) + 6 * CollapsedNum));
return MutableArrayRef<Expr *>(Storage, CollapsedNum);
}
/// Get the finals conditions storage.
MutableArrayRef<Expr *> getFinalsConditions() {
Expr **Storage = reinterpret_cast<Expr **>(
&*std::next(child_begin(),
getArraysOffset(getDirectiveKind()) + 7 * CollapsedNum));
return MutableArrayRef<Expr *>(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<Expr *> A);
void setUpdates(ArrayRef<Expr *> A);
void setFinals(ArrayRef<Expr *> A);
void setDependentCounters(ArrayRef<Expr *> A);
void setDependentInits(ArrayRef<Expr *> A);
void setFinalsConditions(ArrayRef<Expr *> A);
public:
/// The expressions built to support OpenMP loops in combined/composite
@ -798,6 +828,15 @@ public:
SmallVector<Expr *, 4> Updates;
/// Final loop counter values for GodeGen.
SmallVector<Expr *, 4> Finals;
/// List of counters required for the generation of the non-rectangular
/// loops.
SmallVector<Expr *, 4> DependentCounters;
/// List of initializers required for the generation of the non-rectangular
/// loops.
SmallVector<Expr *, 4> DependentInits;
/// List of final conditions required for the generation of the
/// non-rectangular loops.
SmallVector<Expr *, 4> 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<OMPLoopDirective *>(this)->getFinals();
}
ArrayRef<Expr *> dependent_counters() { return getDependentCounters(); }
ArrayRef<Expr *> dependent_counters() const {
return const_cast<OMPLoopDirective *>(this)->getDependentCounters();
}
ArrayRef<Expr *> dependent_inits() { return getDependentInits(); }
ArrayRef<Expr *> dependent_inits() const {
return const_cast<OMPLoopDirective *>(this)->getDependentInits();
}
ArrayRef<Expr *> finals_conditions() { return getFinalsConditions(); }
ArrayRef<Expr *> finals_conditions() const {
return const_cast<OMPLoopDirective *>(this)->getFinalsConditions();
}
static bool classof(const Stmt *T) {
return T->getStmtClass() == OMPSimdDirectiveClass ||
T->getStmtClass() == OMPForDirectiveClass ||

View File

@ -72,6 +72,25 @@ void OMPLoopDirective::setFinals(ArrayRef<Expr *> A) {
std::copy(A.begin(), A.end(), getFinals().begin());
}
void OMPLoopDirective::setDependentCounters(ArrayRef<Expr *> 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<Expr *> 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<Expr *> 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<OMPClause *> 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;
}

View File

@ -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<VarDecl>(cast<DeclRefExpr>(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(

View File

@ -4709,6 +4709,54 @@ StmtResult Sema::ActOnOpenMPParallelDirective(ArrayRef<OMPClause *> 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<unsigned> CondDependOnLC;
/// Checks if the provide statement depends on the loop counter.
Optional<unsigned> 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<LoopIterationSpace> ResultIterSpaces, bool LimitedType,
llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) const;
/// Build the precondition expression for the loops.
Expr *
@ -4813,8 +4864,21 @@ public:
llvm::MapVector<const Expr *, DeclRefExpr *> &Captures,
SourceLocation Loc, Expr *Inc = nullptr,
OverloadedOperatorKind OOK = OO_Amp);
/// Builds the minimum value for the loop counter.
std::pair<Expr *, Expr *> buildMinMaxValues(
Scope *S, llvm::MapVector<const Expr *, DeclRefExpr *> &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<BinaryOperator>(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<LoopIterationSpace> ResultIterSpaces, bool LimitedType,
llvm::MapVector<const Expr *, DeclRefExpr *> &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<Expr *, Expr *> OpenMPIterationSpaceChecker::buildMinMaxValues(
Scope *S, llvm::MapVector<const Expr *, DeclRefExpr *> &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<const Expr *, DeclRefExpr *> &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<LoopIterationSpace> ResultIterSpaces,
llvm::MapVector<const Expr *, DeclRefExpr *> &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<const Expr *, DeclRefExpr *> &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<const Expr *, DeclRefExpr *> *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(),

View File

@ -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) {

View File

@ -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) {

View File

@ -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<char> begin, It<char> 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(

View File

@ -651,10 +651,9 @@ public:
;
#pragma omp parallel
// expected-error@+6 2 {{expected loop invariant expression or '<invariant1> * ii + <invariant2>' kind of expression}}
// expected-error@+5 {{expected loop invariant expression or '<invariant1> * TC::ii + <invariant2>' kind of expression}}
// expected-error@+5 2 {{expected loop invariant expression or '<invariant1> * ii + <invariant2>' kind of expression}}
// expected-error@+4 {{expected loop invariant expression or '<invariant1> * TC::ii + <invariant2>' kind of expression}}
// expected-error@+4 {{expected loop invariant expression or '<invariant1> * TC::ii + <invariant2>' 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)

View File

@ -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')}}
;
}