[clang] [llvm] [openmp] [Clang][OpenMP] Add reverse directive (PR #92916)
Alexey Bataev via cfe-commits
cfe-commits at lists.llvm.org
Wed Jul 17 04:47:49 PDT 2024
================
@@ -15749,6 +15757,186 @@ StmtResult SemaOpenMP::ActOnOpenMPUnrollDirective(ArrayRef<OMPClause *> Clauses,
buildPreInits(Context, PreInits));
}
+StmtResult SemaOpenMP::ActOnOpenMPReverseDirective(Stmt *AStmt,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ ASTContext &Context = getASTContext();
+ Scope *CurScope = SemaRef.getCurScope();
+
+ // Empty statement should only be possible if there already was an error.
+ if (!AStmt)
+ return StmtError();
+
+ constexpr unsigned NumLoops = 1;
+ Stmt *Body = nullptr;
+ SmallVector<OMPLoopBasedDirective::HelperExprs, NumLoops> LoopHelpers(
+ NumLoops);
+ SmallVector<SmallVector<Stmt *, 0>, NumLoops + 1> OriginalInits;
+ if (!checkTransformableLoopNest(OMPD_reverse, AStmt, NumLoops, LoopHelpers,
+ Body, OriginalInits))
+ return StmtError();
+
+ // Delay applying the transformation to when template is completely
+ // instantiated.
+ if (SemaRef.CurContext->isDependentContext())
+ return OMPReverseDirective::Create(Context, StartLoc, EndLoc, AStmt,
+ nullptr, nullptr);
+
+ assert(LoopHelpers.size() == NumLoops &&
+ "Expecting a single-dimensional loop iteration space");
+ assert(OriginalInits.size() == NumLoops &&
+ "Expecting a single-dimensional loop iteration space");
+ OMPLoopBasedDirective::HelperExprs &LoopHelper = LoopHelpers.front();
+
+ // Find the loop statement.
+ Stmt *LoopStmt = nullptr;
+ collectLoopStmts(AStmt, {LoopStmt});
+
+ // Determine the PreInit declarations.
+ SmallVector<Stmt *> PreInits;
+ addLoopPreInits(Context, LoopHelper, LoopStmt, OriginalInits[0], PreInits);
+
+ auto *IterationVarRef = cast<DeclRefExpr>(LoopHelper.IterationVarRef);
+ QualType IVTy = IterationVarRef->getType();
+ uint64_t IVWidth = Context.getTypeSize(IVTy);
+ auto *OrigVar = cast<DeclRefExpr>(LoopHelper.Counters.front());
+
+ // Iteration variable SourceLocations.
+ SourceLocation OrigVarLoc = OrigVar->getExprLoc();
+ SourceLocation OrigVarLocBegin = OrigVar->getBeginLoc();
+ SourceLocation OrigVarLocEnd = OrigVar->getEndLoc();
+
+ // Locations pointing to the transformation.
+ SourceLocation TransformLoc = StartLoc;
+ SourceLocation TransformLocBegin = StartLoc;
+ SourceLocation TransformLocEnd = EndLoc;
+
+ // Internal variable names.
+ std::string OrigVarName = OrigVar->getNameInfo().getAsString();
+ std::string TripCountName = (Twine(".tripcount.") + OrigVarName).str();
+ std::string ForwardIVName = (Twine(".forward.iv.") + OrigVarName).str();
+ std::string ReversedIVName = (Twine(".reversed.iv.") + OrigVarName).str();
+
+ // LoopHelper.Updates will read the logical iteration number from
+ // LoopHelper.IterationVarRef, compute the value of the user loop counter of
+ // that logical iteration from it, then assign it to the user loop counter
+ // variable. We cannot directly use LoopHelper.IterationVarRef as the
+ // induction variable of the generated loop because it may cause an underflow:
+ // \code
+ // for (unsigned i = 0; i < n; ++i)
+ // body(i);
+ // \endcode
+ //
+ // Naive reversal:
+ // \code
+ // for (unsigned i = n-1; i >= 0; --i)
+ // body(i);
+ // \endcode
+ //
+ // Instead, we introduce a new iteration variable representing the logical
+ // iteration counter of the original loop, convert it to the logical iteration
+ // number of the reversed loop, then let LoopHelper.Updates compute the user's
+ // loop iteration variable from it.
+ // \code
+ // for (auto .forward.iv = 0; .forward.iv < n; ++.forward.iv) {
+ // auto .reversed.iv = n - .forward.iv - 1;
+ // i = (.reversed.iv + 0) * 1; // LoopHelper.Updates
+ // body(i); // Body
+ // }
+ // \endcode
+
+ // Subexpressions with more than one use. One of the constraints of an AST is
+ // that every node object must appear at most once, hence we define a lambda
+ // that creates a new AST node at every use.
+ CaptureVars CopyTransformer(SemaRef);
+ auto MakeNumIterations = [&CopyTransformer, &LoopHelper]() -> Expr * {
+ return AssertSuccess(
+ CopyTransformer.TransformExpr(LoopHelper.NumIterations));
+ };
+
+ // Create the iteration variable for the forward loop (from 0 to n-1).
+ VarDecl *ForwardIVDecl =
+ buildVarDecl(SemaRef, {}, IVTy, ForwardIVName, nullptr, OrigVar);
+ auto MakeForwardRef = [&SemaRef = this->SemaRef, ForwardIVDecl, IVTy,
+ OrigVarLoc]() {
+ return buildDeclRefExpr(SemaRef, ForwardIVDecl, IVTy, OrigVarLoc);
+ };
+
+ // Iteration variable for the reversed induction variable (from n-1 downto 0):
+ // Reuse the iteration variable created by checkOpenMPLoop.
+ auto *ReversedIVDecl = cast<VarDecl>(IterationVarRef->getDecl());
+ ReversedIVDecl->setDeclName(
+ &SemaRef.PP.getIdentifierTable().get(ReversedIVName));
+
+ // For init-statement:
+ // \code
+ // auto .forward.iv = 0
+ // \endcode
+ IntegerLiteral *Zero =
+ IntegerLiteral::Create(Context, llvm::APInt::getZero(IVWidth),
+ ForwardIVDecl->getType(), OrigVarLoc);
+ SemaRef.AddInitializerToDecl(ForwardIVDecl, Zero, /*DirectInit=*/false);
+ StmtResult Init = new (Context)
+ DeclStmt(DeclGroupRef(ForwardIVDecl), OrigVarLocBegin, OrigVarLocEnd);
+ if (!Init.isUsable())
+ return StmtError();
+
+ // Forward iv cond-expression:
+ // \code
+ // .forward.iv < NumIterations
+ // \endcode
+ ExprResult Cond =
+ SemaRef.BuildBinOp(CurScope, LoopHelper.Cond->getExprLoc(), BO_LT,
+ MakeForwardRef(), MakeNumIterations());
+ if (!Cond.isUsable())
+ return StmtError();
+
+ // Forward incr-statement: ++.forward.iv
+ ExprResult Incr = SemaRef.BuildUnaryOp(CurScope, LoopHelper.Inc->getExprLoc(),
+ UO_PreInc, MakeForwardRef());
+ if (!Incr.isUsable())
+ return StmtError();
+
+ // Reverse the forward-iv: auto .reversed.iv = MakeNumIterations() - 1 -
+ // .forward.iv
+ IntegerLiteral *One = IntegerLiteral::Create(Context, llvm::APInt(IVWidth, 1),
+ IVTy, TransformLoc);
+ ExprResult Minus = SemaRef.BuildBinOp(CurScope, TransformLoc, BO_Sub,
+ MakeNumIterations(), One);
+ if (!Minus.isUsable())
+ return StmtError();
+ Minus = SemaRef.BuildBinOp(CurScope, TransformLoc, BO_Sub, Minus.get(),
+ MakeForwardRef());
+ if (!Minus.isUsable())
+ return StmtError();
+ StmtResult InitReversed = new (Context) DeclStmt(
+ DeclGroupRef(ReversedIVDecl), TransformLocBegin, TransformLocEnd);
+ if (!InitReversed.isUsable())
+ return StmtError();
+ SemaRef.AddInitializerToDecl(ReversedIVDecl, Minus.get(),
+ /*DirectInit=*/false);
+
+ // The new loop body.
+ SmallVector<Stmt *> BodyStmts;
+ BodyStmts.push_back(InitReversed.get());
+ llvm::append_range(BodyStmts, LoopHelper.Updates);
+ if (auto *CXXRangeFor = dyn_cast<CXXForRangeStmt>(LoopStmt))
+ BodyStmts.push_back(CXXRangeFor->getLoopVarStmt());
+ BodyStmts.push_back(Body);
----------------
alexey-bataev wrote:
No, it is not not on a stack. It is on stack only in some preallocated (small) cases, otherwise it is dynamically allocated
https://github.com/llvm/llvm-project/pull/92916
More information about the cfe-commits
mailing list