- Reduce the algorithmic complexity of parts of the register allocator
so the worst case runtime of romcc is much more predictable git-svn-id: svn://svn.coreboot.org/coreboot/trunk@879 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
This commit is contained in:
parent
d3e377a520
commit
f96a810f11
|
@ -1,5 +1,5 @@
|
||||||
VERSION:=0.27
|
VERSION:=0.28
|
||||||
RELEASE_DATE:=10 June 2003
|
RELEASE_DATE:=16 June 2003
|
||||||
PACKAGE:=romcc
|
PACKAGE:=romcc
|
||||||
|
|
||||||
|
|
||||||
|
@ -52,7 +52,8 @@ TESTS=\
|
||||||
simple_test31.c \
|
simple_test31.c \
|
||||||
raminit_test.c \
|
raminit_test.c \
|
||||||
raminit_test2.c \
|
raminit_test2.c \
|
||||||
raminit_test3.c
|
raminit_test3.c \
|
||||||
|
raminit_test4.c
|
||||||
|
|
||||||
TEST_SRCS:=$(patsubst %, tests/%, $(TESTS))
|
TEST_SRCS:=$(patsubst %, tests/%, $(TESTS))
|
||||||
TEST_ASM:=$(patsubst %.c, tests/%.S, $(TESTS))
|
TEST_ASM:=$(patsubst %.c, tests/%.S, $(TESTS))
|
||||||
|
@ -77,5 +78,5 @@ echo:
|
||||||
echo "TEST_ELF=$(TEST_ELF)"
|
echo "TEST_ELF=$(TEST_ELF)"
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f romcc core $(TEST_ASM) $(TEST_OBJ) $(TEST_ELF) tests/*.debug tests/*.debug2
|
rm -f romcc romcc_pg core $(TEST_ASM) $(TEST_OBJ) $(TEST_ELF) tests/*.debug tests/*.debug2 tests/*.gmon.out
|
||||||
|
|
||||||
|
|
|
@ -847,7 +847,11 @@ struct type {
|
||||||
|
|
||||||
#define MAX_REGISTERS 75
|
#define MAX_REGISTERS 75
|
||||||
#define MAX_REG_EQUIVS 16
|
#define MAX_REG_EQUIVS 16
|
||||||
|
#if 1
|
||||||
|
#define REGISTER_BITS 16
|
||||||
|
#else
|
||||||
#define REGISTER_BITS 28
|
#define REGISTER_BITS 28
|
||||||
|
#endif
|
||||||
#define MAX_VIRT_REGISTERS (1<<REGISTER_BITS)
|
#define MAX_VIRT_REGISTERS (1<<REGISTER_BITS)
|
||||||
#define TEMPLATE_BITS 6
|
#define TEMPLATE_BITS 6
|
||||||
#define MAX_TEMPLATES (1<<TEMPLATE_BITS)
|
#define MAX_TEMPLATES (1<<TEMPLATE_BITS)
|
||||||
|
@ -862,9 +866,22 @@ struct type {
|
||||||
#define REG_VIRT5 (MAX_REGISTERS + 5)
|
#define REG_VIRT5 (MAX_REGISTERS + 5)
|
||||||
|
|
||||||
/* Provision for 8 register classes */
|
/* Provision for 8 register classes */
|
||||||
|
#if 1
|
||||||
|
#define REG_SHIFT 0
|
||||||
|
#define REGC_SHIFT REGISTER_BITS
|
||||||
|
#define REGC_MASK (((1 << MAX_REGC) - 1) << REGISTER_BITS)
|
||||||
#define REG_MASK (MAX_VIRT_REGISTERS -1)
|
#define REG_MASK (MAX_VIRT_REGISTERS -1)
|
||||||
#define ID_REG(ID) ((ID) & REG_MASK)
|
#define ID_REG(ID) ((ID) & REG_MASK)
|
||||||
#define SET_REG(ID, REG) ((ID) = (((ID) & ~REG_MASK) | ((REG) & REG_MASK)))
|
#define SET_REG(ID, REG) ((ID) = (((ID) & ~REG_MASK) | ((REG) & REG_MASK)))
|
||||||
|
#define ID_REGCM(ID) (((ID) & REGC_MASK) >> REGC_SHIFT)
|
||||||
|
#define SET_REGCM(ID, REGCM) ((ID) = (((ID) & ~REGC_MASK) | (((REGCM) << REGC_SHIFT) & REGC_MASK)))
|
||||||
|
#define SET_INFO(ID, INFO) ((ID) = (((ID) & ~(REG_MASK | REGC_MASK)) | \
|
||||||
|
(((INFO).reg) & REG_MASK) | ((((INFO).regcm) << REGC_SHIFT) & REGC_MASK)))
|
||||||
|
#else
|
||||||
|
#define REG_MASK (MAX_VIRT_REGISTERS -1)
|
||||||
|
#define ID_REG(ID) ((ID) & REG_MASK)
|
||||||
|
#define SET_REG(ID, REG) ((ID) = (((ID) & ~REG_MASK) | ((REG) & REG_MASK)))
|
||||||
|
#endif
|
||||||
|
|
||||||
static unsigned arch_reg_regcm(struct compile_state *state, int reg);
|
static unsigned arch_reg_regcm(struct compile_state *state, int reg);
|
||||||
static unsigned arch_regcm_normalize(struct compile_state *state, unsigned regcm);
|
static unsigned arch_regcm_normalize(struct compile_state *state, unsigned regcm);
|
||||||
|
@ -10843,7 +10860,7 @@ static void free_variable_lifetimes(
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct triple *(*wvl_cb_t)(
|
typedef void (*wvl_cb_t)(
|
||||||
struct compile_state *state,
|
struct compile_state *state,
|
||||||
struct reg_block *blocks, struct triple_reg_set *live,
|
struct reg_block *blocks, struct triple_reg_set *live,
|
||||||
struct reg_block *rb, struct triple *ins, void *arg);
|
struct reg_block *rb, struct triple *ins, void *arg);
|
||||||
|
@ -10873,7 +10890,7 @@ static void walk_variable_lifetimes(struct compile_state *state,
|
||||||
}
|
}
|
||||||
/* Walk through the basic block calculating live */
|
/* Walk through the basic block calculating live */
|
||||||
for(done = 0, ptr = block->last; !done; ptr = prev) {
|
for(done = 0, ptr = block->last; !done; ptr = prev) {
|
||||||
struct triple **expr, *result;
|
struct triple **expr;
|
||||||
|
|
||||||
prev = ptr->prev;
|
prev = ptr->prev;
|
||||||
done = (ptr == block->first);
|
done = (ptr == block->first);
|
||||||
|
@ -10886,20 +10903,11 @@ static void walk_variable_lifetimes(struct compile_state *state,
|
||||||
/* Inform the callback function of what is
|
/* Inform the callback function of what is
|
||||||
* going on.
|
* going on.
|
||||||
*/
|
*/
|
||||||
result = cb(state, blocks, live, rb, ptr, arg);
|
cb(state, blocks, live, rb, ptr, arg);
|
||||||
|
|
||||||
/* Remove the current definition from live */
|
/* Remove the current definition from live */
|
||||||
do_triple_unset(&live, ptr);
|
do_triple_unset(&live, ptr);
|
||||||
|
|
||||||
/* If the current instruction was deleted continue */
|
|
||||||
if (!result) {
|
|
||||||
if (block->last == ptr) {
|
|
||||||
block->last = prev;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Add the current uses to live.
|
/* Add the current uses to live.
|
||||||
*
|
*
|
||||||
* It is safe to skip phi functions because they do
|
* It is safe to skip phi functions because they do
|
||||||
|
@ -11769,7 +11777,7 @@ static void initialize_live_ranges(
|
||||||
} while(ins != first);
|
} while(ins != first);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct triple *graph_ins(
|
static void graph_ins(
|
||||||
struct compile_state *state,
|
struct compile_state *state,
|
||||||
struct reg_block *blocks, struct triple_reg_set *live,
|
struct reg_block *blocks, struct triple_reg_set *live,
|
||||||
struct reg_block *rb, struct triple *ins, void *arg)
|
struct reg_block *rb, struct triple *ins, void *arg)
|
||||||
|
@ -11783,7 +11791,7 @@ static struct triple *graph_ins(
|
||||||
* the interference graph.
|
* the interference graph.
|
||||||
*/
|
*/
|
||||||
if (!triple_is_def(state, ins)) {
|
if (!triple_is_def(state, ins)) {
|
||||||
return ins;
|
return;
|
||||||
}
|
}
|
||||||
def = rstate->lrd[ins->id].lr;
|
def = rstate->lrd[ins->id].lr;
|
||||||
|
|
||||||
|
@ -11805,11 +11813,11 @@ static struct triple *graph_ins(
|
||||||
}
|
}
|
||||||
add_live_edge(rstate, def, lr);
|
add_live_edge(rstate, def, lr);
|
||||||
}
|
}
|
||||||
return ins;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static struct triple *print_interference_ins(
|
static void print_interference_ins(
|
||||||
struct compile_state *state,
|
struct compile_state *state,
|
||||||
struct reg_block *blocks, struct triple_reg_set *live,
|
struct reg_block *blocks, struct triple_reg_set *live,
|
||||||
struct reg_block *rb, struct triple *ins, void *arg)
|
struct reg_block *rb, struct triple *ins, void *arg)
|
||||||
|
@ -11855,7 +11863,7 @@ static struct triple *print_interference_ins(
|
||||||
if (triple_is_branch(state, ins)) {
|
if (triple_is_branch(state, ins)) {
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
return ins;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int coalesce_live_ranges(
|
static int coalesce_live_ranges(
|
||||||
|
@ -11962,17 +11970,11 @@ static int coalesce_live_ranges(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct coalesce_conflict {
|
static void fix_coalesce_conflicts(struct compile_state *state,
|
||||||
struct triple *ins;
|
|
||||||
int index;
|
|
||||||
};
|
|
||||||
static struct triple *spot_coalesce_conflict(struct compile_state *state,
|
|
||||||
struct reg_block *blocks, struct triple_reg_set *live,
|
struct reg_block *blocks, struct triple_reg_set *live,
|
||||||
struct reg_block *rb, struct triple *ins, void *arg)
|
struct reg_block *rb, struct triple *ins, void *arg)
|
||||||
{
|
{
|
||||||
struct coalesce_conflict *conflict = arg;
|
|
||||||
int zlhs, zrhs, i, j;
|
int zlhs, zrhs, i, j;
|
||||||
int found;
|
|
||||||
|
|
||||||
/* See if we have a mandatory coalesce operation between
|
/* See if we have a mandatory coalesce operation between
|
||||||
* a lhs and a rhs value. If so and the rhs value is also
|
* a lhs and a rhs value. If so and the rhs value is also
|
||||||
|
@ -11980,101 +11982,113 @@ static struct triple *spot_coalesce_conflict(struct compile_state *state,
|
||||||
* we would have two definitions in the same live range simultaneously
|
* we would have two definitions in the same live range simultaneously
|
||||||
* alive.
|
* alive.
|
||||||
*/
|
*/
|
||||||
found = -1;
|
|
||||||
zlhs = TRIPLE_LHS(ins->sizes);
|
zlhs = TRIPLE_LHS(ins->sizes);
|
||||||
if ((zlhs == 0) && triple_is_def(state, ins)) {
|
if ((zlhs == 0) && triple_is_def(state, ins)) {
|
||||||
zlhs = 1;
|
zlhs = 1;
|
||||||
}
|
}
|
||||||
zrhs = TRIPLE_RHS(ins->sizes);
|
zrhs = TRIPLE_RHS(ins->sizes);
|
||||||
for(i = 0; (i < zlhs) && (found == -1); i++) {
|
for(i = 0; i < zlhs; i++) {
|
||||||
struct reg_info linfo;
|
struct reg_info linfo;
|
||||||
linfo = arch_reg_lhs(state, ins, i);
|
linfo = arch_reg_lhs(state, ins, i);
|
||||||
if (linfo.reg < MAX_REGISTERS) {
|
if (linfo.reg < MAX_REGISTERS) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for(j = 0; (j < zrhs) && (found == -1); j++) {
|
for(j = 0; j < zrhs; j++) {
|
||||||
struct reg_info rinfo;
|
struct reg_info rinfo;
|
||||||
struct triple *rhs;
|
struct triple *rhs;
|
||||||
struct triple_reg_set *set;
|
struct triple_reg_set *set;
|
||||||
|
int found;
|
||||||
|
found = 0;
|
||||||
rinfo = arch_reg_rhs(state, ins, j);
|
rinfo = arch_reg_rhs(state, ins, j);
|
||||||
if (rinfo.reg != linfo.reg) {
|
if (rinfo.reg != linfo.reg) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
rhs = RHS(ins, j);
|
rhs = RHS(ins, j);
|
||||||
for(set = live; set && (found == -1); set = set->next) {
|
for(set = live; set && !found; set = set->next) {
|
||||||
if (set->member == rhs) {
|
if (set->member == rhs) {
|
||||||
found = j;
|
found = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (found) {
|
||||||
|
struct triple *copy;
|
||||||
|
copy = pre_copy(state, ins, j);
|
||||||
|
copy->id |= TRIPLE_FLAG_PRE_SPLIT;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Only update conflict if we are the least dominated conflict */
|
return;
|
||||||
if ((found != -1) &&
|
|
||||||
(!conflict->ins || tdominates(state, ins, conflict->ins))) {
|
|
||||||
conflict->ins = ins;
|
|
||||||
conflict->index = found;
|
|
||||||
}
|
|
||||||
return ins;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void resolve_coalesce_conflict(
|
static void replace_set_use(struct compile_state *state,
|
||||||
struct compile_state *state, struct coalesce_conflict *conflict)
|
struct triple_reg_set *head, struct triple *orig, struct triple *new)
|
||||||
{
|
{
|
||||||
struct triple *copy;
|
|
||||||
copy = pre_copy(state, conflict->ins, conflict->index);
|
|
||||||
copy->id |= TRIPLE_FLAG_PRE_SPLIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static struct triple *spot_tangle(struct compile_state *state,
|
|
||||||
struct reg_block *blocks, struct triple_reg_set *live,
|
|
||||||
struct reg_block *rb, struct triple *ins, void *arg)
|
|
||||||
{
|
|
||||||
struct triple **tangle = arg;
|
|
||||||
char used[MAX_REGISTERS];
|
|
||||||
struct triple_reg_set *set;
|
struct triple_reg_set *set;
|
||||||
|
for(set = head; set; set = set->next) {
|
||||||
/* Find out which registers have multiple uses at this point */
|
if (set->member == orig) {
|
||||||
memset(used, 0, sizeof(used));
|
set->member = new;
|
||||||
for(set = live; set; set = set->next) {
|
|
||||||
struct reg_info info;
|
|
||||||
info = find_lhs_color(state, set->member, 0);
|
|
||||||
if (info.reg == REG_UNSET) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
reg_inc_used(state, used, info.reg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Now find the least dominated definition of a register in
|
|
||||||
* conflict I have seen so far.
|
|
||||||
*/
|
|
||||||
for(set = live; set; set = set->next) {
|
|
||||||
struct reg_info info;
|
|
||||||
info = find_lhs_color(state, set->member, 0);
|
|
||||||
if (used[info.reg] < 2) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!*tangle || tdominates(state, set->member, *tangle)) {
|
|
||||||
*tangle = set->member;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ins;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void resolve_tangle(struct compile_state *state, struct triple *tangle)
|
static void replace_block_use(struct compile_state *state,
|
||||||
|
struct reg_block *blocks, struct triple *orig, struct triple *new)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
#warning "WISHLIST visit just those blocks that need it *"
|
||||||
|
for(i = 1; i <= state->last_vertex; i++) {
|
||||||
|
struct reg_block *rb;
|
||||||
|
rb = &blocks[i];
|
||||||
|
replace_set_use(state, rb->in, orig, new);
|
||||||
|
replace_set_use(state, rb->out, orig, new);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void color_instructions(struct compile_state *state)
|
||||||
|
{
|
||||||
|
struct triple *ins, *first;
|
||||||
|
first = RHS(state->main_function, 0);
|
||||||
|
ins = first;
|
||||||
|
do {
|
||||||
|
if (triple_is_def(state, ins)) {
|
||||||
|
struct reg_info info;
|
||||||
|
info = find_lhs_color(state, ins, 0);
|
||||||
|
if (info.reg >= MAX_REGISTERS) {
|
||||||
|
info.reg = REG_UNSET;
|
||||||
|
}
|
||||||
|
SET_INFO(ins->id, info);
|
||||||
|
}
|
||||||
|
ins = ins->next;
|
||||||
|
} while(ins != first);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct reg_info read_lhs_color(
|
||||||
|
struct compile_state *state, struct triple *ins, int index)
|
||||||
|
{
|
||||||
|
struct reg_info info;
|
||||||
|
if ((index == 0) && triple_is_def(state, ins)) {
|
||||||
|
info.reg = ID_REG(ins->id);
|
||||||
|
info.regcm = ID_REGCM(ins->id);
|
||||||
|
}
|
||||||
|
else if (index < TRIPLE_LHS(ins->sizes)) {
|
||||||
|
info = read_lhs_color(state, LHS(ins, index), 0);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
internal_error(state, ins, "Bad lhs %d", index);
|
||||||
|
info.reg = REG_UNSET;
|
||||||
|
info.regcm = 0;
|
||||||
|
}
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct triple *resolve_tangle(
|
||||||
|
struct compile_state *state, struct triple *tangle)
|
||||||
{
|
{
|
||||||
struct reg_info info, uinfo;
|
struct reg_info info, uinfo;
|
||||||
struct triple_set *set, *next;
|
struct triple_set *set, *next;
|
||||||
struct triple *copy;
|
struct triple *copy;
|
||||||
|
|
||||||
#if 0
|
#warning "WISHLIST recalculate all affected instructions colors"
|
||||||
fprintf(stderr, "Resolving tangle: %p\n", tangle);
|
|
||||||
print_blocks(state, stderr);
|
|
||||||
#endif
|
|
||||||
info = find_lhs_color(state, tangle, 0);
|
info = find_lhs_color(state, tangle, 0);
|
||||||
#if 0
|
|
||||||
fprintf(stderr, "color: %d\n", info.reg);
|
|
||||||
#endif
|
|
||||||
for(set = tangle->use; set; set = next) {
|
for(set = tangle->use; set; set = next) {
|
||||||
struct triple *user;
|
struct triple *user;
|
||||||
int i, zrhs;
|
int i, zrhs;
|
||||||
|
@ -12086,27 +12100,85 @@ static void resolve_tangle(struct compile_state *state, struct triple *tangle)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
uinfo = find_rhs_post_color(state, user, i);
|
uinfo = find_rhs_post_color(state, user, i);
|
||||||
#if 0
|
|
||||||
fprintf(stderr, "%p rhs %d color: %d\n",
|
|
||||||
user, i, uinfo.reg);
|
|
||||||
#endif
|
|
||||||
if (uinfo.reg == info.reg) {
|
if (uinfo.reg == info.reg) {
|
||||||
copy = pre_copy(state, user, i);
|
copy = pre_copy(state, user, i);
|
||||||
copy->id |= TRIPLE_FLAG_PRE_SPLIT;
|
copy->id |= TRIPLE_FLAG_PRE_SPLIT;
|
||||||
|
SET_INFO(copy->id, uinfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
copy = 0;
|
||||||
uinfo = find_lhs_pre_color(state, tangle, 0);
|
uinfo = find_lhs_pre_color(state, tangle, 0);
|
||||||
#if 0
|
|
||||||
fprintf(stderr, "pre color: %d\n", uinfo.reg);
|
|
||||||
#endif
|
|
||||||
if (uinfo.reg == info.reg) {
|
if (uinfo.reg == info.reg) {
|
||||||
|
struct reg_info linfo;
|
||||||
copy = post_copy(state, tangle);
|
copy = post_copy(state, tangle);
|
||||||
copy->id |= TRIPLE_FLAG_PRE_SPLIT;
|
copy->id |= TRIPLE_FLAG_PRE_SPLIT;
|
||||||
|
linfo = find_lhs_color(state, copy, 0);
|
||||||
|
SET_INFO(copy->id, linfo);
|
||||||
}
|
}
|
||||||
|
info = find_lhs_color(state, tangle, 0);
|
||||||
|
SET_INFO(tangle->id, info);
|
||||||
|
|
||||||
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void fix_tangles(struct compile_state *state,
|
||||||
|
struct reg_block *blocks, struct triple_reg_set *live,
|
||||||
|
struct reg_block *rb, struct triple *ins, void *arg)
|
||||||
|
{
|
||||||
|
struct triple *tangle;
|
||||||
|
do {
|
||||||
|
char used[MAX_REGISTERS];
|
||||||
|
struct triple_reg_set *set;
|
||||||
|
tangle = 0;
|
||||||
|
|
||||||
|
/* Find out which registers have multiple uses at this point */
|
||||||
|
memset(used, 0, sizeof(used));
|
||||||
|
for(set = live; set; set = set->next) {
|
||||||
|
struct reg_info info;
|
||||||
|
info = read_lhs_color(state, set->member, 0);
|
||||||
|
if (info.reg == REG_UNSET) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
reg_inc_used(state, used, info.reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now find the least dominated definition of a register in
|
||||||
|
* conflict I have seen so far.
|
||||||
|
*/
|
||||||
|
for(set = live; set; set = set->next) {
|
||||||
|
struct reg_info info;
|
||||||
|
info = read_lhs_color(state, set->member, 0);
|
||||||
|
if (used[info.reg] < 2) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!tangle || tdominates(state, set->member, tangle)) {
|
||||||
|
tangle = set->member;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* If I have found a tangle resolve it */
|
||||||
|
if (tangle) {
|
||||||
|
struct triple *post_copy;
|
||||||
|
post_copy = resolve_tangle(state, tangle);
|
||||||
|
if (post_copy) {
|
||||||
|
replace_block_use(state, blocks, tangle, post_copy);
|
||||||
|
}
|
||||||
|
if (post_copy && (tangle != ins)) {
|
||||||
|
replace_set_use(state, live, tangle, post_copy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while(tangle);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void correct_tangles(
|
||||||
|
struct compile_state *state, struct reg_block *blocks)
|
||||||
|
{
|
||||||
|
color_instructions(state);
|
||||||
|
walk_variable_lifetimes(state, blocks, fix_tangles, 0);
|
||||||
|
}
|
||||||
|
|
||||||
struct least_conflict {
|
struct least_conflict {
|
||||||
struct reg_state *rstate;
|
struct reg_state *rstate;
|
||||||
struct live_range *ref_range;
|
struct live_range *ref_range;
|
||||||
|
@ -12114,7 +12186,7 @@ struct least_conflict {
|
||||||
struct triple_reg_set *live;
|
struct triple_reg_set *live;
|
||||||
size_t count;
|
size_t count;
|
||||||
};
|
};
|
||||||
static struct triple *least_conflict(struct compile_state *state,
|
static void least_conflict(struct compile_state *state,
|
||||||
struct reg_block *blocks, struct triple_reg_set *live,
|
struct reg_block *blocks, struct triple_reg_set *live,
|
||||||
struct reg_block *rb, struct triple *ins, void *arg)
|
struct reg_block *rb, struct triple *ins, void *arg)
|
||||||
{
|
{
|
||||||
|
@ -12128,7 +12200,7 @@ static struct triple *least_conflict(struct compile_state *state,
|
||||||
* can be the conflict instruction.
|
* can be the conflict instruction.
|
||||||
*/
|
*/
|
||||||
if (!triple_is_def(state, ins)) {
|
if (!triple_is_def(state, ins)) {
|
||||||
return ins;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* See if live ranges at this instruction are a
|
/* See if live ranges at this instruction are a
|
||||||
|
@ -12144,12 +12216,12 @@ static struct triple *least_conflict(struct compile_state *state,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!edge && (lr != conflict->ref_range)) {
|
if (!edge && (lr != conflict->ref_range)) {
|
||||||
return ins;
|
return;
|
||||||
}
|
}
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
if (count <= 1) {
|
if (count <= 1) {
|
||||||
return ins;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* See if there is an uncolored member in this subset.
|
/* See if there is an uncolored member in this subset.
|
||||||
|
@ -12162,7 +12234,7 @@ static struct triple *least_conflict(struct compile_state *state,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!set && (conflict->ref_range != REG_UNSET)) {
|
if (!set && (conflict->ref_range != REG_UNSET)) {
|
||||||
return ins;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -12208,7 +12280,7 @@ static struct triple *least_conflict(struct compile_state *state,
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ins;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void find_range_conflict(struct compile_state *state,
|
static void find_range_conflict(struct compile_state *state,
|
||||||
|
@ -12975,49 +13047,23 @@ static void allocate_registers(struct compile_state *state)
|
||||||
|
|
||||||
do {
|
do {
|
||||||
struct live_range **point, **next;
|
struct live_range **point, **next;
|
||||||
struct triple *tangle;
|
|
||||||
struct coalesce_conflict conflict;
|
|
||||||
int coalesced;
|
int coalesced;
|
||||||
|
|
||||||
/* Restore ids */
|
/* Restore ids */
|
||||||
ids_from_rstate(state, &rstate);
|
ids_from_rstate(state, &rstate);
|
||||||
|
|
||||||
do {
|
/* Cleanup the temporary data structures */
|
||||||
/* Cleanup the temporary data structures */
|
cleanup_rstate(state, &rstate);
|
||||||
cleanup_rstate(state, &rstate);
|
|
||||||
|
|
||||||
/* Compute the variable lifetimes */
|
/* Compute the variable lifetimes */
|
||||||
rstate.blocks = compute_variable_lifetimes(state);
|
rstate.blocks = compute_variable_lifetimes(state);
|
||||||
|
|
||||||
/* Find an invalid mandatory live range coalesce */
|
/* Fix invalid mandatory live range coalesce conflicts */
|
||||||
conflict.ins = 0;
|
walk_variable_lifetimes(
|
||||||
conflict.index = -1;
|
state, rstate.blocks, fix_coalesce_conflicts, 0);
|
||||||
walk_variable_lifetimes(
|
|
||||||
state, rstate.blocks, spot_coalesce_conflict, &conflict);
|
|
||||||
|
|
||||||
/* If a tangle was found resolve it */
|
|
||||||
if (conflict.ins) {
|
|
||||||
resolve_coalesce_conflict(state, &conflict);
|
|
||||||
}
|
|
||||||
} while(conflict.ins);
|
|
||||||
|
|
||||||
do {
|
/* Fix two simultaneous uses of the same register */
|
||||||
/* Cleanup the temporary data structures */
|
correct_tangles(state, rstate.blocks);
|
||||||
cleanup_rstate(state, &rstate);
|
|
||||||
|
|
||||||
/* Compute the variable lifetimes */
|
|
||||||
rstate.blocks = compute_variable_lifetimes(state);
|
|
||||||
|
|
||||||
/* Find two simultaneous uses of the same register */
|
|
||||||
tangle = 0;
|
|
||||||
walk_variable_lifetimes(
|
|
||||||
state, rstate.blocks, spot_tangle, &tangle);
|
|
||||||
|
|
||||||
/* If a tangle was found resolve it */
|
|
||||||
if (tangle) {
|
|
||||||
resolve_tangle(state, tangle);
|
|
||||||
}
|
|
||||||
} while(tangle);
|
|
||||||
|
|
||||||
if (state->debug & DEBUG_INSERTED_COPIES) {
|
if (state->debug & DEBUG_INSERTED_COPIES) {
|
||||||
printf("After resolve_tangles\n");
|
printf("After resolve_tangles\n");
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue