[flang-commits] [flang] [Flang] Fix symbol name clash when dummy procedure name is the same as common-block-name (PR #155508)
Carlos Seo via flang-commits
flang-commits at lists.llvm.org
Thu Aug 28 10:56:34 PDT 2025
https://github.com/ceseo updated https://github.com/llvm/llvm-project/pull/155508
>From d71046ab248c0864b9b30ad112b12d50162f0b93 Mon Sep 17 00:00:00 2001
From: Carlos Seo <carlos.seo at linaro.org>
Date: Tue, 26 Aug 2025 21:08:24 +0000
Subject: [PATCH 1/4] [Flang] Fix symbol name clash when dummy procedure name
is the same as common-block-name
Dummy procedures in interface blocks are not external procedures that need to
be linked. Do not externalize those.
Fixes #122822
---
.../Transforms/ExternalNameConversion.cpp | 42 +++++++++++++++++++
.../dummy-procedure-common-block-name.f | 12 ++++++
2 files changed, 54 insertions(+)
create mode 100644 flang/test/Transforms/dummy-procedure-common-block-name.f
diff --git a/flang/lib/Optimizer/Transforms/ExternalNameConversion.cpp b/flang/lib/Optimizer/Transforms/ExternalNameConversion.cpp
index 2fcff87fdc393..b6198e5d424b4 100644
--- a/flang/lib/Optimizer/Transforms/ExternalNameConversion.cpp
+++ b/flang/lib/Optimizer/Transforms/ExternalNameConversion.cpp
@@ -82,6 +82,48 @@ void ExternalNameConversionPass::runOnOperation() {
mlir::SymbolTable::getSymbolAttrName());
auto deconstructedName = fir::NameUniquer::deconstruct(symName);
if (fir::NameUniquer::isExternalFacingUniquedName(deconstructedName)) {
+ // Check if this is a private function that would conflict with a common
+ // block and get its mangled name.
+ if (auto funcOp = llvm::dyn_cast<mlir::func::FuncOp>(funcOrGlobal)) {
+ if (funcOp.isPrivate()) {
+ auto mangledName =
+ mangleExternalName(deconstructedName, appendUnderscoreOpt);
+ auto mod = funcOp->getParentOfType<mlir::ModuleOp>();
+ bool hasConflictingCommonBlock = false;
+
+ // Check if any existing global has the same mangled name.
+ mod.walk([&](fir::GlobalOp globalOp) {
+ auto globalSymName = globalOp.getSymName();
+ if (globalSymName == mangledName) {
+ hasConflictingCommonBlock = true;
+ return mlir::WalkResult::interrupt();
+ }
+ return mlir::WalkResult::advance();
+ });
+
+ // Skip externalization if the function has a conflicting common block
+ // and is not directly called (i.e. procedure pointers or type
+ // specifications)
+ if (hasConflictingCommonBlock) {
+ bool isDirectlyCalled = false;
+ auto uses = funcOp.getSymbolUses(mod);
+ if (uses.has_value()) {
+ for (auto use : *uses) {
+ auto *user = use.getUser();
+ if (mlir::isa<fir::CallOp>(user) ||
+ mlir::isa<mlir::func::CallOp>(user)) {
+ isDirectlyCalled = true;
+ break;
+ }
+ }
+ }
+ if (!isDirectlyCalled) {
+ return;
+ }
+ }
+ }
+ }
+
auto newName = mangleExternalName(deconstructedName, appendUnderscoreOpt);
auto newAttr = mlir::StringAttr::get(context, newName);
mlir::SymbolTable::setSymbolName(&funcOrGlobal, newAttr);
diff --git a/flang/test/Transforms/dummy-procedure-common-block-name.f b/flang/test/Transforms/dummy-procedure-common-block-name.f
new file mode 100644
index 0000000000000..2c3ebb965fe49
--- /dev/null
+++ b/flang/test/Transforms/dummy-procedure-common-block-name.f
@@ -0,0 +1,12 @@
+! RUN: bbc -emit-fir %s -o - | FileCheck %s
+
+subroutine ss5()
+common /com_dummy1/ x
+! CHECK: fir.global common @com_dummy1_
+interface
+ subroutine com_dummy1()
+ end subroutine
+end interface
+! CHECK: func.func private @_QPcom_dummy1()
+print *,fun_sub(com_dummy1)
+end
>From e02f15eff0277873a433c50cfabb704508420af1 Mon Sep 17 00:00:00 2001
From: Carlos Seo <carlos.seo at linaro.org>
Date: Tue, 26 Aug 2025 22:52:51 +0000
Subject: [PATCH 2/4] Address Valentin's comments
---
.../Optimizer/Transforms/ExternalNameConversion.cpp | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/flang/lib/Optimizer/Transforms/ExternalNameConversion.cpp b/flang/lib/Optimizer/Transforms/ExternalNameConversion.cpp
index b6198e5d424b4..77e8e46483559 100644
--- a/flang/lib/Optimizer/Transforms/ExternalNameConversion.cpp
+++ b/flang/lib/Optimizer/Transforms/ExternalNameConversion.cpp
@@ -86,7 +86,7 @@ void ExternalNameConversionPass::runOnOperation() {
// block and get its mangled name.
if (auto funcOp = llvm::dyn_cast<mlir::func::FuncOp>(funcOrGlobal)) {
if (funcOp.isPrivate()) {
- auto mangledName =
+ std::string mangledName =
mangleExternalName(deconstructedName, appendUnderscoreOpt);
auto mod = funcOp->getParentOfType<mlir::ModuleOp>();
bool hasConflictingCommonBlock = false;
@@ -106,10 +106,11 @@ void ExternalNameConversionPass::runOnOperation() {
// specifications)
if (hasConflictingCommonBlock) {
bool isDirectlyCalled = false;
- auto uses = funcOp.getSymbolUses(mod);
+ std::optional<SymbolTable::UseRange> uses =
+ funcOp.getSymbolUses(mod);
if (uses.has_value()) {
for (auto use : *uses) {
- auto *user = use.getUser();
+ mlir::Operation *user = use.getUser();
if (mlir::isa<fir::CallOp>(user) ||
mlir::isa<mlir::func::CallOp>(user)) {
isDirectlyCalled = true;
@@ -117,9 +118,8 @@ void ExternalNameConversionPass::runOnOperation() {
}
}
}
- if (!isDirectlyCalled) {
+ if (!isDirectlyCalled)
return;
- }
}
}
}
>From f5740dfe0aa04832cd1a03cea2bb4244ee2483cc Mon Sep 17 00:00:00 2001
From: Carlos Seo <carlos.seo at linaro.org>
Date: Wed, 27 Aug 2025 14:49:17 +0000
Subject: [PATCH 3/4] Use a SymbolTable instead of traversing every op in the
module
---
.../Optimizer/Transforms/ExternalNameConversion.cpp | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/flang/lib/Optimizer/Transforms/ExternalNameConversion.cpp b/flang/lib/Optimizer/Transforms/ExternalNameConversion.cpp
index 77e8e46483559..fa739e203ae1d 100644
--- a/flang/lib/Optimizer/Transforms/ExternalNameConversion.cpp
+++ b/flang/lib/Optimizer/Transforms/ExternalNameConversion.cpp
@@ -92,14 +92,12 @@ void ExternalNameConversionPass::runOnOperation() {
bool hasConflictingCommonBlock = false;
// Check if any existing global has the same mangled name.
- mod.walk([&](fir::GlobalOp globalOp) {
- auto globalSymName = globalOp.getSymName();
- if (globalSymName == mangledName) {
+ mlir::SymbolTable symbolTable(mod);
+ if (auto conflictingOp = symbolTable.lookup(mangledName)) {
+ if (mlir::isa<fir::GlobalOp>(conflictingOp)) {
hasConflictingCommonBlock = true;
- return mlir::WalkResult::interrupt();
}
- return mlir::WalkResult::advance();
- });
+ }
// Skip externalization if the function has a conflicting common block
// and is not directly called (i.e. procedure pointers or type
>From 9c599f40fef3cc971b31605872a4483ee9c48966 Mon Sep 17 00:00:00 2001
From: Carlos Seo <carlos.seo at linaro.org>
Date: Thu, 28 Aug 2025 17:55:49 +0000
Subject: [PATCH 4/4] Move SymbolTable creation to the pass level
---
flang/lib/Optimizer/Transforms/ExternalNameConversion.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/flang/lib/Optimizer/Transforms/ExternalNameConversion.cpp b/flang/lib/Optimizer/Transforms/ExternalNameConversion.cpp
index fa739e203ae1d..1b27555123d2e 100644
--- a/flang/lib/Optimizer/Transforms/ExternalNameConversion.cpp
+++ b/flang/lib/Optimizer/Transforms/ExternalNameConversion.cpp
@@ -76,6 +76,7 @@ void ExternalNameConversionPass::runOnOperation() {
auto *context = &getContext();
llvm::DenseMap<mlir::StringAttr, mlir::FlatSymbolRefAttr> remappings;
+ mlir::SymbolTable symbolTable(op);
auto processFctOrGlobal = [&](mlir::Operation &funcOrGlobal) {
auto symName = funcOrGlobal.getAttrOfType<mlir::StringAttr>(
@@ -92,7 +93,6 @@ void ExternalNameConversionPass::runOnOperation() {
bool hasConflictingCommonBlock = false;
// Check if any existing global has the same mangled name.
- mlir::SymbolTable symbolTable(mod);
if (auto conflictingOp = symbolTable.lookup(mangledName)) {
if (mlir::isa<fir::GlobalOp>(conflictingOp)) {
hasConflictingCommonBlock = true;
More information about the flang-commits
mailing list