mirror of
https://github.com/intel/llvm.git
synced 2026-01-26 03:56:16 +08:00
Rename the Instruction class to Operation. This just renames the class, usages of Instruction will still refer to a typedef in the interim.
This is step 1/N to renaming Instruction to Operation. PiperOrigin-RevId: 240431520
This commit is contained in:
@@ -35,7 +35,8 @@ class AffineApplyOp;
|
||||
class AffineForOp;
|
||||
class AffineValueMap;
|
||||
class FlatAffineConstraints;
|
||||
class Instruction;
|
||||
class Operation;
|
||||
using Instruction = Operation;
|
||||
class Value;
|
||||
|
||||
/// Returns in `affineApplyOps`, the sequence of those AffineApplyOp
|
||||
|
||||
@@ -31,7 +31,8 @@ namespace mlir {
|
||||
class AffineExpr;
|
||||
class AffineForOp;
|
||||
class AffineMap;
|
||||
class Instruction;
|
||||
class Operation;
|
||||
using Instruction = Operation;
|
||||
class MemRefType;
|
||||
class Value;
|
||||
|
||||
|
||||
@@ -24,7 +24,8 @@
|
||||
namespace mlir {
|
||||
|
||||
struct NestedPattern;
|
||||
class Instruction;
|
||||
class Operation;
|
||||
using Instruction = Operation;
|
||||
|
||||
/// An NestedPattern captures nested patterns in the IR.
|
||||
/// It is used in conjunction with a scoped NestedPatternContext which is an
|
||||
|
||||
@@ -27,7 +27,8 @@
|
||||
|
||||
namespace mlir {
|
||||
|
||||
class Instruction;
|
||||
class Operation;
|
||||
using Instruction = Operation;
|
||||
|
||||
/// Type of the condition to limit the propagation of transitive use-defs.
|
||||
/// This can be used in particular to limit the propagation to a given Scope or
|
||||
|
||||
@@ -38,10 +38,10 @@ namespace mlir {
|
||||
class AffineForOp;
|
||||
class Block;
|
||||
class FlatAffineConstraints;
|
||||
class Instruction;
|
||||
class Location;
|
||||
class MemRefAccess;
|
||||
class Instruction;
|
||||
class Operation;
|
||||
using Instruction = Operation;
|
||||
class Value;
|
||||
|
||||
/// Populates 'loops' with IVs of the loops surrounding 'inst' ordered from
|
||||
|
||||
@@ -28,9 +28,10 @@ class AffineApplyOp;
|
||||
class AffineForOp;
|
||||
class AffineMap;
|
||||
class FuncBuilder;
|
||||
class Instruction;
|
||||
class Location;
|
||||
class MemRefType;
|
||||
class Operation;
|
||||
using Instruction = Operation;
|
||||
class Value;
|
||||
class VectorType;
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#define MLIR_IR_BUILDERS_H
|
||||
|
||||
#include "mlir/IR/Function.h"
|
||||
#include "mlir/IR/Instruction.h"
|
||||
#include "mlir/IR/Operation.h"
|
||||
|
||||
namespace mlir {
|
||||
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
#include "mlir/IR/Attributes.h"
|
||||
#include "mlir/IR/Block.h"
|
||||
#include "mlir/IR/Identifier.h"
|
||||
#include "mlir/IR/Instruction.h"
|
||||
#include "mlir/IR/Location.h"
|
||||
#include "mlir/IR/Operation.h"
|
||||
#include "mlir/IR/Types.h"
|
||||
#include "mlir/Support/LLVM.h"
|
||||
#include "llvm/ADT/ilist.h"
|
||||
|
||||
@@ -1,171 +0,0 @@
|
||||
//===- InstructionSupport.h - MLIR Instruction Utilities --------*- C++ -*-===//
|
||||
//
|
||||
// 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.
|
||||
// =============================================================================
|
||||
//
|
||||
// This file defines utilities for the Instruction class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef MLIR_IR_INSTRUCTION_SUPPORT_H
|
||||
#define MLIR_IR_INSTRUCTION_SUPPORT_H
|
||||
|
||||
#include "mlir/IR/OperationSupport.h"
|
||||
#include "mlir/IR/Value.h"
|
||||
#include "mlir/Support/LLVM.h"
|
||||
#include "llvm/Support/TrailingObjects.h"
|
||||
|
||||
namespace mlir {
|
||||
class Instruction;
|
||||
|
||||
namespace detail {
|
||||
/// A utility class holding the information necessary to dynamically resize
|
||||
/// operands.
|
||||
struct ResizableStorage {
|
||||
ResizableStorage(InstOperand *opBegin, unsigned numOperands)
|
||||
: firstOpAndIsDynamic(opBegin, false), capacity(numOperands) {}
|
||||
|
||||
~ResizableStorage() { cleanupStorage(); }
|
||||
|
||||
/// Cleanup any allocated storage.
|
||||
void cleanupStorage() {
|
||||
// If the storage is dynamic, then we need to free the storage.
|
||||
if (isStorageDynamic())
|
||||
free(firstOpAndIsDynamic.getPointer());
|
||||
}
|
||||
|
||||
/// Sets the storage pointer to a new dynamically allocated block.
|
||||
void setDynamicStorage(InstOperand *opBegin) {
|
||||
/// Cleanup the old storage if necessary.
|
||||
cleanupStorage();
|
||||
firstOpAndIsDynamic.setPointerAndInt(opBegin, true);
|
||||
}
|
||||
|
||||
/// Returns the current storage pointer.
|
||||
InstOperand *getPointer() { return firstOpAndIsDynamic.getPointer(); }
|
||||
const InstOperand *getPointer() const {
|
||||
return firstOpAndIsDynamic.getPointer();
|
||||
}
|
||||
|
||||
/// Returns if the current storage of operands is in the trailing objects is
|
||||
/// in a dynamically allocated memory block.
|
||||
bool isStorageDynamic() const { return firstOpAndIsDynamic.getInt(); }
|
||||
|
||||
/// A pointer to the first operand element. This is either to the trailing
|
||||
/// objects storage, or a dynamically allocated block of memory.
|
||||
llvm::PointerIntPair<InstOperand *, 1, bool> firstOpAndIsDynamic;
|
||||
|
||||
// The maximum number of operands that can be currently held by the storage.
|
||||
unsigned capacity;
|
||||
};
|
||||
|
||||
/// This class handles the management of instruction operands. Operands are
|
||||
/// stored similarly to the elements of a SmallVector except for two key
|
||||
/// differences. The first is the inline storage, which is a trailing objects
|
||||
/// array. The second is that being able to dynamically resize the operand list
|
||||
/// is optional.
|
||||
class OperandStorage final
|
||||
: private llvm::TrailingObjects<OperandStorage, ResizableStorage,
|
||||
InstOperand> {
|
||||
public:
|
||||
OperandStorage(unsigned numOperands, bool resizable)
|
||||
: numOperands(numOperands), resizable(resizable) {
|
||||
// Initialize the resizable storage.
|
||||
if (resizable) {
|
||||
new (&getResizableStorage())
|
||||
ResizableStorage(getTrailingObjects<InstOperand>(), numOperands);
|
||||
}
|
||||
}
|
||||
|
||||
~OperandStorage() {
|
||||
// Manually destruct the operands.
|
||||
for (auto &operand : getInstOperands())
|
||||
operand.~InstOperand();
|
||||
|
||||
// If the storage is resizable then destruct the utility.
|
||||
if (resizable)
|
||||
getResizableStorage().~ResizableStorage();
|
||||
}
|
||||
|
||||
/// Replace the operands contained in the storage with the ones provided in
|
||||
/// 'operands'.
|
||||
void setOperands(Instruction *owner, ArrayRef<Value *> operands);
|
||||
|
||||
/// Erase an operand held by the storage.
|
||||
void eraseOperand(unsigned index);
|
||||
|
||||
/// Get the instruction operands held by the storage.
|
||||
ArrayRef<InstOperand> getInstOperands() const {
|
||||
return {getRawOperands(), size()};
|
||||
}
|
||||
MutableArrayRef<InstOperand> getInstOperands() {
|
||||
return {getRawOperands(), size()};
|
||||
}
|
||||
|
||||
/// Return the number of operands held in the storage.
|
||||
unsigned size() const { return numOperands; }
|
||||
|
||||
/// Returns the additional size necessary for allocating this object.
|
||||
static size_t additionalAllocSize(unsigned numOperands, bool resizable) {
|
||||
return additionalSizeToAlloc<ResizableStorage, InstOperand>(
|
||||
resizable ? 1 : 0, numOperands);
|
||||
}
|
||||
|
||||
/// Returns if this storage is resizable.
|
||||
bool isResizable() const { return resizable; }
|
||||
|
||||
private:
|
||||
/// Clear the storage and destroy the current operands held by the storage.
|
||||
void clear() { numOperands = 0; }
|
||||
|
||||
/// Returns the current pointer for the raw operands array.
|
||||
InstOperand *getRawOperands() {
|
||||
return resizable ? getResizableStorage().getPointer()
|
||||
: getTrailingObjects<InstOperand>();
|
||||
}
|
||||
const InstOperand *getRawOperands() const {
|
||||
return resizable ? getResizableStorage().getPointer()
|
||||
: getTrailingObjects<InstOperand>();
|
||||
}
|
||||
|
||||
/// Returns the resizable operand utility class.
|
||||
ResizableStorage &getResizableStorage() {
|
||||
assert(resizable);
|
||||
return *getTrailingObjects<ResizableStorage>();
|
||||
}
|
||||
const ResizableStorage &getResizableStorage() const {
|
||||
assert(resizable);
|
||||
return *getTrailingObjects<ResizableStorage>();
|
||||
}
|
||||
|
||||
/// Grow the internal resizable operand storage.
|
||||
void grow(ResizableStorage &resizeUtil, size_t minSize);
|
||||
|
||||
/// The current number of operands, and the current max operand capacity.
|
||||
unsigned numOperands : 31;
|
||||
|
||||
/// Whether this storage is resizable or not.
|
||||
bool resizable : 1;
|
||||
|
||||
// This stuff is used by the TrailingObjects template.
|
||||
friend llvm::TrailingObjects<OperandStorage, ResizableStorage, InstOperand>;
|
||||
size_t numTrailingObjects(OverloadToken<ResizableStorage>) const {
|
||||
return resizable ? 1 : 0;
|
||||
}
|
||||
};
|
||||
} // end namespace detail
|
||||
} // end namespace mlir
|
||||
|
||||
#endif // MLIR_IR_INSTRUCTION_SUPPORT_H
|
||||
@@ -25,7 +25,7 @@
|
||||
#define MLIR_MATCHERS_H
|
||||
|
||||
#include "mlir/IR/Attributes.h"
|
||||
#include "mlir/IR/Instruction.h"
|
||||
#include "mlir/IR/Operation.h"
|
||||
#include "mlir/IR/StandardTypes.h"
|
||||
#include "mlir/IR/Value.h"
|
||||
#include <type_traits>
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
#ifndef MLIR_IR_OPDEFINITION_H
|
||||
#define MLIR_IR_OPDEFINITION_H
|
||||
|
||||
#include "mlir/IR/Instruction.h"
|
||||
#include "mlir/IR/Operation.h"
|
||||
#include <type_traits>
|
||||
|
||||
namespace mlir {
|
||||
@@ -782,7 +782,7 @@ protected:
|
||||
/// This is a private constructor only accessible through the
|
||||
/// Instruction::cast family of methods.
|
||||
explicit Op(Instruction *state) : OpState(state) {}
|
||||
friend class Instruction;
|
||||
friend class Operation;
|
||||
|
||||
private:
|
||||
template <typename... Types> struct BaseVerifier;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//===- Instruction.h - MLIR Instruction Class -------------------*- C++ -*-===//
|
||||
//===- Operation.h - MLIR Operation Class -----------------------*- C++ -*-===//
|
||||
//
|
||||
// Copyright 2019 The MLIR Authors.
|
||||
//
|
||||
@@ -15,16 +15,16 @@
|
||||
// limitations under the License.
|
||||
// =============================================================================
|
||||
//
|
||||
// This file defines the Instruction class.
|
||||
// This file defines the Operation class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef MLIR_IR_INSTRUCTION_H
|
||||
#define MLIR_IR_INSTRUCTION_H
|
||||
#ifndef MLIR_IR_OPERATION_H
|
||||
#define MLIR_IR_OPERATION_H
|
||||
|
||||
#include "mlir/IR/AffineMap.h"
|
||||
#include "mlir/IR/Block.h"
|
||||
#include "mlir/IR/InstructionSupport.h"
|
||||
#include "mlir/IR/OperationSupport.h"
|
||||
#include "llvm/ADT/Twine.h"
|
||||
#include "llvm/ADT/ilist.h"
|
||||
#include "llvm/ADT/ilist_node.h"
|
||||
@@ -40,31 +40,31 @@ class ResultTypeIterator;
|
||||
/// Terminator operations can have Block operands to represent successors.
|
||||
using BlockOperand = IROperandImpl<Block>;
|
||||
|
||||
/// Instruction is a basic unit of execution within a function. Instructions can
|
||||
/// be nested within other instructions effectively forming a tree. Child
|
||||
/// instructions are organized into instruction blocks represented by a 'Block'
|
||||
/// Operation is a basic unit of execution within a function. Operations can
|
||||
/// be nested within other operations effectively forming a tree. Child
|
||||
/// operations are organized into operation blocks represented by a 'Block'
|
||||
/// class.
|
||||
class Instruction final
|
||||
: public llvm::ilist_node_with_parent<Instruction, Block>,
|
||||
private llvm::TrailingObjects<Instruction, InstResult, BlockOperand,
|
||||
class Operation final
|
||||
: public llvm::ilist_node_with_parent<Operation, Block>,
|
||||
private llvm::TrailingObjects<Operation, InstResult, BlockOperand,
|
||||
unsigned, Region, detail::OperandStorage> {
|
||||
public:
|
||||
/// Create a new Instruction with the specific fields.
|
||||
static Instruction *create(Location location, OperationName name,
|
||||
ArrayRef<Value *> operands,
|
||||
ArrayRef<Type> resultTypes,
|
||||
ArrayRef<NamedAttribute> attributes,
|
||||
ArrayRef<Block *> successors, unsigned numRegions,
|
||||
bool resizableOperandList, MLIRContext *context);
|
||||
/// Create a new Operation with the specific fields.
|
||||
static Operation *create(Location location, OperationName name,
|
||||
ArrayRef<Value *> operands,
|
||||
ArrayRef<Type> resultTypes,
|
||||
ArrayRef<NamedAttribute> attributes,
|
||||
ArrayRef<Block *> successors, unsigned numRegions,
|
||||
bool resizableOperandList, MLIRContext *context);
|
||||
|
||||
/// Overload of create that takes an existing NamedAttributeList to avoid
|
||||
/// unnecessarily uniquing a list of attributes.
|
||||
static Instruction *create(Location location, OperationName name,
|
||||
ArrayRef<Value *> operands,
|
||||
ArrayRef<Type> resultTypes,
|
||||
const NamedAttributeList &attributes,
|
||||
ArrayRef<Block *> successors, unsigned numRegions,
|
||||
bool resizableOperandList, MLIRContext *context);
|
||||
static Operation *create(Location location, OperationName name,
|
||||
ArrayRef<Value *> operands,
|
||||
ArrayRef<Type> resultTypes,
|
||||
const NamedAttributeList &attributes,
|
||||
ArrayRef<Block *> successors, unsigned numRegions,
|
||||
bool resizableOperandList, MLIRContext *context);
|
||||
|
||||
/// The name of an operation is the key identifier for it.
|
||||
OperationName getName() { return name; }
|
||||
@@ -75,18 +75,18 @@ public:
|
||||
return getName().getAbstractOperation();
|
||||
}
|
||||
|
||||
/// Remove this instruction from its parent block and delete it.
|
||||
/// Remove this operation from its parent block and delete it.
|
||||
void erase();
|
||||
|
||||
/// Create a deep copy of this instruction, remapping any operands that use
|
||||
/// values outside of the instruction using the map that is provided (leaving
|
||||
/// Create a deep copy of this operation, remapping any operands that use
|
||||
/// values outside of the operation using the map that is provided (leaving
|
||||
/// them alone if no entry is present). Replaces references to cloned
|
||||
/// sub-instructions to the corresponding instruction that is copied, and adds
|
||||
/// sub-operations to the corresponding operation that is copied, and adds
|
||||
/// those mappings to the map.
|
||||
Instruction *clone(BlockAndValueMapping &mapper, MLIRContext *context);
|
||||
Instruction *clone(MLIRContext *context);
|
||||
Operation *clone(BlockAndValueMapping &mapper, MLIRContext *context);
|
||||
Operation *clone(MLIRContext *context);
|
||||
|
||||
/// Returns the instruction block that contains this instruction.
|
||||
/// Returns the operation block that contains this operation.
|
||||
Block *getBlock() { return block; }
|
||||
|
||||
/// Return the context this operation is associated with.
|
||||
@@ -102,41 +102,41 @@ public:
|
||||
/// Set the source location the operation was defined or derived from.
|
||||
void setLoc(Location loc) { location = loc; }
|
||||
|
||||
/// Returns the closest surrounding instruction that contains this instruction
|
||||
/// or nullptr if this is a top-level instruction.
|
||||
Instruction *getParentInst();
|
||||
/// Returns the closest surrounding operation that contains this operation
|
||||
/// or nullptr if this is a top-level operation.
|
||||
Operation *getParentInst();
|
||||
|
||||
/// Returns the function that this instruction is part of.
|
||||
/// The function is determined by traversing the chain of parent instructions.
|
||||
/// Returns nullptr if the instruction is unlinked.
|
||||
/// Returns the function that this operation is part of.
|
||||
/// The function is determined by traversing the chain of parent operations.
|
||||
/// Returns nullptr if the operation is unlinked.
|
||||
Function *getFunction();
|
||||
|
||||
/// Destroys this instruction and its subclass data.
|
||||
/// Destroys this operation and its subclass data.
|
||||
void destroy();
|
||||
|
||||
/// This drops all operand uses from this instruction, which is an essential
|
||||
/// This drops all operand uses from this operation, which is an essential
|
||||
/// step in breaking cyclic dependences between references when they are to
|
||||
/// be deleted.
|
||||
void dropAllReferences();
|
||||
|
||||
/// Drop uses of all values defined by this instruction or its nested regions.
|
||||
/// Drop uses of all values defined by this operation or its nested regions.
|
||||
void dropAllDefinedValueUses();
|
||||
|
||||
/// Unlink this instruction from its current block and insert it right before
|
||||
/// Unlink this operation from its current block and insert it right before
|
||||
/// `existingInst` which may be in the same or another block in the same
|
||||
/// function.
|
||||
void moveBefore(Instruction *existingInst);
|
||||
void moveBefore(Operation *existingInst);
|
||||
|
||||
/// Unlink this operation instruction from its current block and insert it
|
||||
/// Unlink this operation operation from its current block and insert it
|
||||
/// right before `iterator` in the specified block.
|
||||
void moveBefore(Block *block, llvm::iplist<Instruction>::iterator iterator);
|
||||
void moveBefore(Block *block, llvm::iplist<Operation>::iterator iterator);
|
||||
|
||||
/// Given an instruction 'other' that is within the same parent block, return
|
||||
/// whether the current instruction is before 'other' in the instruction list
|
||||
/// Given an operation 'other' that is within the same parent block, return
|
||||
/// whether the current operation is before 'other' in the operation list
|
||||
/// of the parent block.
|
||||
/// Note: This function has an average complexity of O(1), but worst case may
|
||||
/// take O(N) where N is the number of instructions within the parent block.
|
||||
bool isBeforeInBlock(Instruction *other);
|
||||
/// take O(N) where N is the number of operations within the parent block.
|
||||
bool isBeforeInBlock(Operation *other);
|
||||
|
||||
void print(raw_ostream &os);
|
||||
void dump();
|
||||
@@ -212,11 +212,11 @@ public:
|
||||
// Attributes
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
// Instructions may optionally carry a list of attributes that associate
|
||||
// Operations may optionally carry a list of attributes that associate
|
||||
// constants to names. Attributes may be dynamically added and removed over
|
||||
// the lifetime of an instruction.
|
||||
// the lifetime of an operation.
|
||||
|
||||
/// Return all of the attributes on this instruction.
|
||||
/// Return all of the attributes on this operation.
|
||||
ArrayRef<NamedAttribute> getAttrs() { return attrs.getAttrs(); }
|
||||
|
||||
/// Return the specified attribute if present, null otherwise.
|
||||
@@ -369,7 +369,7 @@ public:
|
||||
// Conversions to declared operations like DimOp
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
/// The dyn_cast methods perform a dynamic cast from an Instruction to a typed
|
||||
/// The dyn_cast methods perform a dynamic cast from an Operation to a typed
|
||||
/// Op like DimOp. This returns a null Op on failure.
|
||||
template <typename OpClass> OpClass dyn_cast() {
|
||||
if (isa<OpClass>())
|
||||
@@ -377,7 +377,7 @@ public:
|
||||
return OpClass();
|
||||
}
|
||||
|
||||
/// The cast methods perform a cast from an Instruction to a typed Op like
|
||||
/// The cast methods perform a cast from an Operation to a typed Op like
|
||||
/// DimOp. This aborts if the parameter to the template isn't an instance of
|
||||
/// the template type argument.
|
||||
template <typename OpClass> OpClass cast() {
|
||||
@@ -390,31 +390,31 @@ public:
|
||||
template <typename OpClass> bool isa() { return OpClass::isClassFor(this); }
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Instruction Walkers
|
||||
// Operation Walkers
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
/// Walk the instructions held by this instruction in preorder, calling the
|
||||
/// callback for each instruction.
|
||||
void walk(const std::function<void(Instruction *)> &callback);
|
||||
/// Walk the operations held by this operation in preorder, calling the
|
||||
/// callback for each operation.
|
||||
void walk(const std::function<void(Operation *)> &callback);
|
||||
|
||||
/// Specialization of walk to only visit operations of 'OpTy'.
|
||||
template <typename OpTy> void walk(std::function<void(OpTy)> callback) {
|
||||
walk([&](Instruction *inst) {
|
||||
if (auto op = inst->dyn_cast<OpTy>())
|
||||
callback(op);
|
||||
walk([&](Operation *op) {
|
||||
if (auto derivedOp = op->dyn_cast<OpTy>())
|
||||
callback(derivedOp);
|
||||
});
|
||||
}
|
||||
|
||||
/// Walk the instructions held by this function in postorder, calling the
|
||||
/// callback for each instruction.
|
||||
void walkPostOrder(const std::function<void(Instruction *)> &callback);
|
||||
/// Walk the operations held by this function in postorder, calling the
|
||||
/// callback for each operation.
|
||||
void walkPostOrder(const std::function<void(Operation *)> &callback);
|
||||
|
||||
/// Specialization of walkPostOrder to only visit operations of 'OpTy'.
|
||||
template <typename OpTy>
|
||||
void walkPostOrder(std::function<void(OpTy)> callback) {
|
||||
walkPostOrder([&](Instruction *inst) {
|
||||
if (auto op = inst->dyn_cast<OpTy>())
|
||||
callback(op);
|
||||
walkPostOrder([&](Operation *op) {
|
||||
if (auto derivedOp = op->dyn_cast<OpTy>())
|
||||
callback(derivedOp);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -441,13 +441,13 @@ public:
|
||||
void emitNote(const Twine &message);
|
||||
|
||||
private:
|
||||
Instruction(Location location, OperationName name, unsigned numResults,
|
||||
unsigned numSuccessors, unsigned numRegions,
|
||||
const NamedAttributeList &attributes, MLIRContext *context);
|
||||
Operation(Location location, OperationName name, unsigned numResults,
|
||||
unsigned numSuccessors, unsigned numRegions,
|
||||
const NamedAttributeList &attributes, MLIRContext *context);
|
||||
|
||||
// Instructions are deleted through the destroy() member because they are
|
||||
// Operations are deleted through the destroy() member because they are
|
||||
// allocated with malloc.
|
||||
~Instruction();
|
||||
~Operation();
|
||||
|
||||
/// Returns the operand storage object.
|
||||
detail::OperandStorage &getOperandStorage() {
|
||||
@@ -457,15 +457,15 @@ private:
|
||||
// Provide a 'getParent' method for ilist_node_with_parent methods.
|
||||
Block *getParent() { return getBlock(); }
|
||||
|
||||
/// The instruction block that containts this instruction.
|
||||
/// The operation block that containts this operation.
|
||||
Block *block = nullptr;
|
||||
|
||||
/// This holds information about the source location the operation was defined
|
||||
/// or derived from.
|
||||
Location location;
|
||||
|
||||
/// Relative order of this instruction in its parent block. Used for
|
||||
/// O(1) local dominance checks between instructions.
|
||||
/// Relative order of this operation in its parent block. Used for
|
||||
/// O(1) local dominance checks between operations.
|
||||
mutable unsigned orderIndex = 0;
|
||||
|
||||
const unsigned numResults, numSuccs, numRegions;
|
||||
@@ -477,16 +477,16 @@ private:
|
||||
NamedAttributeList attrs;
|
||||
|
||||
// allow ilist_traits access to 'block' field.
|
||||
friend struct llvm::ilist_traits<Instruction>;
|
||||
friend struct llvm::ilist_traits<Operation>;
|
||||
|
||||
// allow block to access the 'orderIndex' field.
|
||||
friend class Block;
|
||||
|
||||
// allow ilist_node_with_parent to access the 'getParent' method.
|
||||
friend class llvm::ilist_node_with_parent<Instruction, Block>;
|
||||
friend class llvm::ilist_node_with_parent<Operation, Block>;
|
||||
|
||||
// This stuff is used by the TrailingObjects template.
|
||||
friend llvm::TrailingObjects<Instruction, InstResult, BlockOperand, unsigned,
|
||||
friend llvm::TrailingObjects<Operation, InstResult, BlockOperand, unsigned,
|
||||
Region, detail::OperandStorage>;
|
||||
size_t numTrailingObjects(OverloadToken<InstResult>) const {
|
||||
return numResults;
|
||||
@@ -498,60 +498,63 @@ private:
|
||||
size_t numTrailingObjects(OverloadToken<unsigned>) const { return numSuccs; }
|
||||
};
|
||||
|
||||
inline raw_ostream &operator<<(raw_ostream &os, Instruction &inst) {
|
||||
inst.print(os);
|
||||
inline raw_ostream &operator<<(raw_ostream &os, Operation &op) {
|
||||
op.print(os);
|
||||
return os;
|
||||
}
|
||||
|
||||
/// Temporary typedef to Instruction to while the codebase transitions to
|
||||
/// Operation.
|
||||
using Instruction = Operation;
|
||||
|
||||
/// This class implements the const/non-const operand iterators for the
|
||||
/// Instruction class in terms of getOperand(idx).
|
||||
/// Operation class in terms of getOperand(idx).
|
||||
class OperandIterator final
|
||||
: public IndexedAccessorIterator<OperandIterator, Instruction, Value> {
|
||||
: public IndexedAccessorIterator<OperandIterator, Operation, Value> {
|
||||
public:
|
||||
/// Initializes the operand iterator to the specified operand index.
|
||||
OperandIterator(Instruction *object, unsigned index)
|
||||
: IndexedAccessorIterator<OperandIterator, Instruction, Value>(object,
|
||||
index) {}
|
||||
OperandIterator(Operation *object, unsigned index)
|
||||
: IndexedAccessorIterator<OperandIterator, Operation, Value>(object,
|
||||
index) {}
|
||||
|
||||
Value *operator*() const { return this->object->getOperand(this->index); }
|
||||
};
|
||||
|
||||
// Implement the inline operand iterator methods.
|
||||
inline auto Instruction::operand_begin() -> operand_iterator {
|
||||
inline auto Operation::operand_begin() -> operand_iterator {
|
||||
return operand_iterator(this, 0);
|
||||
}
|
||||
|
||||
inline auto Instruction::operand_end() -> operand_iterator {
|
||||
inline auto Operation::operand_end() -> operand_iterator {
|
||||
return operand_iterator(this, getNumOperands());
|
||||
}
|
||||
|
||||
inline auto Instruction::getOperands() -> operand_range {
|
||||
inline auto Operation::getOperands() -> operand_range {
|
||||
return {operand_begin(), operand_end()};
|
||||
}
|
||||
|
||||
/// This class implements the result iterators for the Instruction class
|
||||
/// This class implements the result iterators for the Operation class
|
||||
/// in terms of getResult(idx).
|
||||
class ResultIterator final
|
||||
: public IndexedAccessorIterator<ResultIterator, Instruction, Value> {
|
||||
: public IndexedAccessorIterator<ResultIterator, Operation, Value> {
|
||||
public:
|
||||
/// Initializes the result iterator to the specified index.
|
||||
ResultIterator(Instruction *object, unsigned index)
|
||||
: IndexedAccessorIterator<ResultIterator, Instruction, Value>(object,
|
||||
index) {}
|
||||
ResultIterator(Operation *object, unsigned index)
|
||||
: IndexedAccessorIterator<ResultIterator, Operation, Value>(object,
|
||||
index) {}
|
||||
|
||||
Value *operator*() const { return this->object->getResult(this->index); }
|
||||
};
|
||||
|
||||
/// This class implements the result type iterators for the Instruction
|
||||
/// This class implements the result type iterators for the Operation
|
||||
/// class in terms of getResult(idx)->getType().
|
||||
class ResultTypeIterator final
|
||||
: public IndexedAccessorIterator<ResultTypeIterator, Instruction, Value> {
|
||||
: public IndexedAccessorIterator<ResultTypeIterator, Operation, Value> {
|
||||
public:
|
||||
/// Initializes the result type iterator to the specified index.
|
||||
ResultTypeIterator(Instruction *object, unsigned index)
|
||||
: IndexedAccessorIterator<ResultTypeIterator, Instruction, Value>(object,
|
||||
index) {
|
||||
}
|
||||
ResultTypeIterator(Operation *object, unsigned index)
|
||||
: IndexedAccessorIterator<ResultTypeIterator, Operation, Value>(object,
|
||||
index) {}
|
||||
|
||||
Type operator*() const {
|
||||
return this->object->getResult(this->index)->getType();
|
||||
@@ -559,31 +562,31 @@ public:
|
||||
};
|
||||
|
||||
// Implement the inline result iterator methods.
|
||||
inline auto Instruction::result_begin() -> result_iterator {
|
||||
inline auto Operation::result_begin() -> result_iterator {
|
||||
return result_iterator(this, 0);
|
||||
}
|
||||
|
||||
inline auto Instruction::result_end() -> result_iterator {
|
||||
inline auto Operation::result_end() -> result_iterator {
|
||||
return result_iterator(this, getNumResults());
|
||||
}
|
||||
|
||||
inline auto Instruction::getResults() -> llvm::iterator_range<result_iterator> {
|
||||
inline auto Operation::getResults() -> llvm::iterator_range<result_iterator> {
|
||||
return {result_begin(), result_end()};
|
||||
}
|
||||
|
||||
inline auto Instruction::result_type_begin() -> result_type_iterator {
|
||||
inline auto Operation::result_type_begin() -> result_type_iterator {
|
||||
return result_type_iterator(this, 0);
|
||||
}
|
||||
|
||||
inline auto Instruction::result_type_end() -> result_type_iterator {
|
||||
inline auto Operation::result_type_end() -> result_type_iterator {
|
||||
return result_type_iterator(this, getNumResults());
|
||||
}
|
||||
|
||||
inline auto Instruction::getResultTypes()
|
||||
inline auto Operation::getResultTypes()
|
||||
-> llvm::iterator_range<result_type_iterator> {
|
||||
return {result_type_begin(), result_type_end()};
|
||||
}
|
||||
|
||||
} // end namespace mlir
|
||||
|
||||
#endif // MLIR_IR_INSTRUCTION_H
|
||||
#endif // MLIR_IR_OPERATION_H
|
||||
@@ -15,7 +15,7 @@
|
||||
// limitations under the License.
|
||||
// =============================================================================
|
||||
//
|
||||
// This file defines a number of support types that Instruction and related
|
||||
// This file defines a number of support types that Operation and related
|
||||
// classes build on top of.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
@@ -27,14 +27,18 @@
|
||||
#include "mlir/IR/Identifier.h"
|
||||
#include "mlir/IR/Location.h"
|
||||
#include "mlir/IR/Types.h"
|
||||
#include "mlir/IR/Value.h"
|
||||
#include "mlir/Support/LLVM.h"
|
||||
#include "mlir/Support/LogicalResult.h"
|
||||
#include "llvm/ADT/PointerUnion.h"
|
||||
#include "llvm/Support/TrailingObjects.h"
|
||||
#include <memory>
|
||||
|
||||
namespace mlir {
|
||||
class Block;
|
||||
class Dialect;
|
||||
class Instruction;
|
||||
class Operation;
|
||||
using Instruction = Operation;
|
||||
struct OperationState;
|
||||
class OpAsmParser;
|
||||
class OpAsmParserResult;
|
||||
@@ -79,23 +83,22 @@ public:
|
||||
Dialect &dialect;
|
||||
|
||||
/// Return true if this "op class" can match against the specified operation.
|
||||
bool (&isClassFor)(Instruction *op);
|
||||
bool (&isClassFor)(Operation *op);
|
||||
|
||||
/// Use the specified object to parse this ops custom assembly format.
|
||||
bool (&parseAssembly)(OpAsmParser *parser, OperationState *result);
|
||||
|
||||
/// This hook implements the AsmPrinter for this operation.
|
||||
void (&printAssembly)(Instruction *op, OpAsmPrinter *p);
|
||||
void (&printAssembly)(Operation *op, OpAsmPrinter *p);
|
||||
|
||||
/// This hook implements the verifier for this operation. It should emits an
|
||||
/// error message and returns true if a problem is detected, or returns false
|
||||
/// if everything is ok.
|
||||
bool (&verifyInvariants)(Instruction *op);
|
||||
bool (&verifyInvariants)(Operation *op);
|
||||
|
||||
/// This hook implements a constant folder for this operation. It fills in
|
||||
/// `results` on success.
|
||||
LogicalResult (&constantFoldHook)(Instruction *op,
|
||||
ArrayRef<Attribute> operands,
|
||||
LogicalResult (&constantFoldHook)(Operation *op, ArrayRef<Attribute> operands,
|
||||
SmallVectorImpl<Attribute> &results);
|
||||
|
||||
/// This hook implements a generalized folder for this operation. Operations
|
||||
@@ -118,7 +121,7 @@ public:
|
||||
/// "x+0 -> x", "min(x,y,x,z) -> min(x,y,z)", "x+y-x -> y", etc), but does
|
||||
/// not allow for canonicalizations that need to introduce new operations, not
|
||||
/// even constants (e.g. "x-x -> 0" cannot be expressed).
|
||||
LogicalResult (&foldHook)(Instruction *op, SmallVectorImpl<Value *> &results);
|
||||
LogicalResult (&foldHook)(Operation *op, SmallVectorImpl<Value *> &results);
|
||||
|
||||
/// This hook returns any canonicalization pattern rewrites that the operation
|
||||
/// supports, for use by the canonicalization pass.
|
||||
@@ -147,14 +150,14 @@ public:
|
||||
private:
|
||||
AbstractOperation(
|
||||
StringRef name, Dialect &dialect, OperationProperties opProperties,
|
||||
bool (&isClassFor)(Instruction *op),
|
||||
bool (&isClassFor)(Operation *op),
|
||||
bool (&parseAssembly)(OpAsmParser *parser, OperationState *result),
|
||||
void (&printAssembly)(Instruction *op, OpAsmPrinter *p),
|
||||
bool (&verifyInvariants)(Instruction *op),
|
||||
LogicalResult (&constantFoldHook)(Instruction *op,
|
||||
void (&printAssembly)(Operation *op, OpAsmPrinter *p),
|
||||
bool (&verifyInvariants)(Operation *op),
|
||||
LogicalResult (&constantFoldHook)(Operation *op,
|
||||
ArrayRef<Attribute> operands,
|
||||
SmallVectorImpl<Attribute> &results),
|
||||
LogicalResult (&foldHook)(Instruction *op,
|
||||
LogicalResult (&foldHook)(Operation *op,
|
||||
SmallVectorImpl<Value *> &results),
|
||||
void (&getCanonicalizationPatterns)(OwningRewritePatternList &results,
|
||||
MLIRContext *context))
|
||||
@@ -274,14 +277,14 @@ public:
|
||||
operands.append(succOperands.begin(), succOperands.end());
|
||||
}
|
||||
|
||||
/// Create a region that should be attached to the instruction. These regions
|
||||
/// can be filled in immediately without waiting for Instruction to be
|
||||
/// Create a region that should be attached to the operation. These regions
|
||||
/// can be filled in immediately without waiting for Operation to be
|
||||
/// created. When it is, the region bodies will be transferred.
|
||||
Region *addRegion();
|
||||
|
||||
/// Take a region that should be attached to the Instruction. The body of the
|
||||
/// region will be transferred when the Instruction is constructed. If the
|
||||
/// region is null, a new empty region will be attached to the Instruction.
|
||||
/// Take a region that should be attached to the Operation. The body of the
|
||||
/// region will be transferred when the Operation is constructed. If the
|
||||
/// region is null, a new empty region will be attached to the Operation.
|
||||
void addRegion(std::unique_ptr<Region> &®ion);
|
||||
|
||||
/// Sets the operand list of the operation as resizable.
|
||||
@@ -290,6 +293,142 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
/// A utility class holding the information necessary to dynamically resize
|
||||
/// operands.
|
||||
struct ResizableStorage {
|
||||
ResizableStorage(InstOperand *opBegin, unsigned numOperands)
|
||||
: firstOpAndIsDynamic(opBegin, false), capacity(numOperands) {}
|
||||
|
||||
~ResizableStorage() { cleanupStorage(); }
|
||||
|
||||
/// Cleanup any allocated storage.
|
||||
void cleanupStorage() {
|
||||
// If the storage is dynamic, then we need to free the storage.
|
||||
if (isStorageDynamic())
|
||||
free(firstOpAndIsDynamic.getPointer());
|
||||
}
|
||||
|
||||
/// Sets the storage pointer to a new dynamically allocated block.
|
||||
void setDynamicStorage(InstOperand *opBegin) {
|
||||
/// Cleanup the old storage if necessary.
|
||||
cleanupStorage();
|
||||
firstOpAndIsDynamic.setPointerAndInt(opBegin, true);
|
||||
}
|
||||
|
||||
/// Returns the current storage pointer.
|
||||
InstOperand *getPointer() { return firstOpAndIsDynamic.getPointer(); }
|
||||
const InstOperand *getPointer() const {
|
||||
return firstOpAndIsDynamic.getPointer();
|
||||
}
|
||||
|
||||
/// Returns if the current storage of operands is in the trailing objects is
|
||||
/// in a dynamically allocated memory block.
|
||||
bool isStorageDynamic() const { return firstOpAndIsDynamic.getInt(); }
|
||||
|
||||
/// A pointer to the first operand element. This is either to the trailing
|
||||
/// objects storage, or a dynamically allocated block of memory.
|
||||
llvm::PointerIntPair<InstOperand *, 1, bool> firstOpAndIsDynamic;
|
||||
|
||||
// The maximum number of operands that can be currently held by the storage.
|
||||
unsigned capacity;
|
||||
};
|
||||
|
||||
/// This class handles the management of operation operands. Operands are
|
||||
/// stored similarly to the elements of a SmallVector except for two key
|
||||
/// differences. The first is the inline storage, which is a trailing objects
|
||||
/// array. The second is that being able to dynamically resize the operand list
|
||||
/// is optional.
|
||||
class OperandStorage final
|
||||
: private llvm::TrailingObjects<OperandStorage, ResizableStorage,
|
||||
InstOperand> {
|
||||
public:
|
||||
OperandStorage(unsigned numOperands, bool resizable)
|
||||
: numOperands(numOperands), resizable(resizable) {
|
||||
// Initialize the resizable storage.
|
||||
if (resizable) {
|
||||
new (&getResizableStorage())
|
||||
ResizableStorage(getTrailingObjects<InstOperand>(), numOperands);
|
||||
}
|
||||
}
|
||||
|
||||
~OperandStorage() {
|
||||
// Manually destruct the operands.
|
||||
for (auto &operand : getInstOperands())
|
||||
operand.~InstOperand();
|
||||
|
||||
// If the storage is resizable then destruct the utility.
|
||||
if (resizable)
|
||||
getResizableStorage().~ResizableStorage();
|
||||
}
|
||||
|
||||
/// Replace the operands contained in the storage with the ones provided in
|
||||
/// 'operands'.
|
||||
void setOperands(Operation *owner, ArrayRef<Value *> operands);
|
||||
|
||||
/// Erase an operand held by the storage.
|
||||
void eraseOperand(unsigned index);
|
||||
|
||||
/// Get the operation operands held by the storage.
|
||||
ArrayRef<InstOperand> getInstOperands() const {
|
||||
return {getRawOperands(), size()};
|
||||
}
|
||||
MutableArrayRef<InstOperand> getInstOperands() {
|
||||
return {getRawOperands(), size()};
|
||||
}
|
||||
|
||||
/// Return the number of operands held in the storage.
|
||||
unsigned size() const { return numOperands; }
|
||||
|
||||
/// Returns the additional size necessary for allocating this object.
|
||||
static size_t additionalAllocSize(unsigned numOperands, bool resizable) {
|
||||
return additionalSizeToAlloc<ResizableStorage, InstOperand>(
|
||||
resizable ? 1 : 0, numOperands);
|
||||
}
|
||||
|
||||
/// Returns if this storage is resizable.
|
||||
bool isResizable() const { return resizable; }
|
||||
|
||||
private:
|
||||
/// Clear the storage and destroy the current operands held by the storage.
|
||||
void clear() { numOperands = 0; }
|
||||
|
||||
/// Returns the current pointer for the raw operands array.
|
||||
InstOperand *getRawOperands() {
|
||||
return resizable ? getResizableStorage().getPointer()
|
||||
: getTrailingObjects<InstOperand>();
|
||||
}
|
||||
const InstOperand *getRawOperands() const {
|
||||
return resizable ? getResizableStorage().getPointer()
|
||||
: getTrailingObjects<InstOperand>();
|
||||
}
|
||||
|
||||
/// Returns the resizable operand utility class.
|
||||
ResizableStorage &getResizableStorage() {
|
||||
assert(resizable);
|
||||
return *getTrailingObjects<ResizableStorage>();
|
||||
}
|
||||
const ResizableStorage &getResizableStorage() const {
|
||||
assert(resizable);
|
||||
return *getTrailingObjects<ResizableStorage>();
|
||||
}
|
||||
|
||||
/// Grow the internal resizable operand storage.
|
||||
void grow(ResizableStorage &resizeUtil, size_t minSize);
|
||||
|
||||
/// The current number of operands, and the current max operand capacity.
|
||||
unsigned numOperands : 31;
|
||||
|
||||
/// Whether this storage is resizable or not.
|
||||
bool resizable : 1;
|
||||
|
||||
// This stuff is used by the TrailingObjects template.
|
||||
friend llvm::TrailingObjects<OperandStorage, ResizableStorage, InstOperand>;
|
||||
size_t numTrailingObjects(OverloadToken<ResizableStorage>) const {
|
||||
return resizable ? 1 : 0;
|
||||
}
|
||||
};
|
||||
} // end namespace detail
|
||||
} // end namespace mlir
|
||||
|
||||
namespace llvm {
|
||||
|
||||
@@ -28,8 +28,9 @@
|
||||
|
||||
namespace mlir {
|
||||
|
||||
class Instruction;
|
||||
class IROperand;
|
||||
class Operation;
|
||||
using Instruction = Operation;
|
||||
template <typename OperandType> class ValueUseIterator;
|
||||
|
||||
class IRObjectWithUseList {
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
namespace mlir {
|
||||
class Block;
|
||||
class Function;
|
||||
class Instruction;
|
||||
class Operation;
|
||||
using Instruction = Operation;
|
||||
class Value;
|
||||
|
||||
/// Operands contain a Value.
|
||||
|
||||
@@ -31,8 +31,9 @@ namespace mlir {
|
||||
// Forward declarations.
|
||||
class Block;
|
||||
class FuncBuilder;
|
||||
class Instruction;
|
||||
class MLIRContext;
|
||||
class Operation;
|
||||
using Instruction = Operation;
|
||||
class Type;
|
||||
class Value;
|
||||
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
#include "mlir/Analysis/Utils.h"
|
||||
#include "mlir/IR/AffineExprVisitor.h"
|
||||
#include "mlir/IR/Builders.h"
|
||||
#include "mlir/IR/Instruction.h"
|
||||
#include "mlir/IR/IntegerSet.h"
|
||||
#include "mlir/IR/Operation.h"
|
||||
#include "mlir/StandardOps/Ops.h"
|
||||
#include "mlir/Support/MathExtras.h"
|
||||
#include "mlir/Support/STLExtras.h"
|
||||
|
||||
@@ -23,8 +23,8 @@
|
||||
#include "mlir/AffineOps/AffineOps.h"
|
||||
#include "mlir/IR/AffineExprVisitor.h"
|
||||
#include "mlir/IR/AffineMap.h"
|
||||
#include "mlir/IR/Instruction.h"
|
||||
#include "mlir/IR/IntegerSet.h"
|
||||
#include "mlir/IR/Operation.h"
|
||||
#include "mlir/StandardOps/Ops.h"
|
||||
#include "mlir/Support/MathExtras.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "mlir/Analysis/Dominance.h"
|
||||
#include "mlir/IR/Instruction.h"
|
||||
#include "mlir/IR/Operation.h"
|
||||
#include "llvm/Support/GenericDomTreeConstruction.h"
|
||||
using namespace mlir;
|
||||
using namespace mlir::detail;
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
#include "mlir/Analysis/VectorAnalysis.h"
|
||||
#include "mlir/IR/AffineMap.h"
|
||||
#include "mlir/IR/Builders.h"
|
||||
#include "mlir/IR/Instruction.h"
|
||||
#include "mlir/IR/Operation.h"
|
||||
#include "mlir/StandardOps/Ops.h"
|
||||
#include "mlir/SuperVectorOps/SuperVectorOps.h"
|
||||
#include "mlir/Support/Functional.h"
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
// limitations under the License.
|
||||
// =============================================================================
|
||||
|
||||
#include "mlir/IR/Instruction.h"
|
||||
#include "mlir/IR/Module.h"
|
||||
#include "mlir/IR/Operation.h"
|
||||
#include "mlir/IR/OperationSupport.h"
|
||||
#include "mlir/Pass/Pass.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include "mlir/Analysis/SliceAnalysis.h"
|
||||
#include "mlir/AffineOps/AffineOps.h"
|
||||
#include "mlir/Analysis/VectorAnalysis.h"
|
||||
#include "mlir/IR/Instruction.h"
|
||||
#include "mlir/IR/Operation.h"
|
||||
#include "mlir/Support/Functional.h"
|
||||
#include "mlir/Support/STLExtras.h"
|
||||
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
#include "mlir/AffineOps/AffineOps.h"
|
||||
#include "mlir/Analysis/AffineAnalysis.h"
|
||||
#include "mlir/Analysis/LoopAnalysis.h"
|
||||
#include "mlir/IR/Instruction.h"
|
||||
#include "mlir/IR/IntegerSet.h"
|
||||
#include "mlir/IR/Operation.h"
|
||||
#include "mlir/StandardOps/Ops.h"
|
||||
#include "mlir/SuperVectorOps/SuperVectorOps.h"
|
||||
#include "mlir/Support/Functional.h"
|
||||
|
||||
@@ -37,8 +37,8 @@
|
||||
#include "mlir/IR/Attributes.h"
|
||||
#include "mlir/IR/Dialect.h"
|
||||
#include "mlir/IR/Function.h"
|
||||
#include "mlir/IR/Instruction.h"
|
||||
#include "mlir/IR/Module.h"
|
||||
#include "mlir/IR/Operation.h"
|
||||
#include "llvm/Support/FormatVariadic.h"
|
||||
#include "llvm/Support/PrettyStackTrace.h"
|
||||
#include "llvm/Support/Regex.h"
|
||||
|
||||
@@ -26,10 +26,10 @@
|
||||
#include "mlir/EDSC/MLIREmitter.h"
|
||||
#include "mlir/EDSC/Types.h"
|
||||
#include "mlir/IR/Builders.h"
|
||||
#include "mlir/IR/Instruction.h"
|
||||
#include "mlir/IR/IntegerSet.h"
|
||||
#include "mlir/IR/Location.h"
|
||||
#include "mlir/IR/OpDefinition.h"
|
||||
#include "mlir/IR/Operation.h"
|
||||
#include "mlir/IR/Value.h"
|
||||
#include "mlir/StandardOps/Ops.h"
|
||||
#include "mlir/SuperVectorOps/SuperVectorOps.h"
|
||||
|
||||
@@ -25,12 +25,12 @@
|
||||
#include "mlir/IR/Attributes.h"
|
||||
#include "mlir/IR/Dialect.h"
|
||||
#include "mlir/IR/Function.h"
|
||||
#include "mlir/IR/Instruction.h"
|
||||
#include "mlir/IR/IntegerSet.h"
|
||||
#include "mlir/IR/MLIRContext.h"
|
||||
#include "mlir/IR/Matchers.h"
|
||||
#include "mlir/IR/Module.h"
|
||||
#include "mlir/IR/OpImplementation.h"
|
||||
#include "mlir/IR/Operation.h"
|
||||
#include "mlir/IR/StandardTypes.h"
|
||||
#include "mlir/Support/STLExtras.h"
|
||||
#include "llvm/ADT/APFloat.h"
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#include "mlir/IR/Block.h"
|
||||
#include "mlir/IR/BlockAndValueMapping.h"
|
||||
#include "mlir/IR/Builders.h"
|
||||
#include "mlir/IR/Instruction.h"
|
||||
#include "mlir/IR/Operation.h"
|
||||
using namespace mlir;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@@ -1,665 +0,0 @@
|
||||
//===- Instruction.cpp - MLIR 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/Instruction.h"
|
||||
#include "mlir/IR/AffineExpr.h"
|
||||
#include "mlir/IR/AffineMap.h"
|
||||
#include "mlir/IR/BlockAndValueMapping.h"
|
||||
#include "mlir/IR/Dialect.h"
|
||||
#include "mlir/IR/Function.h"
|
||||
#include "mlir/IR/IntegerSet.h"
|
||||
#include "mlir/IR/MLIRContext.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include <numeric>
|
||||
|
||||
using namespace mlir;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// InstResult
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// Return the result number of this result.
|
||||
unsigned InstResult::getResultNumber() {
|
||||
// Results are always stored consecutively, so use pointer subtraction to
|
||||
// figure out what number this is.
|
||||
return this - &getOwner()->getInstResults()[0];
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// InstOperand
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// Return which operand this is in the operand list.
|
||||
template <> unsigned InstOperand::getOperandNumber() {
|
||||
return this - &getOwner()->getInstOperands()[0];
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// BlockOperand
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// Return which operand this is in the operand list.
|
||||
template <> unsigned BlockOperand::getOperandNumber() {
|
||||
return this - &getOwner()->getBlockOperands()[0];
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// OperandStorage
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// Replace the operands contained in the storage with the ones provided in
|
||||
/// 'operands'.
|
||||
void detail::OperandStorage::setOperands(Instruction *owner,
|
||||
ArrayRef<Value *> operands) {
|
||||
// If the number of operands is less than or equal to the current amount, we
|
||||
// can just update in place.
|
||||
if (operands.size() <= numOperands) {
|
||||
auto instOperands = getInstOperands();
|
||||
|
||||
// If the number of new operands is less than the current count, then remove
|
||||
// any extra operands.
|
||||
for (unsigned i = operands.size(); i != numOperands; ++i)
|
||||
instOperands[i].~InstOperand();
|
||||
|
||||
// Set the operands in place.
|
||||
numOperands = operands.size();
|
||||
for (unsigned i = 0; i != numOperands; ++i)
|
||||
instOperands[i].set(operands[i]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, we need to be resizable.
|
||||
assert(resizable && "Only resizable operations may add operands");
|
||||
|
||||
// Grow the capacity if necessary.
|
||||
auto &resizeUtil = getResizableStorage();
|
||||
if (resizeUtil.capacity < operands.size())
|
||||
grow(resizeUtil, operands.size());
|
||||
|
||||
// Set the operands.
|
||||
InstOperand *opBegin = getRawOperands();
|
||||
for (unsigned i = 0; i != numOperands; ++i)
|
||||
opBegin[i].set(operands[i]);
|
||||
for (unsigned e = operands.size(); numOperands != e; ++numOperands)
|
||||
new (&opBegin[numOperands]) InstOperand(owner, operands[numOperands]);
|
||||
}
|
||||
|
||||
/// Erase an operand held by the storage.
|
||||
void detail::OperandStorage::eraseOperand(unsigned index) {
|
||||
assert(index < size());
|
||||
auto Operands = getInstOperands();
|
||||
--numOperands;
|
||||
|
||||
// Shift all operands down by 1 if the operand to remove is not at the end.
|
||||
if (index != numOperands)
|
||||
std::rotate(&Operands[index], &Operands[index + 1], &Operands[numOperands]);
|
||||
Operands[numOperands].~InstOperand();
|
||||
}
|
||||
|
||||
/// Grow the internal operand storage.
|
||||
void detail::OperandStorage::grow(ResizableStorage &resizeUtil,
|
||||
size_t minSize) {
|
||||
// Allocate a new storage array.
|
||||
resizeUtil.capacity =
|
||||
std::max(size_t(llvm::NextPowerOf2(resizeUtil.capacity + 2)), minSize);
|
||||
InstOperand *newStorage = static_cast<InstOperand *>(
|
||||
llvm::safe_malloc(resizeUtil.capacity * sizeof(InstOperand)));
|
||||
|
||||
// Move the current operands to the new storage.
|
||||
auto operands = getInstOperands();
|
||||
std::uninitialized_copy(std::make_move_iterator(operands.begin()),
|
||||
std::make_move_iterator(operands.end()), newStorage);
|
||||
|
||||
// Destroy the original operands and update the resizable storage pointer.
|
||||
for (auto &operand : operands)
|
||||
operand.~InstOperand();
|
||||
resizeUtil.setDynamicStorage(newStorage);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Instruction
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// Create a new Instruction with the specific fields.
|
||||
Instruction *Instruction::create(Location location, OperationName name,
|
||||
ArrayRef<Value *> operands,
|
||||
ArrayRef<Type> resultTypes,
|
||||
ArrayRef<NamedAttribute> attributes,
|
||||
ArrayRef<Block *> successors,
|
||||
unsigned numRegions, bool resizableOperandList,
|
||||
MLIRContext *context) {
|
||||
return create(location, name, operands, resultTypes,
|
||||
NamedAttributeList(context, attributes), successors, numRegions,
|
||||
resizableOperandList, context);
|
||||
}
|
||||
|
||||
/// Overload of create that takes an existing NamedAttributeList to avoid
|
||||
/// unnecessarily uniquing a list of attributes.
|
||||
Instruction *Instruction::create(Location location, OperationName name,
|
||||
ArrayRef<Value *> operands,
|
||||
ArrayRef<Type> resultTypes,
|
||||
const NamedAttributeList &attributes,
|
||||
ArrayRef<Block *> successors,
|
||||
unsigned numRegions, bool resizableOperandList,
|
||||
MLIRContext *context) {
|
||||
unsigned numSuccessors = successors.size();
|
||||
|
||||
// Input operands are nullptr-separated for each successor, the null operands
|
||||
// aren't actually stored.
|
||||
unsigned numOperands = operands.size() - numSuccessors;
|
||||
|
||||
// Compute the byte size for the instruction and the operand storage.
|
||||
auto byteSize = totalSizeToAlloc<InstResult, BlockOperand, unsigned, Region,
|
||||
detail::OperandStorage>(
|
||||
resultTypes.size(), numSuccessors, numSuccessors, numRegions,
|
||||
/*detail::OperandStorage*/ 1);
|
||||
byteSize += llvm::alignTo(detail::OperandStorage::additionalAllocSize(
|
||||
numOperands, resizableOperandList),
|
||||
alignof(Instruction));
|
||||
void *rawMem = malloc(byteSize);
|
||||
|
||||
// Create the new Instruction.
|
||||
auto inst = ::new (rawMem)
|
||||
Instruction(location, name, resultTypes.size(), numSuccessors, numRegions,
|
||||
attributes, context);
|
||||
|
||||
assert((numSuccessors == 0 || !inst->isKnownNonTerminator()) &&
|
||||
"unexpected successors in a non-terminator operation");
|
||||
|
||||
// Initialize the regions.
|
||||
for (unsigned i = 0; i != numRegions; ++i)
|
||||
new (&inst->getRegion(i)) Region(inst);
|
||||
|
||||
// Initialize the results and operands.
|
||||
new (&inst->getOperandStorage())
|
||||
detail::OperandStorage(numOperands, resizableOperandList);
|
||||
|
||||
auto instResults = inst->getInstResults();
|
||||
for (unsigned i = 0, e = resultTypes.size(); i != e; ++i)
|
||||
new (&instResults[i]) InstResult(resultTypes[i], inst);
|
||||
|
||||
auto InstOperands = inst->getInstOperands();
|
||||
|
||||
// Initialize normal operands.
|
||||
unsigned operandIt = 0, operandE = operands.size();
|
||||
unsigned nextOperand = 0;
|
||||
for (; operandIt != operandE; ++operandIt) {
|
||||
// Null operands are used as sentinels between successor operand lists. If
|
||||
// we encounter one here, break and handle the successor operands lists
|
||||
// separately below.
|
||||
if (!operands[operandIt])
|
||||
break;
|
||||
new (&InstOperands[nextOperand++]) InstOperand(inst, operands[operandIt]);
|
||||
}
|
||||
|
||||
unsigned currentSuccNum = 0;
|
||||
if (operandIt == operandE) {
|
||||
// Verify that the amount of sentinel operands is equivalent to the number
|
||||
// of successors.
|
||||
assert(currentSuccNum == numSuccessors);
|
||||
return inst;
|
||||
}
|
||||
|
||||
assert(!inst->isKnownNonTerminator() &&
|
||||
"Unexpected nullptr in operand list when creating non-terminator.");
|
||||
auto instBlockOperands = inst->getBlockOperands();
|
||||
unsigned *succOperandCountIt = inst->getTrailingObjects<unsigned>();
|
||||
unsigned *succOperandCountE = succOperandCountIt + numSuccessors;
|
||||
(void)succOperandCountE;
|
||||
|
||||
for (; operandIt != operandE; ++operandIt) {
|
||||
// If we encounter a sentinel branch to the next operand update the count
|
||||
// variable.
|
||||
if (!operands[operandIt]) {
|
||||
assert(currentSuccNum < numSuccessors);
|
||||
|
||||
// After the first iteration update the successor operand count
|
||||
// variable.
|
||||
if (currentSuccNum != 0) {
|
||||
++succOperandCountIt;
|
||||
assert(succOperandCountIt != succOperandCountE &&
|
||||
"More sentinel operands than successors.");
|
||||
}
|
||||
|
||||
new (&instBlockOperands[currentSuccNum])
|
||||
BlockOperand(inst, successors[currentSuccNum]);
|
||||
*succOperandCountIt = 0;
|
||||
++currentSuccNum;
|
||||
continue;
|
||||
}
|
||||
new (&InstOperands[nextOperand++]) InstOperand(inst, operands[operandIt]);
|
||||
++(*succOperandCountIt);
|
||||
}
|
||||
|
||||
// Verify that the amount of sentinel operands is equivalent to the number of
|
||||
// successors.
|
||||
assert(currentSuccNum == numSuccessors);
|
||||
|
||||
return inst;
|
||||
}
|
||||
|
||||
Instruction::Instruction(Location location, OperationName name,
|
||||
unsigned numResults, unsigned numSuccessors,
|
||||
unsigned numRegions,
|
||||
const NamedAttributeList &attributes,
|
||||
MLIRContext *context)
|
||||
: location(location), numResults(numResults), numSuccs(numSuccessors),
|
||||
numRegions(numRegions), name(name), attrs(attributes) {}
|
||||
|
||||
// Instructions are deleted through the destroy() member because they are
|
||||
// allocated via malloc.
|
||||
Instruction::~Instruction() {
|
||||
assert(block == nullptr && "instruction destroyed but still in a block");
|
||||
|
||||
// Explicitly run the destructors for the operands and results.
|
||||
getOperandStorage().~OperandStorage();
|
||||
|
||||
for (auto &result : getInstResults())
|
||||
result.~InstResult();
|
||||
|
||||
// Explicitly run the destructors for the successors.
|
||||
for (auto &successor : getBlockOperands())
|
||||
successor.~BlockOperand();
|
||||
|
||||
// Explicitly destroy the regions.
|
||||
for (auto ®ion : getRegions())
|
||||
region.~Region();
|
||||
}
|
||||
|
||||
/// Destroy this instruction or one of its subclasses.
|
||||
void Instruction::destroy() {
|
||||
this->~Instruction();
|
||||
free(this);
|
||||
}
|
||||
|
||||
/// Return the context this operation is associated with.
|
||||
MLIRContext *Instruction::getContext() {
|
||||
// If we have a result or operand type, that is a constant time way to get
|
||||
// to the context.
|
||||
if (getNumResults())
|
||||
return getResult(0)->getType().getContext();
|
||||
if (getNumOperands())
|
||||
return getOperand(0)->getType().getContext();
|
||||
|
||||
// In the very odd case where we have no operands or results, fall back to
|
||||
// doing a find.
|
||||
return getFunction()->getContext();
|
||||
}
|
||||
|
||||
/// Return the dialact this operation is associated with, or nullptr if the
|
||||
/// associated dialect is not registered.
|
||||
Dialect *Instruction::getDialect() {
|
||||
if (auto *abstractOp = getAbstractOperation())
|
||||
return &abstractOp->dialect;
|
||||
|
||||
// If this operation hasn't been registered or doesn't have abstract
|
||||
// operation, fall back to a dialect which matches the prefix.
|
||||
auto opName = getName().getStringRef();
|
||||
auto dialectPrefix = opName.split('.').first;
|
||||
return getContext()->getRegisteredDialect(dialectPrefix);
|
||||
}
|
||||
|
||||
Instruction *Instruction::getParentInst() {
|
||||
return block ? block->getContainingInst() : nullptr;
|
||||
}
|
||||
|
||||
Function *Instruction::getFunction() {
|
||||
return block ? block->getFunction() : nullptr;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Instruction Walkers
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void Instruction::walk(const std::function<void(Instruction *)> &callback) {
|
||||
// Visit the current instruction.
|
||||
callback(this);
|
||||
|
||||
// Visit any internal instructions.
|
||||
for (auto ®ion : getRegions())
|
||||
for (auto &block : region)
|
||||
block.walk(callback);
|
||||
}
|
||||
|
||||
void Instruction::walkPostOrder(
|
||||
const std::function<void(Instruction *)> &callback) {
|
||||
// Visit any internal instructions.
|
||||
for (auto ®ion : llvm::reverse(getRegions()))
|
||||
for (auto &block : llvm::reverse(region))
|
||||
block.walkPostOrder(callback);
|
||||
|
||||
// Visit the current instruction.
|
||||
callback(this);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Other
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// Emit a note about this instruction, reporting up to any diagnostic
|
||||
/// handlers that may be listening.
|
||||
void Instruction::emitNote(const Twine &message) {
|
||||
getContext()->emitDiagnostic(getLoc(), message,
|
||||
MLIRContext::DiagnosticKind::Note);
|
||||
}
|
||||
|
||||
/// Emit a warning about this instruction, reporting up to any diagnostic
|
||||
/// handlers that may be listening.
|
||||
void Instruction::emitWarning(const Twine &message) {
|
||||
getContext()->emitDiagnostic(getLoc(), message,
|
||||
MLIRContext::DiagnosticKind::Warning);
|
||||
}
|
||||
|
||||
/// Emit an error about fatal conditions with this operation, reporting up to
|
||||
/// any diagnostic handlers that may be listening. This function always
|
||||
/// returns true. NOTE: This may terminate the containing application, only
|
||||
/// use when the IR is in an inconsistent state.
|
||||
bool Instruction::emitError(const Twine &message) {
|
||||
return getContext()->emitError(getLoc(), message);
|
||||
}
|
||||
|
||||
/// Given an instruction 'other' that is within the same parent block, return
|
||||
/// whether the current instruction is before 'other' in the instruction list
|
||||
/// of the parent block.
|
||||
/// Note: This function has an average complexity of O(1), but worst case may
|
||||
/// take O(N) where N is the number of instructions within the parent block.
|
||||
bool Instruction::isBeforeInBlock(Instruction *other) {
|
||||
assert(block && "Instructions without parent blocks have no order.");
|
||||
assert(other && other->block == block &&
|
||||
"Expected other instruction to have the same parent block.");
|
||||
// Recompute the parent ordering if necessary.
|
||||
if (!block->isInstOrderValid())
|
||||
block->recomputeInstOrder();
|
||||
return orderIndex < other->orderIndex;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ilist_traits for Instruction
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
auto llvm::ilist_detail::SpecificNodeAccess<
|
||||
typename llvm::ilist_detail::compute_node_options<
|
||||
::mlir::Instruction>::type>::getNodePtr(pointer N) -> node_type * {
|
||||
return NodeAccess::getNodePtr<OptionsT>(N);
|
||||
}
|
||||
|
||||
auto llvm::ilist_detail::SpecificNodeAccess<
|
||||
typename llvm::ilist_detail::compute_node_options<
|
||||
::mlir::Instruction>::type>::getNodePtr(const_pointer N)
|
||||
-> const node_type * {
|
||||
return NodeAccess::getNodePtr<OptionsT>(N);
|
||||
}
|
||||
|
||||
auto llvm::ilist_detail::SpecificNodeAccess<
|
||||
typename llvm::ilist_detail::compute_node_options<
|
||||
::mlir::Instruction>::type>::getValuePtr(node_type *N) -> pointer {
|
||||
return NodeAccess::getValuePtr<OptionsT>(N);
|
||||
}
|
||||
|
||||
auto llvm::ilist_detail::SpecificNodeAccess<
|
||||
typename llvm::ilist_detail::compute_node_options<
|
||||
::mlir::Instruction>::type>::getValuePtr(const node_type *N)
|
||||
-> const_pointer {
|
||||
return NodeAccess::getValuePtr<OptionsT>(N);
|
||||
}
|
||||
|
||||
void llvm::ilist_traits<::mlir::Instruction>::deleteNode(Instruction *inst) {
|
||||
inst->destroy();
|
||||
}
|
||||
|
||||
Block *llvm::ilist_traits<::mlir::Instruction>::getContainingBlock() {
|
||||
size_t Offset(size_t(&((Block *)nullptr->*Block::getSublistAccess(nullptr))));
|
||||
iplist<Instruction> *Anchor(static_cast<iplist<Instruction> *>(this));
|
||||
return reinterpret_cast<Block *>(reinterpret_cast<char *>(Anchor) - Offset);
|
||||
}
|
||||
|
||||
/// This is a trait method invoked when a instruction is added to a block. We
|
||||
/// keep the block pointer up to date.
|
||||
void llvm::ilist_traits<::mlir::Instruction>::addNodeToList(Instruction *inst) {
|
||||
assert(!inst->getBlock() && "already in a instruction block!");
|
||||
inst->block = getContainingBlock();
|
||||
|
||||
// Invalidate the block ordering.
|
||||
inst->block->invalidateInstOrder();
|
||||
}
|
||||
|
||||
/// This is a trait method invoked when a instruction is removed from a block.
|
||||
/// We keep the block pointer up to date.
|
||||
void llvm::ilist_traits<::mlir::Instruction>::removeNodeFromList(
|
||||
Instruction *inst) {
|
||||
assert(inst->block && "not already in a instruction block!");
|
||||
inst->block = nullptr;
|
||||
}
|
||||
|
||||
/// This is a trait method invoked when a instruction is moved from one block
|
||||
/// to another. We keep the block pointer up to date.
|
||||
void llvm::ilist_traits<::mlir::Instruction>::transferNodesFromList(
|
||||
ilist_traits<Instruction> &otherList, inst_iterator first,
|
||||
inst_iterator last) {
|
||||
Block *curParent = getContainingBlock();
|
||||
|
||||
// Invalidate the ordering of the parent block.
|
||||
curParent->invalidateInstOrder();
|
||||
|
||||
// If we are transferring instructions within the same block, the block
|
||||
// pointer doesn't need to be updated.
|
||||
if (curParent == otherList.getContainingBlock())
|
||||
return;
|
||||
|
||||
// Update the 'block' member of each instruction.
|
||||
for (; first != last; ++first)
|
||||
first->block = curParent;
|
||||
}
|
||||
|
||||
/// Remove this instruction (and its descendants) from its Block and delete
|
||||
/// all of them.
|
||||
void Instruction::erase() {
|
||||
assert(getBlock() && "Instruction has no block");
|
||||
getBlock()->getInstructions().erase(this);
|
||||
}
|
||||
|
||||
/// Unlink this instruction from its current block and insert it right before
|
||||
/// `existingInst` which may be in the same or another block in the same
|
||||
/// function.
|
||||
void Instruction::moveBefore(Instruction *existingInst) {
|
||||
moveBefore(existingInst->getBlock(), existingInst->getIterator());
|
||||
}
|
||||
|
||||
/// Unlink this operation instruction from its current basic block and insert
|
||||
/// it right before `iterator` in the specified basic block.
|
||||
void Instruction::moveBefore(Block *block,
|
||||
llvm::iplist<Instruction>::iterator iterator) {
|
||||
block->getInstructions().splice(iterator, getBlock()->getInstructions(),
|
||||
getIterator());
|
||||
}
|
||||
|
||||
/// 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();
|
||||
|
||||
for (auto ®ion : getRegions())
|
||||
for (Block &block : region)
|
||||
block.dropAllReferences();
|
||||
|
||||
for (auto &dest : getBlockOperands())
|
||||
dest.drop();
|
||||
}
|
||||
|
||||
/// This drops all uses of any values defined by this operation or its nested
|
||||
/// regions, wherever they are located.
|
||||
void Instruction::dropAllDefinedValueUses() {
|
||||
for (auto &val : getInstResults())
|
||||
val.dropAllUses();
|
||||
|
||||
for (auto ®ion : getRegions())
|
||||
for (auto &block : region)
|
||||
block.dropAllDefinedValueUses();
|
||||
}
|
||||
|
||||
/// Return true if there are no users of any results of this operation.
|
||||
bool Instruction::use_empty() {
|
||||
for (auto *result : getResults())
|
||||
if (!result->use_empty())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Instruction::setSuccessor(Block *block, unsigned index) {
|
||||
assert(index < getNumSuccessors());
|
||||
getBlockOperands()[index].set(block);
|
||||
}
|
||||
|
||||
auto Instruction::getNonSuccessorOperands() -> operand_range {
|
||||
return {operand_iterator(this, 0),
|
||||
operand_iterator(this, getSuccessorOperandIndex(0))};
|
||||
}
|
||||
|
||||
/// Get the index of the first operand of the successor at the provided
|
||||
/// index.
|
||||
unsigned Instruction::getSuccessorOperandIndex(unsigned index) {
|
||||
assert(!isKnownNonTerminator() && "only terminators may have successors");
|
||||
assert(index < getNumSuccessors());
|
||||
|
||||
// Count the number of operands for each of the successors after, and
|
||||
// including, the one at 'index'. This is based upon the assumption that all
|
||||
// non successor operands are placed at the beginning of the operand list.
|
||||
auto *successorOpCountBegin = getTrailingObjects<unsigned>();
|
||||
unsigned postSuccessorOpCount =
|
||||
std::accumulate(successorOpCountBegin + index,
|
||||
successorOpCountBegin + getNumSuccessors(), 0);
|
||||
return getNumOperands() - postSuccessorOpCount;
|
||||
}
|
||||
|
||||
auto Instruction::getSuccessorOperands(unsigned index) -> operand_range {
|
||||
unsigned succOperandIndex = getSuccessorOperandIndex(index);
|
||||
return {operand_iterator(this, succOperandIndex),
|
||||
operand_iterator(this,
|
||||
succOperandIndex + getNumSuccessorOperands(index))};
|
||||
}
|
||||
|
||||
/// Attempt to constant fold this operation with the specified constant
|
||||
/// operand values. If successful, this fills in the results vector. If not,
|
||||
/// results is unspecified.
|
||||
LogicalResult Instruction::constantFold(ArrayRef<Attribute> operands,
|
||||
SmallVectorImpl<Attribute> &results) {
|
||||
if (auto *abstractOp = getAbstractOperation()) {
|
||||
// If we have a registered operation definition matching this one, use it to
|
||||
// try to constant fold the operation.
|
||||
if (succeeded(abstractOp->constantFoldHook(this, operands, results)))
|
||||
return success();
|
||||
|
||||
// Otherwise, fall back on the dialect hook to handle it.
|
||||
return abstractOp->dialect.constantFoldHook(this, operands, results);
|
||||
}
|
||||
|
||||
// If this operation hasn't been registered or doesn't have abstract
|
||||
// operation, fall back to a dialect which matches the prefix.
|
||||
auto opName = getName().getStringRef();
|
||||
auto dialectPrefix = opName.split('.').first;
|
||||
if (auto *dialect = getContext()->getRegisteredDialect(dialectPrefix))
|
||||
return dialect->constantFoldHook(this, operands, results);
|
||||
|
||||
return failure();
|
||||
}
|
||||
|
||||
/// Attempt to fold this operation using the Op's registered foldHook.
|
||||
LogicalResult Instruction::fold(SmallVectorImpl<Value *> &results) {
|
||||
if (auto *abstractOp = getAbstractOperation()) {
|
||||
// If we have a registered operation definition matching this one, use it to
|
||||
// try to constant fold the operation.
|
||||
if (succeeded(abstractOp->foldHook(this, results)))
|
||||
return success();
|
||||
}
|
||||
return failure();
|
||||
}
|
||||
|
||||
/// Emit an error with the op name prefixed, like "'dim' op " which is
|
||||
/// convenient for verifiers.
|
||||
bool Instruction::emitOpError(const Twine &message) {
|
||||
return emitError(Twine('\'') + getName().getStringRef() + "' op " + message);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Instruction Cloning
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// Create a deep copy of this instruction, remapping any operands that use
|
||||
/// values outside of the instruction using the map that is provided (leaving
|
||||
/// them alone if no entry is present). Replaces references to cloned
|
||||
/// sub-instructions to the corresponding instruction that is copied, and adds
|
||||
/// those mappings to the map.
|
||||
Instruction *Instruction::clone(BlockAndValueMapping &mapper,
|
||||
MLIRContext *context) {
|
||||
SmallVector<Value *, 8> operands;
|
||||
SmallVector<Block *, 2> successors;
|
||||
|
||||
operands.reserve(getNumOperands() + getNumSuccessors());
|
||||
|
||||
if (getNumSuccessors() == 0) {
|
||||
// Non-branching operations can just add all the operands.
|
||||
for (auto *opValue : getOperands())
|
||||
operands.push_back(mapper.lookupOrDefault(opValue));
|
||||
} else {
|
||||
// We add the operands separated by nullptr's for each successor.
|
||||
unsigned firstSuccOperand =
|
||||
getNumSuccessors() ? getSuccessorOperandIndex(0) : getNumOperands();
|
||||
auto InstOperands = getInstOperands();
|
||||
|
||||
unsigned i = 0;
|
||||
for (; i != firstSuccOperand; ++i)
|
||||
operands.push_back(mapper.lookupOrDefault(InstOperands[i].get()));
|
||||
|
||||
successors.reserve(getNumSuccessors());
|
||||
for (unsigned succ = 0, e = getNumSuccessors(); succ != e; ++succ) {
|
||||
successors.push_back(mapper.lookupOrDefault(getSuccessor(succ)));
|
||||
|
||||
// Add sentinel to delineate successor operands.
|
||||
operands.push_back(nullptr);
|
||||
|
||||
// Remap the successors operands.
|
||||
for (auto *operand : getSuccessorOperands(succ))
|
||||
operands.push_back(mapper.lookupOrDefault(operand));
|
||||
}
|
||||
}
|
||||
|
||||
SmallVector<Type, 8> resultTypes;
|
||||
resultTypes.reserve(getNumResults());
|
||||
for (auto *result : getResults())
|
||||
resultTypes.push_back(result->getType());
|
||||
|
||||
unsigned numRegions = getNumRegions();
|
||||
auto *newOp = Instruction::create(getLoc(), getName(), operands, resultTypes,
|
||||
attrs, successors, numRegions,
|
||||
hasResizableOperandsList(), context);
|
||||
|
||||
// Clone the regions.
|
||||
for (unsigned i = 0; i != numRegions; ++i)
|
||||
getRegion(i).cloneInto(&newOp->getRegion(i), mapper, context);
|
||||
|
||||
// Remember the mapping of any results.
|
||||
for (unsigned i = 0, e = getNumResults(); i != e; ++i)
|
||||
mapper.map(getResult(i), newOp->getResult(i));
|
||||
return newOp;
|
||||
}
|
||||
|
||||
Instruction *Instruction::clone(MLIRContext *context) {
|
||||
BlockAndValueMapping mapper;
|
||||
return clone(mapper, context);
|
||||
}
|
||||
@@ -15,9 +15,10 @@
|
||||
// limitations under the License.
|
||||
// =============================================================================
|
||||
|
||||
#include "mlir/IR/Operation.h"
|
||||
#include "mlir/IR/BlockAndValueMapping.h"
|
||||
#include "mlir/IR/Dialect.h"
|
||||
#include "mlir/IR/Function.h"
|
||||
#include "mlir/IR/Instruction.h"
|
||||
#include "mlir/IR/MLIRContext.h"
|
||||
#include "mlir/IR/OpDefinition.h"
|
||||
#include "mlir/IR/OpImplementation.h"
|
||||
@@ -51,6 +52,564 @@ OperationName OperationName::getFromOpaquePointer(void *pointer) {
|
||||
|
||||
OpAsmParser::~OpAsmParser() {}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// InstResult
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// Return the result number of this result.
|
||||
unsigned InstResult::getResultNumber() {
|
||||
// Results are always stored consecutively, so use pointer subtraction to
|
||||
// figure out what number this is.
|
||||
return this - &getOwner()->getInstResults()[0];
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// InstOperand
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// Return which operand this is in the operand list.
|
||||
template <> unsigned InstOperand::getOperandNumber() {
|
||||
return this - &getOwner()->getInstOperands()[0];
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// BlockOperand
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// Return which operand this is in the operand list.
|
||||
template <> unsigned BlockOperand::getOperandNumber() {
|
||||
return this - &getOwner()->getBlockOperands()[0];
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Operation
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// Create a new Operation with the specific fields.
|
||||
Operation *Operation::create(Location location, OperationName name,
|
||||
ArrayRef<Value *> operands,
|
||||
ArrayRef<Type> resultTypes,
|
||||
ArrayRef<NamedAttribute> attributes,
|
||||
ArrayRef<Block *> successors, unsigned numRegions,
|
||||
bool resizableOperandList, MLIRContext *context) {
|
||||
return create(location, name, operands, resultTypes,
|
||||
NamedAttributeList(context, attributes), successors, numRegions,
|
||||
resizableOperandList, context);
|
||||
}
|
||||
|
||||
/// Overload of create that takes an existing NamedAttributeList to avoid
|
||||
/// unnecessarily uniquing a list of attributes.
|
||||
Operation *Operation::create(Location location, OperationName name,
|
||||
ArrayRef<Value *> operands,
|
||||
ArrayRef<Type> resultTypes,
|
||||
const NamedAttributeList &attributes,
|
||||
ArrayRef<Block *> successors, unsigned numRegions,
|
||||
bool resizableOperandList, MLIRContext *context) {
|
||||
unsigned numSuccessors = successors.size();
|
||||
|
||||
// Input operands are nullptr-separated for each successor, the null operands
|
||||
// aren't actually stored.
|
||||
unsigned numOperands = operands.size() - numSuccessors;
|
||||
|
||||
// Compute the byte size for the operation and the operand storage.
|
||||
auto byteSize = totalSizeToAlloc<InstResult, BlockOperand, unsigned, Region,
|
||||
detail::OperandStorage>(
|
||||
resultTypes.size(), numSuccessors, numSuccessors, numRegions,
|
||||
/*detail::OperandStorage*/ 1);
|
||||
byteSize += llvm::alignTo(detail::OperandStorage::additionalAllocSize(
|
||||
numOperands, resizableOperandList),
|
||||
alignof(Operation));
|
||||
void *rawMem = malloc(byteSize);
|
||||
|
||||
// Create the new Operation.
|
||||
auto op =
|
||||
::new (rawMem) Operation(location, name, resultTypes.size(),
|
||||
numSuccessors, numRegions, attributes, context);
|
||||
|
||||
assert((numSuccessors == 0 || !op->isKnownNonTerminator()) &&
|
||||
"unexpected successors in a non-terminator operation");
|
||||
|
||||
// Initialize the regions.
|
||||
for (unsigned i = 0; i != numRegions; ++i)
|
||||
new (&op->getRegion(i)) Region(op);
|
||||
|
||||
// Initialize the results and operands.
|
||||
new (&op->getOperandStorage())
|
||||
detail::OperandStorage(numOperands, resizableOperandList);
|
||||
|
||||
auto instResults = op->getInstResults();
|
||||
for (unsigned i = 0, e = resultTypes.size(); i != e; ++i)
|
||||
new (&instResults[i]) InstResult(resultTypes[i], op);
|
||||
|
||||
auto InstOperands = op->getInstOperands();
|
||||
|
||||
// Initialize normal operands.
|
||||
unsigned operandIt = 0, operandE = operands.size();
|
||||
unsigned nextOperand = 0;
|
||||
for (; operandIt != operandE; ++operandIt) {
|
||||
// Null operands are used as sentinels between successor operand lists. If
|
||||
// we encounter one here, break and handle the successor operands lists
|
||||
// separately below.
|
||||
if (!operands[operandIt])
|
||||
break;
|
||||
new (&InstOperands[nextOperand++]) InstOperand(op, operands[operandIt]);
|
||||
}
|
||||
|
||||
unsigned currentSuccNum = 0;
|
||||
if (operandIt == operandE) {
|
||||
// Verify that the amount of sentinel operands is equivalent to the number
|
||||
// of successors.
|
||||
assert(currentSuccNum == numSuccessors);
|
||||
return op;
|
||||
}
|
||||
|
||||
assert(!op->isKnownNonTerminator() &&
|
||||
"Unexpected nullptr in operand list when creating non-terminator.");
|
||||
auto instBlockOperands = op->getBlockOperands();
|
||||
unsigned *succOperandCountIt = op->getTrailingObjects<unsigned>();
|
||||
unsigned *succOperandCountE = succOperandCountIt + numSuccessors;
|
||||
(void)succOperandCountE;
|
||||
|
||||
for (; operandIt != operandE; ++operandIt) {
|
||||
// If we encounter a sentinel branch to the next operand update the count
|
||||
// variable.
|
||||
if (!operands[operandIt]) {
|
||||
assert(currentSuccNum < numSuccessors);
|
||||
|
||||
// After the first iteration update the successor operand count
|
||||
// variable.
|
||||
if (currentSuccNum != 0) {
|
||||
++succOperandCountIt;
|
||||
assert(succOperandCountIt != succOperandCountE &&
|
||||
"More sentinel operands than successors.");
|
||||
}
|
||||
|
||||
new (&instBlockOperands[currentSuccNum])
|
||||
BlockOperand(op, successors[currentSuccNum]);
|
||||
*succOperandCountIt = 0;
|
||||
++currentSuccNum;
|
||||
continue;
|
||||
}
|
||||
new (&InstOperands[nextOperand++]) InstOperand(op, operands[operandIt]);
|
||||
++(*succOperandCountIt);
|
||||
}
|
||||
|
||||
// Verify that the amount of sentinel operands is equivalent to the number of
|
||||
// successors.
|
||||
assert(currentSuccNum == numSuccessors);
|
||||
|
||||
return op;
|
||||
}
|
||||
|
||||
Operation::Operation(Location location, OperationName name, unsigned numResults,
|
||||
unsigned numSuccessors, unsigned numRegions,
|
||||
const NamedAttributeList &attributes, MLIRContext *context)
|
||||
: location(location), numResults(numResults), numSuccs(numSuccessors),
|
||||
numRegions(numRegions), name(name), attrs(attributes) {}
|
||||
|
||||
// Operations are deleted through the destroy() member because they are
|
||||
// allocated via malloc.
|
||||
Operation::~Operation() {
|
||||
assert(block == nullptr && "operation destroyed but still in a block");
|
||||
|
||||
// Explicitly run the destructors for the operands and results.
|
||||
getOperandStorage().~OperandStorage();
|
||||
|
||||
for (auto &result : getInstResults())
|
||||
result.~InstResult();
|
||||
|
||||
// Explicitly run the destructors for the successors.
|
||||
for (auto &successor : getBlockOperands())
|
||||
successor.~BlockOperand();
|
||||
|
||||
// Explicitly destroy the regions.
|
||||
for (auto ®ion : getRegions())
|
||||
region.~Region();
|
||||
}
|
||||
|
||||
/// Destroy this operation or one of its subclasses.
|
||||
void Operation::destroy() {
|
||||
this->~Operation();
|
||||
free(this);
|
||||
}
|
||||
|
||||
/// Return the context this operation is associated with.
|
||||
MLIRContext *Operation::getContext() {
|
||||
// If we have a result or operand type, that is a constant time way to get
|
||||
// to the context.
|
||||
if (getNumResults())
|
||||
return getResult(0)->getType().getContext();
|
||||
if (getNumOperands())
|
||||
return getOperand(0)->getType().getContext();
|
||||
|
||||
// In the very odd case where we have no operands or results, fall back to
|
||||
// doing a find.
|
||||
return getFunction()->getContext();
|
||||
}
|
||||
|
||||
/// Return the dialact this operation is associated with, or nullptr if the
|
||||
/// associated dialect is not registered.
|
||||
Dialect *Operation::getDialect() {
|
||||
if (auto *abstractOp = getAbstractOperation())
|
||||
return &abstractOp->dialect;
|
||||
|
||||
// If this operation hasn't been registered or doesn't have abstract
|
||||
// operation, fall back to a dialect which matches the prefix.
|
||||
auto opName = getName().getStringRef();
|
||||
auto dialectPrefix = opName.split('.').first;
|
||||
return getContext()->getRegisteredDialect(dialectPrefix);
|
||||
}
|
||||
|
||||
Operation *Operation::getParentInst() {
|
||||
return block ? block->getContainingInst() : nullptr;
|
||||
}
|
||||
|
||||
Function *Operation::getFunction() {
|
||||
return block ? block->getFunction() : nullptr;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Operation Walkers
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void Operation::walk(const std::function<void(Operation *)> &callback) {
|
||||
// Visit the current operation.
|
||||
callback(this);
|
||||
|
||||
// Visit any internal operations.
|
||||
for (auto ®ion : getRegions())
|
||||
for (auto &block : region)
|
||||
block.walk(callback);
|
||||
}
|
||||
|
||||
void Operation::walkPostOrder(
|
||||
const std::function<void(Operation *)> &callback) {
|
||||
// Visit any internal operations.
|
||||
for (auto ®ion : llvm::reverse(getRegions()))
|
||||
for (auto &block : llvm::reverse(region))
|
||||
block.walkPostOrder(callback);
|
||||
|
||||
// Visit the current operation.
|
||||
callback(this);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Other
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// Emit a note about this operation, reporting up to any diagnostic
|
||||
/// handlers that may be listening.
|
||||
void Operation::emitNote(const Twine &message) {
|
||||
getContext()->emitDiagnostic(getLoc(), message,
|
||||
MLIRContext::DiagnosticKind::Note);
|
||||
}
|
||||
|
||||
/// Emit a warning about this operation, reporting up to any diagnostic
|
||||
/// handlers that may be listening.
|
||||
void Operation::emitWarning(const Twine &message) {
|
||||
getContext()->emitDiagnostic(getLoc(), message,
|
||||
MLIRContext::DiagnosticKind::Warning);
|
||||
}
|
||||
|
||||
/// Emit an error about fatal conditions with this operation, reporting up to
|
||||
/// any diagnostic handlers that may be listening. This function always
|
||||
/// returns true. NOTE: This may terminate the containing application, only
|
||||
/// use when the IR is in an inconsistent state.
|
||||
bool Operation::emitError(const Twine &message) {
|
||||
return getContext()->emitError(getLoc(), message);
|
||||
}
|
||||
|
||||
/// Given an operation 'other' that is within the same parent block, return
|
||||
/// whether the current operation is before 'other' in the operation list
|
||||
/// of the parent block.
|
||||
/// Note: This function has an average complexity of O(1), but worst case may
|
||||
/// take O(N) where N is the number of operations within the parent block.
|
||||
bool Operation::isBeforeInBlock(Operation *other) {
|
||||
assert(block && "Operations without parent blocks have no order.");
|
||||
assert(other && other->block == block &&
|
||||
"Expected other operation to have the same parent block.");
|
||||
// Recompute the parent ordering if necessary.
|
||||
if (!block->isInstOrderValid())
|
||||
block->recomputeInstOrder();
|
||||
return orderIndex < other->orderIndex;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ilist_traits for Operation
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
auto llvm::ilist_detail::SpecificNodeAccess<
|
||||
typename llvm::ilist_detail::compute_node_options<
|
||||
::mlir::Operation>::type>::getNodePtr(pointer N) -> node_type * {
|
||||
return NodeAccess::getNodePtr<OptionsT>(N);
|
||||
}
|
||||
|
||||
auto llvm::ilist_detail::SpecificNodeAccess<
|
||||
typename llvm::ilist_detail::compute_node_options<
|
||||
::mlir::Operation>::type>::getNodePtr(const_pointer N)
|
||||
-> const node_type * {
|
||||
return NodeAccess::getNodePtr<OptionsT>(N);
|
||||
}
|
||||
|
||||
auto llvm::ilist_detail::SpecificNodeAccess<
|
||||
typename llvm::ilist_detail::compute_node_options<
|
||||
::mlir::Operation>::type>::getValuePtr(node_type *N) -> pointer {
|
||||
return NodeAccess::getValuePtr<OptionsT>(N);
|
||||
}
|
||||
|
||||
auto llvm::ilist_detail::SpecificNodeAccess<
|
||||
typename llvm::ilist_detail::compute_node_options<
|
||||
::mlir::Operation>::type>::getValuePtr(const node_type *N)
|
||||
-> const_pointer {
|
||||
return NodeAccess::getValuePtr<OptionsT>(N);
|
||||
}
|
||||
|
||||
void llvm::ilist_traits<::mlir::Operation>::deleteNode(Operation *op) {
|
||||
op->destroy();
|
||||
}
|
||||
|
||||
Block *llvm::ilist_traits<::mlir::Operation>::getContainingBlock() {
|
||||
size_t Offset(size_t(&((Block *)nullptr->*Block::getSublistAccess(nullptr))));
|
||||
iplist<Operation> *Anchor(static_cast<iplist<Operation> *>(this));
|
||||
return reinterpret_cast<Block *>(reinterpret_cast<char *>(Anchor) - Offset);
|
||||
}
|
||||
|
||||
/// This is a trait method invoked when a operation is added to a block. We
|
||||
/// keep the block pointer up to date.
|
||||
void llvm::ilist_traits<::mlir::Operation>::addNodeToList(Operation *op) {
|
||||
assert(!op->getBlock() && "already in a operation block!");
|
||||
op->block = getContainingBlock();
|
||||
|
||||
// Invalidate the block ordering.
|
||||
op->block->invalidateInstOrder();
|
||||
}
|
||||
|
||||
/// This is a trait method invoked when a operation is removed from a block.
|
||||
/// We keep the block pointer up to date.
|
||||
void llvm::ilist_traits<::mlir::Operation>::removeNodeFromList(Operation *op) {
|
||||
assert(op->block && "not already in a operation block!");
|
||||
op->block = nullptr;
|
||||
}
|
||||
|
||||
/// This is a trait method invoked when a operation is moved from one block
|
||||
/// to another. We keep the block pointer up to date.
|
||||
void llvm::ilist_traits<::mlir::Operation>::transferNodesFromList(
|
||||
ilist_traits<Operation> &otherList, inst_iterator first,
|
||||
inst_iterator last) {
|
||||
Block *curParent = getContainingBlock();
|
||||
|
||||
// Invalidate the ordering of the parent block.
|
||||
curParent->invalidateInstOrder();
|
||||
|
||||
// If we are transferring operations within the same block, the block
|
||||
// pointer doesn't need to be updated.
|
||||
if (curParent == otherList.getContainingBlock())
|
||||
return;
|
||||
|
||||
// Update the 'block' member of each operation.
|
||||
for (; first != last; ++first)
|
||||
first->block = curParent;
|
||||
}
|
||||
|
||||
/// Remove this operation (and its descendants) from its Block and delete
|
||||
/// all of them.
|
||||
void Operation::erase() {
|
||||
assert(getBlock() && "Operation has no block");
|
||||
getBlock()->getInstructions().erase(this);
|
||||
}
|
||||
|
||||
/// Unlink this operation from its current block and insert it right before
|
||||
/// `existingInst` which may be in the same or another block in the same
|
||||
/// function.
|
||||
void Operation::moveBefore(Operation *existingInst) {
|
||||
moveBefore(existingInst->getBlock(), existingInst->getIterator());
|
||||
}
|
||||
|
||||
/// Unlink this operation operation from its current basic block and insert
|
||||
/// it right before `iterator` in the specified basic block.
|
||||
void Operation::moveBefore(Block *block,
|
||||
llvm::iplist<Operation>::iterator iterator) {
|
||||
block->getInstructions().splice(iterator, getBlock()->getInstructions(),
|
||||
getIterator());
|
||||
}
|
||||
|
||||
/// This drops all operand uses from this operation, which is an essential
|
||||
/// step in breaking cyclic dependences between references when they are to
|
||||
/// be deleted.
|
||||
void Operation::dropAllReferences() {
|
||||
for (auto &op : getInstOperands())
|
||||
op.drop();
|
||||
|
||||
for (auto ®ion : getRegions())
|
||||
for (Block &block : region)
|
||||
block.dropAllReferences();
|
||||
|
||||
for (auto &dest : getBlockOperands())
|
||||
dest.drop();
|
||||
}
|
||||
|
||||
/// This drops all uses of any values defined by this operation or its nested
|
||||
/// regions, wherever they are located.
|
||||
void Operation::dropAllDefinedValueUses() {
|
||||
for (auto &val : getInstResults())
|
||||
val.dropAllUses();
|
||||
|
||||
for (auto ®ion : getRegions())
|
||||
for (auto &block : region)
|
||||
block.dropAllDefinedValueUses();
|
||||
}
|
||||
|
||||
/// Return true if there are no users of any results of this operation.
|
||||
bool Operation::use_empty() {
|
||||
for (auto *result : getResults())
|
||||
if (!result->use_empty())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Operation::setSuccessor(Block *block, unsigned index) {
|
||||
assert(index < getNumSuccessors());
|
||||
getBlockOperands()[index].set(block);
|
||||
}
|
||||
|
||||
auto Operation::getNonSuccessorOperands() -> operand_range {
|
||||
return {operand_iterator(this, 0),
|
||||
operand_iterator(this, getSuccessorOperandIndex(0))};
|
||||
}
|
||||
|
||||
/// Get the index of the first operand of the successor at the provided
|
||||
/// index.
|
||||
unsigned Operation::getSuccessorOperandIndex(unsigned index) {
|
||||
assert(!isKnownNonTerminator() && "only terminators may have successors");
|
||||
assert(index < getNumSuccessors());
|
||||
|
||||
// Count the number of operands for each of the successors after, and
|
||||
// including, the one at 'index'. This is based upon the assumption that all
|
||||
// non successor operands are placed at the beginning of the operand list.
|
||||
auto *successorOpCountBegin = getTrailingObjects<unsigned>();
|
||||
unsigned postSuccessorOpCount =
|
||||
std::accumulate(successorOpCountBegin + index,
|
||||
successorOpCountBegin + getNumSuccessors(), 0u);
|
||||
return getNumOperands() - postSuccessorOpCount;
|
||||
}
|
||||
|
||||
auto Operation::getSuccessorOperands(unsigned index) -> operand_range {
|
||||
unsigned succOperandIndex = getSuccessorOperandIndex(index);
|
||||
return {operand_iterator(this, succOperandIndex),
|
||||
operand_iterator(this,
|
||||
succOperandIndex + getNumSuccessorOperands(index))};
|
||||
}
|
||||
|
||||
/// Attempt to constant fold this operation with the specified constant
|
||||
/// operand values. If successful, this fills in the results vector. If not,
|
||||
/// results is unspecified.
|
||||
LogicalResult Operation::constantFold(ArrayRef<Attribute> operands,
|
||||
SmallVectorImpl<Attribute> &results) {
|
||||
if (auto *abstractOp = getAbstractOperation()) {
|
||||
// If we have a registered operation definition matching this one, use it to
|
||||
// try to constant fold the operation.
|
||||
if (succeeded(abstractOp->constantFoldHook(this, operands, results)))
|
||||
return success();
|
||||
|
||||
// Otherwise, fall back on the dialect hook to handle it.
|
||||
return abstractOp->dialect.constantFoldHook(this, operands, results);
|
||||
}
|
||||
|
||||
// If this operation hasn't been registered or doesn't have abstract
|
||||
// operation, fall back to a dialect which matches the prefix.
|
||||
auto opName = getName().getStringRef();
|
||||
auto dialectPrefix = opName.split('.').first;
|
||||
if (auto *dialect = getContext()->getRegisteredDialect(dialectPrefix))
|
||||
return dialect->constantFoldHook(this, operands, results);
|
||||
|
||||
return failure();
|
||||
}
|
||||
|
||||
/// Attempt to fold this operation using the Op's registered foldHook.
|
||||
LogicalResult Operation::fold(SmallVectorImpl<Value *> &results) {
|
||||
if (auto *abstractOp = getAbstractOperation()) {
|
||||
// If we have a registered operation definition matching this one, use it to
|
||||
// try to constant fold the operation.
|
||||
if (succeeded(abstractOp->foldHook(this, results)))
|
||||
return success();
|
||||
}
|
||||
return failure();
|
||||
}
|
||||
|
||||
/// Emit an error with the op name prefixed, like "'dim' op " which is
|
||||
/// convenient for verifiers.
|
||||
bool Operation::emitOpError(const Twine &message) {
|
||||
return emitError(Twine('\'') + getName().getStringRef() + "' op " + message);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Operation Cloning
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// Create a deep copy of this operation, remapping any operands that use
|
||||
/// values outside of the operation using the map that is provided (leaving
|
||||
/// them alone if no entry is present). Replaces references to cloned
|
||||
/// sub-operations to the corresponding operation that is copied, and adds
|
||||
/// those mappings to the map.
|
||||
Operation *Operation::clone(BlockAndValueMapping &mapper,
|
||||
MLIRContext *context) {
|
||||
SmallVector<Value *, 8> operands;
|
||||
SmallVector<Block *, 2> successors;
|
||||
|
||||
operands.reserve(getNumOperands() + getNumSuccessors());
|
||||
|
||||
if (getNumSuccessors() == 0) {
|
||||
// Non-branching operations can just add all the operands.
|
||||
for (auto *opValue : getOperands())
|
||||
operands.push_back(mapper.lookupOrDefault(opValue));
|
||||
} else {
|
||||
// We add the operands separated by nullptr's for each successor.
|
||||
unsigned firstSuccOperand =
|
||||
getNumSuccessors() ? getSuccessorOperandIndex(0) : getNumOperands();
|
||||
auto InstOperands = getInstOperands();
|
||||
|
||||
unsigned i = 0;
|
||||
for (; i != firstSuccOperand; ++i)
|
||||
operands.push_back(mapper.lookupOrDefault(InstOperands[i].get()));
|
||||
|
||||
successors.reserve(getNumSuccessors());
|
||||
for (unsigned succ = 0, e = getNumSuccessors(); succ != e; ++succ) {
|
||||
successors.push_back(mapper.lookupOrDefault(getSuccessor(succ)));
|
||||
|
||||
// Add sentinel to delineate successor operands.
|
||||
operands.push_back(nullptr);
|
||||
|
||||
// Remap the successors operands.
|
||||
for (auto *operand : getSuccessorOperands(succ))
|
||||
operands.push_back(mapper.lookupOrDefault(operand));
|
||||
}
|
||||
}
|
||||
|
||||
SmallVector<Type, 8> resultTypes;
|
||||
resultTypes.reserve(getNumResults());
|
||||
for (auto *result : getResults())
|
||||
resultTypes.push_back(result->getType());
|
||||
|
||||
unsigned numRegions = getNumRegions();
|
||||
auto *newOp = Operation::create(getLoc(), getName(), operands, resultTypes,
|
||||
attrs, successors, numRegions,
|
||||
hasResizableOperandsList(), context);
|
||||
|
||||
// Clone the regions.
|
||||
for (unsigned i = 0; i != numRegions; ++i)
|
||||
getRegion(i).cloneInto(&newOp->getRegion(i), mapper, context);
|
||||
|
||||
// Remember the mapping of any results.
|
||||
for (unsigned i = 0, e = getNumResults(); i != e; ++i)
|
||||
mapper.map(getResult(i), newOp->getResult(i));
|
||||
return newOp;
|
||||
}
|
||||
|
||||
Operation *Operation::clone(MLIRContext *context) {
|
||||
BlockAndValueMapping mapper;
|
||||
return clone(mapper, context);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// OpState trait class.
|
||||
//===----------------------------------------------------------------------===//
|
||||
@@ -93,19 +652,19 @@ void OpState::emitNote(const Twine &message) {
|
||||
// Op Trait implementations
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
bool OpTrait::impl::verifyZeroOperands(Instruction *op) {
|
||||
bool OpTrait::impl::verifyZeroOperands(Operation *op) {
|
||||
if (op->getNumOperands() != 0)
|
||||
return op->emitOpError("requires zero operands");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool OpTrait::impl::verifyOneOperand(Instruction *op) {
|
||||
bool OpTrait::impl::verifyOneOperand(Operation *op) {
|
||||
if (op->getNumOperands() != 1)
|
||||
return op->emitOpError("requires a single operand");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool OpTrait::impl::verifyNOperands(Instruction *op, unsigned numOperands) {
|
||||
bool OpTrait::impl::verifyNOperands(Operation *op, unsigned numOperands) {
|
||||
if (op->getNumOperands() != numOperands) {
|
||||
return op->emitOpError("expected " + Twine(numOperands) +
|
||||
" operands, but found " +
|
||||
@@ -114,7 +673,7 @@ bool OpTrait::impl::verifyNOperands(Instruction *op, unsigned numOperands) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool OpTrait::impl::verifyAtLeastNOperands(Instruction *op,
|
||||
bool OpTrait::impl::verifyAtLeastNOperands(Operation *op,
|
||||
unsigned numOperands) {
|
||||
if (op->getNumOperands() < numOperands)
|
||||
return op->emitOpError("expected " + Twine(numOperands) +
|
||||
@@ -134,7 +693,7 @@ static Type getTensorOrVectorElementType(Type type) {
|
||||
return type;
|
||||
}
|
||||
|
||||
bool OpTrait::impl::verifyOperandsAreIntegerLike(Instruction *op) {
|
||||
bool OpTrait::impl::verifyOperandsAreIntegerLike(Operation *op) {
|
||||
for (auto *operand : op->getOperands()) {
|
||||
auto type = getTensorOrVectorElementType(operand->getType());
|
||||
if (!type.isIntOrIndex())
|
||||
@@ -143,7 +702,7 @@ bool OpTrait::impl::verifyOperandsAreIntegerLike(Instruction *op) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool OpTrait::impl::verifySameTypeOperands(Instruction *op) {
|
||||
bool OpTrait::impl::verifySameTypeOperands(Operation *op) {
|
||||
// Zero or one operand always have the "same" type.
|
||||
unsigned nOperands = op->getNumOperands();
|
||||
if (nOperands < 2)
|
||||
@@ -157,26 +716,25 @@ bool OpTrait::impl::verifySameTypeOperands(Instruction *op) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool OpTrait::impl::verifyZeroResult(Instruction *op) {
|
||||
bool OpTrait::impl::verifyZeroResult(Operation *op) {
|
||||
if (op->getNumResults() != 0)
|
||||
return op->emitOpError("requires zero results");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool OpTrait::impl::verifyOneResult(Instruction *op) {
|
||||
bool OpTrait::impl::verifyOneResult(Operation *op) {
|
||||
if (op->getNumResults() != 1)
|
||||
return op->emitOpError("requires one result");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool OpTrait::impl::verifyNResults(Instruction *op, unsigned numOperands) {
|
||||
bool OpTrait::impl::verifyNResults(Operation *op, unsigned numOperands) {
|
||||
if (op->getNumResults() != numOperands)
|
||||
return op->emitOpError("expected " + Twine(numOperands) + " results");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool OpTrait::impl::verifyAtLeastNResults(Instruction *op,
|
||||
unsigned numOperands) {
|
||||
bool OpTrait::impl::verifyAtLeastNResults(Operation *op, unsigned numOperands) {
|
||||
if (op->getNumResults() < numOperands)
|
||||
return op->emitOpError("expected " + Twine(numOperands) +
|
||||
" or more results");
|
||||
@@ -204,7 +762,7 @@ static bool verifyShapeMatch(Type type1, Type type2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool OpTrait::impl::verifySameOperandsAndResultShape(Instruction *op) {
|
||||
bool OpTrait::impl::verifySameOperandsAndResultShape(Operation *op) {
|
||||
if (op->getNumOperands() == 0 || op->getNumResults() == 0)
|
||||
return true;
|
||||
|
||||
@@ -222,7 +780,7 @@ bool OpTrait::impl::verifySameOperandsAndResultShape(Instruction *op) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool OpTrait::impl::verifySameOperandsAndResultType(Instruction *op) {
|
||||
bool OpTrait::impl::verifySameOperandsAndResultType(Operation *op) {
|
||||
if (op->getNumOperands() == 0 || op->getNumResults() == 0)
|
||||
return true;
|
||||
|
||||
@@ -241,8 +799,8 @@ bool OpTrait::impl::verifySameOperandsAndResultType(Instruction *op) {
|
||||
}
|
||||
|
||||
static bool
|
||||
verifyBBArguments(llvm::iterator_range<Instruction::operand_iterator> operands,
|
||||
Block *destBB, Instruction *op) {
|
||||
verifyBBArguments(llvm::iterator_range<Operation::operand_iterator> operands,
|
||||
Block *destBB, Operation *op) {
|
||||
unsigned operandCount = std::distance(operands.begin(), operands.end());
|
||||
if (operandCount != destBB->getNumArguments())
|
||||
return op->emitError("branch has " + Twine(operandCount) +
|
||||
@@ -258,7 +816,7 @@ verifyBBArguments(llvm::iterator_range<Instruction::operand_iterator> operands,
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool verifyTerminatorSuccessors(Instruction *op) {
|
||||
static bool verifyTerminatorSuccessors(Operation *op) {
|
||||
// Verify that the operands lines up with the BB arguments in the successor.
|
||||
Function *fn = op->getFunction();
|
||||
for (unsigned i = 0, e = op->getNumSuccessors(); i != e; ++i) {
|
||||
@@ -271,11 +829,11 @@ static bool verifyTerminatorSuccessors(Instruction *op) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool OpTrait::impl::verifyIsTerminator(Instruction *op) {
|
||||
bool OpTrait::impl::verifyIsTerminator(Operation *op) {
|
||||
Block *block = op->getBlock();
|
||||
// Verify that the operation is at the end of the respective parent block.
|
||||
if (!block || &block->back() != op)
|
||||
return op->emitOpError("must be the last instruction in the parent block");
|
||||
return op->emitOpError("must be the last operation in the parent block");
|
||||
|
||||
// Verify the state of the successor blocks.
|
||||
if (op->getNumSuccessors() != 0 && verifyTerminatorSuccessors(op))
|
||||
@@ -283,7 +841,7 @@ bool OpTrait::impl::verifyIsTerminator(Instruction *op) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool OpTrait::impl::verifyResultsAreBoolLike(Instruction *op) {
|
||||
bool OpTrait::impl::verifyResultsAreBoolLike(Operation *op) {
|
||||
for (auto *result : op->getResults()) {
|
||||
auto elementType = getTensorOrVectorElementType(result->getType());
|
||||
bool isBoolType = elementType.isInteger(1);
|
||||
@@ -294,7 +852,7 @@ bool OpTrait::impl::verifyResultsAreBoolLike(Instruction *op) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool OpTrait::impl::verifyResultsAreFloatLike(Instruction *op) {
|
||||
bool OpTrait::impl::verifyResultsAreFloatLike(Operation *op) {
|
||||
for (auto *result : op->getResults()) {
|
||||
if (!getTensorOrVectorElementType(result->getType()).isa<FloatType>())
|
||||
return op->emitOpError("requires a floating point type");
|
||||
@@ -303,7 +861,7 @@ bool OpTrait::impl::verifyResultsAreFloatLike(Instruction *op) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool OpTrait::impl::verifyResultsAreIntegerLike(Instruction *op) {
|
||||
bool OpTrait::impl::verifyResultsAreIntegerLike(Operation *op) {
|
||||
for (auto *result : op->getResults()) {
|
||||
auto type = getTensorOrVectorElementType(result->getType());
|
||||
if (!type.isIntOrIndex())
|
||||
@@ -336,7 +894,7 @@ bool impl::parseBinaryOp(OpAsmParser *parser, OperationState *result) {
|
||||
parser->addTypeToList(type, result->types);
|
||||
}
|
||||
|
||||
void impl::printBinaryOp(Instruction *op, OpAsmPrinter *p) {
|
||||
void impl::printBinaryOp(Operation *op, OpAsmPrinter *p) {
|
||||
assert(op->getNumOperands() == 2 && "binary op should have two operands");
|
||||
assert(op->getNumResults() == 1 && "binary op should have one result");
|
||||
|
||||
@@ -375,7 +933,7 @@ bool impl::parseCastOp(OpAsmParser *parser, OperationState *result) {
|
||||
parser->addTypeToList(dstType, result->types);
|
||||
}
|
||||
|
||||
void impl::printCastOp(Instruction *op, OpAsmPrinter *p) {
|
||||
void impl::printCastOp(Operation *op, OpAsmPrinter *p) {
|
||||
*p << op->getName() << ' ' << *op->getOperand(0) << " : "
|
||||
<< op->getOperand(0)->getType() << " to " << op->getResult(0)->getType();
|
||||
}
|
||||
|
||||
@@ -16,14 +16,18 @@
|
||||
// =============================================================================
|
||||
//
|
||||
// This file contains out-of-line implementations of the support types that
|
||||
// Instruction and related classes build on top of.
|
||||
// Operation and related classes build on top of.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "mlir/IR/OperationSupport.h"
|
||||
#include "mlir/IR/Block.h"
|
||||
#include "mlir/IR/Operation.h"
|
||||
using namespace mlir;
|
||||
|
||||
namespace mlir {
|
||||
//===----------------------------------------------------------------------===//
|
||||
// OperationState
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
OperationState::OperationState(MLIRContext *context, Location location,
|
||||
StringRef name)
|
||||
@@ -59,4 +63,75 @@ void OperationState::addRegion(std::unique_ptr<Region> &®ion) {
|
||||
regions.push_back(std::move(region));
|
||||
}
|
||||
|
||||
} // end namespace mlir
|
||||
//===----------------------------------------------------------------------===//
|
||||
// OperandStorage
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// Replace the operands contained in the storage with the ones provided in
|
||||
/// 'operands'.
|
||||
void detail::OperandStorage::setOperands(Operation *owner,
|
||||
ArrayRef<Value *> operands) {
|
||||
// If the number of operands is less than or equal to the current amount, we
|
||||
// can just update in place.
|
||||
if (operands.size() <= numOperands) {
|
||||
auto instOperands = getInstOperands();
|
||||
|
||||
// If the number of new operands is less than the current count, then remove
|
||||
// any extra operands.
|
||||
for (unsigned i = operands.size(); i != numOperands; ++i)
|
||||
instOperands[i].~InstOperand();
|
||||
|
||||
// Set the operands in place.
|
||||
numOperands = operands.size();
|
||||
for (unsigned i = 0; i != numOperands; ++i)
|
||||
instOperands[i].set(operands[i]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, we need to be resizable.
|
||||
assert(resizable && "Only resizable operations may add operands");
|
||||
|
||||
// Grow the capacity if necessary.
|
||||
auto &resizeUtil = getResizableStorage();
|
||||
if (resizeUtil.capacity < operands.size())
|
||||
grow(resizeUtil, operands.size());
|
||||
|
||||
// Set the operands.
|
||||
InstOperand *opBegin = getRawOperands();
|
||||
for (unsigned i = 0; i != numOperands; ++i)
|
||||
opBegin[i].set(operands[i]);
|
||||
for (unsigned e = operands.size(); numOperands != e; ++numOperands)
|
||||
new (&opBegin[numOperands]) InstOperand(owner, operands[numOperands]);
|
||||
}
|
||||
|
||||
/// Erase an operand held by the storage.
|
||||
void detail::OperandStorage::eraseOperand(unsigned index) {
|
||||
assert(index < size());
|
||||
auto Operands = getInstOperands();
|
||||
--numOperands;
|
||||
|
||||
// Shift all operands down by 1 if the operand to remove is not at the end.
|
||||
if (index != numOperands)
|
||||
std::rotate(&Operands[index], &Operands[index + 1], &Operands[numOperands]);
|
||||
Operands[numOperands].~InstOperand();
|
||||
}
|
||||
|
||||
/// Grow the internal operand storage.
|
||||
void detail::OperandStorage::grow(ResizableStorage &resizeUtil,
|
||||
size_t minSize) {
|
||||
// Allocate a new storage array.
|
||||
resizeUtil.capacity =
|
||||
std::max(size_t(llvm::NextPowerOf2(resizeUtil.capacity + 2)), minSize);
|
||||
InstOperand *newStorage = static_cast<InstOperand *>(
|
||||
llvm::safe_malloc(resizeUtil.capacity * sizeof(InstOperand)));
|
||||
|
||||
// Move the current operands to the new storage.
|
||||
auto operands = getInstOperands();
|
||||
std::uninitialized_copy(std::make_move_iterator(operands.begin()),
|
||||
std::make_move_iterator(operands.end()), newStorage);
|
||||
|
||||
// Destroy the original operands and update the resizable storage pointer.
|
||||
for (auto &operand : operands)
|
||||
operand.~InstOperand();
|
||||
resizeUtil.setDynamicStorage(newStorage);
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
// =============================================================================
|
||||
|
||||
#include "mlir/IR/PatternMatch.h"
|
||||
#include "mlir/IR/Instruction.h"
|
||||
#include "mlir/IR/Operation.h"
|
||||
#include "mlir/IR/Value.h"
|
||||
using namespace mlir;
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
#include "mlir/IR/Value.h"
|
||||
#include "mlir/IR/Function.h"
|
||||
#include "mlir/IR/Instruction.h"
|
||||
#include "mlir/IR/Operation.h"
|
||||
using namespace mlir;
|
||||
|
||||
/// If this value is the result of an Instruction, return the instruction
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
|
||||
#include "mlir/Analysis/AffineStructures.h"
|
||||
#include "mlir/IR/Function.h"
|
||||
#include "mlir/IR/Instruction.h"
|
||||
#include "mlir/IR/IntegerSet.h"
|
||||
#include "mlir/IR/Operation.h"
|
||||
#include "mlir/Pass/Pass.h"
|
||||
#include "mlir/Transforms/Passes.h"
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
// =============================================================================
|
||||
|
||||
#include "mlir/IR/Function.h"
|
||||
#include "mlir/IR/Instruction.h"
|
||||
#include "mlir/IR/Operation.h"
|
||||
#include "mlir/Pass/Pass.h"
|
||||
#include "mlir/Transforms/Passes.h"
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
#include "mlir/IR/AffineMap.h"
|
||||
#include "mlir/IR/BlockAndValueMapping.h"
|
||||
#include "mlir/IR/Builders.h"
|
||||
#include "mlir/IR/Instruction.h"
|
||||
#include "mlir/IR/Operation.h"
|
||||
#include "mlir/StandardOps/Ops.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//===- InstructionSupportTest.cpp - Instruction support unit tests --------===//
|
||||
//===- OperationSupportTest.cpp - Operation support unit tests ------------===//
|
||||
//
|
||||
// Copyright 2019 The MLIR Authors.
|
||||
//
|
||||
@@ -15,7 +15,7 @@
|
||||
// limitations under the License.
|
||||
// =============================================================================
|
||||
|
||||
#include "mlir/IR/InstructionSupport.h"
|
||||
#include "mlir/IR/OperationSupport.h"
|
||||
#include "mlir/IR/Builders.h"
|
||||
#include "mlir/IR/StandardTypes.h"
|
||||
#include "gtest/gtest.h"
|
||||
@@ -24,10 +24,10 @@ using namespace mlir;
|
||||
using namespace mlir::detail;
|
||||
|
||||
namespace {
|
||||
Instruction *createInst(MLIRContext *context, bool resizableOperands,
|
||||
ArrayRef<Value *> operands = llvm::None,
|
||||
ArrayRef<Type> resultTypes = llvm::None) {
|
||||
return Instruction::create(
|
||||
Operation *createOp(MLIRContext *context, bool resizableOperands,
|
||||
ArrayRef<Value *> operands = llvm::None,
|
||||
ArrayRef<Type> resultTypes = llvm::None) {
|
||||
return Operation::create(
|
||||
UnknownLoc::get(context), OperationName("foo.bar", context), operands,
|
||||
resultTypes, llvm::None, llvm::None, 0, resizableOperands, context);
|
||||
}
|
||||
@@ -36,14 +36,14 @@ TEST(OperandStorageTest, NonResizable) {
|
||||
MLIRContext context;
|
||||
Builder builder(&context);
|
||||
|
||||
Instruction *useInst =
|
||||
createInst(&context, /*resizableOperands=*/false, /*operands=*/llvm::None,
|
||||
builder.getIntegerType(16));
|
||||
Value *operand = useInst->getResult(0);
|
||||
Operation *useOp =
|
||||
createOp(&context, /*resizableOperands=*/false, /*operands=*/llvm::None,
|
||||
builder.getIntegerType(16));
|
||||
Value *operand = useOp->getResult(0);
|
||||
|
||||
// Create a non-resizable instruction with one operand.
|
||||
Instruction *user = createInst(&context, /*resizableOperands=*/false, operand,
|
||||
builder.getIntegerType(16));
|
||||
Operation *user = createOp(&context, /*resizableOperands=*/false, operand,
|
||||
builder.getIntegerType(16));
|
||||
|
||||
// Sanity check the storage.
|
||||
EXPECT_EQ(user->hasResizableOperandsList(), false);
|
||||
@@ -58,21 +58,21 @@ TEST(OperandStorageTest, NonResizable) {
|
||||
|
||||
// Destroy the instructions.
|
||||
user->destroy();
|
||||
useInst->destroy();
|
||||
useOp->destroy();
|
||||
}
|
||||
|
||||
TEST(OperandStorageDeathTest, AddToNonResizable) {
|
||||
MLIRContext context;
|
||||
Builder builder(&context);
|
||||
|
||||
Instruction *useInst =
|
||||
createInst(&context, /*resizableOperands=*/false, /*operands=*/llvm::None,
|
||||
builder.getIntegerType(16));
|
||||
Value *operand = useInst->getResult(0);
|
||||
Operation *useOp =
|
||||
createOp(&context, /*resizableOperands=*/false, /*operands=*/llvm::None,
|
||||
builder.getIntegerType(16));
|
||||
Value *operand = useOp->getResult(0);
|
||||
|
||||
// Create a non-resizable instruction with one operand.
|
||||
Instruction *user = createInst(&context, /*resizableOperands=*/false, operand,
|
||||
builder.getIntegerType(16));
|
||||
Operation *user = createOp(&context, /*resizableOperands=*/false, operand,
|
||||
builder.getIntegerType(16));
|
||||
|
||||
// Sanity check the storage.
|
||||
EXPECT_EQ(user->hasResizableOperandsList(), false);
|
||||
@@ -85,14 +85,14 @@ TEST(OperandStorageTest, Resizable) {
|
||||
MLIRContext context;
|
||||
Builder builder(&context);
|
||||
|
||||
Instruction *useInst =
|
||||
createInst(&context, /*resizableOperands=*/false, /*operands=*/llvm::None,
|
||||
builder.getIntegerType(16));
|
||||
Value *operand = useInst->getResult(0);
|
||||
Operation *useOp =
|
||||
createOp(&context, /*resizableOperands=*/false, /*operands=*/llvm::None,
|
||||
builder.getIntegerType(16));
|
||||
Value *operand = useOp->getResult(0);
|
||||
|
||||
// Create a resizable instruction with one operand.
|
||||
Instruction *user = createInst(&context, /*resizableOperands=*/true, operand,
|
||||
builder.getIntegerType(16));
|
||||
Operation *user = createOp(&context, /*resizableOperands=*/true, operand,
|
||||
builder.getIntegerType(16));
|
||||
|
||||
// Sanity check the storage.
|
||||
EXPECT_EQ(user->hasResizableOperandsList(), true);
|
||||
@@ -111,7 +111,7 @@ TEST(OperandStorageTest, Resizable) {
|
||||
|
||||
// Destroy the instructions.
|
||||
user->destroy();
|
||||
useInst->destroy();
|
||||
useOp->destroy();
|
||||
}
|
||||
|
||||
} // end namespace
|
||||
Reference in New Issue
Block a user