1 /*
2  * Copyright (C) 2002-2010, Parrot Foundation.
3  */
4 
5 #include <stdlib.h>
6 #include <string.h>
7 #define _PARSER
8 #include "imc.h"
9 #include "pbc.h"
10 #include "optimizer.h"
11 #include "pmc/pmc_callcontext.h"
12 #include "parrot/oplib/core_ops.h"
13 
14 /*
15 
16 =head1 NAME
17 
18 compilers/imcc/instructions.c
19 
20 =head1 DESCRIPTION
21 
22 When generating the code, the instructions of the program
23 are stored in an array.
24 
25 After the register allocation is resolved, the instructions
26 array is flushed.
27 
28 These functions operate over this array and its contents.
29 
30 =head2 Functions
31 
32 =over 4
33 
34 =cut
35 
36 */
37 
38 /* HEADERIZER HFILE: compilers/imcc/instructions.h */
39 
40 /* HEADERIZER BEGIN: static */
41 /* HEADERIZER END: static */
42 
43 /*
44 
45 =item C<Instruction * _mk_instruction(const char *op, const char *fmt, int n,
46 SymReg * const *r, int flags)>
47 
48 Creates a new instruction
49 
50 =cut
51 
52 */
53 
54 PARROT_MALLOC
55 PARROT_CANNOT_RETURN_NULL
56 Instruction *
_mk_instruction(ARGIN (const char * op),ARGIN (const char * fmt),int n,ARGIN (SymReg * const * r),int flags)57 _mk_instruction(ARGIN(const char *op), ARGIN(const char *fmt), int n,
58         ARGIN(SymReg * const *r), int flags)
59 {
60     ASSERT_ARGS(_mk_instruction)
61     const size_t reg_space  = (n > 1) ? (sizeof (SymReg *) * (n - 1)) : 0;
62     Instruction * const ins =
63         (Instruction*)mem_sys_allocate_zeroed(sizeof (Instruction) + reg_space);
64     int i;
65 
66     ins->opname       = mem_sys_strdup(op);
67     ins->format       = mem_sys_strdup(fmt);
68     ins->symreg_count = n;
69 
70     for (i = 0; i < n; i++)
71         ins->symregs[i]  = r[i];
72 
73     ins->flags = flags;
74     ins->op    = NULL;
75 
76     return ins;
77 }
78 
79 /*
80 
81 =item C<int instruction_reads(const Instruction *ins, const SymReg *r)>
82 
83 next two functions are called very often, says gprof
84 they should be fast
85 
86 =cut
87 
88 */
89 
90 int
instruction_reads(ARGIN (const Instruction * ins),ARGIN (const SymReg * r))91 instruction_reads(ARGIN(const Instruction *ins), ARGIN(const SymReg *r))
92 {
93     ASSERT_ARGS(instruction_reads)
94     int f, i;
95     op_lib_t *core_ops = PARROT_GET_CORE_OPLIB(NULL);
96 
97     if (ins->op && ins->op->lib == core_ops) {
98         if (OP_INFO_OPNUM(ins->op) == PARROT_OP_set_args_pc
99         ||  OP_INFO_OPNUM(ins->op) == PARROT_OP_set_returns_pc) {
100 
101             for (i = ins->symreg_count - 1; i >= 0; --i)
102                 if (r == ins->symregs[i])
103                     return 1;
104 
105             return 0;
106         }
107         else if (OP_INFO_OPNUM(ins->op) == PARROT_OP_get_params_pc ||
108                  OP_INFO_OPNUM(ins->op) == PARROT_OP_get_results_pc) {
109             return 0;
110         }
111     }
112 
113     f = ins->flags;
114 
115     for (i = ins->symreg_count - 1; i >= 0; --i) {
116         if (f & (1 << i)) {
117             const SymReg * const ri = ins->symregs[i];
118 
119             if (ri == r)
120                 return 1;
121 
122             /* this additional test for _kc ops seems to slow
123              * down instruction_reads by a huge amount compared to the
124              * _writes below
125              */
126             if (ri->set == 'K') {
127                 const SymReg *key;
128                 for (key = ri->nextkey; key; key = key->nextkey)
129                     if (key->reg == r)
130                         return 1;
131             }
132         }
133     }
134 
135     /* a sub call reads the previous args */
136     if (ins->type & ITPCCSUB) {
137         while (ins && ins->op != &core_ops->op_info_table[PARROT_OP_set_args_pc])
138             ins = ins->prev;
139 
140         if (!ins)
141             return 0;
142 
143         for (i = ins->symreg_count - 1; i >= 0; --i) {
144             if (ins->symregs[i] == r)
145                 return 1;
146         }
147     }
148 
149     return 0;
150 }
151 
152 /*
153 
154 =item C<int instruction_writes(const Instruction *ins, const SymReg *r)>
155 
156 Determines whether the instruction C<ins> writes to the SymReg C<r>.
157 Returns 1 if it does, 0 if not.
158 
159 =cut
160 
161 */
162 
163 int
instruction_writes(ARGIN (const Instruction * ins),ARGIN (const SymReg * r))164 instruction_writes(ARGIN(const Instruction *ins), ARGIN(const SymReg *r))
165 {
166     ASSERT_ARGS(instruction_writes)
167     const int f = ins->flags;
168     int j;
169     op_lib_t *core_ops = PARROT_GET_CORE_OPLIB(NULL);
170 
171     /* a get_results opcode occurs after the actual sub call */
172     if (ins->op == &core_ops->op_info_table[PARROT_OP_get_results_pc]) {
173         int i;
174         /* Old assumption: But only if it isn't the get_results opcode
175          * of an ExceptionHandler, which doesn't have a call next.
176          *
177          * Not with GH #1041: invokecc vs exception handler:
178          * invokecc + get_results x, $I0 does write to $I0
179         if (ins->prev && (ins->prev->type & ITPCCSUB))
180             return 0;
181          */
182 
183         for (i = ins->symreg_count - 1; i >= 0; --i) {
184             if (ins->symregs[i] == r)
185                 return 1;
186         }
187 
188         return 0;
189     }
190     else if (ins->type & ITPCCSUB) {
191         int i;
192         ins = ins->prev;
193         /* can't used pcc_sub->ret due to bug #38406
194          * it seems that all sub SymRegs are shared
195          * and point to the most recent pcc_sub
196          * structure
197          */
198         while (ins && ins->op != &core_ops->op_info_table[PARROT_OP_get_results_pc])
199             ins = ins->next;
200 
201         if (!ins)
202             return 0;
203 
204         for (i = ins->symreg_count - 1; i >= 0; --i) {
205             if (ins->symregs[i] == r)
206                 return 1;
207         }
208 
209         return 0;
210     }
211 
212     if (ins->op == &core_ops->op_info_table[PARROT_OP_get_params_pc]) {
213         int i;
214 
215         for (i = ins->symreg_count - 1; i >= 0; --i) {
216             if (ins->symregs[i] == r)
217                 return 1;
218         }
219 
220         return 0;
221     }
222     else if (ins->op == &core_ops->op_info_table[PARROT_OP_set_args_pc]
223          ||  ins->op == &core_ops->op_info_table[PARROT_OP_set_returns_pc]) {
224         return 0;
225     }
226 
227     for (j = 0; j < ins->symreg_count; j++)
228         if (f & (1 << (16 + j)))
229             if (ins->symregs[j] == r)
230                 return 1;
231 
232     return 0;
233 }
234 
235 
236 /*
237 
238 =item C<int get_branch_regno(const Instruction *ins)>
239 
240 Get the register number of an address which is a branch target
241 
242 =cut
243 
244 */
245 
246 int
get_branch_regno(ARGIN (const Instruction * ins))247 get_branch_regno(ARGIN(const Instruction *ins))
248 {
249     ASSERT_ARGS(get_branch_regno)
250     int j;
251 
252     for (j = ins->opsize - 2; j >= 0 && ins->symregs[j] ; --j)
253         if (ins->type & (1 << j))
254             return j;
255 
256     return -1;
257 }
258 
259 /*
260 
261 =item C<SymReg * get_branch_reg(const Instruction *ins)>
262 
263 Get the register corresponding to an address which is a branch target
264 
265 =cut
266 
267 */
268 
269 PARROT_WARN_UNUSED_RESULT
270 PARROT_CAN_RETURN_NULL
271 SymReg *
get_branch_reg(ARGIN (const Instruction * ins))272 get_branch_reg(ARGIN(const Instruction *ins))
273 {
274     ASSERT_ARGS(get_branch_reg)
275     const int r = get_branch_regno(ins);
276 
277     if (r >= 0)
278         return ins->symregs[r];
279 
280     return NULL;
281 }
282 
283 /* some useful instruction routines */
284 
285 /*
286 
287 =item C<Instruction * _delete_ins(IMC_Unit *unit, Instruction *ins)>
288 
289 Delete instruction ins. It's up to the caller to actually free the memory
290 of ins, if appropriate.
291 
292 The instruction following ins is returned.
293 
294 =cut
295 
296 */
297 
298 PARROT_WARN_UNUSED_RESULT
299 PARROT_CAN_RETURN_NULL
300 Instruction *
_delete_ins(ARGMOD (IMC_Unit * unit),ARGIN (Instruction * ins))301 _delete_ins(ARGMOD(IMC_Unit *unit), ARGIN(Instruction *ins))
302 {
303     ASSERT_ARGS(_delete_ins)
304     Instruction * const next = ins->next;
305     Instruction * const prev = ins->prev;
306 
307     if (prev)
308         prev->next = next;
309     else
310         unit->instructions = next;
311 
312     if (next)
313         next->prev = prev;
314     else
315         unit->last_ins = prev;
316 
317     return next;
318 }
319 
320 /*
321 
322 =item C<Instruction * delete_ins(IMC_Unit *unit, Instruction *ins)>
323 
324 Delete instruction ins, and then free it.
325 
326 The instruction following ins is returned.
327 
328 =cut
329 
330 */
331 
332 PARROT_WARN_UNUSED_RESULT
333 PARROT_CAN_RETURN_NULL
334 Instruction *
delete_ins(ARGMOD (IMC_Unit * unit),ARGMOD (Instruction * ins))335 delete_ins(ARGMOD(IMC_Unit *unit), ARGMOD(Instruction *ins))
336 {
337     ASSERT_ARGS(delete_ins)
338     Instruction * next = _delete_ins(unit, ins);
339 
340 
341     free_ins(ins);
342 
343     return next;
344 }
345 
346 /*
347 
348 =item C<void insert_ins(IMC_Unit *unit, Instruction *ins, Instruction *tmp)>
349 
350 Insert Instruction C<tmp> in the execution flow after Instruction
351 C<ins>.
352 
353 =cut
354 
355 */
356 
357 void
insert_ins(ARGMOD (IMC_Unit * unit),ARGMOD_NULLOK (Instruction * ins),ARGMOD (Instruction * tmp))358 insert_ins(ARGMOD(IMC_Unit *unit), ARGMOD_NULLOK(Instruction *ins),
359         ARGMOD(Instruction *tmp))
360 {
361     ASSERT_ARGS(insert_ins)
362     if (!ins) {
363         Instruction * const next = unit->instructions;
364 
365         unit->instructions = tmp;
366         tmp->next          = next;
367 
368         if (next) {
369             next->prev = tmp;
370             tmp->line  = next->line;
371         }
372         else {
373             unit->last_ins = tmp;
374         }
375     }
376     else {
377         Instruction * const next = ins->next;
378 
379         ins->next = tmp;
380         tmp->prev = ins;
381         tmp->next = next;
382 
383         if (next)
384             next->prev = tmp;
385         else
386             unit->last_ins = tmp;
387 
388         if (!tmp->line)
389             tmp->line = ins->line;
390     }
391 }
392 
393 /*
394 
395 =item C<void prepend_ins(IMC_Unit *unit, Instruction *ins, Instruction *tmp)>
396 
397 Insert Instruction C<tmp> into the execution flow before
398 Instruction C<ins>.
399 
400 =cut
401 
402 */
403 
404 void
prepend_ins(ARGMOD (IMC_Unit * unit),ARGMOD_NULLOK (Instruction * ins),ARGMOD (Instruction * tmp))405 prepend_ins(ARGMOD(IMC_Unit *unit), ARGMOD_NULLOK(Instruction *ins),
406         ARGMOD(Instruction *tmp))
407 {
408     ASSERT_ARGS(prepend_ins)
409     if (!ins) {
410         Instruction * const next = unit->instructions;
411 
412         unit->instructions = tmp;
413         tmp->next          = next;
414         next->prev         = tmp;
415         tmp->line          = next->line;
416     }
417     else {
418         Instruction * const prev = ins->prev;
419 
420         ins->prev = tmp;
421         tmp->next = ins;
422         tmp->prev = prev;
423 
424         if (prev)
425             prev->next = tmp;
426 
427         if (!tmp->line)
428             tmp->line = ins->line;
429     }
430 }
431 
432 /*
433 
434 =item C<void subst_ins(IMC_Unit *unit, Instruction *ins, Instruction *tmp, int
435 needs_freeing)>
436 
437 Substitute Instruction C<tmp> for Instruction C<ins>.
438 Free C<ins> if C<needs_freeing> is true.
439 
440 =cut
441 
442 */
443 
444 void
subst_ins(ARGMOD (IMC_Unit * unit),ARGMOD (Instruction * ins),ARGMOD (Instruction * tmp),int needs_freeing)445 subst_ins(ARGMOD(IMC_Unit *unit), ARGMOD(Instruction *ins),
446           ARGMOD(Instruction *tmp), int needs_freeing)
447 {
448     ASSERT_ARGS(subst_ins)
449     Instruction * const prev = ins->prev;
450 
451 
452     if (prev)
453         prev->next = tmp;
454     else
455         unit->instructions = tmp;
456 
457     tmp->prev = prev;
458     tmp->next = ins->next;
459 
460     if (ins->next)
461         ins->next->prev = tmp;
462     else
463         unit->last_ins = tmp;
464 
465     if (tmp->line == 0)
466         tmp->line = ins->line;
467 
468     if (needs_freeing)
469         free_ins(ins);
470 }
471 
472 /*
473 
474 =item C<Instruction * move_ins(IMC_Unit *unit, Instruction *ins, Instruction
475 *to)>
476 
477 Move instruction ins from its current position to the position
478 following instruction to. Returns the instruction following the
479 initial position of ins.
480 
481 =cut
482 
483 */
484 
485 PARROT_CAN_RETURN_NULL
486 Instruction *
move_ins(ARGMOD (IMC_Unit * unit),ARGMOD (Instruction * ins),ARGMOD (Instruction * to))487 move_ins(ARGMOD(IMC_Unit *unit), ARGMOD(Instruction *ins), ARGMOD(Instruction *to))
488 {
489     ASSERT_ARGS(move_ins)
490     Instruction * const next = _delete_ins(unit, ins);
491     insert_ins(unit, to, ins);
492     return next;
493 }
494 
495 
496 /*
497 
498 =item C<Instruction * emitb(imc_info_t * imcc, IMC_Unit *unit, Instruction *i)>
499 
500 Emit a single instruction into the current unit buffer.
501 
502 =cut
503 
504 */
505 
506 PARROT_CAN_RETURN_NULL
507 Instruction *
emitb(ARGMOD (imc_info_t * imcc),ARGMOD_NULLOK (IMC_Unit * unit),ARGIN_NULLOK (Instruction * i))508 emitb(ARGMOD(imc_info_t * imcc), ARGMOD_NULLOK(IMC_Unit *unit),
509         ARGIN_NULLOK(Instruction *i))
510 {
511     ASSERT_ARGS(emitb)
512     if (!unit || !i)
513         return NULL;
514 
515     if (!unit->instructions)
516         unit->last_ins = unit->instructions = i;
517     else {
518         unit->last_ins->next = i;
519         i->prev              = unit->last_ins;
520         unit->last_ins       = i;
521     }
522 
523     /* lexer is in next line already */
524     i->line = imcc->line;
525 
526     return i;
527 }
528 
529 /*
530 
531 =item C<void free_ins(Instruction *ins)>
532 
533 Free the Instruction structure ins.
534 
535 =cut
536 
537 */
538 
539 void
free_ins(ARGMOD (Instruction * ins))540 free_ins(ARGMOD(Instruction *ins))
541 {
542     ASSERT_ARGS(free_ins)
543     mem_sys_free(ins->format);
544     mem_sys_free(ins->opname);
545     mem_sys_free(ins);
546 }
547 
548 /*
549 
550 =item C<int ins_print(imc_info_t * imcc, PIOHANDLE io, const Instruction *ins)>
551 
552 Print details of instruction ins in file fd.
553 
554 =cut
555 
556 */
557 
558 #define REGB_SIZE 256
559 PARROT_IGNORABLE_RESULT
560 int
ins_print(ARGMOD (imc_info_t * imcc),PIOHANDLE io,ARGIN (const Instruction * ins))561 ins_print(ARGMOD(imc_info_t * imcc), PIOHANDLE io, ARGIN(const Instruction *ins))
562 {
563     ASSERT_ARGS(ins_print)
564     char regb[IMCC_MAX_FIX_REGS][REGB_SIZE];
565     /* only long key constants can overflow */
566     char *regstr[IMCC_MAX_FIX_REGS];
567     int i;
568     int len;
569 
570     /* comments, labels and such */
571     if (!ins->symregs[0] || !strchr(ins->format, '%'))
572         return Parrot_io_pprintf(imcc->interp, io, "%s", ins->format);
573 
574     for (i = 0; i < ins->symreg_count; i++) {
575         const SymReg *p = ins->symregs[i];
576         if (!p)
577             continue;
578 
579         if (p->type & VT_CONSTP)
580             p = p->reg;
581 
582         if (p->color >= 0 && REG_NEEDS_ALLOC(p)) {
583             snprintf(regb[i], REGB_SIZE, "%c%d", p->set, (int)p->color);
584             regstr[i] = regb[i];
585         }
586         else if (p->type & VTREGKEY) {
587             const SymReg *k = p;
588 
589             *regb[i] = '\0';
590 
591             while ((k = k->nextkey) != NULL) {
592                 const size_t used = strlen(regb[i]);
593 
594                 if (k->reg && k->reg->color >= 0)
595                     snprintf(regb[i]+used, REGB_SIZE - used, "%c%d",
596                             k->reg->set, (int)k->reg->color);
597                 else
598                     strncat(regb[i], k->name, REGB_SIZE - used - 1);
599 
600                 if (k->nextkey)
601                     strncat(regb[i], ";", REGB_SIZE - strlen(regb[i]) - 1);
602             }
603 
604             regstr[i] = regb[i];
605         }
606         else if (p->type == VTCONST
607              &&  p->set  == 'S'
608              && *p->name != '"'
609              && *p->name != '\'') {
610             /* unquoted string const */
611             snprintf(regb[i], REGB_SIZE, "\"%s\"", p->name);
612             regstr[i] = regb[i];
613         }
614         else
615             regstr[i] = p->name;
616     }
617 
618     switch (ins->opsize-1) {
619       case -1:        /* labels */
620       case 1:
621         len = Parrot_io_pprintf(imcc->interp, io, ins->format, regstr[0]);
622         break;
623       case 2:
624         len = Parrot_io_pprintf(imcc->interp, io, ins->format, regstr[0], regstr[1]);
625         break;
626       case 3:
627         len = Parrot_io_pprintf(imcc->interp, io, ins->format, regstr[0], regstr[1], regstr[2]);
628         break;
629       case 4:
630         len = Parrot_io_pprintf(imcc->interp, io, ins->format, regstr[0], regstr[1], regstr[2],
631                     regstr[3]);
632         break;
633       case 5:
634         len = Parrot_io_pprintf(imcc->interp, io, ins->format, regstr[0], regstr[1], regstr[2],
635                     regstr[3], regstr[4]);
636         break;
637       case 6:
638         len = Parrot_io_pprintf(imcc->interp, io, ins->format, regstr[0], regstr[1], regstr[2],
639                     regstr[3], regstr[4], regstr[5]);
640         break;
641       default:
642         Parrot_io_eprintf(imcc->interp, "unhandled: opsize (%d), op %s, fmt %s\n",
643                 ins->opsize, ins->opname, ins->format);
644         exit(EXIT_FAILURE);
645         break;
646     }
647 
648     return len;
649 }
650 
651 /*
652 
653 =item C<void emit_open(imc_info_t * imcc)>
654 
655 Opens the emitter function C<open> of the given C<type>. Passes
656 the C<param> to the open function.
657 
658 =cut
659 
660 */
661 
662 void
emit_open(ARGMOD (imc_info_t * imcc))663 emit_open(ARGMOD(imc_info_t * imcc))
664 {
665     ASSERT_ARGS(emit_open)
666     imcc->dont_optimize = 0;
667     e_pbc_open(imcc);
668 }
669 
670 /*
671 
672 =item C<void emit_flush(imc_info_t * imcc, void *param, IMC_Unit *unit)>
673 
674 Flushes the emitter by emitting all the instructions in the current
675 IMC_Unit C<unit>.
676 
677 =cut
678 
679 */
680 
681 void
emit_flush(ARGMOD (imc_info_t * imcc),ARGIN_NULLOK (void * param),ARGIN (IMC_Unit * unit))682 emit_flush(ARGMOD(imc_info_t * imcc), ARGIN_NULLOK(void *param),
683         ARGIN(IMC_Unit *unit))
684 {
685     ASSERT_ARGS(emit_flush)
686     Instruction *ins;
687 
688     e_pbc_new_sub(imcc, param, unit);
689 
690     for (ins = unit->instructions; ins; ins = ins->next) {
691         IMCC_debug(imcc, DEBUG_IMC, "emit %d\n", ins);
692         e_pbc_emit(imcc, param, unit, ins);
693     }
694 
695     e_pbc_end_sub(imcc, param, unit);
696 }
697 
698 /*
699 
700 =item C<void emit_close(imc_info_t *imcc, void *param)>
701 
702 Closes the given emitter.
703 
704 =cut
705 
706 */
707 
708 void
emit_close(ARGMOD (imc_info_t * imcc),ARGIN_NULLOK (void * param))709 emit_close(ARGMOD(imc_info_t *imcc), ARGIN_NULLOK(void *param))
710 {
711     ASSERT_ARGS(emit_close)
712     e_pbc_close(imcc, param);
713 }
714 
715 /*
716 
717 =back
718 
719 =cut
720 
721 */
722 
723 /*
724  * Local variables:
725  *   c-file-style: "parrot"
726  * End:
727  * vim: expandtab shiftwidth=4 cinoptions='\:2=2' :
728  */
729