Skip to content

Commit e006b73

Browse files
committed
[flang] Add initial implementation of module variables.
This PR add supports for module variables and function. The module variables are added as global variables but their scope is set to module instead of compile unit. The scope of function declared inside a module is also set accordingly. After this patch, a module variable could be evaluated in the GDB as `p helper::gli` where helper is name of the module and gli is the name of the variable. A future patch will add the import module functionality which will remove the need to prefix the name with helper::. The line number where is module is declared is a best guess at the moment as this information is not part of the GlobalOp.
1 parent 61da636 commit e006b73

File tree

4 files changed

+174
-3
lines changed

4 files changed

+174
-3
lines changed

flang/lib/Optimizer/CodeGen/CodeGen.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2716,6 +2716,18 @@ struct GlobalOpConversion : public fir::FIROpConversion<fir::GlobalOp> {
27162716
mlir::LogicalResult
27172717
matchAndRewrite(fir::GlobalOp global, OpAdaptor adaptor,
27182718
mlir::ConversionPatternRewriter &rewriter) const override {
2719+
2720+
mlir::LLVM::DIGlobalVariableExpressionAttr dbgExpr;
2721+
2722+
if (auto fusedLoc = mlir::dyn_cast<mlir::FusedLoc>(global.getLoc())) {
2723+
if (auto gvAttr =
2724+
mlir::dyn_cast_or_null<mlir::LLVM::DIGlobalVariableAttr>(
2725+
fusedLoc.getMetadata())) {
2726+
dbgExpr = mlir::LLVM::DIGlobalVariableExpressionAttr::get(
2727+
global.getContext(), gvAttr, mlir::LLVM::DIExpressionAttr());
2728+
}
2729+
}
2730+
27192731
auto tyAttr = convertType(global.getType());
27202732
if (auto boxType = mlir::dyn_cast<fir::BaseBoxType>(global.getType()))
27212733
tyAttr = this->lowerTy().convertBoxTypeAsStruct(boxType);
@@ -2724,8 +2736,11 @@ struct GlobalOpConversion : public fir::FIROpConversion<fir::GlobalOp> {
27242736
assert(attributeTypeIsCompatible(global.getContext(), initAttr, tyAttr));
27252737
auto linkage = convertLinkage(global.getLinkName());
27262738
auto isConst = global.getConstant().has_value();
2739+
mlir::SymbolRefAttr comdat;
2740+
llvm::ArrayRef<mlir::NamedAttribute> attrs;
27272741
auto g = rewriter.create<mlir::LLVM::GlobalOp>(
2728-
loc, tyAttr, isConst, linkage, global.getSymName(), initAttr);
2742+
loc, tyAttr, isConst, linkage, global.getSymName(), initAttr, 0, 0,
2743+
false, false, comdat, attrs, dbgExpr);
27292744

27302745
auto module = global->getParentOfType<mlir::ModuleOp>();
27312746
// Add comdat if necessary

flang/lib/Optimizer/Transforms/AddDebugInfo.cpp

Lines changed: 82 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include "llvm/Support/FileSystem.h"
3636
#include "llvm/Support/Path.h"
3737
#include "llvm/Support/raw_ostream.h"
38+
#include <map>
3839

3940
namespace fir {
4041
#define GEN_PASS_DEF_ADDDEBUGINFO
@@ -54,6 +55,16 @@ class AddDebugInfoPass : public fir::impl::AddDebugInfoBase<AddDebugInfoPass> {
5455
public:
5556
AddDebugInfoPass(fir::AddDebugInfoOptions options) : Base(options) {}
5657
void runOnOperation() override;
58+
59+
private:
60+
std::map<std::string, mlir::LLVM::DIModuleAttr> moduleMap;
61+
62+
mlir::LLVM::DIModuleAttr getOrCreateModuleAttr(
63+
const std::string &name, mlir::LLVM::DIFileAttr fileAttr,
64+
mlir::LLVM::DIScopeAttr scope, unsigned line, bool decl);
65+
66+
void handleGlobalOp(fir::GlobalOp glocalOp, mlir::LLVM::DIFileAttr fileAttr,
67+
mlir::LLVM::DIScopeAttr scope);
5768
};
5869

5970
static uint32_t getLineFromLoc(mlir::Location loc) {
@@ -99,6 +110,66 @@ void AddDebugInfoPass::handleDeclareOp(fir::cg::XDeclareOp declOp,
99110
declOp->setLoc(builder.getFusedLoc({declOp->getLoc()}, localVarAttr));
100111
}
101112

113+
// The `module` does not have a first class representation in the `FIR`. We
114+
// extract information about it from the name of the identifiers and keep a
115+
// map to avoid duplication.
116+
mlir::LLVM::DIModuleAttr AddDebugInfoPass::getOrCreateModuleAttr(
117+
const std::string &name, mlir::LLVM::DIFileAttr fileAttr,
118+
mlir::LLVM::DIScopeAttr scope, unsigned line, bool decl) {
119+
mlir::MLIRContext *context = &getContext();
120+
mlir::LLVM::DIModuleAttr modAttr;
121+
if (auto iter{moduleMap.find(name)}; iter != moduleMap.end())
122+
modAttr = iter->second;
123+
else {
124+
modAttr = mlir::LLVM::DIModuleAttr::get(
125+
context, fileAttr, scope, mlir::StringAttr::get(context, name),
126+
mlir::StringAttr(), mlir::StringAttr(), mlir::StringAttr(), line, decl);
127+
moduleMap[name] = modAttr;
128+
}
129+
return modAttr;
130+
}
131+
132+
void AddDebugInfoPass::handleGlobalOp(fir::GlobalOp globalOp,
133+
mlir::LLVM::DIFileAttr fileAttr,
134+
mlir::LLVM::DIScopeAttr scope) {
135+
mlir::ModuleOp module = getOperation();
136+
mlir::MLIRContext *context = &getContext();
137+
fir::DebugTypeGenerator typeGen(module);
138+
mlir::OpBuilder builder(context);
139+
140+
auto result = fir::NameUniquer::deconstruct(globalOp.getSymName());
141+
if (result.first != fir::NameUniquer::NameKind::VARIABLE)
142+
return;
143+
144+
unsigned line = getLineFromLoc(globalOp.getLoc());
145+
146+
// DWARF5 says following about the fortran modules:
147+
// A Fortran 90 module may also be represented by a module entry
148+
// (but no declaration attribute is warranted because Fortran has no concept
149+
// of a corresponding module body).
150+
// But in practice, compilers use declaration attribute with a module in cases
151+
// where module was defined in another source file (only being used in this
152+
// one). The hasInitializationBody() seems to provide the right information
153+
// but inverted. It is true where module is actually defined but false where
154+
// it is used.
155+
// FIXME: Currently we don't have the line number on which a module was
156+
// declared. We are using a best guess of line - 1 where line is the source
157+
// line of the first member of the module that we encounter.
158+
159+
if (!result.second.modules.empty())
160+
scope = getOrCreateModuleAttr(result.second.modules[0], fileAttr, scope,
161+
line - 1, !globalOp.hasInitializationBody());
162+
163+
auto diType = typeGen.convertType(globalOp.getType(), fileAttr, scope,
164+
globalOp.getLoc());
165+
auto gvAttr = mlir::LLVM::DIGlobalVariableAttr::get(
166+
context, scope, mlir::StringAttr::get(context, result.second.name),
167+
mlir::StringAttr::get(context, globalOp.getName()), fileAttr, line,
168+
diType, /*isLocalToUnit*/ false,
169+
/*isDefinition*/ globalOp.hasInitializationBody(), /* alignInBits*/ 0);
170+
globalOp->setLoc(builder.getFusedLoc({globalOp->getLoc()}, gvAttr));
171+
}
172+
102173
void AddDebugInfoPass::runOnOperation() {
103174
mlir::ModuleOp module = getOperation();
104175
mlir::MLIRContext *context = &getContext();
@@ -138,6 +209,10 @@ void AddDebugInfoPass::runOnOperation() {
138209
llvm::dwarf::getLanguage("DW_LANG_Fortran95"), fileAttr, producer,
139210
isOptimized, debugLevel);
140211

212+
module.walk([&](fir::GlobalOp globalOp) {
213+
handleGlobalOp(globalOp, fileAttr, cuAttr);
214+
});
215+
141216
module.walk([&](mlir::func::FuncOp funcOp) {
142217
mlir::Location l = funcOp->getLoc();
143218
// If fused location has already been created then nothing to do
@@ -180,6 +255,7 @@ void AddDebugInfoPass::runOnOperation() {
180255

181256
// Only definitions need a distinct identifier and a compilation unit.
182257
mlir::DistinctAttr id;
258+
mlir::LLVM::DIScopeAttr Scope = fileAttr;
183259
mlir::LLVM::DICompileUnitAttr compilationUnit;
184260
mlir::LLVM::DISubprogramFlags subprogramFlags =
185261
mlir::LLVM::DISubprogramFlags{};
@@ -192,9 +268,13 @@ void AddDebugInfoPass::runOnOperation() {
192268
subprogramFlags | mlir::LLVM::DISubprogramFlags::Definition;
193269
}
194270
unsigned line = getLineFromLoc(l);
271+
if (!result.second.modules.empty())
272+
Scope = getOrCreateModuleAttr(result.second.modules[0], fileAttr, cuAttr,
273+
line - 1, false);
274+
195275
auto spAttr = mlir::LLVM::DISubprogramAttr::get(
196-
context, id, compilationUnit, fileAttr, funcName, fullName,
197-
funcFileAttr, line, line, subprogramFlags, subTypeAttr);
276+
context, id, compilationUnit, Scope, funcName, fullName, funcFileAttr,
277+
line, line, subprogramFlags, subTypeAttr);
198278
funcOp->setLoc(builder.getFusedLoc({funcOp->getLoc()}, spAttr));
199279

200280
funcOp.walk([&](fir::cg::XDeclareOp declOp) {
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
! RUN: %flang_fc1 -emit-fir -debug-info-kind=standalone -mmlir --mlir-print-debuginfo %s -o - | \
2+
! RUN: fir-opt --cg-rewrite --mlir-print-debuginfo | fir-opt --add-debug-info --mlir-print-debuginfo | FileCheck %s
3+
4+
! CHECK-DAG: #[[I4:.*]] = #llvm.di_basic_type<tag = DW_TAG_base_type, name = "integer", sizeInBits = 32, encoding = DW_ATE_signed>
5+
! CHECK-DAG: #[[R4:.*]] = #llvm.di_basic_type<tag = DW_TAG_base_type, name = "real", sizeInBits = 32, encoding = DW_ATE_float>
6+
! CHECK-DAG: #[[FILE:.*]] = #llvm.di_file<"debug-module-1.f90" {{.*}}>
7+
! CHECK-DAG: #[[CU:.*]] = #llvm.di_compile_unit<{{.*}}, file = #[[FILE]], {{.*}}>
8+
! CHECK-DAG: #[[MOD:.*]] = #llvm.di_module<file = #[[FILE]], scope = #[[CU]], name = "helper", {{.*}}>
9+
module helper
10+
! CHECK-DAG: #[[LOC1:.*]] = loc("{{.*}}debug-module-1.f90":[[@LINE+2]]{{.*}})
11+
! CHECK-DAG: #[[GLR:.*]] = #llvm.di_global_variable<scope = #[[MOD]], name = "glr", linkageName = "_QMhelperEglr", file = #[[FILE]], line = [[@LINE+1]], type = #[[R4]], isDefined = true>
12+
real glr
13+
! CHECK-DAG: #[[LOC2:.*]] = loc("{{.*}}debug-module-1.f90":[[@LINE+2]]{{.*}})
14+
! CHECK-DAG: #[[GLI:.*]] = #llvm.di_global_variable<scope = #[[MOD]], name = "gli", linkageName = "_QMhelperEgli", file = #[[FILE]], line = [[@LINE+1]], type = #[[I4]], isDefined = true>
15+
integer gli
16+
17+
contains
18+
! CHECK-DAG: #[[LOC3:.*]] = loc("{{.*}}debug-module-1.f90":[[@LINE+2]]{{.*}})
19+
! CHECK-DAG: #[[TEST:.*]] = #llvm.di_subprogram<{{.*}}compileUnit = #[[CU]], scope = #[[MOD]], name = "test", linkageName = "_QMhelperPtest", file = #[[FILE]], line = [[@LINE+1]], scopeLine = [[@LINE+1]]{{.*}}>
20+
subroutine test()
21+
glr = 12.34
22+
gli = 67
23+
24+
end subroutine
25+
end module helper
26+
27+
program test
28+
use helper
29+
implicit none
30+
31+
glr = 3.14
32+
gli = 2
33+
call test()
34+
35+
end program test
36+
37+
! CHECK-DAG: loc(fused<#[[GLR]]>[#[[LOC1]]])
38+
! CHECK-DAG: loc(fused<#[[GLI]]>[#[[LOC2]]])
39+
! CHECK-DAG: loc(fused<#[[TEST]]>[#[[LOC3]]])
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
! RUN: %flang_fc1 -emit-llvm -debug-info-kind=standalone %s -o - | FileCheck %s
2+
3+
! CHECK-DAG: ![[FILE:.*]] = !DIFile(filename: {{.*}}debug-module-2.f90{{.*}})
4+
! CHECK-DAG: ![[FILE2:.*]] = !DIFile(filename: {{.*}}debug-module-2.f90{{.*}})
5+
! CHECK-DAG: ![[CU:.*]] = distinct !DICompileUnit({{.*}}file: ![[FILE]]{{.*}} globals: ![[GLOBALS:.*]])
6+
! CHECK-DAG: ![[MOD:.*]] = !DIModule(scope: ![[CU]], name: "helper", file: ![[FILE]]{{.*}})
7+
! CHECK-DAG: ![[R4:.*]] = !DIBasicType(name: "real", size: 32, encoding: DW_ATE_float)
8+
! CHECK-DAG: ![[I4:.*]] = !DIBasicType(name: "integer", size: 32, encoding: DW_ATE_signed)
9+
module helper
10+
! CHECK-DAG: ![[GLR:.*]] = distinct !DIGlobalVariable(name: "glr", linkageName: "_QMhelperEglr", scope: ![[MOD]], file: ![[FILE]], line: [[@LINE+2]], type: ![[R4]], isLocal: false, isDefinition: true)
11+
! CHECK-DAG: ![[GLRX:.*]] = !DIGlobalVariableExpression(var: ![[GLR]], expr: !DIExpression())
12+
real glr
13+
14+
! CHECK-DAG: ![[GLI:.*]] = distinct !DIGlobalVariable(name: "gli", linkageName: "_QMhelperEgli", scope: ![[MOD]], file: ![[FILE]], line: [[@LINE+2]], type: ![[I4]], isLocal: false, isDefinition: true)
15+
! CHECK-DAG: ![[GLIX:.*]] = !DIGlobalVariableExpression(var: ![[GLI]], expr: !DIExpression())
16+
integer gli
17+
18+
contains
19+
!CHECK-DAG: !DISubprogram(name: "test", linkageName: "_QMhelperPtest", scope: ![[MOD]], file: ![[FILE2]], line: [[@LINE+1]]{{.*}}unit: ![[CU]])
20+
subroutine test()
21+
glr = 12.34
22+
gli = 67
23+
24+
end subroutine
25+
end module helper
26+
27+
program test
28+
use helper
29+
implicit none
30+
31+
glr = 3.14
32+
gli = 2
33+
call test()
34+
35+
end program test
36+
37+
! CHECK-DAG: ![[GLOBALS]] = !{![[GLIX]], ![[GLRX]]}

0 commit comments

Comments
 (0)