[Mlir-commits] [mlir] 29a0000 - [MLIR][LLVMIR] Add module flags support (#130679)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Fri Mar 14 18:03:39 PDT 2025


Author: Bruno Cardoso Lopes
Date: 2025-03-14T18:03:36-07:00
New Revision: 29a000023caf5b0b02a5d8b517d03f9538e2885e

URL: https://github.com/llvm/llvm-project/commit/29a000023caf5b0b02a5d8b517d03f9538e2885e
DIFF: https://github.com/llvm/llvm-project/commit/29a000023caf5b0b02a5d8b517d03f9538e2885e.diff

LOG: [MLIR][LLVMIR] Add module flags support (#130679)

Import and translation support.

Note that existing support (prior to this PR) already covers enough in
translation specifically to emit "Debug Info Version". Also, the debug
info version metadata is being emitted even though the imported IR has
no information and is showing up in some tests (will fix that in another
PR).

---------

Co-authored-by: Tobias Gysi <tobias.gysi at nextsilicon.com>
Co-authored-by: Henrich Lauko <xlauko at mail.muni.cz>

Added: 
    mlir/test/Dialect/LLVMIR/module-roundtrip.mlir
    mlir/test/Target/LLVMIR/Import/module-flags.ll

Modified: 
    mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
    mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.td
    mlir/include/mlir/Dialect/LLVMIR/LLVMEnums.td
    mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
    mlir/include/mlir/Target/LLVMIR/ModuleImport.h
    mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
    mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
    mlir/lib/Target/LLVMIR/ModuleImport.cpp
    mlir/test/Dialect/LLVMIR/invalid.mlir
    mlir/test/Target/LLVMIR/llvmir-invalid.mlir
    mlir/test/Target/LLVMIR/llvmir.mlir
    mlir/test/mlir-translate/split-markers.mlir

Removed: 
    


################################################################################
diff  --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
index d90d2ba6d6181..ede9f2d365b20 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
@@ -1291,4 +1291,29 @@ def LLVM_DereferenceableAttr : LLVM_Attr<"Dereferenceable", "dereferenceable"> {
   let assemblyFormat = "`<` struct(params) `>`";
 }
 
+//===----------------------------------------------------------------------===//
+// ModuleFlagAttr
+//===----------------------------------------------------------------------===//
+
+def ModuleFlagAttr
+    : LLVM_Attr<"ModuleFlag", "mlir.module_flag"> {
+  let summary = "LLVM module flag metadata";
+  let description = [{
+    Represents a single entry of llvm.module.flags metadata
+    (llvm::Module::ModuleFlagEntry in LLVM). The first element is a behavior
+    flag described by `ModFlagBehaviorAttr`, the second is a string ID
+    and third is the value of the flag (currently only integer constants
+    are supported).
+
+    Example:
+    ```mlir
+      #llvm.mlir.module_flag<error, "wchar_size", 4>
+    ```
+  }];
+  let parameters = (ins "ModFlagBehavior":$behavior,
+                        "StringAttr":$key,
+                        "uint32_t":$value);
+  let assemblyFormat = "`<` $behavior `,` $key `,` $value `>`";
+}
+
 #endif // LLVMIR_ATTRDEFS

diff  --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.td
index d35f48b13b2d8..46fae44f7b0fa 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.td
@@ -33,6 +33,7 @@ def LLVM_Dialect : Dialect {
     static StringRef getAliasScopesAttrName() { return "alias_scopes"; }
     static StringRef getAccessGroupsAttrName() { return "access_groups"; }
     static StringRef getIdentAttrName() { return "llvm.ident"; }
+    static StringRef getModuleFlags() { return "llvm.module.flags"; }
     static StringRef getCommandlineAttrName() { return "llvm.commandline"; }
 
     /// Names of llvm parameter attributes.

diff  --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMEnums.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMEnums.td
index c08b75de03647..a9de787806452 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMEnums.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMEnums.td
@@ -818,4 +818,37 @@ def FPExceptionBehaviorAttr : LLVM_EnumAttr<
   let cppNamespace = "::mlir::LLVM";
 }
 
+//===----------------------------------------------------------------------===//
+// Module Flag Behavior
+//===----------------------------------------------------------------------===//
+
+// These values must match llvm::Module::ModFlagBehavior ones.
+// See llvm/include/llvm/IR/Module.h.
+def ModFlagBehaviorError
+    : LLVM_EnumAttrCase<"Error", "error", "Error", 1>;
+def ModFlagBehaviorWarning
+    : LLVM_EnumAttrCase<"Warning", "warning", "Warning", 2>;
+def ModFlagBehaviorRequire
+    : LLVM_EnumAttrCase<"Require", "require", "Require", 3>;
+def ModFlagBehaviorOverride
+    : LLVM_EnumAttrCase<"Override", "override", "Override", 4>;
+def ModFlagBehaviorAppend
+    : LLVM_EnumAttrCase<"Append", "append", "Append", 5>;
+def ModFlagBehaviorAppendUnique
+    : LLVM_EnumAttrCase<"AppendUnique", "append_unique", "AppendUnique", 6>;
+def ModFlagBehaviorMax
+    : LLVM_EnumAttrCase<"Max", "max", "Max", 7>;
+def ModFlagBehaviorMin
+    : LLVM_EnumAttrCase<"Min", "min", "Min", 8>;
+
+def ModFlagBehaviorAttr : LLVM_EnumAttr<
+    "ModFlagBehavior",
+    "::llvm::Module::ModFlagBehavior",
+    "LLVM Module Flag Behavior",
+    [ModFlagBehaviorError, ModFlagBehaviorWarning, ModFlagBehaviorRequire,
+     ModFlagBehaviorOverride, ModFlagBehaviorAppend,
+     ModFlagBehaviorAppendUnique, ModFlagBehaviorMax, ModFlagBehaviorMin]> {
+  let cppNamespace = "::mlir::LLVM";
+}
+
 #endif // LLVMIR_ENUMS

diff  --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
index b27da58d484a3..90cc851c0a3b2 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
@@ -2183,4 +2183,36 @@ def LLVM_LinkerOptionsOp
   let hasVerifier = 1;
 }
 
+//===--------------------------------------------------------------------===//
+// ModuleFlagsOp
+//===--------------------------------------------------------------------===//
+
+def LLVM_ModuleFlagsOp
+    : LLVM_Op<"module_flags"> {
+  let summary = "Information about module properties";
+  let description = [{
+    Represents the equivalent in MLIR for LLVM's `llvm.module.flags` metadata,
+    which requires a list of metadata triplets. Each triplet entry is described
+    by a `ModuleFlagAttr`.
+
+    Example:
+    ```mlir
+    llvm.module.flags [
+      #llvm.mlir.module_flag<error, "wchar_size", 4>,
+      #llvm.mlir.module_flag<max, "PIC Level", 2>
+    ]
+    ```
+  }];
+  let arguments  = (ins ArrayAttr:$flags);
+  let assemblyFormat = [{
+    $flags attr-dict
+  }];
+
+  let llvmBuilder = [{
+    convertModuleFlagsOp($flags, builder, moduleTranslation);
+  }];
+
+  let hasVerifier = 1;
+}
+
 #endif // LLVMIR_OPS

diff  --git a/mlir/include/mlir/Target/LLVMIR/ModuleImport.h b/mlir/include/mlir/Target/LLVMIR/ModuleImport.h
index a4d108e349c00..b766b1710ad80 100644
--- a/mlir/include/mlir/Target/LLVMIR/ModuleImport.h
+++ b/mlir/include/mlir/Target/LLVMIR/ModuleImport.h
@@ -218,6 +218,9 @@ class ModuleImport {
   /// LLVM dialect operation.
   LogicalResult convertLinkerOptionsMetadata();
 
+  /// Converts !llvm.module.flags metadata.
+  LogicalResult convertModuleFlagsMetadata();
+
   /// Converts !llvm.ident metadata to the llvm.ident LLVM ModuleOp attribute.
   LogicalResult convertIdentMetadata();
 

diff  --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
index 239dcbd8c5d19..5370de501a85c 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
@@ -3712,6 +3712,20 @@ LogicalResult LinkerOptionsOp::verify() {
   return success();
 }
 
+//===----------------------------------------------------------------------===//
+// ModuleFlagsOp
+//===----------------------------------------------------------------------===//
+
+LogicalResult ModuleFlagsOp::verify() {
+  if (Operation *parentOp = (*this)->getParentOp();
+      parentOp && !satisfiesLLVMModule(parentOp))
+    return emitOpError("must appear at the module level");
+  for (Attribute flag : getFlags())
+    if (!isa<ModuleFlagAttr>(flag))
+      return emitOpError("expected a module flag attribute");
+  return success();
+}
+
 //===----------------------------------------------------------------------===//
 // InlineAsmOp
 //===----------------------------------------------------------------------===//

diff  --git a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
index 25599efe64322..833b19c1bece2 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
@@ -270,6 +270,15 @@ static void convertLinkerOptionsOp(ArrayAttr options,
   linkerMDNode->addOperand(listMDNode);
 }
 
+static void convertModuleFlagsOp(ArrayAttr flags, llvm::IRBuilderBase &builder,
+                                 LLVM::ModuleTranslation &moduleTranslation) {
+  llvm::Module *llvmModule = moduleTranslation.getLLVMModule();
+  for (auto flagAttr : flags.getAsRange<ModuleFlagAttr>())
+    llvmModule->addModuleFlag(
+        convertModFlagBehaviorToLLVM(flagAttr.getBehavior()),
+        flagAttr.getKey().getValue(), flagAttr.getValue());
+}
+
 static LogicalResult
 convertOperationImpl(Operation &opInst, llvm::IRBuilderBase &builder,
                      LLVM::ModuleTranslation &moduleTranslation) {

diff  --git a/mlir/lib/Target/LLVMIR/ModuleImport.cpp b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
index ab187cd05de75..663cad7d3cd24 100644
--- a/mlir/lib/Target/LLVMIR/ModuleImport.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
@@ -517,6 +517,33 @@ void ModuleImport::addDebugIntrinsic(llvm::CallInst *intrinsic) {
   debugIntrinsics.insert(intrinsic);
 }
 
+LogicalResult ModuleImport::convertModuleFlagsMetadata() {
+  SmallVector<llvm::Module::ModuleFlagEntry> llvmModuleFlags;
+  llvmModule->getModuleFlagsMetadata(llvmModuleFlags);
+
+  SmallVector<Attribute> moduleFlags;
+  for (const auto [behavior, key, val] : llvmModuleFlags) {
+    // Currently only supports most common: int constant values.
+    auto *constInt = llvm::mdconst::dyn_extract<llvm::ConstantInt>(val);
+    if (!constInt) {
+      emitWarning(mlirModule.getLoc())
+          << "unsupported module flag value: " << diagMD(val, llvmModule.get())
+          << ", only constant integer currently supported";
+      continue;
+    }
+
+    moduleFlags.push_back(builder.getAttr<ModuleFlagAttr>(
+        convertModFlagBehaviorFromLLVM(behavior),
+        builder.getStringAttr(key->getString()), constInt->getZExtValue()));
+  }
+
+  if (!moduleFlags.empty())
+    builder.create<LLVM::ModuleFlagsOp>(mlirModule.getLoc(),
+                                        builder.getArrayAttr(moduleFlags));
+
+  return success();
+}
+
 LogicalResult ModuleImport::convertLinkerOptionsMetadata() {
   for (const llvm::NamedMDNode &named : llvmModule->named_metadata()) {
     if (named.getName() != "llvm.linker.options")
@@ -596,6 +623,8 @@ LogicalResult ModuleImport::convertMetadata() {
   }
   if (failed(convertLinkerOptionsMetadata()))
     return failure();
+  if (failed(convertModuleFlagsMetadata()))
+    return failure();
   if (failed(convertIdentMetadata()))
     return failure();
   if (failed(convertCommandlineMetadata()))

diff  --git a/mlir/test/Dialect/LLVMIR/invalid.mlir b/mlir/test/Dialect/LLVMIR/invalid.mlir
index fcb6ae07f4912..6d3d3937b651c 100644
--- a/mlir/test/Dialect/LLVMIR/invalid.mlir
+++ b/mlir/test/Dialect/LLVMIR/invalid.mlir
@@ -1764,3 +1764,10 @@ llvm.mlir.alias external @y5 : i32 {
   llvm.return %0 : !llvm.ptr<4>
 }
 
+// -----
+
+module {
+  // expected-error at +2 {{expected integer value}}
+  // expected-error at +1 {{failed to parse ModuleFlagAttr parameter 'value' which is to be a `uint32_t`}}
+  llvm.module_flags [#llvm.mlir.module_flag<error, "wchar_size", "yolo">]
+}

diff  --git a/mlir/test/Dialect/LLVMIR/module-roundtrip.mlir b/mlir/test/Dialect/LLVMIR/module-roundtrip.mlir
new file mode 100644
index 0000000000000..d99a93c1e8565
--- /dev/null
+++ b/mlir/test/Dialect/LLVMIR/module-roundtrip.mlir
@@ -0,0 +1,16 @@
+// RUN: mlir-opt %s | mlir-opt | FileCheck %s
+
+module {
+  llvm.module_flags [#llvm.mlir.module_flag<error, "wchar_size", 4>,
+                     #llvm.mlir.module_flag<min, "PIC Level", 2>,
+                     #llvm.mlir.module_flag<max, "PIE Level", 2>,
+                     #llvm.mlir.module_flag<max, "uwtable", 2>,
+                     #llvm.mlir.module_flag<max, "frame-pointer", 1>]
+}
+
+// CHECK: llvm.module_flags [
+// CHECK-SAME: #llvm.mlir.module_flag<error, "wchar_size", 4>,
+// CHECK-SAME: #llvm.mlir.module_flag<min, "PIC Level", 2>,
+// CHECK-SAME: #llvm.mlir.module_flag<max, "PIE Level", 2>,
+// CHECK-SAME: #llvm.mlir.module_flag<max, "uwtable", 2>,
+// CHECK-SAME: #llvm.mlir.module_flag<max, "frame-pointer", 1>]

diff  --git a/mlir/test/Target/LLVMIR/Import/module-flags.ll b/mlir/test/Target/LLVMIR/Import/module-flags.ll
new file mode 100644
index 0000000000000..b7b686f94c7f4
--- /dev/null
+++ b/mlir/test/Target/LLVMIR/Import/module-flags.ll
@@ -0,0 +1,25 @@
+; RUN: mlir-translate -import-llvm -split-input-file -verify-diagnostics %s | FileCheck %s
+
+!llvm.module.flags = !{!0, !1, !2, !3, !4}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{i32 8, !"PIC Level", i32 2}
+!2 = !{i32 7, !"PIE Level", i32 2}
+!3 = !{i32 7, !"uwtable", i32 2}
+!4 = !{i32 7, !"frame-pointer", i32 1}
+
+; CHECK-LABEL: module attributes {{.*}} {
+; CHECK: llvm.module_flags [
+; CHECK-SAME: #llvm.mlir.module_flag<error, "wchar_size", 4>,
+; CHECK-SAME: #llvm.mlir.module_flag<min, "PIC Level", 2>,
+; CHECK-SAME: #llvm.mlir.module_flag<max, "PIE Level", 2>,
+; CHECK-SAME: #llvm.mlir.module_flag<max, "uwtable", 2>,
+; CHECK-SAME: #llvm.mlir.module_flag<max, "frame-pointer", 1>]
+; CHECK: }
+
+; // -----
+
+!llvm.module.flags = !{!0}
+
+; expected-warning at -5{{unsupported module flag value: !"yolo_more", only constant integer currently supported}}
+!0 = !{i32 1, !"yolo", !"yolo_more"}

diff  --git a/mlir/test/Target/LLVMIR/llvmir-invalid.mlir b/mlir/test/Target/LLVMIR/llvmir-invalid.mlir
index 15658ea606812..f755c4e508c22 100644
--- a/mlir/test/Target/LLVMIR/llvmir-invalid.mlir
+++ b/mlir/test/Target/LLVMIR/llvmir-invalid.mlir
@@ -348,6 +348,20 @@ llvm.func @foo() {
 
 // -----
 
+llvm.func @foo() {
+  // expected-error @below{{must appear at the module level}}
+  llvm.module_flags [#llvm.mlir.module_flag<error, "wchar_size", 4>]
+}
+
+// -----
+
+module attributes {} {
+  // expected-error @below{{expected a module flag attribute}}
+  llvm.module_flags [4 : i32]
+}
+
+// -----
+
 module @does_not_exist {
   // expected-error @below{{resource does not exist}}
   llvm.mlir.global internal constant @constant(dense_resource<test0> : tensor<4xf32>) : !llvm.array<4 x f32>

diff  --git a/mlir/test/Target/LLVMIR/llvmir.mlir b/mlir/test/Target/LLVMIR/llvmir.mlir
index f9473bf112387..ca06b26b03409 100644
--- a/mlir/test/Target/LLVMIR/llvmir.mlir
+++ b/mlir/test/Target/LLVMIR/llvmir.mlir
@@ -2763,3 +2763,22 @@ llvm.func @call_intrin_with_opbundle(%arg0 : !llvm.ptr) {
 // CHECK-NEXT:   call void @llvm.assume(i1 true) [ "align"(ptr %0, i32 16) ]
 // CHECK-NEXT:   ret void
 // CHECK-NEXT: }
+
+// -----
+
+module {
+  llvm.module_flags [#llvm.mlir.module_flag<error, "wchar_size", 4>,
+                     #llvm.mlir.module_flag<min, "PIC Level", 2>,
+                     #llvm.mlir.module_flag<max, "PIE Level", 2>,
+                     #llvm.mlir.module_flag<max, "uwtable", 2>,
+                     #llvm.mlir.module_flag<max, "frame-pointer", 1>]
+}
+
+// CHECK: !llvm.module.flags = !{![[#DBG:]], ![[#WCHAR:]], ![[#PIC:]], ![[#PIE:]], ![[#UWTABLE:]], ![[#FrameP:]]}
+
+// CHECK: ![[#DBG]] = !{i32 2, !"Debug Info Version", i32 3}
+// CHECK: ![[#WCHAR]] = !{i32 1, !"wchar_size", i32 4}
+// CHECK: ![[#PIC]] = !{i32 8, !"PIC Level", i32 2}
+// CHECK: ![[#PIE]] = !{i32 7, !"PIE Level", i32 2}
+// CHECK: ![[#UWTABLE]] = !{i32 7, !"uwtable", i32 2}
+// CHECK: ![[#FrameP]] = !{i32 7, !"frame-pointer", i32 1}

diff  --git a/mlir/test/mlir-translate/split-markers.mlir b/mlir/test/mlir-translate/split-markers.mlir
index ed576bcd85236..cf950eb12ec5a 100644
--- a/mlir/test/mlir-translate/split-markers.mlir
+++ b/mlir/test/mlir-translate/split-markers.mlir
@@ -21,6 +21,8 @@
 // CHECK-OUTPUT-NEXT: ModuleID
 
 // CHECK-ROUNDTRIP:       module {{.*}} {
+// FIXME: importer forces debug info version even without importing one.
+// CHECK-ROUNDTRIP-NEXT:    llvm.module_flag
 // CHECK-ROUNDTRIP-NEXT:  }
 // CHECK-ROUNDTRIP-EMPTY:
 // CHECK-ROUNDTRIP:       module


        


More information about the Mlir-commits mailing list