summaryrefslogtreecommitdiffstats
path: root/mlir
diff options
context:
space:
mode:
authorRiver Riddle <riverriddle@google.com>2019-08-19 17:01:13 -0700
committerA. Unique TensorFlower <gardener@tensorflow.org>2019-08-19 17:01:46 -0700
commit774b37b89b88e063aa4df47bd2637cf51283740c (patch)
treebab5c5beb02156143ac56f2b6a77065c77493426 /mlir
parent2277b9fb5c235dccfbfb803fd81f3ffe3c09872a (diff)
downloadbcm5719-llvm-774b37b89b88e063aa4df47bd2637cf51283740c.tar.gz
bcm5719-llvm-774b37b89b88e063aa4df47bd2637cf51283740c.zip
Add a DialectConversion document detailing the conversion infrastructure.
This is an important piece of the infrastructure that is missing proper high level documentation on usage. PiperOrigin-RevId: 264275482
Diffstat (limited to 'mlir')
-rw-r--r--mlir/g3doc/DialectConversion.md229
-rw-r--r--mlir/include/mlir/Transforms/DialectConversion.h4
2 files changed, 231 insertions, 2 deletions
diff --git a/mlir/g3doc/DialectConversion.md b/mlir/g3doc/DialectConversion.md
new file mode 100644
index 00000000000..22137e48204
--- /dev/null
+++ b/mlir/g3doc/DialectConversion.md
@@ -0,0 +1,229 @@
+# Dialect Conversion
+
+This document describes a framework in MLIR in which to perform operation
+conversions between, and within dialects. This framework allows for transforming
+illegal operations to those supported by a provided conversion target, via a set
+of pattern-based operation rewriting patterns.
+
+[TOC]
+
+To utilize the framework, a few things must be provided:
+
+* A [Conversion Target](#conversion-target)
+* A set of [Rewrite Patterns](#rewrite-pattern-specification)
+* A [Type Converter](#type-conversion) (Optional)
+
+## Modes of Conversion
+
+When applying a conversion to a set of operations, there are several conversion
+modes that can be selected from:
+
+* Partial Conversion
+
+ - A partial conversion will legalize as many operations to the target as
+ possible, but will allow pre-existing operations that were not
+ explicitly marked as `illegal` to remain unconverted. This allows for
+ partially lowering parts of the module in the presence of unknown
+ operations.
+ - A partial conversion can be applied via `applyPartialConversion`.
+
+* Full Conversion
+
+ - A full conversion is only successful if all operations are properly
+ legalized to the given conversion target. This ensures that only known
+ operations will exist after the conversion process.
+ - A full conversion can be applied via `applyFullConversion`.
+
+* Analysis Conversion
+
+ - An analysis conversion will analyze which operations are legalizable to
+ the given conversion target if a conversion were to be applied. Note
+ that no rewrites, or transformations, are actually applied to the input
+ operations.
+ - An analysis conversion can be applied via `applyAnalysisConversion`.
+
+## Conversion Target
+
+The conversion target is the formal definition of what is considered to be legal
+during the conversion process. The final operations generated by the conversion
+framework must be marked as legal on the `ConversionTarget` for the rewrite to
+be a success. Existing operations need not always be legal though, see the
+different conversion modes for why. Operations, and dialects, may be marked with
+any of the provided legality actions below:
+
+* Legal
+
+ - This action signals that every instance of a given operation is legal,
+ i.e. any combination of attributes, operands, types, etc. are valid.
+
+* Dynamic
+
+ - This action signals that only some instances of a given operation are
+ legal. This allows for defining fine-tune constraints, e.g. saying that
+ `addi` is only legal when operating on 32-bit integers.
+ - If a specific handler is not provided when setting the action, the
+ target must override the `isDynamicallyLegal` hook provided by
+ `ConversionTarget`.
+
+* Illegal
+
+ - This action signals that no instance of a given operation is legal.
+ Operations marked as `illegal` must always be converted for the
+ conversion to be successful. This action also allows for selectively
+ marking specific operations, in an otherwise legal dialect, as illegal.
+
+An example conversion target is shown below:
+
+```c++
+struct MyTarget : public ConversionTarget {
+ MyTarget(MLIRContext &ctx) : ConversionTarget(ctx) {
+ //--------------------------------------------------------------------------
+ // Marking an operation as Legal:
+
+ /// Mark all operations within the LLVM dialect are legal.
+ addLegalDialects<LLVMDialect>();
+
+ /// Mark `std.constant` op is always legal on this target.
+ addLegalOps<ConstantOp>();
+
+ //--------------------------------------------------------------------------
+ // Marking an operation as dynamically legal.
+
+ /// Mark all operations within Affine dialect have dynamic legality
+ /// constraints.
+ addDynamicallyLegalDialects<AffineDialect>();
+
+ /// Mark `std.return` as dynamically legal.
+ addDynamicallyLegalOp<ReturnOp>();
+
+ /// Mark `std.return` as dynamically legal, but provide a specific legality
+ /// callback.
+ addDynamicallyLegalOp<ReturnOp>([](ReturnOp op) { ... });
+
+ //--------------------------------------------------------------------------
+ // Marking an operation as illegal.
+
+ /// All operations within the GPU dialect are illegal.
+ addIllegalDialect<GPUDialect>();
+
+ /// Mark `std.br` and `std.cond_br` as illegal.
+ addIllegalOp<BranchOp, 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 { ... }
+};
+```
+
+## Rewrite Pattern Specification
+
+After the conversion target has been defined, a set of legalization patterns
+must be provided to transform illegal operations into legal ones. The patterns
+supplied here, that do not [require type changes](#conversion-patterns), are the
+same as those described in the
+[quickstart rewrites guide](QuickstartRewrites.md#adding-patterns). The patterns
+provided do not need to generate operations that are directly legal on the
+target. The framework will automatically build a graph of conversions to convert
+non-legal operations into a set of legal ones.
+
+As an example, say you define a target that supports one operation: `foo.add`.
+When providing the following patterns: [`bar.add` -> `baz.add`, `baz.add` ->
+`foo.add`], the framework will automatically detect that it can legalize
+`baz.add` -> `foo.add` even though a direct conversion does not exist. This
+means that you don’t have to define a direct legalization pattern for `bar.add`
+-> `foo.add`.
+
+## Type Conversion
+
+It is sometimes necessary as part of a conversion to convert the set types of
+being operated on. In these cases a `TypeConverter` object may be defined that
+details how types should be converted. The `TypeConverter` is used by patterns,
+and the general conversion infrastructure, to convert the signatures of blocks
+and regions.
+
+### Type Converter
+
+As stated above, the `TypeConverter` contains several hooks for detailing how to
+convert types, several of these hooks are detailed below:
+
+```c++
+class TypeConverter {
+ public:
+ /// This hook allows for converting a type. This function should return
+ /// failure if no valid conversion exists, success otherwise. If the new set
+ /// of types is empty, the type is removed and any usages of the existing
+ /// value are expected to be removed during conversion.
+ virtual LogicalResult convertType(Type t, SmallVectorImpl<Type> &results);
+
+ /// This hook simplifies defining 1-1 type conversions. This function returns
+ /// the type to convert to on success, and a null type on failure.
+ virtual Type convertType(Type t);
+
+ /// This hook allows for materializing a conversion from a set of types into
+ /// one result type by generating a cast operation of some kind. The generated
+ /// operation should produce one result, of 'resultType', with the provided
+ /// 'inputs' as operands. This hook must be overridden when a type conversion
+ /// results in more than one type, or if a type conversion may persist after
+ /// the conversion has finished.
+ virtual Operation *materializeConversion(PatternRewriter &rewriter,
+ Type resultType,
+ ArrayRef<Value *> inputs,
+ Location loc);
+};
+```
+
+### Conversion Patterns
+
+When type conversion comes into play, the general Rewrite Patterns can no longer
+be used. This is due to the fact that the operands of the operation being
+matched will not correspond with the operands of the correct type as determined
+by `TypeConverter`. The operation rewrites on type boundaries must thus use a
+special pattern, the `ConversionPattern`. This pattern provides, as an
+additional argument to the `matchAndRewrite` and `rewrite` methods, the set of
+remapped operands corresponding to the desired type. These patterns also utilize
+a special `PatternRewriter`, `ConversionPatternRewriter`, that provides special
+hooks for use with the conversion infrastructure.
+
+```c++
+struct MyConversionPattern : public ConversionPattern {
+ /// The `matchAndRewrite` hooks on ConversionPatterns take an additional
+ /// `operands` parameter, containing the remapped operands of the original
+ /// operation.
+ virtual PatternMatchResult
+ matchAndRewrite(Operation *op, ArrayRef<Value *> operands,
+ ConversionPatternRewriter &rewriter) const;
+};
+```
+
+### Region Signature Conversion
+
+From the perspective of type conversion, the entry block to a region is often
+special. The types of the entry block arguments are often tied semantically to
+details on the operation, e.g. FuncOp, AffineForOp, etc. Given this, the
+conversion of the types for this block must be done explicitly via a conversion
+pattern. To convert the signature of a region entry block, a custom hook on the
+ConversionPatternRewriter must be invoked `applySignatureConversion`. A
+signature conversion, `TypeConverter::SignatureConversion`, can be built
+programmatically:
+
+```c++
+class SignatureConversion {
+public:
+ /// Remap an input of the original signature with a new set of types. The
+ /// new types are appended to the new signature conversion.
+ void addInputs(unsigned origInputNo, ArrayRef<Type> types);
+
+ /// Append new input types to the signature conversion, this should only be
+ /// used if the new types are not intended to remap an existing input.
+ void addInputs(ArrayRef<Type> types);
+
+ /// Remap an input of the original signature with a range of types in the
+ /// new signature.
+ void remapInput(unsigned origInputNo, unsigned newInputNo,
+ unsigned newInputCount = 1);
+};
+```
+
+The `TypeConverter` provides several default utilities for signature conversion:
+`convertSignatureArg`/`convertBlockSignature`.
diff --git a/mlir/include/mlir/Transforms/DialectConversion.h b/mlir/include/mlir/Transforms/DialectConversion.h
index bd7d021ddcd..3cdf14c3eb3 100644
--- a/mlir/include/mlir/Transforms/DialectConversion.h
+++ b/mlir/include/mlir/Transforms/DialectConversion.h
@@ -94,14 +94,14 @@ public:
SmallVector<Type, 4> argTypes;
};
- /// This hooks allows for converting a type. This function should return
+ /// This hook allows for converting a type. This function should return
/// failure if no valid conversion exists, success otherwise. If the new set
/// of types is empty, the type is removed and any usages of the existing
/// value are expected to be removed during conversion.
virtual LogicalResult convertType(Type t, SmallVectorImpl<Type> &results);
/// This hook simplifies defining 1-1 type conversions. This function returns
- /// the type convert to on success, and a null type on failure.
+ /// the type to convert to on success, and a null type on failure.
virtual Type convertType(Type t) { return t; }
/// Convert the given set of types, filling 'results' as necessary. This
OpenPOWER on IntegriCloud