[Mlir-commits] [mlir] 9d4c1be - [mlir] Add support for LLVMIR comdat operation

David Truby llvmlistbot at llvm.org
Mon Jun 19 06:19:58 PDT 2023


Author: David Truby
Date: 2023-06-19T14:19:39+01:00
New Revision: 9d4c1be8b0793ee94e0906e4ff40d1ff325470de

URL: https://github.com/llvm/llvm-project/commit/9d4c1be8b0793ee94e0906e4ff40d1ff325470de
DIFF: https://github.com/llvm/llvm-project/commit/9d4c1be8b0793ee94e0906e4ff40d1ff325470de.diff

LOG: [mlir] Add support for LLVMIR comdat operation

The LLVM comdat operation specifies how to deduplicate globals with the
same key in two different object files. This is necessary on Windows
where e.g. two object files with linkonce globals will not link unless
a comdat for those globals is specified. It is also supported in the ELF
format.

Differential Revision: https://reviews.llvm.org/D150796

Added: 
    mlir/test/Dialect/LLVMIR/comdat.mlir
    mlir/test/Target/LLVMIR/Import/comdat.ll

Modified: 
    mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
    mlir/include/mlir/Dialect/LLVMIR/LLVMEnums.td
    mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
    mlir/include/mlir/Target/LLVMIR/ModuleImport.h
    mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
    mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
    mlir/lib/Target/LLVMIR/ModuleImport.cpp
    mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
    mlir/test/Dialect/LLVMIR/global.mlir
    mlir/test/Dialect/LLVMIR/invalid.mlir
    mlir/test/Target/LLVMIR/llvmir-invalid.mlir
    mlir/test/Target/LLVMIR/llvmir.mlir

Removed: 
    


################################################################################
diff  --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
index 05ee0832360dc..62eca517c828c 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
@@ -29,6 +29,15 @@ def CConvAttr : LLVM_Attr<"CConv", "cconv"> {
   let assemblyFormat = "`<` $CallingConv `>`";
 }
 
+//===----------------------------------------------------------------------===//
+// ComdatAttr
+//===----------------------------------------------------------------------===//
+
+def ComdatAttr : LLVM_Attr<"Comdat", "comdat"> {
+  let parameters = (ins "comdat::Comdat":$comdat);
+  let assemblyFormat = "$comdat";
+}
+
 //===----------------------------------------------------------------------===//
 // LinkageAttr
 //===----------------------------------------------------------------------===//

diff  --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMEnums.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMEnums.td
index 8d8494924e2a9..9eb012a971efb 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMEnums.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMEnums.td
@@ -589,6 +589,31 @@ def Linkage : DialectAttr<
           "::mlir::LLVM::LinkageAttr::get($_builder.getContext(), $0)";
 }
 
+
+//===----------------------------------------------------------------------===//
+// Comdat
+//===----------------------------------------------------------------------===//
+
+def ComdatAny
+    : LLVM_EnumAttrCase<"Any", "any", "Any", 0>;
+def ComdatExactMatch
+    : LLVM_EnumAttrCase<"ExactMatch", "exactmatch", "ExactMatch", 1>;
+def ComdatLargest
+    : LLVM_EnumAttrCase<"Largest", "largest", "Largest", 2>;
+def ComdatNoDeduplicate
+    : LLVM_EnumAttrCase<"NoDeduplicate", "nodeduplicate", "NoDeduplicate", 3>;
+def ComdatSameSize
+    : LLVM_EnumAttrCase<"SameSize", "samesize", "SameSize", 4>;
+
+def Comdat : LLVM_EnumAttr<
+  "Comdat",
+  "::llvm::Comdat::SelectionKind",
+  "LLVM Comdat Types",
+  [ComdatAny, ComdatExactMatch, ComdatLargest,
+   ComdatNoDeduplicate, ComdatSameSize]> {
+  let cppNamespace = "::mlir::LLVM::comdat";
+}
+
 //===----------------------------------------------------------------------===//
 // UnnamedAddr
 //===----------------------------------------------------------------------===//

