Implement a proper function list in module, which auto-maintain the parent
pointer, and ensure that functions are deleted when the module is destroyed.
This exposed the fact that MLFunction had no dtor, and that the dtor in
CFGFunction was broken with cyclic references. Fix both of these problems.
PiperOrigin-RevId: 206051666
diff --git a/lib/IR/AsmPrinter.cpp b/lib/IR/AsmPrinter.cpp
index e23964d..4fd7e61 100644
--- a/lib/IR/AsmPrinter.cpp
+++ b/lib/IR/AsmPrinter.cpp
@@ -157,8 +157,8 @@
// Initializes module state, populating affine map state.
void ModuleState::initialize(const Module *module) {
- for (auto fn : module->functionList) {
- visitFunction(fn);
+ for (auto &fn : *module) {
+ visitFunction(&fn);
}
}
@@ -236,8 +236,8 @@
map->print(os);
os << '\n';
}
- for (auto *fn : module->functionList)
- print(fn);
+ for (auto const &fn : *module)
+ print(&fn);
}
void ModulePrinter::printAttribute(const Attribute *attr) {
diff --git a/lib/IR/Function.cpp b/lib/IR/Function.cpp
index 72ec443..8476b06 100644
--- a/lib/IR/Function.cpp
+++ b/lib/IR/Function.cpp
@@ -17,6 +17,7 @@
#include "mlir/IR/CFGFunction.h"
#include "mlir/IR/MLFunction.h"
+#include "mlir/IR/Module.h"
#include "mlir/IR/Types.h"
#include "llvm/ADT/StringRef.h"
using namespace mlir;
@@ -27,6 +28,64 @@
MLIRContext *Function::getContext() const { return getType()->getContext(); }
+/// Delete this object.
+void Function::destroy() {
+ switch (getKind()) {
+ case Kind::ExtFunc:
+ delete cast<ExtFunction>(this);
+ break;
+ case Kind::MLFunc:
+ delete cast<MLFunction>(this);
+ break;
+ case Kind::CFGFunc:
+ delete cast<CFGFunction>(this);
+ break;
+ }
+}
+
+Module *llvm::ilist_traits<Function>::getContainingModule() {
+ size_t Offset(
+ size_t(&((Module *)nullptr->*Module::getSublistAccess(nullptr))));
+ iplist<Function> *Anchor(static_cast<iplist<Function> *>(this));
+ return reinterpret_cast<Module *>(reinterpret_cast<char *>(Anchor) - Offset);
+}
+
+/// This is a trait method invoked when a Function is added to a Module. We
+/// keep the module pointer up to date.
+void llvm::ilist_traits<Function>::addNodeToList(Function *function) {
+ assert(!function->getModule() && "already in a module!");
+ function->module = getContainingModule();
+}
+
+/// This is a trait method invoked when a Function is removed from a Module.
+/// We keep the module pointer up to date.
+void llvm::ilist_traits<Function>::removeNodeFromList(Function *function) {
+ assert(function->module && "not already in a module!");
+ function->module = nullptr;
+}
+
+/// This is a trait method invoked when an instruction is moved from one block
+/// to another. We keep the block pointer up to date.
+void llvm::ilist_traits<Function>::transferNodesFromList(
+ ilist_traits<Function> &otherList, function_iterator first,
+ function_iterator last) {
+ // If we are transferring functions within the same module, the Module
+ // pointer doesn't need to be updated.
+ Module *curParent = getContainingModule();
+ if (curParent == otherList.getContainingModule())
+ return;
+
+ // Update the 'module' member of each function.
+ for (; first != last; ++first)
+ first->module = curParent;
+}
+
+/// Unlink this function from its Module and delete it.
+void Function::eraseFromModule() {
+ assert(getModule() && "Function has no parent");
+ getModule()->getFunctions().erase(this);
+}
+
//===----------------------------------------------------------------------===//
// ExtFunction implementation.
//===----------------------------------------------------------------------===//
@@ -43,9 +102,23 @@
: Function(name, type, Kind::CFGFunc) {
}
+CFGFunction::~CFGFunction() {
+ // Instructions may have cyclic references, which need to be dropped before we
+ // can start deleting them.
+ for (auto &bb : *this) {
+ for (auto &inst : bb)
+ inst.dropAllReferences();
+ }
+}
+
//===----------------------------------------------------------------------===//
// MLFunction implementation.
//===----------------------------------------------------------------------===//
MLFunction::MLFunction(StringRef name, FunctionType *type)
: Function(name, type, Kind::MLFunc), StmtBlock(StmtBlockKind::MLFunc) {}
+
+MLFunction::~MLFunction() {
+ // TODO: When move SSA stuff is supported.
+ // dropAllReferences();
+}
diff --git a/lib/IR/Instructions.cpp b/lib/IR/Instructions.cpp
index 8cbdabc..a1cdcb3 100644
--- a/lib/IR/Instructions.cpp
+++ b/lib/IR/Instructions.cpp
@@ -99,6 +99,14 @@
}
}
+/// This drops all operand uses from this instruction, which is an essential
+/// step in breaking cyclic dependences between references when they are to
+/// be deleted.
+void Instruction::dropAllReferences() {
+ for (auto &op : getInstOperands())
+ op.drop();
+}
+
//===----------------------------------------------------------------------===//
// OperationInst
//===----------------------------------------------------------------------===//
diff --git a/lib/IR/Verifier.cpp b/lib/IR/Verifier.cpp
index 96f7f73..9e52556 100644
--- a/lib/IR/Verifier.cpp
+++ b/lib/IR/Verifier.cpp
@@ -330,8 +330,8 @@
bool Module::verify(std::string *errorResult) const {
/// Check that each function is correct.
- for (auto fn : functionList) {
- if (fn->verify(errorResult))
+ for (auto &fn : *this) {
+ if (fn.verify(errorResult))
return true;
}