[Mlir-commits] [mlir] [mlir] Add pass to add comdat to all linkonce functions (PR #65270)

David Truby llvmlistbot at llvm.org
Wed Sep 13 03:22:30 PDT 2023


https://github.com/DavidTruby updated https://github.com/llvm/llvm-project/pull/65270:

>From f7c55e215a3402e12a886c641a8b89ae154b63e5 Mon Sep 17 00:00:00 2001
From: David Truby <david at truby.dev>
Date: Mon, 4 Sep 2023 16:06:24 +0100
Subject: [PATCH] [mlir] Add pass to add comdat to all linkonce functions

This adds a pass operating on the LLVMIR dialect to add an Any comdat to each
linkonce and linkonce_odr function when lowering. These comdats are necessary on
Windows to allow the default system linker to link binaries containing these
functions.
---
 .../Dialect/LLVMIR/Transforms/AddComdats.h    | 26 ++++++++
 .../mlir/Dialect/LLVMIR/Transforms/Passes.h   |  1 +
 .../mlir/Dialect/LLVMIR/Transforms/Passes.td  | 13 ++++
 .../Dialect/LLVMIR/Transforms/AddComdats.cpp  | 64 +++++++++++++++++++
 .../Dialect/LLVMIR/Transforms/CMakeLists.txt  |  1 +
 .../Dialect/LLVMIR/add-linkonce-comdat.mlir   | 17 +++++
 6 files changed, 122 insertions(+)
 create mode 100644 mlir/include/mlir/Dialect/LLVMIR/Transforms/AddComdats.h
 create mode 100644 mlir/lib/Dialect/LLVMIR/Transforms/AddComdats.cpp
 create mode 100644 mlir/test/Dialect/LLVMIR/add-linkonce-comdat.mlir

diff --git a/mlir/include/mlir/Dialect/LLVMIR/Transforms/AddComdats.h b/mlir/include/mlir/Dialect/LLVMIR/Transforms/AddComdats.h
new file mode 100644
index 000000000000000..a7bc1a1d286deda
--- /dev/null
+++ b/mlir/include/mlir/Dialect/LLVMIR/Transforms/AddComdats.h
@@ -0,0 +1,26 @@
+//===- AddComdats.h - Add comdats to linkonce functions -*- C++ -*---------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_DIALECT_LLVMIR_TRANSFORMS_ADDCOMDATS_H
+#define MLIR_DIALECT_LLVMIR_TRANSFORMS_ADDCOMDATS_H
+
+#include <memory>
+
+namespace mlir {
+
+class Pass;
+
+namespace LLVM {
+
+#define GEN_PASS_DECL_LLVMADDCOMDATS
+#include "mlir/Dialect/LLVMIR/Transforms/Passes.h.inc"
+
+} // namespace LLVM
+} // namespace mlir
+
+#endif // MLIR_DIALECT_LLVMIR_TRANSFORMS_ADDCOMDATS_H
diff --git a/mlir/include/mlir/Dialect/LLVMIR/Transforms/Passes.h b/mlir/include/mlir/Dialect/LLVMIR/Transforms/Passes.h
index 7e61bd2419d6509..13e10b29c0743ca 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/Transforms/Passes.h
+++ b/mlir/include/mlir/Dialect/LLVMIR/Transforms/Passes.h
@@ -9,6 +9,7 @@
 #ifndef MLIR_DIALECT_LLVMIR_TRANSFORMS_PASSES_H
 #define MLIR_DIALECT_LLVMIR_TRANSFORMS_PASSES_H
 
+#include "mlir/Dialect/LLVMIR/Transforms/AddComdats.h"
 #include "mlir/Dialect/LLVMIR/Transforms/LegalizeForExport.h"
 #include "mlir/Dialect/LLVMIR/Transforms/OptimizeForNVVM.h"
 #include "mlir/Dialect/LLVMIR/Transforms/RequestCWrappers.h"
diff --git a/mlir/include/mlir/Dialect/LLVMIR/Transforms/Passes.td b/mlir/include/mlir/Dialect/LLVMIR/Transforms/Passes.td
index b7dfc8656fc1fd5..6ebbd08acfc431d 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/Transforms/Passes.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/Transforms/Passes.td
@@ -11,6 +11,19 @@
 
 include "mlir/Pass/PassBase.td"
 
+def LLVMAddComdats : Pass<"llvm-add-comdats", "::mlir::ModuleOp"> {
+  let summary = "Add comdats to linkonce and linkonce_odr functions";
+  let description = [{
+    Add an any COMDAT to every linkonce and linkonce_odr function.
+    This is necessary on Windows to link these functions as the system
+    linker won't link weak symbols without a COMDAT. It also provides better
+    behavior than standard weak symbols on ELF-based platforms.
+    This pass will still add COMDATs on platforms that do not support them,
+    for example macOS, so should only be run when the target platform supports
+    COMDATs.
+  }];
+}
+
 def LLVMLegalizeForExport : Pass<"llvm-legalize-for-export"> {
   let summary = "Legalize LLVM dialect to be convertible to LLVM IR";
   let constructor = "::mlir::LLVM::createLegalizeForExportPass()";
diff --git a/mlir/lib/Dialect/LLVMIR/Transforms/AddComdats.cpp b/mlir/lib/Dialect/LLVMIR/Transforms/AddComdats.cpp
new file mode 100644
index 000000000000000..6fbb0d24826d001
--- /dev/null
+++ b/mlir/lib/Dialect/LLVMIR/Transforms/AddComdats.cpp
@@ -0,0 +1,64 @@
+//===- AddComdats.cpp - Add comdats to linkonce functions -----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "mlir/Dialect/LLVMIR/Transforms/AddComdats.h"
+#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
+#include "mlir/Pass/Pass.h"
+
+namespace mlir {
+namespace LLVM {
+#define GEN_PASS_DEF_LLVMADDCOMDATS
+#include "mlir/Dialect/LLVMIR/Transforms/Passes.h.inc"
+} // namespace LLVM
+} // namespace mlir
+
+using namespace mlir;
+
+static void addComdat(LLVM::LLVMFuncOp &op, OpBuilder &builder,
+                      SymbolTable &symbolTable, ModuleOp &module) {
+  const char *comdatName = "__llvm_comdat";
+  mlir::LLVM::ComdatOp comdatOp =
+      symbolTable.lookup<mlir::LLVM::ComdatOp>(comdatName);
+  if (!comdatOp) {
+    PatternRewriter::InsertionGuard guard(builder);
+    builder.setInsertionPointToStart(module.getBody());
+    comdatOp =
+        builder.create<mlir::LLVM::ComdatOp>(module.getLoc(), comdatName);
+    symbolTable.insert(comdatOp);
+  }
+
+  PatternRewriter::InsertionGuard guard(builder);
+  builder.setInsertionPointToStart(&comdatOp.getBody().back());
+  auto selectorOp = builder.create<mlir::LLVM::ComdatSelectorOp>(
+      comdatOp.getLoc(), op.getSymName(), mlir::LLVM::comdat::Comdat::Any);
+  op.setComdatAttr(mlir::SymbolRefAttr::get(
+      builder.getContext(), comdatName,
+      mlir::FlatSymbolRefAttr::get(selectorOp.getSymNameAttr())));
+}
+
+namespace {
+struct AddComdatsPass : public LLVM::impl::LLVMAddComdatsBase<AddComdatsPass> {
+  void runOnOperation() override {
+    OpBuilder builder{&getContext()};
+    ModuleOp mod = getOperation();
+
+    std::unique_ptr<SymbolTable> symbolTable;
+    auto getSymTab = [&]() -> SymbolTable & {
+      if (!symbolTable)
+        symbolTable = std::make_unique<SymbolTable>(mod);
+      return *symbolTable;
+    };
+    for (auto op : mod.getBody()->getOps<LLVM::LLVMFuncOp>()) {
+      if (op.getLinkage() == LLVM::Linkage::Linkonce ||
+          op.getLinkage() == LLVM::Linkage::LinkonceODR) {
+        addComdat(op, builder, getSymTab(), mod);
+      }
+    }
+  }
+};
+} // namespace
diff --git a/mlir/lib/Dialect/LLVMIR/Transforms/CMakeLists.txt b/mlir/lib/Dialect/LLVMIR/Transforms/CMakeLists.txt
index fac33b29a511c81..47a2a251bf3e8b2 100644
--- a/mlir/lib/Dialect/LLVMIR/Transforms/CMakeLists.txt
+++ b/mlir/lib/Dialect/LLVMIR/Transforms/CMakeLists.txt
@@ -1,4 +1,5 @@
 add_mlir_dialect_library(MLIRLLVMIRTransforms
+  AddComdats.cpp
   DIScopeForLLVMFuncOp.cpp
   LegalizeForExport.cpp
   OptimizeForNVVM.cpp
diff --git a/mlir/test/Dialect/LLVMIR/add-linkonce-comdat.mlir b/mlir/test/Dialect/LLVMIR/add-linkonce-comdat.mlir
new file mode 100644
index 000000000000000..01ebd6650496a87
--- /dev/null
+++ b/mlir/test/Dialect/LLVMIR/add-linkonce-comdat.mlir
@@ -0,0 +1,17 @@
+// RUN: mlir-opt -llvm-add-comdats -verify-diagnostics %s | FileCheck %s
+
+// CHECK: llvm.comdat @__llvm_comdat {
+// CHECK-DAG: llvm.comdat_selector @linkonce any
+// CHECK-DAG: llvm.comdat_selector @linkonce_odr any
+// CHECK: }
+
+// CHECK: llvm.func linkonce @linkonce() comdat(@__llvm_comdat::@linkonce)
+llvm.func linkonce @linkonce() {
+  llvm.return
+}
+
+// CHECK: llvm.func linkonce_odr @linkonce_odr() comdat(@__llvm_comdat::@linkonce_odr)
+llvm.func linkonce_odr @linkonce_odr() {
+  llvm.return
+}
+



More information about the Mlir-commits mailing list