[flang] cleanup merge

Original-commit: flang-compiler/f18@ea00eab799
Reviewed-on: https://github.com/flang-compiler/f18/pull/319
Tree-same-pre-rewrite: false
This commit is contained in:
Eric Schweitz 2019-02-28 10:20:01 -08:00
parent 1ee88d3c81
commit ddedf6688b
20 changed files with 0 additions and 4075 deletions

File diff suppressed because it is too large Load diff

View file

@ -1,37 +0,0 @@
// 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_AFFORESTATION_H_
#define FORTRAN_INTERMEDIATEREPRESENTATION_AFFORESTATION_H_
#include <string>
namespace Fortran::parser {
class Program;
}
namespace Fortran::semantics {
class SemanticsContext;
}
namespace Fortran::IntermediateRepresentation {
class Program;
void SetDebugChannel(const std::string &filename);
Program *CreateFortranIR(const parser::Program &program,
semantics::SemanticsContext &semanticsContext, bool debugLinearIR);
}
#endif

View file

@ -1,57 +0,0 @@
// 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 "program.h"
#include "stmt.h"
namespace Fortran::IntermediateRepresentation {
BasicBlock::BasicBlock(Region *parentRegion, BasicBlock *insertBefore)
: ChildMixin{parentRegion} {
parent->insertBefore(this, insertBefore);
}
BasicBlock::~BasicBlock() { statementList_.clear(); }
void BasicBlock::insertBefore(Statement *stmt, Statement *before) {
if (before) {
statementList_.insert(before->getIterator(), stmt);
} else {
statementList_.push_back(stmt);
}
}
void BasicBlock::addPred(BasicBlock *bb) {
for (auto *p : predecessors_) {
if (p == bb) return;
}
predecessors_.push_back(bb);
}
const Statement *BasicBlock::getTerminator() const {
if (statementList_.empty()) {
return nullptr;
}
const auto &lastStmt{statementList_.back()};
return std::visit(
[&lastStmt](auto stmt) {
if constexpr (std::is_base_of_v<TerminatorStmt_impl, decltype(stmt)>) {
return &lastStmt;
}
return static_cast<const Statement *>(nullptr);
},
lastStmt.u);
}
}

View file

@ -1,69 +0,0 @@
// 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_BASICBLOCK_H_
#define FORTRAN_INTERMEDIATEREPRESENTATION_BASICBLOCK_H_
#include "mixin.h"
#include "region.h"
#include <iostream>
namespace Fortran::IntermediateRepresentation {
struct Region;
struct Statement;
struct BasicBlock final : public llvm::ilist_node<BasicBlock>,
public ChildMixin<BasicBlock, Region> {
using StatementListType = llvm::iplist<Statement>;
using iterator = StatementListType::iterator;
using const_iterator = StatementListType::const_iterator;
using reverse_iterator = StatementListType::reverse_iterator;
using const_reverse_iterator = StatementListType::const_reverse_iterator;
BasicBlock(const BasicBlock &) = delete;
BasicBlock &operator=(const BasicBlock &) = delete;
~BasicBlock();
StatementListType &getSublist(Statement *) { return Statements(); }
void insertBefore(Statement *stmt, Statement *before = nullptr);
static BasicBlock *Create(
Region *parentRegion, BasicBlock *insertBefore = nullptr) {
return new BasicBlock(parentRegion, insertBefore);
}
const Statement *getTerminator() const;
Statement *getTerminator() {
return const_cast<Statement *>(
const_cast<const BasicBlock *>(this)->getTerminator());
}
void SetRegion(Region *region) { parent = region; }
Region *GetRegion() const { return parent; }
void addPred(BasicBlock *bb);
std::vector<BasicBlock *> &Predecessors() { return predecessors_; }
StatementListType &Statements() { return statementList_; }
BasicBlock *SplitEdge(BasicBlock *toBlock) { return nullptr; }
private:
StatementListType statementList_;
std::vector<BasicBlock *> predecessors_;
explicit BasicBlock(Region *parentRegion, BasicBlock *insertBefore);
};
inline std::list<BasicBlock *> pred_list(BasicBlock &block) {
return std::list<BasicBlock *>{
block.Predecessors().begin(), block.Predecessors().end()};
}
}
#endif

View file

