#include "mcg.h" static MAPOF(struct basicblock, struct basicblock) graph; static ARRAYOF(struct ir) pops; static ARRAYOF(struct ir) pushes; static struct ir* get_last_push(struct basicblock* bb) { int i; for (i=bb->irs.count-1; i>=0; i--) { struct ir* ir = bb->irs.item[i]; if (ir->opcode == IR_PUSH) return ir; if (ir_find(ir, IR_POP)) return NULL; } return NULL; } static struct ir* get_first_pop(struct basicblock* bb) { int i; for (i=0; iirs.count; i++) { struct ir* irr; struct ir* ir = bb->irs.item[i]; if (ir->opcode == IR_PUSH) return NULL; irr = ir_find(ir, IR_POP); if (irr) return irr; } return NULL; } static bool collect_outputs_cb(struct ir* ir, void* user) { struct basicblock* caller = user; if (ir->opcode == IR_BLOCK) map_addp(&graph, caller, ir->u.bvalue); return false; } static void make_bb_graph(struct procedure* proc) { int i, j; graph.count = 0; for (i=0; iblocks.count; i++) { struct basicblock* bb = proc->blocks.item[i]; for (j=0; jirs.count; j++) ir_walk(bb->irs.item[j], collect_outputs_cb, bb); } } static void convert_block(struct procedure* proc, struct basicblock* bb) { int i, j; struct ir* ir; pushes.count = pops.count = 0; for (;;) { struct ir* lastpush = get_last_push(bb); if (!lastpush) return; /* Abort unless *every* successor block of this one starts with a pop * of the same size... */ for (i=0; isize != lastpush->size)) return; array_appendu(&pops, ir); /* Also abort unless *every* predecessor block of the one we've * just found *also* ends in a push of the same size. */ for (j=0; jsize != lastpush->size)) return; array_appendu(&pushes, ir); } } } } /* Okay, now we can wire them all up. */ for (i=0; iis_sequence); *ir = *ir->left; ir->is_sequence = true; } for (i=0; isize, pushir); for (j=1; jsize, phi, pushes.item[j]); phi->is_sequence = ir->is_sequence; *ir = *phi; } } } void pass_convert_stack_ops(struct procedure* proc) { int i; make_bb_graph(proc); for (i=0; iblocks.count; i++) convert_block(proc, proc->blocks.item[i]); } /* vim: set sw=4 ts=4 expandtab : */