[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:
parent
1ee88d3c81
commit
ddedf6688b
20 changed files with 0 additions and 4075 deletions
File diff suppressed because it is too large
Load diff
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
|
@ -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";
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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 ®ion, 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});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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 ®ion) {
|
||||
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 ®ion, 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
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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 ®ionList_.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
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
|
@ -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
|
Loading…
Reference in a new issue