--- /dev/null
+// Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef FIRST_TERM_STMT
+#define FIRST_TERM_STMT(num)
+#endif
+#ifndef HANDLE_TERM_STMT
+#ifndef HANDLE_STMT
+#define HANDLE_TERM_STMT(num, opcode, Class)
+#else
+#define HANDLE_TERM_STMT(num, opcode, Class) HANDLE_STMT(num, opcode, Class)
+#endif
+#endif
+#ifndef LAST_TERM_STMT
+#define LAST_TERM_STMT(num)
+#endif
+
+#ifndef FIRST_BINARY_STMT
+#define FIRST_BINARY_STMT(num)
+#endif
+#ifndef HANDLE_BINARY_STMT
+#ifndef HANDLE_STMT
+#define HANDLE_BINARY_STMT(num, opcode, instclass)
+#else
+#define HANDLE_BINARY_STMT(num, opcode, Class) HANDLE_STMT(num, opcode, Class)
+#endif
+#endif
+#ifndef LAST_BINARY_STMT
+#define LAST_BINARY_STMT(num)
+#endif
+
+#ifndef FIRST_MEMORY_STMT
+#define FIRST_MEMORY_STMT(num)
+#endif
+#ifndef HANDLE_MEMORY_STMT
+#ifndef HANDLE_STMT
+#define HANDLE_MEMORY_STMT(num, opcode, Class)
+#else
+#define HANDLE_MEMORY_STMT(num, opcode, Class) HANDLE_STMT(num, opcode, Class)
+#endif
+#endif
+#ifndef LAST_MEMORY_STMT
+#define LAST_MEMORY_STMT(num)
+#endif
+
+#ifndef FIRST_CAST_STMT
+#define FIRST_CAST_STMT(num)
+#endif
+#ifndef HANDLE_CAST_STMT
+#ifndef HANDLE_STMT
+#define HANDLE_CAST_STMT(num, opcode, Class)
+#else
+#define HANDLE_CAST_STMT(num, opcode, Class) HANDLE_STMT(num, opcode, Class)
+#endif
+#endif
+#ifndef LAST_CAST_STMT
+#define LAST_CAST_STMT(num)
+#endif
+
+#ifndef FIRST_OTHER_STMT
+#define FIRST_OTHER_STMT(num)
+#endif
+#ifndef HANDLE_LAST_OTHER_STMT
+#ifndef HANDLE_LAST_STMT
+#ifndef HANDLE_OTHER_STMT
+#ifndef HANDLE_STMT
+#define HANDLE_LAST_OTHER_STMT(num, opcode, Class)
+#else
+#define HANDLE_LAST_OTHER_STMT(num, opcode, Class) \
+ HANDLE_STMT(num, opcode, Class)
+#endif
+#else
+#define HANDLE_LAST_OTHER_STMT(num, opcode, Class) \
+ HANDLE_OTHER_STMT(num, opcode, Class)
+#endif
+#else
+#define HANDLE_LAST_OTHER_STMT(num, opcode, Class) \
+ HANDLE_LAST_STMT(num, opcode, Class)
+#endif
+#endif
+#ifndef HANDLE_OTHER_STMT
+#ifndef HANDLE_STMT
+#define HANDLE_OTHER_STMT(num, opcode, Class)
+#else
+#define HANDLE_OTHER_STMT(num, opcode, Class) HANDLE_STMT(num, opcode, Class)
+#endif
+#endif
+#ifndef LAST_OTHER_STMT
+#define LAST_OTHER_STMT(num)
+#endif
+
+// Terminator Instructions - These instructions are used to terminate a basic
+// block of the program. Every basic block must end with one of these
+// instructions for it to be a well formed basic block.
+FIRST_TERM_STMT(1)
+HANDLE_TERM_STMT(1, Ret, ReturnStmt)
+HANDLE_TERM_STMT(2, Br, BranchStmt)
+HANDLE_TERM_STMT(3, Switch, SwitchStmt)
+HANDLE_TERM_STMT(4, SwitchCase, SwitchCaseStmt)
+HANDLE_TERM_STMT(5, SwitchType, SwitchTypeStmt)
+HANDLE_TERM_STMT(6, SwitchRank, SwitchRankStmt)
+HANDLE_TERM_STMT(7, IndirectBr, IndirectBrStmt)
+HANDLE_TERM_STMT(8, Unreachable, UnreachableStmt)
+LAST_TERM_STMT(8)
+
+// Standard actions - These instructions capture computations as
+// evalute::expressions
+FIRST_BINARY_STMT(9)
+HANDLE_BINARY_STMT(9, Assign, AssignmentStmt)
+HANDLE_BINARY_STMT(10, PtrAssign, PointerAssignStmt)
+HANDLE_BINARY_STMT(11, LblAssign, LabelAssignStmt)
+HANDLE_BINARY_STMT(12, Expr, ExprStmt)
+LAST_BINARY_STMT(12)
+
+// Memory operators - These instructions capture ALLOCATE and DEALLOCATE
+// Fortran statements
+FIRST_MEMORY_STMT(13)
+HANDLE_MEMORY_STMT(13, Alloc, AllocateStmt)
+HANDLE_MEMORY_STMT(14, Dealloc, DeallocateStmt)
+HANDLE_MEMORY_STMT(15, AllocLocal, AllocLocalInsn)
+HANDLE_MEMORY_STMT(16, Load, LoadInsn)
+HANDLE_MEMORY_STMT(17, Store, StoreInsn)
+HANDLE_MEMORY_STMT(18, Disassociate, DisassociateStmt)
+LAST_MEMORY_STMT(18)
+
+// Other operators - These are operations that don't fit the above categories
+FIRST_OTHER_STMT(19)
+HANDLE_OTHER_STMT(19, Call, CallStmt)
+HANDLE_OTHER_STMT(20, RTCall, RuntimeStmt)
+HANDLE_OTHER_STMT(21, IORTCall, IORuntimeStmt)
+HANDLE_OTHER_STMT(22, ScopeEnt, ScopeEnterStmt)
+HANDLE_OTHER_STMT(23, ScopeExt, ScopeExitStmt)
+HANDLE_LAST_OTHER_STMT(24, PHI, PHIStmt)
+LAST_OTHER_STMT(24)
+
+#undef FIRST_TERM_STMT
+#undef HANDLE_TERM_STMT
+#undef LAST_TERM_STMT
+
+#undef FIRST_BINARY_STMT
+#undef HANDLE_BINARY_STMT
+#undef LAST_BINARY_STMT
+
+#undef FIRST_MEMORY_STMT
+#undef HANDLE_MEMORY_STMT
+#undef LAST_MEMORY_STMT
+
+#undef FIRST_CAST_STMT
+#undef HANDLE_CAST_STMT
+#undef LAST_CAST_STMT
+
+#undef FIRST_OTHER_STMT
+#undef HANDLE_OTHER_STMT
+#undef HANDLE_LAST_OTHER_STMT
+#undef HANDLE_LAST_STMT
+#undef LAST_OTHER_STMT
+
+#ifdef HANDLE_STMT
+#undef HANDLE_STMT
+#endif
--- /dev/null
+// Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "stmt.h"
+
+namespace Fortran::IntermediateRepresentation {
+
+static std::string dump(const Expression *expression) {
+ if (expression) {
+ std::stringstream stringStream;
+ expression->v.AsFortran(stringStream);
+ return stringStream.str();
+ }
+ return "<null-expr>"s;
+}
+
+static std::string dump(const Variable *variable) {
+#if 0
+ if (auto *var{std::get_if<const semantics::Symbol *>(&variable->u)}) {
+ return (*var)->name().ToString();
+ }
+ return "<var>"s;
+#endif
+ return (*variable)->name().ToString();
+}
+
+static std::string dump(PathVariable *pathVariable) {
+ if (pathVariable) {
+ return std::visit(
+ common::visitors{
+ [](const common::Indirection<parser::Designator> &designator) {
+ return std::visit(
+ common::visitors{
+ [](const parser::ObjectName &objectName) {
+ return objectName.symbol->name().ToString();
+ },
+ [](const parser::DataRef &dataRef) {
+ return std::visit(
+ common::visitors{
+ [](const parser::Name &name) {
+ return name.symbol->name().ToString();
+ },
+ [](const common::Indirection<
+ parser::StructureComponent> &) {
+ return "<structure-component>"s;
+ },
+ [](const common::Indirection<
+ parser::ArrayElement> &) {
+ return "<array-element>"s;
+ },
+ [](const common::Indirection<
+ parser::CoindexedNamedObject> &) {
+ return "<coindexed-named-object>"s;
+ },
+ },
+ dataRef.u);
+ },
+ [](const parser::Substring &substring) {
+ return "<substring>"s;
+ },
+ },
+ designator->u);
+ },
+ [](const common::Indirection<parser::FunctionReference>
+ &functionReference) { return "<function-reference>"s; },
+ },
+ pathVariable->u);
+ }
+ return "<emty>"s;
+}
+
+std::string Evaluation::dump() const {
+ return std::visit(common::visitors{
+ [](Expression *expression) {
+ return IntermediateRepresentation::dump(expression);
+ },
+ [](Variable *variable) {
+ return IntermediateRepresentation::dump(variable);
+ },
+ [](PathVariable *pathVariable) {
+ return IntermediateRepresentation::dump(pathVariable);
+ },
+ [](const semantics::Symbol *symbol) {
+ return symbol->name().ToString();
+ },
+ },
+ u);
+}
+
+ReturnStmt::ReturnStmt(Expression *expression) : returnValue_{expression} {}
+
+BranchStmt::BranchStmt(
+ Expression *condition, BasicBlock *trueBlock, BasicBlock *falseBlock)
+ : condition_{condition} {
+ succs_[TrueIndex] = trueBlock;
+ succs_[FalseIndex] = falseBlock;
+}
+
+template<typename L>
+static std::list<BasicBlock *> SuccBlocks(const L &valueSuccPairList) {
+ std::list<BasicBlock *> result;
+ for (auto &p : valueSuccPairList) {
+ result.push_back(p.second);
+ }
+ return result;
+}
+
+SwitchStmt::SwitchStmt(const Evaluation &condition, BasicBlock *defaultBlock,
+ const ValueSuccPairListType &args)
+ : condition_{condition} {
+ valueSuccPairs_.push_back({nullptr, defaultBlock});
+ valueSuccPairs_.insert(valueSuccPairs_.end(), args.begin(), args.end());
+}
+std::list<BasicBlock *> SwitchStmt::succ_blocks() const {
+ return SuccBlocks(valueSuccPairs_);
+}
+
+SwitchCaseStmt::SwitchCaseStmt(const Evaluation &condition,
+ BasicBlock *defaultBlock, const ValueSuccPairListType &args)
+ : condition_{condition} {
+ valueSuccPairs_.push_back({SwitchCaseStmt::Default{}, defaultBlock});
+ valueSuccPairs_.insert(valueSuccPairs_.end(), args.begin(), args.end());
+}
+std::list<BasicBlock *> SwitchCaseStmt::succ_blocks() const {
+ return SuccBlocks(valueSuccPairs_);
+}
+
+SwitchTypeStmt::SwitchTypeStmt(const Evaluation &condition,
+ BasicBlock *defaultBlock, const ValueSuccPairListType &args)
+ : condition_{condition} {
+ valueSuccPairs_.push_back({SwitchTypeStmt::Default{}, defaultBlock});
+ valueSuccPairs_.insert(valueSuccPairs_.end(), args.begin(), args.end());
+}
+std::list<BasicBlock *> SwitchTypeStmt::succ_blocks() const {
+ return SuccBlocks(valueSuccPairs_);
+}
+
+SwitchRankStmt ::SwitchRankStmt(const Evaluation &condition,
+ BasicBlock *defaultBlock, const ValueSuccPairListType &args)
+ : condition_{condition} {
+ valueSuccPairs_.push_back({SwitchRankStmt::Default{}, defaultBlock});
+ valueSuccPairs_.insert(valueSuccPairs_.end(), args.begin(), args.end());
+}
+std::list<BasicBlock *> SwitchRankStmt::succ_blocks() const {
+ return SuccBlocks(valueSuccPairs_);
+}
+
+std::string Statement::dump() const {
+ return std::visit(
+ common::visitors{
+ [](const ReturnStmt &) { return "return"s; },
+ [](const BranchStmt &branchStatement) {
+ if (branchStatement.hasCondition()) {
+ return "branch ("s +
+ IntermediateRepresentation::dump(branchStatement.getCond()) +
+ ") "s +
+ std::to_string(reinterpret_cast<std::intptr_t>(
+ branchStatement.getTrueSucc())) +
+ " "s +
+ std::to_string(reinterpret_cast<std::intptr_t>(
+ branchStatement.getFalseSucc()));
+ }
+ return "goto "s +
+ std::to_string(reinterpret_cast<std::intptr_t>(
+ branchStatement.getTrueSucc()));
+ },
+ [](const SwitchStmt &switchStatement) {
+ return "switch("s + switchStatement.getCond().dump() + ")"s;
+ },
+ [](const IndirectBrStmt &) { return "ibranch"s; },
+ [](const UnreachableStmt &) { return "unreachable"s; },
+ [](const AllocateStmt &) { return "alloc"s; },
+ [](const DeallocateStmt &) { return "dealloc"s; },
+ [](const AssignmentStmt &assignmentStatement) {
+ auto computedValue{IntermediateRepresentation::dump(
+ assignmentStatement.GetRightHandSide())};
+ auto address{IntermediateRepresentation::dump(
+ assignmentStatement.GetLeftHandSide())};
+ return "assign ("s + computedValue + ") to "s + address;
+ },
+ [](const PointerAssignStmt &pointerAssignmentStatement) {
+ auto computedAddress{IntermediateRepresentation::dump(
+ pointerAssignmentStatement.GetRightHandSide())};
+ auto address{IntermediateRepresentation::dump(
+ pointerAssignmentStatement.GetLeftHandSide())};
+ return "assign &("s + computedAddress + ") to "s + address;
+ },
+ [](const LabelAssignStmt &) { return "lblassn"s; },
+ [](const DisassociateStmt &) { return "NULLIFY"s; },
+ [](const ExprStmt &expressionStatement) {
+ return std::visit(
+ common::visitors{
+ [](const parser::AssociateStmt *) {
+ return "<eavl-associate>"s;
+ },
+ [](const parser::ChangeTeamStmt *) {
+ return "<eval-change-team>"s;
+ },
+ [](const parser::NonLabelDoStmt *) { return "<eval-do>"s; },
+ [](const parser::SelectTypeStmt *) {
+ return "<eval-select-type>"s;
+ },
+ [](const parser::ForallConstructStmt *) {
+ return "<eval-forall>"s;
+ },
+ [](const parser::SelectRankStmt *) {
+ return "<eval-select-rank>"s;
+ },
+ [](const evaluate::GenericExprWrapper
+ *genericExpressionWrapper) {
+ return IntermediateRepresentation::dump(
+ genericExpressionWrapper);
+ },
+ },
+ expressionStatement.u);
+ },
+ [](const ScopeEnterStmt &) { return "scopeenter"s; },
+ [](const ScopeExitStmt &) { return "scopeexit"s; },
+ [](const PHIStmt &) { return "PHI"s; },
+ [](const CallStmt &) { return "call"s; },
+ [](const RuntimeStmt &) { return "runtime-call()"s; },
+ [](const IORuntimeStmt &) { return "io-call()"s; },
+ [](const SwitchCaseStmt &switchCaseStmt) {
+ return "switch-case("s + switchCaseStmt.getCond().dump() + ")"s;
+ },
+ [](const SwitchTypeStmt &switchTypeStmt) {
+ return "switch-type("s + switchTypeStmt.getCond().dump() + ")"s;
+ },
+ [](const SwitchRankStmt &switchRankStmt) {
+ return "switch-rank("s + switchRankStmt.getCond().dump() + ")"s;
+ },
+ [](const AllocLocalInsn &) { return "alloca"s; },
+ [](const LoadInsn &) { return "load"s; },
+ [](const StoreInsn &) { return "store"s; },
+ },
+ u);
+}
+
+}
--- /dev/null
+// Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef FORTRAN_INTERMEDIATEREPRESENTATION_STATEMENTS_H_
+#define FORTRAN_INTERMEDIATEREPRESENTATION_STATEMENTS_H_
+
+#include "common.h"
+#include "mixin.h"
+#include <initializer_list>
+#include <ostream>
+
+namespace Fortran::IntermediateRepresentation {
+
+#define HANDLE_STMT(num, opcode, name) struct name;
+#include "statement.def"
+
+struct Statement;
+
+CLASS_TRAIT(StatementTrait)
+CLASS_TRAIT(TerminatorTrait)
+CLASS_TRAIT(ActionTrait)
+
+struct Evaluation
+ : public SumTypeCopyMixin<std::variant<Expression *, Variable *,
+ PathVariable *, const semantics::Symbol *>> {
+ SUM_TYPE_COPY_MIXIN(Evaluation)
+ Evaluation(PathVariable *pv) : SumTypeCopyMixin{pv} {
+ if (const auto *designator{
+ std::get_if<common::Indirection<parser::Designator>>(&pv->u)}) {
+ if (const auto *obj{std::get_if<parser::ObjectName>(&(*designator)->u)}) {
+ u = obj->symbol;
+ }
+ }
+ }
+ template<typename A> Evaluation(A *a) : SumTypeCopyMixin{a} {}
+ std::string dump() const;
+};
+
+struct Stmt_impl {
+ using StatementTrait = std::true_type;
+};
+
+struct TerminatorStmt_impl : public Stmt_impl {
+ virtual std::list<BasicBlock *> succ_blocks() const { return {}; }
+ using TerminatorTrait = std::true_type;
+};
+
+struct ReturnStmt : public TerminatorStmt_impl {
+ static ReturnStmt Create() { return ReturnStmt{nullptr}; }
+ static ReturnStmt Create(Expression *expression) {
+ return ReturnStmt{expression};
+ }
+
+private:
+ Expression *returnValue_;
+ explicit ReturnStmt(Expression *);
+};
+
+struct BranchStmt : public TerminatorStmt_impl {
+ static BranchStmt Create(
+ Expression *condition, BasicBlock *trueBlock, BasicBlock *falseBlock) {
+ return BranchStmt{condition, trueBlock, falseBlock};
+ }
+ static BranchStmt Create(BasicBlock *succ) {
+ return BranchStmt{nullptr, succ, nullptr};
+ }
+ bool hasCondition() const { return condition_ != nullptr; }
+ Expression *getCond() const { return condition_; }
+ std::list<BasicBlock *> succ_blocks() const override {
+ if (hasCondition()) {
+ return {succs_[TrueIndex], succs_[FalseIndex]};
+ }
+ return {succs_[TrueIndex]};
+ }
+ BasicBlock *getTrueSucc() const { return succs_[TrueIndex]; }
+ BasicBlock *getFalseSucc() const { return succs_[FalseIndex]; }
+
+private:
+ explicit BranchStmt(
+ Expression *condition, BasicBlock *trueBlock, BasicBlock *falseBlock);
+ static constexpr unsigned TrueIndex{0u};
+ static constexpr unsigned FalseIndex{1u};
+ Expression *condition_;
+ BasicBlock *succs_[2];
+};
+
+/// Switch on an expression into a set of constant values
+struct SwitchStmt : public TerminatorStmt_impl {
+ using ValueType = Expression *;
+ using ValueSuccPairType = std::pair<ValueType, BasicBlock *>;
+ using ValueSuccPairListType = std::vector<ValueSuccPairType>;
+ static SwitchStmt Create(const Evaluation &switchEval,
+ BasicBlock *defaultBlock, const ValueSuccPairListType &args) {
+ return SwitchStmt{switchEval, defaultBlock, args};
+ }
+ BasicBlock *defaultSucc() const { return valueSuccPairs_[0].second; }
+ std::list<BasicBlock *> succ_blocks() const override;
+ const Evaluation &getCond() const { return condition_; }
+
+private:
+ explicit SwitchStmt(const Evaluation &condition, BasicBlock *defaultBlock,
+ const ValueSuccPairListType &args);
+ Evaluation condition_;
+ ValueSuccPairListType valueSuccPairs_;
+};
+
+/// Switch on an expression into a set of value (open or closed) ranges
+struct SwitchCaseStmt : public TerminatorStmt_impl {
+ struct Default {};
+ struct Exactly { // selector == v
+ Expression *v;
+ };
+ struct InclusiveAbove { // v <= selector
+ Expression *v;
+ };
+ struct InclusiveBelow { // selector <= v
+ Expression *v;
+ };
+ struct InclusiveRange { // lower <= selector <= upper
+ Expression *lower;
+ Expression *upper;
+ };
+ using RangeAlternative =
+ std::variant<Exactly, InclusiveAbove, InclusiveBelow, InclusiveRange>;
+ using ValueType = std::variant<Default, std::vector<RangeAlternative>>;
+ using ValueSuccPairType = std::pair<ValueType, BasicBlock *>;
+ using ValueSuccPairListType = std::vector<ValueSuccPairType>;
+
+ static SwitchCaseStmt Create(const Evaluation &switchEval,
+ BasicBlock *defaultBlock, const ValueSuccPairListType &args) {
+ return SwitchCaseStmt{switchEval, defaultBlock, args};
+ }
+ BasicBlock *defaultSucc() const { return valueSuccPairs_[0].second; }
+ std::list<BasicBlock *> succ_blocks() const override;
+ const Evaluation &getCond() const { return condition_; }
+
+private:
+ explicit SwitchCaseStmt(const Evaluation &condition, BasicBlock *defaultBlock,
+ const ValueSuccPairListType &args);
+ Evaluation condition_;
+ ValueSuccPairListType valueSuccPairs_;
+};
+
+using Type = const semantics::DeclTypeSpec *; // FIXME
+/// Switch on the TYPE of the selector into a set of TYPES, etc.
+struct SwitchTypeStmt : public TerminatorStmt_impl {
+ struct Default {};
+ struct TypeSpec {
+ Type v;
+ };
+ struct DerivedTypeSpec {
+ Type v;
+ };
+ using ValueType = std::variant<Default, TypeSpec, DerivedTypeSpec>;
+ using ValueSuccPairType = std::pair<ValueType, BasicBlock *>;
+ using ValueSuccPairListType = std::vector<ValueSuccPairType>;
+ static SwitchTypeStmt Create(const Evaluation &switchEval,
+ BasicBlock *defaultBlock, const ValueSuccPairListType &args) {
+ return SwitchTypeStmt{switchEval, defaultBlock, args};
+ }
+ BasicBlock *defaultSucc() const { return valueSuccPairs_[0].second; }
+ std::list<BasicBlock *> succ_blocks() const override;
+ const Evaluation &getCond() const { return condition_; }
+
+private:
+ explicit SwitchTypeStmt(const Evaluation &condition, BasicBlock *defaultBlock,
+ const ValueSuccPairListType &args);
+ Evaluation condition_;
+ ValueSuccPairListType valueSuccPairs_;
+};
+
+/// Switch on the RANK of the selector into a set of constant integers, etc.
+struct SwitchRankStmt : public TerminatorStmt_impl {
+ struct Default {}; // RANK DEFAULT
+ struct AssumedSize {}; // RANK(*)
+ struct Exactly { // RANK(n)
+ Expression *v;
+ };
+ using ValueType = std::variant<Exactly, AssumedSize, Default>;
+ using ValueSuccPairType = std::pair<ValueType, BasicBlock *>;
+ using ValueSuccPairListType = std::vector<ValueSuccPairType>;
+ static SwitchRankStmt Create(const Evaluation &switchEval,
+ BasicBlock *defaultBlock, const ValueSuccPairListType &args) {
+ return SwitchRankStmt{switchEval, defaultBlock, args};
+ }
+ BasicBlock *defaultSucc() const { return valueSuccPairs_[0].second; }
+ std::list<BasicBlock *> succ_blocks() const override;
+ const Evaluation &getCond() const { return condition_; }
+
+private:
+ explicit SwitchRankStmt(const Evaluation &condition, BasicBlock *defaultBlock,
+ const ValueSuccPairListType &args);
+ Evaluation condition_;
+ ValueSuccPairListType valueSuccPairs_;
+};
+
+struct IndirectBrStmt : public TerminatorStmt_impl {
+ using TargetListType = std::vector<BasicBlock *>;
+ static IndirectBrStmt Create(
+ Variable *variable, const TargetListType &potentialTargets) {
+ return IndirectBrStmt{variable, potentialTargets};
+ }
+
+private:
+ explicit IndirectBrStmt(
+ Variable *variable, const TargetListType &potentialTargets)
+ : variable_{variable}, potentialTargets_{potentialTargets} {}
+ Variable *variable_;
+ TargetListType potentialTargets_;
+};
+
+struct UnreachableStmt : public TerminatorStmt_impl {
+ static UnreachableStmt Create() { return UnreachableStmt{}; }
+
+private:
+ explicit UnreachableStmt() = default;
+};
+
+struct ActionStmt_impl : public Stmt_impl {
+ using ActionTrait = std::true_type;
+
+protected:
+ ActionStmt_impl() : type{std::nullopt} {}
+
+ // TODO: DynamicType is a placeholder for now
+ std::optional<evaluate::DynamicType> type;
+};
+
+struct AssignmentStmt : public ActionStmt_impl {
+ static AssignmentStmt Create(const PathVariable *lhs, const Expression *rhs) {
+ return AssignmentStmt{lhs, rhs};
+ }
+ const PathVariable *GetLeftHandSide() const { return lhs_; }
+ const Expression *GetRightHandSide() const { return rhs_; }
+
+private:
+ explicit AssignmentStmt(const PathVariable *lhs, const Expression *rhs)
+ : lhs_{lhs}, rhs_{rhs} {}
+
+ const PathVariable *lhs_;
+ const Expression *rhs_;
+};
+
+struct PointerAssignStmt : public ActionStmt_impl {
+ static PointerAssignStmt Create(
+ const Expression *lhs, const Expression *rhs) {
+ return PointerAssignStmt{lhs, rhs};
+ }
+ const Expression *GetLeftHandSide() const { return lhs_; }
+ const Expression *GetRightHandSide() const { return rhs_; }
+
+private:
+ explicit PointerAssignStmt(const Expression *lhs, const Expression *rhs)
+ : lhs_{lhs}, rhs_{rhs} {}
+ const parser::PointerAssignmentStmt *assign_;
+ const Expression *lhs_;
+ const Expression *rhs_;
+};
+
+struct LabelAssignStmt : public ActionStmt_impl {
+ static LabelAssignStmt Create(const semantics::Symbol *lhs, BasicBlock *rhs) {
+ return LabelAssignStmt{lhs, rhs};
+ }
+
+private:
+ explicit LabelAssignStmt(const semantics::Symbol *lhs, BasicBlock *rhs)
+ : lhs_{lhs}, rhs_{rhs} {}
+
+ const semantics::Symbol *lhs_;
+ BasicBlock *rhs_;
+};
+
+struct MemoryStmt_impl : public ActionStmt_impl {
+ // FIXME: ought to use a Type, let backend compute size...
+protected:
+ MemoryStmt_impl() {}
+};
+
+/// ALLOCATE allocate space for a pointer target or allocatable and populate the
+/// reference
+struct AllocateStmt : public MemoryStmt_impl {
+ static AllocateStmt Create(const Expression *object) {
+ return AllocateStmt{object};
+ }
+
+private:
+ explicit AllocateStmt(const Expression *object) : object_{object} {}
+ const Expression *object_; // POINTER|ALLOCATABLE to be allocated
+ // TODO: maybe add other arguments
+};
+
+/// DEALLOCATE deallocate allocatable variables and pointer targets. pointers
+/// become disassociated
+struct DeallocateStmt : public MemoryStmt_impl {
+ static DeallocateStmt Create(const Expression *object) {
+ return DeallocateStmt{object};
+ }
+
+private:
+ explicit DeallocateStmt(const Expression *object) : object_{object} {}
+ const Expression *object_; // POINTER|ALLOCATABLE to be deallocated
+ // TODO: maybe add other arguments
+};
+
+struct AllocLocalInsn : public MemoryStmt_impl {
+ static AllocLocalInsn Create(Type type, unsigned alignment = 0u) {
+ return AllocLocalInsn{type, alignment};
+ }
+
+private:
+ explicit AllocLocalInsn(Type type, unsigned alignment)
+ : alignment_{alignment} {}
+ unsigned alignment_;
+};
+
+struct LoadInsn : public MemoryStmt_impl {
+ static LoadInsn Create(const Expression *address) {
+ return LoadInsn{address};
+ }
+
+private:
+ explicit LoadInsn(const Expression *address) : address_{address} {}
+ const Expression *address_;
+};
+
+struct StoreInsn : public MemoryStmt_impl {
+ static StoreInsn Create(const Expression *address, const Expression *value) {
+ return StoreInsn{address, value};
+ }
+
+private:
+ explicit StoreInsn(const Expression *address, const Expression *value)
+ : address_{address}, value_{value} {}
+ const Expression *address_;
+ const Expression *value_;
+};
+
+/// NULLIFY make pointer object disassociated
+struct DisassociateStmt : public ActionStmt_impl {
+ static DisassociateStmt Create(const parser::NullifyStmt *n) {
+ return DisassociateStmt{n};
+ }
+
+private:
+ DisassociateStmt(const parser::NullifyStmt *n) : disassociate_{n} {}
+ const parser::NullifyStmt *disassociate_;
+};
+
+/// expressions that must be evaluated in various statements
+struct ExprStmt
+ : public ActionStmt_impl,
+ public SumTypeCopyMixin<std::variant<const parser::AssociateStmt *,
+ const parser::ChangeTeamStmt *, const parser::NonLabelDoStmt *,
+ const parser::ForallConstructStmt *, const Expression *>> {
+ template<typename T> static ExprStmt Create(const T *e) {
+ return ExprStmt{e};
+ }
+
+private:
+ template<typename T> explicit ExprStmt(const T *e) : SumTypeCopyMixin{e} {}
+ // Evaluation evaluation_;
+};
+
+/// base class for all call-like IR statements
+struct CallStmt_impl : public ActionStmt_impl {
+ const Value *Callee() const { return callee_; }
+ unsigned NumArgs() const { return arguments_.size(); }
+
+protected:
+ CallStmt_impl(const FunctionType *functionType, const Value *callee,
+ CallArguments &&arguments)
+ : functionType_{functionType}, callee_{callee}, arguments_{arguments} {}
+
+ const FunctionType *functionType_;
+ const Value *callee_;
+ CallArguments arguments_;
+};
+
+/// CALL statements and function references
+struct CallStmt : public CallStmt_impl {
+ static CallStmt Create(const FunctionType *type, const Value *callee,
+ CallArguments &&arguments) {
+ return CallStmt{type, callee, std::move(arguments)};
+ }
+
+private:
+ explicit CallStmt(const FunctionType *functionType, const Value *callee,
+ CallArguments &&arguments)
+ : CallStmt_impl{functionType, callee, std::move(arguments)} {}
+};
+
+/// Miscellaneous statements that turn into runtime calls
+struct RuntimeStmt : public CallStmt_impl {
+ static RuntimeStmt Create(
+ RuntimeCallType call, RuntimeCallArguments &&argument) {
+ return RuntimeStmt{call, std::move(argument)};
+ }
+
+private:
+ explicit RuntimeStmt(RuntimeCallType call, RuntimeCallArguments &&arguments)
+ : CallStmt_impl{nullptr, nullptr, std::move(arguments)}, call_{call} {}
+
+ RuntimeCallType call_;
+};
+
+/// The 13 Fortran I/O statements. Will be lowered to whatever becomes of the
+/// I/O runtime.
+struct IORuntimeStmt : public CallStmt_impl {
+ static IORuntimeStmt Create(
+ InputOutputCallType call, IOCallArguments &&arguments) {
+ return IORuntimeStmt{call, std::move(arguments)};
+ }
+
+private:
+ explicit IORuntimeStmt(InputOutputCallType call, IOCallArguments &&arguments)
+ : CallStmt_impl{nullptr, nullptr, std::move(arguments)}, call_{call} {}
+
+ InputOutputCallType call_;
+};
+
+struct ScopeStmt_impl : public ActionStmt_impl {
+ Scope *GetScope() const { return scope; }
+
+protected:
+ ScopeStmt_impl(Scope *scope) : scope{nullptr} {}
+ Scope *scope;
+};
+
+/// From the CFG document
+struct ScopeEnterStmt : public ScopeStmt_impl {
+ static ScopeEnterStmt Create(Scope *scope) { return ScopeEnterStmt{scope}; }
+
+private:
+ ScopeEnterStmt(Scope *scope) : ScopeStmt_impl{scope} {}
+};
+
+/// From the CFG document
+struct ScopeExitStmt : public ScopeStmt_impl {
+ static ScopeExitStmt Create(Scope *scope) { return ScopeExitStmt{scope}; }
+
+private:
+ ScopeExitStmt(Scope *scope) : ScopeStmt_impl{scope} {}
+};
+
+/// From the CFG document to support SSA
+struct PHIStmt : public ActionStmt_impl {
+ static PHIStmt Create(unsigned numReservedValues) {
+ return PHIStmt{numReservedValues};
+ }
+
+private:
+ PHIStmt(unsigned size) : inputs_(size) {}
+
+ std::vector<PHIPair> inputs_;
+};
+
+}
+
+#endif
--- /dev/null
+// Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef FORTRAN_INTERMEDIATEREPRESENTATION_STMT_H_
+#define FORTRAN_INTERMEDIATEREPRESENTATION_STMT_H_
+
+#include "basicblock.h"
+#include "mixin.h"
+#include "statements.h"
+
+namespace Fortran::IntermediateRepresentation {
+
+/// Sum type over all statement classes
+struct Statement : public SumTypeMixin<std::variant<
+#define HANDLE_STMT(num, opcode, name) name,
+#define HANDLE_LAST_STMT(num, opcode, name) name
+#include "statement.def"
+ >>,
+ public ChildMixin<Statement, BasicBlock>,
+ public llvm::ilist_node<Statement> {
+ template<typename A>
+ Statement(BasicBlock *p, A &&t) : SumTypeMixin{t}, ChildMixin{p} {
+ parent->insertBefore(this);
+ }
+ std::string dump() const;
+};
+
+inline std::list<BasicBlock *> succ_list(BasicBlock &block) {
+ if (auto *terminator{block.getTerminator()}) {
+ return reinterpret_cast<const TerminatorStmt_impl *>(&terminator->u)
+ ->succ_blocks();
+ }
+ // CHECK(false && "block does not have terminator");
+ return {};
+}
+
+}
+
+#endif