@ -1,24 +0,0 @@
// 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 "builder.h"
#include <iostream>
namespace Fortran::IntermediateRepresentation {
void IntermediateRepresentationBuilder::dump() const {
std::cerr << "builder state:\n";
}
}

View file

@ -1,139 +0,0 @@
// 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_BUILDER_H_
#define FORTRAN_INTERMEDIATEREPRESENTATION_BUILDER_H_
#include "stmt.h"
#include <initializer_list>
namespace Fortran::IntermediateRepresentation {
struct IntermediateRepresentationBuilder {
explicit IntermediateRepresentationBuilder(BasicBlock &block)
: cursorRegion_{block.getParent()}, cursorBlock_{&block} {}
template<typename A> Statement &Insert(A &&s) {
CHECK(GetInsertionPoint());
auto *statement{new Statement(GetInsertionPoint(), s)};
return *statement;
}
template<typename A> Statement &InsertTerminator(A &&s) {
auto &statement{Insert(s)};
for (auto *block : s.succ_blocks()) {
block->addPred(GetInsertionPoint());
}
return statement;
}
void SetInsertionPoint(BasicBlock *bb) {
cursorBlock_ = bb;
cursorRegion_ = bb->getParent();
}
void ClearInsertionPoint() { cursorBlock_ = nullptr; }
BasicBlock *GetInsertionPoint() const { return cursorBlock_; }
Statement &CreateAlloc(const Expression *object) {
return Insert(AllocateStmt::Create(object));
}
Statement &CreateAssign(const PathVariable *lhs, const Expression *rhs) {
return Insert(AssignmentStmt::Create(lhs, rhs));
}
Statement &CreateAssign(const semantics::Symbol *lhs, BasicBlock *rhs) {
return Insert(LabelAssignStmt::Create(lhs, rhs));
}
Statement &CreateBranch(BasicBlock *block) {
return InsertTerminator(BranchStmt::Create(block));
}
Statement &CreateCall(const FunctionType *type, const Value *callee,
CallArguments &&arguments) {
return Insert(CallStmt::Create(type, callee, std::move(arguments)));
}
template<typename A>
Statement &CreateConditionalBranch(
A *condition, BasicBlock *trueBlock, BasicBlock *falseBlock) {
return InsertTerminator(
BranchStmt::Create(condition, trueBlock, falseBlock));
}
Statement &CreateDealloc(const Expression *object) {
return Insert(DeallocateStmt::Create(object));
}
template<typename A> Statement &CreateExpr(const A *a) {
return Insert(ExprStmt::Create(a));
}
Statement &CreateIOCall(
InputOutputCallType call, IOCallArguments &&arguments) {
return Insert(IORuntimeStmt::Create(call, std::move(arguments)));
}
Statement &CreateIndirectBr(
Variable *var, const std::vector<BasicBlock *> &potentials) {
return InsertTerminator(IndirectBrStmt::Create(var, potentials));
}
Statement &CreateNullify(const parser::NullifyStmt *statement) {
return Insert(DisassociateStmt::Create(statement));
}
Statement &CreatePointerAssign(const Expression *lhs, const Expression *rhs) {
return Insert(PointerAssignStmt::Create(lhs, rhs));
}
Statement &CreateRetVoid() { return InsertTerminator(ReturnStmt::Create()); }
template<typename A> Statement &CreateReturn(A *expr) {
return InsertTerminator(ReturnStmt::Create(expr));
}
Statement &CreateRuntimeCall(
RuntimeCallType call, RuntimeCallArguments &&arguments) {
return Insert(RuntimeStmt::Create(call, std::move(arguments)));
}
Statement &CreateSwitch(const Evaluation &condition, BasicBlock *defaultCase,
const SwitchStmt::ValueSuccPairListType &rest) {
return InsertTerminator(SwitchStmt::Create(condition, defaultCase, rest));
}
Statement &CreateSwitchCase(const Evaluation &condition,
BasicBlock *defaultCase,
const SwitchCaseStmt::ValueSuccPairListType &rest) {
return InsertTerminator(
SwitchCaseStmt::Create(condition, defaultCase, rest));
}
Statement &CreateSwitchType(const Evaluation &condition,
BasicBlock *defaultCase,
const SwitchTypeStmt::ValueSuccPairListType &rest) {
return InsertTerminator(
SwitchTypeStmt::Create(condition, defaultCase, rest));
}
Statement &CreateSwitchRank(const Evaluation &condition,
BasicBlock *defaultCase,
const SwitchRankStmt::ValueSuccPairListType &rest) {
return InsertTerminator(
SwitchRankStmt::Create(condition, defaultCase, rest));
}
Statement &CreateUnreachable() {
return InsertTerminator(UnreachableStmt::Create());
}
void PushBlock(BasicBlock *block) { blockStack_.push_back(block); }
BasicBlock *PopBlock() {
auto *block{blockStack_.back()};
blockStack_.pop_back();
return block;
}
void dump() const;
void SetCurrentRegion(Region *region) { cursorRegion_ = region; }
Region *GetCurrentRegion() const { return cursorRegion_; }
private:
Region *cursorRegion_;
BasicBlock *cursorBlock_;
std::vector<BasicBlock *> blockStack_;
};
}
#endif

