================ @@ -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 = ---------------- alexey-bataev wrote:
```suggestion auto *Zero = ``` 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