Skip to content

Commit bb1ab87

Browse files
authored
[flang][fir] Add external name mangling pass
1 parent 0efc2ba commit bb1ab87

File tree

9 files changed

+297
-0
lines changed

9 files changed

+297
-0
lines changed

flang/include/flang/Optimizer/Support/InternalNames.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,13 @@ struct NameUniquer {
125125
static std::pair<NameKind, DeconstructedName>
126126
deconstruct(llvm::StringRef uniquedName);
127127

128+
/// Check if the name is an external facing name.
129+
static bool isExternalFacingUniquedName(
130+
const std::pair<NameKind, DeconstructedName> &deconstructResult);
131+
132+
/// Check whether the name should be re-mangle with external ABI convention.
133+
static bool needExternalNameMangling(llvm::StringRef uniquedName);
134+
128135
private:
129136
static std::string intAsString(std::int64_t i);
130137
static std::string doKind(std::int64_t kind);

flang/include/flang/Optimizer/Transforms/Passes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ std::unique_ptr<mlir::Pass> createFirToCfgPass();
3535
std::unique_ptr<mlir::Pass> createArrayValueCopyPass();
3636
std::unique_ptr<mlir::Pass> createAbstractResultOptPass();
3737
std::unique_ptr<mlir::Pass> createCharacterConversionPass();
38+
std::unique_ptr<mlir::Pass> createExternalNameConversionPass();
3839

3940
/// A pass to convert the FIR dialect from "Mem-SSA" form to "Reg-SSA" form.
4041
/// This pass is a port of LLVM's mem2reg pass, but modified for the FIR dialect

flang/include/flang/Optimizer/Transforms/Passes.td

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,4 +179,16 @@ def CharacterConversion : Pass<"character-conversion"> {
179179
];
180180
}
181181

182+
def ExternalNameConversion : Pass<"external-name-interop", "mlir::ModuleOp"> {
183+
let summary = "Convert name for external interoperability";
184+
let description = [{
185+
Demangle FIR internal name and mangle them for external interoperability.
186+
}];
187+
let constructor = "::fir::createExternalNameConversionPass()";
188+
let dependentDialects = [
189+
"fir::FIROpsDialect", "mlir::LLVM::LLVMDialect",
190+
"mlir::acc::OpenACCDialect", "mlir::omp::OpenMPDialect"
191+
];
192+
}
193+
182194
#endif // FORTRAN_OPTIMIZER_TRANSFORMS_FIR_PASSES

flang/lib/Optimizer/Support/InternalNames.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,3 +298,18 @@ fir::NameUniquer::deconstruct(llvm::StringRef uniq) {
298298
}
299299
return {NameKind::NOT_UNIQUED, DeconstructedName(uniq)};
300300
}
301+
302+
bool fir::NameUniquer::isExternalFacingUniquedName(
303+
const std::pair<fir::NameUniquer::NameKind,
304+
fir::NameUniquer::DeconstructedName> &deconstructResult) {
305+
return (deconstructResult.first == NameKind::PROCEDURE ||
306+
deconstructResult.first == NameKind::COMMON) &&
307+
deconstructResult.second.modules.empty() &&
308+
!deconstructResult.second.host;
309+
}
310+
311+
bool fir::NameUniquer::needExternalNameMangling(llvm::StringRef uniquedName) {
312+
auto result = fir::NameUniquer::deconstruct(uniquedName);
313+
return result.first != fir::NameUniquer::NameKind::NOT_UNIQUED &&
314+
fir::NameUniquer::isExternalFacingUniquedName(result);
315+
}

flang/lib/Optimizer/Transforms/CMakeLists.txt

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

flang/lib/Optimizer/Transforms/PassDetail.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111

1212
#include "flang/Optimizer/Dialect/FIRDialect.h"
1313
#include "mlir/Dialect/Affine/IR/AffineOps.h"
14+
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
15+
#include "mlir/Dialect/OpenACC/OpenACC.h"
16+
#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
1417
#include "mlir/Dialect/SCF/SCF.h"
1518
#include "mlir/Dialect/StandardOps/IR/Ops.h"
1619
#include "mlir/Pass/Pass.h"