View file

@ -1,107 +0,0 @@
// 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_COMMON_H_
#define FORTRAN_INTERMEDIATEREPRESENTATION_COMMON_H_
#include "../common/idioms.h"
#include "../common/indirection.h"
#include "../evaluate/expression.h"
#include "../evaluate/type.h"
#include "../evaluate/variable.h"
#include "../parser/parse-tree.h"
#include "../semantics/symbol.h"
// Some useful, self-documenting macros for failure modes
#define STRINGIFY(X) #X
#define LINE2STRING(X) STRINGIFY(X)
#define AT_HERE " at " __FILE__ "(" LINE2STRING(__LINE__) ")"
#define DIE Fortran::common::die
#define SEMANTICS_FAILED(STRING) DIE("semantics bug: " STRING AT_HERE)
#define SEMANTICS_CHECK(CONDITION, STRING) \
if (CONDITION) { \
} else { \
DIE("semantics bug: " STRING AT_HERE); \
}
#define WRONG_PATH() DIE("control should not reach here" AT_HERE)
namespace Fortran::IntermediateRepresentation {
class Statement;
class BasicBlock;
struct Program;
struct GraphWriter;
struct Attribute {
enum { IntentIn, IntentOut, IntentInOut } attribute;
unsigned short position;
};
using FunctionType = evaluate::SomeType; // TODO: what should this be?
using AttributeList = std::vector<Attribute>;
enum struct LinkageTypes { Public, Hidden, External };
using Expression = evaluate::GenericExprWrapper;
#if 0
struct Variable {
// TODO: should semantics::Symbol be removed?
template<typename... Ts> struct GVT {
using type =
std::variant<const semantics::Symbol *, evaluate::Variable<Ts>...>;
};
Variable(const semantics::Symbol *symbol) : u{symbol} {}
common::OverMembers<GVT, evaluate::AllIntrinsicTypes>::type u;
};
#endif
using Variable = const semantics::Symbol *;
using PathVariable = const parser::Variable;
using Scope = const semantics::Scope;
using Value = Expression;
using PHIPair = std::pair<Value *, BasicBlock *>;
using CallArguments = std::vector<const Expression *>;
enum InputOutputCallType {
InputOutputCallBackspace = 11,
InputOutputCallClose,
InputOutputCallEndfile,
InputOutputCallFlush,
InputOutputCallInquire,
InputOutputCallOpen,
InputOutputCallPrint,
InputOutputCallRead,
InputOutputCallRewind,
InputOutputCallWait,
InputOutputCallWrite,
InputOutputCallSIZE = InputOutputCallWrite - InputOutputCallBackspace + 1
};
using IOCallArguments = CallArguments;
enum RuntimeCallType {
RuntimeCallFailImage = 31,
RuntimeCallStop,
RuntimeCallPause,
RuntimeCallFormTeam,
RuntimeCallEventPost,
RuntimeCallEventWait,
RuntimeCallSyncAll,
RuntimeCallSyncImages,
RuntimeCallSyncMemory,
RuntimeCallSyncTeam,
RuntimeCallLock,
RuntimeCallUnlock,
RuntimeCallSIZE = RuntimeCallUnlock - RuntimeCallFailImage + 1
};
using RuntimeCallArguments = CallArguments;
}
#endif

