//===- ExternalNameConversion.cpp -- convert name with external convention ===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "flang/Common/Fortran.h" #include "flang/Optimizer/Dialect/FIRDialect.h" #include "flang/Optimizer/Dialect/FIROps.h" #include "flang/Optimizer/Dialect/FIROpsSupport.h" #include "flang/Optimizer/Support/InternalNames.h" #include "flang/Optimizer/Transforms/Passes.h" #include "mlir/Dialect/LLVMIR/LLVMDialect.h" #include "mlir/Dialect/OpenACC/OpenACC.h" #include "mlir/Dialect/OpenMP/OpenMPDialect.h" #include "mlir/IR/Attributes.h" #include "mlir/IR/SymbolTable.h" #include "mlir/Pass/Pass.h" #include "mlir/Transforms/DialectConversion.h" namespace fir { #define GEN_PASS_DEF_EXTERNALNAMECONVERSION #include "flang/Optimizer/Transforms/Passes.h.inc" } // namespace fir using namespace mlir; //===----------------------------------------------------------------------===// // Helper functions //===----------------------------------------------------------------------===// /// Mangle the name with gfortran convention. std::string mangleExternalName(const std::pair result, bool appendUnderscore) { if (result.first == fir::NameUniquer::NameKind::COMMON && result.second.name.empty()) return Fortran::common::blankCommonObjectName; return Fortran::common::GetExternalAssemblyName(result.second.name, appendUnderscore); } //===----------------------------------------------------------------------===// // Rewrite patterns //===----------------------------------------------------------------------===// namespace { struct MangleNameOnFuncOp : public mlir::OpRewritePattern { public: using OpRewritePattern::OpRewritePattern; MangleNameOnFuncOp(mlir::MLIRContext *ctx, bool appendUnderscore) : mlir::OpRewritePattern(ctx), appendUnderscore(appendUnderscore) {} mlir::LogicalResult matchAndRewrite(mlir::func::FuncOp op, mlir::PatternRewriter &rewriter) const override { mlir::LogicalResult ret = success(); rewriter.startOpModification(op); llvm::StringRef oldName = op.getSymName(); auto result = fir::NameUniquer::deconstruct(oldName); if (fir::NameUniquer::isExternalFacingUniquedName(result)) { auto newSymbol = rewriter.getStringAttr(mangleExternalName(result, appendUnderscore)); // Try to update all SymbolRef's in the module that match the current op if (mlir::ModuleOp mod = op->getParentOfType()) ret = op.replaceAllSymbolUses(newSymbol, mod); op.setSymNameAttr(newSymbol); mlir::SymbolTable::setSymbolName(op, newSymbol); op->setAttr(fir::getInternalFuncNameAttrName(), mlir::StringAttr::get(op->getContext(), oldName)); } rewriter.finalizeOpModification(op); return ret; } private: bool appendUnderscore; }; struct MangleNameForCommonBlock : public mlir::OpRewritePattern { public: using OpRewritePattern::OpRewritePattern; MangleNameForCommonBlock(mlir::MLIRContext *ctx, bool appendUnderscore) : mlir::OpRewritePattern(ctx), appendUnderscore(appendUnderscore) {} mlir::LogicalResult matchAndRewrite(fir::GlobalOp op, mlir::PatternRewriter &rewriter) const override { rewriter.startOpModification(op); auto result = fir::NameUniquer::deconstruct( op.getSymref().getRootReference().getValue()); if (fir::NameUniquer::isExternalFacingUniquedName(result)) { auto newName = mangleExternalName(result, appendUnderscore); op.setSymrefAttr(mlir::SymbolRefAttr::get(op.getContext(), newName)); SymbolTable::setSymbolName(op, newName); } rewriter.finalizeOpModification(op); return success(); } private: bool appendUnderscore; }; struct MangleNameOnAddrOfOp : public mlir::OpRewritePattern { public: using OpRewritePattern::OpRewritePattern; MangleNameOnAddrOfOp(mlir::MLIRContext *ctx, bool appendUnderscore) : mlir::OpRewritePattern(ctx), appendUnderscore(appendUnderscore) {} mlir::LogicalResult matchAndRewrite(fir::AddrOfOp op, mlir::PatternRewriter &rewriter) const override { auto result = fir::NameUniquer::deconstruct( op.getSymbol().getRootReference().getValue()); if (fir::NameUniquer::isExternalFacingUniquedName(result)) { auto newName = SymbolRefAttr::get( op.getContext(), mangleExternalName(result, appendUnderscore)); rewriter.replaceOpWithNewOp(op, op.getResTy().getType(), newName); } return success(); } private: bool appendUnderscore; }; class ExternalNameConversionPass : public fir::impl::ExternalNameConversionBase { public: ExternalNameConversionPass(bool appendUnderscoring) : appendUnderscores(appendUnderscoring) {} ExternalNameConversionPass() { usePassOpt = true; } mlir::ModuleOp getModule() { return getOperation(); } void runOnOperation() override; private: bool appendUnderscores; bool usePassOpt = false; }; } // namespace void ExternalNameConversionPass::runOnOperation() { auto op = getOperation(); auto *context = &getContext(); appendUnderscores = (usePassOpt) ? appendUnderscoreOpt : appendUnderscores; mlir::RewritePatternSet patterns(context); patterns.insert(context, appendUnderscores); ConversionTarget target(*context); target.addLegalDialect(); target.addDynamicallyLegalOp([](mlir::func::FuncOp op) { return !fir::NameUniquer::needExternalNameMangling(op.getSymName()); }); target.addDynamicallyLegalOp([](fir::GlobalOp op) { return !fir::NameUniquer::needExternalNameMangling( op.getSymref().getRootReference().getValue()); }); target.addDynamicallyLegalOp([](fir::AddrOfOp op) { return !fir::NameUniquer::needExternalNameMangling( op.getSymbol().getRootReference().getValue()); }); if (failed(applyPartialConversion(op, target, std::move(patterns)))) signalPassFailure(); } std::unique_ptr fir::createExternalNameConversionPass() { return std::make_unique(); } std::unique_ptr fir::createExternalNameConversionPass(bool appendUnderscoring) { return std::make_unique(appendUnderscoring); }