104 lines
2.2 KiB
C
104 lines
2.2 KiB
C
#include "mcg.h"
|
|
|
|
/* Insert empty nodes at certain places in the basic block graph so that when
|
|
* we convert out of SSA form, we have somewhere to insert copies. This is
|
|
* necessary for correctness in certain circumstances. The best explanation of
|
|
* why I've found is here, starting at the bottom of page 23.
|
|
*
|
|
* Briggs, Preston, et al.
|
|
* "Practical improvements to the construction and destruction of static single assignment form."
|
|
* Software-Practice and experience 28.8 (1998): 859-882.
|
|
*
|
|
* http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.25.749
|
|
*/
|
|
|
|
struct rewrite_params
|
|
{
|
|
struct basicblock* find;
|
|
struct basicblock* replace;
|
|
};
|
|
|
|
static bool find_replace_cb(struct ir* ir, void* user)
|
|
{
|
|
struct rewrite_params* rwp = user;
|
|
|
|
if ((ir->opcode == IR_BLOCK) && (ir->u.bvalue == rwp->find))
|
|
ir->u.bvalue = rwp->replace;
|
|
|
|
return false;
|
|
}
|
|
|
|
static void split_edge(struct basicblock* source, struct basicblock* sink)
|
|
{
|
|
int i;
|
|
struct rewrite_params rwp;
|
|
struct basicblock* bb = bb_get(NULL);
|
|
|
|
struct ir* jump =
|
|
new_ir1(
|
|
IR_JUMP, 0,
|
|
new_bbir(sink)
|
|
);
|
|
|
|
jump->root = jump->left->root = jump;
|
|
array_append(&bb->irs, jump);
|
|
|
|
rwp.find = sink;
|
|
rwp.replace = bb;
|
|
|
|
for (i=0; i<source->irs.count; i++)
|
|
ir_walk(source->irs.item[i], find_replace_cb, &rwp);
|
|
|
|
array_remove(&source->nexts, sink);
|
|
array_append(&source->nexts, bb);
|
|
|
|
array_append(&bb->prevs, source);
|
|
array_append(&bb->nexts, sink);
|
|
|
|
array_remove(&sink->prevs, source);
|
|
array_append(&sink->prevs, bb);
|
|
|
|
array_append(¤t_proc->blocks, bb);
|
|
}
|
|
|
|
static bool consider_edges_leading_from(struct basicblock* bb)
|
|
{
|
|
bool changed = false;
|
|
|
|
if (bb->nexts.count > 1)
|
|
{
|
|
int i;
|
|
|
|
for (i=0; i<bb->nexts.count; i++)
|
|
{
|
|
struct basicblock* next = bb->nexts.item[i];
|
|
if (next->prevs.count > 1)
|
|
{
|
|
split_edge(bb, next);
|
|
changed = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return changed;
|
|
}
|
|
|
|
void pass_split_critical_edges(void)
|
|
{
|
|
int i;
|
|
bool changed;
|
|
|
|
do
|
|
{
|
|
changed = false;
|
|
|
|
for (i=0; i<current_proc->blocks.count; i++)
|
|
changed |= consider_edges_leading_from(current_proc->blocks.item[i]);
|
|
|
|
}
|
|
while (changed);
|
|
}
|
|
|
|
/* vim: set sw=4 ts=4 expandtab : */
|
|
|