View file

@ -1,122 +0,0 @@
// 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 "graph-writer.h"
namespace Fortran::IntermediateRepresentation {
std::optional<llvm::raw_ostream *> GraphWriter::defaultOutput_{std::nullopt};
void GraphWriter::dumpHeader() { output_ << "digraph G {\n"; }
void GraphWriter::dumpFooter() { output_ << "}\n"; }
void GraphWriter::dump(Program &program) {
dumpHeader();
for (auto iter{program.procedureMap_.begin()},
iend{program.procedureMap_.end()};
iter != iend; ++iter) {
dump(*iter->getValue(), true);
}
dumpFooter();
}
void GraphWriter::dump(Procedure &procedure, bool box) {
if (box) {
output_ << "subgraph cluster" << counter()
<< " {\n node[style=filled];\n color=red;\n";
}
for (auto iter{procedure.regionList_.begin()},
iend{procedure.regionList_.end()};
iter != iend; ++iter) {
dump(*iter, true);
}
if (box) {
output_ << " label = \"procedure";
if (procedure.getName().empty()) {
output_ << '#' << counter();
} else {
output_ << ": " << procedure.getName().str();
}
output_ << "\"\n}\n";
}
}
void GraphWriter::dump(Region &region, bool box) {
if (box) {
output_ << " subgraph cluster" << counter()
<< " {\n node[style=filled];\n";
}
for (auto iter{region.begin()}, iend{region.end()}; iter != iend; ++iter) {
dump(*iter, true);
}
std::set<BasicBlock *> myNodes;
auto blocks{region.getBlocks()};
auto iend{blocks.end()};
auto iexit{iend};
--iexit;
auto ientry{blocks.begin()};
for (auto iter{ientry}; iter != iend; ++iter) {
isEntry_ = iter == ientry && region.IsOutermost();
isExit_ = iter == iexit && region.IsOutermost();
dump(**iter);
myNodes.insert(*iter);
}
std::list<std::pair<BasicBlock *, BasicBlock *>> emitAfter;
for (auto iter{blocks.begin()}, iend{blocks.end()}; iter != iend; ++iter) {
dumpInternalEdges(**iter, myNodes, emitAfter);
}
if (box) {
output_ << " style=dashed;\n color=blue;\n label = \"region#"
<< counter() << "\\nvariables: {...}\\n\"\n }\n";
}
for (auto pair : emitAfter) {
output_ << " " << block_id(*pair.first) << " -> " << block_id(*pair.second)
<< ";\n";
}
}
void GraphWriter::dump(BasicBlock &block, std::optional<const char *> color) {
output_ << " " << block_id(block) << " [label = \"";
if (isEntry_) {
output_ << "<<ENTRY>>\\n";
}
output_ << block_id(block) << '(' << reinterpret_cast<std::intptr_t>(&block)
<< ")\\n";
for (auto &action : block.getSublist(static_cast<Statement *>(nullptr))) {
output_ << action.dump() << "\\n";
}
if (isExit_) {
output_ << "<<EXIT>>";
}
output_ << "\",shape=rectangle";
if (color) {
output_ << ",color=" << *color;
}
output_ << "];\n";
}
void GraphWriter::dumpInternalEdges(BasicBlock &block,
std::set<BasicBlock *> &nodeSet,
std::list<std::pair<BasicBlock *, BasicBlock *>> &emitAfter) {
for (auto succ : succ_list(block)) {
if (nodeSet.count(succ)) {
output_ << " " << block_id(block) << " -> " << block_id(*succ)
<< ";\n";
} else {
emitAfter.push_back({&block, succ});
}
}
}
}

View file

