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 //===----------------------------------------------------------------------===//
21 // Helper functions
22 //===----------------------------------------------------------------------===//
23 
24 /// Mangle the name with gfortran convention.
25 std::string
26 mangleExternalName(const std::pair<fir::NameUniquer::NameKind,
27                                    fir::NameUniquer::DeconstructedName>
28                        result) {
29   if (result.first == fir::NameUniquer::NameKind::COMMON &&
30       result.second.name.empty())
31     return "__BLNK__";
32   return result.second.name + "_";
33 }
34 
35 //===----------------------------------------------------------------------===//
36 // Rewrite patterns
37 //===----------------------------------------------------------------------===//
38 
39 namespace {
40 
41 class MangleNameOnCallOp : public mlir::OpRewritePattern<fir::CallOp> {
42 public:
43   using OpRewritePattern::OpRewritePattern;
44 
45   mlir::LogicalResult
46   matchAndRewrite(fir::CallOp op,
47                   mlir::PatternRewriter &rewriter) const override {
48     rewriter.startRootUpdate(op);
49     auto callee = op.callee();
50     if (callee.hasValue()) {
51       auto result = fir::NameUniquer::deconstruct(
52           callee.getValue().getRootReference().getValue());
53       if (fir::NameUniquer::isExternalFacingUniquedName(result))
54         op.calleeAttr(
55             SymbolRefAttr::get(op.getContext(), mangleExternalName(result)));
56     }
57     rewriter.finalizeRootUpdate(op);
58     return success();
59   }
60 };
61 
62 struct MangleNameOnFuncOp : public mlir::OpRewritePattern<mlir::FuncOp> {
63 public:
64   using OpRewritePattern::OpRewritePattern;
65 
66   mlir::LogicalResult
67   matchAndRewrite(mlir::FuncOp op,
68                   mlir::PatternRewriter &rewriter) const override {
69     rewriter.startRootUpdate(op);
70     auto result = fir::NameUniquer::deconstruct(op.sym_name());
71     if (fir::NameUniquer::isExternalFacingUniquedName(result)) {
72       auto newName = mangleExternalName(result);
73       op.sym_nameAttr(rewriter.getStringAttr(newName));
74       SymbolTable::setSymbolName(op, newName);
75     }
76     rewriter.finalizeRootUpdate(op);
77     return success();
78   }
79 };
80 
81 struct MangleNameForCommonBlock : public mlir::OpRewritePattern<fir::GlobalOp> {
82 public:
83   using OpRewritePattern::OpRewritePattern;
84 
85   mlir::LogicalResult
86   matchAndRewrite(fir::GlobalOp op,
87                   mlir::PatternRewriter &rewriter) const override {
88     rewriter.startRootUpdate(op);
89     auto result = fir::NameUniquer::deconstruct(
90         op.symref().getRootReference().getValue());
91     if (fir::NameUniquer::isExternalFacingUniquedName(result)) {
92       auto newName = mangleExternalName(result);
93       op.symrefAttr(mlir::SymbolRefAttr::get(op.getContext(), newName));
94       SymbolTable::setSymbolName(op, newName);
95     }
96     rewriter.finalizeRootUpdate(op);
97     return success();
98   }
99 };
100 
101 struct MangleNameOnAddrOfOp : public mlir::OpRewritePattern<fir::AddrOfOp> {
102 public:
103   using OpRewritePattern::OpRewritePattern;
104 
105   mlir::LogicalResult
106   matchAndRewrite(fir::AddrOfOp op,
107                   mlir::PatternRewriter &rewriter) const override {
108     auto result = fir::NameUniquer::deconstruct(
109         op.symbol().getRootReference().getValue());
110     if (fir::NameUniquer::isExternalFacingUniquedName(result)) {
111       auto newName =
112           SymbolRefAttr::get(op.getContext(), mangleExternalName(result));
113       rewriter.replaceOpWithNewOp<fir::AddrOfOp>(op, op.resTy().getType(),
114                                                  newName);
115     }
116     return success();
117   }
118 };
119 
120 struct MangleNameOnEmboxProcOp
121     : public mlir::OpRewritePattern<fir::EmboxProcOp> {
122 public:
123   using OpRewritePattern::OpRewritePattern;
124 
125   mlir::LogicalResult
126   matchAndRewrite(fir::EmboxProcOp op,
127                   mlir::PatternRewriter &rewriter) const override {
128     rewriter.startRootUpdate(op);
129     auto result = fir::NameUniquer::deconstruct(
130         op.funcname().getRootReference().getValue());
131     if (fir::NameUniquer::isExternalFacingUniquedName(result))
132       op.funcnameAttr(
133           SymbolRefAttr::get(op.getContext(), mangleExternalName(result)));
134     rewriter.finalizeRootUpdate(op);
135     return success();
136   }
137 };
138 
139 class ExternalNameConversionPass
140     : public fir::ExternalNameConversionBase<ExternalNameConversionPass> {
141 public:
142   mlir::ModuleOp getModule() { return getOperation(); }
143   void runOnOperation() override;
144 };
145 } // namespace
146 
147 void ExternalNameConversionPass::runOnOperation() {
148   auto op = getOperation();
149   auto *context = &getContext();
150 
151   mlir::OwningRewritePatternList patterns(context);
152   patterns.insert<MangleNameOnCallOp, MangleNameOnCallOp, MangleNameOnFuncOp,
153                   MangleNameForCommonBlock, MangleNameOnAddrOfOp,
154                   MangleNameOnEmboxProcOp>(context);
155 
156   ConversionTarget target(*context);
157   target.addLegalDialect<fir::FIROpsDialect, LLVM::LLVMDialect,
158                          acc::OpenACCDialect, omp::OpenMPDialect>();
159 
160   target.addDynamicallyLegalOp<fir::CallOp>([](fir::CallOp op) {
161     if (op.callee().hasValue())
162       return !fir::NameUniquer::needExternalNameMangling(
163           op.callee().getValue().getRootReference().getValue());
164     return true;
165   });
166 
167   target.addDynamicallyLegalOp<mlir::FuncOp>([](mlir::FuncOp op) {
168     return !fir::NameUniquer::needExternalNameMangling(op.sym_name());
169   });
170 
171   target.addDynamicallyLegalOp<fir::GlobalOp>([](fir::GlobalOp op) {
172     return !fir::NameUniquer::needExternalNameMangling(
173         op.symref().getRootReference().getValue());
174   });
175 
176   target.addDynamicallyLegalOp<fir::AddrOfOp>([](fir::AddrOfOp op) {
177     return !fir::NameUniquer::needExternalNameMangling(
178         op.symbol().getRootReference().getValue());
179   });
180 
181   target.addDynamicallyLegalOp<fir::EmboxProcOp>([](fir::EmboxProcOp op) {
182     return !fir::NameUniquer::needExternalNameMangling(
183         op.funcname().getRootReference().getValue());
184   });
185 
186   if (failed(applyPartialConversion(op, target, std::move(patterns))))
187     signalPassFailure();
188 }
189 
190 std::unique_ptr<mlir::Pass> fir::createExternalNameConversionPass() {
191   return std::make_unique<ExternalNameConversionPass>();
192 }
193