1//===- DILineTableFromLocations.cpp - -------------------------------------===//
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 "mlir/Dialect/LLVMIR/Transforms/Passes.h"
10
11#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
12#include "mlir/Pass/Pass.h"
13#include "llvm/BinaryFormat/Dwarf.h"
14#include "llvm/Support/Debug.h"
15#include "llvm/Support/Path.h"
16
17namespace mlir {
18namespace LLVM {
19#define GEN_PASS_DEF_DISCOPEFORLLVMFUNCOPPASS
20#include "mlir/Dialect/LLVMIR/Transforms/Passes.h.inc"
21} // namespace LLVM
22} // namespace mlir
23
24using namespace mlir;
25
26/// Attempt to extract a filename for the given loc.
27static FileLineColLoc extractFileLoc(Location loc) {
28 if (auto fileLoc = dyn_cast<FileLineColLoc>(loc))
29 return fileLoc;
30 if (auto nameLoc = dyn_cast<NameLoc>(loc))
31 return extractFileLoc(nameLoc.getChildLoc());
32 if (auto opaqueLoc = dyn_cast<OpaqueLoc>(loc))
33 return extractFileLoc(opaqueLoc.getFallbackLocation());
34 if (auto fusedLoc = dyn_cast<FusedLoc>(loc)) {
35 for (auto loc : fusedLoc.getLocations()) {
36 if (auto fileLoc = extractFileLoc(loc))
37 return fileLoc;
38 }
39 }
40 if (auto callerLoc = dyn_cast<CallSiteLoc>(loc))
41 return extractFileLoc(callerLoc.getCaller());
42 return FileLineColLoc();
43}
44
45/// Creates a DISubprogramAttr with the provided compile unit and attaches it
46/// to the function. Does nothing when the function already has an attached
47/// subprogram.
48static void addScopeToFunction(LLVM::LLVMFuncOp llvmFunc,
49 LLVM::DICompileUnitAttr compileUnitAttr) {
50
51 Location loc = llvmFunc.getLoc();
52 if (loc->findInstanceOf<FusedLocWith<LLVM::DISubprogramAttr>>())
53 return;
54
55 MLIRContext *context = llvmFunc->getContext();
56
57 // Filename and line associate to the function.
58 LLVM::DIFileAttr fileAttr;
59 int64_t line = 1;
60 if (FileLineColLoc fileLoc = extractFileLoc(loc)) {
61 line = fileLoc.getLine();
62 StringRef inputFilePath = fileLoc.getFilename().getValue();
63 fileAttr =
64 LLVM::DIFileAttr::get(context, llvm::sys::path::filename(inputFilePath),
65 llvm::sys::path::parent_path(inputFilePath));
66 } else {
67 fileAttr = compileUnitAttr
68 ? compileUnitAttr.getFile()
69 : LLVM::DIFileAttr::get(context, "<unknown>", "");
70 }
71 auto subroutineTypeAttr =
72 LLVM::DISubroutineTypeAttr::get(context, llvm::dwarf::DW_CC_normal, {});
73
74 // Figure out debug information (`subprogramFlags` and `compileUnitAttr`) to
75 // attach to the function definition / declaration. External functions are
76 // declarations only and are defined in a different compile unit, so mark
77 // them appropriately in `subprogramFlags` and set an empty `compileUnitAttr`.
78 DistinctAttr id;
79 auto subprogramFlags = LLVM::DISubprogramFlags::Optimized;
80 if (!llvmFunc.isExternal()) {
81 id = DistinctAttr::create(UnitAttr::get(context));
82 subprogramFlags = subprogramFlags | LLVM::DISubprogramFlags::Definition;
83 } else {
84 compileUnitAttr = {};
85 }
86 auto funcNameAttr = llvmFunc.getNameAttr();
87 auto subprogramAttr = LLVM::DISubprogramAttr::get(
88 context, id, compileUnitAttr, fileAttr, funcNameAttr, funcNameAttr,
89 fileAttr,
90 /*line=*/line, /*scopeLine=*/line, subprogramFlags, subroutineTypeAttr,
91 /*retainedNodes=*/{}, /*annotations=*/{});
92 llvmFunc->setLoc(FusedLoc::get(context, {loc}, subprogramAttr));
93}
94
95// Get a nested loc for inlined functions.
96static Location getNestedLoc(Operation *op, LLVM::DIScopeAttr scopeAttr,
97 Location calleeLoc) {
98 auto calleeFileName = extractFileLoc(loc: calleeLoc).getFilename();
99 auto *context = op->getContext();
100 LLVM::DIFileAttr calleeFileAttr =
101 LLVM::DIFileAttr::get(context, llvm::sys::path::filename(calleeFileName),
102 llvm::sys::path::parent_path(calleeFileName));
103 auto lexicalBlockFileAttr = LLVM::DILexicalBlockFileAttr::get(
104 context, scopeAttr, calleeFileAttr, /*discriminator=*/0);
105 Location loc = calleeLoc;
106 // Recurse if the callee location is again a call site.
107 if (auto callSiteLoc = dyn_cast<CallSiteLoc>(calleeLoc)) {
108 auto nestedLoc = callSiteLoc.getCallee();
109 loc = getNestedLoc(op, lexicalBlockFileAttr, nestedLoc);
110 }
111 return FusedLoc::get(context, {loc}, lexicalBlockFileAttr);
112}
113
114static void setLexicalBlockFileAttr(Operation *op) {
115 if (auto callSiteLoc = dyn_cast<CallSiteLoc>(op->getLoc())) {
116 auto callerLoc = callSiteLoc.getCaller();
117 auto calleeLoc = callSiteLoc.getCallee();
118 LLVM::DIScopeAttr scopeAttr;
119 // We assemble the full inline stack so the parent of this loc must be a
120 // function
121 auto funcOp = op->getParentOfType<LLVM::LLVMFuncOp>();
122 if (auto funcOpLoc = llvm::dyn_cast_if_present<FusedLoc>(funcOp.getLoc())) {
123 scopeAttr = cast<LLVM::DISubprogramAttr>(funcOpLoc.getMetadata());
124 op->setLoc(
125 CallSiteLoc::get(getNestedLoc(op, scopeAttr, calleeLoc), callerLoc));
126 }
127 }
128}
129
130namespace {
131/// Add a debug info scope to LLVMFuncOp that are missing it.
132struct DIScopeForLLVMFuncOpPass
133 : public LLVM::impl::DIScopeForLLVMFuncOpPassBase<
134 DIScopeForLLVMFuncOpPass> {
135 using Base::Base;
136
137 void runOnOperation() override {
138 ModuleOp module = getOperation();
139 Location loc = module.getLoc();
140
141 MLIRContext *context = &getContext();
142 if (!context->getLoadedDialect<LLVM::LLVMDialect>()) {
143 emitError(loc, message: "LLVM dialect is not loaded.");
144 return signalPassFailure();
145 }
146
147 // Find a DICompileUnitAttr attached to a parent (the module for example),
148 // otherwise create a default one.
149 LLVM::DICompileUnitAttr compileUnitAttr;
150 if (auto fusedCompileUnitAttr =
151 module->getLoc()
152 ->findInstanceOf<FusedLocWith<LLVM::DICompileUnitAttr>>()) {
153 compileUnitAttr = fusedCompileUnitAttr.getMetadata();
154 } else {
155 LLVM::DIFileAttr fileAttr;
156 if (FileLineColLoc fileLoc = extractFileLoc(loc)) {
157 StringRef inputFilePath = fileLoc.getFilename().getValue();
158 fileAttr = LLVM::DIFileAttr::get(
159 context, llvm::sys::path::filename(inputFilePath),
160 llvm::sys::path::parent_path(inputFilePath));
161 } else {
162 fileAttr = LLVM::DIFileAttr::get(context, "<unknown>", "");
163 }
164
165 compileUnitAttr = LLVM::DICompileUnitAttr::get(
166 DistinctAttr::create(UnitAttr::get(context)), llvm::dwarf::DW_LANG_C,
167 fileAttr, StringAttr::get(context, "MLIR"),
168 /*isOptimized=*/true, emissionKind);
169 }
170
171 module.walk<WalkOrder::PreOrder>([&](Operation *op) -> void {
172 if (auto funcOp = dyn_cast<LLVM::LLVMFuncOp>(op)) {
173 // Create subprograms for each function with the same distinct compile
174 // unit.
175 addScopeToFunction(funcOp, compileUnitAttr);
176 } else {
177 setLexicalBlockFileAttr(op);
178 }
179 });
180 }
181};
182
183} // end anonymous namespace
184

Provided by KDAB

Privacy Policy
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more

source code of mlir/lib/Dialect/LLVMIR/Transforms/DIScopeForLLVMFuncOp.cpp