1 //===- ExternalNameConversion.cpp -- convert name with external convention ===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "PassDetail.h"
10 #include "flang/Optimizer/Dialect/FIROps.h"
11 #include "flang/Optimizer/Support/InternalNames.h"
12 #include "flang/Optimizer/Transforms/Passes.h"
13 #include "mlir/Dialect/LLVMIR/LLVMDialect.h"
14 #include "mlir/Dialect/OpenACC/OpenACC.h"
15 #include "mlir/Dialect/OpenMP/OpenMPDialect.h"
16 #include "mlir/IR/SymbolTable.h"
17 #include "mlir/Pass/Pass.h"
18 #include "mlir/Transforms/DialectConversion.h"
19 
20 using namespace mlir;
21 
22 //===----------------------------------------------------------------------===//
23 // Helper functions
24 //===----------------------------------------------------------------------===//
25 
26 /// Mangle the name with gfortran convention.
27 std::string
mangleExternalName(const std::pair<fir::NameUniquer::NameKind,fir::NameUniquer::DeconstructedName> result)28 mangleExternalName(const std::pair<fir::NameUniquer::NameKind,
29                                    fir::NameUniquer::DeconstructedName>
30                        result) {
31   if (result.first == fir::NameUniquer::NameKind::COMMON &&
32       result.second.name.empty())
33     return "__BLNK__";
34   return result.second.name + "_";
35 }
36 
37 //===----------------------------------------------------------------------===//
38 // Rewrite patterns
39 //===----------------------------------------------------------------------===//
40 
41 namespace {
42 
43 class MangleNameOnCallOp : public mlir::OpRewritePattern<fir::CallOp> {
44 public:
45   using OpRewritePattern::OpRewritePattern;
46 
47   mlir::LogicalResult
matchAndRewrite(fir::CallOp op,mlir::PatternRewriter & rewriter) const48   matchAndRewrite(fir::CallOp op,
49                   mlir::PatternRewriter &rewriter) const override {
50     rewriter.startRootUpdate(op);
51     auto callee = op.getCallee();
52     if (callee) {
53       auto result =
54           fir::NameUniquer::deconstruct(callee->getRootReference().getValue());
55       if (fir::NameUniquer::isExternalFacingUniquedName(result))
56         op.setCalleeAttr(
57             SymbolRefAttr::get(op.getContext(), mangleExternalName(result)));
58     }
59     rewriter.finalizeRootUpdate(op);
60     return success();
61   }
62 };
63 
64 struct MangleNameOnFuncOp : public mlir::OpRewritePattern<mlir::func::FuncOp> {
65 public:
66   using OpRewritePattern::OpRewritePattern;
67 
68   mlir::LogicalResult
matchAndRewrite__anon849139e70111::MangleNameOnFuncOp69   matchAndRewrite(mlir::func::FuncOp op,
70                   mlir::PatternRewriter &rewriter) const override {
71     rewriter.startRootUpdate(op);
72     auto result = fir::NameUniquer::deconstruct(op.getSymName());
73     if (fir::NameUniquer::isExternalFacingUniquedName(result))
74       op.setSymNameAttr(rewriter.getStringAttr(mangleExternalName(result)));
75     rewriter.finalizeRootUpdate(op);
76     return success();
77   }
78 };
79 
80 struct MangleNameForCommonBlock : public mlir::OpRewritePattern<fir::GlobalOp> {
81 public:
82   using OpRewritePattern::OpRewritePattern;
83 
84   mlir::LogicalResult
matchAndRewrite__anon849139e70111::MangleNameForCommonBlock85   matchAndRewrite(fir::GlobalOp op,
86                   mlir::PatternRewriter &rewriter) const override {
87     rewriter.startRootUpdate(op);
88     auto result = fir::NameUniquer::deconstruct(
89         op.getSymref().getRootReference().getValue());
90     if (fir::NameUniquer::isExternalFacingUniquedName(result)) {
91       auto newName = mangleExternalName(result);
92       op.setSymrefAttr(mlir::SymbolRefAttr::get(op.getContext(), newName));
93       SymbolTable::setSymbolName(op, newName);
94     }
95     rewriter.finalizeRootUpdate(op);
96     return success();
97   }
98 };
99 
100 struct MangleNameOnAddrOfOp : public mlir::OpRewritePattern<fir::AddrOfOp> {
101 public:
102   using OpRewritePattern::OpRewritePattern;
103 
104   mlir::LogicalResult
matchAndRewrite__anon849139e70111::MangleNameOnAddrOfOp105   matchAndRewrite(fir::AddrOfOp op,
106                   mlir::PatternRewriter &rewriter) const override {
107     auto result = fir::NameUniquer::deconstruct(
108         op.getSymbol().getRootReference().getValue());
109     if (fir::NameUniquer::isExternalFacingUniquedName(result)) {
110       auto newName =
111           SymbolRefAttr::get(op.getContext(), mangleExternalName(result));
112       rewriter.replaceOpWithNewOp<fir::AddrOfOp>(op, op.getResTy().getType(),
113                                                  newName);
114     }
115     return success();
116   }
117 };
118 
119 class ExternalNameConversionPass
120     : public fir::ExternalNameConversionBase<ExternalNameConversionPass> {
121 public:
getModule()122   mlir::ModuleOp getModule() { return getOperation(); }
123   void runOnOperation() override;
124 };
125 } // namespace
126 
runOnOperation()127 void ExternalNameConversionPass::runOnOperation() {
128   auto op = getOperation();
129   auto *context = &getContext();
130 
131   mlir::RewritePatternSet patterns(context);
132   patterns.insert<MangleNameOnCallOp, MangleNameOnCallOp, MangleNameOnFuncOp,
133                   MangleNameForCommonBlock, MangleNameOnAddrOfOp>(context);
134 
135   ConversionTarget target(*context);
136   target.addLegalDialect<fir::FIROpsDialect, LLVM::LLVMDialect,
137                          acc::OpenACCDialect, omp::OpenMPDialect>();
138 
139   target.addDynamicallyLegalOp<fir::CallOp>([](fir::CallOp op) {
140     if (op.getCallee())
141       return !fir::NameUniquer::needExternalNameMangling(
142           op.getCallee()->getRootReference().getValue());
143     return true;
144   });
145 
146   target.addDynamicallyLegalOp<mlir::func::FuncOp>([](mlir::func::FuncOp op) {
147     return !fir::NameUniquer::needExternalNameMangling(op.getSymName());
148   });
149 
150   target.addDynamicallyLegalOp<fir::GlobalOp>([](fir::GlobalOp op) {
151     return !fir::NameUniquer::needExternalNameMangling(
152         op.getSymref().getRootReference().getValue());
153   });
154 
155   target.addDynamicallyLegalOp<fir::AddrOfOp>([](fir::AddrOfOp op) {
156     return !fir::NameUniquer::needExternalNameMangling(
157         op.getSymbol().getRootReference().getValue());
158   });
159 
160   if (failed(applyPartialConversion(op, target, std::move(patterns))))
161     signalPassFailure();
162 }
163 
createExternalNameConversionPass()164 std::unique_ptr<mlir::Pass> fir::createExternalNameConversionPass() {
165   return std::make_unique<ExternalNameConversionPass>();
166 }
167