2016-09-22 21:19:29 +00:00
|
|
|
#include "mcg.h"
|
|
|
|
|
2016-10-08 08:21:24 +00:00
|
|
|
static PMAPOF(struct basicblock, struct ir) pops;
|
2016-10-07 22:21:23 +00:00
|
|
|
static PMAPOF(struct basicblock, struct ir) pushes;
|
2016-09-23 21:59:15 +00:00
|
|
|
|
2016-09-22 21:19:29 +00:00
|
|
|
static struct ir* get_last_push(struct basicblock* bb)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2016-09-26 20:48:58 +00:00
|
|
|
for (i=bb->irs.count-1; i>=0; i--)
|
2016-09-22 21:19:29 +00:00
|
|
|
{
|
2016-09-26 20:48:58 +00:00
|
|
|
struct ir* ir = bb->irs.item[i];
|
2016-09-22 21:19:29 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2016-09-26 20:48:58 +00:00
|
|
|
for (i=0; i<bb->irs.count; i++)
|
2016-09-22 21:19:29 +00:00
|
|
|
{
|
|
|
|
struct ir* irr;
|
2016-09-26 20:48:58 +00:00
|
|
|
struct ir* ir = bb->irs.item[i];
|
2016-09-22 21:19:29 +00:00
|
|
|
|
|
|
|
if (ir->opcode == IR_PUSH)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
irr = ir_find(ir, IR_POP);
|
|
|
|
if (irr)
|
|
|
|
return irr;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-10-15 21:19:44 +00:00
|
|
|
static void convert_block(struct basicblock* bb)
|
2016-09-22 21:19:29 +00:00
|
|
|
{
|
|
|
|
int i, j;
|
|
|
|
struct ir* ir;
|
|
|
|
|
2016-09-26 20:48:58 +00:00
|
|
|
pushes.count = pops.count = 0;
|
2016-09-22 21:19:29 +00:00
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
struct ir* lastpush = get_last_push(bb);
|
|
|
|
if (!lastpush)
|
|
|
|
return;
|
|
|
|
|
2016-09-23 21:59:15 +00:00
|
|
|
/* Abort unless *every* successor block of this one starts with a pop
|
2016-09-22 21:19:29 +00:00
|
|
|
* of the same size... */
|
|
|
|
|
2016-10-02 15:50:34 +00:00
|
|
|
for (i=0; i<bb->nexts.count; i++)
|
2016-09-22 21:19:29 +00:00
|
|
|
{
|
2016-10-02 15:50:34 +00:00
|
|
|
struct basicblock* outbb = bb->nexts.item[i];
|
|
|
|
|
|
|
|
ir = get_first_pop(outbb);
|
|
|
|
if (!ir || (ir->size != lastpush->size))
|
|
|
|
return;
|
2016-10-08 08:21:24 +00:00
|
|
|
pmap_add(&pops, outbb, ir);
|
2016-10-02 15:50:34 +00:00
|
|
|
|
|
|
|
/* 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; j<outbb->prevs.count; j++)
|
2016-09-22 21:19:29 +00:00
|
|
|
{
|
2016-10-02 15:50:34 +00:00
|
|
|
struct basicblock* inbb = outbb->prevs.item[j];
|
2016-09-22 21:19:29 +00:00
|
|
|
|
2016-10-02 15:50:34 +00:00
|
|
|
ir = get_last_push(inbb);
|
2016-09-22 21:19:29 +00:00
|
|
|
if (!ir || (ir->size != lastpush->size))
|
|
|
|
return;
|
2016-10-07 22:21:23 +00:00
|
|
|
pmap_add(&pushes, inbb, ir);
|
2016-09-22 21:19:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-01 21:41:35 +00:00
|
|
|
/* If we didn't actually find anything, give up. */
|
|
|
|
|
|
|
|
if ((pushes.count == 0) || (pops.count == 0))
|
|
|
|
return;
|
|
|
|
|
2016-09-22 21:19:29 +00:00
|
|
|
/* Okay, now we can wire them all up. */
|
|
|
|
|
2016-09-26 20:48:58 +00:00
|
|
|
for (i=0; i<pushes.count; i++)
|
2016-09-22 21:19:29 +00:00
|
|
|
{
|
2016-10-07 22:21:23 +00:00
|
|
|
struct ir* ir = pushes.item[i].right;
|
2016-10-22 10:13:57 +00:00
|
|
|
ir->opcode = IR_NOP;
|
2016-09-23 21:59:15 +00:00
|
|
|
}
|
2016-09-22 21:19:29 +00:00
|
|
|
|
2016-09-26 20:48:58 +00:00
|
|
|
for (i=0; i<pops.count; i++)
|
2016-09-23 21:59:15 +00:00
|
|
|
{
|
2016-10-08 08:21:24 +00:00
|
|
|
struct basicblock* outbb = pops.item[i].left;
|
|
|
|
struct ir* ir = pops.item[i].right;
|
2016-09-22 21:19:29 +00:00
|
|
|
|
2016-10-29 08:55:48 +00:00
|
|
|
assert(pushes.count > 0);
|
|
|
|
if (pushes.count == 1)
|
|
|
|
{
|
|
|
|
/* The push happened in exactly one place; that means we don't need a phi and can
|
|
|
|
* just import the value directly. */
|
2016-09-22 21:19:29 +00:00
|
|
|
|
2016-10-29 08:55:48 +00:00
|
|
|
struct ir* src = pushes.item[0].right;
|
|
|
|
ir->opcode = IR_NOP;
|
|
|
|
ir->left = src;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* The push could have happened in one of several places; we need a phi. */
|
|
|
|
|
|
|
|
struct ir* phi = new_ir0(IR_PHI, ir->size);
|
|
|
|
for (j=0; j<pushes.count; j++)
|
|
|
|
{
|
|
|
|
pmap_add(&phi->u.phivalue,
|
|
|
|
pushes.item[j].left,
|
|
|
|
pushes.item[j].right);
|
|
|
|
}
|
|
|
|
phi->root = phi;
|
|
|
|
*ir = *phi;
|
|
|
|
}
|
2016-09-22 21:19:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-15 21:19:44 +00:00
|
|
|
void pass_convert_stack_ops(void)
|
2016-09-23 19:07:16 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2016-10-15 21:19:44 +00:00
|
|
|
for (i=0; i<cfg.preorder.count; i++)
|
|
|
|
convert_block(cfg.preorder.item[i]);
|
2016-09-23 19:07:16 +00:00
|
|
|
}
|
|
|
|
|
2016-09-22 21:19:29 +00:00
|
|
|
/* vim: set sw=4 ts=4 expandtab : */
|