Output register equality constraints work.

This commit is contained in:
David Given 2016-10-14 22:17:02 +02:00
parent 216ff5cc43
commit 98fe70a7de
8 changed files with 119 additions and 28 deletions

View file

@ -26,6 +26,7 @@ struct insel
struct constraint struct constraint
{ {
uint32_t attrs; uint32_t attrs;
struct vreg* equals_to;
}; };
struct hop struct hop

View file

@ -113,6 +113,13 @@ static void constrain_output_reg(uint32_t attr)
get_constraint(vreg)->attrs = attr; get_constraint(vreg)->attrs = attr;
} }
static void constrain_output_reg_equal_to(int child)
{
struct vreg* vreg = find_vreg_of_child(child);
get_constraint(current_hop->output)->equals_to = vreg;
}
static const struct burm_emitter_data emitter_data = static const struct burm_emitter_data emitter_data =
{ {
&emit_string, &emit_string,
@ -122,7 +129,8 @@ static const struct burm_emitter_data emitter_data =
&emit_value, &emit_value,
&emit_eoi, &emit_eoi,
&constrain_input_reg, &constrain_input_reg,
&constrain_output_reg &constrain_output_reg,
&constrain_output_reg_equal_to,
}; };
static void emit(struct insn* insn) static void emit(struct insn* insn)

View file

@ -142,26 +142,74 @@ static void add_output_register(struct vreg* vreg)
{ {
struct hreg* hreg; struct hreg* hreg;
int i; int i;
struct constraint* c;
/* Find an unused output register of the right class. */ /* Is this register supposed to be the same as one of the input registers?
* */
hreg = NULL; c = pmap_findleft(&current_hop->constraints, vreg);
for (i=0; i<hregs.count; i++) if (c->equals_to)
{ {
hreg = hregs.item[i]; /* This output register is constrained to be in the same hreg as an
if (allocatable(hreg, vreg) && * input register (most likely for a 2op instruction). */
!pmap_findleft(current_outs, hreg))
hreg = pmap_findright(current_ins, c->equals_to);
/* If this register is current unused as an output, use it. */
if (!pmap_findleft(current_outs, hreg))
{ {
goto found; pmap_add(current_outs, hreg, vreg);
return;
} }
/* Okay, something's in it. Most likely it's a through being used as an
* input register. Trying to evict it would be pointless as that would
* also evict the input. So, we're going to have to do this the hard
* way: we try to allocate a matched set of input and output registers.
* */
hreg = NULL;
for (i=0; i<hregs.count; i++)
{
hreg = hregs.item[i];
if (allocatable(hreg, vreg) &&
!pmap_findleft(current_ins, hreg) &&
!pmap_findleft(current_outs, hreg))
{
goto found1;
}
}
/* If we couldn't find one, evict a register. */
hreg = evict(vreg);
found1:
pmap_add(current_outs, hreg, vreg);
pmap_add(current_ins, hreg, c->equals_to);
} }
else
{
/* This is an ordinary new register. */
/* If we couldn't find one, evict a register. */ hreg = NULL;
for (i=0; i<hregs.count; i++)
{
hreg = hregs.item[i];
if (allocatable(hreg, vreg) &&
!pmap_findleft(current_outs, hreg))
{
goto found2;
}
}
hreg = evict(vreg); /* If we couldn't find one, evict a register. */
found: hreg = evict(vreg);
pmap_add(current_outs, hreg, vreg);
found2:
pmap_add(current_outs, hreg, vreg);
}
} }
static void find_new_home_for_evicted_register(struct vreg* vreg, struct hreg* src) static void find_new_home_for_evicted_register(struct vreg* vreg, struct hreg* src)

View file

