diff --git a/flang/include/flang/Lower/PFTBuilder.h b/flang/include/flang/Lower/PFTBuilder.h index c7d28dc1bcbdd1..94684e7d3c7733 100644 --- a/flang/include/flang/Lower/PFTBuilder.h +++ b/flang/include/flang/Lower/PFTBuilder.h @@ -87,8 +87,11 @@ using Constructs = parser::CriticalConstruct, parser::DoConstruct, parser::IfConstruct, parser::SelectRankConstruct, parser::SelectTypeConstruct, parser::WhereConstruct, - parser::ForallConstruct, parser::CompilerDirective, - parser::OpenMPConstruct, parser::OmpEndLoopDirective>; + parser::ForallConstruct>; + +using Directives = + std::tuple; template static constexpr bool isActionStmt{common::HasMember}; @@ -102,6 +105,9 @@ static constexpr bool isConstructStmt{common::HasMember}; template static constexpr bool isConstruct{common::HasMember}; +template +static constexpr bool isDirective{common::HasMember}; + template static constexpr bool isIntermediateConstructStmt{common::HasMember< A, std::tuple using MakeReferenceVariant = typename MakeReferenceVariantHelper::type; using EvaluationTuple = - common::CombineTuples; + common::CombineTuples; /// Hide non-nullable pointers to the parse-tree node. /// Build type std::variant /// from EvaluationTuple type (std::tuple). @@ -197,7 +204,8 @@ struct Evaluation : EvaluationVariant { template Evaluation(const A &a, const ParentVariant &parentVariant) : EvaluationVariant{a}, parentVariant{parentVariant} { - static_assert(pft::isConstruct, "must be a construct"); + static_assert(pft::isConstruct || pft::isDirective, + "must be a construct or directive"); } /// Evaluation classification predicates. @@ -218,10 +226,12 @@ struct Evaluation : EvaluationVariant { return visit(common::visitors{ [](auto &r) { return pft::isConstruct>; }}); } - - /// For a construct with multiway control-flow semantics, return true if this - /// is one of the alternative condition statements of the construct. For - /// example, `ELSE IF` in an `IF` construct. + constexpr bool isDirective() const { + return visit(common::visitors{ + [](auto &r) { return pft::isDirective>; }}); + } + /// Return the predicate: "This is a non-initial, non-terminal construct + /// statement." For an IfConstruct, this is ElseIfStmt and ElseStmt. constexpr bool isIntermediateConstructStmt() const { return visit(common::visitors{[](auto &r) { return pft::isIntermediateConstructStmt>; diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp index 6b846a40c3af44..ca66ed43d3278c 100644 --- a/flang/lib/Lower/Bridge.cpp +++ b/flang/lib/Lower/Bridge.cpp @@ -773,17 +773,16 @@ class FirConverter : public Fortran::lower::AbstractConverter { /// Generate FIR to begin a structured or unstructured increment loop. void genFIRIncrementLoopBegin(IncrementLoopInfo &info) { auto location = toLocation(); - mlir::Type type = info.isStructured() - ? mlir::IndexType::get(builder->getContext()) - : info.loopVariableType; + mlir::Type type = + info.isStructured() ? builder->getIndexType() : info.loopVariableType; auto lowerValue = genFIRLoopIndex(info.lowerExpr, type); auto upperValue = genFIRLoopIndex(info.upperExpr, type); info.stepValue = info.stepExpr.has_value() ? genFIRLoopIndex(*info.stepExpr, type) - : (info.isStructured() - ? builder->create(location, 1) - : builder->createIntegerConstant(info.loopVariableType, 1)); + : info.isStructured() + ? builder->create(location, 1) + : builder->createIntegerConstant(info.loopVariableType, 1); assert(info.stepValue && "step value must be set"); info.loopVariable = createTemp(location, *info.loopVariableSym); @@ -1279,7 +1278,7 @@ class FirConverter : public Fortran::lower::AbstractConverter { auto ty = genType(*sym.symbol); auto load = builder->create( toLocation(), lookupSymbol(*sym.symbol)); - auto idxTy = mlir::IndexType::get(&mlirContext); + auto idxTy = builder->getIndexType(); auto zero = builder->create( toLocation(), idxTy, builder->getIntegerAttr(idxTy, 0)); auto cast = builder->createConvert(toLocation(), ty, zero); @@ -1668,8 +1667,7 @@ class FirConverter : public Fortran::lower::AbstractConverter { if (unstructuredContext) { // When transitioning from unstructured to structured code, // the structured code might be a target that starts a new block. - maybeStartBlock(eval.isConstruct() && eval.lowerAsStructured() && - !eval.evaluationList->empty() + maybeStartBlock(eval.isConstruct() && eval.lowerAsStructured() ? eval.evaluationList->front().block : eval.block); } @@ -1679,7 +1677,7 @@ class FirConverter : public Fortran::lower::AbstractConverter { Fortran::lower::pft::Evaluation *successor{}; if (eval.isActionStmt()) successor = eval.controlSuccessor; - else if (eval.isConstruct() && !eval.evaluationList->empty() && + else if (eval.isConstruct() && eval.evaluationList->back() .lexicalSuccessor->isIntermediateConstructStmt()) successor = eval.constructExit; @@ -2057,7 +2055,7 @@ class FirConverter : public Fortran::lower::AbstractConverter { eval.block = builder->createBlock(&builder->getRegion()); for (size_t i = 0, n = eval.localBlocks.size(); i < n; ++i) eval.localBlocks[i] = builder->createBlock(&builder->getRegion()); - if (eval.isConstruct()) { + if (eval.isConstruct() || eval.isDirective()) { if (eval.lowerAsUnstructured()) { createEmptyBlocks(*eval.evaluationList); } else { diff --git a/flang/lib/Lower/PFTBuilder.cpp b/flang/lib/Lower/PFTBuilder.cpp index 78d8b9dca7a844..aee4eb8c9789ff 100644 --- a/flang/lib/Lower/PFTBuilder.cpp +++ b/flang/lib/Lower/PFTBuilder.cpp @@ -74,8 +74,9 @@ class PFTBuilder { constexpr bool Pre(const A &a) { if constexpr (lower::pft::isFunctionLike) { return enterFunction(a, semanticsContext); - } else if constexpr (lower::pft::isConstruct) { - return enterConstruct(a); + } else if constexpr (lower::pft::isConstruct || + lower::pft::isDirective) { + return enterConstructOrDirective(a); } else if constexpr (UnwrapStmt::isStmt) { using T = typename UnwrapStmt::Type; // Node "a" being visited has one of the following types: @@ -101,8 +102,9 @@ class PFTBuilder { constexpr void Post(const A &) { if constexpr (lower::pft::isFunctionLike) { exitFunction(); - } else if constexpr (lower::pft::isConstruct) { - exitConstruct(); + } else if constexpr (lower::pft::isConstruct || + lower::pft::isDirective) { + exitConstructOrDirective(); } } @@ -201,20 +203,20 @@ class PFTBuilder { /// Initialize a new construct and make it the builder's focus. template - bool enterConstruct(const A &construct) { + bool enterConstructOrDirective(const A &construct) { auto &eval = addEvaluation( lower::pft::Evaluation{construct, parentVariantStack.back()}); eval.evaluationList.reset(new lower::pft::EvaluationList); pushEvaluationList(eval.evaluationList.get()); parentVariantStack.emplace_back(eval); - constructStack.emplace_back(&eval); + constructAndDirectiveStack.emplace_back(&eval); return true; } - void exitConstruct() { + void exitConstructOrDirective() { popEvaluationList(); parentVariantStack.pop_back(); - constructStack.pop_back(); + constructAndDirectiveStack.pop_back(); } /// Reset functionList to an enclosing function's functionList. @@ -269,8 +271,8 @@ class PFTBuilder { lower::pft::Evaluation &addEvaluation(lower::pft::Evaluation &&eval) { assert(functionList && "not in a function"); assert(evaluationListStack.size() > 0); - if (constructStack.size() > 0) { - eval.parentConstruct = constructStack.back(); + if (constructAndDirectiveStack.size() > 0) { + eval.parentConstruct = constructAndDirectiveStack.back(); } evaluationListStack.back()->emplace_back(std::move(eval)); lower::pft::Evaluation *p = &evaluationListStack.back()->back(); @@ -732,7 +734,7 @@ class PFTBuilder { /// functionList points to the internal or module procedure function list /// of a FunctionLikeUnit or a ModuleLikeUnit. It may be null. std::list *functionList{nullptr}; - std::vector constructStack{}; + std::vector constructAndDirectiveStack{}; std::vector doConstructStack{}; /// evaluationListStack is the current nested construct evaluationList state. std::vector evaluationListStack{}; @@ -780,7 +782,7 @@ class PFTDumper { for (lower::pft::Evaluation &eval : evaluationList) { llvm::StringRef name{evaluationName(eval)}; std::string bang{eval.isUnstructured ? "!" : ""}; - if (eval.isConstruct()) { + if (eval.isConstruct() || eval.isDirective()) { outputStream << indentString << "<<" << name << bang << ">>"; if (eval.constructExit) { outputStream << " -> " << eval.constructExit->printIndex;