@ -1,93 +0,0 @@
// 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_GRAPH_WRITER_H_
#define FORTRAN_INTERMEDIATEREPRESENTATION_GRAPH_WRITER_H_
#include "program.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/raw_ostream.h"
#include <list>
#include <map>
#include <set>
#include <sstream>
#include <string>
namespace Fortran::IntermediateRepresentation {
struct GraphWriter {
static void setOutput(llvm::raw_ostream *output) { defaultOutput_ = output; }
static void setOutput(const std::string &filename) {
std::error_code ec;
setOutput(new llvm::raw_fd_ostream(filename, ec, llvm::sys::fs::F_None));
CHECK(!ec);
}
static void print(Program &program) {
GraphWriter writer{getOutput()};
writer.dump(program);
}
static void print(Procedure &procedure) {
GraphWriter writer{getOutput()};
writer.dump(procedure);
}
static void print(Region &region) {
GraphWriter writer{getOutput()};
writer.dump(region);
}
private:
GraphWriter(llvm::raw_ostream &output) : output_{output} {}
~GraphWriter() {
if (defaultOutput_) {
delete *defaultOutput_;
defaultOutput_ = std::nullopt;
}
}
void dump(Program &program);
void dump(Procedure &procedure, bool box = false);
void dump(Region &region, bool box = false);
void dumpHeader();
void dumpFooter();
unsigned counter() { return count_++; }
void dump(
BasicBlock &block, std::optional<const char *> color = std::nullopt);
void dumpInternalEdges(BasicBlock &block, std::set<BasicBlock *> &nodeSet,
std::list<std::pair<BasicBlock *, BasicBlock *>> &emitAfter);
std::string block_id(BasicBlock &block) {
unsigned num;
if (blockIds_.count(&block)) {
num = blockIds_[&block];
} else {
blockIds_[&block] = num = blockNum_++;
}
std::ostringstream buffer;
buffer << "BB_" << num;
return buffer.str();
}
static llvm::raw_ostream &getOutput() {
return defaultOutput_ ? *defaultOutput_.value() : llvm::outs();
}
unsigned count_{0u};
llvm::raw_ostream &output_;
unsigned blockNum_{0u};
bool isEntry_{false};
bool isExit_{false};
std::map<BasicBlock *, unsigned> blockIds_;
static std::optional<llvm::raw_ostream *> defaultOutput_;
};
}
#endif

View file

@ -1,114 +0,0 @@
// 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_MIXIN_H_
#define FORTRAN_INTERMEDIATEREPRESENTATION_MIXIN_H_
#include "llvm/ADT/ilist.h"
#include <optional>
#include <tuple>
#include <type_traits>
#include <variant>
namespace Fortran::IntermediateRepresentation {
template<typename T, typename E = void> struct SumTypeMixin {};
template<typename T> // T must be std::optional<...>
struct SumTypeMixin<T, std::enable_if_t<std::variant_size_v<T>>> {
template<typename A> SumTypeMixin(A &&x) : u{std::move(x)} {}
using SumTypeTrait = std::true_type;
SumTypeMixin(SumTypeMixin &&) = default;
SumTypeMixin &operator=(SumTypeMixin &&) = default;
SumTypeMixin(const SumTypeMixin &) = delete;
SumTypeMixin &operator=(const SumTypeMixin &) = delete;
SumTypeMixin() = delete;
T u;
};
template<typename T, typename E = void> struct SumTypeCopyMixin {};
template<typename T> // T must be std::optional<...>
struct SumTypeCopyMixin<T, std::enable_if_t<std::variant_size_v<T>>> {
using CopyableSumTypeTrait = std::true_type;
SumTypeCopyMixin(SumTypeCopyMixin &&) = default;
SumTypeCopyMixin &operator=(SumTypeCopyMixin &&) = default;
SumTypeCopyMixin(const SumTypeCopyMixin &) = default;
SumTypeCopyMixin &operator=(const SumTypeCopyMixin &) = default;
SumTypeCopyMixin() = delete;
T u;
};
#define SUM_TYPE_COPY_MIXIN(Derived) \
Derived(const Derived &derived) : SumTypeCopyMixin(derived) {} \
Derived &operator=(const Derived &derived) { \
SumTypeCopyMixin::operator=(derived); \
return *this; \
}
template<typename T, typename E = void> struct ProductTypeMixin {};
template<typename T> // T must be std::tuple<...>
struct ProductTypeMixin<T, std::enable_if_t<std::tuple_size_v<T>>> {
template<typename A> ProductTypeMixin(A &&x) : t{std::move(x)} {}
using ProductTypeTrait = std::true_type;
ProductTypeMixin(ProductTypeMixin &&) = default;
ProductTypeMixin &operator=(ProductTypeMixin &&) = default;
ProductTypeMixin(const ProductTypeMixin &) = delete;
ProductTypeMixin &operator=(const ProductTypeMixin &) = delete;
ProductTypeMixin() = delete;
T t;
};
template<typename T, typename E = void> struct MaybeMixin {};
template<typename T> // T must be std::optional<...>
struct MaybeMixin<T,
std::enable_if_t<
std::is_same_v<std::optional<typename T::value_type>, T>>> {
template<typename A> MaybeMixin(A &&x) : o{std::move(x)} {}
using MaybeTrait = std::true_type;
MaybeMixin(MaybeMixin &&) = default;
MaybeMixin &operator=(MaybeMixin &&) = default;
MaybeMixin(const MaybeMixin &) = delete;
MaybeMixin &operator=(const MaybeMixin &) = delete;
MaybeMixin() = delete;
T o;
};
template<typename T, typename P> struct ChildMixin {
protected:
P *parent;
public:
ChildMixin(P *p) : parent{p} {}
inline const P *getParent() const { return parent; }
inline P *getParent() { return parent; }
llvm::iplist<T> &getList() { return parent->getSublist(this); }
};
template<typename A, typename B, typename C>
C Zip(C out, A first, A last, B other) {
std::transform(first, last, other, out,
[](auto &&a, auto &&b) -> std::pair<decltype(a), decltype(b)> {
return {a, b};
});
return out;
}
template<typename A, typename B> B &Unzip(B &out, A first, A last) {
std::transform(first, last, std::back_inserter(out.first),
[](auto &&a) -> decltype(a.first) { return a.first; });
std::transform(first, last, std::back_inserter(out.second),
[](auto &&a) -> decltype(a.second) { return a.second; });
return out;
}
}
#endif