@ -167,33 +167,40 @@ PATTERNS
/* Conversions to ubyte and ushort */ /* Conversions to ubyte and ushort */
out:(int)ubyte = in:(int)reg out:(int)ubyte = in:(int)reg
emit "mr %out, %in ! reg -> ubyte" with %out == %in
emit "! reg -> ubyte"
cost 1; cost 1;
out:(int)ubyte = CIU41(value:(int)reg) out:(int)ubyte = CIU41(value:(int)reg)
emit "mr %out, %value ! CIU41(reg) -> ubyte" with %out == %value
emit "! CIU41(reg) -> ubyte"
cost 1; cost 1;
out:(int)ubyte = CIU41(CII14(CIU41(value:(int)reg))) out:(int)ubyte = CIU41(CII14(CIU41(value:(int)reg)))
emit "mr %out, %value ! CIU41(CII14(CIU41(reg))) -> ubyte" with %out == %value
emit "! CIU41(CII14(CIU41(reg))) -> ubyte"
cost 1; cost 1;
out:(int)ushort = in:(int)reg out:(int)ushort = in:(int)reg
emit "mr %out, %in ! reg -> ushort" with %out == %in
emit "! reg -> ushort"
cost 1; cost 1;
out:(int)ushort = CIU42(value:(int)reg) out:(int)ushort = CIU42(value:(int)reg)
emit "mr %out, %value ! CIU42(reg) -> ushort" with %out == %value
emit "! CIU42(reg) -> ushort"
cost 1; cost 1;
out:(int)ushort = CIU42(CII24(CIU42(value:(int)reg))) out:(int)ushort = CIU42(CII24(CIU42(value:(int)reg)))
emit "mr %out, %value ! CIU42(CII24(CIU42(reg))) -> ushort" with %out == %value
emit "! CIU42(CII24(CIU42(reg))) -> ushort"
cost 1; cost 1;
/* Conversions from ubyte and ushort */ /* Conversions from ubyte and ushort */
out:(int)reg = CIU14(in:(int)ubyte) out:(int)reg = CIU14(in:(int)ubyte)
emit "mr %out, %in ! CIU14" with %out == %in
emit "! CIU14"
cost 4; cost 4;

View file

@ -143,12 +143,8 @@ constraints
constraint constraint
: '(' constraint ')' { $$ = $2; } : '(' constraint ')' { $$ = $2; }
| ID ID { $$ = calloc(1, sizeof(*$$)); | '%' ID EQUALS '%' ID { $$ = calloc(1, sizeof(*$$));
$$->type = CONSTRAINT_ATTR; $$->left = $1; $$->right = $2; } $$->type = CONSTRAINT_EQUALS; $$->left = $2; $$->right = $5; }
| ID EQUALS ID { $$ = calloc(1, sizeof(*$$));
$$->type = CONSTRAINT_EQUALS; $$->left = $1; $$->right = $3; }
| ID NOTEQUALS ID { $$ = calloc(1, sizeof(*$$));
$$->type = CONSTRAINT_NOTEQUALS; $$->left = $1; $$->right = $3; }
; ;
qfragments qfragments

View file

@ -1096,6 +1096,36 @@ static void emit_input_regs(Tree node, int* index)
emit_input_regs(node->right, index); emit_input_regs(node->right, index);
} }
static void emit_output_constraints(Rule r)
{
int i;
struct constraint* outputc = NULL;
for (i=0; i<r->constraints.count; i++)
{
struct constraint* c = r->constraints.item[i];
if (c->type == CONSTRAINT_EQUALS)
{
if (strcmp(c->left, r->label) != 0)
yyerror("equality register constraints must have an output register on the left hand side");
if (outputc != NULL)
yyerror("you can't specify more than one output register constraint");
outputc = c;
}
}
if (outputc)
{
int index = 0;
if (!find_child_index(r->pattern, outputc->right, &index, NULL))
label_not_found(r, outputc->right);
print("%1data->constrain_output_reg_equal_to(%d);\n", index);
}
}
/* emitinsndata - emit the code generation data */ /* emitinsndata - emit the code generation data */
static void emitinsndata(Rule rules) static void emitinsndata(Rule rules)
{ {
@ -1129,7 +1159,9 @@ static void emitinsndata(Rule rules)
int index = 0; int index = 0;
emit_input_regs(r->pattern, &index); emit_input_regs(r->pattern, &index);
} }
emit_output_constraints(r);
while (f) while (f)
{ {
switch (f->data[0]) switch (f->data[0])

View file

@ -19,9 +19,7 @@ typedef struct term* Term;
enum enum
{ {
CONSTRAINT_ATTR,
CONSTRAINT_EQUALS, CONSTRAINT_EQUALS,
CONSTRAINT_NOTEQUALS
}; };
struct constraint struct constraint

View file

@ -46,6 +46,7 @@ struct burm_emitter_data
void (*emit_eoi)(void); void (*emit_eoi)(void);
void (*constrain_input_reg)(int child, uint32_t attr); void (*constrain_input_reg)(int child, uint32_t attr);
void (*constrain_output_reg)(uint32_t attr); void (*constrain_output_reg)(uint32_t attr);
void (*constrain_output_reg_equal_to)(int child);
}; };
typedef void burm_emitter_t(const struct burm_emitter_data* data); typedef void burm_emitter_t(const struct burm_emitter_data* data);