u;
};
+struct constraint
+{
+ uint32_t attrs;
+};
+
struct hop
{
int id;
ARRAYOF(struct insel) insels;
struct vreg* output;
+ PMAPOF(struct vreg, struct constraint) constraints;
+
ARRAYOF(struct vreg) ins;
ARRAYOF(struct vreg) outs;
ARRAYOF(struct vreg) throughs;
hop_add_eoi_insel(current_hop);
}
-static void constrain_input_reg(int child, int attr)
+static struct constraint* get_constraint(struct vreg* vreg)
+{
+ struct constraint* c = pmap_findleft(¤t_hop->constraints, vreg);
+ if (!c)
+ {
+ c = calloc(1, sizeof(*c));
+ pmap_put(¤t_hop->constraints, vreg, c);
+ }
+ return c;
+}
+
+static void constrain_input_reg(int child, uint32_t attr)
{
struct vreg* vreg = find_vreg_of_child(child);
+ struct constraint* c;
if (vreg)
array_appendu(¤t_hop->ins, vreg);
+
+ get_constraint(vreg)->attrs = attr;
}
-static void constrain_output_reg(int attr)
+static void constrain_output_reg(uint32_t attr)
{
struct vreg* vreg = current_hop->output;
array_appendu(¤t_hop->outs, vreg);
vreg->defined = current_hop;
+
+ get_constraint(vreg)->attrs = attr;
}
static const struct burm_emitter_data emitter_data =
}
}
-static struct hreg* allocate_hreg(register_assignment_t* regs, struct vreg* vreg)
+static struct hreg* allocate_hreg(register_assignment_t* regs, struct vreg* vreg, uint32_t attr)
{
int i;
struct hreg* hreg = hregs.item[i];
if (!pmap_findleft(regs, hreg))
{
- pmap_put(regs, hreg, vreg);
- return hreg;
+ if (hreg->attrs & attr)
+ {
+ pmap_put(regs, hreg, vreg);
+ return hreg;
+ }
}
}
for (i=0; i<hop->outs.count; i++)
{
struct vreg* vreg = hop->outs.item[i];
- allocate_hreg(out, vreg);
+ struct constraint* c = pmap_findleft(&hop->constraints, vreg);
+ allocate_hreg(out, vreg, c->attrs);
}
}
struct basicblock* bb = dominance.preorder.item[i];
register_assignment_t* old = bb->regsin;
- tracef('R', "R: allocating block %s\n", bb->name);
+ tracef('R', "R: considering block %s\n", bb->name);
/* Attempt to import any block input registers from a predecessor. At
* least one predecessor should export it; our graph traversal order
/* It's possible for the previous stage to fail because in in has
* clobbered the physical register we were wanting. So we need to
- * allocate a new register for that phi value. */
+ * allocate a new register for that phi value.
+ *
+ * We don't bother allocating anything if the vreg is never used.
+ * */
for (j=0; j<bb->phis.count; j++)
{
struct vreg* vreg = bb->phis.item[j].left;
- if (!pmap_findright(old, vreg))
- allocate_hreg(old, vreg);
+ struct phi* phi = bb->phis.item[j].right;
+ if (!pmap_findright(old, vreg) && (vreg->used.count > 0))
+ {
+ struct hop* used = vreg->used.item[0];
+ struct constraint* c = pmap_findleft(&used->constraints, vreg);
+ struct hreg* hreg = allocate_hreg(old, vreg, c->attrs);
+
+ tracef('R', "R: import fallback hreg %s for phi input %%%d from %s\n",
+ hreg->name, vreg->id, phi->prev->name);
+ }
}
for (j=0; j<bb->hops.count; j++)
{
+ int k;
struct hop* hop = bb->hops.item[j];
register_assignment_t* in = &hop->regsin;
register_assignment_t* out = &hop->regsout;;
+ tracef('R', "R: %d from $%d:", hop->id, hop->ir->id);
+ for (k=0; k<hop->ins.count; k++)
+ tracef('R', " r%%%d", hop->ins.item[k]->id);
+ for (k=0; k<hop->throughs.count; k++)
+ tracef('R', " =%%%d", hop->throughs.item[k]->id);
+ for (k=0; k<hop->outs.count; k++)
+ tracef('R', " w%%%d", hop->outs.item[k]->id);
+ tracef('R', "\n");
+
select_registers(hop, old, in, out);
old = out;
if (ti->attr && ti->attr[0])
{
- nt->attr = smap_get(®isterattrs, ti->attr);
- if (!nt->attr)
+ t->attr = smap_get(®isterattrs, ti->attr);
+ if (!t->attr)
yyerror("'%s' doesn't seem to be a known register attribute", ti->attr);
}
}
Nonterm nt = node->op;
if ((nt->kind == NONTERM) && !nt->is_fragment && !node->left && !node->right)
{
- uint32_t attr = 0;
- if (nt->attr->number)
- attr = 1<<nt->attr->number;
- print("%1data->constrain_input_reg(%d, 0x%x);\n", *index, attr);
+ if (node->attr)
+ {
+ uint32_t attr = 1<<node->attr->number;
+ print("%1data->constrain_input_reg(%d, 0x%x /* %s */);\n",
+ *index, attr, node->attr->name);
+ }
}
if (!node->left && !node->right)
print("static void %Pemitter_%d(const struct %Pemitter_data* data) {\n", r->ern);
if (r->attr)
- print("%1data->constrain_output_reg(0x%x);\n", 1<<r->attr->number);
+ print("%1data->constrain_output_reg(0x%x /* %s */);\n",
+ 1<<r->attr->number, r->attr->name);
{
int index = 0;
Rule chain; /* chain rules w/non-terminal on rhs */
Nonterm link; /* next terminal in number order */
bool is_fragment; /* these instructions are all fragments */
- struct regattr* attr; /* input register attribute */
};
extern void* lookup(const char* name);
extern Nonterm nonterm(const char* id, bool allocate);
const char* label; /* user label for this node */
Tree left, right; /* operands */
int nterms; /* number of terminal nodes in this tree */
+ struct regattr* attr; /* input register attribute */
};
extern Tree tree(const struct terminfo* ti, Tree left, Tree right);
S OR
S EOR
S NOT
+S ASL
+S ASR
+S LSL
+S LSR
# Conversions
S CII1
void (*emit_reg)(int child);
void (*emit_value)(int child);
void (*emit_eoi)(void);
- void (*constrain_input_reg)(int child, int attr);
- void (*constrain_output_reg)(int attr);
+ void (*constrain_input_reg)(int child, uint32_t attr);
+ void (*constrain_output_reg)(uint32_t attr);
};
typedef void burm_emitter_t(const struct burm_emitter_data* data);