================ @@ -14477,6 +14484,279 @@ StmtResult SemaOpenMP::ActOnOpenMPTileDirective(ArrayRef<OMPClause *> Clauses, buildPreInits(Context, PreInits)); } +StmtResult SemaOpenMP::ActOnOpenMPStripeDirective(ArrayRef<OMPClause *> Clauses, + Stmt *AStmt, + SourceLocation StartLoc, + SourceLocation EndLoc) { + ASTContext &Context = getASTContext(); + Scope *CurScope = SemaRef.getCurScope(); + + const auto *SizesClause = + OMPExecutableDirective::getSingleClause<OMPSizesClause>(Clauses); + if (!SizesClause || + llvm::any_of(SizesClause->getSizesRefs(), [](Expr *E) { return !E; })) + return StmtError(); + unsigned NumLoops = SizesClause->getNumSizes(); + + // Empty statement should only be possible if there already was an error. + if (!AStmt) + return StmtError(); + + // Verify and diagnose loop nest. + SmallVector<OMPLoopBasedDirective::HelperExprs, 4> LoopHelpers(NumLoops); + Stmt *Body = nullptr; + SmallVector<SmallVector<Stmt *, 0>, 4> OriginalInits; + if (!checkTransformableLoopNest(OMPD_stripe, AStmt, NumLoops, LoopHelpers, + Body, OriginalInits)) + return StmtError(); + + // Delay tiling to when template is completely instantiated. + if (SemaRef.CurContext->isDependentContext()) + return OMPStripeDirective::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"); + + // Collect all affected loop statements. + SmallVector<Stmt *> LoopStmts(NumLoops, nullptr); + collectLoopStmts(AStmt, LoopStmts); + + SmallVector<Stmt *, 4> PreInits; + CaptureVars CopyTransformer(SemaRef); + + // Create iteration variables for the generated loops. + SmallVector<VarDecl *, 4> FloorIndVars; + SmallVector<VarDecl *, 4> StripeIndVars; + FloorIndVars.resize(NumLoops); + StripeIndVars.resize(NumLoops); + for (unsigned I = 0; I < NumLoops; ++I) { + OMPLoopBasedDirective::HelperExprs &LoopHelper = LoopHelpers[I]; + + assert(LoopHelper.Counters.size() == 1 && + "Expect single-dimensional loop iteration space"); + auto *OrigCntVar = cast<DeclRefExpr>(LoopHelper.Counters.front()); + std::string OrigVarName = OrigCntVar->getNameInfo().getAsString(); + DeclRefExpr *IterVarRef = cast<DeclRefExpr>(LoopHelper.IterationVarRef); + QualType CntTy = IterVarRef->getType(); + + // Iteration variable for the floor (i.e. outer) loop. + { + std::string FloorCntName = + (Twine(".floor_") + llvm::utostr(I) + ".iv." + OrigVarName).str(); + VarDecl *FloorCntDecl = + buildVarDecl(SemaRef, {}, CntTy, FloorCntName, nullptr, OrigCntVar); + FloorIndVars[I] = FloorCntDecl; + } + + // Iteration variable for the stripe (i.e. inner) loop. + { + std::string StripeCntName = + (Twine(".stripe_") + llvm::utostr(I) + ".iv." + OrigVarName).str(); + + // Reuse the iteration variable created by checkOpenMPLoop. It is also + // used by the expressions to derive the original iteration variable's + // value from the logical iteration number. + auto *StripeCntDecl = cast<VarDecl>(IterVarRef->getDecl()); + StripeCntDecl->setDeclName( + &SemaRef.PP.getIdentifierTable().get(StripeCntName)); + StripeIndVars[I] = StripeCntDecl; + } + + addLoopPreInits(Context, LoopHelper, LoopStmts[I], OriginalInits[I], + PreInits); + } + + // Once the original iteration values are set, append the innermost body. + Stmt *Inner = Body; + + auto MakeDimStripeSize = [&SemaRef = this->SemaRef, &CopyTransformer, + &Context, SizesClause, CurScope](int I) -> Expr * { + Expr *DimStripeSizeExpr = SizesClause->getSizesRefs()[I]; + if (isa<ConstantExpr>(DimStripeSizeExpr)) + return AssertSuccess(CopyTransformer.TransformExpr(DimStripeSizeExpr)); + + // When the stripe size is not a constant but a variable, it is possible to + // pass non-positive numbers. For instance: + // \code{c} + // int a = 0; + // #pragma omp stripe sizes(a) + // for (int i = 0; i < 42; ++i) + // body(i); + // \endcode + // Although there is no meaningful interpretation of the stripe size, the + // body should still be executed 42 times to avoid surprises. To preserve + // the invariant that every loop iteration is executed exactly once and not + // cause an infinite loop, apply a minimum stripe size of one. + // Build expr: + // \code{c} + // (TS <= 0) ? 1 : TS + // \endcode + QualType DimTy = DimStripeSizeExpr->getType(); + uint64_t DimWidth = Context.getTypeSize(DimTy); + IntegerLiteral *Zero = IntegerLiteral::Create( + Context, llvm::APInt::getZero(DimWidth), DimTy, {}); + IntegerLiteral *One = + IntegerLiteral::Create(Context, llvm::APInt(DimWidth, 1), DimTy, {}); + Expr *Cond = AssertSuccess(SemaRef.BuildBinOp( + CurScope, {}, BO_LE, + AssertSuccess(CopyTransformer.TransformExpr(DimStripeSizeExpr)), Zero)); + Expr *MinOne = new (Context) ConditionalOperator( + Cond, {}, One, {}, + AssertSuccess(CopyTransformer.TransformExpr(DimStripeSizeExpr)), DimTy, + VK_PRValue, OK_Ordinary); + return MinOne; + }; + + // Create stripe loops from the inside to the outside. + for (int I = NumLoops - 1; I >= 0; --I) { + OMPLoopBasedDirective::HelperExprs &LoopHelper = LoopHelpers[I]; + Expr *NumIterations = LoopHelper.NumIterations; + auto *OrigCntVar = cast<DeclRefExpr>(LoopHelper.Counters[0]); + QualType IVTy = NumIterations->getType(); + Stmt *LoopStmt = LoopStmts[I]; + + // Commonly used variables. One of the constraints of an AST is that every + // node object must appear at most once, hence we define lamdas that create + // a new AST node at every use. + auto MakeStripeIVRef = [&SemaRef = this->SemaRef, &StripeIndVars, I, IVTy, + OrigCntVar]() { ---------------- alexey-bataev wrote:
```suggestion auto MakeStripeIVRef = [&]() { ``` https://github.com/llvm/llvm-project/pull/119891 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits