gravity_ircode.c 13 KB

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