Skip to content

Commit bdb1553

Browse files
DavidTrubytru
authored andcommitted
[mlir] Add pass to add comdat to all linkonce functions (#65270)
This adds a new pass to add an Any comdat to each linkonce and linkonce_odr function in the LLVM dialect. These comdats are necessary on Windows to allow the default system linker to link binaries containing these functions. (cherry picked from commit a685715)
1 parent 3347c84 commit bdb1553

File tree

6 files changed

+122
-0
lines changed

6 files changed

+122
-0
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//===- AddComdats.h - Add comdats to linkonce functions -*- C++ -*---------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef MLIR_DIALECT_LLVMIR_TRANSFORMS_ADDCOMDATS_H
10+
#define MLIR_DIALECT_LLVMIR_TRANSFORMS_ADDCOMDATS_H
11+
12+
#include <memory>
13+
14+
namespace mlir {
15+
16+
class Pass;
17+
18+
namespace LLVM {
19+
20+
#define GEN_PASS_DECL_LLVMADDCOMDATS
21+
#include "mlir/Dialect/LLVMIR/Transforms/Passes.h.inc"
22+
23+
} // namespace LLVM
24+
} // namespace mlir
25+
26+
#endif // MLIR_DIALECT_LLVMIR_TRANSFORMS_ADDCOMDATS_H

mlir/include/mlir/Dialect/LLVMIR/Transforms/Passes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#ifndef MLIR_DIALECT_LLVMIR_TRANSFORMS_PASSES_H
1010
#define MLIR_DIALECT_LLVMIR_TRANSFORMS_PASSES_H
1111

12+
#include "mlir/Dialect/LLVMIR/Transforms/AddComdats.h"
1213
#include "mlir/Dialect/LLVMIR/Transforms/LegalizeForExport.h"
1314
#include "mlir/Dialect/LLVMIR/Transforms/OptimizeForNVVM.h"
1415
#include "mlir/Dialect/LLVMIR/Transforms/RequestCWrappers.h"

mlir/include/mlir/Dialect/LLVMIR/Transforms/Passes.td

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,19 @@
1111

1212
include "mlir/Pass/PassBase.td"
1313

14+
def LLVMAddComdats : Pass<"llvm-add-comdats", "::mlir::ModuleOp"> {
15+
let summary = "Add comdats to linkonce and linkonce_odr functions";
16+
let description = [{
17+
Add an any COMDAT to every linkonce and linkonce_odr function.
18+
This is necessary on Windows to link these functions as the system
19+
linker won't link weak symbols without a COMDAT. It also provides better
20+
behavior than standard weak symbols on ELF-based platforms.
21+
This pass will still add COMDATs on platforms that do not support them,
22+
for example macOS, so should only be run when the target platform supports
23+
COMDATs.
24+
}];
25+
}
26+
1427
def LLVMLegalizeForExport : Pass<"llvm-legalize-for-export"> {
1528
let summary = "Legalize LLVM dialect to be convertible to LLVM IR";
1629
let constructor = "::mlir::LLVM::createLegalizeForExportPass()";
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
//===- AddComdats.cpp - Add comdats to linkonce functions -----------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "mlir/Dialect/LLVMIR/Transforms/AddComdats.h"
10+
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
11+
#include "mlir/Pass/Pass.h"
12+
13+
namespace mlir {
14+
namespace LLVM {
15+
#define GEN_PASS_DEF_LLVMADDCOMDATS
16+
#include "mlir/Dialect/LLVMIR/Transforms/Passes.h.inc"
17+
} // namespace LLVM
18+
} // namespace mlir
19+
20+
using namespace mlir;
21+
22+
static void addComdat(LLVM::LLVMFuncOp &op, OpBuilder &builder,
23+
SymbolTable &symbolTable, ModuleOp &module) {
24+
const char *comdatName = "__llvm_comdat";
25+
mlir::LLVM::ComdatOp comdatOp =
26+
symbolTable.lookup<mlir::LLVM::ComdatOp>(comdatName);
27+
if (!comdatOp) {
28+
PatternRewriter::InsertionGuard guard(builder);
29+
builder.setInsertionPointToStart(module.getBody());
30+
comdatOp =
31+
builder.create<mlir::LLVM::ComdatOp>(module.getLoc(), comdatName);
32+
symbolTable.insert(comdatOp);
33+
}
34+
35+
PatternRewriter::InsertionGuard guard(builder);
36+
builder.setInsertionPointToStart(&comdatOp.getBody().back());
37+
auto selectorOp = builder.create<mlir::LLVM::ComdatSelectorOp>(
38+
comdatOp.getLoc(), op.getSymName(), mlir::LLVM::comdat::Comdat::Any);
39+
op.setComdatAttr(mlir::SymbolRefAttr::get(
40+
builder.getContext(), comdatName,
41+
mlir::FlatSymbolRefAttr::get(selectorOp.getSymNameAttr())));
42+
}
43+
44+
namespace {
45+
struct AddComdatsPass : public LLVM::impl::LLVMAddComdatsBase<AddComdatsPass> {
46+
void runOnOperation() override {
47+
OpBuilder builder{&getContext()};
48+
ModuleOp mod = getOperation();
49+
50+
std::unique_ptr<SymbolTable> symbolTable;
51+
auto getSymTab = [&]() -> SymbolTable & {
52+
if (!symbolTable)
53+
symbolTable = std::make_unique<SymbolTable>(mod);
54+
return *symbolTable;
55+
};
56+
for (auto op : mod.getBody()->getOps<LLVM::LLVMFuncOp>()) {
57+
if (op.getLinkage() == LLVM::Linkage::Linkonce ||
58+
op.getLinkage() == LLVM::Linkage::LinkonceODR) {
59+
addComdat(op, builder, getSymTab(), mod);
60+
}
61+
}
62+
}
63+
};
64+
} // namespace

mlir/lib/Dialect/LLVMIR/Transforms/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
add_mlir_dialect_library(MLIRLLVMIRTransforms
2+
AddComdats.cpp
23
DIScopeForLLVMFuncOp.cpp
34
LegalizeForExport.cpp
45
OptimizeForNVVM.cpp
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// RUN: mlir-opt -llvm-add-comdats -verify-diagnostics %s | FileCheck %s
2+
3+
// CHECK: llvm.comdat @__llvm_comdat {
4+
// CHECK-DAG: llvm.comdat_selector @linkonce any
5+
// CHECK-DAG: llvm.comdat_selector @linkonce_odr any
6+
// CHECK: }
7+
8+
// CHECK: llvm.func linkonce @linkonce() comdat(@__llvm_comdat::@linkonce)
9+
llvm.func linkonce @linkonce() {
10+
llvm.return
11+
}
12+
13+
// CHECK: llvm.func linkonce_odr @linkonce_odr() comdat(@__llvm_comdat::@linkonce_odr)
14+
llvm.func linkonce_odr @linkonce_odr() {
15+
llvm.return
16+
}
17+

0 commit comments

Comments
 (0)