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

via flang-commits flang-commits at lists.llvm.org
Wed Apr 8 09:13:26 PDT 2026


Author: Jason Van Beusekom
Date: 2026-04-08T11:13:21-05:00
New Revision: 350d672827deaff38e81a859522e5a3bfb584ed3

URL: https://github.com/llvm/llvm-project/commit/350d672827deaff38e81a859522e5a3bfb584ed3
DIFF: https://github.com/llvm/llvm-project/commit/350d672827deaff38e81a859522e5a3bfb584ed3.diff

LOG: [Flang] mark safe external globals as dso_local (#189709)

Globals inside a Fortran module are not marked as dso_local,
which results in their alignment not being promoted.
This fix mimics some of the functionality found in
shouldAssumeDSOLocal in /clang/lib/CIR/CodeGen/CIRGenModule.cpp

Fixes #189069

Added: 
    flang/test/Fir/dso-local-macho.fir
    flang/test/Fir/dso-local.fir

Modified: 
    flang/include/flang/Optimizer/Dialect/Support/FIRContext.h
    flang/lib/Lower/Bridge.cpp
    flang/lib/Optimizer/CodeGen/CodeGen.cpp
    flang/lib/Optimizer/Dialect/Support/FIRContext.cpp
    flang/test/Lower/common-block.f90

Removed: 
    


################################################################################
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 63867fab57678..2642b08b7514c 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -7447,6 +7447,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 2d01463cf604d..5524d2ea08005 100644
--- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp
+++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
@@ -3391,6 +3391,18 @@ 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.isInitialized();
+    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..2dfc1e845b573 100644
--- a/flang/lib/Optimizer/Dialect/Support/FIRContext.cpp
+++ b/flang/lib/Optimizer/Dialect/Support/FIRContext.cpp
@@ -197,6 +197,40 @@ 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)) {
+    auto val = attr.getInt();
+    if (val >= llvm::Reloc::Static && val <= llvm::Reloc::ROPI_RWPI)
+      return static_cast<llvm::Reloc::Model>(val);
+  }
+  // Default to PIC_ as the conservative choice, ie don't set globals as
+  // dso_local This also matches the default in CodeGenOptions.def.
+  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>

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