flang/test/Fir/external-mangling.fir

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// RUN: fir-opt --external-name-interop %s | FileCheck %s
2+
// RUN: tco --external-name-interop %s | FileCheck %s
3+
// RUN: tco --external-name-interop %s | tco | FileCheck %s --check-prefix=LLVMIR
4+
5+
func @_QPfoo() {
6+
%c0 = constant 0 : index
7+
%0 = fir.address_of(@_QBa) : !fir.ref<!fir.array<4xi8>>
8+
%1 = fir.convert %0 : (!fir.ref<!fir.array<4xi8>>) -> !fir.ref<!fir.array<?xi8>>
9+
%2 = fir.coordinate_of %1, %c0 : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
10+
%3 = fir.convert %2 : (!fir.ref<i8>) -> !fir.ref<i32>
11+
%4 = fir.address_of(@_QB) : !fir.ref<!fir.array<4xi8>>
12+
%5 = fir.convert %4 : (!fir.ref<!fir.array<4xi8>>) -> !fir.ref<!fir.array<?xi8>>
13+
%6 = fir.coordinate_of %5, %c0 : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
14+
%7 = fir.convert %6 : (!fir.ref<i8>) -> !fir.ref<f32>
15+
fir.call @_QPbar(%3) : (!fir.ref<i32>) -> ()
16+
fir.call @_QPbar2(%7) : (!fir.ref<f32>) -> ()
17+
%e6 = fir.alloca tuple<i32,f64>
18+
%8 = fir.emboxproc @_QPfoo_impl, %e6 : ((!fir.box<!fir.type<derived3{f:f32}>>) -> (), !fir.ref<tuple<i32,f64>>) -> !fir.boxproc<(!fir.box<!fir.type<derived3{f:f32}>>) -> ()>
19+
return
20+
}
21+
fir.global common @_QBa(dense<0> : vector<4xi8>) : !fir.array<4xi8>
22+
fir.global common @_QB(dense<0> : vector<4xi8>) : !fir.array<4xi8>
23+
func private @_QPbar(!fir.ref<i32>)
24+
func private @_QPbar2(!fir.ref<f32>)
25+
26+
// CHECK: func @foo_
27+
// CHECK: %{{.*}} = fir.address_of(@a_) : !fir.ref<!fir.array<4xi8>>
28+
// CHECK: %{{.*}} = fir.address_of(@__BLNK__) : !fir.ref<!fir.array<4xi8>>
29+
// CHECK: fir.call @bar_
30+
// CHECK: fir.call @bar2_
31+
// CHECK: %{{.*}}= fir.emboxproc @foo_impl_
32+
// CHECK: fir.global common @a_(dense<0> : vector<4xi8>) : !fir.array<4xi8>
33+
// CHECK: fir.global common @__BLNK__(dense<0> : vector<4xi8>) : !fir.array<4xi8>
34+
// CHECK: func private @bar_(!fir.ref<i32>)
35+
36+
// LLVMIR: @a_ = common global [4 x i8] zeroinitializer
37+
// LLVMIR: @__BLNK__ = common global [4 x i8] zeroinitializer
38+
// LLVMIR: define void @foo_()
39+
// LLVMIR: call void @bar_(
40+
// LLVMIR: call void @bar2_(
41+
// LLVMIR: declare void @bar_(
42+
// LLVMIR: declare void @bar2_(

flang/unittests/Optimizer/InternalNamesTest.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,4 +210,36 @@ TEST(InternalNamesTest, complexdeconstructTest) {
210210
validateDeconstructedName(actual, expectedNameKind, expectedComponents);
211211
}
212212

213+
TEST(InternalNamesTest, needExternalNameMangling) {
214+
ASSERT_FALSE(
215+
NameUniquer::needExternalNameMangling("_QMmodSs1modSs2modFsubPfun"));
216+
ASSERT_FALSE(NameUniquer::needExternalNameMangling("omp_num_thread"));
217+
ASSERT_FALSE(NameUniquer::needExternalNameMangling(""));
218+
ASSERT_FALSE(NameUniquer::needExternalNameMangling("_QDTmytypeK2K8K18"));
219+
ASSERT_FALSE(NameUniquer::needExternalNameMangling("exit_"));
220+
ASSERT_TRUE(NameUniquer::needExternalNameMangling("_QPfoo"));
221+
ASSERT_TRUE(NameUniquer::needExternalNameMangling("_QPbar"));
222+
ASSERT_TRUE(NameUniquer::needExternalNameMangling("_QBa"));
223+
}
224+
225+
TEST(InternalNamesTest, isExternalFacingUniquedName) {
226+
std::pair result = NameUniquer::deconstruct("_QMmodSs1modSs2modFsubPfun");
227+
228+
ASSERT_FALSE(NameUniquer::isExternalFacingUniquedName(result));
229+
result = NameUniquer::deconstruct("omp_num_thread");
230+
ASSERT_FALSE(NameUniquer::isExternalFacingUniquedName(result));
231+
result = NameUniquer::deconstruct("");
232+
ASSERT_FALSE(NameUniquer::isExternalFacingUniquedName(result));
233+
result = NameUniquer::deconstruct("_QDTmytypeK2K8K18");
234+
ASSERT_FALSE(NameUniquer::isExternalFacingUniquedName(result));
235+
result = NameUniquer::deconstruct("exit_");
236+
ASSERT_FALSE(NameUniquer::isExternalFacingUniquedName(result));
237+
result = NameUniquer::deconstruct("_QPfoo");
238+
ASSERT_TRUE(NameUniquer::isExternalFacingUniquedName(result));
239+
result = NameUniquer::deconstruct("_QPbar");
240+
ASSERT_TRUE(NameUniquer::isExternalFacingUniquedName(result));
241+
result = NameUniquer::deconstruct("_QBa");
242+
ASSERT_TRUE(NameUniquer::isExternalFacingUniquedName(result));
243+
}
244+
213245
// main() from gtest_main

0 commit comments

Comments
 (0)