[flang-commits] [flang] [Flang] mark safe external globals as dso_local (PR #189709)

Jason Van Beusekom via flang-commits flang-commits at lists.llvm.org
Tue Mar 31 13:48:50 PDT 2026


https://github.com/Jason-Van-Beusekom updated https://github.com/llvm/llvm-project/pull/189709

>From 1507a035a3306ad2d0bbb3d961b1c7ee3c0ac1e8 Mon Sep 17 00:00:00 2001
From: Jason Van Beusekom <jason.van-beusekom at hpe.com>
Date: Tue, 31 Mar 2026 11:16:16 -0500
Subject: [PATCH 1/3] [Flang] mark safe external globals as dso_local

---
 .../Optimizer/Dialect/Support/FIRContext.h    | 13 +++
 flang/lib/Lower/Bridge.cpp                    |  2 +
 flang/lib/Optimizer/CodeGen/CodeGen.cpp       | 13 +++
 .../Optimizer/Dialect/Support/FIRContext.cpp  | 29 +++++++
 flang/test/Fir/dso-local-macho.fir            | 17 ++++
 flang/test/Fir/dso-local.fir                  | 84 +++++++++++++++++++
 6 files changed, 158 insertions(+)
 create mode 100644 flang/test/Fir/dso-local-macho.fir
 create mode 100644 flang/test/Fir/dso-local.fir

diff --git a/flang/include/flang/Optimizer/Dialect/Support/FIRContext.h b/flang/include/flang/Optimizer/Dialect/Support/FIRContext.h
index c0c0b744206cd..3fea111941551 100644
--- a/flang/include/flang/Optimizer/Dialect/Support/FIRContext.h
+++ b/flang/include/flang/Optimizer/Dialect/Support/FIRContext.h
@@ -19,6 +19,7 @@
 
 #include "mlir/Dialect/LLVMIR/LLVMAttrs.h"
 #include "llvm/ADT/StringRef.h"
+#include "llvm/Support/CodeGen.h"
 #include "llvm/TargetParser/Triple.h"
 
 namespace mlir {
@@ -102,6 +103,18 @@ void setCommandline(mlir::ModuleOp mod, llvm::StringRef cmdLine);
 /// Get the command line used in this invocation.
 llvm::StringRef getCommandline(mlir::ModuleOp mod);
 
+/// Set the relocation model for the module.
+void setRelocationModel(mlir::ModuleOp mod, llvm::Reloc::Model rm);
+
+/// Get the relocation model from the Module (defaults to PIC).
+llvm::Reloc::Model getRelocationModel(mlir::ModuleOp mod);
+
+/// Set whether the module is compiled as a position-independent executable.
+void setIsPIE(mlir::ModuleOp mod, bool value);
+
+/// Get whether the module is compiled as a position-independent executable.
+bool getIsPIE(mlir::ModuleOp mod);
+
 /// Helper for determining the target from the host, etc. Tools may use this
 /// function to provide a consistent interpretation of the `--target=<string>`
 /// command-line option.
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index 7459f814a0d4d..0f2049d41efee 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -7411,6 +7411,8 @@ Fortran::lower::LoweringBridge::LoweringBridge(
   fir::setTargetFeatures(*module, targetMachine.getTargetFeatureString());
   fir::support::setMLIRDataLayout(*module, targetMachine.createDataLayout());
   fir::setIdent(*module, Fortran::common::getFlangFullVersion());
+  fir::setRelocationModel(*module, cgOpts.getRelocationModel());
+  fir::setIsPIE(*module, cgOpts.IsPIE);
   if (cgOpts.RecordCommandLine)
     fir::setCommandline(*module, *cgOpts.RecordCommandLine);
 }
diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
index 25eb6194efa99..849662f9ae35a 100644
--- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp
+++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
@@ -3391,6 +3391,19 @@ struct GlobalOpConversion : public fir::FIROpConversion<fir::GlobalOp> {
       g.setAlignment(*global.getAlignment());
 
     auto module = global->getParentOfType<mlir::ModuleOp>();
+
+    // Mimic shouldAssumeDSOLocal in clang, marking external definitions as dso_local if
+    // it is defined and is ELF, and either static or PIE.
+    bool isDefinition =
+        !global.getRegion().empty() || global.getInitVal().has_value();
+    if (isDefinition && linkage == mlir::LLVM::Linkage::External &&
+        fir::getTargetTriple(module).isOSBinFormatELF()) {
+      llvm::Reloc::Model rm = fir::getRelocationModel(module);
+      bool isPIE = fir::getIsPIE(module);
+      if (rm == llvm::Reloc::Static || isPIE)
+        g.setDsoLocal(true);
+    }
+
     auto gpuMod = global->getParentOfType<mlir::gpu::GPUModuleOp>();
     // Add comdat if necessary
     if (fir::getTargetTriple(module).supportsCOMDAT() &&
diff --git a/flang/lib/Optimizer/Dialect/Support/FIRContext.cpp b/flang/lib/Optimizer/Dialect/Support/FIRContext.cpp
index c2e0afe122b4e..63170dd03f3db 100644
--- a/flang/lib/Optimizer/Dialect/Support/FIRContext.cpp
+++ b/flang/lib/Optimizer/Dialect/Support/FIRContext.cpp
@@ -197,6 +197,35 @@ llvm::StringRef fir::getCommandline(mlir::ModuleOp mod) {
   return {};
 }
 
+static constexpr const char *relocationModelName = "fir.relocation_model";
+
+void fir::setRelocationModel(mlir::ModuleOp mod, llvm::Reloc::Model rm) {
+  auto *ctx = mod.getContext();
+  mod->setAttr(relocationModelName,
+               mlir::IntegerAttr::get(mlir::IntegerType::get(ctx, 32),
+                                      static_cast<unsigned>(rm)));
+}
+
+llvm::Reloc::Model fir::getRelocationModel(mlir::ModuleOp mod) {
+  if (auto attr = mod->getAttrOfType<mlir::IntegerAttr>(relocationModelName))
+    return static_cast<llvm::Reloc::Model>(attr.getInt());
+  return llvm::Reloc::PIC_;
+}
+
+static constexpr const char *isPIEName = "fir.is_pie";
+
+void fir::setIsPIE(mlir::ModuleOp mod, bool value) {
+  if (value) {
+    auto *ctx = mod.getContext();
+    mod->setAttr(isPIEName, mlir::UnitAttr::get(ctx));
+  } else {
+    if (mod->hasAttr(isPIEName))
+      mod->removeAttr(isPIEName);
+  }
+}
+
+bool fir::getIsPIE(mlir::ModuleOp mod) { return mod->hasAttr(isPIEName); }
+
 std::string fir::determineTargetTriple(llvm::StringRef triple) {
   // Treat "" or "default" as stand-ins for the default machine.
   if (triple.empty() || triple == "default")
diff --git a/flang/test/Fir/dso-local-macho.fir b/flang/test/Fir/dso-local-macho.fir
new file mode 100644
index 0000000000000..d34f9fb6f5f67
--- /dev/null
+++ b/flang/test/Fir/dso-local-macho.fir
@@ -0,0 +1,17 @@
+// Test that dso_local is not set on non-ELF targets, even with static
+// relocation model. Uses a separate file because fir-to-llvm-ir target=
+// overrides the module triple for all splits.
+
+// RUN: fir-opt --fir-to-llvm-ir="target=x86_64-apple-darwin" %s | FileCheck %s
+
+module attributes {fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "",
+    fir.relocation_model = 0 : i32,
+    llvm.target_triple = "x86_64-apple-darwin"} {
+  fir.global @macho_def : i32 {
+    %0 = fir.zero_bits i32
+    fir.has_value %0 : i32
+  }
+}
+// CHECK: llvm.mlir.global external @macho_def()
+// CHECK-NOT: dso_local
+// CHECK-SAME: : i32
diff --git a/flang/test/Fir/dso-local.fir b/flang/test/Fir/dso-local.fir
new file mode 100644
index 0000000000000..ab3566184403f
--- /dev/null
+++ b/flang/test/Fir/dso-local.fir
@@ -0,0 +1,84 @@
+// RUN: fir-opt --split-input-file --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" %s | FileCheck %s
+
+// Static relocation model, ELF, external definition: dso_local
+module attributes {fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "",
+    fir.relocation_model = 0 : i32,
+    llvm.target_triple = "x86_64-unknown-linux-gnu"} {
+  fir.global @static_def : i32 {
+    %0 = fir.zero_bits i32
+    fir.has_value %0 : i32
+  }
+}
+// CHECK: llvm.mlir.global external @static_def()
+// CHECK-SAME: dso_local
+
+// -----
+
+// PIC + PIE, ELF, external definition: dso_local
+module attributes {fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "",
+    fir.relocation_model = 1 : i32, fir.is_pie,
+    llvm.target_triple = "x86_64-unknown-linux-gnu"} {
+  fir.global @pie_def : i32 {
+    %0 = fir.zero_bits i32
+    fir.has_value %0 : i32
+  }
+}
+// CHECK: llvm.mlir.global external @pie_def()
+// CHECK-SAME: dso_local
+
+// -----
+
+// PIC without PIE, ELF, external definition: no dso_local
+module attributes {fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "",
+    fir.relocation_model = 1 : i32,
+    llvm.target_triple = "x86_64-unknown-linux-gnu"} {
+  fir.global @pic_def : i32 {
+    %0 = fir.zero_bits i32
+    fir.has_value %0 : i32
+  }
+}
+// CHECK: llvm.mlir.global external @pic_def()
+// CHECK-NOT: dso_local
+// CHECK-SAME: : i32
+
+// -----
+
+// Static relocation model, ELF, declaration only: no dso_local
+module attributes {fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "",
+    fir.relocation_model = 0 : i32,
+    llvm.target_triple = "x86_64-unknown-linux-gnu"} {
+  fir.global @decl_only : i32
+}
+// CHECK: llvm.mlir.global external @decl_only()
+// CHECK-NOT: dso_local
+// CHECK-SAME: : i32
+
+// -----
+
+// Static relocation model, ELF, internal linkage: no dso_local from this path
+module attributes {fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "",
+    fir.relocation_model = 0 : i32,
+    llvm.target_triple = "x86_64-unknown-linux-gnu"} {
+  fir.global internal @internal_var : i32 {
+    %0 = fir.zero_bits i32
+    fir.has_value %0 : i32
+  }
+}
+// CHECK: llvm.mlir.global internal @internal_var()
+// CHECK-NOT: dso_local
+// CHECK-SAME: : i32
+
+// -----
+
+// Static relocation model, ELF, linkonce: no dso_local from this path
+module attributes {fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "",
+    fir.relocation_model = 0 : i32,
+    llvm.target_triple = "x86_64-unknown-linux-gnu"} {
+  fir.global linkonce @linkonce_str constant : !fir.char<1,5> {
+    %0 = fir.string_lit "hello"(5) : !fir.char<1,5>
+    fir.has_value %0 : !fir.char<1,5>
+  }
+}
+// CHECK: llvm.mlir.global linkonce constant @linkonce_str()
+// CHECK-NOT: dso_local
+// CHECK-SAME: : !llvm.array<5 x i8>

>From 3fdde968c368107fdd5eb0138e97863125e377f5 Mon Sep 17 00:00:00 2001
From: Jason Van Beusekom <jason.van-beusekom at hpe.com>
Date: Tue, 31 Mar 2026 12:14:00 -0500
Subject: [PATCH 2/3] format

---
 flang/lib/Optimizer/CodeGen/CodeGen.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
index 849662f9ae35a..d76fac8fbbb5b 100644
--- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp
+++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
@@ -3392,8 +3392,8 @@ struct GlobalOpConversion : public fir::FIROpConversion<fir::GlobalOp> {
 
     auto module = global->getParentOfType<mlir::ModuleOp>();
 
-    // Mimic shouldAssumeDSOLocal in clang, marking external definitions as dso_local if
-    // it is defined and is ELF, and either static or PIE.
+    // Mimic shouldAssumeDSOLocal in clang, marking external definitions as
+    // dso_local if it is defined and is ELF, and either static or PIE.
     bool isDefinition =
         !global.getRegion().empty() || global.getInitVal().has_value();
     if (isDefinition && linkage == mlir::LLVM::Linkage::External &&

>From 59648fec3b3f131ded1f064faccbfd8ae8fd3085 Mon Sep 17 00:00:00 2001
From: Jason-Van-Beusekom <jason.van-beusekom at hpe.com>
Date: Tue, 31 Mar 2026 15:46:33 -0500
Subject: [PATCH 3/3] update on feedback

---
 flang/lib/Optimizer/Dialect/Support/FIRContext.cpp | 7 +++++--
 flang/test/Lower/common-block.f90                  | 4 ++--
 2 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/flang/lib/Optimizer/Dialect/Support/FIRContext.cpp b/flang/lib/Optimizer/Dialect/Support/FIRContext.cpp
index 63170dd03f3db..6b47d7c1a0d66 100644
--- a/flang/lib/Optimizer/Dialect/Support/FIRContext.cpp
+++ b/flang/lib/Optimizer/Dialect/Support/FIRContext.cpp
@@ -207,8 +207,11 @@ void fir::setRelocationModel(mlir::ModuleOp mod, llvm::Reloc::Model rm) {
 }
 
 llvm::Reloc::Model fir::getRelocationModel(mlir::ModuleOp mod) {
-  if (auto attr = mod->getAttrOfType<mlir::IntegerAttr>(relocationModelName))
-    return static_cast<llvm::Reloc::Model>(attr.getInt());
+  if (auto attr = mod->getAttrOfType<mlir::IntegerAttr>(relocationModelName)) {
+    auto val = attr.getInt();
+    if (val >= llvm::Reloc::Static && val <= llvm::Reloc::ROPI_RWPI)
+      return static_cast<llvm::Reloc::Model>(val);
+  }
   return llvm::Reloc::PIC_;
 }
 
diff --git a/flang/test/Lower/common-block.f90 b/flang/test/Lower/common-block.f90
index 5e32c119bcf21..45810d3d00e29 100644
--- a/flang/test/Lower/common-block.f90
+++ b/flang/test/Lower/common-block.f90
@@ -6,9 +6,9 @@
 ! CHECK: @co1_ = common global [16 x i8] zeroinitializer, align 16
 ! CHECK: @rien_ = common global [1 x i8] zeroinitializer
 ! CHECK: @with_empty_equiv_ = common global [8 x i8] zeroinitializer
-! CHECK: @x_ = global { float, float } { float 1.0{{.*}}, float 2.0{{.*}} }
+! CHECK: @x_ = {{(dso_local )?}}global { float, float } { float 1.0{{.*}}, float 2.0{{.*}} }
 ! CHECK: @y_ = common global [12 x i8] zeroinitializer
-! CHECK: @z_ = global { i32, [4 x i8], float } { i32 42, [4 x i8] zeroinitializer, float 3.000000e+00 }
+! CHECK: @z_ = {{(dso_local )?}}global { i32, [4 x i8], float } { i32 42, [4 x i8] zeroinitializer, float 3.000000e+00 }
 
 ! CHECK-LABEL: _QPs0
 subroutine s0



More information about the flang-commits mailing list