# Conversion: Legal and Illegal MLIRにおけるConversionでは、LegalかIllegalを指定することでConversionTargetを決定する。Legalとは、あるConversion passにおいて合法であるためConversion Target上で存在して良いことを示す(要するにConversion passによって変換の必要がない)。IllegalはあるConversion passにおいて合法ではないため変換対象となり、Conversion Targetでは存在しないことがを指す。 つまり、Conversion passを実装する際には、sourceとtarget間での変換対象となるOpなどを指定するが、これをLegal/Illegalで表現する。 - **Legal** - Legalで指定されたDialect/OpsはConversion Target上では合法であるため、Conversion passでは変換対象外となる - **Illegal** - Illegalで指定されたDialect/OpsはConversion Target上では合法ではないため、Conversion passでは変換対象となる - Conversion後にIllegalなDialect/Opsが残っていた場合は、Failureとなる - **Dynamic** - 細かい条件を与えてDialect/OpsのLegal/Illegalを指定する - e.g. i32をオペランドにとる場合の`arith.addi`のみLegal(それ以外のf32をオペランドにとるような`arith.addi`はIllegal) ### Example of conversion target `addLegalDialect`や`addLegalOp`によって、LegalであるDialect/Opを指定する。また、`addDynamicallyLegalOp`といったDynamicな関数には、任意のOpを指定した上でlambda関数で細かい条件を与えて、true/falseを返すことでLegal/Illegalを決定する。 ``` struct MyTarget : public ConversionTarget { MyTarget(MLIRContext &ctx) : ConversionTarget(ctx) { //-------------------------------------------------------------------------- // Marking an operation as Legal: /// Mark all operations within the LLVM dialect are legal. addLegalDialect<LLVMDialect>(); /// Mark `arith.constant` op is always legal on this target. addLegalOp<arith::ConstantOp>(); //-------------------------------------------------------------------------- // Marking an operation as dynamically legal. /// Mark all operations within Affine dialect have dynamic legality /// constraints. addDynamicallyLegalDialect<affine::AffineDialect>( [](Operation *op) { ... }); /// Mark `func.return` as dynamically legal, but provide a specific legality /// callback. addDynamicallyLegalOp<func::ReturnOp>([](func::ReturnOp op) { ... }); /// Treat unknown operations, i.e. those without a legalization action /// directly set, as dynamically legal. markUnknownOpDynamicallyLegal([](Operation *op) { ... }); //-------------------------------------------------------------------------- // Marking an operation as illegal. /// All operations within the GPU dialect are illegal. addIllegalDialect<GPUDialect>(); /// Mark `cf.br` and `cf.cond_br` as illegal. addIllegalOp<cf::BranchOp, cf::CondBranchOp>(); } /// Implement the default legalization handler to handle operations marked as /// dynamically legal that were not provided with an explicit handler. bool isDynamicallyLegal(Operation *op) override { ... } }; ``` ### Recursively 再帰的に指定したDialect/Opが持つRegionの中身を含めてLegalを決めることもできる。 ``` ConversionTarget &target = ...; /// The operation must first be marked as `Legal` or `Dynamic`. target.addLegalOp<MyOp>(...); target.addDynamicallyLegalOp<MySecondOp>(...); /// Mark the operation as always recursively legal. target.markOpRecursivelyLegal<MyOp>(); /// Mark optionally with a callback to allow selective marking. target.markOpRecursivelyLegal<MyOp, MySecondOp>([](Operation *op) { ... }); /// Mark optionally with a callback to allow selective marking. target.markOpRecursivelyLegal<MyOp>([](MyOp op) { ... }); ``` ### Reference - https://mlir.llvm.org/docs/DialectConversion/#conversion-target - https://mlir.llvm.org/doxygen/classmlir_1_1ConversionTarget.html