diff --git a/mlir/include/mlir/Dialect/StandardOps/IR/Ops.td b/mlir/include/mlir/Dialect/StandardOps/IR/Ops.td --- a/mlir/include/mlir/Dialect/StandardOps/IR/Ops.td +++ b/mlir/include/mlir/Dialect/StandardOps/IR/Ops.td @@ -1988,6 +1988,60 @@ let hasFolder = 1; } +//===----------------------------------------------------------------------===// +// InlineAsmOp +//===----------------------------------------------------------------------===// + +def AsmATT : I64EnumAttrCase<"AD_ATT", 0, "att">; +def AsmIntel : I64EnumAttrCase<"AD_Intel", 1, "intel">; +def AsmATTOrIntel : I64EnumAttr< + "AsmDialect", "ATT (0) or Intel (1) asm dialect", [AsmATT, AsmIntel]>; + +def InlineAsmOp : Std_Op<"inline_asm"> { + let description = [{ + MLIR type-compatible equivalent of the LLVM inline_asm op. Detailed + documentation is available in the LLVM + [LangRef](https://llvm.org/docs/LangRef.html#inline-assembler-expressions). + + The `inline_asm` op allows injecting inline assembly passed as an + `asm_string` string attribute and subject to constraints passed as a + `constraints` string attribute. + + `has_side_effects` and `is_align_stack` modifier unit attributes as well as + an `asm_dialect` enum attributes can be specified to modify the semantics of + the op according to the LLVM spec. + + Example: + + ```mlir + %1#2 = inline_asm has_side_effects "some_asm", "=r,=r,r" %0 : + (i64) -> (i32, i32) + ``` + }]; + let arguments = ( + ins Variadic:$operands, + StrAttr:$asm_string, + StrAttr:$constraints, + UnitAttr:$has_side_effects, + UnitAttr:$is_align_stack, + OptionalAttr< + DefaultValuedAttr>:$asm_dialect); + + let results = (outs Variadic:$res); + + let assemblyFormat = [{ + (`has_side_effects` $has_side_effects^)? + (`is_align_stack` $is_align_stack^)? + (`asm_dialect` `=` $asm_dialect^)? + attr-dict + $asm_string `,` $constraints + operands `:` functional-type(operands, results) + }]; + + // `InlineAsmOp` is fully verified by its traits. + let verifier = ?; +} + //===----------------------------------------------------------------------===// // LoadOp //===----------------------------------------------------------------------===// diff --git a/mlir/lib/Conversion/StandardToLLVM/StandardToLLVM.cpp b/mlir/lib/Conversion/StandardToLLVM/StandardToLLVM.cpp --- a/mlir/lib/Conversion/StandardToLLVM/StandardToLLVM.cpp +++ b/mlir/lib/Conversion/StandardToLLVM/StandardToLLVM.cpp @@ -218,7 +218,6 @@ return converted.getPointerTo(); } - // Function types are converted to LLVM Function types by recursively converting // argument and result types. If MLIR Function has zero results, the LLVM // Function has one VoidType result. If MLIR Function has more than one result, @@ -1674,6 +1673,8 @@ using ExpOpLowering = VectorConvertToLLVMPattern; using Exp2OpLowering = VectorConvertToLLVMPattern; using FloorFOpLowering = VectorConvertToLLVMPattern; +using InlineAsmOpLowering = + OneToOneConvertToLLVMPattern; using Log10OpLowering = VectorConvertToLLVMPattern; using Log2OpLowering = VectorConvertToLLVMPattern; using LogOpLowering = VectorConvertToLLVMPattern; @@ -3972,6 +3973,7 @@ FPTruncLowering, ImOpLowering, IndexCastOpLowering, + InlineAsmOpLowering, MulFOpLowering, MulIOpLowering, NegFOpLowering, diff --git a/mlir/test/Conversion/StandardToLLVM/convert-to-llvmir.mlir b/mlir/test/Conversion/StandardToLLVM/convert-to-llvmir.mlir --- a/mlir/test/Conversion/StandardToLLVM/convert-to-llvmir.mlir +++ b/mlir/test/Conversion/StandardToLLVM/convert-to-llvmir.mlir @@ -1475,3 +1475,30 @@ // CHECK32: %[[SIZE:.*]] = llvm.load %{{.*}} : !llvm.ptr // CHECK32-NEXT: llvm.return %[[SIZE]] : !llvm.i32 + +// ----- + +// CHECK-LABEL: @useInlineAsm +func @useInlineAsm(%arg0: i32) { + // CHECK: inline_asm "bswap $0", "=r,r" %{{.*}} : (!llvm.i32) -> !llvm.i8 + %0 = inline_asm "bswap $0", "=r,r" %arg0 : (i32) -> i8 + + // CHECK-NEXT: inline_asm "foo", "bar" %{{.*}}, %{{.*}} : (!llvm.i32, !llvm.i32) -> !llvm.i8 + %1 = inline_asm "foo", "bar" %arg0, %arg0 : (i32, i32) -> i8 + + // CHECK-NEXT: inline_asm has_side_effects "foo", "bar" %{{.*}}, %{{.*}} : (!llvm.i32, !llvm.i32) -> !llvm.i8 + %2 = inline_asm has_side_effects "foo", "bar" %arg0, %arg0 : (i32, i32) -> i8 + + // CHECK-NEXT: inline_asm is_align_stack "foo", "bar" %{{.*}}, %{{.*}} : (!llvm.i32, !llvm.i32) -> !llvm.i8 + %3 = inline_asm is_align_stack "foo", "bar" %arg0, %arg0 : (i32, i32) -> i8 + + // CHECK-NEXT: inline_asm asm_dialect = 1 "foo", "bar" %{{.*}}, %{{.*}} : (!llvm.i32, !llvm.i32) -> !llvm.i8 + %4 = inline_asm asm_dialect = 1 "foo", "bar" %arg0, %arg0 : (i32, i32) -> i8 + + // CHECK-NEXT: %[[MULTI:.*]] = llvm.inline_asm "foo", "=r,=r,r" %{{.*}} : (!llvm.i32) -> !llvm.struct<(i8, i8)> + // CHECK-NEXT: llvm.extractvalue %[[MULTI]][0] : !llvm.struct<(i8, i8)> + // CHECK-NEXT: llvm.extractvalue %[[MULTI]][1] : !llvm.struct<(i8, i8)> + %5:2 = inline_asm "foo", "=r,=r,r" %arg0 : (i32) -> (i8, i8) + + return +} diff --git a/mlir/test/Dialect/Standard/ops.mlir b/mlir/test/Dialect/Standard/ops.mlir --- a/mlir/test/Dialect/Standard/ops.mlir +++ b/mlir/test/Dialect/Standard/ops.mlir @@ -108,3 +108,25 @@ return } +// CHECK-LABEL: @useInlineAsm +func @useInlineAsm(%arg0: i32) { + // CHECK: inline_asm {{.*}} (i32) -> i8 + %0 = inline_asm "bswap $0", "=r,r" %arg0 : (i32) -> i8 + + // CHECK-NEXT: inline_asm {{.*}} (i32, i32) -> i8 + %1 = inline_asm "foo", "bar" %arg0, %arg0 : (i32, i32) -> i8 + + // CHECK-NEXT: inline_asm has_side_effects {{.*}} (i32, i32) -> i8 + %2 = inline_asm has_side_effects "foo", "bar" %arg0, %arg0 : (i32, i32) -> i8 + + // CHECK-NEXT: inline_asm is_align_stack {{.*}} (i32, i32) -> i8 + %3 = inline_asm is_align_stack "foo", "bar" %arg0, %arg0 : (i32, i32) -> i8 + + // CHECK-NEXT: inline_asm asm_dialect = 1 {{.*}} (i32, i32) -> i8 + %4 = inline_asm asm_dialect = 1 "foo", "bar" %arg0, %arg0 : (i32, i32) -> i8 + + // CHECK-NEXT: inline_asm asm_dialect = 1 {{.*}} (i32) -> (i8, i8) + %5:2 = inline_asm "foo", "=r,=r,r" %arg0 : (i32) -> (i8, i8) + + return +}