| //===- BasicBlock.cpp - MLIR BasicBlock Class -----------------------------===// | |
| // | |
| // Copyright 2019 The MLIR Authors. | |
| // | |
| // 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 "mlir/IR/BasicBlock.h" | |
| #include "mlir/IR/CFGFunction.h" | |
| using namespace mlir; | |
| BasicBlock::BasicBlock() {} | |
| BasicBlock::~BasicBlock() { | |
| if (terminator) | |
| terminator->eraseFromBlock(); | |
| for (BBArgument *arg : arguments) | |
| delete arg; | |
| arguments.clear(); | |
| } | |
| //===----------------------------------------------------------------------===// | |
| // Argument list management. | |
| //===----------------------------------------------------------------------===// | |
| BBArgument *BasicBlock::addArgument(Type *type) { | |
| auto *arg = new BBArgument(type, this); | |
| arguments.push_back(arg); | |
| return arg; | |
| } | |
| /// Add one argument to the argument list for each type specified in the list. | |
| auto BasicBlock::addArguments(ArrayRef<Type *> types) | |
| -> llvm::iterator_range<args_iterator> { | |
| arguments.reserve(arguments.size() + types.size()); | |
| auto initialSize = arguments.size(); | |
| for (auto *type : types) { | |
| addArgument(type); | |
| } | |
| return {arguments.data() + initialSize, arguments.data() + arguments.size()}; | |
| } | |
| //===----------------------------------------------------------------------===// | |
| // Terminator management | |
| //===----------------------------------------------------------------------===// | |
| void BasicBlock::setTerminator(TerminatorInst *inst) { | |
| assert((!inst || !inst->block) && "terminator already inserted into a block"); | |
| // If we already had a terminator, abandon it. | |
| if (terminator) | |
| terminator->block = nullptr; | |
| // Reset our terminator to the new instruction. | |
| terminator = inst; | |
| if (inst) | |
| inst->block = this; | |
| } | |
| /// Return true if this block has no predecessors. | |
| bool BasicBlock::hasNoPredecessors() const { | |
| return pred_begin() == pred_end(); | |
| } | |
| /// If this basic block has exactly one predecessor, return it. Otherwise, | |
| /// return null. | |
| /// | |
| /// Note that multiple edges from a single block (e.g. if you have a cond | |
| /// branch with the same block as the true/false destinations) is not | |
| /// considered to be a single predecessor. | |
| BasicBlock *BasicBlock::getSinglePredecessor() { | |
| auto it = pred_begin(); | |
| if (it == pred_end()) | |
| return nullptr; | |
| auto *firstPred = *it; | |
| ++it; | |
| return it == pred_end() ? firstPred : nullptr; | |
| } | |
| //===----------------------------------------------------------------------===// | |
| // ilist_traits for BasicBlock | |
| //===----------------------------------------------------------------------===// | |
| mlir::CFGFunction * | |
| llvm::ilist_traits<::mlir::BasicBlock>::getContainingFunction() { | |
| size_t Offset( | |
| size_t(&((CFGFunction *)nullptr->*CFGFunction::getSublistAccess(nullptr)))); | |
| iplist<BasicBlock> *Anchor(static_cast<iplist<BasicBlock> *>(this)); | |
| return reinterpret_cast<CFGFunction *>(reinterpret_cast<char *>(Anchor) - | |
| Offset); | |
| } | |
| /// This is a trait method invoked when a basic block is added to a function. | |
| /// We keep the function pointer up to date. | |
| void llvm::ilist_traits<::mlir::BasicBlock>:: | |
| addNodeToList(BasicBlock *block) { | |
| assert(!block->function && "already in a function!"); | |
| block->function = getContainingFunction(); | |
| } | |
| /// This is a trait method invoked when an instruction is removed from a | |
| /// function. We keep the function pointer up to date. | |
| void llvm::ilist_traits<::mlir::BasicBlock>:: | |
| removeNodeFromList(BasicBlock *block) { | |
| assert(block->function && "not already in a function!"); | |
| block->function = 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<::mlir::BasicBlock>:: | |
| transferNodesFromList(ilist_traits<BasicBlock> &otherList, | |
| block_iterator first, block_iterator last) { | |
| // If we are transferring instructions within the same function, the parent | |
| // pointer doesn't need to be updated. | |
| CFGFunction *curParent = getContainingFunction(); | |
| if (curParent == otherList.getContainingFunction()) | |
| return; | |
| // Update the 'function' member of each BasicBlock. | |
| for (; first != last; ++first) | |
| first->function = curParent; | |
| } | |
| //===----------------------------------------------------------------------===// | |
| // Manipulators | |
| //===----------------------------------------------------------------------===// | |
| /// Unlink this BasicBlock from its CFGFunction and delete it. | |
| void BasicBlock::eraseFromFunction() { | |
| assert(getFunction() && "BasicBlock has no parent"); | |
| getFunction()->getBlocks().erase(this); | |
| } | |
| /// Split the basic block into two basic blocks before the specified | |
| /// instruction or iterator. | |
| /// | |
| /// Note that all instructions BEFORE the specified iterator stay as part of | |
| /// the original basic block, an unconditional branch is added to the original | |
| /// block (going to the new block), and the rest of the instructions in the | |
| /// original block are moved to the new BB, including the old terminator. The | |
| /// newly formed BasicBlock is returned. | |
| /// | |
| /// This function invalidates the specified iterator. | |
| BasicBlock *BasicBlock::splitBasicBlock(iterator splitBefore) { | |
| // Start by creating a new basic block, and insert it immediate after this | |
| // one in the containing function. | |
| auto newBB = new BasicBlock(); | |
| getFunction()->getBlocks().insert(++CFGFunction::iterator(this), newBB); | |
| // Create an unconditional branch to the new block, and move our terminator | |
| // to the new block. | |
| auto *branchLoc = | |
| splitBefore == end() ? getTerminator()->getLoc() : splitBefore->getLoc(); | |
| auto oldTerm = getTerminator(); | |
| setTerminator(BranchInst::create(branchLoc, newBB)); | |
| newBB->setTerminator(oldTerm); | |
| // Move all of the operations from the split point to the end of the function | |
| // into the new block. | |
| newBB->getOperations().splice(newBB->end(), getOperations(), splitBefore, | |
| end()); | |
| return newBB; | |
| } |