struct constraint
{
uint32_t attrs;
+ struct vreg* equals_to;
};
struct hop
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,
&emit_value,
&emit_eoi,
&constrain_input_reg,
- &constrain_output_reg
+ &constrain_output_reg,
+ &constrain_output_reg_equal_to,
};
static void emit(struct insn* insn)
{
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?
+ * */
- hreg = NULL;
- for (i=0; i<hregs.count; i++)
+ c = pmap_findleft(¤t_hop->constraints, vreg);
+ if (c->equals_to)
{
- hreg = hregs.item[i];
- if (allocatable(hreg, vreg) &&
- !pmap_findleft(current_outs, hreg))
+ /* 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))
{
- 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. */
+
+ hreg = NULL;
+ for (i=0; i<hregs.count; i++)
+ {
+ hreg = hregs.item[i];
+ if (allocatable(hreg, vreg) &&
+ !pmap_findleft(current_outs, hreg))
+ {
+ goto found2;
+ }
+ }
- /* If we couldn't find one, evict a register. */
+ /* If we couldn't find one, evict a register. */
- hreg = evict(vreg);
+ hreg = evict(vreg);
-found:
- 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)
/* 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;
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
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)
{
int index = 0;
emit_input_regs(r->pattern, &index);
}
-
+
+ emit_output_constraints(r);
+
while (f)
{
switch (f->data[0])
enum
{
- CONSTRAINT_ATTR,
CONSTRAINT_EQUALS,
- CONSTRAINT_NOTEQUALS
};
struct constraint
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);