-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCGDebug.cpp
More file actions
111 lines (94 loc) · 3.7 KB
/
Copy pathCGDebug.cpp
File metadata and controls
111 lines (94 loc) · 3.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
// CGDebug.cpp — DWARF debug info emission (U3, epic 001-toolchain-and-stdlib).
//
// All helpers are no-ops when mDebugInfo is false, so a non-`-g` build produces
// byte-identical IR to pre-U3. Design: docs/epics/001-toolchain-and-stdlib/
// design-debug-info.md; spec: specs/025-debug-info/spec.md.
#include "CodeGen.h"
#include "llvm/IR/DIBuilder.h"
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/Module.h"
using namespace QLang;
// Split a source path into (directory, filename) and return a cached DIFile.
// --combine gives each .b its own DIFile so line tables name the correct source.
llvm::DIFile *CodeGen::getOrCreateDIFile( const std::string &path )
{
if ( !mDebugInfo || mDIBuilder == nullptr )
return nullptr;
auto it = mDIFileCache.find( path );
if ( it != mDIFileCache.end() )
return it->second;
std::string dir;
std::string file = path;
size_t slash = path.find_last_of( '/' );
if ( slash != std::string::npos )
{
dir = path.substr( 0, slash );
file = path.substr( slash + 1 );
}
if ( dir.empty() )
dir = ".";
llvm::DIFile *dif = mDIBuilder->createFile( file, dir );
mDIFileCache[path] = dif;
return dif;
}
// Attach a DISubprogram to an LLVM function and make it the current scope.
// A minimal DISubroutineType (unspecified params) is verifier-legal for v1;
// richer parameter types are a documented nice-to-have (spec §B).
llvm::DISubprogram *CodeGen::createDISubprogram( llvm::Function *llvmFunc,
const SourceLocation &loc, const std::string &name )
{
if ( !mDebugInfo || mDIBuilder == nullptr || llvmFunc == nullptr )
return nullptr;
// A function whose location is unset (synthetic) is anchored on the compile
// unit's primary file at line 0 rather than dropped, so every emitted
// function carries a subprogram (keeps emission verifier-clean under -O).
std::string filePath = loc.isSet() ? loc.file : "";
llvm::DIFile *dif = filePath.empty()
? ( mDICompileUnit ? mDICompileUnit->getFile() : nullptr )
: getOrCreateDIFile( filePath );
if ( dif == nullptr )
return nullptr;
unsigned line = loc.isSet() ? loc.line : 0;
// Minimal subroutine type: one null element == unspecified return/params.
llvm::SmallVector<llvm::Metadata*, 1> eltTys;
eltTys.push_back( nullptr );
llvm::DISubroutineType *subTy = mDIBuilder->createSubroutineType(
mDIBuilder->getOrCreateTypeArray( eltTys ) );
llvm::DISubprogram *sp = mDIBuilder->createFunction(
dif, name, llvmFunc->getName(), dif, line, subTy, line,
llvm::DINode::FlagPrototyped,
llvm::DISubprogram::SPFlagDefinition );
llvmFunc->setSubprogram( sp );
mCurrentDISubprogram = sp;
return sp;
}
// Set the IRBuilder's current DebugLoc from a source location, scoped to the
// function currently being generated. ARC/scope-exit instructions emitted while
// this is set inherit a valid location (verifier-clean under -O, spec §F).
void CodeGen::applyDebugLoc( const SourceLocation &loc )
{
if ( !mDebugInfo || mCurrentDISubprogram == nullptr )
return;
unsigned line = loc.isSet() ? loc.line : 0;
unsigned col = loc.isSet() ? loc.col : 0;
mBuilder->SetCurrentDebugLocation(
llvm::DILocation::get( *mContext, line, col, mCurrentDISubprogram ) );
}
// Reset builder debug state on leaving a function so no stale scope leaks into
// the next function's instructions.
void CodeGen::clearDebugLoc()
{
if ( !mDebugInfo )
return;
mBuilder->SetCurrentDebugLocation( llvm::DebugLoc() );
mCurrentDISubprogram = nullptr;
}
// Finalize all debug metadata. MUST run after codegen and before print() —
// unfinalized DWARF metadata is invalid and the verifier rejects it (spec §E).
void CodeGen::finalizeDebugInfo()
{
if ( !mDebugInfo || mDIBuilder == nullptr || mDebugFinalized )
return;
mDIBuilder->finalize();
mDebugFinalized = true;
}