View file

@ -1,86 +0,0 @@
// 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 "procedure.h"
namespace Fortran::IntermediateRepresentation {
Procedure::Procedure(Program *program, FunctionType *ty, LinkageTypes lt,
unsigned addrSpace, const llvm::Twine &n, Procedure *before)
: ChildMixin{program}, procType_{ty}, linkage_{lt},
addressSpace_{addrSpace}, name_{n.str()} {
Region::Create(this);
parent->insertBefore(this, before);
}
Procedure::~Procedure() { regionList_.clear(); }
Region *Procedure::insertBefore(Region *region, Region *before) {
if (before) {
regionList_.insert(before->getIterator(), region);
} else {
regionList_.push_back(region);
}
return region;
}
template<typename T>
static void AddCountScopes(
unsigned count, BasicBlock *block, T callback, semantics::Scope *scope) {
for (; count; --count) {
block->insertBefore(
new Statement(block, callback(scope)), block->getTerminator());
}
}
inline static void AddEnterScopes(unsigned count, BasicBlock *block) {
AddCountScopes(
count, block, ScopeEnterStmt::Create, /*TODO: thread scope? */ nullptr);
}
inline static void AddExitScopes(unsigned count, BasicBlock *block) {
AddCountScopes(
count, block, ScopeExitStmt::Create, /*TODO: thread scope? */ nullptr);
}
static bool DistinctScopes(Region *region1, Region *region2) {
return region1->HasScope() && region2->HasScope() &&
region1->GetScope() != region2->GetScope();
}
void Procedure::FlattenRegions() {
for (auto &block : GetBlocks()) {
auto *region{block.GetRegion()};
if (!region->IsOutermost()) {
for (auto *successor : succ_list(block)) {
auto *successorRegion{successor->GetRegion()};
if (successorRegion != region &&
DistinctScopes(successorRegion, region)) {
if (IsAncestor(region, successorRegion)) {
AddEnterScopes(RegionDepth(region, successorRegion),
successor->SplitEdge(&block));
} else if (IsAncestor(successorRegion, region)) {
AddExitScopes(RegionDepth(successorRegion, region),
block.SplitEdge(successor));
} else {
// TODO: edge to a cousin region
CHECK(false);
}
}
}
}
}
}
}

View file

