-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathir.h
461 lines (411 loc) · 14 KB
/
ir.h
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
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
# pragma once
#include <experimental/optional>
#include "types.h"
#include "include/x64asm.h"
struct IrInstruction;
struct IrFunc;
struct Temp;
using namespace std;
typedef shared_ptr<IrInstruction> instptr_t;
typedef vector<instptr_t> IrInstList;
typedef experimental::optional<int32_t> optint_t;
typedef experimental::optional<string> optstr_t;
typedef int64_t offset_t;
typedef shared_ptr<Temp> tempptr_t;
typedef experimental::optional<tempptr_t> opttemp_t;
typedef vector<tempptr_t> TempList;
typedef shared_ptr<TempList> TempListPtr;
typedef experimental::optional<x64asm::R64> optreg_t;
struct Temp {
int index;
optreg_t reg = nullopt;
optint_t stackOffset = nullopt;
int startInterval = -1;
int endInterval = -1;
Temp(int i) : index(i) {}
};
static string asmRegToString(x64asm::R64 reg) {
switch(reg) {
case x64asm::rdi:
{
return "rdi";
}
case x64asm::rsi:
{
return "rsi";
}
case x64asm::rax:
{
return "rax";
}
case x64asm::rbx:
{
return "rbx";
}
case x64asm::rcx:
{
return "rcx";
}
case x64asm::rdx:
{
return "rdx";
}
case x64asm::r8:
{
return "r8";
}
case x64asm::r9:
{
return "r9";
}
case x64asm::r10:
{
return "r10";
}
case x64asm::r11:
{
return "r11";
}
case x64asm::r12:
{
return "r12";
}
case x64asm::r13:
{
return "r13";
}
case x64asm::r14:
{
return "r14";
}
case x64asm::r15:
{
return "r15";
}
default:
return "reg";
}
}
enum class IrOp {
// Description: Move a constant from constants array into temp var
// op0: index into the constants array of the constant to move
// temp0: temp index to store the constant in
// Result: temp0 stores func.constants_[operand1]
LoadConst,
// Description: Load a function from functions list into temp
// op0: index into functions array to move
// temp0: temp index to store the funtion in
// Result: temp0 stores the specified function
LoadFunc,
// Description: Load a global into a temp
// op0: N/A
// name0: name of the global to load
// temp0: temp index to store into
// Result: temp at temp0 contains the global var indicated by its name
LoadGlobal,
// Description: Store a value from a temp into a local
// temp1: temp representing the val to store
// temp0: temp representing the local to store into
// Result: the local at index op0 contains the value stored by the temp at temp0
StoreLocal,
// Description: Store a value from a temp into a global
// op0: N/A
// name0: name of the global to store into
// temp0: temp index containing the value to store
// Result: the global named contains the value stored by temp0
StoreGlobal,
// Description: Store a reference to a free variable into a temp
// op0: index of the free var to store the reference of
// temp0: temp index to store reference into
// Result: temp at temp0 contains reference to the local variable
PushFreeRef,
// Description: Load the value of a reference into a temp
// temp0: temp index to store into
// temp1: the temp storing the reference to load
// Result: temp at temp0 contains value of the reference
LoadReference,
// Description: Store the value of a temp into a local ref
// temp0: temp of the local to store into
// temp1: index of the temp w/ the val to store
// Result: local temp0 contains the value in temp0
StoreLocalRef,
// Description: Allocate a record and store it to a temp
// op0: N/A
// temp0: temp index to allocate the record in
// Result: temp at temp0 contains a new empty record
AllocRecord,
// Description: Load a value from a record and store it into a temp
// op0: N/A
// name0: name of the field to load from
// temp0: temp index to store the field's value into
// temp1: temp index containing the record to look in (must be record)
// Result: temp at temp0 contains the value of the field
FieldLoad,
// Description: Store a value into a record's field
// op0: N/A
// name0: name of the field to store into
// temp0: temp index containing the record to store into (must be record)
// temp1: temp index containing the field's new value
// Result: temp at temp0 points to record with the new value set
FieldStore,
// Description: Load a value from a record and store it into a temp
// op0: N/A
// temp0: temp index to store the field's value into
// temp1: temp index containing the record to look in (must be record)
// temp2: temp index containing the field
// Result: temp at temp0 contains the value of the field
IndexLoad,
// Description: Store a value into a record's field
// op0: N/A
// temp0: temp index containing the record to store into (must be record)
// temp1: temp index containing the field's new value
// temp2: temp index containing the index/field
// Result: temp at temp0 points to record with the new value set
IndexStore,
// Description: Allocate a new closure
// op0: number of free vars passed to the closure
// temp0: temp index containing the new closure
// temp1: temp index containing the function
// temps 2-m: temps containing references to the free vars we are going to pass
// Result: temp at temp0 now contains the new closure
AllocClosure,
// Description: call a closure
// op0: number of args passed to the function
// temp0: temp index that will contain the return val
// temp1: temp index containing the closure to call (must be closure)
// temp 2-m: temps containing values of the args we are passing
// Result: temp at temp0 contains the result of calling the function
Call,
// Description: return from a function
// op0: N/A
// temp0: temp index containing return value
// Result: return from the function
Return,
// Description: add the constants in two temps (semantics from A2)
// op0: N/A
// temp0: temp index to store the result value in
// temp1: temp index holding right value
// temp2: temp index holding left value
// Result: temp at temp0 stores the result of doing temp2 + temp1
Add,
// Description: performs arithmetic operation on two temps
// op0: N/A
// temp0: temp index to store the result value in
// temp1: temp index holding right value (must be int)
// temp2: temp index holding left value (must be int)
// Result: temp at temp0 stores the result of doing op(temp2, temp1)
Sub,
Mul,
Div,
// Description: computes unary minus
// op0: N/A
// temp0: temp index to store the result value in
// temp1: value to negate (must be int)
// Result: temp at temp0 stores -temp1
Neg,
// Description: computes a comparison on ints
// op0: N/A
// temp0: temp index to store the result value in
// temp1: temp index holding right value (must be int)
// temp2: temp index holding left value (must be int)
// Result: temp at temp0 stores bool indicating result of comparison
Gt,
Geq,
// Description: computes an equality between two vals (semantics from A2)
// op0: N/A
// temp0: temp index to store the result value in
// temp1: temp index holding right value
// temp2: temp index holding left value
// Result: temp at temp0 stores bool eq(temp2, temp1)
Eq,
// Description: computes a boolean operation
// op0: N/A
// temp0: temp index to store the result value in
// temp1: temp index holding right value (must be bool)
// temp2: temp index holding left value (must be bool)
// Result: temp at temp0 stores bool op(temp2, temp1)
And,
Or,
// Description: computes boolean negation
// op0: N/A
// temp0: temp index to store the result value in
// temp1: temp index holding value to negate (must be bool)
// Result: temp at temp0 stores !operand1
Not,
// Description: move to a given label
// op0: index of the label to jump to; should be unique
// Result: transfers execution to the label
Goto,
// Description: move to a given label
// op0: index of the label to jump to conditionally; should be unique
// temp0: temp index holding value to check (must be bool)
// Result: transfers execution to the label if temp at temp0 is true
If,
// Description: asserts that a temp is an integer
// op0: N/A
// temp0: temp index of value to check
// Result: throws RuntimeError if the temp is not an integer
AssertInteger,
// Description: asserts that a temp is a bool
// op0: N/A
// temp0: temp index of value to check
// Result: throws RuntimeError if the temp is not a bool
AssertBoolean,
// Description: asserts that a temp is a string
// op0: N/A
// temp0: temp index of value to check
// Result: throws RuntimeError if the temp is not a string
AssertString,
// Description: asserts that a temp is an record
// op0: N/A
// temp0: temp index of value to check
// Result: throws RuntimeError if the temp is not an record
AssertRecord,
// Description: asserts that a temp is a function
// op0: N/A
// temp0: temp index of value to check
// Result: throws RuntimeError if the temp is not a function
AssertFunction,
// Description: asserts that a temp is a closure
// op0: N/A
// temp0: temp index of value to check
// Result: throws RuntimeError if the temp is not a closure
AssertClosure,
// Description: asserts that a temp is a val wrapper
// op0: N/A
// temp0: temp index of value to check
// Result: throws RuntimeError if the temp is not a val wrapper
AssertValWrapper,
// Description: unboxes a temp to integer
// op0: N/A
// temp0: temp index where the int will be stored
// temp1: temp index of the value to unbox; must be a tagged tagptr_t
// Result: stores int(temp1) in temp0
UnboxInteger,
// Description: unboxes a temp to bool
// op0: N/A
// temp0: temp index where bool will be stored
// temp1: temp index of the value to unbox; must be a tagged tagptr_t
// Result: stores bool(temp1) in temp0
UnboxBoolean,
// Description: takes a raw int and creates an Integer object
// temp0: temp to hold the new Integer object
// temp1: holds the int value
// Result: stores tagptr_t(temp1) in temp0
NewInteger,
// Description: takes a raw bool and creates a Boolean object
// temp0: temp to hold the new Boolean object
// temp1: holds the bool value
// Result: stores tagptr_t(temp1) in temp0
NewBoolean,
// Description: takes an object and casts it to a string
// temp0: temp to hold the new String object
// temp1: holds the thing to cast
// Result: stores String(temp1) in temp0
CastString,
// Description: add a label at this point in the generated asm
// op0: index of label to add
// Result: adds label_op0 to this point in asm execution
AddLabel,
// Description: runs the garbage collector
GarbageCollect
};
// Each instruction contains an optional op0 and an array of temps storing its
// return value and other operands.
// By convention, if the operation stores a value somewhere, it is put in
// extraTemps[0].
struct IrInstruction {
IrOp op;
optint_t op0;
optstr_t name0;
TempListPtr tempIndices;
IrInstruction(const IrOp op, optint_t op0):
op(op),
name0(),
op0(op0),
tempIndices(make_shared<TempList>()) {};
IrInstruction(const IrOp op, tempptr_t temp0, tempptr_t temp1):
op(op),
name0(),
op0(),
tempIndices(make_shared<TempList>(TempList{temp0, temp1})) {};
IrInstruction(const IrOp op, optstr_t name0, tempptr_t temp):
op(op),
name0(name0),
op0(),
tempIndices(make_shared<TempList>(TempList{temp})) {};
IrInstruction(const IrOp op, optstr_t name0, TempListPtr tempIndices):
op(op),
name0(name0),
op0(),
tempIndices(tempIndices) {};
IrInstruction(const IrOp op, optint_t op0, TempListPtr tempIndices):
op(op),
op0(op0),
name0(),
tempIndices(tempIndices) {};
IrInstruction(const IrOp op, optint_t op0, tempptr_t temp):
op(op),
op0(op0),
name0(),
tempIndices(make_shared<TempList>(TempList{temp})) {};
IrInstruction(const IrOp op, tempptr_t temp):
op(op),
op0(),
name0(),
tempIndices(make_shared<TempList>(TempList{temp})) {};
IrInstruction(const IrOp op, TempListPtr tempIndices):
op(op),
op0(),
name0(),
tempIndices(tempIndices) {};
string getInfo() {
string s;
if (op0) {
s += "\top0: " + to_string(op0.value()) + "\n";
}
if (name0) {
s += "\tname0: " + name0.value() + "\n";
}
s += "\ttemps:";
for (tempptr_t t : *tempIndices) {
s += " #";
s += to_string(t->index) + " ";
if (t->reg) {
s += "(" + asmRegToString(t->reg.value()) + ")";
}
if (t->stackOffset) {
s += "(stack " + to_string(t->stackOffset.value()) + ")";
}
}
return s;
}
};
struct IrFunc {
IrInstList instructions;
vector<tagptr_t> constants_;
vector<Function*> functions_;
vector<tempptr_t> temps;
int temp_count;
int32_t parameter_count_;
int32_t local_count_;
// TODO: rn hard-coding this at 0, but we need to actually keep track
// of our refs somehow in the ir-interpreter
int32_t ref_count_ = 0;
IrFunc(IrInstList instructions,
vector<tagptr_t> constants_,
vector<Function*> functions_,
vector<tempptr_t> temps,
int temp_count,
int32_t parameter_count_,
int32_t local_count_,
int32_t ref_count_) :
instructions(instructions),
constants_(constants_),
temps(temps),
temp_count(temp_count),
functions_(functions_),
parameter_count_(parameter_count_),
local_count_(local_count_),
ref_count_(ref_count_) {};
};