diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td index 3f27f6d9ae8b7..b9c138c70a940 100644 --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td @@ -2399,6 +2399,29 @@ def LLVM_InlineAsmOp : LLVM_Op<"inline_asm", [DeclareOpInterfaceMethods { + let description = [{ + The ModuleAsmOp mirrors the underlying LLVM "module asm" semantics, + allowing target-specific assembly code to be embedded at module level. + + Module asm blocks are concatenated and emitted outside of any function, + corresponding to GCC's file scope inline assembly. The assembly string + must be parseable by LLVM's integrated assembler and can reference + module-level symbols but not local variables. + + Example: + ``` + llvm.module_asm "my_function: ret" + llvm.module_asm ".globl my_symbol" + ``` + }]; + let arguments = (ins StrAttr:$asm_string); + + let assemblyFormat = [{ + attr-dict $asm_string + }]; +} + //===--------------------------------------------------------------------===// // CallIntrinsicOp //===--------------------------------------------------------------------===// diff --git a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp index 0f675a0a5df5d..3b91fcab9a926 100644 --- a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp @@ -505,6 +505,12 @@ convertOperationImpl(Operation &opInst, llvm::IRBuilderBase &builder, return success(); } + if (auto moduleAsmOp = dyn_cast(opInst)) { + moduleTranslation.getLLVMModule()->appendModuleInlineAsm( + moduleAsmOp.getAsmString()); + return success(); + } + if (auto invOp = dyn_cast(opInst)) { auto operands = moduleTranslation.lookupValues(invOp.getCalleeOperands()); SmallVector opBundles = diff --git a/mlir/test/Dialect/LLVMIR/canonicalize.mlir b/mlir/test/Dialect/LLVMIR/canonicalize.mlir index 8accf6e263863..326058884500b 100644 --- a/mlir/test/Dialect/LLVMIR/canonicalize.mlir +++ b/mlir/test/Dialect/LLVMIR/canonicalize.mlir @@ -307,3 +307,11 @@ llvm.func @inline_asm_side_effects(%x : i32) { llvm.inline_asm has_side_effects "inline asm with side effects", "r" %x : (i32) -> () llvm.return } + +// ----- + +// CHECK-LABEL: llvm.module_asm +// CHECK-SAME: ".global some_symbol" +// CHECK-NEXT: llvm.module_asm ".global another_symbol" +llvm.module_asm ".global some_symbol" +llvm.module_asm ".global another_symbol" \ No newline at end of file diff --git a/mlir/test/Target/LLVMIR/llvmir.mlir b/mlir/test/Target/LLVMIR/llvmir.mlir index fc1993b50ba2d..a4c301c12b3b0 100644 --- a/mlir/test/Target/LLVMIR/llvmir.mlir +++ b/mlir/test/Target/LLVMIR/llvmir.mlir @@ -2088,6 +2088,15 @@ llvm.func @useInlineAsm2(%arg0: !llvm.ptr, %arg1: i64, %arg2: !llvm.ptr, %arg3: // ----- +module { + // CHECK: module asm ".global file_scope_asm_symbol" + // CHECK-NEXT: module asm "some_asm_label:" + llvm.module_asm ".global file_scope_asm_symbol" + llvm.module_asm "some_asm_label:" +} + +// ----- + llvm.func @fastmathFlagsFunc(f32) -> f32 // CHECK-LABEL: @fastmathFlags