@ -1,80 +0,0 @@
// 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_PROCEDURE_H_
#define FORTRAN_INTERMEDIATEREPRESENTATION_PROCEDURE_H_
#include "mixin.h"
#include "program.h"
#include "region.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
namespace Fortran::IntermediateRepresentation {
struct Program;
struct Region;
struct GraphWriter;
struct Procedure final : public llvm::ilist_node<Procedure>,
public ChildMixin<Procedure, Program> {
friend GraphWriter;
friend Program;
friend Region;
using BasicBlockListType = llvm::iplist<BasicBlock>;
using RegionListType = llvm::iplist<Region>;
using iterator = BasicBlockListType::iterator;
using const_iterator = BasicBlockListType::const_iterator;
using reverse_iterator = BasicBlockListType::reverse_iterator;
using const_reverse_iterator = BasicBlockListType::const_reverse_iterator;
Procedure(const Procedure &) = delete;
Procedure &operator=(const Procedure &) = delete;
~Procedure();
BasicBlockListType &GetBlocks() { return basicBlockList_; }
BasicBlockListType &getSublist(BasicBlock *) { return GetBlocks(); }
RegionListType &GetRegions() { return regionList_; }
RegionListType &getSublist(Region *) { return GetRegions(); }
iterator begin() { return basicBlockList_.begin(); }
const_iterator begin() const { return basicBlockList_.begin(); }
iterator end() { return basicBlockList_.end(); }
const_iterator end() const { return basicBlockList_.end(); }
Region *getLastRegion() { return &regionList_.back(); }
BasicBlock *StartBlock() { return &basicBlockList_.front(); }
static Procedure *Create(Program *prog, FunctionType *ty,
LinkageTypes linkage, unsigned addrSpace = 0u,
const llvm::Twine &name = "", Procedure *before = nullptr) {
return new Procedure(prog, ty, linkage, addrSpace, name, before);
}
void setParent(Program *p) { parent = p; }
bool hasName() const { return !getName().empty(); }
llvm::StringRef getName() const { return name_; }
void FlattenRegions();
private:
RegionListType regionList_;
BasicBlockListType basicBlockList_;
FunctionType *procType_;
LinkageTypes linkage_;
unsigned addressSpace_;
const std::string name_;
explicit Procedure(Program *program, FunctionType *ty, LinkageTypes lt,
unsigned addrSpace, const llvm::Twine &n, Procedure *before);
Region *insertBefore(Region *region, Region *before = nullptr);
};
}
#endif

View file

@ -1,48 +0,0 @@
// 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 "program.h"
namespace Fortran::IntermediateRepresentation {
Program::Program(llvm::StringRef id) : name_{id} {}
Program::~Program() { procedureMap_.clear(); }
void Program::insertBefore(Procedure *subprog, Procedure *before) {
if (before) {
procedureList_.insert(before->getIterator(), subprog);
} else {
procedureList_.push_back(subprog);
}
}
Procedure *Program::getOrInsertProcedure(
llvm::StringRef name, FunctionType *procTy, AttributeList attrs) {
llvm::StringMapEntry<Procedure *> *entry{nullptr};
if (!name.empty()) {
auto iter{procedureMap_.find(name)};
if (iter != procedureMap_.end()) {
return iter->getValue();
}
entry = &*procedureMap_.insert({name, nullptr}).first;
name = entry->getKey();
}
auto *subp{Procedure::Create(this, procTy, LinkageTypes::Public, 0u, name)};
if (entry) {
entry->setValue(subp);
}
return subp;
}
}

View file

@ -1,55 +0,0 @@
// 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_PROGRAM_H_
#define FORTRAN_INTERMEDIATEREPRESENTATION_PROGRAM_H_
#include "common.h"
#include "procedure.h"
#include "../evaluate/type.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
#include <string>
namespace Fortran::IntermediateRepresentation {
struct Procedure;
struct GraphWriter;
struct Program final {
friend GraphWriter;
using ProcedureListType = llvm::iplist<Procedure>;
using ProcedureMapType = llvm::StringMap<Procedure *>;
explicit Program(llvm::StringRef id);
~Program();
void insertBefore(Procedure *subprog, Procedure *before = nullptr);
ProcedureListType &getSublist(Procedure *) { return procedureList_; }
bool containsProcedure(llvm::StringRef name) {
return procedureMap_.find(name) != procedureMap_.end();
}
std::string getName() const { return name_; }
Procedure *getOrInsertProcedure(
llvm::StringRef name, FunctionType *procTy, AttributeList attrs);
private:
ProcedureListType procedureList_;
ProcedureMapType procedureMap_;
const std::string name_;
};
}
#endif

