Keep track of register types as well as attributes --- the type being how we

find new registers when evicting values. Input constraints work (they were
being ignored before). Various bug fixing so they actually work.
This commit is contained in:
David Given 2016-10-12 22:58:46 +02:00
parent 4723a1442f
commit f06b51c981
11 changed files with 191 additions and 87 deletions

View file

@ -20,6 +20,8 @@ struct ir
PMAPOF(struct basicblock, struct ir) phivalue; PMAPOF(struct basicblock, struct ir) phivalue;
} u; } u;
ARRAYOF(struct ir) uses; /* all places this IR is used */
struct vreg* result; /* vreg containing IR result */ struct vreg* result; /* vreg containing IR result */
}; };

View file

@ -28,7 +28,7 @@ static void collect_irs(struct procedure* proc)
{ {
struct ir* ir = bb->irs.item[j]; struct ir* ir = bb->irs.item[j];
addall(ir); addall(ir);
array_appendu(&rootirs, ir); array_append(&rootirs, ir);
} }
} }
} }

View file

@ -177,7 +177,10 @@ static struct insn* walk_instructions(struct burm_node* node, int goal)
switch (node->label) switch (node->label)
{ {
case ir_to_esn(IR_REG, 0): case ir_to_esn(IR_REG, 1):
case ir_to_esn(IR_REG, 2):
case ir_to_esn(IR_REG, 4):
case ir_to_esn(IR_REG, 8):
vreg = node->ir->result; vreg = node->ir->result;
break; break;

View file

@ -8,7 +8,7 @@ struct assignment
static ARRAYOF(struct hreg) hregs; static ARRAYOF(struct hreg) hregs;
static ARRAYOF(struct vreg) evicted; static PMAPOF(struct vreg, struct hreg) evicted;
static struct hop* current_hop; static struct hop* current_hop;
static register_assignment_t* current_ins; static register_assignment_t* current_ins;
static register_assignment_t* current_outs; static register_assignment_t* current_outs;
@ -63,6 +63,42 @@ static struct hreg* allocate_phi_hreg(register_assignment_t* regs,
assert(false); assert(false);
} }
static bool evictable(struct hreg* hreg, struct vreg* vreg)
{
struct constraint* c = pmap_findleft(&current_hop->constraints, vreg);
return (hreg->attrs & c->attrs) && !array_contains(&current_hop->ins, vreg);
/* Find an unused output register of the right class which is not also being used as an input register. */
}
static struct hreg* evict(struct vreg* vreg)
{
int i;
/* Look for a through register which matches our requirements. We should be
* doing some calculation here to figure out the cheapest register to
* evict, but for now we're picking the first one. FIXME. */
for (i=0; i<hregs.count; i++)
{
struct hreg* hreg = hregs.item[i];
struct vreg* candidate = pmap_findleft(current_ins, hreg);
if (candidate &&
(pmap_findleft(current_outs, hreg) == candidate) &&
evictable(hreg, vreg))
{
tracef('R', "R: evicting %%%d from %s\n", candidate->id, hreg->name);
pmap_put(&evicted, candidate, hreg);
pmap_remove(current_ins, hreg, candidate);
pmap_remove(current_outs, hreg, candidate);
return hreg;
}
}
/* Couldn't find anything to evict */
assert(false);
}
static bool allocatable(struct hreg* hreg, struct vreg* vreg) static bool allocatable(struct hreg* hreg, struct vreg* vreg)
{ {
struct constraint* c = pmap_findleft(&current_hop->constraints, vreg); struct constraint* c = pmap_findleft(&current_hop->constraints, vreg);
@ -75,7 +111,7 @@ static void add_input_register(struct vreg* vreg, struct hreg* hreg)
/* Register hint for an input? */ /* Register hint for an input? */
if (hreg) if (hreg && allocatable(hreg, vreg))
{ {
/* If it's already assigned, it's most likely a through. */ /* If it's already assigned, it's most likely a through. */
if (!pmap_findleft(current_ins, hreg)) if (!pmap_findleft(current_ins, hreg))
@ -85,6 +121,7 @@ static void add_input_register(struct vreg* vreg, struct hreg* hreg)
/* Find an unused input register of the right class. */ /* Find an unused input register of the right class. */
hreg = NULL;
for (i=0; i<hregs.count; i++) for (i=0; i<hregs.count; i++)
{ {
hreg = hregs.item[i]; hreg = hregs.item[i];
@ -103,25 +140,59 @@ static void add_input_register(struct vreg* vreg, struct hreg* hreg)
static void add_output_register(struct vreg* vreg) static void add_output_register(struct vreg* vreg)
{ {
struct hreg* hreg;
int i; int i;
/* Find an unused output register of the right class. */ /* Find an unused output register of the right class. */
hreg = NULL;
for (i=0; i<hregs.count; i++) for (i=0; i<hregs.count; i++)
{ {
struct hreg* hreg = hregs.item[i]; hreg = hregs.item[i];
if (allocatable(hreg, vreg) && if (allocatable(hreg, vreg) &&
!pmap_findleft(current_outs, hreg)) !pmap_findleft(current_outs, hreg))
{ {
/* Got one --- use it. */ goto found;
pmap_add(current_outs, hreg, vreg);
return;
} }
} }
/* Evicting an output register is exciting, because the only possible /* If we couldn't find one, evict a register. */
* candidates are throughs. */
hreg = evict(vreg);
found:
pmap_add(current_outs, hreg, vreg);
}
static void find_new_home_for_evicted_register(struct vreg* vreg, struct hreg* src)
{
uint32_t srctype = src->type;
struct hreg* hreg;
int i;
/* Find an unused output register of the right class which is not also
* being used as an input register. */
hreg = NULL;
for (i=0; i<hregs.count; i++)
{
hreg = hregs.item[i];
if ((hreg->type == src->type) &&
!pmap_findleft(current_ins, hreg) &&
!pmap_findleft(current_outs, hreg))
{
goto found;
}
}
/* No more registers --- allocate a stack slot. */
assert(false); assert(false);
found:
tracef('R', "R: evicted %%%d moving to %s\n", vreg->id, hreg->name);
pmap_add(current_ins, hreg, vreg);
pmap_add(current_outs, hreg, vreg);
} }
static void select_registers(struct hop* hop, static void select_registers(struct hop* hop,
@ -132,6 +203,7 @@ static void select_registers(struct hop* hop,
current_hop = hop; current_hop = hop;
current_ins = in; current_ins = in;
current_outs = out; current_outs = out;
evicted.count = 0;
/* First, any vregs passing through the instruction stay in the same /* First, any vregs passing through the instruction stay in the same
* registers they are currently in. */ * registers they are currently in. */
@ -164,6 +236,16 @@ static void select_registers(struct hop* hop,
struct vreg* vreg = hop->outs.item[i]; struct vreg* vreg = hop->outs.item[i];
add_output_register(vreg); add_output_register(vreg);
} }
/* Any evicted registers now need to go somewhere (potentially, the stack).
* */
for (i=0; i<evicted.count; i++)
{
struct vreg* vreg = evicted.item[i].left;
struct hreg* src = evicted.item[i].right;
find_new_home_for_evicted_register(vreg, src);
}
} }
static void assign_hregs_to_vregs(void) static void assign_hregs_to_vregs(void)
@ -253,16 +335,11 @@ static void assign_hregs_to_vregs(void)
register_assignment_t* in = &hop->regsin; register_assignment_t* in = &hop->regsin;
register_assignment_t* out = &hop->regsout;; register_assignment_t* out = &hop->regsout;;
hop_print('R', hop);
select_registers(hop, old, in, out); select_registers(hop, old, in, out);
tracef('R', "R: %d from $%d:", hop->id, hop->ir->id); tracef('R', "R: %d from $%d: [", hop->id, hop->ir->id);
for (k=0; k<hop->ins.count; k++)
tracef('R', " r%%%d", hop->ins.item[k]->id);
for (k=0; k<hop->throughs.count; k++)
tracef('R', " =%%%d", hop->throughs.item[k]->id);
for (k=0; k<hop->outs.count; k++)
tracef('R', " w%%%d", hop->outs.item[k]->id);
tracef('R', " [");
for (k=0; k<hop->regsin.count; k++) for (k=0; k<hop->regsin.count; k++)
{ {
struct hreg* hreg = hop->regsin.item[k].left; struct hreg* hreg = hop->regsin.item[k].left;

View file

@ -14,6 +14,7 @@ struct phicongruence
struct hreg struct hreg
{ {
const char* name; const char* name;
uint32_t type;
uint32_t attrs; uint32_t attrs;
bool is_stacked; bool is_stacked;
int offset; int offset;

View file

@ -1,73 +1,77 @@
REGISTERS REGISTERS
/* Registers are allocated top down; the order here is odd in order to make /* Registers are allocated top down; the order here is odd in order to make
* sure that non-volatile registers get allocated from r31 (or f31) down. */ * sure that non-volatile registers get allocated from r31 (or f31) down.
*
* Attributes ending in an exclamation mark must match exactly when copying
* a register into another register (e.g. for eviction).
*/
r12 bytes4 int volatile; r12 bytes4! int! volatile;
r11 bytes4 int volatile; r11 bytes4! int! volatile;
r10 bytes4 int volatile; r10 bytes4! int! volatile;
r9 bytes4 int volatile; r9 bytes4! int! volatile;
r8 bytes4 int volatile; r8 bytes4! int! volatile;
r7 bytes4 int volatile; r7 bytes4! int! volatile;
r6 bytes4 int volatile; r6 bytes4! int! volatile;
r5 bytes4 int volatile; r5 bytes4! int! volatile;
r4 bytes4 int volatile; r4 bytes4! int! volatile;
r3 bytes4 int ret volatile; r3 bytes4! int! ret volatile;
r31 bytes4 int; r31 bytes4! int!;
r30 bytes4 int; r30 bytes4! int!;
r29 bytes4 int; r29 bytes4! int!;
r28 bytes4 int; r28 bytes4! int!;
r27 bytes4 int; r27 bytes4! int!;
r26 bytes4 int; r26 bytes4! int!;
r25 bytes4 int; r25 bytes4! int!;
r24 bytes4 int; r24 bytes4! int!;
r23 bytes4 int; r23 bytes4! int!;
r22 bytes4 int; r22 bytes4! int!;
r21 bytes4 int; r21 bytes4! int!;
r20 bytes4 int; r20 bytes4! int!;
r19 bytes4 int; r19 bytes4! int!;
r18 bytes4 int; r18 bytes4! int!;
r17 bytes4 int; r17 bytes4! int!;
r16 bytes4 int; r16 bytes4! int!;
r15 bytes4 int; r15 bytes4! int!;
r14 bytes4 int; r14 bytes4! int!;
f14 bytes4 float volatile; f14 bytes4! float! volatile;
f13 bytes4 float volatile; f13 bytes4! float! volatile;
f12 bytes4 float volatile; f12 bytes4! float! volatile;
f11 bytes4 float volatile; f11 bytes4! float! volatile;
f10 bytes4 float volatile; f10 bytes4! float! volatile;
f9 bytes4 float volatile; f9 bytes4! float! volatile;
f8 bytes4 float volatile; f8 bytes4! float! volatile;
f7 bytes4 float volatile; f7 bytes4! float! volatile;
f6 bytes4 float volatile; f6 bytes4! float! volatile;
f5 bytes4 float volatile; f5 bytes4! float! volatile;
f4 bytes4 float volatile; f4 bytes4! float! volatile;
f3 bytes4 float volatile; f3 bytes4! float! volatile;
f2 bytes4 float volatile; f2 bytes4! float! volatile;
f1 bytes4 float volatile; f1 bytes4! float! volatile;
f0 bytes4 float volatile; f0 bytes4! float! volatile;
f31 bytes4 float; f31 bytes4! float!;
f30 bytes4 float; f30 bytes4! float!;
f29 bytes4 float; f29 bytes4! float!;
f28 bytes4 float; f28 bytes4! float!;
f27 bytes4 float; f27 bytes4! float!;
f26 bytes4 float; f26 bytes4! float!;
f25 bytes4 float; f25 bytes4! float!;
f24 bytes4 float; f24 bytes4! float!;
f23 bytes4 float; f23 bytes4! float!;
f22 bytes4 float; f22 bytes4! float!;
f21 bytes4 float; f21 bytes4! float!;
f20 bytes4 float; f20 bytes4! float!;
f19 bytes4 float; f19 bytes4! float!;
f18 bytes4 float; f18 bytes4! float!;
f17 bytes4 float; f17 bytes4! float!;
f16 bytes4 float; f16 bytes4! float!;
f15 bytes4 float; f15 bytes4! float!;
cr0 cr; cr0 cr!;
DECLARATIONS DECLARATIONS
@ -75,7 +79,7 @@ DECLARATIONS
cr; cr;
ubyte_to_be; ubyte_to_be;
address fragment; address fragment;
PATTERNS PATTERNS
@ -107,10 +111,11 @@ PATTERNS
cost 4; cost 4;
SETRET4(in:(ret)reg) SETRET4(in:(ret)reg)
emit "mr r3, %in" emit "! setret4"
cost 4; cost 4;
(ret)reg = GETRET4 (ret)reg = GETRET4
emit "! getret4"
cost 1; cost 1;
STACKADJUST4(delta:CONST4) STACKADJUST4(delta:CONST4)
@ -139,12 +144,15 @@ PATTERNS
cost 4; cost 4;
out:(int)ubyte_to_be = in:(int)reg out:(int)ubyte_to_be = in:(int)reg
emit "! reg -> ubyte"
cost 1; cost 1;
out:(int)ubyte_to_be = CIU41(value:(int)reg) out:(int)ubyte_to_be = CIU41(value:(int)reg)
emit "! CIU41(reg) -> ubyte"
cost 1; cost 1;
out:(int)ubyte_to_be = CIU41(CII14(CIU41(value:(int)reg))) out:(int)ubyte_to_be = CIU41(CII14(CIU41(value:(int)reg)))
emit "! CIU41(CII14(CIU41(reg))) -> ubyte"
cost 1; cost 1;
out:(int)reg = LOAD4(addr:address) out:(int)reg = LOAD4(addr:address)
@ -284,9 +292,12 @@ PATTERNS
cost 4; cost 4;
out:(int)reg = CIU44(in:(int)reg) out:(int)reg = CIU44(in:(int)reg)
emit "mr %out, %in" emit "mr %out, %in ! ciu44"
cost 4; cost 4;
out:(int)reg = CUI44(in:(int)reg)
emit "mr %out, %in ! cui44"
cost 4;
/* ALU operations */ /* ALU operations */

View file

@ -71,7 +71,8 @@ registers
register register
: ID { $$ = makereg($1); } : ID { $$ = makereg($1); }
| register ID { $$ = $1; addregattr($1, $2); } | register ID { $$ = $1; addregattr($1, $2, false); }
| register ID '!' { $$ = $1; addregattr($1, $2, true); }
; ;
declarations declarations

View file

@ -283,7 +283,7 @@ struct regattr* makeregattr(const char* id)
return p; return p;
} }
void addregattr(struct reg* reg, const char* id) void addregattr(struct reg* reg, const char* id, bool exact)
{ {
struct regattr* p = smap_get(&registerattrs, id); struct regattr* p = smap_get(&registerattrs, id);
@ -291,6 +291,8 @@ void addregattr(struct reg* reg, const char* id)
p = makeregattr(id); p = makeregattr(id);
reg->attrs |= 1<<(p->number); reg->attrs |= 1<<(p->number);
if (exact)
reg->type |= 1<<(p->number);
} }
struct regattr* getregattr(const char* id) struct regattr* getregattr(const char* id)
@ -589,7 +591,7 @@ static void emitregisters(void)
struct reg* r = registers.item[i].right; struct reg* r = registers.item[i].right;
assert(r->number == i); assert(r->number == i);
print("%1{ \"%s\", 0x%x },\n", r->name, r->attrs); print("%1{ \"%s\", 0x%x, 0x%x },\n", r->name, r->type, r->attrs);
} }
print("%1{ NULL }\n"); print("%1{ NULL }\n");
print("};\n\n"); print("};\n\n");

View file

@ -62,6 +62,7 @@ struct reg
const char* name; /* register name */ const char* name; /* register name */
int number; /* identifying number */ int number; /* identifying number */
uint32_t attrs; /* bitfield of register attributes */ uint32_t attrs; /* bitfield of register attributes */
uint32_t type; /* register type */
}; };
struct regattr struct regattr
@ -71,7 +72,7 @@ struct regattr
}; };
extern struct reg* makereg(const char* name); extern struct reg* makereg(const char* name);
extern void addregattr(struct reg* reg, const char* regattr); extern void addregattr(struct reg* reg, const char* regattr, bool exact);
extern struct regattr* getregattr(const char* name); extern struct regattr* getregattr(const char* name);
struct term struct term

View file

@ -58,6 +58,11 @@ S CIU2
S CIU4 S CIU4
S CIU8 S CIU8
S CUI1
S CUI2
S CUI4
S CUI8
# Tristate comparisons # Tristate comparisons
S COMPARES S COMPARES
S COMPAREU S COMPAREU

View file

@ -62,6 +62,7 @@ extern const struct burm_instruction_data burm_instruction_data[];
struct burm_register_data struct burm_register_data
{ {
const char* name; const char* name;
uint32_t type;
uint32_t attrs; uint32_t attrs;
}; };