[flang] Fortran IR: lowest layer of the IR hierarchy. Specifically, Basic Blocks
authorEric Schweitz <eschweitz@nvidia.com>
Wed, 20 Feb 2019 20:12:17 +0000 (12:12 -0800)
committerEric Schweitz <eschweitz@nvidia.com>
Wed, 20 Feb 2019 20:12:17 +0000 (12:12 -0800)
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

flang/lib/IntermediateRepresentation/statement.def [new file with mode: 0644]
flang/lib/IntermediateRepresentation/statements.cc [new file with mode: 0644]
flang/lib/IntermediateRepresentation/statements.h [new file with mode: 0644]
flang/lib/IntermediateRepresentation/stmt.h [new file with mode: 0644]

diff --git a/flang/lib/IntermediateRepresentation/statement.def b/flang/lib/IntermediateRepresentation/statement.def
new file mode 100644 (file)
index 0000000..1d53389
--- /dev/null
@@ -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 (file)
index 0000000..052d6a1
--- /dev/null
@@ -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 "<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);
+}
+
+}
diff --git a/flang/lib/IntermediateRepresentation/statements.h b/flang/lib/IntermediateRepresentation/statements.h
new file mode 100644 (file)
index 0000000..3f39233
--- /dev/null
@@ -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 <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
diff --git a/flang/lib/IntermediateRepresentation/stmt.h b/flang/lib/IntermediateRepresentation/stmt.h
new file mode 100644 (file)
index 0000000..1fd8a0a
--- /dev/null
@@ -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<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