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