3 * Copyright (C) 2002-2008, The Perl Foundation.
10 compilers/imcc/optimizer.c
14 Optimization occurs in three stages:
15 1) pre_optimizer -- runs before control flow graph (CFG) is built
16 2) optimizer -- runs after CFG is built, but before register allocation
17 3) post_optimizer -- runs after register allocation
22 During pre-optimization we perform optimizations which don't require
23 full knowledge of the control flow graph and the life ranges of each
24 variable. This phase is handled by two functions: pre_optimize() and
27 pre_optimize() runs before the construction of the CFG begins. It calls
28 strength_reduce() to perform simple strength reduction, and if_branch()
29 to rewrite certain if/branch/label constructs (for details, see
32 [pre_optimize() may also be called later, during the main optimization
33 phase, but this is not guaranteed.]
35 cfg_optimize() runs during the construction of the CFG. It calls
36 branch_branch() to perform jump optimization (i.e. branches to
37 branch statements or jumps to jumps are converted into single
38 branches/jumps to the final destination), unused_label() to remove
39 unused labels and dead_code_remove() to remove unreachable code
40 (e.g. basic blocks which are never entered or instructions after
41 and unconditional branch which are never branched to).
43 cfg_optimize may be called multiple times during the construction of the
44 CFG depending on whether or not it finds anything to optimize.
46 RT#46277: subst_constants ... rewrite e.g. add_i_ic_ic -- where does this happen?
51 runs with CFG and life info
53 used_once ... deletes assignments, when LHS is unused
54 loop_optimization ... pulls invariants out of loops
55 RT#46279 e.g. constant_propagation
57 post_optimizer: currently pcc_optimize in pcc.c
60 runs after register alloocation
62 e.g. eliminate new Px .PerlUndef because Px where different before
75 #include "optimizer.h"
77 /* HEADERIZER HFILE: compilers/imcc/optimizer.h */
80 /* buggy - turned off */
81 #define DO_LOOP_OPTIMIZATION 0
83 /* HEADERIZER BEGIN: static */
85 static int branch_branch(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
))
86 __attribute__nonnull__(1)
87 __attribute__nonnull__(2)
90 static int branch_cond_loop(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
))
91 __attribute__nonnull__(1)
92 __attribute__nonnull__(2)
95 PARROT_WARN_UNUSED_RESULT
96 static int branch_cond_loop_swap(PARROT_INTERP
,
97 ARGMOD(IMC_Unit
*unit
),
98 ARGMOD(Instruction
*branch
),
99 ARGMOD(Instruction
*start
),
100 ARGMOD(Instruction
*cond
))
101 __attribute__nonnull__(1)
102 __attribute__nonnull__(2)
103 __attribute__nonnull__(3)
104 __attribute__nonnull__(4)
105 __attribute__nonnull__(5)
107 FUNC_MODIFIES(*branch
)
108 FUNC_MODIFIES(*start
)
109 FUNC_MODIFIES(*cond
);
111 PARROT_WARN_UNUSED_RESULT
112 static int branch_reorg(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
))
113 __attribute__nonnull__(1)
114 __attribute__nonnull__(2)
115 FUNC_MODIFIES(*unit
);
117 static int constant_propagation(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
))
118 __attribute__nonnull__(1)
119 __attribute__nonnull__(2)
120 FUNC_MODIFIES(*unit
);
122 static int dead_code_remove(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
))
123 __attribute__nonnull__(1)
124 __attribute__nonnull__(2)
125 FUNC_MODIFIES(*unit
);
127 PARROT_WARN_UNUSED_RESULT
128 static int eval_ins(PARROT_INTERP
,
129 ARGIN(const char *op
),
132 __attribute__nonnull__(1)
133 __attribute__nonnull__(2)
134 __attribute__nonnull__(4);
136 static int if_branch(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
))
137 __attribute__nonnull__(1)
138 __attribute__nonnull__(2)
139 FUNC_MODIFIES(*unit
);
141 #if DO_LOOP_OPTIMIZATION
143 PARROT_WARN_UNUSED_RESULT
144 static int _is_ins_save(
145 ARGIN(const IMC_Unit
*unit
),
146 ARGIN(const Instruction
*check_ins
),
147 ARGIN(const SymReg
*r
),
149 __attribute__nonnull__(1)
150 __attribute__nonnull__(2)
151 __attribute__nonnull__(3);
153 PARROT_WARN_UNUSED_RESULT
154 static int is_ins_save(PARROT_INTERP
,
155 ARGIN(const IMC_Unit
*unit
),
156 ARGIN(const Instruction
*ins
),
157 ARGIN(const SymReg
*r
),
159 __attribute__nonnull__(1)
160 __attribute__nonnull__(2)
161 __attribute__nonnull__(3)
162 __attribute__nonnull__(4);
164 #endif /* DO_LOOP_OPTIMIZATION */
166 static int strength_reduce(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
))
167 __attribute__nonnull__(1)
168 __attribute__nonnull__(2)
169 FUNC_MODIFIES(*unit
);
171 PARROT_WARN_UNUSED_RESULT
172 static int unused_label(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
))
173 __attribute__nonnull__(1)
174 __attribute__nonnull__(2)
175 FUNC_MODIFIES(*unit
);
177 static int used_once(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
))
178 __attribute__nonnull__(1)
179 __attribute__nonnull__(2)
180 FUNC_MODIFIES(*unit
);
182 /* HEADERIZER END: static */
183 #if DO_LOOP_OPTIMIZATION
184 int loop_optimization(Interp
*, IMC_Unit
*);
189 =item C<int pre_optimize>
191 Handles optimizations occuring before the construction of the CFG.
198 pre_optimize(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
))
202 if (IMCC_INFO(interp
)->optimizer_level
& OPT_PRE
) {
203 IMCC_info(interp
, 2, "pre_optimize\n");
204 /* RT#46281 integrate all in one pass */
205 changed
+= strength_reduce(interp
, unit
);
206 if (!IMCC_INFO(interp
)->dont_optimize
)
207 changed
+= if_branch(interp
, unit
);
214 =item C<int cfg_optimize>
216 Handles optimizations occuring during the construction of the CFG.
217 Returns TRUE if any optimization was performed. Otherwise, returns
224 PARROT_WARN_UNUSED_RESULT
226 cfg_optimize(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
))
228 if (IMCC_INFO(interp
)->dont_optimize
)
230 if (IMCC_INFO(interp
)->optimizer_level
& OPT_PRE
) {
231 IMCC_info(interp
, 2, "cfg_optimize\n");
232 if (branch_branch(interp
, unit
))
234 if (branch_cond_loop(interp
, unit
))
236 if (branch_reorg(interp
, unit
))
238 /* RT#46283 cfg / loop detection breaks e.g. in t/compiler/5_3 */
239 if (unused_label(interp
, unit
))
241 if (dead_code_remove(interp
, unit
))
249 =item C<int optimize>
251 RT#48260: Not yet documented!!!
258 optimize(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
))
261 if (IMCC_INFO(interp
)->optimizer_level
& OPT_CFG
) {
262 IMCC_info(interp
, 2, "optimize\n");
263 any
= constant_propagation(interp
, unit
);
264 if (used_once(interp
, unit
))
266 #if DO_LOOP_OPTIMIZATION
267 if (loop_optimization(interp
, unit
))
276 =item C<const char * get_neg_op>
278 Get negated form of operator. If no negated form is known, return NULL.
284 PARROT_WARN_UNUSED_RESULT
285 PARROT_CAN_RETURN_NULL
287 get_neg_op(ARGIN(const char *op
), ARGOUT(int *n
))
289 static const struct br_pairs
{
290 const char * const op
;
291 const char * const nop
;
294 { "if", "unless", 2 },
300 for (i
= 0; i
< N_ELEMENTS(br_pairs
); i
++) {
302 if (STREQ(op
, br_pairs
[i
].op
))
303 return br_pairs
[i
].nop
;
304 if (STREQ(op
, br_pairs
[i
].nop
))
305 return br_pairs
[i
].op
;
315 =item C<static int if_branch>
317 Convert if/branch/label constructs of the form:
323 to the simpler negated form:
332 if_branch(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
))
334 Instruction
*ins
, *last
;
335 int reg
, changed
= 0;
337 last
= unit
->instructions
;
340 IMCC_info(interp
, 2, "\tif_branch\n");
341 for (ins
= last
->next
; ins
;) {
342 if ((last
->type
& ITBRANCH
) && /* if ...L1 */
343 (ins
->type
& IF_goto
) && /* branch L2*/
344 STREQ(ins
->opname
, "branch") &&
345 (reg
= get_branch_regno(last
)) >= 0) {
346 SymReg
* const br_dest
= last
->symregs
[reg
];
348 (ins
->next
->type
& ITLABEL
) && /* L1 */
349 ins
->next
->symregs
[0] == br_dest
) {
351 SymReg
* const go
= get_branch_reg(ins
);
354 IMCC_debug(interp
, DEBUG_OPT1
, "if_branch %s ... %s\n",
355 last
->opname
, br_dest
->name
);
356 /* find the negated op (e.g if->unless, ne->eq ... */
357 if ((neg_op
= get_neg_op(last
->opname
, &args
)) != 0) {
359 last
->symregs
[reg
] = go
;
360 tmp
= INS(interp
, unit
, (char*)neg_op
, "",
361 last
->symregs
, args
, 0, 0);
362 last
->opnum
= tmp
->opnum
;
363 last
->opsize
= tmp
->opsize
;
365 last
->opname
= str_dup(tmp
->opname
);
369 unit
->ostat
.deleted_ins
++;
370 ins
= delete_ins(unit
, ins
);
371 unit
->ostat
.if_branch
++;
375 } /* branch detected */
384 =item C<static int strength_reduce>
386 strength_reduce ... rewrites e.g add Ix, Ix, y => add Ix, y
388 These are run after constant simplification, so it is
389 guaranteed that one operand is non constant if opsize == 4
396 strength_reduce(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
))
398 Instruction
*ins
, *tmp
;
403 IMCC_info(interp
, 2, "\tstrength_reduce\n");
404 for (ins
= unit
->instructions
; ins
; ins
= ins
->next
) {
406 * add Ix, Ix, Iy => add Ix, Iy
407 * add Ix, Iy, Ix => add Ix, Iy
408 * sub Ix, Ix, Iy => sub Ix, Iy
409 * mul Ix, Ix, Iy => sub Ix, Iy
410 * mul Ix, Iy, Ix => sub Ix, Iy
411 * div Ix, Ix, Iy => sub Ix, Iy
412 * fdiv Ix, Ix, Iy => sub Ix, Iy
413 * add Nx, Nx, Ny => add Nx, Ny
414 * add Nx, Ny, Nx => add Nx, Ny
415 * sub Nx, Nx, Ny => sub Nx, Ny
416 * mul Nx, Nx, Ny => sub Nx, Ny
417 * mul Nx, Ny, Nx => sub Nx, Ny
418 * div Nx, Nx, Ny => sub Nx, Ny
419 * fdiv Nx, Nx, Ny => sub Nx, Ny
421 if (((ins
->opnum
== PARROT_OP_sub_i_i_i
||
422 ins
->opnum
== PARROT_OP_sub_i_i_ic
||
423 ins
->opnum
== PARROT_OP_sub_i_ic_i
||
424 ins
->opnum
== PARROT_OP_div_i_i_i
||
425 ins
->opnum
== PARROT_OP_div_i_i_ic
||
426 ins
->opnum
== PARROT_OP_div_i_ic_i
||
427 ins
->opnum
== PARROT_OP_fdiv_i_i_i
||
428 ins
->opnum
== PARROT_OP_fdiv_i_i_ic
||
429 ins
->opnum
== PARROT_OP_fdiv_i_ic_i
||
430 ins
->opnum
== PARROT_OP_sub_n_n_n
||
431 ins
->opnum
== PARROT_OP_sub_n_n_nc
||
432 ins
->opnum
== PARROT_OP_sub_n_nc_n
||
433 ins
->opnum
== PARROT_OP_div_n_n_n
||
434 ins
->opnum
== PARROT_OP_div_n_n_nc
||
435 ins
->opnum
== PARROT_OP_div_n_nc_n
||
436 ins
->opnum
== PARROT_OP_fdiv_n_n_n
||
437 ins
->opnum
== PARROT_OP_fdiv_n_n_nc
||
438 ins
->opnum
== PARROT_OP_fdiv_n_nc_n
) &&
439 ins
->symregs
[0] == ins
->symregs
[1])
440 || ((ins
->opnum
== PARROT_OP_add_i_i_i
||
441 ins
->opnum
== PARROT_OP_add_i_i_ic
||
442 ins
->opnum
== PARROT_OP_add_i_ic_i
||
443 ins
->opnum
== PARROT_OP_mul_i_i_i
||
444 ins
->opnum
== PARROT_OP_mul_i_i_ic
||
445 ins
->opnum
== PARROT_OP_mul_i_ic_i
||
446 ins
->opnum
== PARROT_OP_add_n_n_n
||
447 ins
->opnum
== PARROT_OP_add_n_n_nc
||
448 ins
->opnum
== PARROT_OP_add_n_nc_n
||
449 ins
->opnum
== PARROT_OP_mul_n_n_n
||
450 ins
->opnum
== PARROT_OP_mul_n_n_nc
||
451 ins
->opnum
== PARROT_OP_mul_n_nc_n
) &&
452 (ins
->symregs
[0] == ins
->symregs
[1] ||
453 ins
->symregs
[0] == ins
->symregs
[2]))) {
454 IMCC_debug(interp
, DEBUG_OPT1
, "opt1 %I => ", ins
);
455 if (ins
->symregs
[0] == ins
->symregs
[1]) {
456 ins
->symregs
[1] = ins
->symregs
[2];
458 tmp
= INS(interp
, unit
, ins
->opname
, "", ins
->symregs
, 2, 0, 0);
459 IMCC_debug(interp
, DEBUG_OPT1
, "%I\n", tmp
);
460 subst_ins(unit
, ins
, tmp
, 1);
465 * add Ix, 0 => delete
466 * sub Ix, 0 => delete
467 * mul Ix, 1 => delete
468 * div Ix, 1 => delete
469 * fdiv Ix, 1 => delete
470 * add Nx, 0 => delete
471 * sub Nx, 0 => delete
472 * mul Nx, 1 => delete
473 * div Nx, 1 => delete
474 * fdiv Nx, 1 => delete
476 if (((ins
->opnum
== PARROT_OP_add_i_ic
||
477 ins
->opnum
== PARROT_OP_sub_i_ic
) &&
478 IMCC_int_from_reg(interp
, ins
->symregs
[1]) == 0)
479 || ((ins
->opnum
== PARROT_OP_mul_i_ic
||
480 ins
->opnum
== PARROT_OP_div_i_ic
||
481 ins
->opnum
== PARROT_OP_fdiv_i_ic
) &&
482 IMCC_int_from_reg(interp
, ins
->symregs
[1]) == 1)
483 || ((ins
->opnum
== PARROT_OP_add_n_nc
||
484 ins
->opnum
== PARROT_OP_sub_n_nc
) &&
485 (f
= atof(ins
->symregs
[1]->name
), FLOAT_IS_ZERO(f
)))
486 || ((ins
->opnum
== PARROT_OP_mul_n_nc
||
487 ins
->opnum
== PARROT_OP_div_n_nc
||
488 ins
->opnum
== PARROT_OP_fdiv_n_nc
) &&
489 atof(ins
->symregs
[1]->name
) == 1.0)) {
490 IMCC_debug(interp
, DEBUG_OPT1
, "opt1 %I => ", ins
);
491 ins
= delete_ins(unit
, ins
);
493 ins
= ins
->prev
? ins
->prev
: unit
->instructions
;
496 IMCC_debug(interp
, DEBUG_OPT1
, "deleted\n");
501 * add Ix, 1 => inc Ix
502 * add Nx, 1 => inc Nx
503 * sub Ix, 1 => dec Ix
504 * sub Nx, 1 => dec Nx
506 if (((ins
->opnum
== PARROT_OP_add_i_ic
||
507 ins
->opnum
== PARROT_OP_sub_i_ic
) &&
508 IMCC_int_from_reg(interp
, ins
->symregs
[1]) == 1)
509 || ((ins
->opnum
== PARROT_OP_add_n_nc
||
510 ins
->opnum
== PARROT_OP_sub_n_nc
) &&
511 atof(ins
->symregs
[1]->name
) == 1.0)) {
512 IMCC_debug(interp
, DEBUG_OPT1
, "opt1 %I => ", ins
);
513 --ins
->symregs
[1]->use_count
;
514 if (ins
->opnum
== PARROT_OP_add_i_ic
||
515 ins
->opnum
== PARROT_OP_add_n_nc
)
516 tmp
= INS(interp
, unit
, "inc", "", ins
->symregs
, 1, 0, 0);
518 tmp
= INS(interp
, unit
, "dec", "", ins
->symregs
, 1, 0, 0);
519 subst_ins(unit
, ins
, tmp
, 1);
520 IMCC_debug(interp
, DEBUG_OPT1
, "%I\n", tmp
);
526 * add Ix, Iy, 0 => set Ix, Iy
527 * add Ix, 0, Iy => set Ix, Iy
528 * sub Ix, Iy, 0 => set Ix, Iy
529 * mul Ix, Iy, 1 => set Ix, Iy
530 * mul Ix, 1, Iy => set Ix, Iy
531 * div Ix, Iy, 1 => set Ix, Iy
532 * fdiv Ix, Iy, 1 => set Ix, Iy
533 * add Nx, Ny, 0 => set Nx, Ny
534 * add Nx, 0, Ny => set Nx, Ny
535 * sub Nx, Ny, 0 => set Nx, Ny
536 * mul Nx, Ny, 1 => set Nx, Ny
537 * mul Nx, 1, Ny => set Nx, Ny
538 * div Nx, Ny, 1 => set Nx, Ny
539 * fdiv Nx, Ny, 1 => set Nx, Ny
541 if (((ins
->opnum
== PARROT_OP_add_i_i_ic
||
542 ins
->opnum
== PARROT_OP_sub_i_i_ic
) &&
543 IMCC_int_from_reg(interp
, ins
->symregs
[2]) == 0)
544 || (ins
->opnum
== PARROT_OP_add_i_ic_i
&&
545 IMCC_int_from_reg(interp
, ins
->symregs
[1]) == 0)
546 || ((ins
->opnum
== PARROT_OP_mul_i_i_ic
||
547 ins
->opnum
== PARROT_OP_div_i_i_ic
||
548 ins
->opnum
== PARROT_OP_fdiv_i_i_ic
) &&
549 IMCC_int_from_reg(interp
, ins
->symregs
[2]) == 1)
550 || (ins
->opnum
== PARROT_OP_mul_i_ic_i
&&
551 IMCC_int_from_reg(interp
, ins
->symregs
[1]) == 1)
552 || ((ins
->opnum
== PARROT_OP_add_n_n_nc
||
553 ins
->opnum
== PARROT_OP_sub_n_n_nc
) &&
554 (f
= atof(ins
->symregs
[2]->name
), FLOAT_IS_ZERO(f
)))
555 || (ins
->opnum
== PARROT_OP_add_n_nc_n
&&
556 (f
= atof(ins
->symregs
[1]->name
), FLOAT_IS_ZERO(f
)))
557 || ((ins
->opnum
== PARROT_OP_mul_n_n_nc
||
558 ins
->opnum
== PARROT_OP_div_n_n_nc
||
559 ins
->opnum
== PARROT_OP_fdiv_n_n_nc
) &&
560 atof(ins
->symregs
[2]->name
) == 1.0)
561 || (ins
->opnum
== PARROT_OP_mul_n_nc_n
&&
562 atof(ins
->symregs
[1]->name
) == 1.0)) {
563 IMCC_debug(interp
, DEBUG_OPT1
, "opt1 %I => ", ins
);
564 if (ins
->symregs
[1]->type
== VTCONST
) {
565 --ins
->symregs
[1]->use_count
;
566 ins
->symregs
[1] = ins
->symregs
[2];
569 --ins
->symregs
[2]->use_count
;
571 tmp
= INS(interp
, unit
, "set", "", ins
->symregs
, 2, 0, 0);
572 IMCC_debug(interp
, DEBUG_OPT1
, "%I\n", tmp
);
573 subst_ins(unit
, ins
, tmp
, 1);
579 * mul Ix, Iy, 0 => set Ix, 0
580 * mul Ix, 0, Iy => set Ix, 0
581 * mul Ix, 0 => set Ix, 0
583 if ((ins
->opnum
== PARROT_OP_mul_i_i_ic
&&
584 IMCC_int_from_reg(interp
, ins
->symregs
[2]) == 0)
585 || ((ins
->opnum
== PARROT_OP_mul_i_ic_i
||
586 ins
->opnum
== PARROT_OP_mul_i_ic
) &&
587 IMCC_int_from_reg(interp
, ins
->symregs
[1]) == 0)
588 || (ins
->opnum
== PARROT_OP_mul_n_n_nc
&&
589 (f
= atof(ins
->symregs
[2]->name
), FLOAT_IS_ZERO(f
)))
590 || ((ins
->opnum
== PARROT_OP_mul_n_nc_n
||
591 ins
->opnum
== PARROT_OP_mul_n_nc
) &&
592 (f
= atof(ins
->symregs
[1]->name
), FLOAT_IS_ZERO(f
)))) {
593 IMCC_debug(interp
, DEBUG_OPT1
, "opt1 %I => ", ins
);
594 r
= mk_const(interp
, "0", ins
->symregs
[0]->set
);
595 --ins
->symregs
[1]->use_count
;
596 if (ins
->opsize
== 4)
597 --ins
->symregs
[2]->use_count
;
599 tmp
= INS(interp
, unit
, "set", "", ins
->symregs
, 2, 0, 0);
600 IMCC_debug(interp
, DEBUG_OPT1
, "%I\n", tmp
);
601 subst_ins(unit
, ins
, tmp
, 1);
606 * set Ix, 0 => null Ix
607 * set Nx, 0 => null Nx
609 if ((ins
->opnum
== PARROT_OP_set_i_ic
&&
610 IMCC_int_from_reg(interp
, ins
->symregs
[1]) == 0)
611 || (ins
->opnum
== PARROT_OP_set_n_nc
&&
612 (f
= atof(ins
->symregs
[1]->name
), FLOAT_IS_ZERO(f
)) &&
613 ins
->symregs
[1]->name
[0] != '-')) {
614 IMCC_debug(interp
, DEBUG_OPT1
, "opt1 %I => ", ins
);
615 --ins
->symregs
[1]->use_count
;
616 tmp
= INS(interp
, unit
, "null", "", ins
->symregs
, 1, 0, 0);
617 subst_ins(unit
, ins
, tmp
, 1);
618 IMCC_debug(interp
, DEBUG_OPT1
, "%I\n", tmp
);
629 =item C<static int constant_propagation>
631 Does conservative constant propagation.
632 This code will not propagate constants past labels or saves,
633 even though sometimes it may be safe.
640 constant_propagation(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
))
642 Instruction
*ins
, *ins2
, *tmp
, *prev
;
647 o
= c
= NULL
; /* silence compiler uninit warning */
649 IMCC_info(interp
, 2, "\tconstant_propagation\n");
650 for (ins
= unit
->instructions
; ins
; ins
= ins
->next
) {
652 if (STREQ(ins
->opname
, "set") &&
653 ins
->opsize
== 3 && /* no keyed set */
654 ins
->symregs
[1]->type
== VTCONST
&&
655 ins
->symregs
[0]->set
!= 'P') { /* no PMC consts */
659 } else if (STREQ(ins
->opname
, "null") && ins
->symregs
[0]->set
== 'I') {
661 c
= mk_const(interp
, "0", 'I');
663 } /* this would be good because 'set I0, 0' is reduced to 'null I0'
664 before it gets to us */
667 IMCC_debug(interp
, DEBUG_OPT2
,
668 "propagating constant %I => \n", ins
);
669 for (ins2
= ins
->next
; ins2
; ins2
= ins2
->next
) {
670 if (ins2
->type
& ITSAVES
||
671 /* restrict to within a basic block */
672 ins2
->bbindex
!= ins
->bbindex
)
674 /* was opsize - 2, changed to n_r - 1
676 for (i
= ins2
->symreg_count
- 1; i
>= 0; i
--) {
677 if (STREQ(o
->name
, ins2
->symregs
[i
]->name
)) {
678 if (instruction_writes(ins2
, ins2
->symregs
[i
]))
680 else if (instruction_reads(ins2
, ins2
->symregs
[i
])) {
682 IMCC_debug(interp
, DEBUG_OPT2
,
683 "\tpropagating into %I register %i",
685 old
= ins2
->symregs
[i
];
686 ins2
->symregs
[i
] = c
;
687 /* first we try subst_constants for e.g. if 10 < 5 goto next*/
688 tmp
= IMCC_subst_constants(interp
,
689 unit
, ins2
->opname
, ins2
->symregs
, ins2
->opsize
,
694 subst_ins(unit
, ins2
, tmp
, 1);
696 IMCC_debug(interp
, DEBUG_OPT2
,
697 " reduced to %I\n", tmp
);
703 const int op
= check_op(interp
, fullname
, ins2
->opname
,
704 ins2
->symregs
, ins2
->symreg_count
, ins2
->keys
);
706 ins2
->symregs
[i
] = old
;
707 IMCC_debug(interp
, DEBUG_OPT2
,
708 " - no %s\n", fullname
);
714 IMCC_debug(interp
, DEBUG_OPT2
,
722 }/* for (ins2 ... )*/
732 =item C<Instruction * IMCC_subst_constants_umix>
734 rewrite e.g. add_n_ic => add_n_nc
740 PARROT_WARN_UNUSED_RESULT
741 PARROT_CAN_RETURN_NULL
743 IMCC_subst_constants_umix(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
), ARGIN(const char *name
),
744 ARGMOD(SymReg
**r
), int n
)
747 const char * const ops
[] = {
748 "abs", "add", "div", "mul", "sub", "fdiv"
754 for (i
= 0; i
< N_ELEMENTS(ops
); i
++) {
757 r
[1]->type
== VTCONST
&&
759 STREQ(name
, ops
[i
])) {
760 IMCC_debug(interp
, DEBUG_OPT1
, "opt1 %s_nc_ic => ", name
);
761 strcpy(b
, r
[1]->name
);
762 r
[1] = mk_const(interp
, b
, 'N');
763 tmp
= INS(interp
, unit
, name
, "", r
, 2, 0, 0);
764 IMCC_debug(interp
, DEBUG_OPT1
, "%I\n", tmp
);
772 =item C<static int eval_ins>
774 Run one parrot instruction, registers are filled with the
775 according constants. If an exception occurs, return -1, aborting
776 this optimization: this lets the runtime handle any exceptions.
782 PARROT_WARN_UNUSED_RESULT
784 eval_ins(PARROT_INTERP
, ARGIN(const char *op
), size_t ops
, ARGIN(SymReg
**r
))
786 opcode_t eval
[4], *pc
;
791 opnum
= interp
->op_lib
->op_code(op
, 1);
793 IMCC_fatal(interp
, 1, "eval_ins: op '%s' not found\n", op
);
794 op_info
= interp
->op_info_table
+ opnum
;
795 /* now fill registers */
797 for (i
= 0; i
< op_info
->op_count
- 1; i
++) {
798 switch (op_info
->types
[i
]) {
800 PARROT_ASSERT(i
&& ops
== (unsigned int)i
);
801 /* set branch offset to zero */
807 eval
[i
+ 1] = i
; /* regs used are I0, I1, I2 */
808 if (ops
<= 2 || i
) { /* fill source regs */
811 REG_INT(interp
, i
) = IMCC_int_from_reg(interp
, r
[i
]);
815 STRING
* const s
= string_from_cstring(interp
, r
[i
]->name
, 0);
816 REG_NUM(interp
, i
) = string_to_num(interp
, s
);
820 REG_STR(interp
, i
) = IMCC_string_from_reg(interp
, r
[i
]);
828 IMCC_fatal(interp
, 1, "eval_ins"
829 "invalid arg #%d for op '%s' not found\n",
834 /* eval the opcode */
835 new_internal_exception(interp
);
836 if (setjmp(interp
->exceptions
->destination
))
839 pc
= (interp
->op_func_table
[opnum
]) (eval
, interp
);
840 free_internal_exception(interp
);
841 /* the returned pc is either incremented by op_count or is eval,
842 * as the branch offset is 0 - return true if it branched
844 PARROT_ASSERT(pc
== eval
+ op_info
->op_count
|| pc
== eval
);
850 =item C<Instruction * IMCC_subst_constants>
852 rewrite e.g. add_n_nc_nc => set_n_nc
854 eq_ic_ic_ic => branch_ic / delete
855 if_ic_ic => branch_ic / delete
861 PARROT_WARN_UNUSED_RESULT
862 PARROT_CAN_RETURN_NULL
864 IMCC_subst_constants(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
), ARGIN(const char *name
),
865 ARGMOD(SymReg
**r
), int n
, ARGOUT(int *ok
))
868 const char * const ops
[] = {
869 "add", "sub", "mul", "div", "fdiv", "pow",
870 "cmod", "mod", "atan",
873 "band", "bor", "bxor",
874 "bands", "bors", "bxors",
876 "iseq", "isne", "islt", "isle", "isgt", "isge", "cmp"
878 const char * const ops2
[] = {
879 "abs", "neg", "not", "fact", "sqrt", "ceil", "floor"
880 "acos", "asec", "asin",
881 "atan", "cos", "cosh", "exp", "ln", "log10", "log2", "sec",
882 "sech", "sin", "sinh", "tan", "tanh", "fact"
884 const char * const ops3
[] = {
885 "eq", "ne", "gt", "ge", "lt", "le"
887 const char * const ops4
[] = {
892 char fmt
[64], op
[20];
893 const char *debug_fmt
= NULL
; /* gcc -O uninit warn */
896 /* construct a FLOATVAL_FMT with needed precision */
897 switch (NUMVAL_SIZE
) {
899 strcpy(fmt
, "%0.16g");
902 strcpy(fmt
, "%0.18Lg");
905 IMCC_warning(interp
, "subs_constants",
906 "used default FLOATVAL_FMT\n");
907 strcpy(fmt
, FLOATVAL_FMT
);
913 for (i
= 0; i
< N_ELEMENTS(ops
); i
++) {
915 r
[1]->type
& (VTCONST
|VT_CONSTP
) &&
916 r
[2]->type
& (VTCONST
|VT_CONSTP
) &&
917 STREQ(name
, ops
[i
])) {
920 * create instruction e.g. add_i_ic_ic => add_i_i_i
922 snprintf(op
, sizeof (op
), "%s_%c_%c_%c", name
, tolower((unsigned char)r
[0]->set
),
923 tolower((unsigned char)r
[1]->set
), tolower((unsigned char)r
[2]->set
));
924 debug_fmt
= "opt %s_x_xc_xc => ";
928 for (i
= 0; !found
&& i
< N_ELEMENTS(ops2
); i
++) {
933 r
[1]->type
& (VTCONST
|VT_CONSTP
) &&
934 STREQ(name
, ops2
[i
])) {
936 snprintf(op
, sizeof (op
), "%s_%c_%c", name
, tolower((unsigned char)r
[0]->set
),
937 tolower((unsigned char)r
[1]->set
));
938 debug_fmt
= "opt %s_x_xc => ";
942 for (i
= 0; !found
&& i
< N_ELEMENTS(ops3
); i
++) {
944 * eq_xc_xc_labelc ...
947 r
[0]->type
& (VTCONST
|VT_CONSTP
) &&
948 r
[1]->type
& (VTCONST
|VT_CONSTP
) &&
949 STREQ(name
, ops3
[i
])) {
951 snprintf(op
, sizeof (op
), "%s_%c_%c_ic", name
, tolower((unsigned char)r
[0]->set
),
952 tolower((unsigned char)r
[1]->set
));
953 debug_fmt
= "opt %s_xc_xc_ic => ";
957 for (i
= 0; !found
&& i
< N_ELEMENTS(ops4
); i
++) {
959 * if_xc_labelc, unless
962 r
[0]->type
& (VTCONST
|VT_CONSTP
) &&
963 STREQ(name
, ops4
[i
])) {
965 snprintf(op
, sizeof (op
), "%s_%c_ic", name
, tolower((unsigned char)r
[0]->set
));
966 debug_fmt
= "opt %s_xc_ic => ";
976 IMCC_debug(interp
, DEBUG_OPT1
, debug_fmt
, name
);
977 /* we construct a parrot instruction
978 * here and let parrot do the calculation in a
979 * separate context and make a constant
982 branched
= eval_ins(interp
, op
, found
, r
);
983 if (branched
== -1) {
984 /* Don't set ok (See RT #43048 for info) */
988 * for math ops result is in I0/N0
989 * if it was a branch with constant args, the result is
994 * create a branch or delete instruction
998 tmp
= INS(interp
, unit
, "branch", "", r
, 1, 0, 0);
1001 IMCC_debug(interp
, DEBUG_OPT1
, "deleted\n");
1006 * create set x, constant
1009 switch (r
[0]->set
) {
1011 snprintf(b
, sizeof (b
), INTVAL_FMT
, REG_INT(interp
, 0));
1014 snprintf(b
, sizeof (b
), fmt
, REG_NUM(interp
, 0));
1019 r
[1] = mk_const(interp
, b
, r
[0]->set
);
1020 tmp
= INS(interp
, unit
, "set", "", r
, 2, 0, 0);
1023 IMCC_debug(interp
, DEBUG_OPT1
, "%I\n", tmp
);
1030 /* optimizations with CFG built */
1034 =item C<static int branch_branch>
1036 if I0 goto L1 => if IO goto L2
1041 Returns TRUE if any optimizations were performed. Otherwise, returns
1049 branch_branch(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
))
1054 IMCC_info(interp
, 2, "\tbranch_branch\n");
1055 /* reset statistic globals */
1056 for (ins
= unit
->instructions
; ins
; ins
= ins
->next
) {
1057 if (get_branch_regno(ins
) >= 0) {
1058 SymReg
* const r
= get_sym(interp
, get_branch_reg(ins
)->name
);
1060 if (r
&& (r
->type
& VTADDRESS
) && r
->first_ins
) {
1061 Instruction
* const next
= r
->first_ins
->next
;
1063 STREQ(next->symregs[0]->name, get_branch_reg(ins)->name))
1066 (next
->type
& IF_goto
) &&
1067 STREQ(next
->opname
, "branch") &&
1068 !STREQ(next
->symregs
[0]->name
, get_branch_reg(ins
)->name
)) {
1069 const int regno
= get_branch_regno(ins
);
1070 IMCC_debug(interp
, DEBUG_OPT1
,
1071 "found branch to branch '%s' %I\n",
1072 r
->first_ins
->symregs
[0]->name
, next
);
1073 unit
->ostat
.branch_branch
++;
1075 real_exception(interp
, NULL
, 1,
1076 "Register number determination failed in branch_branch()");
1078 ins
->symregs
[regno
] = next
->symregs
[0];
1089 =item C<static int branch_reorg>
1100 Returns TRUE if any optimizations were performed. Otherwise, returns
1107 PARROT_WARN_UNUSED_RESULT
1109 branch_reorg(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
))
1113 IMCC_info(interp
, 2, "\tbranch_reorg\n");
1114 for (i
= 0; i
< unit
->n_basic_blocks
; i
++) {
1115 Instruction
*ins
= unit
->bb_list
[i
]->end
;
1117 /* if basic block ends with unconditional jump */
1118 if ((ins
->type
& IF_goto
) && STREQ(ins
->opname
, "branch")) {
1119 SymReg
* const r
= get_sym(interp
, ins
->symregs
[0]->name
);
1120 if (r
&& (r
->type
& VTADDRESS
) && r
->first_ins
) {
1122 Instruction
* const start
= r
->first_ins
;
1124 for (edge
= unit
->bb_list
[start
->bbindex
]->pred_list
;
1125 edge
; edge
= edge
->pred_next
)
1127 if (edge
->from
->index
== start
->bbindex
- 1) {
1132 /* if target block is not reached by falling into it
1133 * from another block */
1136 /* move target block and its positional successors
1137 * to follow block with unconditional jump
1138 * (this could actually be in another block) */
1139 for (end
= start
; end
->next
; end
= end
->next
) {
1140 if ((end
->type
& IF_goto
) &&
1141 STREQ(end
->opname
, "branch")) {
1146 /* this was screwing up multi-block loops... */
1147 if (end
!= ins
&& ins
->next
!= NULL
) {
1148 ins
->next
->prev
= end
;
1149 start
->prev
->next
= end
->next
;
1151 end
->next
->prev
= start
->prev
;
1152 end
->next
= ins
->next
;
1155 IMCC_debug(interp
, DEBUG_OPT1
,
1156 "found branch to reorganize '%s' %I\n",
1157 r
->first_ins
->symregs
[0]->name
, ins
);
1158 /* unconditional jump can be eliminated */
1159 unit
->ostat
.deleted_ins
++;
1160 ins
= delete_ins(unit
, ins
);
1172 =item C<static int branch_cond_loop_swap>
1174 RT#48260: Not yet documented!!!
1180 PARROT_WARN_UNUSED_RESULT
1182 branch_cond_loop_swap(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
), ARGMOD(Instruction
*branch
),
1183 ARGMOD(Instruction
*start
), ARGMOD(Instruction
*cond
))
1187 const char * const neg_op
= get_neg_op(cond
->opname
, &args
);
1189 const size_t size
= strlen(branch
->symregs
[0]->name
) + 10; /* + '_post999' */
1190 char * const label
= (char *)mem_sys_allocate(size
);
1194 for (count
= 1; count
!= 999; ++count
) {
1195 snprintf(label
, size
, "%s_post%d", branch
->symregs
[0]->name
, count
);
1196 if (get_sym(interp
, label
) == 0) {
1204 SymReg
*regs
[3], *r
;
1207 /* cond_op has 2 or 3 args */
1208 PARROT_ASSERT(args
<= 3);
1210 r
= mk_local_label(interp
, label
);
1211 tmp
= INS_LABEL(interp
, unit
, r
, 0);
1212 insert_ins(unit
, cond
, tmp
);
1214 for (start
= start
->next
; start
!= cond
; start
= start
->next
) {
1215 if (!(start
->type
& ITLABEL
)) {
1216 tmp
= INS(interp
, unit
, start
->opname
, "",
1217 start
->symregs
, start
->symreg_count
, start
->keys
, 0);
1218 prepend_ins(unit
, branch
, tmp
);
1222 for (count
= 0; count
!= args
; ++count
) {
1223 regs
[count
] = cond
->symregs
[count
];
1226 reg_index
= get_branch_regno(cond
);
1227 if (reg_index
< 0) {
1228 real_exception(interp
, NULL
, 1,
1229 "Negative branch register address detected");
1231 regs
[reg_index
] = mk_label_address(interp
, label
);
1232 tmp
= INS(interp
, unit
, (const char*)neg_op
, "", regs
, args
, 0, 0);
1234 IMCC_debug(interp
, DEBUG_OPT1
,
1235 "loop %s -> %s converted to post-test, added label %s\n",
1236 branch
->symregs
[0]->name
, get_branch_reg(cond
)->name
, label
);
1238 subst_ins(unit
, branch
, tmp
, 1);
1239 unit
->ostat
.branch_cond_loop
++;
1251 =item C<static int branch_cond_loop>
1254 if cond goto end if cond goto end
1256 branch start start_post1:
1258 unless cond goto start_post562
1261 The basic premise is "branch (A) to conditional (B), where B goes to
1264 Returns TRUE if any optimizations were performed. Otherwise, returns
1272 branch_cond_loop(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
))
1274 Instruction
*ins
, *cond
, *start
, *prev
;
1275 int changed
= 0, found
;
1277 IMCC_info(interp
, 2, "\tbranch_cond_loop\n");
1278 /* reset statistic globals */
1280 for (ins
= unit
->instructions
; ins
; ins
= ins
->next
) {
1281 if ((ins
->type
& IF_goto
) && STREQ(ins
->opname
, "branch")) {
1282 /* get `end` label */
1283 Instruction
* const end
= ins
->next
;
1284 /* get `start` label */
1285 SymReg
* const r
= get_sym(interp
, ins
->symregs
[0]->name
);
1287 if (end
&& (end
->type
& ITLABEL
) &&
1288 r
&& (r
->type
& VTADDRESS
) && r
->first_ins
) {
1290 start
= r
->first_ins
;
1293 for (cond
= start
->next
; cond
; cond
= cond
->next
) {
1294 /* no good if it's an unconditional branch*/
1295 if (cond
->type
& IF_goto
&& STREQ(cond
->opname
, "branch")) {
1297 } else if (cond
->type
& ITPCCRET
|| cond
->type
& ITPCCSUB
1298 || cond
->type
& ITCALL
) {
1300 /* just until we can copy set_args et al */
1301 } else if (cond
->type
& ITBRANCH
&&
1302 get_branch_regno(cond
) >= 0) {
1309 const char * const lbl
= get_branch_reg(cond
)->name
;
1310 const SymReg
* const r
= get_sym(interp
, lbl
);
1311 if (r
&& (r
->type
& VTADDRESS
) && r
->first_ins
== end
) {
1312 /* the current ins is replaced - remember prev
1313 * and set ins again after the changes
1318 changed
|= branch_cond_loop_swap(interp
,
1319 unit
, ins
, start
, cond
);
1331 =item C<static int unused_label>
1333 Removes unused labels. A label is unused if ... [RT#46287: finish this].
1335 Returns TRUE if any optimizations were performed. Otherwise, returns
1342 PARROT_WARN_UNUSED_RESULT
1344 unused_label(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
))
1350 IMCC_info(interp
, 2, "\tunused_label\n");
1351 for (i
=1; i
< unit
->n_basic_blocks
; i
++) {
1352 Instruction
*ins
= unit
->bb_list
[i
]->start
;
1353 if ((ins
->type
& ITLABEL
) && *ins
->symregs
[0]->name
!= '_') {
1354 const SymReg
* const lab
= ins
->symregs
[0];
1356 if (IMCC_INFO(interp
)->has_compile
)
1358 if (!lab
->first_ins
)
1361 else if (lab
->last_ins
)
1368 for (j
=0; unit
->bb_list
[j
]; j
++) {
1369 /* a branch can be the first ins in a block
1370 * (if prev ins was a label)
1371 * or the last ins in a block
1373 ins2
= unit
->bb_list
[j
]->start
;
1374 if ((ins2
->type
& ITBRANCH
) &&
1375 (addr
= get_branch_reg(ins2
)) != 0) {
1376 if (addr
== lab
&& addr
->type
== VTADDRESS
) {
1381 ins2
= unit
->bb_list
[j
]->end
;
1382 if ((ins2
->type
& ITBRANCH
) &&
1383 (addr
= get_branch_reg(ins2
)) != 0) {
1384 if (addr
== lab
&& addr
->type
== VTADDRESS
) {
1393 unit
->ostat
.deleted_labels
++;
1394 IMCC_debug(interp
, DEBUG_OPT1
,
1395 "block %d label %s deleted\n", i
, lab
->name
);
1396 unit
->ostat
.deleted_ins
++;
1397 ins
= delete_ins(unit
, ins
);
1408 =item C<static int dead_code_remove>
1410 RT#48260: Not yet documented!!!
1417 dead_code_remove(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
))
1421 Instruction
*ins
, *last
;
1423 /* this could be a separate level, now it's done with -O1 */
1424 if (!(IMCC_INFO(interp
)->optimizer_level
& OPT_PRE
))
1426 IMCC_info(interp
, 2, "\tdead_code_remove\n");
1428 /* Unreachable blocks */
1430 for (i
=1; i
< unit
->n_basic_blocks
; i
++) {
1431 Basic_block
* const bb
= unit
->bb_list
[i
];
1433 if ((bb
->start
->type
& ITLABEL
) && *bb
->start
->symregs
[0]->name
== '_')
1435 /* this block isn't entered from anywhere */
1436 if (!bb
->pred_list
) {
1437 const int bbi
= bb
->index
;
1438 IMCC_debug(interp
, DEBUG_OPT1
,
1439 "found dead block %d\n", bb
->index
);
1440 for (ins
= bb
->start
; ins
&& ins
->bbindex
== bbi
;) {
1441 IMCC_debug(interp
, DEBUG_OPT1
,
1442 "\tins deleted (dead block) %I\n", ins
);
1443 ins
= delete_ins(unit
, ins
);
1444 unit
->ostat
.deleted_ins
++;
1450 /* Unreachable instructions */
1452 for (last
= unit
->instructions
, ins
=last
->next
;
1455 if ((last
->type
& IF_goto
) && !(ins
->type
& ITLABEL
) &&
1456 STREQ(last
->opname
, "branch")) {
1457 IMCC_debug(interp
, DEBUG_OPT1
,
1458 "unreachable ins deleted (after branch) %I\n", ins
);
1459 ins
= delete_ins(unit
, ins
);
1460 unit
->ostat
.deleted_ins
++;
1467 if (ins
&& last
&& (last
->type
& IF_goto
) && (ins
->type
& ITLABEL
) &&
1468 STREQ(last
->opname
, "branch") &&
1469 STREQ(last
->symregs
[0]->name
, ins
->symregs
[0]->name
)) {
1470 IMCC_debug(interp
, DEBUG_OPT1
, "dead branch deleted %I\n", ins
);
1471 ins
= delete_ins(unit
, last
);
1472 unit
->ostat
.deleted_ins
++;
1482 /* optimizations with CFG & life info built */
1485 =item C<static int used_once>
1487 RT#48260: Not yet documented!!!
1494 used_once(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
))
1499 for (ins
= unit
->instructions
; ins
; ins
= ins
->next
) {
1501 SymReg
* const r
= ins
->symregs
[0];
1502 if (r
&& (r
->use_count
== 1 && r
->lhs_use_count
== 1)) {
1503 IMCC_debug(interp
, DEBUG_OPT2
, "used once '%I' deleted\n", ins
);
1504 ins
= delete_ins(unit
, ins
);
1505 ins
= ins
->prev
? ins
->prev
: unit
->instructions
;
1506 unit
->ostat
.deleted_ins
++;
1507 unit
->ostat
.used_once
++;
1515 #if DO_LOOP_OPTIMIZATION
1518 enum check_t
{ CHK_INV_NEW
, CHK_INV_SET
, CHK_CLONE
};
1522 =item C<static int _is_ins_save>
1524 RT#48260: Not yet documented!!!
1530 PARROT_WARN_UNUSED_RESULT
1532 _is_ins_save(ARGIN(const IMC_Unit
*unit
), ARGIN(const Instruction
*check_ins
),
1533 ARGIN(const SymReg
*r
), int what
)
1537 int use_count
, lhs_use_count
;
1539 int new_bl
=-1, set_bl
=-1;
1541 /* now check all instructions where r is used */
1543 /* we give up fast ;-) */
1547 if (r
->set
== 'P' && r
->lhs_use_count
!= 2)
1549 if (r
->set
!= 'P' && r
->lhs_use_count
!= 1)
1553 if (r
->set
== 'P' && r
->lhs_use_count
!= 2)
1560 use_count
= r
->use_count
;
1561 lhs_use_count
= r
->lhs_use_count
;
1562 for (bb
= 0; bb
< unit
->n_basic_blocks
; bb
++) {
1563 const Life_range
* const lr
= r
->life_info
[bb
];
1565 for (ins
= lr
->first_ins
; ins
; ins
= ins
->next
) {
1567 /* finished with this range */
1568 if (!lr
->last_ins
->next
|| ins
== lr
->last_ins
->next
)
1570 for (i
= in_use
= 0; ins
->symregs
[i
]; i
++)
1571 if (ins
->symregs
[i
] == r
) {
1578 /* var is in use in this ins */
1580 if (instruction_writes(ins
, r
)) {
1582 if (STREQ(ins
->opname
, "new"))
1584 if (STREQ(ins
->opname
, ""))
1587 /* this is the instruction, to check, it's safe */
1588 if (check_ins
== ins
)
1591 /* now look for dangerous ops */
1592 if (STREQ(ins
->opname
, "find_global"))
1594 if (STREQ(ins
->opname
, "store_global"))
1596 if (STREQ(ins
->opname
, "push"))
1598 if (STREQ(ins
->opname
, "pop"))
1600 if (STREQ(ins
->opname
, "clone"))
1602 /* indexed set/get ??? RT#46289, as index is ok */
1603 if (0 && STREQ(ins
->opname
, "set") && nregs
!= 2)
1606 * set P, P - dangerous?
1608 if (ins
->type
& ITALIAS
)
1610 /* we saw all occurencies of reg, so fine */
1611 if (lhs_use_count
== 0 && use_count
== 0) {
1612 if (what
== CHK_INV_SET
&& new_bl
!= set_bl
)
1617 /* we have finished this life range */
1619 return what
== CHK_CLONE
? 1 : (reason
=10, 0);
1624 =item C<static int is_ins_save>
1626 RT#48260: Not yet documented!!!
1632 PARROT_WARN_UNUSED_RESULT
1634 is_ins_save(PARROT_INTERP
, ARGIN(const IMC_Unit
*unit
), ARGIN(const Instruction
*ins
),
1635 ARGIN(const SymReg
*r
), int what
)
1640 save
= _is_ins_save(unit
, ins
, r
, what
);
1641 if (!save
&& reason
)
1642 IMCC_debug(interp
, DEBUG_OPT2
,
1643 "ins not save var %s reason %d %I\n",
1644 r
->name
, reason
, ins
);
1650 =item C<int max_loop_depth>
1652 RT#48260: Not yet documented!!!
1658 PARROT_WARN_UNUSED_RESULT
1660 max_loop_depth(ARGIN(const IMC_Unit
*unit
))
1665 for (i
= 0; i
< unit
->n_basic_blocks
; i
++)
1666 if (unit
->bb_list
[i
]->loop_depth
> d
)
1667 d
= unit
->bb_list
[i
]->loop_depth
;
1673 =item C<int is_invariant>
1675 RT#48260: Not yet documented!!!
1682 is_invariant(PARROT_INTERP
, ARGIN(const IMC_Unit
*unit
), ARGIN(const Instruction
*ins
))
1687 if (STREQ(ins
->opname
, "new")) {
1691 /* only, if once assigned and not changed */
1692 else if (STREQ(ins
->opname
, "set") &&
1693 !(ins
->symregs
[0]->usage
& U_KEYED
) &&
1694 ins
->symregs
[1]->type
& VTCONST
) {
1699 return is_ins_save(interp
, unit
, ins
, ins
->symregs
[0], what
);
1703 # define MOVE_INS_1_BL
1704 # ifdef MOVE_INS_1_BL
1707 =item C<Basic_block * find_outer>
1709 RT #48260: Not yet documented!!!
1715 PARROT_WARN_UNUSED_RESULT
1716 PARROT_CAN_RETURN_NULL
1718 find_outer(ARGIN(const IMC_Unit
*unit
), ARGIN(const Basic_block
*blk
))
1721 Loop_info
** const loop_info
= unit
->loop_info
;
1722 const int bb
= blk
->index
;
1723 int i
= unit
->n_loops
- 1;
1725 /* loops are sorted depth last */
1726 for (; i
>= 0; i
--) {
1727 Loop_info
* const info
= loop_info
[i
];
1728 if (set_contains(info
->loop
, bb
)) {
1729 const int preheader
= info
->preheader
;
1731 return unit
->bb_list
[preheader
];
1740 =item C<int move_ins_out>
1742 move the instruction ins before loop in bb
1749 move_ins_out(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
),
1750 ARGMOD(Instruction
**ins
), ARGIN(const Basic_block
*bb
))
1753 Instruction
* next
, *out
;
1755 /* check loop_info, where this loop started
1756 * actually, this moves instruction to block 0 */
1757 # ifdef MOVE_INS_1_BL
1758 pred
= find_outer(unit
, bb
);
1761 pred
= unit
->bb_list
[0];
1764 IMCC_debug(interp
, DEBUG_OPT2
, "outer loop not found (CFG?)\n");
1768 next
= (*ins
)->next
;
1769 (*ins
)->bbindex
= pred
->index
;
1770 IMCC_debug(interp
, DEBUG_OPT2
, "inserting it in blk %d after %I\n",
1772 *ins
= move_ins(unit
, *ins
, out
);
1773 if (0 && (DEBUG_OPT2
& IMCC_INFO(interp
)->debug
)) {
1775 SymReg
* regs
[IMCC_MAX_REGS
];
1779 snprintf(buf
, sizeof (buf
), "# Invar moved: %s", out
->next
->op
);
1780 tmp
= INS(interp
, unit
, "", buf
, regs
, 0, 0, 0);
1781 insert_ins(unit
, (*ins
)->prev
, tmp
);
1783 ostat
.invariants_moved
++;
1784 /* RT#46291 CFG is changed here, which also means
1785 * that the life_info is wrong now
1786 * so, currently we calc CFG and life again */
1792 =item C<int loop_one>
1794 RT#48260: Not yet documented!!!
1801 loop_one(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
), int bnr
)
1803 Basic_block
* const bb
= unit
->bb_list
[bnr
];
1808 IMCC_warning(interp
, "loop_one", "wrong loop depth in block 0\n");
1811 IMCC_debug(interp
, DEBUG_OPT2
, "loop_one blk %d\n", bnr
);
1812 for (ins
= bb
->start
; ins
; ins
= ins
->next
) {
1814 if (is_invariant(interp
, unit
, ins
)) {
1815 IMCC_debug(interp
, DEBUG_OPT2
, "found invariant %I\n", ins
);
1816 if (move_ins_out(interp
, unit
, &ins
, bb
)) {
1830 =item C<int loop_optimization>
1832 RT#48260: Not yet documented!!!
1839 loop_optimization(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
))
1843 static int prev_depth
;
1845 const int loop_depth
= prev_depth
? prev_depth
: max_loop_depth(unit
);
1847 /* work from inside out */
1848 IMCC_debug(interp
, DEBUG_OPT2
, "loop_optimization\n");
1849 for (l
= loop_depth
; l
> 0; l
--) {
1852 IMCC_debug(interp
, DEBUG_OPT2
, "loop_depth %d\n", l
);
1853 for (bb
= 0; bb
< unit
->n_basic_blocks
; bb
++)
1854 if (unit
->bb_list
[bb
]->loop_depth
== l
) {
1855 changed
|= loop_one(interp
, unit
, bb
);
1857 /* currently e.g. mandel.p6 breaks, if not only the most
1858 * inner loop is changed, but outer loops too */
1861 IMCC_debug(interp
, DEBUG_OPT2
, "after loop_opt\n");
1862 if (IMCC_INFO(interp
)->debug
>1)
1863 dump_instructions(interp
, unit
);
1882 * c-file-style: "parrot"
1884 * vim: expandtab shiftwidth=4: