================
@@ -16382,6 +16395,277 @@ StmtResult
SemaOpenMP::ActOnOpenMPInterchangeDirective(
buildPreInits(Context, PreInits));
}
+/// Counts the perfectly nested canonical loop depth at \p AStmt. Returns
+/// std::nullopt if a loop-generating transformation prevents a static count.
+static std::optional<unsigned> getCanonicalLoopNestDepth(Stmt *AStmt) {
+ unsigned Depth = 0;
+ Stmt *CurStmt = AStmt ? AStmt->IgnoreContainers() : nullptr;
+ while (CurStmt) {
+ if (isa<OMPLoopTransformationDirective>(CurStmt))
+ return std::nullopt;
+ if (auto *CanonLoop = dyn_cast<OMPCanonicalLoop>(CurStmt))
+ CurStmt = CanonLoop->getLoopStmt();
+ Stmt *Body = nullptr;
+ if (auto *For = dyn_cast<ForStmt>(CurStmt))
+ Body = For->getBody();
+ else if (auto *RangeFor = dyn_cast<CXXForRangeStmt>(CurStmt))
+ Body = RangeFor->getBody();
+ else
+ break;
+ ++Depth;
+ CurStmt = Body ? Body->IgnoreContainers() : nullptr;
+ }
+ return Depth;
+}
+
+StmtResult
+SemaOpenMP::ActOnOpenMPFlattenDirective(ArrayRef<OMPClause *> Clauses,
+ Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ ASTContext &Context = getASTContext();
+ DeclContext *CurContext = SemaRef.CurContext;
+ Scope *CurScope = SemaRef.getCurScope();
+
+ // Empty statement should only be possible if there already was an error.
+ if (!AStmt)
+ return StmtError();
+
+ // flatten without 'depth' clause combines two loops; 'depth(k)' selects k.
+ unsigned NumLoops = 2;
+ bool DepthIsValueDependent = false;
+ const auto *DepthClause =
+ OMPExecutableDirective::getSingleClause<OMPDepthClause>(Clauses);
+ if (DepthClause) {
+ Expr *DepthExpr = DepthClause->getDepth();
+ if (DepthExpr && DepthExpr->isValueDependent()) {
+ DepthIsValueDependent = true;
+ } else if (DepthExpr) {
+ Expr::EvalResult EvalResult;
+ if (DepthExpr->EvaluateAsInt(EvalResult, Context))
+ NumLoops = EvalResult.Val.getInt().getZExtValue();
+ }
+ }
+
+ // Report "expected k for loops, but found only n" when depth exceeds the
+ // perfect nest (same form as 'collapse'); skip if depth or nest is unknown.
+ if (DepthClause && !DepthIsValueDependent) {
+ if (std::optional<unsigned> NestDepth = getCanonicalLoopNestDepth(AStmt);
+ NestDepth && NumLoops > *NestDepth) {
+ Diag(AStmt->getBeginLoc(), diag::err_omp_not_for)
+ << /*expected N for loops form=*/1
+ << getOpenMPDirectiveName(OMPD_flatten) << NumLoops
+ << (*NestDepth > 0) << *NestDepth;
+ return StmtError();
+ }
+ }
+
+ // Defer when 'depth' is value-dependent (concrete k unknown until
+ // instantiation).
+ if (DepthIsValueDependent)
+ return OMPFlattenDirective::Create(Context, StartLoc, EndLoc, Clauses,
+ NumLoops, AStmt, nullptr, nullptr);
+
+ // Verify and diagnose loop nest.
+ SmallVector<OMPLoopBasedDirective::HelperExprs, 4> LoopHelpers(NumLoops);
+ Stmt *Body = nullptr;
+ SmallVector<SmallVector<Stmt *>, 4> OriginalInits;
+ if (!checkTransformableLoopNest(OMPD_flatten, AStmt, NumLoops, LoopHelpers,
+ Body, OriginalInits))
+ return StmtError();
+
+ // Delay flattening to when template is completely instantiated.
+ if (CurContext->isDependentContext())
+ return OMPFlattenDirective::Create(Context, StartLoc, EndLoc, Clauses,
+ NumLoops, AStmt, nullptr, nullptr);
+
+ assert(LoopHelpers.size() == NumLoops &&
+ "Expecting loop iteration space dimensionality to match number of "
+ "affected loops");
+ assert(OriginalInits.size() == NumLoops &&
+ "Expecting loop iteration space dimensionality to match number of "
+ "affected loops");
+
+ // Find the affected loops.
+ SmallVector<Stmt *> LoopStmts(NumLoops, nullptr);
+ collectLoopStmts(AStmt, LoopStmts);
+
+ // Collect pre-init statements in outer-to-inner order.
+ SmallVector<Stmt *> PreInits;
+ for (auto I : llvm::seq<int>(NumLoops)) {
+ OMPLoopBasedDirective::HelperExprs &LoopHelper = LoopHelpers[I];
+ assert(LoopHelper.Counters.size() == 1 &&
+ "Single-dimensional loop iteration space expected");
+ addLoopPreInits(Context, LoopHelper, LoopStmts[I], OriginalInits[I],
+ PreInits);
+ }
+
+ CaptureVars CopyTransformer(SemaRef);
+ auto MakeNumIterations = [&CopyTransformer,
+ &LoopHelpers](unsigned I) -> Expr * {
+ return AssertSuccess(
+ CopyTransformer.TransformExpr(LoopHelpers[I].NumIterations));
+ };
+
+ OMPLoopBasedDirective::HelperExprs &OutermostHelper = LoopHelpers[0];
+ auto *OutermostCntVar = cast<DeclRefExpr>(OutermostHelper.Counters.front());
+ SourceLocation OrigVarLoc = OutermostCntVar->getExprLoc();
+ SourceLocation OrigVarLocBegin = OutermostCntVar->getBeginLoc();
+ SourceLocation OrigVarLocEnd = OutermostCntVar->getEndLoc();
+ SourceLocation CondLoc = OutermostHelper.Cond->getExprLoc();
+
+ // Product of trip counts; mirror 'collapse' IV-width selection to avoid
+ // overflow when several counts are multiplied.
+ auto BuildTripCount = [&](unsigned Bits) -> ExprResult {
+ ExprResult Product;
+ for (unsigned I = 0; I < NumLoops; ++I) {
+ ExprResult N = widenIterationCount(Bits, MakeNumIterations(I), SemaRef);
+ if (!N.isUsable())
+ return ExprError();
+ if (I == 0)
+ Product = N;
+ else
+ Product = SemaRef.BuildBinOp(CurScope, CondLoc, BO_Mul, Product.get(),
+ N.get());
+ if (!Product.isUsable())
+ return ExprError();
+ }
+ return Product;
+ };
+
+ bool AllCountsLessThan32Bits = true;
+ for (unsigned I = 0; I < NumLoops; ++I)
+ AllCountsLessThan32Bits &=
+ Context.getTypeSize(LoopHelpers[I].NumIterations->getType()) < 32;
+
+ ExprResult TripCount32 = BuildTripCount(/*Bits=*/32);
+ ExprResult TripCount64 = BuildTripCount(/*Bits=*/64);
----------------
Meinersbur wrote:
Don't create both expressions if you are going to use just one of them.
https://github.com/llvm/llvm-project/pull/206977
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits