222 lines
7.8 KiB
C++
222 lines
7.8 KiB
C++
//===- Instructions.cpp - MLIR CFGFunction Instruction Classes ------------===//
|
|
//
|
|
// 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/Instructions.h"
|
|
#include "mlir/IR/BasicBlock.h"
|
|
using namespace mlir;
|
|
|
|
/// Replace all uses of 'this' value with the new value, updating anything in
|
|
/// the IR that uses 'this' to use the other value instead. When this returns
|
|
/// there are zero uses of 'this'.
|
|
void SSAValue::replaceAllUsesWith(SSAValue *newValue) {
|
|
assert(this != newValue && "cannot RAUW a value with itself");
|
|
while (!use_empty()) {
|
|
use_begin()->set(newValue);
|
|
}
|
|
}
|
|
|
|
/// Return the result number of this result.
|
|
unsigned InstResult::getResultNumber() const {
|
|
// Results are always stored consecutively, so use pointer subtraction to
|
|
// figure out what number this is.
|
|
return this - &getOwner()->getInstResults()[0];
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Instruction
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Instructions are deleted through the destroy() member because we don't have
|
|
// a virtual destructor.
|
|
Instruction::~Instruction() {
|
|
assert(block == nullptr && "instruction destroyed but still in a block");
|
|
}
|
|
|
|
/// Destroy this instruction or one of its subclasses.
|
|
void Instruction::destroy() {
|
|
switch (getKind()) {
|
|
case Kind::Operation:
|
|
cast<OperationInst>(this)->destroy();
|
|
break;
|
|
case Kind::Branch:
|
|
delete cast<BranchInst>(this);
|
|
break;
|
|
case Kind::Return:
|
|
cast<ReturnInst>(this)->destroy();
|
|
break;
|
|
}
|
|
}
|
|
|
|
void OperationInst::destroy() {
|
|
this->~OperationInst();
|
|
free(this);
|
|
}
|
|
|
|
CFGFunction *Instruction::getFunction() const {
|
|
return getBlock()->getFunction();
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// OperationInst
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// Create a new OperationInst with the specific fields.
|
|
OperationInst *OperationInst::create(Identifier name,
|
|
ArrayRef<CFGValue *> operands,
|
|
ArrayRef<Type *> resultTypes,
|
|
ArrayRef<NamedAttribute> attributes,
|
|
MLIRContext *context) {
|
|
auto byteSize = totalSizeToAlloc<InstOperand, InstResult>(operands.size(),
|
|
resultTypes.size());
|
|
void *rawMem = malloc(byteSize);
|
|
|
|
// Initialize the OperationInst part of the instruction.
|
|
auto inst = ::new (rawMem) OperationInst(
|
|
name, operands.size(), resultTypes.size(), attributes, context);
|
|
|
|
// Initialize the operands and results.
|
|
auto instOperands = inst->getInstOperands();
|
|
for (unsigned i = 0, e = operands.size(); i != e; ++i)
|
|
new (&instOperands[i]) InstOperand(inst, operands[i]);
|
|
|
|
auto instResults = inst->getInstResults();
|
|
for (unsigned i = 0, e = resultTypes.size(); i != e; ++i)
|
|
new (&instResults[i]) InstResult(resultTypes[i], inst);
|
|
return inst;
|
|
}
|
|
|
|
OperationInst::OperationInst(Identifier name, unsigned numOperands,
|
|
unsigned numResults,
|
|
ArrayRef<NamedAttribute> attributes,
|
|
MLIRContext *context)
|
|
: Operation(name, /*isInstruction=*/ true, attributes, context),
|
|
Instruction(Kind::Operation), numOperands(numOperands),
|
|
numResults(numResults) {}
|
|
|
|
OperationInst::~OperationInst() {
|
|
// Explicitly run the destructors for the operands and results.
|
|
for (auto &operand : getInstOperands())
|
|
operand.~InstOperand();
|
|
|
|
for (auto &result : getInstResults())
|
|
result.~InstResult();
|
|
}
|
|
|
|
mlir::BasicBlock *
|
|
llvm::ilist_traits<::mlir::OperationInst>::getContainingBlock() {
|
|
size_t Offset(
|
|
size_t(&((BasicBlock *)nullptr->*BasicBlock::getSublistAccess(nullptr))));
|
|
iplist<OperationInst> *Anchor(static_cast<iplist<OperationInst> *>(this));
|
|
return reinterpret_cast<BasicBlock *>(reinterpret_cast<char *>(Anchor) -
|
|
Offset);
|
|
}
|
|
|
|
/// This is a trait method invoked when an instruction is added to a block. We
|
|
/// keep the block pointer up to date.
|
|
void llvm::ilist_traits<::mlir::OperationInst>::
|
|
addNodeToList(OperationInst *inst) {
|
|
assert(!inst->getBlock() && "already in a basic block!");
|
|
inst->block = getContainingBlock();
|
|
}
|
|
|
|
/// This is a trait method invoked when an instruction is removed from a block.
|
|
/// We keep the block pointer up to date.
|
|
void llvm::ilist_traits<::mlir::OperationInst>::
|
|
removeNodeFromList(OperationInst *inst) {
|
|
assert(inst->block && "not already in a basic block!");
|
|
inst->block = 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::OperationInst>::
|
|
transferNodesFromList(ilist_traits<OperationInst> &otherList,
|
|
instr_iterator first, instr_iterator last) {
|
|
// If we are transferring instructions within the same basic block, the block
|
|
// pointer doesn't need to be updated.
|
|
BasicBlock *curParent = getContainingBlock();
|
|
if (curParent == otherList.getContainingBlock())
|
|
return;
|
|
|
|
// Update the 'block' member of each instruction.
|
|
for (; first != last; ++first)
|
|
first->block = curParent;
|
|
}
|
|
|
|
/// Unlink this instruction from its BasicBlock and delete it.
|
|
void OperationInst::eraseFromBlock() {
|
|
assert(getBlock() && "Instruction has no parent");
|
|
getBlock()->getOperations().erase(this);
|
|
}
|
|
|
|
/// If this value is the result of an OperationInst, return the instruction
|
|
/// that defines it.
|
|
OperationInst *SSAValue::getDefiningInst() {
|
|
if (auto *result = dyn_cast<InstResult>(this))
|
|
return result->getOwner();
|
|
return nullptr;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Terminators
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// Remove this terminator from its BasicBlock and delete it.
|
|
void TerminatorInst::eraseFromBlock() {
|
|
assert(getBlock() && "Instruction has no parent");
|
|
getBlock()->setTerminator(nullptr);
|
|
destroy();
|
|
}
|
|
|
|
/// Create a new OperationInst with the specific fields.
|
|
ReturnInst *ReturnInst::create(ArrayRef<CFGValue *> operands) {
|
|
auto byteSize = totalSizeToAlloc<InstOperand>(operands.size());
|
|
void *rawMem = malloc(byteSize);
|
|
|
|
// Initialize the ReturnInst part of the instruction.
|
|
auto inst = ::new (rawMem) ReturnInst(operands.size());
|
|
|
|
// Initialize the operands and results.
|
|
auto instOperands = inst->getInstOperands();
|
|
for (unsigned i = 0, e = operands.size(); i != e; ++i)
|
|
new (&instOperands[i]) InstOperand(inst, operands[i]);
|
|
return inst;
|
|
}
|
|
|
|
void ReturnInst::destroy() {
|
|
this->~ReturnInst();
|
|
free(this);
|
|
}
|
|
|
|
ReturnInst::~ReturnInst() {
|
|
// Explicitly run the destructors for the operands.
|
|
for (auto &operand : getInstOperands())
|
|
operand.~InstOperand();
|
|
}
|
|
|
|
/// Add one value to the operand list.
|
|
void BranchInst::addOperand(CFGValue *value) {
|
|
operands.emplace_back(InstOperand(this, value));
|
|
}
|
|
|
|
/// Add a list of values to the operand list.
|
|
void BranchInst::addOperands(ArrayRef<CFGValue *> values) {
|
|
operands.reserve(operands.size() + values.size());
|
|
for (auto *value : values)
|
|
addOperand(value);
|
|
}
|