diff --git a/mlir/include/mlir/IR/Dialect.h b/mlir/include/mlir/IR/Dialect.h --- a/mlir/include/mlir/IR/Dialect.h +++ b/mlir/include/mlir/IR/Dialect.h @@ -150,12 +150,9 @@ /// This method is used by derived classes to add their operations to the set. /// template void addOperations() { - (void)std::initializer_list{0, (addOperation(), 0)...}; - } - template void addOperation() { - addOperation(AbstractOperation::get(*this)); + (void)std::initializer_list{ + 0, (AbstractOperation::insert(*this), 0)...}; } - void addOperation(AbstractOperation opInfo); /// Register a set of type classes with this dialect. template void addTypes() { diff --git a/mlir/include/mlir/IR/OpDefinition.h b/mlir/include/mlir/IR/OpDefinition.h --- a/mlir/include/mlir/IR/OpDefinition.h +++ b/mlir/include/mlir/IR/OpDefinition.h @@ -105,6 +105,12 @@ /// Return the operation that this refers to. Operation *getOperation() { return state; } + /// Return the dialect that this refers to. + Dialect *getDialect() { return getOperation()->getDialect(); } + + /// Return the parent Region of this operation. + Region *getParentRegion() { return getOperation()->getParentRegion(); } + /// Returns the closest surrounding operation that contains this operation /// or nullptr if this is a top-level operation. Operation *getParentOp() { return getOperation()->getParentOp(); } @@ -238,7 +244,7 @@ static ParseResult parse(OpAsmParser &parser, OperationState &result); // The fallback for the printer is to print it the generic assembly form. - void print(OpAsmPrinter &p); + static void print(Operation *op, OpAsmPrinter &p); /// Mutability management is handled by the OpWrapper/OpConstWrapper classes, /// so we can cast it away here. @@ -246,6 +252,9 @@ private: Operation *state; + + /// Allow access to internal hook implementation methods. + friend AbstractOperation; }; // Allow comparing operators. @@ -267,117 +276,6 @@ return os; } -/// This template defines the foldHook as used by AbstractOperation. -/// -/// The default implementation uses a general fold method that can be defined on -/// custom ops which can return multiple results. -template -class FoldingHook { -public: - /// This is an implementation detail of the constant folder hook for - /// AbstractOperation. - static LogicalResult foldHook(Operation *op, ArrayRef operands, - SmallVectorImpl &results) { - auto operationFoldResult = cast(op).fold(operands, results); - // Failure to fold or in place fold both mean we can continue folding. - if (failed(operationFoldResult) || results.empty()) { - auto traitFoldResult = ConcreteType::foldTraits(op, operands, results); - // Only return the trait fold result if it is a success since - // operationFoldResult might have been a success originally. - if (succeeded(traitFoldResult)) - return traitFoldResult; - } - return operationFoldResult; - } - - /// This hook implements a generalized folder for this operation. Operations - /// can implement this to provide simplifications rules that are applied by - /// the Builder::createOrFold API and the canonicalization pass. - /// - /// This is an intentionally limited interface - implementations of this hook - /// can only perform the following changes to the operation: - /// - /// 1. They can leave the operation alone and without changing the IR, and - /// return failure. - /// 2. They can mutate the operation in place, without changing anything else - /// in the IR. In this case, return success. - /// 3. They can return a list of existing values that can be used instead of - /// the operation. In this case, fill in the results list and return - /// success. The caller will remove the operation and use those results - /// instead. - /// - /// This allows expression of some simple in-place canonicalizations (e.g. - /// "x+0 -> x", "min(x,y,x,z) -> min(x,y,z)", "x+y-x -> y", etc), as well as - /// generalized constant folding. - /// - /// If not overridden, this fallback implementation always fails to fold. - /// - LogicalResult fold(ArrayRef operands, - SmallVectorImpl &results) { - return failure(); - } -}; - -/// This template specialization defines the foldHook as used by -/// AbstractOperation for single-result operations. This gives the hook a nicer -/// signature that is easier to implement. -template -class FoldingHook::type> { -public: - /// If the operation returns a single value, then the Op can be implicitly - /// converted to an Value. This yields the value of the only result. - operator Value() { - return static_cast(this)->getOperation()->getResult(0); - } - - /// This is an implementation detail of the constant folder hook for - /// AbstractOperation. - static LogicalResult foldHook(Operation *op, ArrayRef operands, - SmallVectorImpl &results) { - auto result = cast(op).fold(operands); - // Failure to fold or in place fold both mean we can continue folding. - if (!result || result.template dyn_cast() == op->getResult(0)) { - // Only consider the trait fold result if it is a success since - // the operation fold might have been a success originally. - if (auto traitFoldResult = ConcreteType::foldTraits(op, operands)) - result = traitFoldResult; - } - - if (!result) - return failure(); - - // Check if the operation was folded in place. In this case, the operation - // returns itself. - if (result.template dyn_cast() != op->getResult(0)) - results.push_back(result); - return success(); - } - - /// This hook implements a generalized folder for this operation. Operations - /// can implement this to provide simplifications rules that are applied by - /// the Builder::createOrFold API and the canonicalization pass. - /// - /// This is an intentionally limited interface - implementations of this hook - /// can only perform the following changes to the operation: - /// - /// 1. They can leave the operation alone and without changing the IR, and - /// return nullptr. - /// 2. They can mutate the operation in place, without changing anything else - /// in the IR. In this case, return the operation itself. - /// 3. They can return an existing SSA value that can be used instead of - /// the operation. In this case, return that value. The caller will - /// remove the operation and use that result instead. - /// - /// This allows expression of some simple in-place canonicalizations (e.g. - /// "x+0 -> x", "min(x,y,x,z) -> min(x,y,z)", "x+y-x -> y", etc), as well as - /// generalized constant folding. - /// - /// If not overridden, this fallback implementation always fails to fold. - /// - OpFoldResult fold(ArrayRef operands) { return {}; } -}; - //===----------------------------------------------------------------------===// // Operation Trait Types //===----------------------------------------------------------------------===// @@ -428,8 +326,7 @@ /// Helper class for implementing traits. Clients are not expected to interact /// with this directly, so its members are all protected. template class TraitType> -class TraitBase { -protected: +struct TraitBase { /// Return the ultimate Operation being worked on. Operation *getOperation() { // We have to cast up to the trait type, then to the concrete type, then to @@ -441,30 +338,6 @@ auto *base = static_cast(concrete); return base->getOperation(); } - - /// Provide default implementations of trait hooks. This allows traits to - /// provide exactly the overrides they care about. - static LogicalResult verifyTrait(Operation *op) { return success(); } - static AbstractOperation::OperationProperties getTraitProperties() { - return 0; - } - - static OpFoldResult foldTrait(Operation *op, ArrayRef operands) { - SmallVector results; - if (failed(foldTrait(op, operands, results))) - return {}; - if (results.empty()) - return op->getResult(0); - assert(results.size() == 1 && - "Single result op cannot return multiple fold results"); - - return results[0]; - } - - static LogicalResult foldTrait(Operation *op, ArrayRef operands, - SmallVectorImpl &results) { - return failure(); - } }; //===----------------------------------------------------------------------===// @@ -738,6 +611,12 @@ Value getResult() { return this->getOperation()->getResult(0); } Type getType() { return getResult().getType(); } + /// If the operation returns a single value, then the Op can be implicitly + /// converted to an Value. This yields the value of the only result. + operator Value() { + return static_cast(this)->getOperation()->getResult(0); + } + /// Replace all uses of 'this' value with the new value, updating anything in /// the IR that uses 'this' to use the other value instead. When this returns /// there are zero uses of 'this'. @@ -1306,6 +1185,170 @@ } // end namespace OpTrait +//===----------------------------------------------------------------------===// +// Internal Trait Utilities +//===----------------------------------------------------------------------===// + +namespace op_definition_impl { +//===----------------------------------------------------------------------===// +// Trait Existence + +/// Returns true if this given Trait ID matches the IDs of any of the provided +/// trait types `Traits`. +template