Reworking conversion/translation to make it easier to integrate and adding helpers. The helpers make targeting the VM dialect in conversions easier to write and (hopefully) mostly just boilerplate that can eventually be generated. PiperOrigin-RevId: 284291987
diff --git a/iree/compiler/Dialect/HAL/IR/HALOps.cpp b/iree/compiler/Dialect/HAL/IR/HALOps.cpp index f7bdacb..60a6085 100644 --- a/iree/compiler/Dialect/HAL/IR/HALOps.cpp +++ b/iree/compiler/Dialect/HAL/IR/HALOps.cpp
@@ -497,62 +497,44 @@ return success(); } -void VariableOp::build(Builder *builder, OperationState &state, StringRef name, +void VariableOp::build(Builder *builder, OperationState &result, StringRef name, bool isMutable, Type type, Optional<StringRef> initializer, Optional<Attribute> initialValue, ArrayRef<NamedAttribute> attrs) { - state.addAttribute(SymbolTable::getSymbolAttrName(), - builder->getStringAttr(name)); + result.addAttribute(SymbolTable::getSymbolAttrName(), + builder->getStringAttr(name)); if (isMutable) { - state.addAttribute("is_mutable", builder->getUnitAttr()); + result.addAttribute("is_mutable", builder->getUnitAttr()); } if (initializer.hasValue()) { - state.addAttribute("initializer", - builder->getSymbolRefAttr(initializer.getValue())); + result.addAttribute("initializer", + builder->getSymbolRefAttr(initializer.getValue())); } else if (initialValue.hasValue()) { - state.addAttribute("initial_value", initialValue.getValue()); + result.addAttribute("initial_value", initialValue.getValue()); } - state.addAttribute("type", TypeAttr::get(type)); - state.attributes.append(attrs.begin(), attrs.end()); + result.addAttribute("type", TypeAttr::get(type)); + result.attributes.append(attrs.begin(), attrs.end()); } -void VariableOp::build(Builder *builder, OperationState &state, StringRef name, +void VariableOp::build(Builder *builder, OperationState &result, StringRef name, bool isMutable, mlir::FuncOp initializer, ArrayRef<NamedAttribute> attrs) { - state.addAttribute(SymbolTable::getSymbolAttrName(), - builder->getStringAttr(name)); - if (isMutable) { - state.addAttribute("is_mutable", builder->getUnitAttr()); - } - state.addAttribute("initializer", builder->getSymbolRefAttr(initializer)); - state.addAttribute("type", TypeAttr::get(initializer.getType().getResult(0))); - state.attributes.append(attrs.begin(), attrs.end()); + build(builder, result, name, isMutable, initializer.getType().getResult(0), + initializer.getName(), llvm::None, attrs); } void VariableOp::build(Builder *builder, OperationState &result, StringRef name, bool isMutable, Type type, Attribute initialValue, ArrayRef<NamedAttribute> attrs) { - result.addAttribute(SymbolTable::getSymbolAttrName(), - builder->getStringAttr(name)); - if (isMutable) { - result.addAttribute("is_mutable", builder->getUnitAttr()); - } - result.addAttribute("initial_value", initialValue); - result.addAttribute("type", TypeAttr::get(type)); - result.attributes.append(attrs.begin(), attrs.end()); + build(builder, result, name, isMutable, type, llvm::None, initialValue, + attrs); } void VariableOp::build(Builder *builder, OperationState &result, StringRef name, bool isMutable, Type type, ArrayRef<NamedAttribute> attrs) { - result.addAttribute(SymbolTable::getSymbolAttrName(), - builder->getStringAttr(name)); - if (isMutable) { - result.addAttribute("is_mutable", builder->getUnitAttr()); - } - result.addAttribute("type", TypeAttr::get(type)); - result.attributes.append(attrs.begin(), attrs.end()); + build(builder, result, name, isMutable, type, llvm::None, llvm::None, attrs); } //===----------------------------------------------------------------------===//
diff --git a/iree/compiler/Dialect/HAL/IR/HALTypes.h b/iree/compiler/Dialect/HAL/IR/HALTypes.h index 6f0f005..a6139b8 100644 --- a/iree/compiler/Dialect/HAL/IR/HALTypes.h +++ b/iree/compiler/Dialect/HAL/IR/HALTypes.h
@@ -175,14 +175,6 @@ } }; -class BufferBarrierListType { - public: - static TupleType get(size_t count, MLIRContext *context) { - SmallVector<Type, 4> elementTypes(count, BufferBarrierType::get(context)); - return TupleType::get(elementTypes, context); - } -}; - class MemoryBarrierType { public: static TupleType get(MLIRContext *context) { @@ -195,14 +187,6 @@ } }; -class MemoryBarrierListType { - public: - static TupleType get(size_t count, MLIRContext *context) { - SmallVector<Type, 4> elementTypes(count, MemoryBarrierType::get(context)); - return TupleType::get(elementTypes, context); - } -}; - class DescriptorSetBindingType { public: static TupleType get(MLIRContext *context) {
diff --git a/iree/compiler/Dialect/VM/Conversion/BUILD b/iree/compiler/Dialect/VM/Conversion/BUILD index 2618fd6..1abc463 100644 --- a/iree/compiler/Dialect/VM/Conversion/BUILD +++ b/iree/compiler/Dialect/VM/Conversion/BUILD
@@ -18,19 +18,23 @@ ) cc_library( - name = "ImportUtils", + name = "Conversion", srcs = [ + "ConversionTarget.cpp", "ImportUtils.cpp", + "TypeConverter.cpp", ], hdrs = [ + "ConversionTarget.h", "ImportUtils.h", + "TypeConverter.h", ], deps = [ "//iree/compiler/Dialect", "//iree/compiler/Dialect/VM/IR", "@local_config_mlir//:IR", "@local_config_mlir//:Parser", - "@local_config_mlir//:Support", + "@local_config_mlir//:StandardOps", "@local_config_mlir//:Transforms", ], )
diff --git a/iree/compiler/Dialect/VM/Conversion/ConversionTarget.cpp b/iree/compiler/Dialect/VM/Conversion/ConversionTarget.cpp new file mode 100644 index 0000000..af229be --- /dev/null +++ b/iree/compiler/Dialect/VM/Conversion/ConversionTarget.cpp
@@ -0,0 +1,51 @@ +// Copyright 2019 Google LLC +// +// 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 +// +// https://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 "iree/compiler/Dialect/VM/Conversion/ConversionTarget.h" + +namespace mlir { +namespace iree_compiler { + +// static +std::pair<mlir::ModuleOp, mlir::ModuleOp> +VMConversionTarget::nestModuleForConversion(mlir::ModuleOp outerModuleOp) { + auto innerModuleOp = dyn_cast<ModuleOp>(outerModuleOp.getBody()->front()); + if (!innerModuleOp) { + innerModuleOp = + ModuleOp::create(outerModuleOp.getLoc(), outerModuleOp.getName()); + innerModuleOp.getBodyRegion().takeBody(outerModuleOp.getBodyRegion()); + outerModuleOp.getBodyRegion().getBlocks().push_back(new Block()); + OpBuilder builder(outerModuleOp.getBody()); + builder.create<mlir::ModuleTerminatorOp>(outerModuleOp.getLoc()); + outerModuleOp.push_back(innerModuleOp); + } + return std::make_pair(outerModuleOp, innerModuleOp); +} + +VMConversionTarget::VMConversionTarget(MLIRContext *context) + : ConversionTarget(*context) { + addLegalDialect<IREE::VM::VMDialect>(); + + // NOTE: we need to allow the outermost std.module to be legal to support the + // double-nesting (module { vm.module { ... } }). + addDynamicallyLegalOp<mlir::ModuleOp>( + +[](mlir::ModuleOp op) { return op.getParentOp() == nullptr; }); + addDynamicallyLegalOp<mlir::ModuleTerminatorOp>( + +[](mlir::ModuleTerminatorOp op) { + return op.getParentOp()->getParentOp() == nullptr; + }); +} + +} // namespace iree_compiler +} // namespace mlir
diff --git a/iree/compiler/Dialect/VM/Conversion/ConversionTarget.h b/iree/compiler/Dialect/VM/Conversion/ConversionTarget.h new file mode 100644 index 0000000..5c6e795 --- /dev/null +++ b/iree/compiler/Dialect/VM/Conversion/ConversionTarget.h
@@ -0,0 +1,48 @@ +// Copyright 2019 Google LLC +// +// 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 +// +// https://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. + +#ifndef IREE_COMPILER_DIALECT_VM_CONVERSION_CONVERSIONTARGET_H_ +#define IREE_COMPILER_DIALECT_VM_CONVERSION_CONVERSIONTARGET_H_ + +#include "iree/compiler/Dialect/VM/IR/VMOps.h" +#include "mlir/IR/MLIRContext.h" +#include "mlir/IR/Module.h" +#include "mlir/Transforms/DialectConversion.h" + +namespace mlir { +namespace iree_compiler { + +// A conversion target for the VM dialect that handles some boilerplate for +// nested module conversion. +// Conversions targeting the VM dialect should always use this. +class VMConversionTarget : public ConversionTarget { + public: + // Ensures that a module has double-nesting to allow for module conversion. + // If the module is already nested then this is a no-op. + // Returns a pair of (outer module, inner module). + // + // Example: + // module { func @foo() { ... } } + // -> + // module { module { func @foo() { ... } } } + static std::pair<mlir::ModuleOp, mlir::ModuleOp> nestModuleForConversion( + mlir::ModuleOp outerModuleOp); + + VMConversionTarget(MLIRContext *context); +}; + +} // namespace iree_compiler +} // namespace mlir + +#endif // IREE_COMPILER_DIALECT_VM_CONVERSION_CONVERSIONTARGET_H_
diff --git a/iree/compiler/Dialect/VM/Conversion/ImportUtils.h b/iree/compiler/Dialect/VM/Conversion/ImportUtils.h index b9cb619..ba62ed2 100644 --- a/iree/compiler/Dialect/VM/Conversion/ImportUtils.h +++ b/iree/compiler/Dialect/VM/Conversion/ImportUtils.h
@@ -17,9 +17,11 @@ #include "iree/compiler/Dialect/Types.h" #include "iree/compiler/Dialect/VM/IR/VMOps.h" +#include "mlir/Dialect/StandardOps/Ops.h" #include "mlir/IR/Attributes.h" #include "mlir/IR/Module.h" #include "mlir/IR/Operation.h" +#include "mlir/Transforms/DialectConversion.h" namespace mlir { namespace iree_compiler { @@ -40,6 +42,107 @@ LogicalResult appendImportModule(StringRef importModuleSrc, ModuleOp targetModuleOp); +// Utility for op to vm.call conversion. +template <typename T, typename Adaptor = typename T::OperandAdaptor> +class VMImportOpConversion : public OpConversionPattern<T> { + public: + VMImportOpConversion(MLIRContext *context, SymbolTable &importSymbols, + TypeConverter &typeConverter, StringRef importName) + : OpConversionPattern<T>(context), typeConverter(typeConverter) { + importOp = importSymbols.lookup<IREE::VM::ImportOp>(importName); + assert(importOp); + } + + // Returns true if the import must be called with vm.call.variadic. + bool isVariadic() const { + for (int i = 0; i < importOp.getNumFuncArguments(); ++i) { + if (importOp.isFuncArgumentVariadic(i)) return true; + } + return false; + } + + PatternMatchResult matchAndRewrite( + T op, llvm::ArrayRef<Value *> operands, + ConversionPatternRewriter &rewriter) const override { + if (failed(rewriteToCall(op, Adaptor{operands}, rewriter))) { + return OpConversionPattern<T>::matchFailure(); + } + return OpConversionPattern<T>::matchSuccess(); + } + + virtual LogicalResult rewriteToCall( + T op, Adaptor adaptor, ConversionPatternRewriter &rewriter) const { + auto *operation = op.getOperation(); + bool isOpVariadic = isVariadic(); + OperationState state{ + op.getLoc(), isOpVariadic ? IREE::VM::CallVariadicOp::getOperationName() + : IREE::VM::CallOp::getOperationName()}; + state.addAttributes(llvm::to_vector<4>(operation->getDialectAttrs())); + state.addAttribute("callee", rewriter.getSymbolRefAttr(importOp)); + + auto importType = importOp.getType(); + for (auto resultType : operation->getResultTypes()) { + if (failed(typeConverter.convertType(resultType, state.types))) { + return failure(); + } + } + + SmallVector<uint8_t, 4> segmentSizes; + int inputSetIndex = 0; + for (auto input : llvm::enumerate(importType.getInputs())) { + auto inputType = input.value(); + auto inputName = importOp.getFuncArgumentName(input.index()); + if (auto attrValue = op.getAttr(inputName)) { + if (auto intAttr = attrValue.template dyn_cast<IntegerAttr>()) { + // NOTE: we intentionally go to std.constant ops so that the standard + // conversions can do their job. If we want to remove the dependency + // from standard ops in the future we could instead go directly to + // one of the vm constant ops. + auto *constOp = rewriter.createOrFold<mlir::ConstantOp>( + op.getLoc(), inputType, intAttr); + state.operands.push_back(constOp); + } else { + op.emitOpError() << "unsupported attribute encoding: " + << attrValue.getType(); + return failure(); + } + segmentSizes.push_back(-1); + } else { + auto operands = + llvm::to_vector<4>(adaptor.getODSOperands(inputSetIndex++)); + state.addOperands(operands); + if (importOp.isFuncArgumentVariadic(input.index())) { + segmentSizes.push_back(operands.size()); + } else { + segmentSizes.push_back(-1); + } + } + } + if (isOpVariadic) { + state.addAttribute( + "segment_sizes", + DenseIntElementsAttr::get( + VectorType::get({static_cast<int64_t>(segmentSizes.size())}, + rewriter.getIntegerType(8)), + segmentSizes)); + state.addAttribute( + "segment_types", + rewriter.getArrayAttr(llvm::to_vector<4>( + llvm::map_range(importType.getInputs(), [&](Type type) { + return TypeAttr::get(type).cast<Attribute>(); + })))); + } + + auto *callOp = rewriter.createOperation(state); + rewriter.replaceOp(op, llvm::to_vector<4>(callOp->getResults())); + return success(); + } + + protected: + mutable IREE::VM::ImportOp importOp; + TypeConverter &typeConverter; +}; + } // namespace iree_compiler } // namespace mlir
diff --git a/iree/compiler/Dialect/VM/Conversion/StandardToVM/BUILD b/iree/compiler/Dialect/VM/Conversion/StandardToVM/BUILD index 1b6d052..e1375d4 100644 --- a/iree/compiler/Dialect/VM/Conversion/StandardToVM/BUILD +++ b/iree/compiler/Dialect/VM/Conversion/StandardToVM/BUILD
@@ -14,6 +14,7 @@ ], deps = [ "//iree/compiler/Dialect", + "//iree/compiler/Dialect/VM/Conversion", "//iree/compiler/Dialect/VM/IR", "@llvm//:support", "@local_config_mlir//:IR",
diff --git a/iree/compiler/Dialect/VM/Conversion/StandardToVM/ConvertStandardToVM.cpp b/iree/compiler/Dialect/VM/Conversion/StandardToVM/ConvertStandardToVM.cpp index 6d2b72c..ba49771 100644 --- a/iree/compiler/Dialect/VM/Conversion/StandardToVM/ConvertStandardToVM.cpp +++ b/iree/compiler/Dialect/VM/Conversion/StandardToVM/ConvertStandardToVM.cpp
@@ -15,6 +15,7 @@ #include "iree/compiler/Dialect/VM/Conversion/StandardToVM/ConvertStandardToVM.h" #include "iree/compiler/Dialect/Types.h" +#include "iree/compiler/Dialect/VM/Conversion/TypeConverter.h" #include "iree/compiler/Dialect/VM/IR/VMOps.h" #include "mlir/Dialect/StandardOps/Ops.h" #include "mlir/IR/Attributes.h" @@ -29,32 +30,6 @@ namespace { -class VmTypeConverter : public TypeConverter { - public: - static TypeConverter &getInstance() { - static VmTypeConverter instance; - return instance; - } - - private: - Type convertType(Type t) override { - if (auto integerType = t.dyn_cast<IntegerType>()) { - if (integerType.getIntOrFloatBitWidth() == 32) { - return t; - } else if (integerType.getIntOrFloatBitWidth() == 1) { - // Promote i1 -> i32. - return IntegerType::get(32, t.getContext()); - } - } else if (t.isa<IREE::RefPtrType>()) { - return t; - } - // Default to not supporting the type. This dialect is very limited - // with respect to valid types and the above should be expanded as - // needed. - return {}; - } -}; - class ModuleOpConversion : public OpConversionPattern<ModuleOp> { using OpConversionPattern::OpConversionPattern; @@ -90,7 +65,7 @@ FuncOp srcOp, ArrayRef<Value *> operands, ConversionPatternRewriter &rewriter) const override { FunctionType srcFuncType = srcOp.getType(); - TypeConverter &typeConverter = VmTypeConverter::getInstance(); + VMTypeConverter typeConverter; TypeConverter::SignatureConversion signatureConversion( srcOp.getNumArguments()); @@ -326,7 +301,7 @@ CallOpOperandAdaptor srcAdaptor(operands); // Convert function result types. The conversion framework will ensure // that the callee has been equivalently converted. - auto &typeConverter = VmTypeConverter::getInstance(); + VMTypeConverter typeConverter; SmallVector<Type, 4> resultTypes; for (auto resultType : srcOp.getResultTypes()) { resultType = typeConverter.convertType(resultType); @@ -371,9 +346,5 @@ context); } -TypeConverter *getStandardToVMTypeConverter() { - return &VmTypeConverter::getInstance(); -} - } // namespace iree_compiler } // namespace mlir
diff --git a/iree/compiler/Dialect/VM/Conversion/StandardToVM/ConvertStandardToVM.h b/iree/compiler/Dialect/VM/Conversion/StandardToVM/ConvertStandardToVM.h index 7c3e787..93b6dbd 100644 --- a/iree/compiler/Dialect/VM/Conversion/StandardToVM/ConvertStandardToVM.h +++ b/iree/compiler/Dialect/VM/Conversion/StandardToVM/ConvertStandardToVM.h
@@ -25,10 +25,6 @@ void populateStandardToVMPatterns(MLIRContext *context, OwningRewritePatternList &patterns); -// Gets the TypeConverter that must be used for legalizing the standard to -// VM dialect. -TypeConverter *getStandardToVMTypeConverter(); - } // namespace iree_compiler } // namespace mlir
diff --git a/iree/compiler/Dialect/VM/Conversion/StandardToVM/ConvertStandardToVMPass.cpp b/iree/compiler/Dialect/VM/Conversion/StandardToVM/ConvertStandardToVMPass.cpp index 2050d5f..86e98a7 100644 --- a/iree/compiler/Dialect/VM/Conversion/StandardToVM/ConvertStandardToVMPass.cpp +++ b/iree/compiler/Dialect/VM/Conversion/StandardToVM/ConvertStandardToVMPass.cpp
@@ -13,6 +13,7 @@ // limitations under the License. #include "iree/compiler/Dialect/VM/Conversion/StandardToVM/ConvertStandardToVM.h" +#include "iree/compiler/Dialect/VM/Conversion/TypeConverter.h" #include "iree/compiler/Dialect/VM/IR/VMDialect.h" #include "mlir/Dialect/StandardOps/Ops.h" #include "mlir/Pass/Pass.h" @@ -34,11 +35,13 @@ OwningRewritePatternList patterns; populateStandardToVMPatterns(&getContext(), patterns); + VMTypeConverter typeConverter; + // NOTE: we allow other dialects besides just VM during this pass as we are // only trying to eliminate the std ops. When used as part of a larger set // of rewrites a full conversion should be used instead. if (failed(applyPartialConversion(getModule(), target, patterns, - getStandardToVMTypeConverter()))) { + &typeConverter))) { return signalPassFailure(); } }
diff --git a/iree/compiler/Dialect/VM/Conversion/TypeConverter.cpp b/iree/compiler/Dialect/VM/Conversion/TypeConverter.cpp new file mode 100644 index 0000000..8321c62 --- /dev/null +++ b/iree/compiler/Dialect/VM/Conversion/TypeConverter.cpp
@@ -0,0 +1,41 @@ +// Copyright 2019 Google LLC +// +// 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 +// +// https://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 "iree/compiler/Dialect/VM/Conversion/TypeConverter.h" + +#include "iree/compiler/Dialect/Types.h" +#include "mlir/IR/StandardTypes.h" + +namespace mlir { +namespace iree_compiler { + +Type VMTypeConverter::convertType(Type t) { + if (auto integerType = t.dyn_cast<IntegerType>()) { + if (integerType.getIntOrFloatBitWidth() == 32) { + return t; + } else if (integerType.getIntOrFloatBitWidth() == 1) { + // Promote i1 -> i32. + return IntegerType::get(32, t.getContext()); + } + } else if (t.isa<IREE::RefPtrType>()) { + return t; + } + // Default to not supporting the type. This dialect is very limited + // with respect to valid types and the above should be expanded as + // needed. + return {}; +} + +} // namespace iree_compiler +} // namespace mlir
diff --git a/iree/compiler/Dialect/VM/Conversion/TypeConverter.h b/iree/compiler/Dialect/VM/Conversion/TypeConverter.h new file mode 100644 index 0000000..9108351 --- /dev/null +++ b/iree/compiler/Dialect/VM/Conversion/TypeConverter.h
@@ -0,0 +1,31 @@ +// Copyright 2019 Google LLC +// +// 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 +// +// https://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. + +#ifndef IREE_COMPILER_DIALECT_VM_CONVERSION_TYPECONVERTER_H_ +#define IREE_COMPILER_DIALECT_VM_CONVERSION_TYPECONVERTER_H_ + +#include "mlir/Transforms/DialectConversion.h" + +namespace mlir { +namespace iree_compiler { + +class VMTypeConverter : public TypeConverter { + public: + Type convertType(Type t) override; +}; + +} // namespace iree_compiler +} // namespace mlir + +#endif // IREE_COMPILER_DIALECT_VM_CONVERSION_TYPECONVERTER_H_
diff --git a/iree/compiler/Dialect/VM/IR/VMOps.cpp b/iree/compiler/Dialect/VM/IR/VMOps.cpp index 06b872e..55ee0fe 100644 --- a/iree/compiler/Dialect/VM/IR/VMOps.cpp +++ b/iree/compiler/Dialect/VM/IR/VMOps.cpp
@@ -217,6 +217,7 @@ } argTypes.push_back(operandType); NamedAttributeList argAttrList; + operand.name.consume_front("%"); argAttrList.set(builder.getIdentifier("vm.name"), builder.getStringAttr(operand.name)); if (succeeded(parser.parseOptionalEllipsis())) { @@ -263,7 +264,7 @@ p << "("; for (int i = 0; i < op.getNumFuncArguments(); ++i) { if (auto name = op.getArgAttrOfType<StringAttr>(i, "vm.name")) { - p << name.getValue() << " : "; + p << '%' << name.getValue() << " : "; } p.printType(op.getType().getInput(i)); if (op.getArgAttrOfType<UnitAttr>(i, "vm.variadic")) { @@ -394,20 +395,20 @@ auto initialValueAttr = op->getAttr("initial_value"); if (initializerAttr && initialValueAttr) { return op->emitOpError() - << "Globals can have either an initializer or an initial value"; + << "globals can have either an initializer or an initial value"; } else if (initializerAttr) { // Ensure initializer returns the same value as the global. auto initializer = op->getParentOfType<ModuleOp>().lookupSymbol<FuncOp>( initializerAttr.getValue()); if (!initializer) { return op->emitOpError() - << "Initializer function " << initializerAttr << " not found"; + << "initializer function " << initializerAttr << " not found"; } if (initializer.getType().getNumInputs() != 0 || initializer.getType().getNumResults() != 1 || initializer.getType().getResult(0) != globalType.getValue()) { return op->emitOpError() - << "Initializer type mismatch; global " << globalName << " is " + << "initializer type mismatch; global " << globalName << " is " << globalType << " but initializer function " << initializer.getName() << " is " << initializer.getType(); } @@ -415,7 +416,7 @@ // Ensure the value is something we can convert to a const. if (initialValueAttr.getType() != globalType.getValue()) { return op->emitOpError() - << "Initial value type mismatch; global " << globalName << " is " + << "initial value type mismatch; global " << globalName << " is " << globalType << " but initial value provided is " << initialValueAttr.getType(); } @@ -424,83 +425,85 @@ } void GlobalI32Op::build(Builder *builder, OperationState &result, - StringRef name, bool isMutable, FuncOp initializer, + StringRef name, bool isMutable, Type type, + Optional<StringRef> initializer, + Optional<Attribute> initialValue, ArrayRef<NamedAttribute> attrs) { result.addAttribute(SymbolTable::getSymbolAttrName(), builder->getStringAttr(name)); if (isMutable) { result.addAttribute("is_mutable", builder->getUnitAttr()); } - result.addAttribute("initializer", builder->getSymbolRefAttr(initializer)); - result.addAttribute("type", - TypeAttr::get(initializer.getType().getResult(0))); + if (initializer.hasValue()) { + result.addAttribute("initializer", + builder->getSymbolRefAttr(initializer.getValue())); + } else if (initialValue.hasValue()) { + result.addAttribute("initial_value", initialValue.getValue()); + } + result.addAttribute("type", TypeAttr::get(type)); result.attributes.append(attrs.begin(), attrs.end()); } void GlobalI32Op::build(Builder *builder, OperationState &result, + StringRef name, bool isMutable, + IREE::VM::FuncOp initializer, + ArrayRef<NamedAttribute> attrs) { + build(builder, result, name, isMutable, initializer.getType().getResult(0), + initializer.getName(), llvm::None, attrs); +} + +void GlobalI32Op::build(Builder *builder, OperationState &result, StringRef name, bool isMutable, Type type, Attribute initialValue, ArrayRef<NamedAttribute> attrs) { - result.addAttribute(SymbolTable::getSymbolAttrName(), - builder->getStringAttr(name)); - if (isMutable) { - result.addAttribute("is_mutable", builder->getUnitAttr()); - } - result.addAttribute("initial_value", initialValue); - result.addAttribute("type", TypeAttr::get(type)); - result.attributes.append(attrs.begin(), attrs.end()); + build(builder, result, name, isMutable, type, llvm::None, initialValue, + attrs); } void GlobalI32Op::build(Builder *builder, OperationState &result, StringRef name, bool isMutable, Type type, ArrayRef<NamedAttribute> attrs) { - result.addAttribute(SymbolTable::getSymbolAttrName(), - builder->getStringAttr(name)); - if (isMutable) { - result.addAttribute("is_mutable", builder->getUnitAttr()); - } - result.addAttribute("initial_value", builder->getZeroAttr(type)); - result.addAttribute("type", TypeAttr::get(type)); - result.attributes.append(attrs.begin(), attrs.end()); + build(builder, result, name, isMutable, type, llvm::None, llvm::None, attrs); } void GlobalRefOp::build(Builder *builder, OperationState &result, - StringRef name, bool isMutable, FuncOp initializer, + StringRef name, bool isMutable, Type type, + Optional<StringRef> initializer, + Optional<Attribute> initialValue, ArrayRef<NamedAttribute> attrs) { result.addAttribute(SymbolTable::getSymbolAttrName(), builder->getStringAttr(name)); if (isMutable) { result.addAttribute("is_mutable", builder->getUnitAttr()); } - result.addAttribute("initializer", builder->getSymbolRefAttr(initializer)); - result.addAttribute("type", - TypeAttr::get(initializer.getType().getResult(0))); + if (initializer.hasValue()) { + result.addAttribute("initializer", + builder->getSymbolRefAttr(initializer.getValue())); + } + result.addAttribute("type", TypeAttr::get(type)); result.attributes.append(attrs.begin(), attrs.end()); } void GlobalRefOp::build(Builder *builder, OperationState &result, + StringRef name, bool isMutable, + IREE::VM::FuncOp initializer, + ArrayRef<NamedAttribute> attrs) { + build(builder, result, name, isMutable, initializer.getType().getResult(0), + initializer.getName(), llvm::None, attrs); +} + +void GlobalRefOp::build(Builder *builder, OperationState &result, StringRef name, bool isMutable, Type type, Attribute initialValue, ArrayRef<NamedAttribute> attrs) { - result.addAttribute(SymbolTable::getSymbolAttrName(), - builder->getStringAttr(name)); - if (isMutable) { - result.addAttribute("is_mutable", builder->getUnitAttr()); - } - result.addAttribute("type", TypeAttr::get(type)); - result.attributes.append(attrs.begin(), attrs.end()); + build(builder, result, name, isMutable, type, llvm::None, initialValue, + attrs); } void GlobalRefOp::build(Builder *builder, OperationState &result, StringRef name, bool isMutable, Type type, ArrayRef<NamedAttribute> attrs) { - result.addAttribute(SymbolTable::getSymbolAttrName(), - builder->getStringAttr(name)); - if (isMutable) { - result.addAttribute("is_mutable", builder->getUnitAttr()); - } - result.addAttribute("type", TypeAttr::get(type)); - result.attributes.append(attrs.begin(), attrs.end()); + build(builder, result, name, isMutable, type, llvm::None, llvm::None, attrs); } static ParseResult parseGlobalLoadOp(OpAsmParser &parser,
diff --git a/iree/compiler/Dialect/VM/IR/VMOps.td b/iree/compiler/Dialect/VM/IR/VMOps.td index 013cc07..0420342 100644 --- a/iree/compiler/Dialect/VM/IR/VMOps.td +++ b/iree/compiler/Dialect/VM/IR/VMOps.td
@@ -172,7 +172,6 @@ def VM_ImportOp : VM_Op<"import", [ Symbol, - HasParent<"IREE::VM::ModuleOp">, NativeOpTrait<"FunctionLike">, CallableOpInterface, ]> { @@ -262,6 +261,12 @@ let builders = [ OpBuilder<[{ Builder *builder, OperationState &result, StringRef name, bool isMutable, + Type type, + Optional<StringRef> initializer, Optional<Attribute> initialValue, + ArrayRef<NamedAttribute> attrs = {} + }]>, + OpBuilder<[{ + Builder *builder, OperationState &result, StringRef name, bool isMutable, IREE::VM::FuncOp initializer, ArrayRef<NamedAttribute> attrs = {} }]>, OpBuilder<[{
diff --git a/iree/compiler/Dialect/VM/Transforms/BUILD b/iree/compiler/Dialect/VM/Transforms/BUILD index af053f1..710ac41 100644 --- a/iree/compiler/Dialect/VM/Transforms/BUILD +++ b/iree/compiler/Dialect/VM/Transforms/BUILD
@@ -6,12 +6,16 @@ cc_library( name = "Transforms", srcs = [ + "Conversion.cpp", "OrdinalAllocationPass.cpp", + "Passes.cpp", ], hdrs = [ "Passes.h", ], deps = [ + "//iree/compiler/Dialect/VM/Conversion", + "//iree/compiler/Dialect/VM/Conversion/StandardToVM", "//iree/compiler/Dialect/VM/IR", "@llvm//:support", "@local_config_mlir//:IR",
diff --git a/iree/compiler/Dialect/VM/Transforms/Conversion.cpp b/iree/compiler/Dialect/VM/Transforms/Conversion.cpp new file mode 100644 index 0000000..6fcdf55 --- /dev/null +++ b/iree/compiler/Dialect/VM/Transforms/Conversion.cpp
@@ -0,0 +1,68 @@ +// Copyright 2019 Google LLC +// +// 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 +// +// https://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 <tuple> + +#include "iree/compiler/Dialect/VM/Conversion/ConversionTarget.h" +#include "iree/compiler/Dialect/VM/Conversion/StandardToVM/ConvertStandardToVM.h" +#include "iree/compiler/Dialect/VM/Conversion/TypeConverter.h" +#include "mlir/IR/Module.h" +#include "mlir/IR/PatternMatch.h" +#include "mlir/Pass/Pass.h" +#include "mlir/Pass/PassRegistry.h" +#include "mlir/Transforms/DialectConversion.h" + +namespace mlir { +namespace iree_compiler { +namespace IREE { +namespace VM { + +// TODO(benvanik): import dialect registration. + +// Runs conversion with registered input dialects. +class ConversionPass : public OperationPass<ConversionPass, mlir::ModuleOp> { + public: + void runOnOperation() override { + auto *context = &getContext(); + VMConversionTarget conversionTarget(context); + VMTypeConverter typeConverter; + + mlir::ModuleOp outerModuleOp, innerModuleOp; + std::tie(outerModuleOp, innerModuleOp) = + VMConversionTarget::nestModuleForConversion(getOperation()); + + // TODO(benvanik): registration system for custom dialects. + + OwningRewritePatternList conversionPatterns; + populateStandardToVMPatterns(context, conversionPatterns); + + if (failed(applyFullConversion(outerModuleOp, conversionTarget, + conversionPatterns, &typeConverter))) { + outerModuleOp.emitError() << "conversion to vm.module failed"; + return signalPassFailure(); + } + } +}; + +std::unique_ptr<OpPassBase<mlir::ModuleOp>> createConversionPass() { + return std::make_unique<ConversionPass>(); +} + +static PassRegistration<ConversionPass> pass( + "iree-vm-conversion", "Converts from various dialects to the VM dialect"); + +} // namespace VM +} // namespace IREE +} // namespace iree_compiler +} // namespace mlir
diff --git a/iree/compiler/Dialect/VM/Transforms/Passes.cpp b/iree/compiler/Dialect/VM/Transforms/Passes.cpp new file mode 100644 index 0000000..17889b0 --- /dev/null +++ b/iree/compiler/Dialect/VM/Transforms/Passes.cpp
@@ -0,0 +1,47 @@ +// Copyright 2019 Google LLC +// +// 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 +// +// https://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 "iree/compiler/Dialect/VM/Transforms/Passes.h" + +#include <memory> + +#include "iree/compiler/Dialect/VM/IR/VMOps.h" +#include "mlir/Pass/PassManager.h" +#include "mlir/Pass/PassRegistry.h" +#include "mlir/Transforms/Passes.h" + +namespace mlir { +namespace iree_compiler { +namespace IREE { +namespace VM { + +void buildVMTransformPassPipeline(OpPassManager &passManager) { + passManager.addPass(createConversionPass()); + + passManager.addPass(createCSEPass()); + + // TODO(benvanik): run symbol DCE pass. +} + +static PassPipelineRegistration<> transformPassPipeline( + "iree-vm-transformation-pipeline", + "Runs the full IREE VM dialect transformation pipeline", + [](OpPassManager &passManager) { + buildVMTransformPassPipeline(passManager); + }); + +} // namespace VM +} // namespace IREE +} // namespace iree_compiler +} // namespace mlir
diff --git a/iree/compiler/Dialect/VM/Transforms/Passes.h b/iree/compiler/Dialect/VM/Transforms/Passes.h index d0dacd3..5f32f23 100644 --- a/iree/compiler/Dialect/VM/Transforms/Passes.h +++ b/iree/compiler/Dialect/VM/Transforms/Passes.h
@@ -16,6 +16,7 @@ #define IREE_COMPILER_DIALECT_VM_TRANSFORMS_PASSES_H_ #include "iree/compiler/Dialect/VM/IR/VMOps.h" +#include "mlir/IR/Module.h" #include "mlir/Pass/Pass.h" namespace mlir { @@ -24,12 +25,35 @@ namespace VM { //===----------------------------------------------------------------------===// +// Helpers +//===----------------------------------------------------------------------===// + +// Adds a set of passes to the given pass manager that run the required VM +// transforms in the canonical order. +// +// Most translation code should prefer to use this instead of manually adding +// the passes themselves to ensure that expected pass ordering is observed. +// +// The expected usage is: +// <run conversion to HAL/etc> +// buildVMTransformPassPipeline & run +// <run target serialization/etc> +void buildVMTransformPassPipeline(OpPassManager &passManager); + +//===----------------------------------------------------------------------===// +// Conversion +//===----------------------------------------------------------------------===// + +// Converts from various dialects (standard, HAL, etc) to the VM dialect. +std::unique_ptr<OpPassBase<mlir::ModuleOp>> createConversionPass(); + +//===----------------------------------------------------------------------===// // Module Analysis and Assignment //===----------------------------------------------------------------------===// // Assigns module-unique ordinals to function/global/etc symbols within the // module. -std::unique_ptr<OpPassBase<ModuleOp>> createOrdinalAllocationPass(); +std::unique_ptr<OpPassBase<IREE::VM::ModuleOp>> createOrdinalAllocationPass(); } // namespace VM } // namespace IREE
diff --git a/iree/compiler/Translation/BUILD b/iree/compiler/Translation/BUILD index 18ea6cb..8dd204e 100644 --- a/iree/compiler/Translation/BUILD +++ b/iree/compiler/Translation/BUILD
@@ -21,7 +21,6 @@ name = "IREEVM", srcs = [ "IREEVM.cpp", - "IREEVMTranslationRegistration.cpp", ], hdrs = ["IREEVM.h"], deps = [ @@ -34,11 +33,11 @@ "//iree/compiler/Dialect/VM/Conversion/StandardToVM", "//iree/compiler/Dialect/VM/IR", "//iree/compiler/Dialect/VM/Target/Bytecode", + "//iree/compiler/Dialect/VM/Transforms", "@llvm//:support", "@local_config_mlir//:IR", "@local_config_mlir//:Pass", "@local_config_mlir//:StandardDialectRegistration", - "@local_config_mlir//:StandardOps", "@local_config_mlir//:Support", "@local_config_mlir//:Translation", "@org_tensorflow//tensorflow/compiler/mlir/xla:xla_dialect_registration",
diff --git a/iree/compiler/Translation/IREEVM.cpp b/iree/compiler/Translation/IREEVM.cpp index 69e8a1a..84b081a 100644 --- a/iree/compiler/Translation/IREEVM.cpp +++ b/iree/compiler/Translation/IREEVM.cpp
@@ -15,18 +15,17 @@ #include "iree/compiler/Translation/IREEVM.h" #include "iree/compiler/Dialect/Flow/Transforms/Passes.h" -#include "iree/compiler/Dialect/HAL/Conversion/HALToVM/ConvertHALToVM.h" +#include "iree/compiler/Dialect/HAL/Target/ExecutableTarget.h" #include "iree/compiler/Dialect/HAL/Transforms/Passes.h" -#include "iree/compiler/Dialect/VM/Conversion/StandardToVM/ConvertStandardToVM.h" -#include "iree/compiler/Dialect/VM/IR/VMOps.h" -#include "iree/compiler/Dialect/VM/Target/Bytecode/BytecodeModuleTarget.h" -#include "mlir/Dialect/StandardOps/Ops.h" +#include "iree/compiler/Dialect/VM/Target/Bytecode/TranslationFlags.h" +#include "iree/compiler/Dialect/VM/Transforms/Passes.h" +#include "mlir/IR/Module.h" #include "mlir/Pass/PassManager.h" +#include "mlir/Translation.h" namespace mlir { namespace iree_compiler { -// Runs the flow transform pipeline to partition and produce the flow module. LogicalResult convertToFlowModule(ModuleOp moduleOp) { PassManager passManager(moduleOp.getContext()); IREE::Flow::buildFlowTransformPassPipeline(passManager); @@ -37,8 +36,7 @@ return success(); } -// TODO(benvanik): replace with the real HAL dialect. -static LogicalResult convertToTemporaryHALModule( +LogicalResult convertToHALModule( ModuleOp moduleOp, IREE::HAL::ExecutableTargetOptions executableOptions) { PassManager passManager(moduleOp.getContext()); IREE::HAL::buildHALTransformPassPipeline(passManager, executableOptions); @@ -49,36 +47,26 @@ return success(); } -// Converts the lowered module to a canonical vm.module containing only vm ops. -// This uses patterns to convert from standard ops and other dialects to their -// vm ABI form. -static LogicalResult convertToVMModule(ModuleOp moduleOp) { - ConversionTarget conversionTarget(*moduleOp.getContext()); - conversionTarget.addLegalDialect<IREE::VM::VMDialect>(); - conversionTarget.addIllegalDialect<IREE::HAL::HALDialect>(); - conversionTarget.addIllegalDialect<StandardOpsDialect>(); - // NOTE: we need to allow the outermost std.module to be legal. - conversionTarget.addDynamicallyLegalOp<mlir::ModuleOp>( - [&](mlir::ModuleOp op) { return op.getParentOp() == nullptr; }); - conversionTarget.addDynamicallyLegalOp<mlir::ModuleTerminatorOp>( - [&](mlir::ModuleTerminatorOp op) { - return op.getParentOp()->getParentOp() == nullptr; - }); - - OwningRewritePatternList conversionPatterns; - populateHALToVMPatterns(moduleOp.getContext(), conversionPatterns); - populateStandardToVMPatterns(moduleOp.getContext(), conversionPatterns); - - // TODO(benvanik): HAL -> VM conversion. - - if (failed(applyFullConversion(moduleOp, conversionTarget, conversionPatterns, - getStandardToVMTypeConverter()))) { - return moduleOp.emitError() << "conversion to vm.module failed"; +LogicalResult convertToVMModule(ModuleOp moduleOp) { + PassManager passManager(moduleOp.getContext()); + IREE::VM::buildVMTransformPassPipeline(passManager); + if (failed(passManager.run(moduleOp))) { + return moduleOp.emitError() + << "failed to run VM transformation pass pipeline"; } - return success(); } +static PassPipelineRegistration<> transformPassPipeline( + "iree-transformation-pipeline", + "Runs the full IREE input to VM transformation pipeline", + [](OpPassManager &passManager) { + IREE::Flow::buildFlowTransformPassPipeline(passManager); + IREE::HAL::buildHALTransformPassPipeline( + passManager, IREE::HAL::getExecutableTargetOptionsFromFlags()); + IREE::VM::buildVMTransformPassPipeline(passManager); + }); + LogicalResult translateFromMLIRToVMBytecodeModule( ModuleOp moduleOp, IREE::HAL::ExecutableTargetOptions executableOptions, IREE::VM::BytecodeTargetOptions bytecodeOptions, @@ -86,9 +74,11 @@ // Convert from our source to a vm.module in canonical form. // After this completes we have a non-bytecode-specific vm.module that we // could lower to other forms (LLVM IR, C, etc). - if (failed(convertToFlowModule(moduleOp)) || - failed(convertToTemporaryHALModule(moduleOp, executableOptions)) || - failed(convertToVMModule(moduleOp))) { + PassManager passManager(moduleOp.getContext()); + IREE::Flow::buildFlowTransformPassPipeline(passManager); + IREE::HAL::buildHALTransformPassPipeline(passManager, executableOptions); + IREE::VM::buildVMTransformPassPipeline(passManager); + if (failed(passManager.run(moduleOp))) { return moduleOp.emitError() << "conversion from source -> vm failed"; } @@ -96,5 +86,18 @@ return translateModuleToBytecode(moduleOp, bytecodeOptions, output); } +static LogicalResult translateFromMLIRToVMBytecodeModuleWithFlags( + ModuleOp moduleOp, llvm::raw_ostream &output) { + auto executableTargetOptions = + IREE::HAL::getExecutableTargetOptionsFromFlags(); + auto bytecodeTargetOptions = IREE::VM::getBytecodeTargetOptionsFromFlags(); + return translateFromMLIRToVMBytecodeModule(moduleOp, executableTargetOptions, + bytecodeTargetOptions, output); +} + +static TranslateFromMLIRRegistration toVMBytecodeModuleWithFlags( + "iree-mlir-to-vm-bytecode-module", + translateFromMLIRToVMBytecodeModuleWithFlags); + } // namespace iree_compiler } // namespace mlir
diff --git a/iree/compiler/Translation/IREEVM.h b/iree/compiler/Translation/IREEVM.h index dfe2b78..7cba21b 100644 --- a/iree/compiler/Translation/IREEVM.h +++ b/iree/compiler/Translation/IREEVM.h
@@ -32,6 +32,16 @@ // unsupported SPIR-V lowering) or a bug. LogicalResult convertToFlowModule(ModuleOp moduleOp); +// Runs the flow->HAL transform pipeline to lower a flow module and compile +// executables for the specified target backends. +LogicalResult convertToHALModule( + ModuleOp moduleOp, IREE::HAL::ExecutableTargetOptions executableOptions); + +// Converts the lowered module to a canonical vm.module containing only vm ops. +// This uses patterns to convert from standard ops and other dialects to their +// vm ABI form. +LogicalResult convertToVMModule(ModuleOp moduleOp); + // Translates an MLIR module containing a set of supported IREE input dialects // to an IREE VM bytecode module for loading at runtime. //
diff --git a/iree/compiler/Translation/IREEVMTranslationRegistration.cpp b/iree/compiler/Translation/IREEVMTranslationRegistration.cpp deleted file mode 100644 index 32b996a..0000000 --- a/iree/compiler/Translation/IREEVMTranslationRegistration.cpp +++ /dev/null
@@ -1,37 +0,0 @@ -// Copyright 2019 Google LLC -// -// 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 -// -// https://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 "iree/compiler/Dialect/VM/Target/Bytecode/TranslationFlags.h" -#include "iree/compiler/Translation/IREEVM.h" -#include "llvm/Support/CommandLine.h" -#include "mlir/Translation.h" - -namespace mlir { -namespace iree_compiler { - -static LogicalResult translateFromMLIRToVMBytecodeModuleWithFlags( - ModuleOp moduleOp, llvm::raw_ostream &output) { - // TODO(benvanik): parse flags. - auto executableTargetOptions = IREE::HAL::ExecutableTargetOptions{}; - auto bytecodeTargetOptions = IREE::VM::getBytecodeTargetOptionsFromFlags(); - return translateFromMLIRToVMBytecodeModule(moduleOp, executableTargetOptions, - bytecodeTargetOptions, output); -} - -static TranslateFromMLIRRegistration toVMBytecodeModuleWithFlags( - "iree-mlir-to-vm-bytecode-module", - translateFromMLIRToVMBytecodeModuleWithFlags); - -} // namespace iree_compiler -} // namespace mlir
diff --git a/iree/tools/BUILD b/iree/tools/BUILD index 3366c05..2b63d78 100644 --- a/iree/tools/BUILD +++ b/iree/tools/BUILD
@@ -50,6 +50,7 @@ "//iree/compiler/Transforms", "//iree/compiler/Transforms/Interpreter", "//iree/compiler/Transforms/Sequencer", + "//iree/compiler/Translation:IREEVM", "//iree/compiler/Translation/SPIRV", "@llvm//:support", "@local_config_mlir//:AffineDialectRegistration",