123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525 |
- //
- // gravity_ircode.c
- // gravity
- //
- // Created by Marco Bambini on 06/11/14.
- // Copyright (c) 2014 CreoLabs. All rights reserved.
- //
- #include "gravity_ircode.h"
- #include "gravity_value.h"
- #include "gravity_debug.h"
- typedef marray_t(inst_t *) code_r;
- typedef marray_t(bool *) context_r;
- struct ircode_t {
- code_r *list; // array of ircode instructions
-
- uint32_r label_true; // labels used in loops
- uint32_r label_false;
- uint32_t label_counter;
-
- uint32_t maxtemp; // maximum number of temp registers used in this ircode
- uint32_t ntemps; // current number of temp registers in use
- uint16_t nlocals; // number of local registers (params + local variables)
- bool error; // error flag set when no more registers are availables
-
- bool state[MAX_REGISTERS]; // registers mask
- bool skipclear[MAX_REGISTERS]; // registers protection for temps used in for loop
- uint32_r registers; // registers stack
- context_r context; // context array
- };
- ircode_t *ircode_create (uint16_t nlocals) {
- ircode_t *code = (ircode_t *)mem_alloc(sizeof(ircode_t));
- code->label_counter = 0;
- code->nlocals = nlocals;
- code->ntemps = 0;
- code->maxtemp = 0;
- code->error = false;
-
- code->list = mem_alloc(sizeof(code_r));
- marray_init(*code->list);
- marray_init(code->label_true);
- marray_init(code->label_false);
- marray_init(code->registers);
- marray_init(code->context);
-
- // init state array (register 0 is reserved)
- bzero(code->state, MAX_REGISTERS * sizeof(bool));
- code->state[0] = true;
- for (uint32_t i=0; i<nlocals; ++i) {
- code->state[i] = true;
- }
- return code;
- }
- void ircode_free (ircode_t *code) {
- uint32_t count = ircode_count(code);
- for (uint32_t i=0; i<count; ++i) {
- inst_t *inst = marray_get(*code->list, i);
- mem_free(inst);
- }
-
- marray_destroy(*code->list);
- marray_destroy(code->registers);
- marray_destroy(code->label_true);
- marray_destroy(code->label_false);
- mem_free(code->list);
- mem_free(code);
- }
- uint32_t ircode_ntemps (ircode_t *code) {
- return code->ntemps;
- }
- uint32_t ircode_count (ircode_t *code) {
- return (uint32_t)marray_size(*code->list);
- }
- inst_t *ircode_get (ircode_t *code, uint32_t index) {
- uint32_t n = (uint32_t)marray_size(*code->list);
- if (index == IRCODE_LATEST) index = n-1;
- return (index >= n) ? NULL : marray_get(*code->list, index);
- }
- bool ircode_iserror (ircode_t *code) {
- return code->error;
- }
- // MARK: -
- 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) {
-
- // debug code
- #if GRAVITY_OPCODE_DEBUG
- if (tag == LABEL_TAG) {
- DEBUG_OPCODE("LABEL %d", p1);
- } else {
- const char *op_name = opcode_name(op);
-
- if (op == LOADI) {
- if (tag == DOUBLE_TAG)
- printf("%s %d %.2f\n", op_name, p1, d);
- else
- printf("%s %d %lld\n", op_name, p1, n);
- } else {
- int nop = opcode_numop(op);
- if (nop == 0) {
- DEBUG_OPCODE("%s", op_name);
- } else if (nop == 1) {
- DEBUG_OPCODE("%s %d", op_name, p1);
- } else if (nop == 2) {
- DEBUG_OPCODE("%s %d %d", op_name, p1, p2);
- } else if (nop == 3) {
- DEBUG_OPCODE("%s %d %d %d", opcode_name(op), p1, p2, p3);
- }
- }
- }
- #endif
-
- inst_t *inst = (inst_t *)mem_alloc(sizeof(inst_t));
- inst->op = op;
- inst->tag = tag;
- inst->p1 = p1;
- inst->p2 = p2;
- inst->p3 = p3;
-
- if (tag == DOUBLE_TAG) inst->d = d;
- else if (tag == INT_TAG) inst->n = n;
-
- assert(inst);
- return inst;
- }
- void inst_setskip (inst_t *inst) {
- inst->tag = SKIP_TAG;
- }
- void ircode_patch_init (ircode_t *code, uint16_t index) {
- // prepend call instructions to code
- // LOADK temp index
- // LOAD temp 0 temp
- // MOVE temp+1 0
- // CALL temp temp 1
-
- // load constant
- uint32_t dest = ircode_register_push_temp(code);
- inst_t *inst1 = inst_new(LOADK, dest, index, 0, NO_TAG, 0, 0.0);
-
- // load from lookup
- inst_t *inst2 = inst_new(LOAD, dest, 0, dest, NO_TAG, 0, 0.0);
-
- // prepare parameter
- uint32_t dest2 = ircode_register_push_temp(code);
- inst_t *inst3 = inst_new(MOVE, dest2, 0, 0, NO_TAG, 0, 0.0);
- ircode_register_pop(code);
-
- // execute call
- inst_t *inst4 = inst_new(CALL, dest, dest, 1, NO_TAG, 0, 0.0);
-
- // pop temps used
- ircode_register_pop(code);
-
- // create new instruction list
- code_r *list = mem_alloc(sizeof(code_r));
- marray_init(*list);
-
- // add newly create instructions
- marray_push(inst_t*, *list, inst1);
- marray_push(inst_t*, *list, inst2);
- marray_push(inst_t*, *list, inst3);
- marray_push(inst_t*, *list, inst4);
-
- // then copy original instructions
- code_r *orig_list = code->list;
- uint32_t count = ircode_count(code);
- for (uint32_t i=0; i<count; ++i) {
- inst_t *inst = marray_get(*orig_list, i);
- marray_push(inst_t*, *list, inst);
- }
-
- // free dest list
- marray_destroy(*orig_list);
- mem_free(code->list);
-
- // replace dest list with the newly created list
- code->list = list;
- }
- uint8_t opcode_numop (opcode_t op) {
- switch (op) {
- case HALT: return 0;
- case NOP: return 0;
- case RET0: return 0;
- case RET: return 1;
- case CALL: return 3;
- case SETLIST: return 3;
- case LOADK: return 2;
- case LOADG: return 2;
- case LOADI: return 2;
- case LOADAT: return 3;
- case LOADS: return 3;
- case LOAD: return 3;
- case LOADU: return 2;
- case MOVE: return 2;
- case STOREG: return 2;
- case STOREAT: return 3;
- case STORE: return 3;
- case STOREU: return 2;
- case JUMP: return 1;
- case JUMPF: return 2;
- case SWITCH: return 1;
- case ADD: return 3;
- case SUB: return 3;
- case DIV: return 3;
- case MUL: return 3;
- case REM: return 3;
- case AND: return 3;
- case OR: return 3;
- case LT: return 3;
- case GT: return 3;
- case EQ: return 3;
- case ISA: return 3;
- case MATCH: return 3;
- case EQQ: return 3;
- case LEQ: return 3;
- case GEQ: return 3;
- case NEQ: return 3;
- case NEQQ: return 3;
- case NEG: return 2;
- case NOT: return 2;
- case LSHIFT: return 3;
- case RSHIFT: return 3;
- case BAND: return 3;
- case BOR: return 3;
- case BXOR: return 3;
- case BNOT: return 2;
- case MAPNEW: return 2;
- case LISTNEW: return 2;
- case RANGENEW: return 3;
- case CLOSURE: return 2;
- case CLOSE: return 1;
- case RESERVED1:
- case RESERVED2:
- case RESERVED3:
- case RESERVED4:
- case RESERVED5:
- case RESERVED6: return 0;
- }
-
- assert(0);
- return 0;
- }
- void ircode_dump (void *_code) {
- ircode_t *code = (ircode_t *)_code;
- code_r *list = code->list;
- uint32_t count = ircode_count(code);
-
- if (count == 0) {
- printf("NONE\n");
- return;
- }
-
- for (uint32_t i=0, line=0; i<count; ++i) {
- inst_t *inst = marray_get(*list, i);
- opcode_t op = inst->op;
- int32_t p1 = inst->p1;
- int32_t p2 = inst->p2;
- int32_t p3 = inst->p3;
- if (inst->tag == SKIP_TAG) continue;
- if (inst->tag == PRAGMA_OPTIMIZATION) continue;
- if (inst->tag == LABEL_TAG) {printf("LABEL %d:\n", p1); continue;}
-
- uint8_t n = opcode_numop(op);
- if ((op == SETLIST) && (p2 == 0)) n = 2;
-
- switch (n) {
- case 0: {
- printf("%05d\t%s\n", line, opcode_name(op));
- }
-
- case 1: {
- printf("%05d\t%s %d\n", line, opcode_name(op), p1);
- } break;
-
- case 2: {
- if (op == LOADI) {
- if (inst->tag == DOUBLE_TAG) printf("%05d\t%s %d %.2f\n", line, opcode_name(op), p1, inst->d);
- else printf("%05d\t%s %d %d\n", line, opcode_name(op), p1, (int32_t)inst->n);
- } else if (op == LOADK) {
- if (p2 < CPOOL_INDEX_MAX) printf("%05d\t%s %d %d\n", line, opcode_name(op), p1, p2);
- else printf("%05d\t%s %d %s\n", line, opcode_name(op), p1, opcode_constname(p2));
- } else {
- printf("%05d\t%s %d %d\n", line, opcode_name(op), p1, p2);
- }
- } break;
-
- case 3: {
- printf("%05d\t%s %d %d %d\n", line, opcode_name(op), p1, p2, p3);
- } break;
-
- default: assert(0);
- }
- ++line;
- }
- }
- // MARK: -
- uint32_t ircode_newlabel (ircode_t *code) {
- return ++code->label_counter;
- }
- void ircode_setlabel_true (ircode_t *code, uint32_t nlabel) {
- marray_push(uint32_t, code->label_true, nlabel);
- }
- void ircode_setlabel_false (ircode_t *code, uint32_t nlabel) {
- marray_push(uint32_t, code->label_false, nlabel);
- }
- void ircode_unsetlabel_true (ircode_t *code) {
- marray_pop(code->label_true);
- }
- void ircode_unsetlabel_false (ircode_t *code) {
- marray_pop(code->label_false);
- }
- uint32_t ircode_getlabel_true (ircode_t *code) {
- size_t n = marray_size(code->label_true);
- uint32_t v = marray_get(code->label_true, n-1);
- return v;
- }
- uint32_t ircode_getlabel_false (ircode_t *code) {
- size_t n = marray_size(code->label_false);
- uint32_t v = marray_get(code->label_false, n-1);
- return v;
- }
- void ircode_marklabel (ircode_t *code, uint32_t nlabel) {
- inst_t *inst = inst_new(0, nlabel, 0, 0, LABEL_TAG, 0, 0.0);
- marray_push(inst_t*, *code->list, inst);
- }
- // MARK: -
- void ircode_set_index (uint32_t index, ircode_t *code, opcode_t op, uint32_t p1, uint32_t p2, uint32_t p3) {
- inst_t *inst = marray_get(*code->list, index);
- inst->op = op;
- inst->p1 = p1;
- inst->p2 = p2;
- inst->p3 = p3;
- inst->tag = NO_TAG;
- }
- void ircode_add (ircode_t *code, opcode_t op, uint32_t p1, uint32_t p2, uint32_t p3) {
- ircode_add_tag(code, op, p1, p2, p3, 0);
- }
- void ircode_add_tag (ircode_t *code, opcode_t op, uint32_t p1, uint32_t p2, uint32_t p3, optag_t tag) {
- inst_t *inst = inst_new(op, p1, p2, p3, tag, 0, 0.0);
- marray_push(inst_t*, *code->list, inst);
- }
- void ircode_add_double (ircode_t *code, double d) {
- uint32_t regnum = ircode_register_push_temp(code);
- inst_t *inst = inst_new(LOADI, regnum, 0, 0, DOUBLE_TAG, 0, d);
- marray_push(inst_t*, *code->list, inst);
- }
- void ircode_add_constant (ircode_t *code, uint32_t index) {
- uint32_t regnum = ircode_register_push_temp(code);
- inst_t *inst = inst_new(LOADK, regnum, index, 0, NO_TAG, 0, 0);
- marray_push(inst_t*, *code->list, inst);
- }
- void ircode_add_int (ircode_t *code, int64_t n) {
- uint32_t regnum = ircode_register_push_temp(code);
- inst_t *inst = inst_new(LOADI, regnum, 0, 0, INT_TAG, n, 0);
- marray_push(inst_t*, *code->list, inst);
- }
- void ircode_add_skip (ircode_t *code) {
- inst_t *inst = inst_new(0, 0, 0, 0, NO_TAG, 0, 0);
- inst_setskip(inst);
- marray_push(inst_t*, *code->list, inst);
- }
- // MARK: - Context based functions -
- #if 0
- static void dump_context(bool *context) {
- for (uint32_t i=0; i<MAX_REGISTERS; ++i) {
- printf("%d ", context[i]);
- }
- printf("\n");
- }
- #endif
- void ircode_push_context (ircode_t *code) {
- bool *context = mem_alloc(sizeof(bool) * MAX_REGISTERS);
- marray_push(bool *, code->context, context);
- }
- void ircode_pop_context (ircode_t *code) {
- bool *context = marray_pop(code->context);
- // apply context mask
- for (uint32_t i=0; i<MAX_REGISTERS; ++i) {
- if (context[i]) code->state[i] = false;
- }
- mem_free(context);
- }
- uint32_t ircode_register_pop_context_protect (ircode_t *code, bool protect) {
- assert(marray_size(code->registers) != 0);
- uint32_t value = (uint32_t)marray_pop(code->registers);
-
- if (protect) code->state[value] = true;
- else if (value >= code->nlocals) code->state[value] = false;
-
- if (protect && value >= code->nlocals) {
- bool *context = marray_last(code->context);
- context[value] = true;
- }
-
- DEBUG_REGISTER("POP REGISTER %d", value);
- return value;
- }
- void ircode_register_protect_outside_context (ircode_t *code, uint32_t nreg) {
- if (nreg < code->nlocals) return;
- assert(code->state[nreg]);
- bool *context = marray_last(code->context);
- context[nreg] = false;
- }
- void ircode_register_protect_in_context (ircode_t *code, uint32_t nreg) {
- assert(code->state[nreg]);
- bool *context = marray_last(code->context);
- context[nreg] = true;
- }
- // MARK: -
- static uint32_t ircode_register_new (ircode_t *code) {
- for (uint32_t i=0; i<MAX_REGISTERS; ++i) {
- if (code->state[i] == false) {
- code->state[i] = true;
- return i;
- }
- }
- // 0 means no registers available
- code->error = true;
- return 0;
- }
- uint32_t ircode_register_push (ircode_t *code, uint32_t nreg) {
- marray_push(uint32_t, code->registers, nreg);
- if (ircode_register_istemp(code, nreg)) ++code->ntemps;
-
- DEBUG_REGISTER("PUSH REGISTER %d", nreg);
- return nreg;
- }
- uint32_t ircode_register_push_temp (ircode_t *code) {
- uint32_t value = ircode_register_new(code);
- marray_push(uint32_t, code->registers, value);
- if (value > code->maxtemp) {code->maxtemp = value; ++code->ntemps;}
-
- DEBUG_REGISTER("PUSH REGISTER %d", value);
- return value;
- }
- uint32_t ircode_register_pop (ircode_t *code) {
- return ircode_register_pop_context_protect(code, false);
- }
- void ircode_register_clear (ircode_t *code, uint32_t nreg) {
- // cleanup busy mask only if it is a temp register
- if (nreg >= code->nlocals) code->state[nreg] = false;
- }
- uint32_t ircode_register_last (ircode_t *code) {
- assert(marray_size(code->registers) != 0);
- uint32_t value = (uint32_t)marray_last(code->registers);
-
- return value;
- }
- bool ircode_register_istemp (ircode_t *code, uint32_t nreg) {
- return (nreg >= (uint32_t)code->nlocals);
- }
- void ircode_register_dump (ircode_t *code) {
- uint32_t n = (uint32_t)marray_size(code->registers);
- if (n == 0) printf("EMPTY\n");
- for (uint32_t i=0; i<n; ++i) {
- uint32_t value = marray_get(code->registers, i);
- printf("[%d]\t%d\n", i, value);
- }
- }
- uint32_t ircode_register_count (ircode_t *code) {
- return (uint32_t)marray_size(code->registers);
- }
- // MARK: -
- void ircode_register_set_skip_clear (ircode_t *code, uint32_t nreg) {
- code->skipclear[nreg] = true;
- }
- void ircode_register_unset_skip_clear (ircode_t *code, uint32_t nreg) {
- code->skipclear[nreg] = false;
- }
- void ircode_register_clear_temps (ircode_t *code) {
- // clear all temporary registers (if not protected)
- for (uint32_t i=code->nlocals; i<=code->maxtemp; ++i) {
- if (!code->skipclear[i]) code->state[i] = false;
- }
- }
|