blob: 29494de97372f22ffedb6e157b06f40f3f3d662b [file] [log] [blame]
Chris Lattnerc0c5e0f2018-06-21 09:49:33 -07001//===- Function.cpp - MLIR Function Classes -------------------------------===//
2//
3// Copyright 2019 The MLIR Authors.
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16// =============================================================================
Chris Lattnerc0c5e0f2018-06-21 09:49:33 -070017
Chris Lattner4613d9e2018-08-19 21:17:22 -070018#include "mlir/IR/Attributes.h"
Chris Lattner4c95a502018-06-23 16:03:42 -070019#include "mlir/IR/CFGFunction.h"
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -070020#include "mlir/IR/MLFunction.h"
Chris Lattner791813d2018-09-07 09:08:13 -070021#include "mlir/IR/MLIRContext.h"
Chris Lattnera8e47672018-07-25 14:08:16 -070022#include "mlir/IR/Module.h"
Tatiana Shpeisman60bf7be2018-07-26 18:09:20 -070023#include "mlir/IR/StmtVisitor.h"
Chris Lattnerff0d5902018-07-05 09:12:11 -070024#include "mlir/IR/Types.h"
Chris Lattner974a8762018-08-17 16:49:42 -070025#include "llvm/ADT/SmallString.h"
Chris Lattner4c95a502018-06-23 16:03:42 -070026#include "llvm/ADT/StringRef.h"
Chris Lattnerc0c5e0f2018-06-21 09:49:33 -070027using namespace mlir;
28
Chris Lattner791813d2018-09-07 09:08:13 -070029Function::Function(Kind kind, Location *location, StringRef name,
30 FunctionType *type)
31 : nameAndKind(Identifier::get(name, type->getContext()), kind),
32 location(location), type(type) {}
Chris Lattnerc0c5e0f2018-06-21 09:49:33 -070033
Chris Lattner4613d9e2018-08-19 21:17:22 -070034Function::~Function() {
35 // Clean up function attributes referring to this function.
36 FunctionAttr::dropFunctionReference(this);
37}
38
Chris Lattnerff0d5902018-07-05 09:12:11 -070039MLIRContext *Function::getContext() const { return getType()->getContext(); }
40
Chris Lattnera8e47672018-07-25 14:08:16 -070041/// Delete this object.
42void Function::destroy() {
43 switch (getKind()) {
44 case Kind::ExtFunc:
45 delete cast<ExtFunction>(this);
46 break;
47 case Kind::MLFunc:
Tatiana Shpeismanbc3c7492018-08-06 11:54:39 -070048 cast<MLFunction>(this)->destroy();
Chris Lattnera8e47672018-07-25 14:08:16 -070049 break;
50 case Kind::CFGFunc:
51 delete cast<CFGFunction>(this);
52 break;
53 }
54}
55
56Module *llvm::ilist_traits<Function>::getContainingModule() {
57 size_t Offset(
58 size_t(&((Module *)nullptr->*Module::getSublistAccess(nullptr))));
59 iplist<Function> *Anchor(static_cast<iplist<Function> *>(this));
60 return reinterpret_cast<Module *>(reinterpret_cast<char *>(Anchor) - Offset);
61}
62
63/// This is a trait method invoked when a Function is added to a Module. We
Chris Lattner974a8762018-08-17 16:49:42 -070064/// keep the module pointer and module symbol table up to date.
Chris Lattnera8e47672018-07-25 14:08:16 -070065void llvm::ilist_traits<Function>::addNodeToList(Function *function) {
66 assert(!function->getModule() && "already in a module!");
Chris Lattner974a8762018-08-17 16:49:42 -070067 auto *module = getContainingModule();
68 function->module = module;
69
70 // Add this function to the symbol table of the module, uniquing the name if
71 // a conflict is detected.
Chris Lattner791813d2018-09-07 09:08:13 -070072 if (!module->symbolTable.insert({function->getName(), function}).second) {
Chris Lattner974a8762018-08-17 16:49:42 -070073 // If a conflict was detected, then the function will not have been added to
74 // the symbol table. Try suffixes until we get to a unique name that works.
75 SmallString<128> nameBuffer(function->getName().begin(),
76 function->getName().end());
77 unsigned originalLength = nameBuffer.size();
78
79 // Iteratively try suffixes until we find one that isn't used. We use a
80 // module level uniquing counter to avoid N^2 behavior.
81 do {
82 nameBuffer.resize(originalLength);
83 nameBuffer += '_';
84 nameBuffer += std::to_string(module->uniquingCounter++);
Chris Lattner791813d2018-09-07 09:08:13 -070085 function->nameAndKind.setPointer(
86 Identifier::get(nameBuffer, module->getContext()));
87 } while (
88 !module->symbolTable.insert({function->getName(), function}).second);
Chris Lattner974a8762018-08-17 16:49:42 -070089 }
Chris Lattnera8e47672018-07-25 14:08:16 -070090}
91
92/// This is a trait method invoked when a Function is removed from a Module.
93/// We keep the module pointer up to date.
94void llvm::ilist_traits<Function>::removeNodeFromList(Function *function) {
95 assert(function->module && "not already in a module!");
Chris Lattner974a8762018-08-17 16:49:42 -070096
97 // Remove the symbol table entry.
98 function->module->symbolTable.erase(function->getName());
Chris Lattnera8e47672018-07-25 14:08:16 -070099 function->module = nullptr;
100}
101
102/// This is a trait method invoked when an instruction is moved from one block
103/// to another. We keep the block pointer up to date.
104void llvm::ilist_traits<Function>::transferNodesFromList(
105 ilist_traits<Function> &otherList, function_iterator first,
106 function_iterator last) {
107 // If we are transferring functions within the same module, the Module
108 // pointer doesn't need to be updated.
109 Module *curParent = getContainingModule();
110 if (curParent == otherList.getContainingModule())
111 return;
112
Chris Lattner974a8762018-08-17 16:49:42 -0700113 // Update the 'module' member and symbol table records for each function.
114 for (; first != last; ++first) {
115 removeNodeFromList(&*first);
116 addNodeToList(&*first);
117 }
Chris Lattnera8e47672018-07-25 14:08:16 -0700118}
119
120/// Unlink this function from its Module and delete it.
121void Function::eraseFromModule() {
122 assert(getModule() && "Function has no parent");
123 getModule()->getFunctions().erase(this);
124}
125
Chris Lattner791813d2018-09-07 09:08:13 -0700126/// Emit a note about this instruction, reporting up to any diagnostic
127/// handlers that may be listening.
128void Function::emitNote(const Twine &message) const {
129 getContext()->emitDiagnostic(getLoc(), message,
130 MLIRContext::DiagnosticKind::Note);
131}
132
133/// Emit a warning about this operation, reporting up to any diagnostic
134/// handlers that may be listening.
135void Function::emitWarning(const Twine &message) const {
136 getContext()->emitDiagnostic(getLoc(), message,
137 MLIRContext::DiagnosticKind::Warning);
138}
139
140/// Emit an error about fatal conditions with this instruction, reporting up to
141/// any diagnostic handlers that may be listening. NOTE: This may terminate
142/// the containing application, only use when the IR is in an inconsistent
143/// state.
144void Function::emitError(const Twine &message) const {
145 getContext()->emitDiagnostic(getLoc(), message,
146 MLIRContext::DiagnosticKind::Error);
147}
Chris Lattner4c95a502018-06-23 16:03:42 -0700148//===----------------------------------------------------------------------===//
149// ExtFunction implementation.
150//===----------------------------------------------------------------------===//
Chris Lattnerf7e22732018-06-22 22:03:48 -0700151
Chris Lattner791813d2018-09-07 09:08:13 -0700152ExtFunction::ExtFunction(Location *location, StringRef name, FunctionType *type)
153 : Function(Kind::ExtFunc, location, name, type) {}
Chris Lattnere2259872018-06-21 15:22:42 -0700154
Chris Lattner4c95a502018-06-23 16:03:42 -0700155//===----------------------------------------------------------------------===//
156// CFGFunction implementation.
157//===----------------------------------------------------------------------===//
158
Chris Lattner791813d2018-09-07 09:08:13 -0700159CFGFunction::CFGFunction(Location *location, StringRef name, FunctionType *type)
160 : Function(Kind::CFGFunc, location, name, type) {}
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -0700161
Chris Lattnera8e47672018-07-25 14:08:16 -0700162CFGFunction::~CFGFunction() {
163 // Instructions may have cyclic references, which need to be dropped before we
164 // can start deleting them.
165 for (auto &bb : *this) {
166 for (auto &inst : bb)
167 inst.dropAllReferences();
James Molloyf8bbadb2018-08-01 11:53:50 -0700168 if (bb.getTerminator())
169 bb.getTerminator()->dropAllReferences();
Chris Lattnera8e47672018-07-25 14:08:16 -0700170 }
171}
172
Tatiana Shpeismanc96b5872018-06-28 17:02:32 -0700173//===----------------------------------------------------------------------===//
174// MLFunction implementation.
175//===----------------------------------------------------------------------===//
176
Tatiana Shpeismanbc3c7492018-08-06 11:54:39 -0700177/// Create a new MLFunction with the specific fields.
Chris Lattner791813d2018-09-07 09:08:13 -0700178MLFunction *MLFunction::create(Location *location, StringRef name,
179 FunctionType *type) {
Tatiana Shpeismanbc3c7492018-08-06 11:54:39 -0700180 const auto &argTypes = type->getInputs();
181 auto byteSize = totalSizeToAlloc<MLFuncArgument>(argTypes.size());
182 void *rawMem = malloc(byteSize);
183
184 // Initialize the MLFunction part of the function object.
Chris Lattner791813d2018-09-07 09:08:13 -0700185 auto function = ::new (rawMem) MLFunction(location, name, type);
Tatiana Shpeismanbc3c7492018-08-06 11:54:39 -0700186
187 // Initialize the arguments.
188 auto arguments = function->getArgumentsInternal();
189 for (unsigned i = 0, e = argTypes.size(); i != e; ++i)
190 new (&arguments[i]) MLFuncArgument(argTypes[i], function);
191 return function;
192}
193
Chris Lattner791813d2018-09-07 09:08:13 -0700194MLFunction::MLFunction(Location *location, StringRef name, FunctionType *type)
195 : Function(Kind::MLFunc, location, name, type),
196 StmtBlock(StmtBlockKind::MLFunc) {}
Chris Lattnera8e47672018-07-25 14:08:16 -0700197
198MLFunction::~MLFunction() {
Tatiana Shpeismanbc3c7492018-08-06 11:54:39 -0700199 // Explicitly erase statements instead of relying of 'StmtBlock' destructor
200 // since child statements need to be destroyed before function arguments
201 // are destroyed.
202 clear();
203
204 // Explicitly run the destructors for the function arguments.
205 for (auto &arg : getArgumentsInternal())
206 arg.~MLFuncArgument();
207}
208
209void MLFunction::destroy() {
210 this->~MLFunction();
211 free(this);
Chris Lattnera8e47672018-07-25 14:08:16 -0700212}
Uday Bondhugula2ce3b572018-08-13 11:30:36 -0700213
214const OperationStmt *MLFunction::getReturnStmt() const {
215 return cast<OperationStmt>(&back());
216}
217
218OperationStmt *MLFunction::getReturnStmt() {
219 return cast<OperationStmt>(&back());
220}