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