-
Notifications
You must be signed in to change notification settings - Fork 46
/
Copy pathdebug.bal
230 lines (208 loc) · 8.6 KB
/
debug.bal
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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
import wso2/nballerina.bir;
import wso2/nballerina.print.llvm;
import wso2/nballerina.types as t;
import wso2/nballerina.comm.err;
type DIBuilder llvm:DIBuilder;
type DISubprogram llvm:Metadata;
type DILocation llvm:Metadata;
type DIFile llvm:Metadata;
type DICompileUnit llvm:Metadata;
type DISubroutineType llvm:Metadata;
type DIScope llvm:Metadata;
type Scope record {|
DIScope diScope;
bir:Position startPos;
bir:Position endPos;
Scope[] childScopes;
|};
type ModuleDI record {|
DIBuilder builder;
DIFile[] files;
DICompileUnit compileUnit;
DISubroutineType funcType;
boolean debugFull;
|};
type DwarfType "int"|"float"|"boolean"|"any";
// Debug location will always be added
public const int DEBUG_USAGE_ERROR_CONSTRUCT = 0;
public const int DEBUG_USAGE_CALL = 1;
public type DebugLocationUsage DEBUG_USAGE_ERROR_CONSTRUCT|DEBUG_USAGE_CALL;
class DIScaffold {
private Scaffold scaffold;
private map<llvm:Metadata> typeMetadata = {};
private boolean debugFull;
final Scope rootScope;
final DIBuilder diBuilder;
final DIFile diFile;
private bir:Position? currentPosition = ();
private DILocation? noLineLocation = ();
private DILocation? currentDebugLocation = ();
function init(DISubprogram diFunc, ModuleDI moduleDI, Scaffold scaffold, bir:Position startPos, int partIndex) {
self.rootScope = { diScope: diFunc, startPos, endPos: int:MAX_VALUE, childScopes: [] };
self.diBuilder = moduleDI.builder;
self.diFile = moduleDI.files[partIndex];
self.debugFull = moduleDI.debugFull;
self.scaffold = scaffold;
}
function registerTypeToMetadata(bir:Register register) returns llvm:Metadata {
t:SemType semType = register.semType;
DwarfType ty = semTypeToDWARF(semType);
llvm:Metadata? stored = self.typeMetadata[ty];
if stored !is () {
return stored;
}
llvm:Metadata tyMeta = DwarfTypeMetadata(ty, self.diBuilder, self.diFile);
self.typeMetadata[ty] = tyMeta;
return tyMeta;
}
function createScope(bir:Position startPos, bir:Position endPos, Scope parent, Scope[] childScopes) returns Scope {
var [line, column] = self.scaffold.lineColumn(startPos);
DIScope diScope = self.diBuilder.createLexicalBlock(parent.diScope, self.diFile, line, column);
return { diScope, startPos, endPos, childScopes };
}
// we use a seperate declPosition instead of startPos of registerScope since register scope starts at the begining of the Stmt/Function
function currentPos() returns bir:Position {
return <bir:Position> self.currentPosition;
}
function clearDebugLocation(llvm:Builder builder) {
// in debugFull case every instruction must have a debug location
if !self.debugFull {
builder.setCurrentDebugLocation(());
self.currentDebugLocation = ();
}
}
function setCurrentPosition(llvm:Builder builder, bir:Position pos) {
self.currentPosition = pos;
if self.debugFull {
self.currentDebugLocation = self.debugLocation(pos);
builder.setCurrentDebugLocation(self.currentDebugLocation);
}
else {
self.currentDebugLocation = ();
}
}
function useDebugLocation(llvm:Builder builder, DebugLocationUsage usage) {
// In the debugFull case, there is no need to do anything for DEBUG_USAGE_ERROR_CONSTRUCT
// because the full location will have been set earlier.
if usage == DEBUG_USAGE_ERROR_CONSTRUCT && self.debugFull {
return;
}
DILocation loc;
if usage == DEBUG_USAGE_ERROR_CONSTRUCT {
DILocation? noLineLoc = self.noLineLocation;
if noLineLoc == () {
loc = self.debugLocation(0);
self.noLineLocation = loc;
}
else {
loc = noLineLoc;
}
}
else {
if self.currentDebugLocation == () {
self.currentDebugLocation = self.debugLocation(self.currentPos());
}
loc = <DILocation>self.currentDebugLocation;
}
builder.setCurrentDebugLocation(loc);
}
function debugLocation(bir:Position pos) returns DILocation {
var [line, column] = self.scaffold.lineColumn(pos);
return self.diBuilder.createDebugLocation(line, column, diScope(pos, self.rootScope));
}
}
function diScope(bir:Position pos, Scope parent) returns DIScope {
foreach var child in parent.childScopes {
if child.startPos <= pos && child.endPos >= pos {
return diScope(pos, child);
}
}
return parent.diScope;
}
function semTypeToDWARF(t:SemType semType) returns DwarfType {
if t:isSubtypeSimple(semType, t:INT) {
return "int";
}
else if t:isSubtypeSimple(semType, t:FLOAT) {
return "float";
}
else if t:isSubtypeSimple(semType, t:BOOLEAN) {
return "boolean";
}
else {
return "any";
}
}
function DwarfTypeMetadata(DwarfType ty, DIBuilder diBuilder, DIFile diFile) returns llvm:Metadata {
match ty {
"int" => {
return diBuilder.createBasicType(name="int", encoding="signed", sizeInBits=64);
}
"float" => {
return diBuilder.createBasicType(name="float", encoding="float", sizeInBits=64);
}
"boolean" => {
return diBuilder.createBasicType(name="boolean", encoding="boolean", sizeInBits=1);
}
_ => {
llvm:Metadata charMeta = diBuilder.createBasicType(name="char", encoding="signed_char", sizeInBits=8);
return diBuilder.createTypedef(diBuilder.createPointerType(pointeeTy=charMeta, sizeInBits=64, addressSpace=1),
"TaggedPtr", diFile, 0, scope=diFile);
}
}
}
function declareVariables(Scaffold scaffold, DIScaffold diScaffold, llvm:BasicBlock initBlock, bir:Register[] registers) {
llvm:Metadata emptyExpr = diScaffold.diBuilder.createExpression([]);
foreach bir:Register register in registers {
if register !is bir:DeclRegister {
continue;
}
Scope scope = addToParentScope(register.scope, register.pos, diScaffold.rootScope, diScaffold);
var [line, column] = scaffold.lineColumn(register.pos);
llvm:Metadata tyMeta = diScaffold.registerTypeToMetadata(register);
declareVariable(initBlock, register, diScaffold.diBuilder, diScaffold.diFile, scope.diScope, emptyExpr, tyMeta, scaffold.address(register), line, column);
}
}
function addToParentScope(bir:RegisterScope registerScope, bir:Position declPos, Scope parent, DIScaffold diScaffold) returns Scope {
int childCount = parent.childScopes.length();
int? addIndex = ();
foreach int i in 0 ..< childCount {
Scope child = parent.childScopes[i];
if declPos < child.startPos {
if registerScope.endPos > child.startPos {
if registerScope.endPos < child.endPos {
// this should never happen
panic err:impossible("unexpected scope");
}
Scope newScope = diScaffold.createScope(declPos, registerScope.endPos, parent, [child]);
parent.childScopes[i] = newScope;
return newScope;
}
addIndex = i;
break;
}
else if child.startPos == declPos && child.endPos == registerScope.endPos {
// we already have the scope
return child;
}
else if child.startPos < declPos && child.endPos >= registerScope.endPos {
return addToParentScope(registerScope, declPos, child, diScaffold);
}
}
Scope newScope = diScaffold.createScope(declPos, registerScope.endPos, parent, []);
if addIndex is () {
parent.childScopes.push(newScope);
}
else {
Scope[] newChildScopes = parent.childScopes.slice(0, addIndex);
newChildScopes.push(newScope, ...parent.childScopes.slice(addIndex));
parent.childScopes = newChildScopes;
}
return newScope;
}
function declareVariable(llvm:BasicBlock bb, bir:DeclRegister register, DIBuilder diBuilder, DIFile diFile, DIScope diScope, llvm:Metadata expr,
llvm:Metadata tyMeta, llvm:Value value, int line, int column) {
llvm:Metadata varMeta = diBuilder.createAutoVariable(ty=tyMeta, scope=diScope, name=register.name, lineNo=line, file=diFile);
llvm:Metadata declLoc = diBuilder.createDebugLocation(line, column, diScope);
diBuilder.insertDeclareAtEnd(value=value, varInfo=varMeta, expr=expr, debugLoc=declLoc, block=bb);
}