include "mlir/Dialect/EmitC/IR/EmitCAttributes.td"
include "mlir/Dialect/EmitC/IR/EmitCTypes.td"
+include "mlir/Interfaces/CastInterfaces.td"
include "mlir/Interfaces/SideEffectInterfaces.td"
//===----------------------------------------------------------------------===//
let hasVerifier = 1;
}
+def EmitC_CastOp : EmitC_Op<"cast", [
+ DeclareOpInterfaceMethods<CastOpInterface>,
+ SameOperandsAndResultShape
+ ]> {
+ let summary = "Cast operation";
+ let description = [{
+ The `cast` operation performs an explicit type conversion and is emitted
+ as a C-style cast expression. It can be applied to integer, float, index
+ and EmitC types.
+
+ Example:
+
+ ```mlir
+ // Cast from `int32_t` to `float`
+ %0 = emitc.cast %arg0: i32 to f32
+
+ // Cast from `void` to `int32_t` pointer
+ %1 = emitc.cast %arg1 :
+ !emitc.ptr<!emitc.opaque<"void">> to !emitc.ptr<i32>
+ ```
+ }];
+
+ let arguments = (ins AnyType:$source);
+ let results = (outs AnyType:$dest);
+ let assemblyFormat = "$source attr-dict `:` type($source) `to` type($dest)";
+}
+
def EmitC_ConstantOp : EmitC_Op<"constant", [ConstantLike]> {
let summary = "Constant operation";
let description = [{
MLIREmitCAttributesIncGen
LINK_LIBS PUBLIC
+ MLIRCastInterfaces
MLIRIR
MLIRSideEffectInterfaces
)
return success();
}
+//===----------------------------------------------------------------------===//
+// CastOp
+//===----------------------------------------------------------------------===//
+
+bool CastOp::areCastCompatible(TypeRange inputs, TypeRange outputs) {
+ Type input = inputs.front(), output = outputs.front();
+
+ return ((input.isa<IntegerType, FloatType, IndexType, emitc::OpaqueType,
+ emitc::PointerType>()) &&
+ (output.isa<IntegerType, FloatType, IndexType, emitc::OpaqueType,
+ emitc::PointerType>()));
+}
+
//===----------------------------------------------------------------------===//
// CallOp
//===----------------------------------------------------------------------===//
return success();
}
+static LogicalResult printOperation(CppEmitter &emitter, emitc::CastOp castOp) {
+ raw_ostream &os = emitter.ostream();
+ Operation &op = *castOp.getOperation();
+
+ if (failed(emitter.emitAssignPrefix(op)))
+ return failure();
+ os << "(";
+ if (failed(emitter.emitType(op.getLoc(), op.getResult(0).getType())))
+ return failure();
+ os << ") ";
+ os << emitter.getOrCreateName(castOp.getOperand());
+
+ return success();
+}
+
static LogicalResult printOperation(CppEmitter &emitter,
emitc::IncludeOp includeOp) {
raw_ostream &os = emitter.ostream();
.Case<cf::BranchOp, cf::CondBranchOp>(
[&](auto op) { return printOperation(*this, op); })
// EmitC ops.
- .Case<emitc::ApplyOp, emitc::CallOp, emitc::ConstantOp,
+ .Case<emitc::ApplyOp, emitc::CallOp, emitc::CastOp, emitc::ConstantOp,
emitc::IncludeOp, emitc::VariableOp>(
[&](auto op) { return printOperation(*this, op); })
// Func ops.
%c0 = "emitc.variable"(){value = "nullptr" : !emitc.ptr<i64>} : () -> !emitc.ptr<i32>
return
}
+
+// -----
+
+func.func @cast_tensor(%arg : tensor<f32>) {
+ // expected-error @+1 {{'emitc.cast' op operand type 'tensor<f32>' and result type 'tensor<f32>' are cast incompatible}}
+ %1 = emitc.cast %arg: tensor<f32> to tensor<f32>
+ return
+}
return
}
+func.func @cast(%arg0: i32) {
+ %1 = emitc.cast %arg0: i32 to f32
+ return
+}
+
func.func @c() {
%1 = "emitc.constant"(){value = 42 : i32} : () -> i32
return
--- /dev/null
+// RUN: mlir-translate -mlir-to-cpp %s | FileCheck %s
+// CHECK-LABEL: void cast
+func.func @cast(%arg0 : i32) {
+ // CHECK-NEXT: uint32_t [[V1:[^ ]*]] = (uint32_t) [[V0:[^ ]*]]
+ %1 = emitc.cast %arg0: i32 to ui32
+
+ // CHECK-NEXT: int64_t [[V4:[^ ]*]] = (int64_t) [[V0:[^ ]*]]
+ %2 = emitc.cast %arg0: i32 to i64
+ // CHECK-NEXT: int64_t [[V5:[^ ]*]] = (uint64_t) [[V0:[^ ]*]]
+ %3 = emitc.cast %arg0: i32 to ui64
+
+ // CHECK-NEXT: float [[V4:[^ ]*]] = (float) [[V0:[^ ]*]]
+ %4 = emitc.cast %arg0: i32 to f32
+ // CHECK-NEXT: double [[V5:[^ ]*]] = (double) [[V0:[^ ]*]]
+ %5 = emitc.cast %arg0: i32 to f64
+
+ // CHECK-NEXT: bool [[V6:[^ ]*]] = (bool) [[V0:[^ ]*]]
+ %6 = emitc.cast %arg0: i32 to i1
+
+ // CHECK-NEXT: mytype [[V7:[^ ]*]] = (mytype) [[V0:[^ ]*]]
+ %7 = emitc.cast %arg0: i32 to !emitc.opaque<"mytype">
+ return
+}
+
+// CHECK-LABEL: void cast_ptr
+func.func @cast_ptr(%arg0 : !emitc.ptr<!emitc.opaque<"void">>) {
+ // CHECK-NEXT: int32_t* [[V1:[^ ]*]] = (int32_t*) [[V0:[^ ]*]]
+ %1 = emitc.cast %arg0 : !emitc.ptr<!emitc.opaque<"void">> to !emitc.ptr<i32>
+ return
+}