tagged release 0.6.4
[parrot.git] / compilers / imcc / instructions.c
blob28d0cf3c527c5486f829077f59b8f5923c358b59
1 /* $Id$ */
3 /*
4 * Copyright (C) 2002-2008, The Perl Foundation.
5 */
7 #include <stdlib.h>
8 #include <string.h>
9 #define _PARSER
10 #include "imc.h"
11 #include "pbc.h"
12 #include "optimizer.h"
16 =head1 NAME
18 compilers/imcc/instructions.c
20 =head1 DESCRIPTION
22 When generating the code, the instructions of the program
23 are stored in an array.
25 After the register allocation is resolved, the instructions
26 array is flushed.
28 These functions operate over this array and its contents.
30 =head2 Functions
32 =over 4
34 =cut
38 /* Global variables , forward def */
40 #if 0
41 static Instruction * last_ins;
43 int n_comp_units;
44 #endif
46 /* HEADERIZER HFILE: compilers/imcc/instructions.h */
48 /* HEADERIZER BEGIN: static */
49 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
51 static int e_file_close(PARROT_INTERP, SHIM(void *param))
52 __attribute__nonnull__(1);
54 static int e_file_emit(PARROT_INTERP,
55 SHIM(void *param),
56 SHIM(const IMC_Unit *unit),
57 ARGIN(const Instruction *ins))
58 __attribute__nonnull__(1)
59 __attribute__nonnull__(4);
61 static int e_file_open(SHIM_INTERP, ARGIN(void *param))
62 __attribute__nonnull__(2);
64 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
65 /* HEADERIZER END: static */
67 static const char types[] = "INPS";
69 static const Emitter emitters[] = {
70 {e_file_open,
71 e_file_emit,
72 NULL,
73 NULL,
74 e_file_close},
76 {e_pbc_open,
77 e_pbc_emit,
78 e_pbc_new_sub,
79 e_pbc_end_sub,
80 e_pbc_close},
83 static int emitter; /* XXX */
87 =item C<Instruction * _mk_instruction>
89 Creates a new instruction
91 =cut
95 PARROT_MALLOC
96 PARROT_CANNOT_RETURN_NULL
97 Instruction *
98 _mk_instruction(ARGIN(const char *op), ARGIN(const char *fmt), int n,
99 ARGIN(SymReg * const *r), int flags)
101 const size_t reg_space = (n > 1) ? (sizeof (SymReg *) * (n - 1)) : 0;
102 Instruction * const ins =
103 (Instruction*)mem_sys_allocate_zeroed(sizeof (Instruction) + reg_space);
104 int i;
106 ins->opname = str_dup(op);
107 ins->format = str_dup(fmt);
108 ins->symreg_count = n;
110 for (i = 0; i < n; i++)
111 ins->symregs[i] = r[i];
113 ins->flags = flags;
114 ins->opnum = -1;
116 return ins;
121 * Some instructions don't have a hint in op_info that they work
122 * on all registers or all registers of a given type (e.g., cleari)
123 * These instructions need special handling at various points in the code.
126 static int w_special[1+4*3];
130 =item C<void imcc_init_tables>
132 RT#48260: Not yet documented!!!
134 =cut
138 void
139 imcc_init_tables(PARROT_INTERP)
141 const char *writes[] = {
142 "cleari", "clearn", "clearp", "clears",
144 /* init opnums */
145 if (!w_special[0]) {
146 size_t i;
147 for (i = 0; i < N_ELEMENTS(writes); i++) {
148 const int n = interp->op_lib->op_code(writes[i], 1);
149 PARROT_ASSERT(n);
150 w_special[i] = n;
157 =item C<int ins_writes2>
159 Returns TRUE if instruction ins writes to a register of type t
161 =cut
166 ins_writes2(ARGIN(const Instruction *ins), int t)
168 const char *p;
170 if (ins->opnum == w_special[0])
171 return 1;
173 p = strchr(types, t);
175 if (p) {
176 const size_t idx = p - types;
177 size_t i;
179 for (i = 1; i < N_ELEMENTS(w_special); i += 4)
180 if (ins->opnum == w_special[i + idx])
181 return 1;
184 return 0;
189 =item C<int instruction_reads>
191 next two functions are called very often, says gprof
192 they should be fast
194 =cut
199 instruction_reads(ARGIN(const Instruction *ins), ARGIN(const SymReg *r))
201 int f, i;
203 if (ins->opnum == PARROT_OP_set_args_pc
204 || ins->opnum == PARROT_OP_set_returns_pc) {
206 for (i = ins->symreg_count - 1; i >= 0; --i)
207 if (r == ins->symregs[i])
208 return 1;
210 return 0;
212 else if (ins->opnum == PARROT_OP_get_params_pc ||
213 ins->opnum == PARROT_OP_get_results_pc) {
214 return 0;
217 f = ins->flags;
219 for (i = ins->symreg_count - 1; i >= 0; --i) {
220 if (f & (1 << i)) {
221 const SymReg * const ri = ins->symregs[i];
223 if (ri == r)
224 return 1;
226 /* this additional test for _kc ops seems to slow
227 * down instruction_reads by a huge amount compared to the
228 * _writes below
230 if (ri->set == 'K') {
231 const SymReg *key;
232 for (key = ri->nextkey; key; key = key->nextkey)
233 if (key->reg == r)
234 return 1;
239 /* a sub call reads the previous args */
240 if (ins->type & ITPCCSUB) {
241 while (ins && ins->opnum != PARROT_OP_set_args_pc)
242 ins = ins->prev;
244 if (!ins)
245 return 0;
247 for (i = ins->symreg_count - 1; i >= 0; --i) {
248 if (ins->symregs[i] == r)
249 return 1;
253 return 0;
258 =item C<int instruction_writes>
260 RT#48260: Not yet documented!!!
262 =cut
267 instruction_writes(ARGIN(const Instruction *ins), ARGIN(const SymReg *r))
269 const int f = ins->flags;
270 int i;
273 * a get_results opcode is before the actual sub call
274 * but for the register allocator, the effect matters, thus
275 * postpone the effect after the invoke
277 if (ins->opnum == PARROT_OP_get_results_pc) {
278 int i;
280 /* but only if it isn't the get_results opcode of
281 * an exception_handler, which doesn't have
282 * a call next
284 if (ins->next && (ins->next->type & ITPCCSUB))
285 return 0;
287 for (i = ins->symreg_count - 1; i >= 0; --i) {
288 if (ins->symregs[i] == r)
289 return 1;
292 return 0;
294 else if (ins->type & ITPCCSUB) {
295 int i;
296 ins = ins->prev;
297 /* can't used pcc_sub->ret due to bug #38406
298 * it seems that all sub SymRegs are shared
299 * and point to the most recemt pcc_sub
300 * structure
302 while (ins && ins->opnum != PARROT_OP_get_results_pc)
303 ins = ins->prev;
305 if (!ins)
306 return 0;
308 for (i = ins->symreg_count - 1; i >= 0; --i) {
309 if (ins->symregs[i] == r)
310 return 1;
313 return 0;
316 if (ins->opnum == PARROT_OP_get_params_pc) {
317 int i;
319 for (i = ins->symreg_count - 1; i >= 0; --i) {
320 if (ins->symregs[i] == r)
321 return 1;
324 return 0;
326 else if (ins->opnum == PARROT_OP_set_args_pc
327 || ins->opnum == PARROT_OP_set_returns_pc) {
328 return 0;
331 for (i = 0; i < ins->symreg_count; i++)
332 if (f & (1 << (16 + i)))
333 if (ins->symregs[i] == r)
334 return 1;
336 return 0;
341 =item C<int get_branch_regno>
343 Get the register number of an address which is a branch target
345 =cut
350 get_branch_regno(ARGIN(const Instruction *ins))
352 int j;
354 for (j = ins->opsize - 2; j >= 0 && ins->symregs[j] ; --j)
355 if (ins->type & (1 << j))
356 return j;
358 return -1;
363 =item C<SymReg * get_branch_reg>
365 Get the register corresponding to an address which is a branch target
367 =cut
371 PARROT_WARN_UNUSED_RESULT
372 PARROT_CAN_RETURN_NULL
373 SymReg *
374 get_branch_reg(ARGIN(const Instruction *ins))
376 const int r = get_branch_regno(ins);
378 if (r >= 0)
379 return ins->symregs[r];
381 return NULL;
384 /* some useful instruction routines */
388 =item C<Instruction * _delete_ins>
390 Delete instruction ins. It's up to the caller to actually free the memory
391 of ins, if appropriate.
393 The instruction following ins is returned.
395 =cut
399 PARROT_WARN_UNUSED_RESULT
400 PARROT_CAN_RETURN_NULL
401 Instruction *
402 _delete_ins(ARGMOD(struct _IMC_Unit *unit), ARGIN(Instruction *ins))
404 Instruction * const next = ins->next;
405 Instruction * const prev = ins->prev;
407 if (prev)
408 prev->next = next;
409 else
410 unit->instructions = next;
412 if (next)
413 next->prev = prev;
414 else
415 unit->last_ins = prev;
417 return next;
422 =item C<Instruction * delete_ins>
424 Delete instruction ins, and then free it.
426 The instruction following ins is returned.
428 =cut
432 PARROT_WARN_UNUSED_RESULT
433 PARROT_CAN_RETURN_NULL
434 Instruction *
435 delete_ins(ARGMOD(struct _IMC_Unit *unit), ARGMOD(Instruction *ins))
437 Instruction * next = _delete_ins(unit, ins);
439 free_ins(ins);
441 return next;
446 =item C<void insert_ins>
448 insert tmp after ins
450 =cut
454 void
455 insert_ins(ARGMOD(struct _IMC_Unit *unit), ARGMOD_NULLOK(Instruction *ins),
456 ARGMOD(Instruction *tmp))
458 if (!ins) {
459 Instruction * const next = unit->instructions;
461 unit->instructions = tmp;
462 tmp->next = next;
464 if (next) {
465 next->prev = tmp;
466 tmp->line = next->line;
468 else {
469 unit->last_ins = tmp;
472 else {
473 Instruction * const next = ins->next;
475 ins->next = tmp;
476 tmp->prev = ins;
477 tmp->next = next;
479 if (next)
480 next->prev = tmp;
481 else
482 unit->last_ins = tmp;
484 if (!tmp->line)
485 tmp->line = ins->line;
491 =item C<void prepend_ins>
493 insert tmp before ins
495 =cut
499 void
500 prepend_ins(ARGMOD(struct _IMC_Unit *unit), ARGMOD_NULLOK(Instruction *ins),
501 ARGMOD(Instruction *tmp))
503 if (!ins) {
504 Instruction * const next = unit->instructions;
506 unit->instructions = tmp;
507 tmp->next = next;
508 next->prev = tmp;
509 tmp->line = next->line;
511 else {
512 Instruction * const prev = ins->prev;
514 ins->prev = tmp;
515 tmp->next = ins;
516 tmp->prev = prev;
518 if (prev)
519 prev->next = tmp;
521 if (!tmp->line)
522 tmp->line = ins->line;
528 =item C<void subst_ins>
530 Substitute tmp for ins. Free ins if needs_freeing is true.
532 =cut
536 void
537 subst_ins(ARGMOD(struct _IMC_Unit *unit), ARGMOD(Instruction *ins),
538 ARGMOD(Instruction *tmp), int needs_freeing)
540 Instruction * const prev = ins->prev;
542 if (prev)
543 prev->next = tmp;
544 else
545 unit->instructions = tmp;
547 tmp->prev = prev;
548 tmp->next = ins->next;
550 if (ins->next)
551 ins->next->prev = tmp;
552 else
553 unit->last_ins = tmp;
555 if (tmp->line == 0)
556 tmp->line = ins->line;
558 if (needs_freeing)
559 free_ins(ins);
564 =item C<Instruction * move_ins>
566 Move instruction ins from its current position to the position
567 following instruction to. Returns the instruction following the
568 initial position of ins.
570 =cut
574 PARROT_CAN_RETURN_NULL
575 Instruction *
576 move_ins(ARGMOD(struct _IMC_Unit *unit), ARGMOD(Instruction *ins), ARGMOD(Instruction *to))
578 Instruction * const next = _delete_ins(unit, ins);
579 insert_ins(unit, to, ins);
580 return next;
586 =item C<Instruction * emitb>
588 Emit a single instruction into the current unit buffer.
590 =cut
594 PARROT_CAN_RETURN_NULL
595 Instruction *
596 emitb(PARROT_INTERP, ARGMOD_NULLOK(struct _IMC_Unit *unit), ARGIN_NULLOK(Instruction *i))
599 if (!unit || !i)
600 return NULL;
602 if (!unit->instructions)
603 unit->last_ins = unit->instructions = i;
604 else {
605 unit->last_ins->next = i;
606 i->prev = unit->last_ins;
607 unit->last_ins = i;
610 /* lexer is in next line already */
611 i->line = IMCC_INFO(interp)->line - 1;
613 return i;
618 =item C<void free_ins>
620 Free the Instruction structure ins.
622 =cut
626 void
627 free_ins(ARGMOD(Instruction *ins))
629 free(ins->format);
630 free(ins->opname);
631 free(ins);
636 =item C<int ins_print>
638 Print details of instruction ins in file fd.
640 =cut
644 #define REGB_SIZE 256
646 ins_print(PARROT_INTERP, ARGMOD(FILE *fd), ARGIN(const Instruction *ins))
648 char regb[IMCC_MAX_FIX_REGS][REGB_SIZE];
649 /* only long key constants can overflow */
650 char *regstr[IMCC_MAX_FIX_REGS];
651 int i;
652 int len;
654 #if IMC_TRACE
655 PIO_eprintf(NULL, "ins_print\n");
656 #endif
658 /* comments, labels and such */
659 if (!ins->symregs[0] || !strchr(ins->format, '%'))
660 return fprintf(fd, "%s", ins->format);
662 for (i = 0; i < ins->symreg_count; i++) {
663 const SymReg *p = ins->symregs[i];
664 if (!p)
665 continue;
667 if (p->type & VT_CONSTP)
668 p = p->reg;
670 if (p->color >= 0 && REG_NEEDS_ALLOC(p)) {
671 snprintf(regb[i], REGB_SIZE, "%c%d", p->set, (int)p->color);
672 regstr[i] = regb[i];
674 else if (IMCC_INFO(interp)->allocated
675 && (IMCC_INFO(interp)->optimizer_level & OPT_J)
676 && p->set != 'K'
677 && p->color < 0
678 && REG_NEEDS_ALLOC(p)) {
679 snprintf(regb[i], REGB_SIZE,
680 "r%c%d", tolower((unsigned char)p->set),
681 -1 -(int)p->color);
682 regstr[i] = regb[i];
684 else if (p->type & VTREGKEY) {
685 const SymReg *k = p;
687 *regb[i] = '\0';
689 while ((k = k->nextkey) != NULL) {
690 const size_t used = strlen(regb[i]);
692 if (k->reg && k->reg->color >= 0)
693 snprintf(regb[i]+used, REGB_SIZE - used, "%c%d",
694 k->reg->set, (int)k->reg->color);
695 else if (IMCC_INFO(interp)->allocated
696 && (IMCC_INFO(interp)->optimizer_level & OPT_J)
697 && k->reg
698 && k->reg->color < 0)
699 snprintf(regb[i]+used, REGB_SIZE - used, "r%c%d",
700 tolower((unsigned char)k->reg->set),
701 -1 -(int)k->reg->color);
702 else
703 strncat(regb[i], k->name, REGB_SIZE - used - 1);
705 if (k->nextkey)
706 strncat(regb[i], ";", REGB_SIZE - strlen(regb[i]) - 1);
709 regstr[i] = regb[i];
711 else if (p->type == VTCONST
712 && p->set == 'S'
713 && *p->name != '"'
714 && *p->name != '\'') {
715 /* unquoted string const */
716 snprintf(regb[i], REGB_SIZE, "\"%s\"", p->name);
717 regstr[i] = regb[i];
719 else
720 regstr[i] = p->name;
723 switch (ins->opsize-1) {
724 case -1: /* labels */
725 case 1:
726 len = fprintf(fd, ins->format, regstr[0]);
727 break;
728 case 2:
729 len = fprintf(fd, ins->format, regstr[0], regstr[1]);
730 break;
731 case 3:
732 len = fprintf(fd, ins->format, regstr[0], regstr[1], regstr[2]);
733 break;
734 case 4:
735 len = fprintf(fd, ins->format, regstr[0], regstr[1], regstr[2],
736 regstr[3]);
737 break;
738 case 5:
739 len = fprintf(fd, ins->format, regstr[0], regstr[1], regstr[2],
740 regstr[3], regstr[4]);
741 break;
742 case 6:
743 len = fprintf(fd, ins->format, regstr[0], regstr[1], regstr[2],
744 regstr[3], regstr[4], regstr[5]);
745 break;
746 default:
747 fprintf(stderr, "unhandled: opsize (%d), op %s, fmt %s\n",
748 ins->opsize, ins->opname, ins->format);
749 exit(EXIT_FAILURE);
750 break;
753 return len;
756 /* for debug */
757 static char *output;
761 =item C<static int e_file_open>
763 RT#48260: Not yet documented!!!
765 =cut
769 static int
770 e_file_open(SHIM_INTERP, ARGIN(void *param))
772 char * const file = (char *) param;
774 if (!STREQ(file, "-"))
775 freopen(file, "w", stdout);
776 output = file;
777 printf("# IMCC does produce b0rken PASM files\n");
778 printf("# see http://guest@rt.perl.org/rt3/Ticket/Display.html?id=32392\n");
779 return 1;
784 =item C<static int e_file_close>
786 RT#48260: Not yet documented!!!
788 =cut
792 static int
793 e_file_close(PARROT_INTERP, SHIM(void *param))
795 printf("\n\n");
796 fclose(stdout);
797 IMCC_info(interp, 1, "assembly module %s written.\n", output);
798 return 0;
803 =item C<static int e_file_emit>
805 RT#48260: Not yet documented!!!
807 =cut
811 static int
812 e_file_emit(PARROT_INTERP,
813 SHIM(void *param),
814 SHIM(const IMC_Unit *unit),
815 ARGIN(const Instruction *ins))
817 #if IMC_TRACE
818 PIO_eprintf(NULL, "e_file_emit\n");
819 #endif
820 if ((ins->type & ITLABEL) || ! *ins->opname)
821 ins_print(interp, stdout, ins);
822 else {
823 imcc_fprintf(interp, stdout, "\t%I ", ins);
825 printf("\n");
826 return 0;
831 =item C<int emit_open>
833 RT#48260: Not yet documented!!!
835 =cut
839 PARROT_API
841 emit_open(PARROT_INTERP, int type, ARGIN_NULLOK(void *param))
843 emitter = type;
844 IMCC_INFO(interp)->has_compile = 0;
845 IMCC_INFO(interp)->dont_optimize = 0;
847 return (emitters[emitter]).open(interp, param);
852 =item C<int emit_flush>
854 RT#48260: Not yet documented!!!
856 =cut
860 PARROT_API
862 emit_flush(PARROT_INTERP, ARGIN_NULLOK(void *param), ARGIN(struct _IMC_Unit *unit))
864 Instruction * ins;
866 if (emitters[emitter].new_sub)
867 (emitters[emitter]).new_sub(interp, param, unit);
869 for (ins = unit->instructions; ins; ins = ins->next) {
870 IMCC_debug(interp, DEBUG_IMC, "emit %I\n", ins);
871 (emitters[emitter]).emit(interp, param, unit, ins);
874 if (emitters[emitter].end_sub)
875 (emitters[emitter]).end_sub(interp, param, unit);
877 return 0;
882 =item C<int emit_close>
884 RT#48260: Not yet documented!!!
886 =cut
890 PARROT_API
892 emit_close(PARROT_INTERP, ARGIN_NULLOK(void *param))
894 return (emitters[emitter]).close(interp, param);
899 =back
901 =cut
906 * Local variables:
907 * c-file-style: "parrot"
908 * End:
909 * vim: expandtab shiftwidth=4: