Skip to content

Commit 5f476b8

Browse files
authored
[flang] Add comdats to functions with linkonce linkage (#66516)
This fixes a bug where functions generated by the MLIR Math dialect, for example ipowi, would fail to link with link.exe on Windows due to having linkonce linkage but no associated comdat. Adding the comdat on ELF also allows linkers to perform better garbage collection in the binary. Simply adding comdats to all functions with this linkage type should also cover future cases where linkonce or linkonce_odr functions might be necessary.
1 parent 00ecef9 commit 5f476b8

File tree

3 files changed

+57
-1
lines changed

3 files changed

+57
-1
lines changed

flang/lib/Optimizer/CodeGen/CodeGen.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "mlir/Conversion/ReconcileUnrealizedCasts/ReconcileUnrealizedCasts.h"
3535
#include "mlir/Conversion/VectorToLLVM/ConvertVectorToLLVM.h"
3636
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
37+
#include "mlir/Dialect/LLVMIR/Transforms/AddComdats.h"
3738
#include "mlir/Dialect/OpenACC/OpenACC.h"
3839
#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
3940
#include "mlir/IR/BuiltinTypes.h"
@@ -3861,6 +3862,14 @@ class FIRToLLVMLowering
38613862
std::move(pattern)))) {
38623863
signalPassFailure();
38633864
}
3865+
3866+
// Run pass to add comdats to functions that have weak linkage on relevant platforms
3867+
if (fir::getTargetTriple(mod).supportsCOMDAT()) {
3868+
mlir::OpPassManager comdatPM("builtin.module");
3869+
comdatPM.addPass(mlir::LLVM::createLLVMAddComdats());
3870+
if (mlir::failed(runPipeline(comdatPM, mod)))
3871+
return signalPassFailure();
3872+
}
38643873
}
38653874

38663875
private:

flang/test/Fir/comdat.fir

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
2+
// RUN: fir-opt %s --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %s --check-prefixes="CHECK-COMDAT"
3+
// RUN: fir-opt %s --fir-to-llvm-ir="target=x86_64-pc-windows-msvc" | FileCheck %s --check-prefixes="CHECK-COMDAT"
4+
// RUN: fir-opt %s --fir-to-llvm-ir="target=aarch64-apple-darwin" | FileCheck %s --check-prefixes="CHECK-NOCOMDAT"
5+
// RUN: fir-opt %s --fir-to-llvm-ir="target=powerpc64-ibm-aix" | FileCheck %s --check-prefixes="CHECK-NOCOMDAT"
6+
7+
// CHECK-COMDAT: llvm.func linkonce @fun_linkonce(%arg0: i32) -> i32 comdat(@__llvm_comdat::@fun_linkonce)
8+
// CHECK-NOCOMDAT: llvm.func linkonce @fun_linkonce(%arg0: i32) -> i32 {
9+
func.func @fun_linkonce(%arg0: i32) -> i32 attributes {llvm.linkage = #llvm.linkage<linkonce>} {
10+
return %arg0 : i32
11+
}
12+
13+
// CHECK-COMDAT: llvm.func linkonce_odr @fun_linkonce_odr(%arg0: i32) -> i32 comdat(@__llvm_comdat::@fun_linkonce_odr)
14+
// CHECK-NOCOMDAT: llvm.func linkonce_odr @fun_linkonce_odr(%arg0: i32) -> i32 {
15+
func.func @fun_linkonce_odr(%arg0: i32) -> i32 attributes {llvm.linkage = #llvm.linkage<linkonce_odr>} {
16+
return %arg0 : i32
17+
}
18+
19+
// CHECK-COMDAT: llvm.mlir.global linkonce constant @global_linkonce() comdat(@__llvm_comdat::@global_linkonce) {addr_space = 0 : i32} : i32
20+
// CHECK-NOCOMDAT: llvm.mlir.global linkonce constant @global_linkonce() {addr_space = 0 : i32} : i32 {
21+
fir.global linkonce @global_linkonce constant : i32 {
22+
%0 = arith.constant 0 : i32
23+
fir.has_value %0 : i32
24+
}
25+
26+
// CHECK-COMDAT: llvm.comdat @__llvm_comdat {
27+
// CHECK-COMDAT: llvm.comdat_selector @fun_linkonce_odr any
28+
// CHECK-COMDAT: llvm.comdat_selector @fun_linkonce any
29+
// CHECK-COMDAT: llvm.comdat_selector @global_linkonce any
30+
// CHECK-COMDAT: llvm.comdat_selector @global_linkonce_odr any
31+
32+
// CHECK-NOCOMDAT-NOT: llvm.comdat
33+
// CHECK-NOCOMDAT-NOT: llvm.comdat_selector
34+
35+
36+
// CHECK-COMDAT: llvm.mlir.global linkonce_odr constant @global_linkonce_odr() comdat(@__llvm_comdat::@global_linkonce_odr) {addr_space = 0 : i32} : i32
37+
// CHECK-NOCOMDAT: llvm.mlir.global linkonce_odr constant @global_linkonce_odr() {addr_space = 0 : i32} : i32 {
38+
fir.global linkonce_odr @global_linkonce_odr constant : i32 {
39+
%0 = arith.constant 0 : i32
40+
fir.has_value %0 : i32
41+
}

flang/test/Intrinsics/math-codegen.fir

+7-1
Original file line numberDiff line numberDiff line change
@@ -1467,9 +1467,15 @@ func.func private @llvm.powi.f64.i32(f64, i32) -> f64
14671467
func.func private @pow(f64, f64) -> f64
14681468

14691469
//--- exponentiation_integer.fir
1470-
// RUN: fir-opt %t/exponentiation_integer.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/exponentiation_integer.fir
1470+
// RUN: fir-opt %t/exponentiation_integer.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/exponentiation_integer.fir --check-prefixes="CHECK,CHECK-COMDAT"
1471+
// RUN: fir-opt %t/exponentiation_integer.fir --fir-to-llvm-ir="target=x86_64-pc-windows-msvc" | FileCheck %t/exponentiation_integer.fir --check-prefixes="CHECK,CHECK-COMDAT"
1472+
// RUN: fir-opt %t/exponentiation_integer.fir --fir-to-llvm-ir="target=aarch64-apple-darwin" | FileCheck %t/exponentiation_integer.fir --check-prefixes="CHECK,CHECK-NOCOMDAT"
1473+
// CHECK-COMDAT: llvm.comdat_selector @__mlir_math_ipowi_i32 any
1474+
// CHECK-NOCOMDAT-NOT: llvm.comdat_selector @__mlir_math_ipowi_i32 any
14711475
// CHECK: @_QPtest_int4
14721476
// CHECK: llvm.call @__mlir_math_ipowi_i32({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) : (i32, i32) -> i32
1477+
// CHECK-COMDAT: llvm.func linkonce_odr @__mlir_math_ipowi_i32(%arg0: i32, %arg1: i32) -> i32 comdat(@__llvm_comdat::@__mlir_math_ipowi_i32)
1478+
// CHECK-NOCOMDAT: llvm.func linkonce_odr @__mlir_math_ipowi_i32(%arg0: i32, %arg1: i32) -> i32
14731479

14741480
func.func @_QPtest_int4(%arg0: !fir.ref<i32> {fir.bindc_name = "x"}, %arg1: !fir.ref<i32> {fir.bindc_name = "y"}, %arg2: !fir.ref<i32> {fir.bindc_name = "z"}) {
14751481
%0 = fir.load %arg0 : !fir.ref<i32>

0 commit comments

Comments
 (0)