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 */
84 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
86 PARROT_WARN_UNUSED_RESULT
87 static int _is_ins_save(
88 ARGIN(const IMC_Unit
*unit
),
89 ARGIN(const Instruction
*check_ins
),
90 ARGIN(const SymReg
*r
),
92 __attribute__nonnull__(1)
93 __attribute__nonnull__(2)
94 __attribute__nonnull__(3);
96 static int branch_branch(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
))
97 __attribute__nonnull__(1)
98 __attribute__nonnull__(2)
101 static int branch_cond_loop(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
))
102 __attribute__nonnull__(1)
103 __attribute__nonnull__(2)
104 FUNC_MODIFIES(*unit
);
106 PARROT_WARN_UNUSED_RESULT
107 static int branch_cond_loop_swap(PARROT_INTERP
,
108 ARGMOD(IMC_Unit
*unit
),
109 ARGMOD(Instruction
*branch
),
110 ARGMOD(Instruction
*start
),
111 ARGMOD(Instruction
*cond
))
112 __attribute__nonnull__(1)
113 __attribute__nonnull__(2)
114 __attribute__nonnull__(3)
115 __attribute__nonnull__(4)
116 __attribute__nonnull__(5)
118 FUNC_MODIFIES(*branch
)
119 FUNC_MODIFIES(*start
)
120 FUNC_MODIFIES(*cond
);
122 PARROT_WARN_UNUSED_RESULT
123 static int branch_reorg(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
))
124 __attribute__nonnull__(1)
125 __attribute__nonnull__(2)
126 FUNC_MODIFIES(*unit
);
128 static int constant_propagation(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
))
129 __attribute__nonnull__(1)
130 __attribute__nonnull__(2)
131 FUNC_MODIFIES(*unit
);
133 static int dead_code_remove(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
))
134 __attribute__nonnull__(1)
135 __attribute__nonnull__(2)
136 FUNC_MODIFIES(*unit
);
138 PARROT_WARN_UNUSED_RESULT
139 static int eval_ins(PARROT_INTERP
,
140 ARGIN(const char *op
),
143 __attribute__nonnull__(1)
144 __attribute__nonnull__(2)
145 __attribute__nonnull__(4);
147 static int if_branch(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
))
148 __attribute__nonnull__(1)
149 __attribute__nonnull__(2)
150 FUNC_MODIFIES(*unit
);
152 PARROT_WARN_UNUSED_RESULT
153 static int is_ins_save(PARROT_INTERP
,
154 ARGIN(const IMC_Unit
*unit
),
155 ARGIN(const Instruction
*ins
),
156 ARGIN(const SymReg
*r
),
158 __attribute__nonnull__(1)
159 __attribute__nonnull__(2)
160 __attribute__nonnull__(3)
161 __attribute__nonnull__(4);
163 static int strength_reduce(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
))
164 __attribute__nonnull__(1)
165 __attribute__nonnull__(2)
166 FUNC_MODIFIES(*unit
);
168 PARROT_WARN_UNUSED_RESULT
169 static int unused_label(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
))
170 __attribute__nonnull__(1)
171 __attribute__nonnull__(2)
172 FUNC_MODIFIES(*unit
);
174 static int used_once(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
))
175 __attribute__nonnull__(1)
176 __attribute__nonnull__(2)
177 FUNC_MODIFIES(*unit
);
179 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
180 /* HEADERIZER END: static */
182 #if DO_LOOP_OPTIMIZATION
183 int loop_optimization(Interp
*, IMC_Unit
*);
185 PARROT_WARN_UNUSED_RESULT
187 ARGIN(const IMC_Unit
*unit
),
188 ARGIN(const Instruction
*check_ins
),
189 ARGIN(const SymReg
*r
),
191 __attribute__nonnull__(1)
192 __attribute__nonnull__(2)
193 __attribute__nonnull__(3);
195 PARROT_WARN_UNUSED_RESULT
196 int is_ins_save(PARROT_INTERP
,
197 ARGIN(const IMC_Unit
*unit
),
198 ARGIN(const Instruction
*ins
),
199 ARGIN(const SymReg
*r
),
201 __attribute__nonnull__(1)
202 __attribute__nonnull__(2)
203 __attribute__nonnull__(3)
204 __attribute__nonnull__(4);
206 PARROT_WARN_UNUSED_RESULT
207 int max_loop_depth(ARGIN(const IMC_Unit
*unit
))
208 __attribute__nonnull__(1);
210 int is_invariant(PARROT_INTERP
,
211 ARGIN(const IMC_Unit
*unit
),
212 ARGIN(const Instruction
*ins
))
213 __attribute__nonnull__(1)
214 __attribute__nonnull__(2)
215 __attribute__nonnull__(3);
217 PARROT_WARN_UNUSED_RESULT
218 PARROT_CAN_RETURN_NULL
219 Basic_block
* find_outer(
220 ARGIN(const IMC_Unit
*unit
),
221 ARGIN(const Basic_block
*blk
))
222 __attribute__nonnull__(1)
223 __attribute__nonnull__(2);
230 =item C<int pre_optimize>
232 Handles optimizations occuring before the construction of the CFG.
239 pre_optimize(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
))
243 if (IMCC_INFO(interp
)->optimizer_level
& OPT_PRE
) {
244 IMCC_info(interp
, 2, "pre_optimize\n");
245 /* RT #46281 integrate all in one pass */
246 changed
+= strength_reduce(interp
, unit
);
247 if (!IMCC_INFO(interp
)->dont_optimize
)
248 changed
+= if_branch(interp
, unit
);
255 =item C<int cfg_optimize>
257 Handles optimizations occuring during the construction of the CFG.
258 Returns TRUE if any optimization was performed. Otherwise, returns
265 PARROT_WARN_UNUSED_RESULT
267 cfg_optimize(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
))
269 if (IMCC_INFO(interp
)->dont_optimize
)
271 if (IMCC_INFO(interp
)->optimizer_level
& OPT_PRE
) {
272 IMCC_info(interp
, 2, "cfg_optimize\n");
273 if (branch_branch(interp
, unit
))
275 if (branch_cond_loop(interp
, unit
))
277 if (branch_reorg(interp
, unit
))
279 /* RT #46283 cfg / loop detection breaks e.g. in t/compiler/5_3 */
280 if (unused_label(interp
, unit
))
282 if (dead_code_remove(interp
, unit
))
290 =item C<int optimize>
292 RT #48260: Not yet documented!!!
299 optimize(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
))
302 if (IMCC_INFO(interp
)->optimizer_level
& OPT_CFG
) {
303 IMCC_info(interp
, 2, "optimize\n");
304 any
= constant_propagation(interp
, unit
);
305 if (used_once(interp
, unit
))
307 #if DO_LOOP_OPTIMIZATION
308 if (loop_optimization(interp
, unit
))
317 =item C<const char * get_neg_op>
319 Get negated form of operator. If no negated form is known, return NULL.
325 PARROT_WARN_UNUSED_RESULT
326 PARROT_CAN_RETURN_NULL
328 get_neg_op(ARGIN(const char *op
), ARGOUT(int *n
))
330 static const struct br_pairs
{
331 const char * const op
;
332 const char * const nop
;
335 { "if", "unless", 2 },
341 for (i
= 0; i
< N_ELEMENTS(br_pairs
); i
++) {
343 if (STREQ(op
, br_pairs
[i
].op
))
344 return br_pairs
[i
].nop
;
345 if (STREQ(op
, br_pairs
[i
].nop
))
346 return br_pairs
[i
].op
;
356 =item C<static int if_branch>
358 Convert if/branch/label constructs of the form:
364 to the simpler negated form:
373 if_branch(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
))
375 Instruction
*ins
, *last
;
376 int reg
, changed
= 0;
378 last
= unit
->instructions
;
381 IMCC_info(interp
, 2, "\tif_branch\n");
382 for (ins
= last
->next
; ins
;) {
383 if ((last
->type
& ITBRANCH
) && /* if ...L1 */
384 (ins
->type
& IF_goto
) && /* branch L2*/
385 STREQ(ins
->opname
, "branch") &&
386 (reg
= get_branch_regno(last
)) >= 0) {
387 SymReg
* const br_dest
= last
->symregs
[reg
];
389 (ins
->next
->type
& ITLABEL
) && /* L1 */
390 ins
->next
->symregs
[0] == br_dest
) {
392 SymReg
* const go
= get_branch_reg(ins
);
395 IMCC_debug(interp
, DEBUG_OPT1
, "if_branch %s ... %s\n",
396 last
->opname
, br_dest
->name
);
397 /* find the negated op (e.g if->unless, ne->eq ... */
398 if ((neg_op
= get_neg_op(last
->opname
, &args
)) != 0) {
400 last
->symregs
[reg
] = go
;
401 tmp
= INS(interp
, unit
, (char*)neg_op
, "",
402 last
->symregs
, args
, 0, 0);
403 last
->opnum
= tmp
->opnum
;
404 last
->opsize
= tmp
->opsize
;
406 last
->opname
= str_dup(tmp
->opname
);
410 unit
->ostat
.deleted_ins
++;
411 ins
= delete_ins(unit
, ins
);
412 unit
->ostat
.if_branch
++;
416 } /* branch detected */
425 =item C<static int strength_reduce>
427 strength_reduce ... rewrites e.g add Ix, Ix, y => add Ix, y
429 These are run after constant simplification, so it is
430 guaranteed that one operand is non constant if opsize == 4
437 strength_reduce(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
))
439 Instruction
*ins
, *tmp
;
444 IMCC_info(interp
, 2, "\tstrength_reduce\n");
445 for (ins
= unit
->instructions
; ins
; ins
= ins
->next
) {
447 * add Ix, Ix, Iy => add Ix, Iy
448 * add Ix, Iy, Ix => add Ix, Iy
449 * sub Ix, Ix, Iy => sub Ix, Iy
450 * mul Ix, Ix, Iy => sub Ix, Iy
451 * mul Ix, Iy, Ix => sub Ix, Iy
452 * div Ix, Ix, Iy => sub Ix, Iy
453 * fdiv Ix, Ix, Iy => sub Ix, Iy
454 * add Nx, Nx, Ny => add Nx, Ny
455 * add Nx, Ny, Nx => add Nx, Ny
456 * sub Nx, Nx, Ny => sub Nx, Ny
457 * mul Nx, Nx, Ny => sub Nx, Ny
458 * mul Nx, Ny, Nx => sub Nx, Ny
459 * div Nx, Nx, Ny => sub Nx, Ny
460 * fdiv Nx, Nx, Ny => sub Nx, Ny
462 if (((ins
->opnum
== PARROT_OP_sub_i_i_i
||
463 ins
->opnum
== PARROT_OP_sub_i_i_ic
||
464 ins
->opnum
== PARROT_OP_sub_i_ic_i
||
465 ins
->opnum
== PARROT_OP_div_i_i_i
||
466 ins
->opnum
== PARROT_OP_div_i_i_ic
||
467 ins
->opnum
== PARROT_OP_div_i_ic_i
||
468 ins
->opnum
== PARROT_OP_fdiv_i_i_i
||
469 ins
->opnum
== PARROT_OP_fdiv_i_i_ic
||
470 ins
->opnum
== PARROT_OP_fdiv_i_ic_i
||
471 ins
->opnum
== PARROT_OP_sub_n_n_n
||
472 ins
->opnum
== PARROT_OP_sub_n_n_nc
||
473 ins
->opnum
== PARROT_OP_sub_n_nc_n
||
474 ins
->opnum
== PARROT_OP_div_n_n_n
||
475 ins
->opnum
== PARROT_OP_div_n_n_nc
||
476 ins
->opnum
== PARROT_OP_div_n_nc_n
||
477 ins
->opnum
== PARROT_OP_fdiv_n_n_n
||
478 ins
->opnum
== PARROT_OP_fdiv_n_n_nc
||
479 ins
->opnum
== PARROT_OP_fdiv_n_nc_n
) &&
480 ins
->symregs
[0] == ins
->symregs
[1])
481 || ((ins
->opnum
== PARROT_OP_add_i_i_i
||
482 ins
->opnum
== PARROT_OP_add_i_i_ic
||
483 ins
->opnum
== PARROT_OP_add_i_ic_i
||
484 ins
->opnum
== PARROT_OP_mul_i_i_i
||
485 ins
->opnum
== PARROT_OP_mul_i_i_ic
||
486 ins
->opnum
== PARROT_OP_mul_i_ic_i
||
487 ins
->opnum
== PARROT_OP_add_n_n_n
||
488 ins
->opnum
== PARROT_OP_add_n_n_nc
||
489 ins
->opnum
== PARROT_OP_add_n_nc_n
||
490 ins
->opnum
== PARROT_OP_mul_n_n_n
||
491 ins
->opnum
== PARROT_OP_mul_n_n_nc
||
492 ins
->opnum
== PARROT_OP_mul_n_nc_n
) &&
493 (ins
->symregs
[0] == ins
->symregs
[1] ||
494 ins
->symregs
[0] == ins
->symregs
[2]))) {
495 IMCC_debug(interp
, DEBUG_OPT1
, "opt1 %I => ", ins
);
496 if (ins
->symregs
[0] == ins
->symregs
[1]) {
497 ins
->symregs
[1] = ins
->symregs
[2];
499 tmp
= INS(interp
, unit
, ins
->opname
, "", ins
->symregs
, 2, 0, 0);
500 IMCC_debug(interp
, DEBUG_OPT1
, "%I\n", tmp
);
501 subst_ins(unit
, ins
, tmp
, 1);
506 * add Ix, 0 => delete
507 * sub Ix, 0 => delete
508 * mul Ix, 1 => delete
509 * div Ix, 1 => delete
510 * fdiv Ix, 1 => delete
511 * add Nx, 0 => delete
512 * sub Nx, 0 => delete
513 * mul Nx, 1 => delete
514 * div Nx, 1 => delete
515 * fdiv Nx, 1 => delete
517 if (((ins
->opnum
== PARROT_OP_add_i_ic
||
518 ins
->opnum
== PARROT_OP_sub_i_ic
) &&
519 IMCC_int_from_reg(interp
, ins
->symregs
[1]) == 0)
520 || ((ins
->opnum
== PARROT_OP_mul_i_ic
||
521 ins
->opnum
== PARROT_OP_div_i_ic
||
522 ins
->opnum
== PARROT_OP_fdiv_i_ic
) &&
523 IMCC_int_from_reg(interp
, ins
->symregs
[1]) == 1)
524 || ((ins
->opnum
== PARROT_OP_add_n_nc
||
525 ins
->opnum
== PARROT_OP_sub_n_nc
) &&
526 (f
= atof(ins
->symregs
[1]->name
), FLOAT_IS_ZERO(f
)))
527 || ((ins
->opnum
== PARROT_OP_mul_n_nc
||
528 ins
->opnum
== PARROT_OP_div_n_nc
||
529 ins
->opnum
== PARROT_OP_fdiv_n_nc
) &&
530 atof(ins
->symregs
[1]->name
) == 1.0)) {
531 IMCC_debug(interp
, DEBUG_OPT1
, "opt1 %I => ", ins
);
532 ins
= delete_ins(unit
, ins
);
534 ins
= ins
->prev
? ins
->prev
: unit
->instructions
;
537 IMCC_debug(interp
, DEBUG_OPT1
, "deleted\n");
542 * add Ix, 1 => inc Ix
543 * add Nx, 1 => inc Nx
544 * sub Ix, 1 => dec Ix
545 * sub Nx, 1 => dec Nx
547 if (((ins
->opnum
== PARROT_OP_add_i_ic
||
548 ins
->opnum
== PARROT_OP_sub_i_ic
) &&
549 IMCC_int_from_reg(interp
, ins
->symregs
[1]) == 1)
550 || ((ins
->opnum
== PARROT_OP_add_n_nc
||
551 ins
->opnum
== PARROT_OP_sub_n_nc
) &&
552 atof(ins
->symregs
[1]->name
) == 1.0)) {
553 IMCC_debug(interp
, DEBUG_OPT1
, "opt1 %I => ", ins
);
554 --ins
->symregs
[1]->use_count
;
555 if (ins
->opnum
== PARROT_OP_add_i_ic
||
556 ins
->opnum
== PARROT_OP_add_n_nc
)
557 tmp
= INS(interp
, unit
, "inc", "", ins
->symregs
, 1, 0, 0);
559 tmp
= INS(interp
, unit
, "dec", "", ins
->symregs
, 1, 0, 0);
560 subst_ins(unit
, ins
, tmp
, 1);
561 IMCC_debug(interp
, DEBUG_OPT1
, "%I\n", tmp
);
567 * add Ix, Iy, 0 => set Ix, Iy
568 * add Ix, 0, Iy => set Ix, Iy
569 * sub Ix, Iy, 0 => set Ix, Iy
570 * mul Ix, Iy, 1 => set Ix, Iy
571 * mul Ix, 1, Iy => set Ix, Iy
572 * div Ix, Iy, 1 => set Ix, Iy
573 * fdiv Ix, Iy, 1 => set Ix, Iy
574 * add Nx, Ny, 0 => set Nx, Ny
575 * add Nx, 0, Ny => set Nx, Ny
576 * sub Nx, Ny, 0 => set Nx, Ny
577 * mul Nx, Ny, 1 => set Nx, Ny
578 * mul Nx, 1, Ny => set Nx, Ny
579 * div Nx, Ny, 1 => set Nx, Ny
580 * fdiv Nx, Ny, 1 => set Nx, Ny
582 if (((ins
->opnum
== PARROT_OP_add_i_i_ic
||
583 ins
->opnum
== PARROT_OP_sub_i_i_ic
) &&
584 IMCC_int_from_reg(interp
, ins
->symregs
[2]) == 0)
585 || (ins
->opnum
== PARROT_OP_add_i_ic_i
&&
586 IMCC_int_from_reg(interp
, ins
->symregs
[1]) == 0)
587 || ((ins
->opnum
== PARROT_OP_mul_i_i_ic
||
588 ins
->opnum
== PARROT_OP_div_i_i_ic
||
589 ins
->opnum
== PARROT_OP_fdiv_i_i_ic
) &&
590 IMCC_int_from_reg(interp
, ins
->symregs
[2]) == 1)
591 || (ins
->opnum
== PARROT_OP_mul_i_ic_i
&&
592 IMCC_int_from_reg(interp
, ins
->symregs
[1]) == 1)
593 || ((ins
->opnum
== PARROT_OP_add_n_n_nc
||
594 ins
->opnum
== PARROT_OP_sub_n_n_nc
) &&
595 (f
= atof(ins
->symregs
[2]->name
), FLOAT_IS_ZERO(f
)))
596 || (ins
->opnum
== PARROT_OP_add_n_nc_n
&&
597 (f
= atof(ins
->symregs
[1]->name
), FLOAT_IS_ZERO(f
)))
598 || ((ins
->opnum
== PARROT_OP_mul_n_n_nc
||
599 ins
->opnum
== PARROT_OP_div_n_n_nc
||
600 ins
->opnum
== PARROT_OP_fdiv_n_n_nc
) &&
601 atof(ins
->symregs
[2]->name
) == 1.0)
602 || (ins
->opnum
== PARROT_OP_mul_n_nc_n
&&
603 atof(ins
->symregs
[1]->name
) == 1.0)) {
604 IMCC_debug(interp
, DEBUG_OPT1
, "opt1 %I => ", ins
);
605 if (ins
->symregs
[1]->type
== VTCONST
) {
606 --ins
->symregs
[1]->use_count
;
607 ins
->symregs
[1] = ins
->symregs
[2];
610 --ins
->symregs
[2]->use_count
;
612 tmp
= INS(interp
, unit
, "set", "", ins
->symregs
, 2, 0, 0);
613 IMCC_debug(interp
, DEBUG_OPT1
, "%I\n", tmp
);
614 subst_ins(unit
, ins
, tmp
, 1);
620 * mul Ix, Iy, 0 => set Ix, 0
621 * mul Ix, 0, Iy => set Ix, 0
622 * mul Ix, 0 => set Ix, 0
624 if ((ins
->opnum
== PARROT_OP_mul_i_i_ic
&&
625 IMCC_int_from_reg(interp
, ins
->symregs
[2]) == 0)
626 || ((ins
->opnum
== PARROT_OP_mul_i_ic_i
||
627 ins
->opnum
== PARROT_OP_mul_i_ic
) &&
628 IMCC_int_from_reg(interp
, ins
->symregs
[1]) == 0)
629 || (ins
->opnum
== PARROT_OP_mul_n_n_nc
&&
630 (f
= atof(ins
->symregs
[2]->name
), FLOAT_IS_ZERO(f
)))
631 || ((ins
->opnum
== PARROT_OP_mul_n_nc_n
||
632 ins
->opnum
== PARROT_OP_mul_n_nc
) &&
633 (f
= atof(ins
->symregs
[1]->name
), FLOAT_IS_ZERO(f
)))) {
634 IMCC_debug(interp
, DEBUG_OPT1
, "opt1 %I => ", ins
);
635 r
= mk_const(interp
, "0", ins
->symregs
[0]->set
);
636 --ins
->symregs
[1]->use_count
;
637 if (ins
->opsize
== 4)
638 --ins
->symregs
[2]->use_count
;
640 tmp
= INS(interp
, unit
, "set", "", ins
->symregs
, 2, 0, 0);
641 IMCC_debug(interp
, DEBUG_OPT1
, "%I\n", tmp
);
642 subst_ins(unit
, ins
, tmp
, 1);
647 * set Ix, 0 => null Ix
648 * set Nx, 0 => null Nx
650 if ((ins
->opnum
== PARROT_OP_set_i_ic
&&
651 IMCC_int_from_reg(interp
, ins
->symregs
[1]) == 0)
652 || (ins
->opnum
== PARROT_OP_set_n_nc
&&
653 (f
= atof(ins
->symregs
[1]->name
), FLOAT_IS_ZERO(f
)) &&
654 ins
->symregs
[1]->name
[0] != '-')) {
655 IMCC_debug(interp
, DEBUG_OPT1
, "opt1 %I => ", ins
);
656 --ins
->symregs
[1]->use_count
;
657 tmp
= INS(interp
, unit
, "null", "", ins
->symregs
, 1, 0, 0);
658 subst_ins(unit
, ins
, tmp
, 1);
659 IMCC_debug(interp
, DEBUG_OPT1
, "%I\n", tmp
);
670 =item C<static int constant_propagation>
672 Does conservative constant propagation.
673 This code will not propagate constants past labels or saves,
674 even though sometimes it may be safe.
681 constant_propagation(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
))
683 Instruction
*ins
, *ins2
, *tmp
, *prev
;
688 o
= c
= NULL
; /* silence compiler uninit warning */
690 IMCC_info(interp
, 2, "\tconstant_propagation\n");
691 for (ins
= unit
->instructions
; ins
; ins
= ins
->next
) {
693 if (STREQ(ins
->opname
, "set") &&
694 ins
->opsize
== 3 && /* no keyed set */
695 ins
->symregs
[1]->type
== VTCONST
&&
696 ins
->symregs
[0]->set
!= 'P') { /* no PMC consts */
700 } else if (STREQ(ins
->opname
, "null") && ins
->symregs
[0]->set
== 'I') {
702 c
= mk_const(interp
, "0", 'I');
704 } /* this would be good because 'set I0, 0' is reduced to 'null I0'
705 before it gets to us */
708 IMCC_debug(interp
, DEBUG_OPT2
,
709 "propagating constant %I => \n", ins
);
710 for (ins2
= ins
->next
; ins2
; ins2
= ins2
->next
) {
711 if (ins2
->bbindex
!= ins
->bbindex
)
712 /* restrict to within a basic block */
714 /* was opsize - 2, changed to n_r - 1
716 for (i
= ins2
->symreg_count
- 1; i
>= 0; i
--) {
717 if (STREQ(o
->name
, ins2
->symregs
[i
]->name
)) {
718 if (instruction_writes(ins2
, ins2
->symregs
[i
]))
720 else if (instruction_reads(ins2
, ins2
->symregs
[i
])) {
722 IMCC_debug(interp
, DEBUG_OPT2
,
723 "\tpropagating into %I register %i",
725 old
= ins2
->symregs
[i
];
726 ins2
->symregs
[i
] = c
;
727 /* first we try subst_constants for e.g. if 10 < 5 goto next*/
728 tmp
= IMCC_subst_constants(interp
,
729 unit
, ins2
->opname
, ins2
->symregs
, ins2
->opsize
,
734 subst_ins(unit
, ins2
, tmp
, 1);
736 IMCC_debug(interp
, DEBUG_OPT2
,
737 " reduced to %I\n", tmp
);
743 const int op
= check_op(interp
, fullname
, ins2
->opname
,
744 ins2
->symregs
, ins2
->symreg_count
, ins2
->keys
);
746 ins2
->symregs
[i
] = old
;
747 IMCC_debug(interp
, DEBUG_OPT2
,
748 " - no %s\n", fullname
);
754 IMCC_debug(interp
, DEBUG_OPT2
,
762 }/* for (ins2 ... )*/
772 =item C<Instruction * IMCC_subst_constants_umix>
774 rewrite e.g. add_n_ic => add_n_nc
780 PARROT_WARN_UNUSED_RESULT
781 PARROT_CAN_RETURN_NULL
783 IMCC_subst_constants_umix(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
), ARGIN(const char *name
),
784 ARGMOD(SymReg
**r
), int n
)
787 const char * const ops
[] = {
788 "abs", "add", "div", "mul", "sub", "fdiv"
794 for (i
= 0; i
< N_ELEMENTS(ops
); i
++) {
797 r
[1]->type
== VTCONST
&&
799 STREQ(name
, ops
[i
])) {
800 IMCC_debug(interp
, DEBUG_OPT1
, "opt1 %s_nc_ic => ", name
);
801 strcpy(b
, r
[1]->name
);
802 r
[1] = mk_const(interp
, b
, 'N');
803 tmp
= INS(interp
, unit
, name
, "", r
, 2, 0, 0);
804 IMCC_debug(interp
, DEBUG_OPT1
, "%I\n", tmp
);
812 =item C<static int eval_ins>
814 Run one parrot instruction, registers are filled with the
815 according constants. If an exception occurs, return -1, aborting
816 this optimization: this lets the runtime handle any exceptions.
822 PARROT_WARN_UNUSED_RESULT
824 eval_ins(PARROT_INTERP
, ARGIN(const char *op
), size_t ops
, ARGIN(SymReg
**r
))
826 opcode_t eval
[4], *pc
;
831 opnum
= interp
->op_lib
->op_code(op
, 1);
833 IMCC_fatal(interp
, 1, "eval_ins: op '%s' not found\n", op
);
834 op_info
= interp
->op_info_table
+ opnum
;
835 /* now fill registers */
837 for (i
= 0; i
< op_info
->op_count
- 1; i
++) {
838 switch (op_info
->types
[i
]) {
840 PARROT_ASSERT(i
&& ops
== (unsigned int)i
);
841 /* set branch offset to zero */
847 eval
[i
+ 1] = i
; /* regs used are I0, I1, I2 */
848 if (ops
<= 2 || i
) { /* fill source regs */
851 REG_INT(interp
, i
) = IMCC_int_from_reg(interp
, r
[i
]);
855 STRING
* const s
= string_from_cstring(interp
, r
[i
]->name
, 0);
856 REG_NUM(interp
, i
) = string_to_num(interp
, s
);
860 REG_STR(interp
, i
) = IMCC_string_from_reg(interp
, r
[i
]);
868 IMCC_fatal(interp
, 1, "eval_ins"
869 "invalid arg #%d for op '%s' not found\n",
874 /* eval the opcode */
875 new_runloop_jump_point(interp
);
876 if (setjmp(interp
->current_runloop
->resume
))
879 pc
= (interp
->op_func_table
[opnum
]) (eval
, interp
);
880 free_runloop_jump_point(interp
);
881 /* the returned pc is either incremented by op_count or is eval,
882 * as the branch offset is 0 - return true if it branched
884 PARROT_ASSERT(pc
== eval
+ op_info
->op_count
|| pc
== eval
);
890 =item C<Instruction * IMCC_subst_constants>
892 rewrite e.g. add_n_nc_nc => set_n_nc
894 eq_ic_ic_ic => branch_ic / delete
895 if_ic_ic => branch_ic / delete
901 PARROT_WARN_UNUSED_RESULT
902 PARROT_CAN_RETURN_NULL
904 IMCC_subst_constants(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
), ARGIN(const char *name
),
905 ARGMOD(SymReg
**r
), int n
, ARGOUT(int *ok
))
908 const char * const ops
[] = {
909 "add", "sub", "mul", "div", "fdiv", "pow",
910 "cmod", "mod", "atan",
913 "band", "bor", "bxor",
914 "bands", "bors", "bxors",
916 "iseq", "isne", "islt", "isle", "isgt", "isge", "cmp", "concat"
918 const char * const ops2
[] = {
919 "abs", "neg", "not", "fact", "sqrt", "ceil", "floor"
920 "acos", "asec", "asin",
921 "atan", "cos", "cosh", "exp", "ln", "log10", "log2", "sec",
922 "sech", "sin", "sinh", "tan", "tanh", "fact"
924 const char * const ops3
[] = {
925 "eq", "ne", "gt", "ge", "lt", "le"
927 const char * const ops4
[] = {
932 char fmt
[64], op
[20];
933 const char *debug_fmt
= NULL
; /* gcc -O uninit warn */
936 /* construct a FLOATVAL_FMT with needed precision */
937 switch (NUMVAL_SIZE
) {
939 strcpy(fmt
, "%0.16g");
942 strcpy(fmt
, "%0.18Lg");
945 IMCC_warning(interp
, "subs_constants",
946 "used default FLOATVAL_FMT\n");
947 strcpy(fmt
, FLOATVAL_FMT
);
953 for (i
= 0; i
< N_ELEMENTS(ops
); i
++) {
955 r
[1]->type
& (VTCONST
|VT_CONSTP
) &&
956 r
[2]->type
& (VTCONST
|VT_CONSTP
) &&
957 STREQ(name
, ops
[i
])) {
960 * create instruction e.g. add_i_ic_ic => add_i_i_i
962 snprintf(op
, sizeof (op
), "%s_%c_%c_%c", name
, tolower((unsigned char)r
[0]->set
),
963 tolower((unsigned char)r
[1]->set
), tolower((unsigned char)r
[2]->set
));
964 debug_fmt
= "opt %s_x_xc_xc => ";
968 for (i
= 0; !found
&& i
< N_ELEMENTS(ops2
); i
++) {
974 if (r
[1]->type
& (VTCONST
|VT_CONSTP
) &&
975 STREQ(name
, ops2
[i
])) {
977 snprintf(op
, sizeof (op
), "%s_%c_%c", name
, tolower((unsigned char)r
[0]->set
),
978 tolower((unsigned char)r
[1]->set
));
979 debug_fmt
= "opt %s_x_xc => ";
984 for (i
= 0; !found
&& i
< N_ELEMENTS(ops3
); i
++) {
986 * eq_xc_xc_labelc ...
989 r
[0]->type
& (VTCONST
|VT_CONSTP
) &&
990 r
[1]->type
& (VTCONST
|VT_CONSTP
) &&
991 STREQ(name
, ops3
[i
])) {
993 snprintf(op
, sizeof (op
), "%s_%c_%c_ic", name
, tolower((unsigned char)r
[0]->set
),
994 tolower((unsigned char)r
[1]->set
));
995 debug_fmt
= "opt %s_xc_xc_ic => ";
999 for (i
= 0; !found
&& i
< N_ELEMENTS(ops4
); i
++) {
1001 * if_xc_labelc, unless
1004 r
[0]->type
& (VTCONST
|VT_CONSTP
) &&
1005 STREQ(name
, ops4
[i
])) {
1007 snprintf(op
, sizeof (op
), "%s_%c_ic", name
, tolower((unsigned char)r
[0]->set
));
1008 debug_fmt
= "opt %s_xc_ic => ";
1018 IMCC_debug(interp
, DEBUG_OPT1
, debug_fmt
, name
);
1019 /* we construct a parrot instruction
1020 * here and let parrot do the calculation in a
1021 * separate context and make a constant
1024 branched
= eval_ins(interp
, op
, found
, r
);
1025 if (branched
== -1) {
1026 /* Don't set ok (See RT #43048 for info) */
1030 * for math ops result is in I0/N0
1031 * if it was a branch with constant args, the result is
1036 * create a branch or delete instruction
1040 tmp
= INS(interp
, unit
, "branch", "", r
, 1, 0, 0);
1043 IMCC_debug(interp
, DEBUG_OPT1
, "deleted\n");
1048 * create set x, constant
1051 switch (r
[0]->set
) {
1053 snprintf(b
, sizeof (b
), INTVAL_FMT
, REG_INT(interp
, 0));
1054 r
[1] = mk_const(interp
, b
, r
[0]->set
);
1057 snprintf(b
, sizeof (b
), fmt
, REG_NUM(interp
, 0));
1058 r
[1] = mk_const(interp
, b
, r
[0]->set
);
1061 r
[1] = mk_const(interp
, string_to_cstring(interp
,
1062 REG_STR(interp
, 0)), r
[0]->set
);
1063 snprintf(b
, sizeof (b
), "%p", REG_STR(interp
, 0));
1068 tmp
= INS(interp
, unit
, "set", "", r
, 2, 0, 0);
1071 IMCC_debug(interp
, DEBUG_OPT1
, "%I\n", tmp
);
1078 /* optimizations with CFG built */
1082 =item C<static int branch_branch>
1084 if I0 goto L1 => if IO goto L2
1089 Returns TRUE if any optimizations were performed. Otherwise, returns
1097 branch_branch(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
))
1102 IMCC_info(interp
, 2, "\tbranch_branch\n");
1103 /* reset statistic globals */
1104 for (ins
= unit
->instructions
; ins
; ins
= ins
->next
) {
1105 if (get_branch_regno(ins
) >= 0) {
1106 SymReg
* const r
= get_sym(interp
, get_branch_reg(ins
)->name
);
1108 if (r
&& (r
->type
& VTADDRESS
) && r
->first_ins
) {
1109 Instruction
* const next
= r
->first_ins
->next
;
1111 STREQ(next->symregs[0]->name, get_branch_reg(ins)->name))
1114 (next
->type
& IF_goto
) &&
1115 STREQ(next
->opname
, "branch") &&
1116 !STREQ(next
->symregs
[0]->name
, get_branch_reg(ins
)->name
)) {
1117 const int regno
= get_branch_regno(ins
);
1118 IMCC_debug(interp
, DEBUG_OPT1
,
1119 "found branch to branch '%s' %I\n",
1120 r
->first_ins
->symregs
[0]->name
, next
);
1121 unit
->ostat
.branch_branch
++;
1123 Parrot_ex_throw_from_c_args(interp
, NULL
, 1,
1124 "Register number determination failed in branch_branch()");
1126 ins
->symregs
[regno
] = next
->symregs
[0];
1137 =item C<static int branch_reorg>
1148 Returns TRUE if any optimizations were performed. Otherwise, returns
1155 PARROT_WARN_UNUSED_RESULT
1157 branch_reorg(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
))
1162 IMCC_info(interp
, 2, "\tbranch_reorg\n");
1163 for (i
= 0; i
< unit
->n_basic_blocks
; i
++) {
1164 Instruction
*ins
= unit
->bb_list
[i
]->end
;
1166 /* if basic block ends with unconditional jump */
1167 if ((ins
->type
& IF_goto
) && STREQ(ins
->opname
, "branch")) {
1168 SymReg
* const r
= get_sym(interp
, ins
->symregs
[0]->name
);
1169 if (r
&& (r
->type
& VTADDRESS
) && r
->first_ins
) {
1171 Instruction
* const start
= r
->first_ins
;
1173 for (edge
= unit
->bb_list
[start
->bbindex
]->pred_list
;
1174 edge
; edge
= edge
->pred_next
) {
1175 if (edge
->from
->index
== start
->bbindex
- 1) {
1181 /* if target block is not reached by falling into it
1182 * from another block */
1185 /* move target block and its positional successors
1186 * to follow block with unconditional jump
1187 * (this could actually be in another block) */
1188 for (end
= start
; end
->next
; end
= end
->next
) {
1189 if ((end
->type
& IF_goto
) &&
1190 STREQ(end
->opname
, "branch")) {
1195 /* this was screwing up multi-block loops... */
1196 if (end
!= ins
&& ins
->next
!= NULL
) {
1197 ins
->next
->prev
= end
;
1198 start
->prev
->next
= end
->next
;
1200 end
->next
->prev
= start
->prev
;
1202 end
->next
= ins
->next
;
1206 IMCC_debug(interp
, DEBUG_OPT1
,
1207 "found branch to reorganize '%s' %I\n",
1208 r
->first_ins
->symregs
[0]->name
, ins
);
1210 /* unconditional jump can be eliminated */
1211 unit
->ostat
.deleted_ins
++;
1212 ins
= delete_ins(unit
, ins
);
1225 =item C<static int branch_cond_loop_swap>
1227 RT #48260: Not yet documented!!!
1233 PARROT_WARN_UNUSED_RESULT
1235 branch_cond_loop_swap(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
), ARGMOD(Instruction
*branch
),
1236 ARGMOD(Instruction
*start
), ARGMOD(Instruction
*cond
))
1240 const char * const neg_op
= get_neg_op(cond
->opname
, &args
);
1242 const size_t size
= strlen(branch
->symregs
[0]->name
) + 10; /* + '_post999' */
1243 char * const label
= (char *)mem_sys_allocate(size
);
1247 for (count
= 1; count
!= 999; ++count
) {
1248 snprintf(label
, size
, "%s_post%d", branch
->symregs
[0]->name
, count
);
1249 if (get_sym(interp
, label
) == 0) {
1257 SymReg
*regs
[3], *r
;
1260 /* cond_op has 2 or 3 args */
1261 PARROT_ASSERT(args
<= 3);
1263 r
= mk_local_label(interp
, label
);
1264 tmp
= INS_LABEL(interp
, unit
, r
, 0);
1265 insert_ins(unit
, cond
, tmp
);
1267 for (start
= start
->next
; start
!= cond
; start
= start
->next
) {
1268 if (!(start
->type
& ITLABEL
)) {
1269 tmp
= INS(interp
, unit
, start
->opname
, "",
1270 start
->symregs
, start
->symreg_count
, start
->keys
, 0);
1271 prepend_ins(unit
, branch
, tmp
);
1275 for (count
= 0; count
!= args
; ++count
) {
1276 regs
[count
] = cond
->symregs
[count
];
1279 reg_index
= get_branch_regno(cond
);
1281 Parrot_ex_throw_from_c_args(interp
, NULL
, 1,
1282 "Negative branch register address detected");
1284 regs
[reg_index
] = mk_label_address(interp
, label
);
1285 tmp
= INS(interp
, unit
, (const char*)neg_op
, "", regs
, args
, 0, 0);
1287 IMCC_debug(interp
, DEBUG_OPT1
,
1288 "loop %s -> %s converted to post-test, added label %s\n",
1289 branch
->symregs
[0]->name
, get_branch_reg(cond
)->name
, label
);
1291 subst_ins(unit
, branch
, tmp
, 1);
1292 unit
->ostat
.branch_cond_loop
++;
1304 =item C<static int branch_cond_loop>
1307 if cond goto end if cond goto end
1309 branch start start_post1:
1311 unless cond goto start_post562
1314 The basic premise is "branch (A) to conditional (B), where B goes to
1317 Returns TRUE if any optimizations were performed. Otherwise, returns
1325 branch_cond_loop(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
))
1327 Instruction
*ins
, *cond
, *start
, *prev
;
1328 int changed
= 0, found
;
1330 IMCC_info(interp
, 2, "\tbranch_cond_loop\n");
1331 /* reset statistic globals */
1333 for (ins
= unit
->instructions
; ins
; ins
= ins
->next
) {
1334 if ((ins
->type
& IF_goto
) && STREQ(ins
->opname
, "branch")) {
1335 /* get `end` label */
1336 Instruction
* const end
= ins
->next
;
1337 /* get `start` label */
1338 SymReg
* const r
= get_sym(interp
, ins
->symregs
[0]->name
);
1340 if (end
&& (end
->type
& ITLABEL
) &&
1341 r
&& (r
->type
& VTADDRESS
) && r
->first_ins
) {
1343 start
= r
->first_ins
;
1346 for (cond
= start
->next
; cond
; cond
= cond
->next
) {
1347 /* no good if it's an unconditional branch*/
1348 if (cond
->type
& IF_goto
&& STREQ(cond
->opname
, "branch")) {
1350 } else if (cond
->type
& ITPCCRET
|| cond
->type
& ITPCCSUB
1351 || cond
->type
& ITCALL
) {
1353 /* just until we can copy set_args et al */
1354 } else if (cond
->type
& ITBRANCH
&&
1355 get_branch_regno(cond
) >= 0) {
1362 const char * const lbl
= get_branch_reg(cond
)->name
;
1363 const SymReg
* const r
= get_sym(interp
, lbl
);
1364 if (r
&& (r
->type
& VTADDRESS
) && r
->first_ins
== end
) {
1365 /* the current ins is replaced - remember prev
1366 * and set ins again after the changes
1371 changed
|= branch_cond_loop_swap(interp
,
1372 unit
, ins
, start
, cond
);
1384 =item C<static int unused_label>
1386 Removes unused labels. A label is unused if ... [RT #46287: finish this].
1388 Returns TRUE if any optimizations were performed. Otherwise, returns
1395 PARROT_WARN_UNUSED_RESULT
1397 unused_label(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
))
1403 IMCC_info(interp
, 2, "\tunused_label\n");
1404 for (i
= 1; i
< unit
->n_basic_blocks
; i
++) {
1405 Instruction
*ins
= unit
->bb_list
[i
]->start
;
1406 if ((ins
->type
& ITLABEL
) && *ins
->symregs
[0]->name
!= '_') {
1407 const SymReg
* const lab
= ins
->symregs
[0];
1408 used
= IMCC_INFO(interp
)->has_compile
? 1 : 0;
1410 if (!lab
->first_ins
)
1413 else if (lab
->last_ins
)
1421 for (j
=0; unit
->bb_list
[j
]; j
++) {
1422 /* a branch can be the first ins in a block
1423 * (if prev ins was a label)
1424 * or the last ins in a block */
1425 ins2
= unit
->bb_list
[j
]->start
;
1426 if ((ins2
->type
& ITBRANCH
) &&
1427 (addr
= get_branch_reg(ins2
)) != 0) {
1428 if (addr
== lab
&& addr
->type
== VTADDRESS
) {
1433 ins2
= unit
->bb_list
[j
]->end
;
1434 if ((ins2
->type
& ITBRANCH
) &&
1435 (addr
= get_branch_reg(ins2
)) != 0) {
1436 if (addr
== lab
&& addr
->type
== VTADDRESS
) {
1445 unit
->ostat
.deleted_labels
++;
1446 IMCC_debug(interp
, DEBUG_OPT1
,
1447 "block %d label %s deleted\n", i
, lab
->name
);
1448 unit
->ostat
.deleted_ins
++;
1449 ins
= delete_ins(unit
, ins
);
1460 =item C<static int dead_code_remove>
1462 RT #48260: Not yet documented!!!
1469 dead_code_remove(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
))
1473 Instruction
*ins
, *last
;
1475 /* this could be a separate level, now it's done with -O1 */
1476 if (!(IMCC_INFO(interp
)->optimizer_level
& OPT_PRE
))
1478 IMCC_info(interp
, 2, "\tdead_code_remove\n");
1480 /* Unreachable blocks */
1482 for (i
= 1; i
< unit
->n_basic_blocks
; i
++) {
1483 Basic_block
* const bb
= unit
->bb_list
[i
];
1485 if ((bb
->start
->type
& ITLABEL
) && *bb
->start
->symregs
[0]->name
== '_')
1487 /* this block isn't entered from anywhere */
1488 if (!bb
->pred_list
) {
1489 const int bbi
= bb
->index
;
1490 IMCC_debug(interp
, DEBUG_OPT1
,
1491 "found dead block %d\n", bb
->index
);
1492 for (ins
= bb
->start
; ins
&& ins
->bbindex
== bbi
;) {
1493 IMCC_debug(interp
, DEBUG_OPT1
,
1494 "\tins deleted (dead block) %I\n", ins
);
1495 ins
= delete_ins(unit
, ins
);
1496 unit
->ostat
.deleted_ins
++;
1502 /* Unreachable instructions */
1504 for (last
= unit
->instructions
, ins
=last
->next
;
1507 if ((last
->type
& IF_goto
) && !(ins
->type
& ITLABEL
) &&
1508 STREQ(last
->opname
, "branch")) {
1509 IMCC_debug(interp
, DEBUG_OPT1
,
1510 "unreachable ins deleted (after branch) %I\n", ins
);
1511 ins
= delete_ins(unit
, ins
);
1512 unit
->ostat
.deleted_ins
++;
1519 if (ins
&& last
&& (last
->type
& IF_goto
) && (ins
->type
& ITLABEL
) &&
1520 STREQ(last
->opname
, "branch") &&
1521 STREQ(last
->symregs
[0]->name
, ins
->symregs
[0]->name
)) {
1522 IMCC_debug(interp
, DEBUG_OPT1
, "dead branch deleted %I\n", ins
);
1523 ins
= delete_ins(unit
, last
);
1524 unit
->ostat
.deleted_ins
++;
1534 /* optimizations with CFG & life info built */
1537 =item C<static int used_once>
1539 RT #48260: Not yet documented!!!
1546 used_once(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
))
1551 for (ins
= unit
->instructions
; ins
; ins
= ins
->next
) {
1553 SymReg
* const r
= ins
->symregs
[0];
1554 if (r
&& (r
->use_count
== 1 && r
->lhs_use_count
== 1)) {
1555 IMCC_debug(interp
, DEBUG_OPT2
, "used once '%I' deleted\n", ins
);
1556 ins
= delete_ins(unit
, ins
);
1557 ins
= ins
->prev
? ins
->prev
: unit
->instructions
;
1558 unit
->ostat
.deleted_ins
++;
1559 unit
->ostat
.used_once
++;
1567 #if DO_LOOP_OPTIMIZATION
1570 enum check_t
{ CHK_INV_NEW
, CHK_INV_SET
, CHK_CLONE
};
1574 =item C<static int _is_ins_save>
1576 RT #48260: Not yet documented!!!
1582 PARROT_WARN_UNUSED_RESULT
1584 _is_ins_save(ARGIN(const IMC_Unit
*unit
), ARGIN(const Instruction
*check_ins
),
1585 ARGIN(const SymReg
*r
), int what
)
1589 int use_count
, lhs_use_count
;
1591 int new_bl
=-1, set_bl
=-1;
1593 /* now check all instructions where r is used */
1595 /* we give up fast ;-) */
1599 if (r
->set
== 'P' && r
->lhs_use_count
!= 2)
1601 if (r
->set
!= 'P' && r
->lhs_use_count
!= 1)
1605 if (r
->set
== 'P' && r
->lhs_use_count
!= 2)
1612 use_count
= r
->use_count
;
1613 lhs_use_count
= r
->lhs_use_count
;
1614 for (bb
= 0; bb
< unit
->n_basic_blocks
; bb
++) {
1615 const Life_range
* const lr
= r
->life_info
[bb
];
1617 for (ins
= lr
->first_ins
; ins
; ins
= ins
->next
) {
1619 /* finished with this range */
1620 if (!lr
->last_ins
->next
|| ins
== lr
->last_ins
->next
)
1622 for (i
= in_use
= 0; ins
->symregs
[i
]; i
++)
1623 if (ins
->symregs
[i
] == r
) {
1630 /* var is in use in this ins */
1632 if (instruction_writes(ins
, r
)) {
1634 if (STREQ(ins
->opname
, "new"))
1636 if (STREQ(ins
->opname
, ""))
1639 /* this is the instruction, to check, it's safe */
1640 if (check_ins
== ins
)
1643 /* now look for dangerous ops */
1644 if (STREQ(ins
->opname
, "find_global"))
1646 if (STREQ(ins
->opname
, "store_global"))
1648 if (STREQ(ins
->opname
, "push"))
1650 if (STREQ(ins
->opname
, "pop"))
1652 if (STREQ(ins
->opname
, "clone"))
1654 /* indexed set/get ??? RT #46289, as index is ok */
1655 if (0 && STREQ(ins
->opname
, "set") && nregs
!= 2)
1658 * set P, P - dangerous?
1660 if (ins
->type
& ITALIAS
)
1662 /* we saw all occurencies of reg, so fine */
1663 if (lhs_use_count
== 0 && use_count
== 0) {
1664 if (what
== CHK_INV_SET
&& new_bl
!= set_bl
)
1669 /* we have finished this life range */
1671 return what
== CHK_CLONE
? 1 : (reason
=10, 0);
1676 =item C<static int is_ins_save>
1678 RT #48260: Not yet documented!!!
1684 PARROT_WARN_UNUSED_RESULT
1686 is_ins_save(PARROT_INTERP
, ARGIN(const IMC_Unit
*unit
), ARGIN(const Instruction
*ins
),
1687 ARGIN(const SymReg
*r
), int what
)
1692 save
= _is_ins_save(unit
, ins
, r
, what
);
1693 if (!save
&& reason
)
1694 IMCC_debug(interp
, DEBUG_OPT2
,
1695 "ins not save var %s reason %d %I\n",
1696 r
->name
, reason
, ins
);
1702 =item C<int max_loop_depth>
1704 RT #48260: Not yet documented!!!
1710 PARROT_WARN_UNUSED_RESULT
1712 max_loop_depth(ARGIN(const IMC_Unit
*unit
))
1717 for (i
= 0; i
< unit
->n_basic_blocks
; i
++)
1718 if (unit
->bb_list
[i
]->loop_depth
> d
)
1719 d
= unit
->bb_list
[i
]->loop_depth
;
1725 =item C<int is_invariant>
1727 RT #48260: Not yet documented!!!
1734 is_invariant(PARROT_INTERP
, ARGIN(const IMC_Unit
*unit
), ARGIN(const Instruction
*ins
))
1739 if (STREQ(ins
->opname
, "new")) {
1743 /* only, if once assigned and not changed */
1744 else if (STREQ(ins
->opname
, "set") &&
1745 !(ins
->symregs
[0]->usage
& U_KEYED
) &&
1746 ins
->symregs
[1]->type
& VTCONST
) {
1751 return is_ins_save(interp
, unit
, ins
, ins
->symregs
[0], what
);
1755 # define MOVE_INS_1_BL
1756 # ifdef MOVE_INS_1_BL
1759 =item C<Basic_block * find_outer>
1761 RT #48260: Not yet documented!!!
1767 PARROT_WARN_UNUSED_RESULT
1768 PARROT_CAN_RETURN_NULL
1770 find_outer(ARGIN(const IMC_Unit
*unit
), ARGIN(const Basic_block
*blk
))
1773 Loop_info
** const loop_info
= unit
->loop_info
;
1774 const int bb
= blk
->index
;
1775 int i
= unit
->n_loops
- 1;
1777 /* loops are sorted depth last */
1778 for (; i
>= 0; i
--) {
1779 Loop_info
* const info
= loop_info
[i
];
1780 if (set_contains(info
->loop
, bb
)) {
1781 const int preheader
= info
->preheader
;
1783 return unit
->bb_list
[preheader
];
1792 =item C<int move_ins_out>
1794 move the instruction ins before loop in bb
1801 move_ins_out(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
),
1802 ARGMOD(Instruction
**ins
), ARGIN(const Basic_block
*bb
))
1805 Instruction
* next
, *out
;
1807 /* check loop_info, where this loop started
1808 * actually, this moves instruction to block 0 */
1809 # ifdef MOVE_INS_1_BL
1810 pred
= find_outer(unit
, bb
);
1813 pred
= unit
->bb_list
[0];
1816 IMCC_debug(interp
, DEBUG_OPT2
, "outer loop not found (CFG?)\n");
1820 next
= (*ins
)->next
;
1821 (*ins
)->bbindex
= pred
->index
;
1822 IMCC_debug(interp
, DEBUG_OPT2
, "inserting it in blk %d after %I\n",
1824 *ins
= move_ins(unit
, *ins
, out
);
1825 if (0 && (DEBUG_OPT2
& IMCC_INFO(interp
)->debug
)) {
1827 SymReg
* regs
[IMCC_MAX_REGS
];
1831 snprintf(buf
, sizeof (buf
), "# Invar moved: %s", out
->next
->op
);
1832 tmp
= INS(interp
, unit
, "", buf
, regs
, 0, 0, 0);
1833 insert_ins(unit
, (*ins
)->prev
, tmp
);
1835 ostat
.invariants_moved
++;
1836 /* RT #46291 CFG is changed here, which also means
1837 * that the life_info is wrong now
1838 * so, currently we calc CFG and life again */
1844 =item C<int loop_one>
1846 RT #48260: Not yet documented!!!
1853 loop_one(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
), int bnr
)
1855 Basic_block
* const bb
= unit
->bb_list
[bnr
];
1860 IMCC_warning(interp
, "loop_one", "wrong loop depth in block 0\n");
1863 IMCC_debug(interp
, DEBUG_OPT2
, "loop_one blk %d\n", bnr
);
1864 for (ins
= bb
->start
; ins
; ins
= ins
->next
) {
1866 if (is_invariant(interp
, unit
, ins
)) {
1867 IMCC_debug(interp
, DEBUG_OPT2
, "found invariant %I\n", ins
);
1868 if (move_ins_out(interp
, unit
, &ins
, bb
)) {
1882 =item C<int loop_optimization>
1884 RT #48260: Not yet documented!!!
1891 loop_optimization(PARROT_INTERP
, ARGMOD(IMC_Unit
*unit
))
1895 static int prev_depth
;
1897 const int loop_depth
= prev_depth
? prev_depth
: max_loop_depth(unit
);
1899 /* work from inside out */
1900 IMCC_debug(interp
, DEBUG_OPT2
, "loop_optimization\n");
1901 for (l
= loop_depth
; l
> 0; l
--) {
1904 IMCC_debug(interp
, DEBUG_OPT2
, "loop_depth %d\n", l
);
1905 for (bb
= 0; bb
< unit
->n_basic_blocks
; bb
++)
1906 if (unit
->bb_list
[bb
]->loop_depth
== l
) {
1907 changed
|= loop_one(interp
, unit
, bb
);
1909 /* currently e.g. mandel.p6 breaks, if not only the most
1910 * inner loop is changed, but outer loops too */
1913 IMCC_debug(interp
, DEBUG_OPT2
, "after loop_opt\n");
1914 if (IMCC_INFO(interp
)->debug
>1)
1915 dump_instructions(interp
, unit
);
1934 * c-file-style: "parrot"
1936 * vim: expandtab shiftwidth=4: