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
{
uint32_t attrs;
struct vreg* equals_to;
};
struct hop

View file

@ -113,6 +113,13 @@ static void constrain_output_reg(uint32_t 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 =
{
&emit_string,
@ -122,7 +129,8 @@ static const struct burm_emitter_data emitter_data =
&emit_value,
&emit_eoi,
&constrain_input_reg,
&constrain_output_reg
&constrain_output_reg,
&constrain_output_reg_equal_to,
};
static void emit(struct insn* insn)

View file

@ -142,8 +142,55 @@ static void add_output_register(struct vreg* vreg)
{
struct hreg* hreg;
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?
* */
c = pmap_findleft(&current_hop->constraints, vreg);
if (c->equals_to)
{
/* This output register is constrained to be in the same hreg as an
* input register (most likely for a 2op instruction). */
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))
{
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. */
hreg = NULL;
for (i=0; i<hregs.count; i++)
@ -152,7 +199,7 @@ static void add_output_register(struct vreg* vreg)
if (allocatable(hreg, vreg) &&
!pmap_findleft(current_outs, hreg))
{
goto found;
goto found2;
}
}
@ -160,9 +207,10 @@ static void add_output_register(struct vreg* vreg)
hreg = evict(vreg);
found:
found2:
pmap_add(current_outs, hreg, vreg);
}
}
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 */
out:(int)ubyte = in:(int)reg
emit "mr %out, %in ! reg -> ubyte"
with %out == %in
emit "! reg -> ubyte"
cost 1;
out:(int)ubyte = CIU41(value:(int)reg)
emit "mr %out, %value ! CIU41(reg) -> ubyte"
with %out == %value
emit "! CIU41(reg) -> ubyte"
cost 1;
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;
out:(int)ushort = in:(int)reg
emit "mr %out, %in ! reg -> ushort"
with %out == %in
emit "! reg -> ushort"
cost 1;
out:(int)ushort = CIU42(value:(int)reg)
emit "mr %out, %value ! CIU42(reg) -> ushort"
with %out == %value
emit "! CIU42(reg) -> ushort"
cost 1;
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;
/* Conversions from ubyte and ushort */
out:(int)reg = CIU14(in:(int)ubyte)
emit "mr %out, %in ! CIU14"
with %out == %in
emit "! CIU14"
cost 4;

View file

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

View file

@ -1096,6 +1096,36 @@ static void emit_input_regs(Tree node, int* 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 */
static void emitinsndata(Rule rules)
{
@ -1130,6 +1160,8 @@ static void emitinsndata(Rule rules)
emit_input_regs(r->pattern, &index);
}
emit_output_constraints(r);
while (f)
{
switch (f->data[0])

View file

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

View file

@ -46,6 +46,7 @@ struct burm_emitter_data
void (*emit_eoi)(void);
void (*constrain_input_reg)(int child, 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);