@@ -76,12 +76,49 @@ void ExternalNameConversionPass::runOnOperation() {
7676 auto *context = &getContext ();
7777
7878 llvm::DenseMap<mlir::StringAttr, mlir::FlatSymbolRefAttr> remappings;
79+ mlir::SymbolTable symbolTable (op);
7980
8081 auto processFctOrGlobal = [&](mlir::Operation &funcOrGlobal) {
8182 auto symName = funcOrGlobal.getAttrOfType <mlir::StringAttr>(
8283 mlir::SymbolTable::getSymbolAttrName ());
8384 auto deconstructedName = fir::NameUniquer::deconstruct (symName);
8485 if (fir::NameUniquer::isExternalFacingUniquedName (deconstructedName)) {
86+ // Check if this is a private function that would conflict with a common
87+ // block and get its mangled name.
88+ if (auto funcOp = llvm::dyn_cast<mlir::func::FuncOp>(funcOrGlobal)) {
89+ if (funcOp.isPrivate ()) {
90+ std::string mangledName =
91+ mangleExternalName (deconstructedName, appendUnderscoreOpt);
92+ auto mod = funcOp->getParentOfType <mlir::ModuleOp>();
93+ bool hasConflictingCommonBlock = false ;
94+
95+ // Check if any existing global has the same mangled name.
96+ if (symbolTable.lookup <fir::GlobalOp>(mangledName))
97+ hasConflictingCommonBlock = true ;
98+
99+ // Skip externalization if the function has a conflicting common block
100+ // and is not directly called (i.e. procedure pointers or type
101+ // specifications)
102+ if (hasConflictingCommonBlock) {
103+ bool isDirectlyCalled = false ;
104+ std::optional<SymbolTable::UseRange> uses =
105+ funcOp.getSymbolUses (mod);
106+ if (uses.has_value ()) {
107+ for (auto use : *uses) {
108+ mlir::Operation *user = use.getUser ();
109+ if (mlir::isa<fir::CallOp>(user) ||
110+ mlir::isa<mlir::func::CallOp>(user)) {
111+ isDirectlyCalled = true ;
112+ break ;
113+ }
114+ }
115+ }
116+ if (!isDirectlyCalled)
117+ return ;
118+ }
119+ }
120+ }
121+
85122 auto newName = mangleExternalName (deconstructedName, appendUnderscoreOpt);
86123 auto newAttr = mlir::StringAttr::get (context, newName);
87124 mlir::SymbolTable::setSymbolName (&funcOrGlobal, newAttr);
0 commit comments