================ @@ -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:
```suggestion SmallVector<Stmt *> BodyStmts(LoopHelper.Updates.size() + 2 + (isa<CXXForRangeStmt>(LoopStmt) ? 1 : 0)); BodyStmts.front() = InitReversed.get(); llvm::copy(LoopHelper.Updates, std::next(BodyStmts.begin()); if (auto *CXXRangeFor = dyn_cast<CXXForRangeStmt>(LoopStmt)) BodyStmts[LoopHelper.Updates.size() + 1] = CXXRangeFor->getLoopVarStmt(); BodyStmts.back() = Body; ``` https://github.com/llvm/llvm-project/pull/92916 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits