blob: f36f9c9bd6a2912e56f78a5e4d2b3893c03df5e1 [file] [log] [blame]
Ben Claytonac07ed82019-03-26 14:17:41 +00001// Copyright 2019 The SwiftShader Authors. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "LLVMReactorDebugInfo.hpp"
16
17#ifdef ENABLE_RR_DEBUG_INFO
18
Ben Clayton713b8d32019-12-17 20:37:56 +000019# include "LLVMReactor.hpp"
20# include "Reactor.hpp"
Ben Claytonac07ed82019-03-26 14:17:41 +000021
Ben Clayton713b8d32019-12-17 20:37:56 +000022# include "boost/stacktrace.hpp"
Ben Claytonac07ed82019-03-26 14:17:41 +000023
Ben Clayton713b8d32019-12-17 20:37:56 +000024# include "llvm/Demangle/Demangle.h"
25# include "llvm/ExecutionEngine/JITEventListener.h"
26# include "llvm/IR/DIBuilder.h"
27# include "llvm/IR/IRBuilder.h"
28# include "llvm/IR/Intrinsics.h"
Ben Claytonac07ed82019-03-26 14:17:41 +000029
Ben Clayton713b8d32019-12-17 20:37:56 +000030# include <cctype>
31# include <fstream>
32# include <mutex>
33# include <regex>
34# include <sstream>
35# include <string>
Ben Claytonac07ed82019-03-26 14:17:41 +000036
Ben Clayton713b8d32019-12-17 20:37:56 +000037# if 0
38# define LOG(msg, ...) printf(msg "\n", ##__VA_ARGS__)
39# else
40# define LOG(msg, ...)
41# endif
Ben Claytonac07ed82019-03-26 14:17:41 +000042
Nicolas Capens157ba262019-12-10 17:49:14 -050043namespace {
44
Ben Clayton713b8d32019-12-17 20:37:56 +000045std::pair<llvm::StringRef, llvm::StringRef> splitPath(const char *path)
Ben Claytonac07ed82019-03-26 14:17:41 +000046{
Nicolas Capens157ba262019-12-10 17:49:14 -050047 return llvm::StringRef(path).rsplit('/');
48}
Ben Clayton90cb2602019-05-23 14:42:32 +010049
Nicolas Capens157ba262019-12-10 17:49:14 -050050// Note: createGDBRegistrationListener() returns a pointer to a singleton.
51// Nothing is actually created.
Ben Clayton713b8d32019-12-17 20:37:56 +000052auto jitEventListener = llvm::JITEventListener::createGDBRegistrationListener(); // guarded by jitEventListenerMutex
Nicolas Capens157ba262019-12-10 17:49:14 -050053std::mutex jitEventListenerMutex;
Ben Clayton90cb2602019-05-23 14:42:32 +010054
Ben Clayton713b8d32019-12-17 20:37:56 +000055} // namespace
Ben Claytonac07ed82019-03-26 14:17:41 +000056
Nicolas Capens157ba262019-12-10 17:49:14 -050057namespace rr {
58
59DebugInfo::DebugInfo(
Ben Clayton713b8d32019-12-17 20:37:56 +000060 llvm::IRBuilder<> *builder,
61 llvm::LLVMContext *context,
62 llvm::Module *module,
63 llvm::Function *function)
64 : builder(builder)
65 , context(context)
66 , module(module)
67 , function(function)
Ben Claytonac07ed82019-03-26 14:17:41 +000068{
Nicolas Capens157ba262019-12-10 17:49:14 -050069 using namespace ::llvm;
Ben Claytonac07ed82019-03-26 14:17:41 +000070
Nicolas Capens157ba262019-12-10 17:49:14 -050071 auto location = getCallerLocation();
Ben Claytonac07ed82019-03-26 14:17:41 +000072
Nicolas Capens157ba262019-12-10 17:49:14 -050073 auto fileAndDir = splitPath(location.function.file.c_str());
74 diBuilder.reset(new llvm::DIBuilder(*module));
75 diCU = diBuilder->createCompileUnit(
Ben Clayton713b8d32019-12-17 20:37:56 +000076 llvm::dwarf::DW_LANG_C,
77 diBuilder->createFile(fileAndDir.first, fileAndDir.second),
78 "Reactor",
79 0, "", 0);
Ben Claytonac07ed82019-03-26 14:17:41 +000080
Nicolas Capens157ba262019-12-10 17:49:14 -050081 registerBasicTypes();
Ben Claytonac07ed82019-03-26 14:17:41 +000082
Nicolas Capens157ba262019-12-10 17:49:14 -050083 SmallVector<Metadata *, 8> EltTys;
84 auto funcTy = diBuilder->createSubroutineType(diBuilder->getOrCreateTypeArray(EltTys));
Ben Claytonac07ed82019-03-26 14:17:41 +000085
Nicolas Capens157ba262019-12-10 17:49:14 -050086 auto file = getOrCreateFile(location.function.file.c_str());
87 auto sp = diBuilder->createFunction(
Ben Clayton713b8d32019-12-17 20:37:56 +000088 file, // scope
89 "ReactorFunction", // function name
90 "ReactorFunction", // linkage
91 file, // file
92 location.line, // line
93 funcTy, // type
94 false, // internal linkage
95 true, // definition
96 location.line, // scope line
97 DINode::FlagPrototyped, // flags
98 false // is optimized
Nicolas Capens157ba262019-12-10 17:49:14 -050099 );
100 diSubprogram = sp;
101 function->setSubprogram(sp);
102 diRootLocation = DILocation::get(*context, location.line, 0, sp);
103 builder->SetCurrentDebugLocation(diRootLocation);
104}
Ben Claytonac07ed82019-03-26 14:17:41 +0000105
Nicolas Capens157ba262019-12-10 17:49:14 -0500106DebugInfo::~DebugInfo() = default;
Ben Clayton90cb2602019-05-23 14:42:32 +0100107
Nicolas Capens157ba262019-12-10 17:49:14 -0500108void DebugInfo::Finalize()
109{
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500110 while(diScope.size() > 0)
Ben Claytonac07ed82019-03-26 14:17:41 +0000111 {
Ben Clayton90cb2602019-05-23 14:42:32 +0100112 emitPending(diScope.back(), builder);
Nicolas Capens157ba262019-12-10 17:49:14 -0500113 diScope.pop_back();
114 }
115 diBuilder->finalize();
116}
117
118void DebugInfo::EmitLocation()
119{
Ben Clayton713b8d32019-12-17 20:37:56 +0000120 auto const &backtrace = getCallerBacktrace();
Nicolas Capens157ba262019-12-10 17:49:14 -0500121 syncScope(backtrace);
122 builder->SetCurrentDebugLocation(getLocation(backtrace, backtrace.size() - 1));
123
Ben Clayton713b8d32019-12-17 20:37:56 +0000124# ifdef ENABLE_RR_EMIT_PRINT_LOCATION
Nicolas Capens157ba262019-12-10 17:49:14 -0500125 static Location lastLocation;
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500126 if(backtrace.size() == 0)
Nicolas Capens157ba262019-12-10 17:49:14 -0500127 {
128 return;
129 }
130 Location currLocation = backtrace[backtrace.size() - 1];
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500131 if(currLocation != lastLocation)
Nicolas Capens157ba262019-12-10 17:49:14 -0500132 {
133 rr::Print("rr> {0} [{1}:{2}]\n", currLocation.function.name.c_str(), currLocation.function.file.c_str(), currLocation.line);
134 lastLocation = std::move(currLocation);
135 }
Ben Clayton713b8d32019-12-17 20:37:56 +0000136# endif // ENABLE_RR_EMIT_PRINT_LOCATION
Nicolas Capens157ba262019-12-10 17:49:14 -0500137}
138
139void DebugInfo::Flush()
140{
141 emitPending(diScope.back(), builder);
142}
143
Ben Clayton713b8d32019-12-17 20:37:56 +0000144void DebugInfo::syncScope(Backtrace const &backtrace)
Nicolas Capens157ba262019-12-10 17:49:14 -0500145{
Ben Clayton713b8d32019-12-17 20:37:56 +0000146 auto shrink = [this](size_t newsize) {
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500147 while(diScope.size() > newsize)
Nicolas Capens157ba262019-12-10 17:49:14 -0500148 {
149 auto &scope = diScope.back();
150 LOG("- STACK(%d): di: %p, location: %s:%d",
Ben Clayton713b8d32019-12-17 20:37:56 +0000151 int(diScope.size() - 1), scope.di,
152 scope.location.function.file.c_str(),
153 int(scope.location.line));
Nicolas Capens157ba262019-12-10 17:49:14 -0500154 emitPending(scope, builder);
155 diScope.pop_back();
156 }
157 };
158
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500159 if(backtrace.size() < diScope.size())
Nicolas Capens157ba262019-12-10 17:49:14 -0500160 {
161 shrink(backtrace.size());
Ben Claytonac07ed82019-03-26 14:17:41 +0000162 }
163
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500164 for(size_t i = 0; i < diScope.size(); i++)
Ben Claytonac07ed82019-03-26 14:17:41 +0000165 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500166 auto &scope = diScope[i];
167 auto const &oldLocation = scope.location;
168 auto const &newLocation = backtrace[i];
Ben Claytonac07ed82019-03-26 14:17:41 +0000169
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500170 if(oldLocation.function != newLocation.function)
Ben Claytonac07ed82019-03-26 14:17:41 +0000171 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500172 LOG(" STACK(%d): Changed function %s -> %s", int(i),
Ben Clayton713b8d32019-12-17 20:37:56 +0000173 oldLocation.function.name.c_str(), newLocation.function.name.c_str());
Nicolas Capens157ba262019-12-10 17:49:14 -0500174 shrink(i);
175 break;
Ben Claytonac07ed82019-03-26 14:17:41 +0000176 }
177
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500178 if(oldLocation.line > newLocation.line)
Ben Claytonac07ed82019-03-26 14:17:41 +0000179 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500180 // Create a new di block to shadow all the variables in the loop.
181 auto file = getOrCreateFile(newLocation.function.file.c_str());
182 auto di = diBuilder->createLexicalBlock(scope.di, file, newLocation.line, 0);
183 LOG(" STACK(%d): Jumped backwards %d -> %d. di: %p -> %p", int(i),
Ben Clayton713b8d32019-12-17 20:37:56 +0000184 oldLocation.line, newLocation.line, scope.di, di);
Nicolas Capens157ba262019-12-10 17:49:14 -0500185 emitPending(scope, builder);
Ben Clayton713b8d32019-12-17 20:37:56 +0000186 scope = { newLocation, di };
187 shrink(i + 1);
Nicolas Capens157ba262019-12-10 17:49:14 -0500188 break;
Ben Claytonac07ed82019-03-26 14:17:41 +0000189 }
190
Nicolas Capens157ba262019-12-10 17:49:14 -0500191 scope.location = newLocation;
Ben Claytonac07ed82019-03-26 14:17:41 +0000192 }
193
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500194 while(backtrace.size() > diScope.size())
Ben Claytonac07ed82019-03-26 14:17:41 +0000195 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500196 auto i = diScope.size();
197 auto location = backtrace[i];
198 auto file = getOrCreateFile(location.function.file.c_str());
199 auto funcTy = diBuilder->createSubroutineType(diBuilder->getOrCreateTypeArray({}));
200
201 char buf[1024];
202 size_t size = sizeof(buf);
203 int status = 0;
204 llvm::itaniumDemangle(location.function.name.c_str(), buf, &size, &status);
205 auto name = "jit!" + (status == 0 ? std::string(buf) : location.function.name);
206
207 auto func = diBuilder->createFunction(
Ben Clayton713b8d32019-12-17 20:37:56 +0000208 file, // scope
209 name, // function name
210 "", // linkage
211 file, // file
212 location.line, // line
213 funcTy, // type
214 false, // internal linkage
215 true, // definition
216 location.line, // scope line
217 llvm::DINode::FlagPrototyped, // flags
218 false // is optimized
Ben Claytonac07ed82019-03-26 14:17:41 +0000219 );
Ben Clayton713b8d32019-12-17 20:37:56 +0000220 diScope.push_back({ location, func });
Nicolas Capens157ba262019-12-10 17:49:14 -0500221 LOG("+ STACK(%d): di: %p, location: %s:%d", int(i), di,
Ben Clayton713b8d32019-12-17 20:37:56 +0000222 location.function.file.c_str(), int(location.line));
Ben Claytonac07ed82019-03-26 14:17:41 +0000223 }
Nicolas Capens157ba262019-12-10 17:49:14 -0500224}
Ben Claytonac07ed82019-03-26 14:17:41 +0000225
Ben Clayton713b8d32019-12-17 20:37:56 +0000226llvm::DILocation *DebugInfo::getLocation(const Backtrace &backtrace, size_t i)
Nicolas Capens157ba262019-12-10 17:49:14 -0500227{
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500228 if(backtrace.size() == 0) { return nullptr; }
Nicolas Capens157ba262019-12-10 17:49:14 -0500229 assert(backtrace.size() == diScope.size());
230 return llvm::DILocation::get(
Ben Clayton713b8d32019-12-17 20:37:56 +0000231 *context,
232 backtrace[i].line,
233 0,
234 diScope[i].di,
235 i > 0 ? getLocation(backtrace, i - 1) : diRootLocation);
Nicolas Capens157ba262019-12-10 17:49:14 -0500236}
237
238void DebugInfo::EmitVariable(Value *variable)
239{
Ben Clayton713b8d32019-12-17 20:37:56 +0000240 auto const &backtrace = getCallerBacktrace();
Nicolas Capens157ba262019-12-10 17:49:14 -0500241 syncScope(backtrace);
242
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500243 for(int i = backtrace.size() - 1; i >= 0; i--)
Ben Claytonac07ed82019-03-26 14:17:41 +0000244 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500245 auto const &location = backtrace[i];
246 auto tokens = getOrParseFileTokens(location.function.file.c_str());
247 auto tokIt = tokens->find(location.line);
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500248 if(tokIt == tokens->end())
Ben Claytonac07ed82019-03-26 14:17:41 +0000249 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500250 break;
Ben Claytonac07ed82019-03-26 14:17:41 +0000251 }
Nicolas Capens157ba262019-12-10 17:49:14 -0500252 auto token = tokIt->second;
253 auto name = token.identifier;
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500254 if(token.kind == Token::Return)
Ben Claytonac07ed82019-03-26 14:17:41 +0000255 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500256 // This is a:
Ben Claytonac07ed82019-03-26 14:17:41 +0000257 //
Nicolas Capens157ba262019-12-10 17:49:14 -0500258 // return <expr>;
Ben Claytonac07ed82019-03-26 14:17:41 +0000259 //
Nicolas Capens157ba262019-12-10 17:49:14 -0500260 // Emit this expression as two variables -
261 // Once as a synthetic 'return_value' variable at this scope.
262 // Again by bubbling the expression value up the callstack as
263 // Return Value Optimizations (RVOs) are likely to carry across
264 // the value to a local without calling a constructor in
265 // statements like:
266 //
267 // auto val = foo();
268 //
269 name = "return_value";
Ben Claytonac07ed82019-03-26 14:17:41 +0000270 }
271
Nicolas Capens157ba262019-12-10 17:49:14 -0500272 auto &scope = diScope[i];
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500273 if(scope.pending.location != location)
Ben Claytonac07ed82019-03-26 14:17:41 +0000274 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500275 emitPending(scope, builder);
276 }
277
278 auto value = V(variable);
279 auto block = builder->GetInsertBlock();
280
281 auto insertAfter = block->size() > 0 ? &block->back() : nullptr;
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500282 while(insertAfter != nullptr && insertAfter->isTerminator())
Nicolas Capens157ba262019-12-10 17:49:14 -0500283 {
284 insertAfter = insertAfter->getPrevNode();
Ben Claytonac07ed82019-03-26 14:17:41 +0000285 }
286
287 scope.pending = Pending{};
Nicolas Capens157ba262019-12-10 17:49:14 -0500288 scope.pending.name = name;
289 scope.pending.location = location;
290 scope.pending.diLocation = getLocation(backtrace, i);
291 scope.pending.value = value;
292 scope.pending.block = block;
293 scope.pending.insertAfter = insertAfter;
294 scope.pending.scope = scope.di;
Ben Claytonac07ed82019-03-26 14:17:41 +0000295
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500296 if(token.kind == Token::Return)
Antonio Maioranof448d8e2019-04-26 16:19:16 -0400297 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500298 // Insert a noop instruction so the debugger can inspect the
299 // return value before the function scope closes.
300 scope.pending.addNopOnNextLine = true;
301 }
302 else
303 {
304 break;
305 }
306 }
307}
Ben Claytonac07ed82019-03-26 14:17:41 +0000308
Nicolas Capens157ba262019-12-10 17:49:14 -0500309void DebugInfo::emitPending(Scope &scope, IRBuilder *builder)
310{
311 auto const &pending = scope.pending;
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500312 if(pending.value == nullptr)
Nicolas Capens157ba262019-12-10 17:49:14 -0500313 {
314 return;
315 }
Antonio Maioranof448d8e2019-04-26 16:19:16 -0400316
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500317 if(!scope.symbols.emplace(pending.name).second)
Nicolas Capens157ba262019-12-10 17:49:14 -0500318 {
319 return;
320 }
321
322 bool isAlloca = llvm::isa<llvm::AllocaInst>(pending.value);
323
324 LOG(" EMIT(%s): di: %p, location: %s:%d, isAlloca: %s", pending.name.c_str(), scope.di,
Ben Clayton713b8d32019-12-17 20:37:56 +0000325 pending.location.function.file.c_str(), pending.location.line, isAlloca ? "true" : "false");
Nicolas Capens157ba262019-12-10 17:49:14 -0500326
327 auto value = pending.value;
328
329 IRBuilder::InsertPointGuard guard(*builder);
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500330 if(pending.insertAfter != nullptr)
Nicolas Capens157ba262019-12-10 17:49:14 -0500331 {
332 builder->SetInsertPoint(pending.block, ++pending.insertAfter->getIterator());
333 }
334 else
335 {
336 builder->SetInsertPoint(pending.block);
337 }
338 builder->SetCurrentDebugLocation(pending.diLocation);
339
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500340 if(!isAlloca)
Nicolas Capens157ba262019-12-10 17:49:14 -0500341 {
342 // While insertDbgValueIntrinsic should be enough to declare a
343 // variable with no storage, variables of RValues can share the same
344 // llvm::Value, and only one can be named. Take for example:
345 //
346 // Int a = 42;
347 // RValue<Int> b = a;
348 // RValue<Int> c = b;
349 //
350 // To handle this, always promote named RValues to an alloca.
351
352 llvm::BasicBlock &entryBlock = function->getEntryBlock();
353 auto alloca = new llvm::AllocaInst(value->getType(), 0, pending.name);
354 entryBlock.getInstList().push_front(alloca);
355 builder->CreateStore(value, alloca);
356 value = alloca;
357 }
358
359 value->setName(pending.name);
360
361 auto diFile = getOrCreateFile(pending.location.function.file.c_str());
362 auto diType = getOrCreateType(value->getType()->getPointerElementType());
363 auto diVar = diBuilder->createAutoVariable(scope.di, pending.name, diFile, pending.location.line, diType);
364
365 auto di = diBuilder->insertDeclare(value, diVar, diBuilder->createExpression(), pending.diLocation, pending.block);
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500366 if(pending.insertAfter != nullptr) { di->moveAfter(pending.insertAfter); }
Nicolas Capens157ba262019-12-10 17:49:14 -0500367
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500368 if(pending.addNopOnNextLine)
Nicolas Capens157ba262019-12-10 17:49:14 -0500369 {
370 builder->SetCurrentDebugLocation(llvm::DILocation::get(
Ben Clayton713b8d32019-12-17 20:37:56 +0000371 *context,
372 pending.diLocation->getLine() + 1,
373 0,
374 pending.diLocation->getScope(),
375 pending.diLocation->getInlinedAt()));
Nicolas Capens157ba262019-12-10 17:49:14 -0500376 Nop();
377 }
378
379 scope.pending = Pending{};
380}
381
382void DebugInfo::NotifyObjectEmitted(const llvm::object::ObjectFile &Obj, const llvm::LoadedObjectInfo &L)
383{
384 std::unique_lock<std::mutex> lock(jitEventListenerMutex);
Ben Clayton713b8d32019-12-17 20:37:56 +0000385 jitEventListener->NotifyObjectEmitted(Obj, static_cast<const llvm::RuntimeDyld::LoadedObjectInfo &>(L));
Nicolas Capens157ba262019-12-10 17:49:14 -0500386}
387
388void DebugInfo::NotifyFreeingObject(const llvm::object::ObjectFile &Obj)
389{
390 std::unique_lock<std::mutex> lock(jitEventListenerMutex);
391 jitEventListener->NotifyFreeingObject(Obj);
392}
393
394void DebugInfo::registerBasicTypes()
395{
396 using namespace rr;
397 using namespace llvm;
398
399 auto vec4 = diBuilder->getOrCreateArray(diBuilder->getOrCreateSubrange(0, 4));
400 auto vec8 = diBuilder->getOrCreateArray(diBuilder->getOrCreateSubrange(0, 8));
401 auto vec16 = diBuilder->getOrCreateArray(diBuilder->getOrCreateSubrange(0, 16));
402
403 diTypes.emplace(T(Bool::getType()), diBuilder->createBasicType("Bool", sizeof(bool), dwarf::DW_ATE_boolean));
404 diTypes.emplace(T(Byte::getType()), diBuilder->createBasicType("Byte", 8, dwarf::DW_ATE_unsigned_char));
405 diTypes.emplace(T(SByte::getType()), diBuilder->createBasicType("SByte", 8, dwarf::DW_ATE_signed_char));
406 diTypes.emplace(T(Short::getType()), diBuilder->createBasicType("Short", 16, dwarf::DW_ATE_signed));
407 diTypes.emplace(T(UShort::getType()), diBuilder->createBasicType("UShort", 16, dwarf::DW_ATE_unsigned));
408 diTypes.emplace(T(Int::getType()), diBuilder->createBasicType("Int", 32, dwarf::DW_ATE_signed));
409 diTypes.emplace(T(UInt::getType()), diBuilder->createBasicType("UInt", 32, dwarf::DW_ATE_unsigned));
410 diTypes.emplace(T(Long::getType()), diBuilder->createBasicType("Long", 64, dwarf::DW_ATE_signed));
411 diTypes.emplace(T(Half::getType()), diBuilder->createBasicType("Half", 16, dwarf::DW_ATE_float));
412 diTypes.emplace(T(Float::getType()), diBuilder->createBasicType("Float", 32, dwarf::DW_ATE_float));
413
Ben Clayton713b8d32019-12-17 20:37:56 +0000414 diTypes.emplace(T(Byte4::getType()), diBuilder->createVectorType(128, 128, diTypes[T(Byte::getType())], { vec16 }));
415 diTypes.emplace(T(SByte4::getType()), diBuilder->createVectorType(128, 128, diTypes[T(SByte::getType())], { vec16 }));
416 diTypes.emplace(T(Byte8::getType()), diBuilder->createVectorType(128, 128, diTypes[T(Byte::getType())], { vec16 }));
417 diTypes.emplace(T(SByte8::getType()), diBuilder->createVectorType(128, 128, diTypes[T(SByte::getType())], { vec16 }));
418 diTypes.emplace(T(Byte16::getType()), diBuilder->createVectorType(128, 128, diTypes[T(Byte::getType())], { vec16 }));
419 diTypes.emplace(T(SByte16::getType()), diBuilder->createVectorType(128, 128, diTypes[T(SByte::getType())], { vec16 }));
420 diTypes.emplace(T(Short2::getType()), diBuilder->createVectorType(128, 128, diTypes[T(Short::getType())], { vec8 }));
421 diTypes.emplace(T(UShort2::getType()), diBuilder->createVectorType(128, 128, diTypes[T(UShort::getType())], { vec8 }));
422 diTypes.emplace(T(Short4::getType()), diBuilder->createVectorType(128, 128, diTypes[T(Short::getType())], { vec8 }));
423 diTypes.emplace(T(UShort4::getType()), diBuilder->createVectorType(128, 128, diTypes[T(UShort::getType())], { vec8 }));
424 diTypes.emplace(T(Short8::getType()), diBuilder->createVectorType(128, 128, diTypes[T(Short::getType())], { vec8 }));
425 diTypes.emplace(T(UShort8::getType()), diBuilder->createVectorType(128, 128, diTypes[T(UShort::getType())], { vec8 }));
426 diTypes.emplace(T(Int2::getType()), diBuilder->createVectorType(128, 128, diTypes[T(Int::getType())], { vec4 }));
427 diTypes.emplace(T(UInt2::getType()), diBuilder->createVectorType(128, 128, diTypes[T(UInt::getType())], { vec4 }));
428 diTypes.emplace(T(Int4::getType()), diBuilder->createVectorType(128, 128, diTypes[T(Int::getType())], { vec4 }));
429 diTypes.emplace(T(UInt4::getType()), diBuilder->createVectorType(128, 128, diTypes[T(UInt::getType())], { vec4 }));
430 diTypes.emplace(T(Float2::getType()), diBuilder->createVectorType(128, 128, diTypes[T(Float::getType())], { vec4 }));
431 diTypes.emplace(T(Float4::getType()), diBuilder->createVectorType(128, 128, diTypes[T(Float::getType())], { vec4 }));
Nicolas Capens157ba262019-12-10 17:49:14 -0500432}
433
434DebugInfo::Location DebugInfo::getCallerLocation() const
435{
436 return getCallerBacktrace(1)[0];
437}
438
439DebugInfo::Backtrace DebugInfo::getCallerBacktrace(size_t limit /* = 0 */) const
440{
441 auto shouldSkipFile = [](llvm::StringRef fileSR) {
Ben Clayton713b8d32019-12-17 20:37:56 +0000442 return fileSR.empty() ||
443 fileSR.endswith_lower("ReactorDebugInfo.cpp") ||
444 fileSR.endswith_lower("Reactor.cpp") ||
445 fileSR.endswith_lower("Reactor.hpp") ||
446 fileSR.endswith_lower("stacktrace.hpp");
Nicolas Capens157ba262019-12-10 17:49:14 -0500447 };
448
449 std::vector<DebugInfo::Location> locations;
450
451 // Note that bs::stacktrace() effectively returns a vector of addresses; bs::frame construction is where
452 // the heavy lifting is done: resolving the function name, file and line number.
453 namespace bs = boost::stacktrace;
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500454 for(bs::frame frame : bs::stacktrace())
Nicolas Capens157ba262019-12-10 17:49:14 -0500455 {
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500456 if(shouldSkipFile(frame.source_file()))
Nicolas Capens157ba262019-12-10 17:49:14 -0500457 {
458 continue;
Antonio Maioranof448d8e2019-04-26 16:19:16 -0400459 }
460
Nicolas Capens157ba262019-12-10 17:49:14 -0500461 DebugInfo::Location location;
462 location.function.file = frame.source_file();
463 location.function.name = frame.name();
464 location.line = frame.source_line();
465 locations.push_back(location);
Antonio Maioranof448d8e2019-04-26 16:19:16 -0400466
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500467 if(limit > 0 && locations.size() >= limit)
Ben Claytonac07ed82019-03-26 14:17:41 +0000468 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500469 break;
Ben Claytonac07ed82019-03-26 14:17:41 +0000470 }
Ben Claytonac07ed82019-03-26 14:17:41 +0000471 }
472
Nicolas Capens157ba262019-12-10 17:49:14 -0500473 std::reverse(locations.begin(), locations.end());
474
475 return locations;
476}
477
Ben Clayton713b8d32019-12-17 20:37:56 +0000478llvm::DIType *DebugInfo::getOrCreateType(llvm::Type *type)
Nicolas Capens157ba262019-12-10 17:49:14 -0500479{
480 auto it = diTypes.find(type);
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500481 if(it != diTypes.end()) { return it->second; }
Nicolas Capens157ba262019-12-10 17:49:14 -0500482
483 if(type->isPointerTy())
Ben Claytonac07ed82019-03-26 14:17:41 +0000484 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500485 auto dbgTy = diBuilder->createPointerType(
Ben Clayton713b8d32019-12-17 20:37:56 +0000486 getOrCreateType(type->getPointerElementType()),
487 sizeof(void *) * 8, alignof(void *) * 8);
Nicolas Capens157ba262019-12-10 17:49:14 -0500488 diTypes.emplace(type, dbgTy);
489 return dbgTy;
490 }
491 llvm::errs() << "Unimplemented debug type: " << type << "\n";
492 assert(false);
493 return nullptr;
494}
495
Ben Clayton713b8d32019-12-17 20:37:56 +0000496llvm::DIFile *DebugInfo::getOrCreateFile(const char *path)
Nicolas Capens157ba262019-12-10 17:49:14 -0500497{
498 auto it = diFiles.find(path);
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500499 if(it != diFiles.end()) { return it->second; }
Nicolas Capens157ba262019-12-10 17:49:14 -0500500 auto dirAndName = splitPath(path);
501 auto file = diBuilder->createFile(dirAndName.second, dirAndName.first);
502 diFiles.emplace(path, file);
503 return file;
504}
505
Ben Clayton713b8d32019-12-17 20:37:56 +0000506DebugInfo::LineTokens const *DebugInfo::getOrParseFileTokens(const char *path)
Nicolas Capens157ba262019-12-10 17:49:14 -0500507{
508 static std::regex reLocalDecl(
Ben Clayton713b8d32019-12-17 20:37:56 +0000509 "^" // line start
510 "\\s*" // initial whitespace
511 "(?:For\\s*\\(\\s*)?" // optional 'For('
512 "((?:\\w+(?:<[^>]+>)?)(?:::\\w+(?:<[^>]+>)?)*)" // type (match group 1)
513 "\\s+" // whitespace between type and name
514 "(\\w+)" // identifier (match group 2)
515 "\\s*" // whitespace after identifier
516 "(\\[.*\\])?"); // optional array suffix (match group 3)
Nicolas Capens157ba262019-12-10 17:49:14 -0500517
518 auto it = fileTokens.find(path);
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500519 if(it != fileTokens.end())
Nicolas Capens157ba262019-12-10 17:49:14 -0500520 {
521 return it->second.get();
Ben Claytonac07ed82019-03-26 14:17:41 +0000522 }
523
Ben Clayton368d39c2020-01-08 23:10:47 +0000524 auto tokens = std::make_unique<LineTokens>();
Nicolas Capens157ba262019-12-10 17:49:14 -0500525
526 std::ifstream file(path);
527 std::string line;
528 int lineCount = 0;
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500529 while(std::getline(file, line))
Ben Claytonac07ed82019-03-26 14:17:41 +0000530 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500531 lineCount++;
532 std::smatch match;
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500533 if(std::regex_search(line, match, reLocalDecl) && match.size() > 3)
Ben Claytonac07ed82019-03-26 14:17:41 +0000534 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500535 bool isArray = match.str(3) != "";
Ben Clayton713b8d32019-12-17 20:37:56 +0000536 if(!isArray) // Cannot deal with C-arrays of values.
Ben Claytonac07ed82019-03-26 14:17:41 +0000537 {
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500538 if(match.str(1) == "return")
Ben Claytonac07ed82019-03-26 14:17:41 +0000539 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000540 (*tokens)[lineCount] = Token{ Token::Return };
Nicolas Capens157ba262019-12-10 17:49:14 -0500541 }
542 else
543 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000544 (*tokens)[lineCount] = Token{ Token::Identifier, match.str(2) };
Ben Claytonac07ed82019-03-26 14:17:41 +0000545 }
546 }
547 }
Ben Claytonac07ed82019-03-26 14:17:41 +0000548 }
549
Nicolas Capens157ba262019-12-10 17:49:14 -0500550 auto out = tokens.get();
551 fileTokens.emplace(path, std::move(tokens));
552 return out;
553}
554
555} // namespace rr
Ben Claytonac07ed82019-03-26 14:17:41 +0000556
Ben Clayton713b8d32019-12-17 20:37:56 +0000557#endif // ENABLE_RR_DEBUG_INFO