# 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