docc 0.8.3 (0d44999b)
C++ API Reference
Loading...
Searching...
No Matches
utils.h
Go to the documentation of this file.
1#pragma once
2
3#include <csignal>
4#include <cstdlib>
5#include <filesystem>
6#include <functional>
7#include <regex>
8#include <string>
9
10#include <llvm/Analysis/RegionInfo.h>
11#include <llvm/BinaryFormat/Dwarf.h>
12#include <llvm/Demangle/Demangle.h>
13#include <llvm/IR/DebugInfoMetadata.h>
14#include <llvm/IR/Function.h>
15#include <llvm/IR/Instructions.h>
16#include <llvm/IR/IntrinsicInst.h>
17#include <llvm/IR/Module.h>
18
19#include <llvm/Support/Debug.h>
20
21#include <sdfg/element.h>
22
23#ifndef NDEBUG
24#define LLVM_DEBUG_PRINTLN(msg) \
25 do { \
26 llvm::errs() << "[DEBUG] " << msg << "\n"; \
27 } while (0)
28#define LLVM_DEBUG_PRINT(msg) \
29 do { \
30 llvm::errs() << "[DEBUG] " << msg; \
31 } while (0)
32#else
33#define LLVM_DEBUG_PRINTLN(msg) \
34 do { \
35 } while (0)
36#define LLVM_DEBUG_PRINT(msg) \
37 do { \
38 } while (0)
39#endif
40
41namespace docc {
42
44
45namespace utils {
46
47inline std::string hash_function_name(const std::string& function_name) {
48 std::hash<std::string> hash_fn;
49 size_t hash_value = hash_fn(function_name);
50
51 return std::to_string(hash_value);
52};
53
54inline std::string hash_module_name(const llvm::Module& Module) {
55 std::string srcName = Module.getSourceFileName();
56 std::string absPath = std::filesystem::absolute(srcName).string();
57
58 std::hash<std::string> hash_fn;
59 size_t hash_value = hash_fn(absPath);
60 std::string stable_hash = std::to_string(hash_value);
61
62 return stable_hash;
63};
64
65inline bool is_mangled_name(const std::string& name) {
66 // Regex patterns for common mangling styles
67 std::regex itaniumPattern("^_Z");
68
69 return std::regex_search(name, itaniumPattern);
70};
71
72inline std::string get_demangled_name(const std::string& name) {
73 if (is_mangled_name(name)) {
74 char* demangled = llvm::itaniumDemangle(name.c_str());
75 if (demangled) {
76 std::string full_name(demangled);
77 std::free(demangled);
78 return full_name;
79 }
80 }
81 return name;
82};
83
84inline std::string get_truncated_demangled_name(const std::string& name) {
85 if (is_mangled_name(name)) {
86 char* demangled = llvm::itaniumDemangle(name.c_str());
87 if (demangled) {
88 std::string full_name(demangled);
89 std::free(demangled);
90 size_t pos = full_name.find("(");
91 assert(pos != std::string::npos);
92 std::string sdfg_name = full_name.substr(0, pos);
93 return sdfg_name;
94 }
95 }
96 return name;
97};
98
99inline llvm::dwarf::SourceLanguage source_language(llvm::Module& Module) {
100 if (auto* compile_unit = Module.getNamedMetadata("llvm.dbg.cu")) {
101 if (auto* Node = compile_unit->getOperand(0)) {
102 if (auto* CUNode = llvm::dyn_cast<llvm::DICompileUnit>(Node)) {
103 unsigned lang = CUNode->getSourceLanguage();
104 switch (lang) {
105 case llvm::dwarf::DW_LANG_C:
106 case llvm::dwarf::DW_LANG_C89:
107 case llvm::dwarf::DW_LANG_C99:
108 case llvm::dwarf::DW_LANG_C11: {
109 return llvm::dwarf::DW_LANG_C;
110 }
111 case llvm::dwarf::DW_LANG_C_plus_plus:
112 case llvm::dwarf::DW_LANG_C_plus_plus_03:
113 case llvm::dwarf::DW_LANG_C_plus_plus_11:
114 case llvm::dwarf::DW_LANG_C_plus_plus_14: {
115 return llvm::dwarf::DW_LANG_C_plus_plus;
116 }
117 default:
118 break;
119 }
120 }
121 }
122 }
123
124 return llvm::dwarf::DW_LANG_C_plus_plus;
125};
126
127inline bool has_debug(const llvm::Module& Module) {
128 for (const auto& F : Module) {
129 if (F.getSubprogram() != nullptr) {
130 return true;
131 }
132 }
133 for (const auto& N : Module.named_metadata()) {
134 if (N.getName().starts_with("llvm.dbg.")) {
135 return true;
136 }
137 }
138 return false;
139};
140
141inline sdfg::DebugInfo get_debug_info(const llvm::Instruction& inst) {
142 // Retrieve the attached debug location (if any)
143 llvm::DebugLoc dbg = inst.getDebugLoc();
144 if (!dbg || dbg->getLine() == 0) {
145 return sdfg::DebugInfo();
146 }
147
148 // LLVM 16+ stores the directory as part of the DIFile object. Earlier versions
149 // provided helper accessors on the location itself. Use the DIFile object to
150 // build an absolute path that works across all supported LLVM versions.
151 const llvm::DILocation* loc = dbg.get();
152
153
154 // Get the file name
155 const llvm::DIFile* file = loc->getFile();
156 if (!file) {
157 return sdfg::DebugInfo();
158 }
159 llvm::StringRef directory = file->getDirectory();
160 llvm::StringRef filename_ref = file->getFilename();
161 std::filesystem::path filepath;
162 if (!directory.empty()) {
163 filepath = std::filesystem::path(directory.str()) / filename_ref.str();
164 } else {
165 filepath = std::filesystem::path(filename_ref.str());
166 }
167
168 // Make sure we operate on an absolute path so downstream components can rely
169 // on a stable file identifier irrespective of the current working directory.
170 std::string filename = std::filesystem::absolute(filepath).lexically_normal().string();
171
172 // Get the line and column
173 size_t line = loc->getLine();
174 size_t col = loc->getColumn();
175
176 // Get the subprogram
177 std::string subprogram_name;
178 const auto* LS = llvm::dyn_cast<llvm::DILocalScope>(loc->getScope());
179 if (LS) {
180 const llvm::DISubprogram* SP = LS->getSubprogram();
181 if (SP) {
182 if (!SP->getName().empty()) {
183 // strip .extracted if it exists
184 std::string name = SP->getLinkageName().str();
185 if (name.empty()) {
186 name = SP->getName().str();
187 }
188 size_t pos = name.find(".extracted");
189 if (pos != std::string::npos) {
190 name = name.substr(0, pos);
191 }
192 subprogram_name = get_demangled_name(name);
193 }
194 }
195 }
196
197 return sdfg::DebugInfo(filename, subprogram_name, line, col, line, col);
198};
199
200inline sdfg::DebugInfo get_debug_info(llvm::BasicBlock& block) {
201 sdfg::DebugInfo dbg_info = docc::utils::get_debug_info(block.front());
202 for (auto& inst : block) {
203 auto inst_dbg_info = docc::utils::get_debug_info(inst);
204 dbg_info = dbg_info.merge(inst_dbg_info, dbg_info);
205 }
206 return dbg_info;
207};
208
209inline sdfg::DebugInfo get_debug_info(llvm::Function& function) {
210 sdfg::DebugInfo dbg_info = docc::utils::get_debug_info(function.getEntryBlock());
211 for (auto& block : function) {
212 auto block_dbg_info = docc::utils::get_debug_info(block);
213 dbg_info = dbg_info.merge(block_dbg_info, dbg_info);
214 }
215 return dbg_info;
216};
217
218inline sdfg::DebugInfo get_debug_info(llvm::Region& region) {
219 sdfg::DebugInfo dbg_info;
220 for (auto block : region.blocks()) {
221 auto block_dbg_info = docc::utils::get_debug_info(*block);
222 dbg_info = dbg_info.merge(block_dbg_info, dbg_info);
223 }
224 return dbg_info;
225};
226
227// Grab a DebugLoc from the value itself (if Instruction), or from one of its users.
228inline sdfg::DebugInfo bestEffortLoc(const llvm::Value& V) {
229 if (auto* I = llvm::dyn_cast<llvm::Instruction>(&V)) {
230 return get_debug_info(*I);
231 }
232
233 // Try users that are instructions with a location (common when V is an Argument or Constant).
234 for (const llvm::User* U : V.users()) {
235 if (auto* I = llvm::dyn_cast<llvm::Instruction>(U)) {
236 if (auto DL = I->getDebugLoc()) {
237 return get_debug_info(*I);
238 }
239 }
240 }
241
242 return sdfg::DebugInfo(); // nothing found
243}
244
245inline std::vector<std::string> get_recorded_driver_flags(const llvm::Module& M) {
246 // Warning, this s broken. llvm.commandline may already contain additional lines from other modules due to thin-LTO
247 // It makes no sense to merge them all, including multiple compiler-executables
248 std::vector<std::string> Flags;
249
250 if (auto* CMD = M.getNamedMetadata("llvm.commandline")) {
251 for (llvm::MDNode* Op : CMD->operands()) {
252 auto* S = llvm::dyn_cast<llvm::MDString>(Op->getOperand(0));
253 if (S) {
254 // Split the recorded command line into individual flags
255 std::string cmd = S->getString().str();
256 std::stringstream ss(cmd);
257 std::string part;
258 while (std::getline(ss, part, ' ')) {
259 Flags.emplace_back(part);
260 }
261 }
262 }
263 }
264 return Flags;
265}
266
267template<typename T>
268inline std::string toIRString(const T& value) {
269 std::string result;
270 llvm::raw_string_ostream os(result);
271 value.print(os);
272 return os.str();
273}
274
275} // namespace utils
276} // namespace docc
Definition element.h:30
static DebugInfo merge(const DebugInfo &left, const DebugInfo &right)
sdfg::DebugInfo bestEffortLoc(const llvm::Value &V)
Definition utils.h:228
std::string toIRString(const T &value)
Definition utils.h:268
std::string hash_module_name(const llvm::Module &Module)
Definition utils.h:54
std::vector< std::string > get_recorded_driver_flags(const llvm::Module &M)
Definition utils.h:245
std::string hash_function_name(const std::string &function_name)
Definition utils.h:47
sdfg::DebugInfo get_debug_info(const llvm::Instruction &inst)
Definition utils.h:141
bool is_mangled_name(const std::string &name)
Definition utils.h:65
std::string get_demangled_name(const std::string &name)
Definition utils.h:72
bool has_debug(const llvm::Module &Module)
Definition utils.h:127
std::string get_truncated_demangled_name(const std::string &name)
Definition utils.h:84
llvm::dwarf::SourceLanguage source_language(llvm::Module &Module)
Definition utils.h:99
Definition targets.h:8
TargetType
Definition utils.h:43
@ HOST
Definition utils.h:43
@ CUDA
Definition utils.h:43