diff  --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
index 53418cfec0735..b4081091a579d 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
@@ -1321,6 +1321,7 @@ def LLVM_GlobalOp : LLVM_Op<"mlir.global",
     DefaultValuedAttr<ConfinedAttr<I32Attr, [IntNonNegative]>, "0">:$addr_space,
     OptionalAttr<UnnamedAddr>:$unnamed_addr,
     OptionalAttr<StrAttr>:$section,
+    OptionalAttr<SymbolRefAttr>:$comdat,
     DefaultValuedAttr<Visibility, "mlir::LLVM::Visibility::Default">:$visibility_
   );
   let summary = "LLVM dialect global.";
@@ -1429,6 +1430,7 @@ def LLVM_GlobalOp : LLVM_Op<"mlir.global",
       CArg<"unsigned", "0">:$addrSpace,
       CArg<"bool", "false">:$dsoLocal,
       CArg<"bool", "false">:$thread_local_,
+      CArg<"SymbolRefAttr", "{}">:$comdat,
       CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs)>
   ];
 
@@ -1520,6 +1522,55 @@ def LLVM_GlobalDtorsOp : LLVM_Op<"mlir.global_dtors", [
   let hasVerifier = 1;
 }
 
+def LLVM_ComdatSelectorOp : LLVM_Op<"comdat_selector", [Symbol]> {
+  let arguments = (ins
+    SymbolNameAttr:$sym_name,
+    Comdat:$comdat
+  );
+
+  let summary = "LLVM dialect comdat selector declaration";
+
+  let description = [{
+    Provides access to object file COMDAT section/group functionality.
+
+    Examples:
+    ```mlir
+    llvm.comdat @__llvm_comdat {
+      llvm.comdat_selector @any any
+    }
+    llvm.mlir.global internal constant @has_any_comdat(1 : i64) comdat(@__llvm_comdat::@any) : i64
+    ```
+  }];
+  let assemblyFormat = "$sym_name $comdat attr-dict";
+}
+
+def LLVM_ComdatOp : LLVM_Op<"comdat", [NoTerminator, NoRegionArguments, SymbolTable, Symbol]> {
+  let arguments = (ins
+    SymbolNameAttr:$sym_name
+  );
+  let summary = "LLVM dialect comdat region";
+
+  let description = [{
+    Provides access to object file COMDAT section/group functionality.
+
+    Examples:
+    ```mlir
+    llvm.comdat @__llvm_comdat {
+      llvm.comdat_selector @any any
+    }
+    llvm.mlir.global internal constant @has_any_comdat(1 : i64) comdat(@__llvm_comdat::@any) : i64
+    ```
+  }];
+  let regions = (region SizedRegion<1>:$body);
+
+
+  let skipDefaultBuilders = 1;
+  let builders = [OpBuilder<(ins "StringRef":$symName)>];
+
+  let assemblyFormat = "$sym_name $body attr-dict";
+  let hasRegionVerifier = 1;
+}
+
 def LLVM_LLVMFuncOp : LLVM_Op<"func", [
     AutomaticAllocationScope, IsolatedFromAbove, FunctionOpInterface,
     CallableOpInterface

diff  --git a/mlir/include/mlir/Target/LLVMIR/ModuleImport.h b/mlir/include/mlir/Target/LLVMIR/ModuleImport.h
index ce622f7cabab3..b9d7463d34c63 100644
--- a/mlir/include/mlir/Target/LLVMIR/ModuleImport.h
+++ b/mlir/include/mlir/Target/LLVMIR/ModuleImport.h
@@ -56,6 +56,10 @@ class ModuleImport {
   /// Converts all functions of the LLVM module to MLIR functions.
   LogicalResult convertFunctions();
 
+  /// Converts all comdat selectors of the LLVM module to MLIR comdat
+  /// operations.
+  LogicalResult convertComdats();
+
   /// Converts all global variables of the LLVM module to MLIR global variables.
   LogicalResult convertGlobals();
 
@@ -284,6 +288,10 @@ class ModuleImport {
   /// metadata that converts to MLIR operations. Creates the global metadata
   /// operation on the first invocation.
   MetadataOp getGlobalMetadataOp();
+  /// Returns a global comdat operation that serves as a container for LLVM
+  /// comdat selectors. Creates the global comdat operation on the first
+  /// invocation.
+  ComdatOp getGlobalComdatOp();
   /// Performs conversion of LLVM TBAA metadata starting from
   /// `node`. On exit from this function all nodes reachable
   /// from `node` are converted, and tbaaMapping map is updated
@@ -312,6 +320,8 @@ class ModuleImport {
   Operation *globalInsertionOp = nullptr;
   /// Operation to insert metadata operations into.
   MetadataOp globalMetadataOp = nullptr;
+  /// Operation to insert comdat selector operations into.
+  ComdatOp globalComdatOp = nullptr;
   /// The current context.
   MLIRContext *context;
   /// The MLIR module being created.

diff  --git a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
index 949a0c705066f..960416d4913f7 100644
--- a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
+++ b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
@@ -274,6 +274,7 @@ class ModuleTranslation {
   LogicalResult convertOperation(Operation &op, llvm::IRBuilderBase &builder);
   LogicalResult convertFunctionSignatures();
   LogicalResult convertFunctions();
+  LogicalResult convertComdats();
   LogicalResult convertGlobals();
   LogicalResult convertOneFunction(LLVMFuncOp func);
 

diff  --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
index c44c60a0bc176..a97632c222287 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
@@ -1609,6 +1609,28 @@ AddressOfOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
   return success();
 }
 
+//===----------------------------------------------------------------------===//
+// Verifier for LLVM::ComdatOp.
+//===----------------------------------------------------------------------===//
+
+void ComdatOp::build(OpBuilder &builder, OperationState &result,
+                     StringRef symName) {
+  result.addAttribute(getSymNameAttrName(result.name),
+                      builder.getStringAttr(symName));
+  Region *body = result.addRegion();
+  body->emplaceBlock();
+}
+
+LogicalResult ComdatOp::verifyRegions() {
+  Region &body = getBody();
+  for (Operation &op : body.getOps())
+    if (!isa<ComdatSelectorOp>(op))
+      return op.emitError(
+          "only comdat selector symbols can appear in a comdat region");
+
+  return success();
+}
+
 //===----------------------------------------------------------------------===//
 // Builder, printer and verifier for LLVM::GlobalOp.
 //===----------------------------------------------------------------------===//
@@ -1616,7 +1638,7 @@ AddressOfOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
 void GlobalOp::build(OpBuilder &builder, OperationState &result, Type type,
                      bool isConstant, Linkage linkage, StringRef name,
                      Attribute value, uint64_t alignment, unsigned addrSpace,
-                     bool dsoLocal, bool threadLocal,
+                     bool dsoLocal, bool threadLocal, SymbolRefAttr comdat,
                      ArrayRef<NamedAttribute> attrs) {
   result.addAttribute(getSymNameAttrName(result.name),
                       builder.getStringAttr(name));
@@ -1632,6 +1654,8 @@ void GlobalOp::build(OpBuilder &builder, OperationState &result, Type type,
   if (threadLocal)
     result.addAttribute(getThreadLocal_AttrName(result.name),
                         builder.getUnitAttr());
+  if (comdat)
+    result.addAttribute(getComdatAttrName(result.name), comdat);
 
   // Only add an alignment attribute if the "alignment" input
   // is 
diff erent from 0. The value must also be a power of two, but
@@ -1668,6 +1692,9 @@ void GlobalOp::print(OpAsmPrinter &p) {
   if (auto value = getValueOrNull())
     p.printAttribute(value);
   p << ')';
+  if (auto comdat = getComdat())
+    p << " comdat(" << *comdat << ')';
+
   // Note that the alignment attribute is printed using the
   // default syntax here, even though it is an inherent attribute
   // (as defined in https://mlir.llvm.org/docs/LangRef/#attributes)
@@ -1676,7 +1703,7 @@ void GlobalOp::print(OpAsmPrinter &p) {
                            getGlobalTypeAttrName(), getConstantAttrName(),
                            getValueAttrName(), getLinkageAttrName(),
                            getUnnamedAddrAttrName(), getThreadLocal_AttrName(),
-                           getVisibility_AttrName()});
+                           getVisibility_AttrName(), getComdatAttrName()});
 
   // Print the trailing type unless it's a string global.
   if (llvm::dyn_cast_or_null<StringAttr>(getValueOrNull()))
@@ -1736,6 +1763,18 @@ static RetTy parseOptionalLLVMKeyword(OpAsmParser &parser,
   return static_cast<RetTy>(index);
 }
 
+static LogicalResult verifyComdat(Operation *op,
+                                  std::optional<SymbolRefAttr> attr) {
+  if (!attr)
+    return success();
+
+  auto *comdatSelector = SymbolTable::lookupNearestSymbolFrom(op, *attr);
+  if (!isa_and_nonnull<ComdatSelectorOp>(comdatSelector))
+    return op->emitError() << "expected comdat symbol";
+
+  return success();
+}
+
 // operation ::= `llvm.mlir.global` linkage? `constant`? `@` identifier
 //               `(` attribute? `)` align? attribute-list? (`:` type)? region?
 // align     ::= `align` `=` UINT64
@@ -1784,6 +1823,15 @@ ParseResult GlobalOp::parse(OpAsmParser &parser, OperationState &result) {
       return failure();
   }
 
+  if (succeeded(parser.parseOptionalKeyword("comdat"))) {
+    SymbolRefAttr comdat;
+    if (parser.parseLParen() || parser.parseAttribute(comdat) ||
+        parser.parseRParen())
+      return failure();
+
+    result.addAttribute(getComdatAttrName(result.name), comdat);
+  }
+
   SmallVector<Type, 1> types;
   if (parser.parseOptionalAttrDict(result.attributes) ||
       parser.parseOptionalColonTypeList(types))
@@ -1882,6 +1930,9 @@ LogicalResult GlobalOp::verify() {
     }
   }
 
+  if (failed(verifyComdat(*this, getComdat())))
+    return failure();
+
   std::optional<uint64_t> alignAttr = getAlignment();
   if (alignAttr.has_value()) {
     uint64_t value = alignAttr.value();

diff  --git a/mlir/lib/Target/LLVMIR/ModuleImport.cpp b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
index 5f9eb1835cd2d..fbb20bed6e8ff 100644
--- a/mlir/lib/Target/LLVMIR/ModuleImport.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
@@ -29,6 +29,7 @@
 #include "llvm/ADT/PostOrderIterator.h"
 #include "llvm/ADT/ScopeExit.h"
 #include "llvm/ADT/StringSet.h"
+#include "llvm/IR/Comdat.h"
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/InlineAsm.h"
 #include "llvm/IR/InstIterator.h"
@@ -81,6 +82,12 @@ static constexpr StringRef getGlobalMetadataOpName() {
   return "__llvm_global_metadata";
 }
 
+/// Returns the symbol name for the module-level comdat operation. It must not
+/// conflict with the user namespace.
+static constexpr StringRef getGlobalComdatOpName() {
+  return "__llvm_global_comdat";
+}
+
 /// Converts the sync scope identifier of `inst` to the string representation
 /// necessary to build an atomic LLVM dialect operation. Returns the empty
 /// string if the operation has either no sync scope or the default system-level
@@ -167,6 +174,16 @@ MetadataOp ModuleImport::getGlobalMetadataOp() {
              mlirModule.getLoc(), getGlobalMetadataOpName());
 }
 
+ComdatOp ModuleImport::getGlobalComdatOp() {
+  if (globalComdatOp)
+    return globalComdatOp;
+
+  OpBuilder::InsertionGuard guard(builder);
+  builder.setInsertionPointToStart(mlirModule.getBody());
+  return globalComdatOp = builder.create<ComdatOp>(mlirModule.getLoc(),
+                                                   getGlobalComdatOpName());
+}
+
 LogicalResult ModuleImport::processTBAAMetadata(const llvm::MDNode *node) {
   Location loc = mlirModule.getLoc();
   SmallVector<const llvm::MDNode *> workList;
@@ -540,6 +557,20 @@ LogicalResult ModuleImport::convertMetadata() {
   return success();
 }
 
+LogicalResult ModuleImport::convertComdats() {
+  ComdatOp comdat = getGlobalComdatOp();
+  OpBuilder::InsertionGuard guard(builder);
+  builder.setInsertionPointToEnd(&comdat.getBody().back());
+  for (auto &kv : llvmModule->getComdatSymbolTable()) {
+    StringRef name = kv.getKey();
+    llvm::Comdat::SelectionKind selector = kv.getValue().getSelectionKind();
+    builder.create<ComdatSelectorOp>(mlirModule.getLoc(), name,
+                                     convertComdatFromLLVM(selector));
+  }
+
+  return success();
+}
+
 LogicalResult ModuleImport::convertGlobals() {
   for (llvm::GlobalVariable &globalVar : llvmModule->globals()) {
     if (globalVar.getName() == getGlobalCtorsVarName() ||
@@ -857,6 +888,19 @@ LogicalResult ModuleImport::convertGlobal(llvm::GlobalVariable *globalVar) {
   globalOp.setVisibility_(
       convertVisibilityFromLLVM(globalVar->getVisibility()));
 
+  if (globalVar->hasComdat()) {
+    llvm::Comdat *llvmComdat = globalVar->getComdat();
+    ComdatOp comdat = getGlobalComdatOp();
+    if (ComdatSelectorOp selector = dyn_cast<ComdatSelectorOp>(
+            comdat.lookupSymbol(llvmComdat->getName()))) {
+      auto symbolRef =
+          SymbolRefAttr::get(builder.getContext(), getGlobalComdatOpName(),
+                             FlatSymbolRefAttr::get(selector.getSymNameAttr()));
+      globalOp.setComdatAttr(symbolRef);
+    } else
+      return failure();
+  }
+
   return success();
 }
 
@@ -1780,6 +1824,8 @@ mlir::translateLLVMIRToModule(std::unique_ptr<llvm::Module> llvmModule,
     return {};
   if (failed(moduleImport.convertMetadata()))
     return {};
+  if (failed(moduleImport.convertComdats()))
+    return {};
   if (failed(moduleImport.convertGlobals()))
     return {};
   if (failed(moduleImport.convertFunctions()))

diff  --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
index ee176a43c6ff9..9f072191804e0 100644
--- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
@@ -27,6 +27,7 @@
 #include "mlir/IR/BuiltinTypes.h"
 #include "mlir/IR/RegionGraphTraits.h"
 #include "mlir/Support/LLVM.h"
+#include "mlir/Support/LogicalResult.h"
 #include "mlir/Target/LLVMIR/LLVMTranslationInterface.h"
 #include "mlir/Target/LLVMIR/TypeToLLVM.h"
 
@@ -724,6 +725,14 @@ LogicalResult ModuleTranslation::convertGlobals() {
                              : llvm::GlobalValue::NotThreadLocal,
         addrSpace);
 
+    if (std::optional<mlir::SymbolRefAttr> comdat = op.getComdat()) {
+      StringRef name = comdat->getLeafReference().getValue();
+      if (!llvmModule->getComdatSymbolTable().contains(name))
+        return emitError(op.getLoc(), "global references non-existant comdat");
+      llvm::Comdat *llvmComdat = llvmModule->getOrInsertComdat(name);
+      var->setComdat(llvmComdat);
+    }
+
     if (op.getUnnamedAddr().has_value())
       var->setUnnamedAddr(convertUnnamedAddrToLLVM(*op.getUnnamedAddr()));
 
@@ -1037,6 +1046,23 @@ LogicalResult ModuleTranslation::convertFunctions() {
   return success();
 }
 
+LogicalResult ModuleTranslation::convertComdats() {
+  for (ComdatOp comdat : getModuleBody(mlirModule).getOps<ComdatOp>()) {
+    for (ComdatSelectorOp selector : comdat.getOps<ComdatSelectorOp>()) {
+      StringRef name = selector.getName();
+      llvm::Module *module = getLLVMModule();
+      if (module->getComdatSymbolTable().contains(name)) {
+        return emitError(selector.getLoc())
+               << "comdat selection symbols must be unique even in 
diff erent "
+                  "comdat regions";
+      }
+      llvm::Comdat *comdat = module->getOrInsertComdat(name);
+      comdat->setSelectionKind(convertComdatToLLVM(selector.getComdat()));
+    }
+  }
+  return success();
+}
+
 LogicalResult ModuleTranslation::createAccessGroupMetadata() {
   return loopAnnotationTranslation->createAccessGroupMetadata();
 }
@@ -1372,6 +1398,8 @@ mlir::translateModuleToLLVMIR(Operation *module, llvm::LLVMContext &llvmContext,
   ModuleTranslation translator(module, std::move(llvmModule));
   if (failed(translator.convertFunctionSignatures()))
     return nullptr;
+  if (failed(translator.convertComdats()))
+    return nullptr;
   if (failed(translator.convertGlobals()))
     return nullptr;
   if (failed(translator.createAccessGroupMetadata()))
@@ -1387,7 +1415,7 @@ mlir::translateModuleToLLVMIR(Operation *module, llvm::LLVMContext &llvmContext,
   llvm::IRBuilder<> llvmBuilder(llvmContext);
   for (Operation &o : getModuleBody(module).getOperations()) {
     if (!isa<LLVM::LLVMFuncOp, LLVM::GlobalOp, LLVM::GlobalCtorsOp,
-             LLVM::GlobalDtorsOp, LLVM::MetadataOp>(&o) &&
+             LLVM::GlobalDtorsOp, LLVM::MetadataOp, LLVM::ComdatOp>(&o) &&
         !o.hasTrait<OpTrait::IsTerminator>() &&
         failed(translator.convertOperation(o, llvmBuilder))) {
       return nullptr;

diff  --git a/mlir/test/Dialect/LLVMIR/comdat.mlir b/mlir/test/Dialect/LLVMIR/comdat.mlir
new file mode 100644
index 0000000000000..e8eaaa15160a0
--- /dev/null
+++ b/mlir/test/Dialect/LLVMIR/comdat.mlir
@@ -0,0 +1,16 @@
+// RUN: mlir-opt -split-input-file -verify-diagnostics %s | FileCheck %s
+
+// CHECK: llvm.comdat @__llvm_comdat
+llvm.comdat @__llvm_comdat {
+  // CHECK: llvm.comdat_selector @any_comdat any
+  llvm.comdat_selector @any_comdat any
+  // CHECK: llvm.comdat_selector @exactmatch_comdat exactmatch
+  llvm.comdat_selector @exactmatch_comdat exactmatch
+  // CHECK: llvm.comdat_selector @largest_comdat largest
+  llvm.comdat_selector @largest_comdat largest
+  // CHECK: llvm.comdat_selector @nodeduplicate_comdat nodeduplicate
+  llvm.comdat_selector @nodeduplicate_comdat nodeduplicate
+  // CHECK: llvm.comdat_selector @samesize_comdat samesize
+  llvm.comdat_selector @samesize_comdat samesize
+}
+

diff  --git a/mlir/test/Dialect/LLVMIR/global.mlir b/mlir/test/Dialect/LLVMIR/global.mlir
index 00b73f0549fab..c9a28e0a9eb93 100644
--- a/mlir/test/Dialect/LLVMIR/global.mlir
+++ b/mlir/test/Dialect/LLVMIR/global.mlir
@@ -64,6 +64,14 @@ llvm.mlir.global external @has_dso_local(42 : i64) {dso_local} : i64
 // CHECK: llvm.mlir.global external @has_addr_space(32 : i64) {addr_space = 3 : i32} : i64
 llvm.mlir.global external @has_addr_space(32 : i64) {addr_space = 3: i32} : i64
 
+// CHECK: llvm.comdat @__llvm_comdat
+llvm.comdat @__llvm_comdat {
+  // CHECK: llvm.comdat_selector @any any
+  llvm.comdat_selector @any any
+}
+// CHECK: llvm.mlir.global external @any() comdat(@__llvm_comdat::@any) {addr_space = 0 : i32} : i64
+llvm.mlir.global @any() comdat(@__llvm_comdat::@any) : i64
+
 // CHECK-LABEL: references
 func.func @references() {
   // CHECK: llvm.mlir.addressof @".string" : !llvm.ptr

diff  --git a/mlir/test/Dialect/LLVMIR/invalid.mlir b/mlir/test/Dialect/LLVMIR/invalid.mlir
index b88619b1e388d..db8b304182805 100644
--- a/mlir/test/Dialect/LLVMIR/invalid.mlir
+++ b/mlir/test/Dialect/LLVMIR/invalid.mlir
@@ -1423,3 +1423,16 @@ func.func @invalid_target_ext_constant() {
   // expected-error at +1 {{only zero-initializer allowed for target extension types}}
   %0 = llvm.mlir.constant(42 : index) : !llvm.target<"spirv.Event">
 }
+
+// -----
+
+llvm.comdat @__llvm_comdat {
+  // expected-error at +1 {{only comdat selector symbols can appear in a comdat region}}
+  llvm.return
+}
+
+// -----
+
+llvm.mlir.global @not_comdat(0 : i32) : i32
+// expected-error at +1 {{expected comdat symbol}}
+llvm.mlir.global @invalid_comdat_use(0 : i32) comdat(@not_comdat) : i32

diff  --git a/mlir/test/Target/LLVMIR/Import/comdat.ll b/mlir/test/Target/LLVMIR/Import/comdat.ll
new file mode 100644
index 0000000000000..8ef38eb8728a1
--- /dev/null
+++ b/mlir/test/Target/LLVMIR/Import/comdat.ll
@@ -0,0 +1,20 @@
+; RUN: mlir-translate -import-llvm %s | FileCheck %s
+
+; CHECK: llvm.mlir.global external @foo(42 : i64) comdat(@__llvm_global_comdat::@foo) {addr_space = 0 : i32} : i64
+ at foo = global i64 42, comdat
+; CHECK: llvm.mlir.global external @bar(42 : i64) comdat(@__llvm_global_comdat::@foo) {addr_space = 0 : i32} : i64
+ at bar = global i64 42, comdat($foo)
+
+; CHECK: llvm.comdat @__llvm_global_comdat {
+; CHECK-DAG: llvm.comdat_selector @foo any
+$foo = comdat any
+; CHECK-DAG: llvm.comdat_selector @exact exactmatch
+$exact = comdat exactmatch
+; CHECK-DAG: llvm.comdat_selector @largest largest
+$largest = comdat largest
+; CHECK-DAG: llvm.comdat_selector @nodedup nodeduplicate
+$nodedup = comdat nodeduplicate
+; CHECK-DAG: llvm.comdat_selector @same samesize
+$same = comdat samesize
+
+; CHECK: }

diff  --git a/mlir/test/Target/LLVMIR/llvmir-invalid.mlir b/mlir/test/Target/LLVMIR/llvmir-invalid.mlir
index 0522a8a14f525..2d6ccff2d436f 100644
--- a/mlir/test/Target/LLVMIR/llvmir-invalid.mlir
+++ b/mlir/test/Target/LLVMIR/llvmir-invalid.mlir
@@ -242,3 +242,14 @@ llvm.func @stepvector_intr_wrong_type() -> vector<7xf32> {
   %0 = llvm.intr.experimental.stepvector : vector<7xf32>
   llvm.return %0 : vector<7xf32>
 }
+
+// -----
+
+llvm.comdat @__llvm_comdat {
+  llvm.comdat_selector @foo any
+}
+
+llvm.comdat @__llvm_comdat_1 {
+  // expected-error @below{{comdat selection symbols must be unique even in 
diff erent comdat regions}}
+  llvm.comdat_selector @foo any
+}

diff  --git a/mlir/test/Target/LLVMIR/llvmir.mlir b/mlir/test/Target/LLVMIR/llvmir.mlir
index 5a56862817ac5..d23b6a7c289cc 100644
--- a/mlir/test/Target/LLVMIR/llvmir.mlir
+++ b/mlir/test/Target/LLVMIR/llvmir.mlir
@@ -1,5 +1,21 @@
 // RUN: mlir-translate -mlir-to-llvmir -split-input-file %s | FileCheck %s
 
+
+// Comdat sections
+llvm.comdat @__llvm_comdat {
+  // CHECK: $any = comdat any
+  llvm.comdat_selector @any any
+  // CHECK: $exactmatch = comdat exactmatch
+  llvm.comdat_selector @exactmatch exactmatch
+  // CHECK: $largest = comdat largest
+  llvm.comdat_selector @largest largest
+  // CHECK: $nodeduplicate = comdat nodeduplicate
+  llvm.comdat_selector @nodeduplicate nodeduplicate
+  // CHECK: $samesize = comdat samesize
+  llvm.comdat_selector @samesize samesize
+}
+
+
 // CHECK: @global_aligned32 = private global i64 42, align 32
 "llvm.mlir.global"() ({}) {sym_name = "global_aligned32", global_type = i64, value = 42 : i64, linkage = #llvm.linkage<private>, alignment = 32} : () -> ()
 
@@ -153,6 +169,20 @@ llvm.mlir.global thread_local @has_thr_local(42 : i64) : i64
 // CHECK: @sectionvar = internal constant [10 x i8] c"teststring", section ".mysection"
 llvm.mlir.global internal constant @sectionvar("teststring")  {section = ".mysection"}: !llvm.array<10 x i8>
 
+//
+// Comdat attribute.
+//
+// CHECK: @has_any_comdat = internal constant i64 1, comdat($any)
+llvm.mlir.global internal constant @has_any_comdat(1 : i64) comdat(@__llvm_comdat::@any) : i64
+// CHECK: @has_exactmatch_comdat = internal constant i64 1, comdat($exactmatch)
+llvm.mlir.global internal constant @has_exactmatch_comdat(1 : i64) comdat(@__llvm_comdat::@exactmatch) : i64
+// CHECK: @has_largest_comdat = internal constant i64 1, comdat($largest)
+llvm.mlir.global internal constant @has_largest_comdat(1 : i64) comdat(@__llvm_comdat::@largest) : i64
+// CHECK: @has_nodeduplicate_comdat = internal constant i64 1, comdat($nodeduplicate)
+llvm.mlir.global internal constant @has_nodeduplicate_comdat(1 : i64) comdat(@__llvm_comdat::@nodeduplicate) : i64
+// CHECK: @has_samesize_comdat = internal constant i64 1, comdat($samesize)
+llvm.mlir.global internal constant @has_samesize_comdat(1 : i64) comdat(@__llvm_comdat::@samesize) : i64
+
 //
 // Declarations of the allocation functions to be linked against. These are
 // inserted before other functions in the module.


        


More information about the Mlir-commits mailing list