155 lines · cpp
1//===-- lib/Semantics/canonicalize-do.cpp ---------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "canonicalize-do.h"10#include "flang/Parser/openmp-utils.h"11#include "flang/Parser/parse-tree-visitor.h"12#include "flang/Parser/tools.h"13 14namespace Fortran::parser {15 16class CanonicalizationOfDoLoops {17 struct LabelInfo {18 Block::iterator iter;19 Label label;20 };21 22public:23 template <typename T> bool Pre(T &) { return true; }24 template <typename T> void Post(T &) {}25 void Post(Block &block) {26 std::vector<LabelInfo> stack;27 for (auto i{block.begin()}, end{block.end()}; i != end; ++i) {28 if (auto *executableConstruct{std::get_if<ExecutableConstruct>(&i->u)}) {29 common::visit(30 common::visitors{31 [](auto &) {},32 // Labels on end-stmt of constructs are accepted by f18 as an33 // extension.34 [&](common::Indirection<AssociateConstruct> &associate) {35 CanonicalizeIfMatch(block, stack, i,36 std::get<Statement<EndAssociateStmt>>(37 associate.value().t));38 },39 [&](common::Indirection<BlockConstruct> &blockConstruct) {40 CanonicalizeIfMatch(block, stack, i,41 std::get<Statement<EndBlockStmt>>(42 blockConstruct.value().t));43 },44 [&](common::Indirection<ChangeTeamConstruct> &changeTeam) {45 CanonicalizeIfMatch(block, stack, i,46 std::get<Statement<EndChangeTeamStmt>>(47 changeTeam.value().t));48 },49 [&](common::Indirection<CriticalConstruct> &critical) {50 CanonicalizeIfMatch(block, stack, i,51 std::get<Statement<EndCriticalStmt>>(critical.value().t));52 },53 [&](common::Indirection<DoConstruct> &doConstruct) {54 CanonicalizeIfMatch(block, stack, i,55 std::get<Statement<EndDoStmt>>(doConstruct.value().t));56 },57 [&](common::Indirection<IfConstruct> &ifConstruct) {58 CanonicalizeIfMatch(block, stack, i,59 std::get<Statement<EndIfStmt>>(ifConstruct.value().t));60 },61 [&](common::Indirection<CaseConstruct> &caseConstruct) {62 CanonicalizeIfMatch(block, stack, i,63 std::get<Statement<EndSelectStmt>>(64 caseConstruct.value().t));65 },66 [&](common::Indirection<SelectRankConstruct> &selectRank) {67 CanonicalizeIfMatch(block, stack, i,68 std::get<Statement<EndSelectStmt>>(selectRank.value().t));69 },70 [&](common::Indirection<SelectTypeConstruct> &selectType) {71 CanonicalizeIfMatch(block, stack, i,72 std::get<Statement<EndSelectStmt>>(selectType.value().t));73 },74 [&](common::Indirection<ForallConstruct> &forall) {75 CanonicalizeIfMatch(block, stack, i,76 std::get<Statement<EndForallStmt>>(forall.value().t));77 },78 [&](common::Indirection<WhereConstruct> &where) {79 CanonicalizeIfMatch(block, stack, i,80 std::get<Statement<EndWhereStmt>>(where.value().t));81 },82 [&](Statement<common::Indirection<LabelDoStmt>> &labelDoStmt) {83 auto &label{std::get<Label>(labelDoStmt.statement.value().t)};84 stack.push_back(LabelInfo{i, label});85 },86 [&](Statement<common::Indirection<EndDoStmt>> &endDoStmt) {87 CanonicalizeIfMatch(block, stack, i, endDoStmt);88 },89 [&](Statement<ActionStmt> &actionStmt) {90 CanonicalizeIfMatch(block, stack, i, actionStmt);91 },92 [&](common::Indirection<OpenMPConstruct> &construct) {93 // If the body of the OpenMP construct ends with a label,94 // treat the label as ending the construct itself.95 CanonicalizeIfMatch(96 block, stack, i, omp::GetFinalLabel(construct.value()));97 },98 },99 executableConstruct->u);100 }101 }102 }103 104private:105 template <typename T>106 void CanonicalizeIfMatch(Block &originalBlock, std::vector<LabelInfo> &stack,107 Block::iterator &i, Statement<T> &statement) {108 CanonicalizeIfMatch(originalBlock, stack, i, statement.label);109 }110 111 void CanonicalizeIfMatch(Block &originalBlock, std::vector<LabelInfo> &stack,112 Block::iterator &i, std::optional<Label> label) {113 if (!stack.empty() && label && stack.back().label == *label) {114 auto currentLabel{stack.back().label};115 if (Unwrap<EndDoStmt>(*i)) {116 std::get<ExecutableConstruct>(i->u).u = Statement<ActionStmt>{117 std::optional<Label>{currentLabel}, ContinueStmt{}};118 }119 auto next{++i};120 do {121 Block block;122 auto doLoop{stack.back().iter};123 auto originalSource{124 std::get<Statement<common::Indirection<LabelDoStmt>>>(125 std::get<ExecutableConstruct>(doLoop->u).u)126 .source};127 block.splice(block.begin(), originalBlock, ++stack.back().iter, next);128 auto &labelDo{std::get<Statement<common::Indirection<LabelDoStmt>>>(129 std::get<ExecutableConstruct>(doLoop->u).u)};130 auto &loopControl{131 std::get<std::optional<LoopControl>>(labelDo.statement.value().t)};132 Statement<NonLabelDoStmt> nonLabelDoStmt{std::move(labelDo.label),133 NonLabelDoStmt{std::make_tuple(std::optional<Name>{},134 std::optional<Label>{}, std::move(loopControl))}};135 nonLabelDoStmt.source = originalSource;136 std::get<ExecutableConstruct>(doLoop->u).u =137 common::Indirection<DoConstruct>{138 std::make_tuple(std::move(nonLabelDoStmt), std::move(block),139 Statement<EndDoStmt>{std::optional<Label>{},140 EndDoStmt{std::optional<Name>{}}})};141 stack.pop_back();142 } while (!stack.empty() && stack.back().label == currentLabel);143 i = --next;144 }145 }146};147 148bool CanonicalizeDo(Program &program) {149 CanonicalizationOfDoLoops canonicalizationOfDoLoops;150 Walk(program, canonicalizationOfDoLoops);151 return true;152}153 154} // namespace Fortran::parser155