Skip to content

Commit fc66dbb

Browse files
committed
[fir] Add external name interop pass
Add the external name conversion pass needed for compiler interoperability. This pass convert the Flang internal symbol name to the common gfortran convention. Clean up old passes without implementation in the Passes.ts file so the project and fir-opt can build correctly. This patch is part of the upstreaming effort from fir-dev branch. Reviewed By: schweitz Differential Revision: https://reviews.llvm.org/D111057
1 parent d9346f5 commit fc66dbb

File tree

12 files changed

+331
-47
lines changed

12 files changed

+331
-47
lines changed

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

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

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

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

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -22,25 +22,7 @@ class Region;
2222

2323
namespace fir {
2424

25-
/// Convert fir.select_type to the standard dialect
26-
std::unique_ptr<mlir::Pass> createControlFlowLoweringPass();
27-
28-
/// Effects aware CSE pass
29-
std::unique_ptr<mlir::Pass> createCSEPass();
30-
31-
/// Convert FIR loop constructs to the Affine dialect
32-
std::unique_ptr<mlir::Pass> createPromoteToAffinePass();
33-
34-
/// Convert `fir.do_loop` and `fir.if` to a CFG. This
35-
/// conversion enables the `createLowerToCFGPass` to transform these to CFG
36-
/// form.
37-
std::unique_ptr<mlir::Pass> createFirToCfgPass();
38-
39-
/// A pass to convert the FIR dialect from "Mem-SSA" form to "Reg-SSA"
40-
/// form. This pass is a port of LLVM's mem2reg pass, but modified for the FIR
41-
/// dialect as well as the restructuring of MLIR's representation to present PHI
42-
/// nodes as block arguments.
43-
std::unique_ptr<mlir::Pass> createMemToRegPass();
25+
std::unique_ptr<mlir::Pass> createExternalNameConversionPass();
4426

4527
/// Support for inlining on FIR.
4628
bool canLegallyInline(mlir::Operation *op, mlir::Region *reg,

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

Lines changed: 4 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -16,36 +16,12 @@
1616

1717
include "mlir/Pass/PassBase.td"
1818

19-
def AffineDialectPromotion : FunctionPass<"promote-to-affine"> {
20-
let summary = "Promotes fir.do_loop and fir.where to affine.for and affine.if where possible";
19+
def ExternalNameConversion : Pass<"external-name-interop", "mlir::ModuleOp"> {
20+
let summary = "Convert name for external interoperability";
2121
let description = [{
22-
TODO
22+
Demangle FIR internal name and mangle them for external interoperability.
2323
}];
24-
let constructor = "fir::createPromoteToAffinePass()";
25-
}
26-
27-
def BasicCSE : FunctionPass<"basic-cse"> {
28-
let summary = "Basic common sub-expression elimination";
29-
let description = [{
30-
TODO
31-
}];
32-
let constructor = "fir::createCSEPass()";
33-
}
34-
35-
def ControlFlowLowering : FunctionPass<"lower-control-flow"> {
36-
let summary = "Convert affine dialect, fir.select_type to standard dialect";
37-
let description = [{
38-
TODO
39-
}];
40-
let constructor = "fir::createControlFlowLoweringPass()";
41-
}
42-
43-
def CFGConversion : FunctionPass<"cfg-conversion"> {
44-
let summary = "Convert FIR structured control flow ops to CFG ops.";
45-
let description = [{
46-
TODO
47-
}];
48-
let constructor = "fir::createFirToCfgPass()";
24+
let constructor = "::fir::createExternalNameConversionPass()";
4925
}
5026

5127
#endif // FLANG_OPTIMIZER_TRANSFORMS_PASSES

flang/lib/Optimizer/Support/InternalNames.cpp

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

flang/lib/Optimizer/Transforms/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
add_flang_library(FIRTransforms
22
Inliner.cpp
3+
ExternalNameConversion.cpp
34

45
DEPENDS
56
FIRDialect
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
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+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//===- PassDetail.h - Optimizer Transforms Pass class details ---*- C++ -*-===//
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+
#ifndef FORTRAN_OPTMIZER_TRANSFORMS_PASSDETAIL_H
9+
#define FORTRAN_OPTMIZER_TRANSFORMS_PASSDETAIL_H
10+
11+
#include "flang/Optimizer/Dialect/FIRDialect.h"
12+
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
13+
#include "mlir/Dialect/OpenACC/OpenACC.h"
14+
#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
15+
#include "mlir/Dialect/StandardOps/IR/Ops.h"
16+
#include "mlir/Pass/Pass.h"
17+
#include "mlir/Pass/PassRegistry.h"
18+
19+
namespace fir {
20+
21+
#define GEN_PASS_CLASSES
22+
#include "flang/Optimizer/Transforms/Passes.h.inc"
23+
24+
} // namespace fir
25+
26+
#endif // FORTRAN_OPTMIZER_TRANSFORMS_PASSDETAIL_H
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// RUN: fir-opt --external-name-interop %s | FileCheck %s
2+
3+
func @_QPfoo() {
4+
%e6 = fir.alloca tuple<i32,f64>
5+
%0 = 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}>>) -> ()>
6+
return
7+
}
8+
func private @_QPfoo_impl(!fir.ref<i32>)
9+
10+
// CHECK: %{{.*}}= fir.emboxproc @foo_impl_

flang/test/Fir/external-mangling.fir

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// RUN: fir-opt --external-name-interop %s | FileCheck %s
2+
3+
func @_QPfoo() {
4+
%c0 = constant 0 : index
5+
%0 = fir.address_of(@_QBa) : !fir.ref<!fir.array<4xi8>>
6+
%1 = fir.convert %0 : (!fir.ref<!fir.array<4xi8>>) -> !fir.ref<!fir.array<?xi8>>
7+
%2 = fir.coordinate_of %1, %c0 : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
8+
%3 = fir.convert %2 : (!fir.ref<i8>) -> !fir.ref<i32>
9+
%4 = fir.address_of(@_QB) : !fir.ref<!fir.array<4xi8>>
10+
%5 = fir.convert %4 : (!fir.ref<!fir.array<4xi8>>) -> !fir.ref<!fir.array<?xi8>>
11+
%6 = fir.coordinate_of %5, %c0 : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
12+
%7 = fir.convert %6 : (!fir.ref<i8>) -> !fir.ref<f32>
13+
fir.call @_QPbar(%3) : (!fir.ref<i32>) -> ()
14+
fir.call @_QPbar2(%7) : (!fir.ref<f32>) -> ()
15+
return
16+
}
17+
fir.global common @_QBa(dense<0> : vector<4xi8>) : !fir.array<4xi8>
18+
fir.global common @_QB(dense<0> : vector<4xi8>) : !fir.array<4xi8>
19+
func private @_QPbar(!fir.ref<i32>)
20+
func private @_QPbar2(!fir.ref<f32>)
21+
22+
// CHECK: func @foo_
23+
// CHECK: %{{.*}} = fir.address_of(@a_) : !fir.ref<!fir.array<4xi8>>
24+
// CHECK: %{{.*}} = fir.address_of(@__BLNK__) : !fir.ref<!fir.array<4xi8>>
25+
// CHECK: fir.call @bar_
26+
// CHECK: fir.call @bar2_
27+
// CHECK: fir.global common @a_(dense<0> : vector<4xi8>) : !fir.array<4xi8>
28+
// CHECK: fir.global common @__BLNK__(dense<0> : vector<4xi8>) : !fir.array<4xi8>
29+
// CHECK: func private @bar_(!fir.ref<i32>)

flang/tools/fir-opt/CMakeLists.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,18 @@ target_link_libraries(fir-opt PRIVATE
1111

1212
# TODO: these should be transitive dependencies from a target providing
1313
# "registerFIRPasses()"
14+
MLIRIR
15+
MLIRLLVMIR
16+
MLIRPass
17+
MLIRStandardToLLVM
18+
MLIRTransforms
1419
MLIRAffineToStandard
20+
MLIRAnalysis
21+
MLIRSCFToStandard
22+
MLIRParser
23+
MLIRStandardToLLVM
24+
MLIRSupport
25+
MLIRVectorToLLVM
1526
MLIROptLib
27+
1628
)

0 commit comments

Comments
 (0)