From: Eric Schweitz Date: Wed, 20 Feb 2019 20:12:17 +0000 (-0800) Subject: [flang] Fortran IR: lowest layer of the IR hierarchy. Specifically, Basic Blocks X-Git-Tag: llvmorg-12-init~9537^2~1720 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=467bad4bdb5099fe45b4e9a26bf841f31de52de7;p=platform%2Fupstream%2Fllvm.git [flang] Fortran IR: lowest layer of the IR hierarchy. Specifically, Basic Blocks contain Statements. This layer is still evolving as the IR takes better shape and other code in the compiler is written. Original-commit: flang-compiler/f18@e1a282296b4dc90d05acb7d67f536f169fa36a39 Reviewed-on: https://github.com/flang-compiler/f18/pull/294 Tree-same-pre-rewrite: false --- diff --git a/flang/lib/IntermediateRepresentation/statement.def b/flang/lib/IntermediateRepresentation/statement.def new file mode 100644 index 0000000..1d53389 --- /dev/null +++ b/flang/lib/IntermediateRepresentation/statement.def @@ -0,0 +1,171 @@ +// 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 diff --git a/flang/lib/IntermediateRepresentation/statements.cc b/flang/lib/IntermediateRepresentation/statements.cc new file mode 100644 index 0000000..052d6a1 --- /dev/null +++ b/flang/lib/IntermediateRepresentation/statements.cc @@ -0,0 +1,250 @@ +// 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 ""s; +} + +static std::string dump(const Variable *variable) { +#if 0 + if (auto *var{std::get_if(&variable->u)}) { + return (*var)->name().ToString(); + } + return ""s; +#endif + return (*variable)->name().ToString(); +} + +static std::string dump(PathVariable *pathVariable) { + if (pathVariable) { + return std::visit( + common::visitors{ + [](const common::Indirection &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 ""s; + }, + [](const common::Indirection< + parser::ArrayElement> &) { + return ""s; + }, + [](const common::Indirection< + parser::CoindexedNamedObject> &) { + return ""s; + }, + }, + dataRef.u); + }, + [](const parser::Substring &substring) { + return ""s; + }, + }, + designator->u); + }, + [](const common::Indirection + &functionReference) { return ""s; }, + }, + pathVariable->u); + } + return ""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 +static std::list SuccBlocks(const L &valueSuccPairList) { + std::list 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 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 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 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 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( + branchStatement.getTrueSucc())) + + " "s + + std::to_string(reinterpret_cast( + branchStatement.getFalseSucc())); + } + return "goto "s + + std::to_string(reinterpret_cast( + 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 ""s; + }, + [](const parser::ChangeTeamStmt *) { + return ""s; + }, + [](const parser::NonLabelDoStmt *) { return ""s; }, + [](const parser::SelectTypeStmt *) { + return ""s; + }, + [](const parser::ForallConstructStmt *) { + return ""s; + }, + [](const parser::SelectRankStmt *) { + return ""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); +} + +} diff --git a/flang/lib/IntermediateRepresentation/statements.h b/flang/lib/IntermediateRepresentation/statements.h new file mode 100644 index 0000000..3f39233 --- /dev/null +++ b/flang/lib/IntermediateRepresentation/statements.h @@ -0,0 +1,470 @@ +// 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 +#include + +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> { + SUM_TYPE_COPY_MIXIN(Evaluation) + Evaluation(PathVariable *pv) : SumTypeCopyMixin{pv} { + if (const auto *designator{ + std::get_if>(&pv->u)}) { + if (const auto *obj{std::get_if(&(*designator)->u)}) { + u = obj->symbol; + } + } + } + template 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 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 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; + using ValueSuccPairListType = std::vector; + 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 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; + using ValueType = std::variant>; + using ValueSuccPairType = std::pair; + using ValueSuccPairListType = std::vector; + + 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 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; + using ValueSuccPairType = std::pair; + using ValueSuccPairListType = std::vector; + 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 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; + using ValueSuccPairType = std::pair; + using ValueSuccPairListType = std::vector; + 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 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; + 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 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> { + template static ExprStmt Create(const T *e) { + return ExprStmt{e}; + } + +private: + template 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 inputs_; +}; + +} + +#endif diff --git a/flang/lib/IntermediateRepresentation/stmt.h b/flang/lib/IntermediateRepresentation/stmt.h new file mode 100644 index 0000000..1fd8a0a --- /dev/null +++ b/flang/lib/IntermediateRepresentation/stmt.h @@ -0,0 +1,50 @@ +// 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>, + public ChildMixin, + public llvm::ilist_node { + template + Statement(BasicBlock *p, A &&t) : SumTypeMixin{t}, ChildMixin{p} { + parent->insertBefore(this); + } + std::string dump() const; +}; + +inline std::list succ_list(BasicBlock &block) { + if (auto *terminator{block.getTerminator()}) { + return reinterpret_cast(&terminator->u) + ->succ_blocks(); + } + // CHECK(false && "block does not have terminator"); + return {}; +} + +} + +#endif