---
# System prepended metadata

title: 'Conversion: Legal and Illegal'
tags: [mlir, conversion]

---

# 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