blob: 21a759ce9697341ef353b5d36092be7d324de80a [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
Nicolas Capens41a73022020-01-30 00:30:14 -050024// TODO(b/143539525): Eliminate when warning has been fixed.
25# ifdef _MSC_VER
26__pragma(warning(push))
27 __pragma(warning(disable : 4146)) // unary minus operator applied to unsigned type, result still unsigned
28# endif
29
Ben Clayton713b8d32019-12-17 20:37:56 +000030# include "llvm/Demangle/Demangle.h"
31# include "llvm/ExecutionEngine/JITEventListener.h"
32# include "llvm/IR/DIBuilder.h"
33# include "llvm/IR/IRBuilder.h"
34# include "llvm/IR/Intrinsics.h"
Ben Claytonac07ed82019-03-26 14:17:41 +000035
Nicolas Capens41a73022020-01-30 00:30:14 -050036# ifdef _MSC_VER
37 __pragma(warning(pop))
38# endif
39
Ben Clayton713b8d32019-12-17 20:37:56 +000040# include <cctype>
41# include <fstream>
42# include <mutex>
43# include <regex>
44# include <sstream>
45# include <string>
Ben Claytonac07ed82019-03-26 14:17:41 +000046
Ben Clayton713b8d32019-12-17 20:37:56 +000047# if 0
48# define LOG(msg, ...) printf(msg "\n", ##__VA_ARGS__)
49# else
50# define LOG(msg, ...)
51# endif
Ben Claytonac07ed82019-03-26 14:17:41 +000052
Nicolas Capens41a73022020-01-30 00:30:14 -050053 namespace
Ben Claytonac07ed82019-03-26 14:17:41 +000054{
Ben Clayton90cb2602019-05-23 14:42:32 +010055
Nicolas Capens41a73022020-01-30 00:30:14 -050056 std::pair<llvm::StringRef, llvm::StringRef> splitPath(const char *path)
57 {
58 return llvm::StringRef(path).rsplit('/');
59 }
60
61 // Note: createGDBRegistrationListener() returns a pointer to a singleton.
62 // Nothing is actually created.
63 auto jitEventListener = llvm::JITEventListener::createGDBRegistrationListener(); // guarded by jitEventListenerMutex
64 std::mutex jitEventListenerMutex;
Ben Clayton90cb2602019-05-23 14:42:32 +010065
Ben Clayton713b8d32019-12-17 20:37:56 +000066} // namespace
Ben Claytonac07ed82019-03-26 14:17:41 +000067
Nicolas Capens157ba262019-12-10 17:49:14 -050068namespace rr {
69
70DebugInfo::DebugInfo(
Ben Clayton713b8d32019-12-17 20:37:56 +000071 llvm::IRBuilder<> *builder,
72 llvm::LLVMContext *context,
73 llvm::Module *module,
74 llvm::Function *function)
75 : builder(builder)
76 , context(context)
77 , module(module)
78 , function(function)
Ben Claytonac07ed82019-03-26 14:17:41 +000079{
Nicolas Capens157ba262019-12-10 17:49:14 -050080 using namespace ::llvm;
Ben Claytonac07ed82019-03-26 14:17:41 +000081
Nicolas Capens157ba262019-12-10 17:49:14 -050082 auto location = getCallerLocation();
Ben Claytonac07ed82019-03-26 14:17:41 +000083
Nicolas Capens157ba262019-12-10 17:49:14 -050084 auto fileAndDir = splitPath(location.function.file.c_str());
85 diBuilder.reset(new llvm::DIBuilder(*module));
86 diCU = diBuilder->createCompileUnit(
Ben Clayton713b8d32019-12-17 20:37:56 +000087 llvm::dwarf::DW_LANG_C,
88 diBuilder->createFile(fileAndDir.first, fileAndDir.second),
89 "Reactor",
90 0, "", 0);
Ben Claytonac07ed82019-03-26 14:17:41 +000091
Nicolas Capens157ba262019-12-10 17:49:14 -050092 registerBasicTypes();
Ben Claytonac07ed82019-03-26 14:17:41 +000093
Nicolas Capens157ba262019-12-10 17:49:14 -050094 SmallVector<Metadata *, 8> EltTys;
95 auto funcTy = diBuilder->createSubroutineType(diBuilder->getOrCreateTypeArray(EltTys));
Ben Claytonac07ed82019-03-26 14:17:41 +000096
Nicolas Capens157ba262019-12-10 17:49:14 -050097 auto file = getOrCreateFile(location.function.file.c_str());
98 auto sp = diBuilder->createFunction(
Ben Clayton713b8d32019-12-17 20:37:56 +000099 file, // scope
100 "ReactorFunction", // function name
101 "ReactorFunction", // linkage
102 file, // file
103 location.line, // line
104 funcTy, // type
105 false, // internal linkage
106 true, // definition
107 location.line, // scope line
108 DINode::FlagPrototyped, // flags
109 false // is optimized
Nicolas Capens157ba262019-12-10 17:49:14 -0500110 );
111 diSubprogram = sp;
112 function->setSubprogram(sp);
113 diRootLocation = DILocation::get(*context, location.line, 0, sp);
114 builder->SetCurrentDebugLocation(diRootLocation);
115}
Ben Claytonac07ed82019-03-26 14:17:41 +0000116
Nicolas Capens157ba262019-12-10 17:49:14 -0500117DebugInfo::~DebugInfo() = default;
Ben Clayton90cb2602019-05-23 14:42:32 +0100118
Nicolas Capens157ba262019-12-10 17:49:14 -0500119void DebugInfo::Finalize()
120{
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500121 while(diScope.size() > 0)
Ben Claytonac07ed82019-03-26 14:17:41 +0000122 {
Ben Clayton90cb2602019-05-23 14:42:32 +0100123 emitPending(diScope.back(), builder);
Nicolas Capens157ba262019-12-10 17:49:14 -0500124 diScope.pop_back();
125 }
126 diBuilder->finalize();
127}
128
129void DebugInfo::EmitLocation()
130{
Ben Clayton713b8d32019-12-17 20:37:56 +0000131 auto const &backtrace = getCallerBacktrace();
Nicolas Capens157ba262019-12-10 17:49:14 -0500132 syncScope(backtrace);
133 builder->SetCurrentDebugLocation(getLocation(backtrace, backtrace.size() - 1));
134
Ben Clayton713b8d32019-12-17 20:37:56 +0000135# ifdef ENABLE_RR_EMIT_PRINT_LOCATION
Nicolas Capens157ba262019-12-10 17:49:14 -0500136 static Location lastLocation;
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500137 if(backtrace.size() == 0)
Nicolas Capens157ba262019-12-10 17:49:14 -0500138 {
139 return;
140 }
141 Location currLocation = backtrace[backtrace.size() - 1];
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500142 if(currLocation != lastLocation)
Nicolas Capens157ba262019-12-10 17:49:14 -0500143 {
144 rr::Print("rr> {0} [{1}:{2}]\n", currLocation.function.name.c_str(), currLocation.function.file.c_str(), currLocation.line);
145 lastLocation = std::move(currLocation);
146 }
Ben Clayton713b8d32019-12-17 20:37:56 +0000147# endif // ENABLE_RR_EMIT_PRINT_LOCATION
Nicolas Capens157ba262019-12-10 17:49:14 -0500148}
149
150void DebugInfo::Flush()
151{
152 emitPending(diScope.back(), builder);
153}
154
Ben Clayton713b8d32019-12-17 20:37:56 +0000155void DebugInfo::syncScope(Backtrace const &backtrace)
Nicolas Capens157ba262019-12-10 17:49:14 -0500156{
Ben Clayton713b8d32019-12-17 20:37:56 +0000157 auto shrink = [this](size_t newsize) {
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500158 while(diScope.size() > newsize)
Nicolas Capens157ba262019-12-10 17:49:14 -0500159 {
160 auto &scope = diScope.back();
161 LOG("- STACK(%d): di: %p, location: %s:%d",
Ben Clayton713b8d32019-12-17 20:37:56 +0000162 int(diScope.size() - 1), scope.di,
163 scope.location.function.file.c_str(),
164 int(scope.location.line));
Nicolas Capens157ba262019-12-10 17:49:14 -0500165 emitPending(scope, builder);
166 diScope.pop_back();
167 }
168 };
169
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500170 if(backtrace.size() < diScope.size())
Nicolas Capens157ba262019-12-10 17:49:14 -0500171 {
172 shrink(backtrace.size());
Ben Claytonac07ed82019-03-26 14:17:41 +0000173 }
174
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500175 for(size_t i = 0; i < diScope.size(); i++)
Ben Claytonac07ed82019-03-26 14:17:41 +0000176 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500177 auto &scope = diScope[i];
178 auto const &oldLocation = scope.location;
179 auto const &newLocation = backtrace[i];
Ben Claytonac07ed82019-03-26 14:17:41 +0000180
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500181 if(oldLocation.function != newLocation.function)
Ben Claytonac07ed82019-03-26 14:17:41 +0000182 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500183 LOG(" STACK(%d): Changed function %s -> %s", int(i),
Ben Clayton713b8d32019-12-17 20:37:56 +0000184 oldLocation.function.name.c_str(), newLocation.function.name.c_str());
Nicolas Capens157ba262019-12-10 17:49:14 -0500185 shrink(i);
186 break;
Ben Claytonac07ed82019-03-26 14:17:41 +0000187 }
188
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500189 if(oldLocation.line > newLocation.line)
Ben Claytonac07ed82019-03-26 14:17:41 +0000190 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500191 // Create a new di block to shadow all the variables in the loop.
192 auto file = getOrCreateFile(newLocation.function.file.c_str());
193 auto di = diBuilder->createLexicalBlock(scope.di, file, newLocation.line, 0);
194 LOG(" STACK(%d): Jumped backwards %d -> %d. di: %p -> %p", int(i),
Ben Clayton713b8d32019-12-17 20:37:56 +0000195 oldLocation.line, newLocation.line, scope.di, di);
Nicolas Capens157ba262019-12-10 17:49:14 -0500196 emitPending(scope, builder);
Ben Clayton713b8d32019-12-17 20:37:56 +0000197 scope = { newLocation, di };
198 shrink(i + 1);
Nicolas Capens157ba262019-12-10 17:49:14 -0500199 break;
Ben Claytonac07ed82019-03-26 14:17:41 +0000200 }
201
Nicolas Capens157ba262019-12-10 17:49:14 -0500202 scope.location = newLocation;
Ben Claytonac07ed82019-03-26 14:17:41 +0000203 }
204
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500205 while(backtrace.size() > diScope.size())
Ben Claytonac07ed82019-03-26 14:17:41 +0000206 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500207 auto i = diScope.size();
208 auto location = backtrace[i];
209 auto file = getOrCreateFile(location.function.file.c_str());
210 auto funcTy = diBuilder->createSubroutineType(diBuilder->getOrCreateTypeArray({}));
211
212 char buf[1024];
213 size_t size = sizeof(buf);
214 int status = 0;
215 llvm::itaniumDemangle(location.function.name.c_str(), buf, &size, &status);
216 auto name = "jit!" + (status == 0 ? std::string(buf) : location.function.name);
217
218 auto func = diBuilder->createFunction(
Ben Clayton713b8d32019-12-17 20:37:56 +0000219 file, // scope
220 name, // function name
221 "", // linkage
222 file, // file
223 location.line, // line
224 funcTy, // type
225 false, // internal linkage
226 true, // definition
227 location.line, // scope line
228 llvm::DINode::FlagPrototyped, // flags
229 false // is optimized
Ben Claytonac07ed82019-03-26 14:17:41 +0000230 );
Ben Clayton713b8d32019-12-17 20:37:56 +0000231 diScope.push_back({ location, func });
Nicolas Capens157ba262019-12-10 17:49:14 -0500232 LOG("+ STACK(%d): di: %p, location: %s:%d", int(i), di,
Ben Clayton713b8d32019-12-17 20:37:56 +0000233 location.function.file.c_str(), int(location.line));
Ben Claytonac07ed82019-03-26 14:17:41 +0000234 }
Nicolas Capens157ba262019-12-10 17:49:14 -0500235}
Ben Claytonac07ed82019-03-26 14:17:41 +0000236
Ben Clayton713b8d32019-12-17 20:37:56 +0000237llvm::DILocation *DebugInfo::getLocation(const Backtrace &backtrace, size_t i)
Nicolas Capens157ba262019-12-10 17:49:14 -0500238{
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500239 if(backtrace.size() == 0) { return nullptr; }
Nicolas Capens157ba262019-12-10 17:49:14 -0500240 assert(backtrace.size() == diScope.size());
241 return llvm::DILocation::get(
Ben Clayton713b8d32019-12-17 20:37:56 +0000242 *context,
243 backtrace[i].line,
244 0,
245 diScope[i].di,
246 i > 0 ? getLocation(backtrace, i - 1) : diRootLocation);
Nicolas Capens157ba262019-12-10 17:49:14 -0500247}
248
249void DebugInfo::EmitVariable(Value *variable)
250{
Ben Clayton713b8d32019-12-17 20:37:56 +0000251 auto const &backtrace = getCallerBacktrace();
Nicolas Capens157ba262019-12-10 17:49:14 -0500252 syncScope(backtrace);
253
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500254 for(int i = backtrace.size() - 1; i >= 0; i--)
Ben Claytonac07ed82019-03-26 14:17:41 +0000255 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500256 auto const &location = backtrace[i];
257 auto tokens = getOrParseFileTokens(location.function.file.c_str());
258 auto tokIt = tokens->find(location.line);
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500259 if(tokIt == tokens->end())
Ben Claytonac07ed82019-03-26 14:17:41 +0000260 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500261 break;
Ben Claytonac07ed82019-03-26 14:17:41 +0000262 }
Nicolas Capens157ba262019-12-10 17:49:14 -0500263 auto token = tokIt->second;
264 auto name = token.identifier;
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500265 if(token.kind == Token::Return)
Ben Claytonac07ed82019-03-26 14:17:41 +0000266 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500267 // This is a:
Ben Claytonac07ed82019-03-26 14:17:41 +0000268 //
Nicolas Capens157ba262019-12-10 17:49:14 -0500269 // return <expr>;
Ben Claytonac07ed82019-03-26 14:17:41 +0000270 //
Nicolas Capens157ba262019-12-10 17:49:14 -0500271 // Emit this expression as two variables -
272 // Once as a synthetic 'return_value' variable at this scope.
273 // Again by bubbling the expression value up the callstack as
274 // Return Value Optimizations (RVOs) are likely to carry across
275 // the value to a local without calling a constructor in
276 // statements like:
277 //
278 // auto val = foo();
279 //
280 name = "return_value";
Ben Claytonac07ed82019-03-26 14:17:41 +0000281 }
282
Nicolas Capens157ba262019-12-10 17:49:14 -0500283 auto &scope = diScope[i];
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500284 if(scope.pending.location != location)
Ben Claytonac07ed82019-03-26 14:17:41 +0000285 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500286 emitPending(scope, builder);
287 }
288
289 auto value = V(variable);
290 auto block = builder->GetInsertBlock();
291
292 auto insertAfter = block->size() > 0 ? &block->back() : nullptr;
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500293 while(insertAfter != nullptr && insertAfter->isTerminator())
Nicolas Capens157ba262019-12-10 17:49:14 -0500294 {
295 insertAfter = insertAfter->getPrevNode();
Ben Claytonac07ed82019-03-26 14:17:41 +0000296 }
297
298 scope.pending = Pending{};
Nicolas Capens157ba262019-12-10 17:49:14 -0500299 scope.pending.name = name;
300 scope.pending.location = location;
301 scope.pending.diLocation = getLocation(backtrace, i);
302 scope.pending.value = value;
303 scope.pending.block = block;
304 scope.pending.insertAfter = insertAfter;
305 scope.pending.scope = scope.di;
Ben Claytonac07ed82019-03-26 14:17:41 +0000306
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500307 if(token.kind == Token::Return)
Antonio Maioranof448d8e2019-04-26 16:19:16 -0400308 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500309 // Insert a noop instruction so the debugger can inspect the
310 // return value before the function scope closes.
311 scope.pending.addNopOnNextLine = true;
312 }
313 else
314 {
315 break;
316 }
317 }
318}
Ben Claytonac07ed82019-03-26 14:17:41 +0000319
Nicolas Capens157ba262019-12-10 17:49:14 -0500320void DebugInfo::emitPending(Scope &scope, IRBuilder *builder)
321{
322 auto const &pending = scope.pending;
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500323 if(pending.value == nullptr)
Nicolas Capens157ba262019-12-10 17:49:14 -0500324 {
325 return;
326 }
Antonio Maioranof448d8e2019-04-26 16:19:16 -0400327
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500328 if(!scope.symbols.emplace(pending.name).second)
Nicolas Capens157ba262019-12-10 17:49:14 -0500329 {
330 return;
331 }
332
333 bool isAlloca = llvm::isa<llvm::AllocaInst>(pending.value);
334
335 LOG(" EMIT(%s): di: %p, location: %s:%d, isAlloca: %s", pending.name.c_str(), scope.di,
Ben Clayton713b8d32019-12-17 20:37:56 +0000336 pending.location.function.file.c_str(), pending.location.line, isAlloca ? "true" : "false");
Nicolas Capens157ba262019-12-10 17:49:14 -0500337
338 auto value = pending.value;
339
340 IRBuilder::InsertPointGuard guard(*builder);
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500341 if(pending.insertAfter != nullptr)
Nicolas Capens157ba262019-12-10 17:49:14 -0500342 {
343 builder->SetInsertPoint(pending.block, ++pending.insertAfter->getIterator());
344 }
345 else
346 {
347 builder->SetInsertPoint(pending.block);
348 }
349 builder->SetCurrentDebugLocation(pending.diLocation);
350
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500351 if(!isAlloca)
Nicolas Capens157ba262019-12-10 17:49:14 -0500352 {
353 // While insertDbgValueIntrinsic should be enough to declare a
354 // variable with no storage, variables of RValues can share the same
355 // llvm::Value, and only one can be named. Take for example:
356 //
357 // Int a = 42;
358 // RValue<Int> b = a;
359 // RValue<Int> c = b;
360 //
361 // To handle this, always promote named RValues to an alloca.
362
363 llvm::BasicBlock &entryBlock = function->getEntryBlock();
364 auto alloca = new llvm::AllocaInst(value->getType(), 0, pending.name);
365 entryBlock.getInstList().push_front(alloca);
366 builder->CreateStore(value, alloca);
367 value = alloca;
368 }
369
370 value->setName(pending.name);
371
372 auto diFile = getOrCreateFile(pending.location.function.file.c_str());
373 auto diType = getOrCreateType(value->getType()->getPointerElementType());
374 auto diVar = diBuilder->createAutoVariable(scope.di, pending.name, diFile, pending.location.line, diType);
375
376 auto di = diBuilder->insertDeclare(value, diVar, diBuilder->createExpression(), pending.diLocation, pending.block);
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500377 if(pending.insertAfter != nullptr) { di->moveAfter(pending.insertAfter); }
Nicolas Capens157ba262019-12-10 17:49:14 -0500378
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500379 if(pending.addNopOnNextLine)
Nicolas Capens157ba262019-12-10 17:49:14 -0500380 {
381 builder->SetCurrentDebugLocation(llvm::DILocation::get(
Ben Clayton713b8d32019-12-17 20:37:56 +0000382 *context,
383 pending.diLocation->getLine() + 1,
384 0,
385 pending.diLocation->getScope(),
386 pending.diLocation->getInlinedAt()));
Nicolas Capens157ba262019-12-10 17:49:14 -0500387 Nop();
388 }
389
390 scope.pending = Pending{};
391}
392
393void DebugInfo::NotifyObjectEmitted(const llvm::object::ObjectFile &Obj, const llvm::LoadedObjectInfo &L)
394{
395 std::unique_lock<std::mutex> lock(jitEventListenerMutex);
Ben Clayton713b8d32019-12-17 20:37:56 +0000396 jitEventListener->NotifyObjectEmitted(Obj, static_cast<const llvm::RuntimeDyld::LoadedObjectInfo &>(L));
Nicolas Capens157ba262019-12-10 17:49:14 -0500397}
398
399void DebugInfo::NotifyFreeingObject(const llvm::object::ObjectFile &Obj)
400{
401 std::unique_lock<std::mutex> lock(jitEventListenerMutex);
402 jitEventListener->NotifyFreeingObject(Obj);
403}
404
405void DebugInfo::registerBasicTypes()
406{
407 using namespace rr;
408 using namespace llvm;
409
410 auto vec4 = diBuilder->getOrCreateArray(diBuilder->getOrCreateSubrange(0, 4));
411 auto vec8 = diBuilder->getOrCreateArray(diBuilder->getOrCreateSubrange(0, 8));
412 auto vec16 = diBuilder->getOrCreateArray(diBuilder->getOrCreateSubrange(0, 16));
413
414 diTypes.emplace(T(Bool::getType()), diBuilder->createBasicType("Bool", sizeof(bool), dwarf::DW_ATE_boolean));
415 diTypes.emplace(T(Byte::getType()), diBuilder->createBasicType("Byte", 8, dwarf::DW_ATE_unsigned_char));
416 diTypes.emplace(T(SByte::getType()), diBuilder->createBasicType("SByte", 8, dwarf::DW_ATE_signed_char));
417 diTypes.emplace(T(Short::getType()), diBuilder->createBasicType("Short", 16, dwarf::DW_ATE_signed));
418 diTypes.emplace(T(UShort::getType()), diBuilder->createBasicType("UShort", 16, dwarf::DW_ATE_unsigned));
419 diTypes.emplace(T(Int::getType()), diBuilder->createBasicType("Int", 32, dwarf::DW_ATE_signed));
420 diTypes.emplace(T(UInt::getType()), diBuilder->createBasicType("UInt", 32, dwarf::DW_ATE_unsigned));
421 diTypes.emplace(T(Long::getType()), diBuilder->createBasicType("Long", 64, dwarf::DW_ATE_signed));
422 diTypes.emplace(T(Half::getType()), diBuilder->createBasicType("Half", 16, dwarf::DW_ATE_float));
423 diTypes.emplace(T(Float::getType()), diBuilder->createBasicType("Float", 32, dwarf::DW_ATE_float));
424
Ben Clayton713b8d32019-12-17 20:37:56 +0000425 diTypes.emplace(T(Byte4::getType()), diBuilder->createVectorType(128, 128, diTypes[T(Byte::getType())], { vec16 }));
426 diTypes.emplace(T(SByte4::getType()), diBuilder->createVectorType(128, 128, diTypes[T(SByte::getType())], { vec16 }));
427 diTypes.emplace(T(Byte8::getType()), diBuilder->createVectorType(128, 128, diTypes[T(Byte::getType())], { vec16 }));
428 diTypes.emplace(T(SByte8::getType()), diBuilder->createVectorType(128, 128, diTypes[T(SByte::getType())], { vec16 }));
429 diTypes.emplace(T(Byte16::getType()), diBuilder->createVectorType(128, 128, diTypes[T(Byte::getType())], { vec16 }));
430 diTypes.emplace(T(SByte16::getType()), diBuilder->createVectorType(128, 128, diTypes[T(SByte::getType())], { vec16 }));
431 diTypes.emplace(T(Short2::getType()), diBuilder->createVectorType(128, 128, diTypes[T(Short::getType())], { vec8 }));
432 diTypes.emplace(T(UShort2::getType()), diBuilder->createVectorType(128, 128, diTypes[T(UShort::getType())], { vec8 }));
433 diTypes.emplace(T(Short4::getType()), diBuilder->createVectorType(128, 128, diTypes[T(Short::getType())], { vec8 }));
434 diTypes.emplace(T(UShort4::getType()), diBuilder->createVectorType(128, 128, diTypes[T(UShort::getType())], { vec8 }));
435 diTypes.emplace(T(Short8::getType()), diBuilder->createVectorType(128, 128, diTypes[T(Short::getType())], { vec8 }));
436 diTypes.emplace(T(UShort8::getType()), diBuilder->createVectorType(128, 128, diTypes[T(UShort::getType())], { vec8 }));
437 diTypes.emplace(T(Int2::getType()), diBuilder->createVectorType(128, 128, diTypes[T(Int::getType())], { vec4 }));
438 diTypes.emplace(T(UInt2::getType()), diBuilder->createVectorType(128, 128, diTypes[T(UInt::getType())], { vec4 }));
439 diTypes.emplace(T(Int4::getType()), diBuilder->createVectorType(128, 128, diTypes[T(Int::getType())], { vec4 }));
440 diTypes.emplace(T(UInt4::getType()), diBuilder->createVectorType(128, 128, diTypes[T(UInt::getType())], { vec4 }));
441 diTypes.emplace(T(Float2::getType()), diBuilder->createVectorType(128, 128, diTypes[T(Float::getType())], { vec4 }));
442 diTypes.emplace(T(Float4::getType()), diBuilder->createVectorType(128, 128, diTypes[T(Float::getType())], { vec4 }));
Nicolas Capens157ba262019-12-10 17:49:14 -0500443}
444
445DebugInfo::Location DebugInfo::getCallerLocation() const
446{
447 return getCallerBacktrace(1)[0];
448}
449
450DebugInfo::Backtrace DebugInfo::getCallerBacktrace(size_t limit /* = 0 */) const
451{
452 auto shouldSkipFile = [](llvm::StringRef fileSR) {
Ben Clayton713b8d32019-12-17 20:37:56 +0000453 return fileSR.empty() ||
454 fileSR.endswith_lower("ReactorDebugInfo.cpp") ||
455 fileSR.endswith_lower("Reactor.cpp") ||
456 fileSR.endswith_lower("Reactor.hpp") ||
457 fileSR.endswith_lower("stacktrace.hpp");
Nicolas Capens157ba262019-12-10 17:49:14 -0500458 };
459
460 std::vector<DebugInfo::Location> locations;
461
462 // Note that bs::stacktrace() effectively returns a vector of addresses; bs::frame construction is where
463 // the heavy lifting is done: resolving the function name, file and line number.
464 namespace bs = boost::stacktrace;
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500465 for(bs::frame frame : bs::stacktrace())
Nicolas Capens157ba262019-12-10 17:49:14 -0500466 {
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500467 if(shouldSkipFile(frame.source_file()))
Nicolas Capens157ba262019-12-10 17:49:14 -0500468 {
469 continue;
Antonio Maioranof448d8e2019-04-26 16:19:16 -0400470 }
471
Nicolas Capens157ba262019-12-10 17:49:14 -0500472 DebugInfo::Location location;
473 location.function.file = frame.source_file();
474 location.function.name = frame.name();
475 location.line = frame.source_line();
476 locations.push_back(location);
Antonio Maioranof448d8e2019-04-26 16:19:16 -0400477
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500478 if(limit > 0 && locations.size() >= limit)
Ben Claytonac07ed82019-03-26 14:17:41 +0000479 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500480 break;
Ben Claytonac07ed82019-03-26 14:17:41 +0000481 }
Ben Claytonac07ed82019-03-26 14:17:41 +0000482 }
483
Nicolas Capens157ba262019-12-10 17:49:14 -0500484 std::reverse(locations.begin(), locations.end());
485
486 return locations;
487}
488
Ben Clayton713b8d32019-12-17 20:37:56 +0000489llvm::DIType *DebugInfo::getOrCreateType(llvm::Type *type)
Nicolas Capens157ba262019-12-10 17:49:14 -0500490{
491 auto it = diTypes.find(type);
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500492 if(it != diTypes.end()) { return it->second; }
Nicolas Capens157ba262019-12-10 17:49:14 -0500493
494 if(type->isPointerTy())
Ben Claytonac07ed82019-03-26 14:17:41 +0000495 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500496 auto dbgTy = diBuilder->createPointerType(
Ben Clayton713b8d32019-12-17 20:37:56 +0000497 getOrCreateType(type->getPointerElementType()),
498 sizeof(void *) * 8, alignof(void *) * 8);
Nicolas Capens157ba262019-12-10 17:49:14 -0500499 diTypes.emplace(type, dbgTy);
500 return dbgTy;
501 }
502 llvm::errs() << "Unimplemented debug type: " << type << "\n";
503 assert(false);
504 return nullptr;
505}
506
Ben Clayton713b8d32019-12-17 20:37:56 +0000507llvm::DIFile *DebugInfo::getOrCreateFile(const char *path)
Nicolas Capens157ba262019-12-10 17:49:14 -0500508{
509 auto it = diFiles.find(path);
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500510 if(it != diFiles.end()) { return it->second; }
Nicolas Capens157ba262019-12-10 17:49:14 -0500511 auto dirAndName = splitPath(path);
512 auto file = diBuilder->createFile(dirAndName.second, dirAndName.first);
513 diFiles.emplace(path, file);
514 return file;
515}
516
Ben Clayton713b8d32019-12-17 20:37:56 +0000517DebugInfo::LineTokens const *DebugInfo::getOrParseFileTokens(const char *path)
Nicolas Capens157ba262019-12-10 17:49:14 -0500518{
519 static std::regex reLocalDecl(
Ben Clayton713b8d32019-12-17 20:37:56 +0000520 "^" // line start
521 "\\s*" // initial whitespace
522 "(?:For\\s*\\(\\s*)?" // optional 'For('
523 "((?:\\w+(?:<[^>]+>)?)(?:::\\w+(?:<[^>]+>)?)*)" // type (match group 1)
524 "\\s+" // whitespace between type and name
525 "(\\w+)" // identifier (match group 2)
526 "\\s*" // whitespace after identifier
527 "(\\[.*\\])?"); // optional array suffix (match group 3)
Nicolas Capens157ba262019-12-10 17:49:14 -0500528
529 auto it = fileTokens.find(path);
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500530 if(it != fileTokens.end())
Nicolas Capens157ba262019-12-10 17:49:14 -0500531 {
532 return it->second.get();
Ben Claytonac07ed82019-03-26 14:17:41 +0000533 }
534
Ben Clayton368d39c2020-01-08 23:10:47 +0000535 auto tokens = std::make_unique<LineTokens>();
Nicolas Capens157ba262019-12-10 17:49:14 -0500536
537 std::ifstream file(path);
538 std::string line;
539 int lineCount = 0;
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500540 while(std::getline(file, line))
Ben Claytonac07ed82019-03-26 14:17:41 +0000541 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500542 lineCount++;
543 std::smatch match;
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500544 if(std::regex_search(line, match, reLocalDecl) && match.size() > 3)
Ben Claytonac07ed82019-03-26 14:17:41 +0000545 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500546 bool isArray = match.str(3) != "";
Ben Clayton713b8d32019-12-17 20:37:56 +0000547 if(!isArray) // Cannot deal with C-arrays of values.
Ben Claytonac07ed82019-03-26 14:17:41 +0000548 {
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500549 if(match.str(1) == "return")
Ben Claytonac07ed82019-03-26 14:17:41 +0000550 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000551 (*tokens)[lineCount] = Token{ Token::Return };
Nicolas Capens157ba262019-12-10 17:49:14 -0500552 }
553 else
554 {
Ben Clayton713b8d32019-12-17 20:37:56 +0000555 (*tokens)[lineCount] = Token{ Token::Identifier, match.str(2) };
Ben Claytonac07ed82019-03-26 14:17:41 +0000556 }
557 }
558 }
Ben Claytonac07ed82019-03-26 14:17:41 +0000559 }
560
Nicolas Capens157ba262019-12-10 17:49:14 -0500561 auto out = tokens.get();
562 fileTokens.emplace(path, std::move(tokens));
563 return out;
564}
565
566} // namespace rr
Ben Claytonac07ed82019-03-26 14:17:41 +0000567
Ben Clayton713b8d32019-12-17 20:37:56 +0000568#endif // ENABLE_RR_DEBUG_INFO