forked from OSchip/llvm-project
[mlir] Add a new builtin `unrealized_conversion_cast` operation
An `unrealized_conversion_cast` operation represents an unrealized conversion from one set of types to another, that is used to enable the inter-mixing of different type systems. This operation should not be attributed any special representational or execution semantics, and is generally only intended to be used to satisfy the temporary intermixing of type systems during the conversion of one type system to another. This operation was discussed in the following RFC(and ODM): https://llvm.discourse.group/t/open-meeting-1-14-dialect-conversion-and-type-conversion-the-question-of-cast-operations/ Differential Revision: https://reviews.llvm.org/D94832
This commit is contained in:
parent
6ccf2d62b4
commit
c78219f644
|
@ -17,6 +17,8 @@
|
|||
#include "mlir/IR/OwningOpRef.h"
|
||||
#include "mlir/IR/SymbolTable.h"
|
||||
#include "mlir/Interfaces/CallInterfaces.h"
|
||||
#include "mlir/Interfaces/CastInterfaces.h"
|
||||
#include "mlir/Interfaces/SideEffectInterfaces.h"
|
||||
#include "llvm/Support/PointerLikeTypeTraits.h"
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
include "mlir/IR/BuiltinDialect.td"
|
||||
include "mlir/IR/SymbolInterfaces.td"
|
||||
include "mlir/Interfaces/CallInterfaces.td"
|
||||
include "mlir/Interfaces/CastInterfaces.td"
|
||||
include "mlir/Interfaces/SideEffectInterfaces.td"
|
||||
|
||||
// Base class for Builtin dialect ops.
|
||||
class Builtin_Op<string mnemonic, list<OpTrait> traits = []> :
|
||||
|
@ -220,4 +222,53 @@ def ModuleTerminatorOp : Builtin_Op<"module_terminator", [
|
|||
let assemblyFormat = "attr-dict";
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// UnrealizedConversionCastOp
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
def UnrealizedConversionCastOp : Builtin_Op<"unrealized_conversion_cast", [
|
||||
DeclareOpInterfaceMethods<CastOpInterface>, NoSideEffect
|
||||
]> {
|
||||
let summary = "An unrealized conversion from one set of types to another";
|
||||
let description = [{
|
||||
An `unrealized_conversion_cast` operation represents an unrealized
|
||||
conversion from one set of types to another, that is used to enable the
|
||||
inter-mixing of different type systems. This operation should not be
|
||||
attributed any special representational or execution semantics, and is
|
||||
generally only intended to be used to satisfy the temporary intermixing of
|
||||
type systems during the conversion of one type system to another.
|
||||
|
||||
This operation may produce results of arity 1-N, and accept as input
|
||||
operands of arity 0-N.
|
||||
|
||||
Example:
|
||||
|
||||
```mlir
|
||||
// An unrealized 0-1 conversion. These types of conversions are useful in
|
||||
// cases where a type is removed from the type system, but not all uses have
|
||||
// been converted. For example, imagine we have a tuple type that is
|
||||
// expanded to its element types. If only some uses of an empty tuple type
|
||||
// instance are converted we still need an instance of the tuple type, but
|
||||
// have no inputs to the unrealized conversion.
|
||||
%result = unrealized_conversion_cast to !bar.tuple_type<>
|
||||
|
||||
// An unrealized 1-1 conversion.
|
||||
%result1 = unrealized_conversion_cast %operand : !foo.type to !bar.lowered_type
|
||||
|
||||
// An unrealized 1-N conversion.
|
||||
%results2:2 = unrealized_conversion_cast %tuple_operand : !foo.tuple_type<!foo.type, !foo.type> to !foo.type, !foo.type
|
||||
|
||||
// An unrealized N-1 conversion.
|
||||
%result3 = unrealized_conversion_cast %operand, %operand : !foo.type, !foo.type to !bar.tuple_type<!foo.type, !foo.type>
|
||||
```
|
||||
}];
|
||||
|
||||
let arguments = (ins Variadic<AnyType>:$inputs);
|
||||
let results = (outs Variadic<AnyType>:$outputs);
|
||||
let assemblyFormat = [{
|
||||
($inputs^ `:` type($inputs))? `to` type($outputs) attr-dict
|
||||
}];
|
||||
let hasFolder = 1;
|
||||
}
|
||||
|
||||
#endif // BUILTIN_OPS
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "mlir/IR/BuiltinTypes.h"
|
||||
#include "mlir/IR/FunctionImplementation.h"
|
||||
#include "mlir/IR/OpImplementation.h"
|
||||
#include "mlir/IR/PatternMatch.h"
|
||||
#include "llvm/ADT/MapVector.h"
|
||||
|
||||
using namespace mlir;
|
||||
|
@ -236,6 +237,38 @@ static LogicalResult verify(ModuleOp op) {
|
|||
return success();
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// UnrealizedConversionCastOp
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
LogicalResult
|
||||
UnrealizedConversionCastOp::fold(ArrayRef<Attribute> attrOperands,
|
||||
SmallVectorImpl<OpFoldResult> &foldResults) {
|
||||
OperandRange operands = inputs();
|
||||
if (operands.empty())
|
||||
return failure();
|
||||
|
||||
// Check that the input is a cast with results that all feed into this
|
||||
// operation, and operand types that directly match the result types of this
|
||||
// operation.
|
||||
ResultRange results = outputs();
|
||||
Value firstInput = operands.front();
|
||||
auto inputOp = firstInput.getDefiningOp<UnrealizedConversionCastOp>();
|
||||
if (!inputOp || inputOp.getResults() != operands ||
|
||||
inputOp.getOperandTypes() != results.getTypes())
|
||||
return failure();
|
||||
|
||||
// If everything matches up, we can fold the passthrough.
|
||||
foldResults.append(inputOp->operand_begin(), inputOp->operand_end());
|
||||
return success();
|
||||
}
|
||||
|
||||
bool UnrealizedConversionCastOp::areCastCompatible(TypeRange inputs,
|
||||
TypeRange outputs) {
|
||||
// `UnrealizedConversionCastOp` is agnostic of the input/output types.
|
||||
return true;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// TableGen'd op method definitions
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -37,8 +37,10 @@ add_mlir_library(MLIRIR
|
|||
MLIRBuiltinOpsIncGen
|
||||
MLIRBuiltinTypesIncGen
|
||||
MLIRCallInterfacesIncGen
|
||||
MLIRCastInterfacesIncGen
|
||||
MLIROpAsmInterfaceIncGen
|
||||
MLIRRegionKindInterfaceIncGen
|
||||
MLIRSideEffectInterfacesIncGen
|
||||
MLIRSymbolInterfacesIncGen
|
||||
|
||||
LINK_LIBS PUBLIC
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
// RUN: mlir-opt %s -canonicalize | FileCheck %s
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// UnrealizedConversionCastOp
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Test folding conversion casts feeding into other casts.
|
||||
// CHECK-LABEL: func @multiple_conversion_casts
|
||||
// CHECK-SAME: %[[ARG0:.*]]: i32, %[[ARG1:.*]]:
|
||||
func @multiple_conversion_casts(%arg0: i32, %arg1: i32) -> (i32, i32) {
|
||||
// CHECK-NOT: unrealized_conversion_cast
|
||||
// CHECK: return %[[ARG0]], %[[ARG1]]
|
||||
%inputs:2 = unrealized_conversion_cast %arg0, %arg1 : i32, i32 to i64, i64
|
||||
%outputs:2 = unrealized_conversion_cast %inputs#0, %inputs#1 : i64, i64 to i32, i32
|
||||
return %outputs#0, %outputs#1 : i32, i32
|
||||
}
|
||||
|
||||
// CHECK-LABEL: func @multiple_conversion_casts
|
||||
func @multiple_conversion_casts_failure(%arg0: i32, %arg1: i32, %arg2: i64) -> (i32, i32) {
|
||||
// CHECK: unrealized_conversion_cast
|
||||
// CHECK: unrealized_conversion_cast
|
||||
%inputs:2 = unrealized_conversion_cast %arg0, %arg1 : i32, i32 to i64, i64
|
||||
%outputs:2 = unrealized_conversion_cast %arg2, %inputs#1 : i64, i64 to i32, i32
|
||||
return %outputs#0, %outputs#1 : i32, i32
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
// RUN: mlir-opt %s -split-input-file -verify-diagnostics
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// UnrealizedConversionCastOp
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// expected-error@+1 {{expected at least one result for cast operation}}
|
||||
"unrealized_conversion_cast"() : () -> ()
|
||||
|
||||
// -----
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// RUN: mlir-opt %s -allow-unregistered-dialect | mlir-opt -allow-unregistered-dialect
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// UnrealizedConversionCastOp
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
%operand = "foo.op"() : () -> !foo.type
|
||||
%tuple_operand = "foo.op"() : () -> !foo.tuple_type<!foo.type, !foo.type>
|
||||
|
||||
// An unrealized 0-1 conversion.
|
||||
%result = unrealized_conversion_cast to !bar.tuple_type<>
|
||||
|
||||
// An unrealized 1-1 conversion.
|
||||
%result1 = unrealized_conversion_cast %operand : !foo.type to !bar.lowered_type
|
||||
|
||||
// An unrealized 1-N conversion.
|
||||
%results2:2 = unrealized_conversion_cast %tuple_operand : !foo.tuple_type<!foo.type, !foo.type> to !foo.type, !foo.type
|
||||
|
||||
// An unrealized N-1 conversion.
|
||||
%result3 = unrealized_conversion_cast %operand, %operand : !foo.type, !foo.type to !bar.tuple_type<!foo.type, !foo.type>
|
Loading…
Reference in New Issue