Output register equality constraints work.
This commit is contained in:
parent
216ff5cc43
commit
98fe70a7de
|
@ -26,6 +26,7 @@ struct insel
|
|||
struct constraint
|
||||
{
|
||||
uint32_t attrs;
|
||||
struct vreg* equals_to;
|
||||
};
|
||||
|
||||
struct hop
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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(¤t_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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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])
|
||||
|
|
|
@ -19,9 +19,7 @@ typedef struct term* Term;
|
|||
|
||||
enum
|
||||
{
|
||||
CONSTRAINT_ATTR,
|
||||
CONSTRAINT_EQUALS,
|
||||
CONSTRAINT_NOTEQUALS
|
||||
};
|
||||
|
||||
struct constraint
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue