Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
epidemian
GitHub Repository: epidemian/gravity
Path: blob/master/src/compiler/gravity_ircode.c
1214 views
1
//
2
// gravity_ircode.c
3
// gravity
4
//
5
// Created by Marco Bambini on 06/11/14.
6
// Copyright (c) 2014 CreoLabs. All rights reserved.
7
//
8
9
#include "gravity_ircode.h"
10
#include "gravity_value.h"
11
#include "gravity_debug.h"
12
13
typedef marray_t(inst_t *) code_r;
14
typedef marray_t(bool *) context_r;
15
16
struct ircode_t {
17
code_r *list; // array of ircode instructions
18
19
uint32_r label_true; // labels used in loops
20
uint32_r label_false;
21
uint32_t label_counter;
22
23
uint32_t maxtemp; // maximum number of temp registers used in this ircode
24
uint32_t ntemps; // current number of temp registers in use
25
uint16_t nlocals; // number of local registers (params + local variables)
26
bool error; // error flag set when no more registers are availables
27
28
bool state[MAX_REGISTERS]; // registers mask
29
uint32_r registers; // registers stack
30
context_r context; // context array
31
};
32
33
ircode_t *ircode_create (uint16_t nlocals) {
34
ircode_t *code = (ircode_t *)mem_alloc(sizeof(ircode_t));
35
code->label_counter = 0;
36
code->nlocals = nlocals;
37
code->ntemps = 0;
38
code->maxtemp = 0;
39
code->error = false;
40
41
code->list = mem_alloc(sizeof(code_r));
42
marray_init(*code->list);
43
marray_init(code->label_true);
44
marray_init(code->label_false);
45
marray_init(code->registers);
46
marray_init(code->context);
47
48
// init state array (register 0 is reserved)
49
bzero(code->state, MAX_REGISTERS * sizeof(bool));
50
code->state[0] = true;
51
for (uint32_t i=0; i<nlocals; ++i) {
52
code->state[i] = true;
53
}
54
return code;
55
}
56
57
#if 0
58
static void dump_context(bool *context) {
59
for (uint32_t i=0; i<MAX_REGISTERS; ++i) {
60
printf("%d ", context[i]);
61
}
62
printf("\n");
63
}
64
#endif
65
66
void ircode_push_context (ircode_t *code) {
67
bool *context = mem_alloc(sizeof(bool) * MAX_REGISTERS);
68
marray_push(bool *, code->context, context);
69
}
70
71
void ircode_pop_context (ircode_t *code) {
72
bool *context = marray_pop(code->context);
73
// apply context mask
74
for (uint32_t i=0; i<MAX_REGISTERS; ++i) {
75
if (context[i]) code->state[i] = false;
76
}
77
mem_free(context);
78
}
79
80
static void ircode_add_context (ircode_t *code, uint32_t n) {
81
bool *context = marray_last(code->context);
82
context[n] = true;
83
}
84
85
void ircode_free (ircode_t *code) {
86
uint32_t count = ircode_count(code);
87
for (uint32_t i=0; i<count; ++i) {
88
inst_t *inst = marray_get(*code->list, i);
89
mem_free(inst);
90
}
91
92
marray_destroy(*code->list);
93
marray_destroy(code->registers);
94
marray_destroy(code->label_true);
95
marray_destroy(code->label_false);
96
mem_free(code->list);
97
mem_free(code);
98
}
99
100
uint32_t ircode_ntemps (ircode_t *code) {
101
return code->ntemps;
102
}
103
104
uint32_t ircode_count (ircode_t *code) {
105
return (uint32_t)marray_size(*code->list);
106
}
107
108
inst_t *ircode_get (ircode_t *code, uint32_t index) {
109
uint32_t n = (uint32_t)marray_size(*code->list);
110
if (index == IRCODE_LATEST) index = n-1;
111
return (index >= n) ? NULL : marray_get(*code->list, index);
112
}
113
114
bool ircode_iserror (ircode_t *code) {
115
return code->error;
116
}
117
// MARK: -
118
119
static inst_t *inst_new (opcode_t op, uint32_t p1, uint32_t p2, uint32_t p3, optag_t tag, int64_t n, double d) {
120
121
// debug code
122
#if GRAVITY_OPCODE_DEBUG
123
if (tag == LABEL_TAG) {
124
DEBUG_OPCODE("LABEL %d", p1);
125
} else {
126
const char *op_name = opcode_name(op);
127
128
if (op == LOADI) {
129
if (tag == DOUBLE_TAG)
130
printf("%s %d %.2f\n", op_name, p1, d);
131
else
132
printf("%s %d %lld\n", op_name, p1, n);
133
} else {
134
int nop = opcode_numop(op);
135
if (nop == 0) {
136
DEBUG_OPCODE("%s", op_name);
137
} else if (nop == 1) {
138
DEBUG_OPCODE("%s %d", op_name, p1);
139
} else if (nop == 2) {
140
DEBUG_OPCODE("%s %d %d", op_name, p1, p2);
141
} else if (nop == 3) {
142
DEBUG_OPCODE("%s %d %d %d", opcode_name(op), p1, p2, p3);
143
}
144
}
145
}
146
#endif
147
148
inst_t *inst = (inst_t *)mem_alloc(sizeof(inst_t));
149
inst->op = op;
150
inst->tag = tag;
151
inst->p1 = p1;
152
inst->p2 = p2;
153
inst->p3 = p3;
154
155
if (tag == DOUBLE_TAG) inst->d = d;
156
else if (tag == INT_TAG) inst->n = n;
157
158
assert(inst);
159
return inst;
160
}
161
162
void inst_setskip (inst_t *inst) {
163
inst->tag = SKIP_TAG;
164
}
165
166
void ircode_patch_init (ircode_t *code, uint16_t index) {
167
// prepend call instructions to code
168
// LOADK temp index
169
// LOAD temp 0 temp
170
// MOVE temp+1 0
171
// CALL temp temp 1
172
173
// load constant
174
uint32_t dest = ircode_register_push_temp(code);
175
inst_t *inst1 = inst_new(LOADK, dest, index, 0, NO_TAG, 0, 0.0);
176
177
// load from lookup
178
inst_t *inst2 = inst_new(LOAD, dest, 0, dest, NO_TAG, 0, 0.0);
179
180
// prepare parameter
181
uint32_t dest2 = ircode_register_push_temp(code);
182
inst_t *inst3 = inst_new(MOVE, dest2, 0, 0, NO_TAG, 0, 0.0);
183
ircode_register_pop(code);
184
185
// execute call
186
inst_t *inst4 = inst_new(CALL, dest, dest, 1, NO_TAG, 0, 0.0);
187
188
// pop temps used
189
ircode_register_pop(code);
190
191
// create new instruction list
192
code_r *list = mem_alloc(sizeof(code_r));
193
marray_init(*list);
194
195
// add newly create instructions
196
marray_push(inst_t*, *list, inst1);
197
marray_push(inst_t*, *list, inst2);
198
marray_push(inst_t*, *list, inst3);
199
marray_push(inst_t*, *list, inst4);
200
201
// then copy original instructions
202
code_r *orig_list = code->list;
203
uint32_t count = ircode_count(code);
204
for (uint32_t i=0; i<count; ++i) {
205
inst_t *inst = marray_get(*orig_list, i);
206
marray_push(inst_t*, *list, inst);
207
}
208
209
// free dest list
210
marray_destroy(*orig_list);
211
mem_free(code->list);
212
213
// replace dest list with the newly created list
214
code->list = list;
215
}
216
217
uint8_t opcode_numop (opcode_t op) {
218
switch (op) {
219
case HALT: return 0;
220
case NOP: return 0;
221
case RET0: return 0;
222
case RET: return 1;
223
case CALL: return 3;
224
case SETLIST: return 3;
225
case LOADK: return 2;
226
case LOADG: return 2;
227
case LOADI: return 2;
228
case LOADAT: return 3;
229
case LOADS: return 3;
230
case LOAD: return 3;
231
case LOADU: return 2;
232
case MOVE: return 2;
233
case STOREG: return 2;
234
case STOREAT: return 3;
235
case STORE: return 3;
236
case STOREU: return 2;
237
case JUMP: return 1;
238
case JUMPF: return 2;
239
case SWITCH: return 1;
240
case ADD: return 3;
241
case SUB: return 3;
242
case DIV: return 3;
243
case MUL: return 3;
244
case REM: return 3;
245
case AND: return 3;
246
case OR: return 3;
247
case LT: return 3;
248
case GT: return 3;
249
case EQ: return 3;
250
case ISA: return 3;
251
case MATCH: return 3;
252
case EQQ: return 3;
253
case LEQ: return 3;
254
case GEQ: return 3;
255
case NEQ: return 3;
256
case NEQQ: return 3;
257
case NEG: return 2;
258
case NOT: return 2;
259
case LSHIFT: return 3;
260
case RSHIFT: return 3;
261
case BAND: return 3;
262
case BOR: return 3;
263
case BXOR: return 3;
264
case BNOT: return 2;
265
case MAPNEW: return 2;
266
case LISTNEW: return 2;
267
case RANGENEW: return 3;
268
case CLOSURE: return 2;
269
case CLOSE: return 1;
270
case RESERVED1:
271
case RESERVED2:
272
case RESERVED3:
273
case RESERVED4:
274
case RESERVED5:
275
case RESERVED6: return 0;
276
}
277
278
assert(0);
279
return 0;
280
}
281
282
void ircode_dump (void *_code) {
283
ircode_t *code = (ircode_t *)_code;
284
code_r *list = code->list;
285
uint32_t count = ircode_count(code);
286
287
if (count == 0) {
288
printf("NONE\n");
289
return;
290
}
291
292
for (uint32_t i=0, line=0; i<count; ++i) {
293
inst_t *inst = marray_get(*list, i);
294
opcode_t op = inst->op;
295
int32_t p1 = inst->p1;
296
int32_t p2 = inst->p2;
297
int32_t p3 = inst->p3;
298
if (inst->tag == SKIP_TAG) continue;
299
if (inst->tag == LABEL_TAG) {printf("LABEL %d:\n", p1); continue;}
300
301
uint8_t n = opcode_numop(op);
302
if ((op == SETLIST) && (p2 == 0)) n = 2;
303
304
switch (n) {
305
case 0: {
306
printf("%05d\t%s\n", line, opcode_name(op));
307
}
308
309
case 1: {
310
printf("%05d\t%s %d\n", line, opcode_name(op), p1);
311
} break;
312
313
case 2: {
314
if (op == LOADI) {
315
if (inst->tag == DOUBLE_TAG) printf("%05d\t%s %d %.2f\n", line, opcode_name(op), p1, inst->d);
316
else printf("%05d\t%s %d %lld\n", line, opcode_name(op), p1, inst->n);
317
} else if (op == LOADK) {
318
if (p2 < CPOOL_INDEX_MAX) printf("%05d\t%s %d %d\n", line, opcode_name(op), p1, p2);
319
else printf("%05d\t%s %d %s\n", line, opcode_name(op), p1, opcode_constname(p2));
320
} else {
321
printf("%05d\t%s %d %d\n", line, opcode_name(op), p1, p2);
322
}
323
} break;
324
325
case 3: {
326
printf("%05d\t%s %d %d %d\n", line, opcode_name(op), p1, p2, p3);
327
} break;
328
329
default: assert(0);
330
}
331
++line;
332
}
333
}
334
335
// MARK: -
336
337
uint32_t ircode_newlabel (ircode_t *code) {
338
return ++code->label_counter;
339
}
340
341
void ircode_setlabel_true (ircode_t *code, uint32_t nlabel) {
342
marray_push(uint32_t, code->label_true, nlabel);
343
}
344
345
void ircode_setlabel_false (ircode_t *code, uint32_t nlabel) {
346
marray_push(uint32_t, code->label_false, nlabel);
347
}
348
349
void ircode_unsetlabel_true (ircode_t *code) {
350
marray_pop(code->label_true);
351
}
352
353
void ircode_unsetlabel_false (ircode_t *code) {
354
marray_pop(code->label_false);
355
}
356
357
uint32_t ircode_getlabel_true (ircode_t *code) {
358
size_t n = marray_size(code->label_true);
359
uint32_t v = marray_get(code->label_true, n-1);
360
return v;
361
}
362
363
uint32_t ircode_getlabel_false (ircode_t *code) {
364
size_t n = marray_size(code->label_false);
365
uint32_t v = marray_get(code->label_false, n-1);
366
return v;
367
}
368
369
void ircode_marklabel (ircode_t *code, uint32_t nlabel) {
370
inst_t *inst = inst_new(0, nlabel, 0, 0, LABEL_TAG, 0, 0.0);
371
marray_push(inst_t*, *code->list, inst);
372
}
373
374
// MARK: -
375
376
void ircode_set_index (uint32_t index, ircode_t *code, opcode_t op, uint32_t p1, uint32_t p2, uint32_t p3) {
377
inst_t *inst = marray_get(*code->list, index);
378
inst->op = op;
379
inst->p1 = p1;
380
inst->p2 = p2;
381
inst->p3 = p3;
382
inst->tag = NO_TAG;
383
}
384
385
void ircode_add (ircode_t *code, opcode_t op, uint32_t p1, uint32_t p2, uint32_t p3) {
386
ircode_add_tag(code, op, p1, p2, p3, 0);
387
}
388
389
void ircode_add_tag (ircode_t *code, opcode_t op, uint32_t p1, uint32_t p2, uint32_t p3, optag_t tag) {
390
inst_t *inst = inst_new(op, p1, p2, p3, tag, 0, 0.0);
391
marray_push(inst_t*, *code->list, inst);
392
}
393
394
void ircode_add_double (ircode_t *code, double d) {
395
uint32_t regnum = ircode_register_push_temp(code);
396
inst_t *inst = inst_new(LOADI, regnum, 0, 0, DOUBLE_TAG, 0, d);
397
marray_push(inst_t*, *code->list, inst);
398
}
399
400
void ircode_add_constant (ircode_t *code, uint32_t index) {
401
uint32_t regnum = ircode_register_push_temp(code);
402
inst_t *inst = inst_new(LOADK, regnum, index, 0, NO_TAG, 0, 0);
403
marray_push(inst_t*, *code->list, inst);
404
}
405
406
void ircode_add_int (ircode_t *code, int64_t n) {
407
uint32_t regnum = ircode_register_push_temp(code);
408
inst_t *inst = inst_new(LOADI, regnum, 0, 0, INT_TAG, n, 0);
409
marray_push(inst_t*, *code->list, inst);
410
}
411
412
void ircode_add_skip (ircode_t *code) {
413
inst_t *inst = inst_new(0, 0, 0, 0, NO_TAG, 0, 0);
414
inst_setskip(inst);
415
marray_push(inst_t*, *code->list, inst);
416
}
417
418
// MARK: -
419
420
static uint32_t ircode_register_new (ircode_t *code) {
421
for (uint32_t i=0; i<MAX_REGISTERS; ++i) {
422
if (code->state[i] == false) {
423
code->state[i] = true;
424
return i;
425
}
426
}
427
// 0 means no registers available
428
code->error = true;
429
return 0;
430
}
431
432
uint32_t ircode_register_push (ircode_t *code, uint32_t nreg) {
433
marray_push(uint32_t, code->registers, nreg);
434
if (nreg >= code->nlocals) ++code->ntemps;
435
436
DEBUG_REGISTER("PUSH REGISTER %d", nreg);
437
return nreg;
438
}
439
440
uint32_t ircode_register_push_temp (ircode_t *code) {
441
uint32_t value = ircode_register_new(code);
442
marray_push(uint32_t, code->registers, value);
443
if (value > code->maxtemp) {code->maxtemp = value; ++code->ntemps;}
444
445
DEBUG_REGISTER("PUSH REGISTER %d", value);
446
return value;
447
}
448
449
uint32_t ircode_register_pop (ircode_t *code) {
450
return ircode_register_pop_protect(code, false);
451
}
452
453
uint32_t ircode_register_pop_protect (ircode_t *code, bool protect) {
454
assert(marray_size(code->registers) != 0);
455
uint32_t value = (uint32_t)marray_pop(code->registers);
456
if (protect) code->state[value] = true;
457
else if (value >= code->nlocals) code->state[value] = false;
458
if (protect && value >= code->nlocals) ircode_add_context(code, value);
459
460
DEBUG_REGISTER("POP REGISTER %d", value);
461
return value;
462
}
463
464
void ircode_register_protect (ircode_t *code, uint32_t nreg) {
465
if (nreg < code->nlocals) return;
466
bool *context = marray_last(code->context);
467
context[nreg] = false;
468
}
469
470
void ircode_register_clean (ircode_t *code, uint32_t nreg) {
471
// cleanup busy mask only if it is a temp register
472
if (nreg >= code->nlocals) code->state[nreg] = false;
473
}
474
475
uint32_t ircode_register_last (ircode_t *code) {
476
assert(marray_size(code->registers) != 0);
477
uint32_t value = (uint32_t)marray_last(code->registers);
478
479
return value;
480
}
481
482
bool ircode_register_istemp (ircode_t *code, uint32_t n) {
483
uint32_t n1 = (uint32_t)code->nlocals;
484
return (n>=n1);
485
}
486
487
void ircode_register_dump (ircode_t *code) {
488
uint32_t n = (uint32_t)marray_size(code->registers);
489
if (n == 0) printf("EMPTY\n");
490
for (uint32_t i=0; i<n; ++i) {
491
uint32_t value = marray_get(code->registers, i);
492
printf("[%d]\t%d\n", i, value);
493
}
494
}
495
496
uint32_t ircode_register_count (ircode_t *code) {
497
return (uint32_t)marray_size(code->registers);
498
}
499
500