View file

@ -1,49 +0,0 @@
// 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 "program.h"
namespace Fortran::IntermediateRepresentation {
Region::Region(
Procedure *procedure, Scope *scope, Region *inRegion, Region *insertBefore)
: ChildMixin{procedure}, basicBlockList_{procedure->GetBlocks()},
enclosingRegion_{inRegion}, scope_{scope} {
if (enclosingRegion_) {
enclosingRegion_->getSublist(static_cast<Region *>(nullptr))
.push_back(this);
} else {
parent->insertBefore(this, insertBefore);
}
}
Region::~Region() { basicBlockList_.clear(); }
void Region::insertBefore(BasicBlock *block, BasicBlock *before) {
if (before) {
basicBlockList_.insert(before->getIterator(), block);
} else {
basicBlockList_.push_back(block);
}
}
std::vector<BasicBlock *> Region::getBlocks() {
std::vector<BasicBlock *> result;
for (auto &block : basicBlockList_) {
if (block.getParent() == this) result.push_back(&block);
}
return result;
}
}

View file

@ -1,91 +0,0 @@
// 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_REGION_H_
#define FORTRAN_INTERMEDIATEREPRESENTATION_REGION_H_
#include "procedure.h"
#include "stmt.h"
#include "../semantics/semantics.h"
namespace Fortran::IntermediateRepresentation {
struct Procedure;
struct BasicBlock;
struct Region final : public llvm::ilist_node<Region>,
public ChildMixin<Region, Procedure> {
friend Procedure;
friend BasicBlock;
using BasicBlockListType = llvm::iplist<BasicBlock>;
using AllocatableListType = std::list<const semantics::Symbol *>;
using SubregionListType = llvm::iplist<Region>;
using iterator = SubregionListType::iterator;
using const_iterator = SubregionListType::const_iterator;
using reverse_iterator = SubregionListType::reverse_iterator;
using const_reverse_iterator = SubregionListType::const_reverse_iterator;
Region(const Region &) = delete;
Region &operator=(const Region &) = delete;
~Region();
std::vector<BasicBlock *> getBlocks();
std::vector<BasicBlock *> getSublist(BasicBlock *) { return getBlocks(); }
SubregionListType &getSublist(Region *) { return subregionList_; }
iterator begin() { return subregionList_.begin(); }
const_iterator begin() const { return subregionList_.begin(); }
iterator end() { return subregionList_.end(); }
const_iterator end() const { return subregionList_.end(); }
Region *GetEnclosing() const { return enclosingRegion_; }
bool IsOutermost() const { return GetEnclosing() == nullptr; }
static Region *Create(Procedure *procedure, Scope *scope = nullptr,
Region *inRegion = nullptr, Region *insertBefore = nullptr) {
return new Region(procedure, scope, inRegion, insertBefore);
}
bool HasScope() const { return scope_.has_value(); }
Scope *GetScope() const { return scope_ ? scope_.value() : nullptr; }
private:
BasicBlockListType &basicBlockList_;
AllocatableListType allocatableList_;
SubregionListType subregionList_; // direct descendants
Region *enclosingRegion_; // parent in nesting tree
std::optional<Scope *> scope_;
explicit Region(Procedure *procedure, Scope *scope, Region *inRegion,
Region *insertBefore);
void insertBefore(BasicBlock *block, BasicBlock *before);
};
inline bool IsAncestor(const Region *fromRegion, const Region *toRegion) {
CHECK(fromRegion && toRegion);
for (const auto *region{fromRegion->GetEnclosing()}; region;
region = region->GetEnclosing()) {
if (region == toRegion) return true;
}
return false;
}
inline unsigned RegionDepth(const Region *fromRegion, const Region *toRegion) {
CHECK(IsAncestor(fromRegion, toRegion));
unsigned result{0u};
for (const auto *region{fromRegion}; region != toRegion;
region = region->GetEnclosing()) {
++result;
}
return result;
}
}
#endif

View file

@ -1,171 +0,0 @@
// 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

View file

@ -1,250 +0,0 @@
// 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);
}
}

View file

@ -1,470 +0,0 @@
// 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

View file

@ -1,50 +0,0 @@
// 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