mirror of
git://projects.qi-hardware.com/wernermisc.git
synced 2024-11-15 11:10:37 +02:00
m1/perf/sched.c: revamped to handle static registers correctly as well
This commit is contained in:
parent
05bbe9103b
commit
8f82a0e8d4
116
m1/perf/sched.c
116
m1/perf/sched.c
@ -62,10 +62,12 @@ struct insn {
|
|||||||
} opa, opb, dest, cond;
|
} opa, opb, dest, cond;
|
||||||
int arity;
|
int arity;
|
||||||
int latency;
|
int latency;
|
||||||
|
int rmw; /* non-zero if instruction is read-modify-write */
|
||||||
int unresolved; /* number of data refs we need before we can sched */
|
int unresolved; /* number of data refs we need before we can sched */
|
||||||
int earliest; /* earliest cycle dependencies seen so far are met */
|
int earliest; /* earliest cycle dependencies seen so far are met */
|
||||||
struct list dependants; /* list of dependencies (constant) */
|
struct list dependants; /* list of dependencies (constant) */
|
||||||
int num_dependants; /* number of dependencies */
|
int num_dependants; /* number of dependencies */
|
||||||
|
struct insn *next_setter; /* next setter of the same register */
|
||||||
#ifdef LCPF
|
#ifdef LCPF
|
||||||
int distance; /* minimum cycles on this path until the end */
|
int distance; /* minimum cycles on this path until the end */
|
||||||
#endif
|
#endif
|
||||||
@ -74,6 +76,7 @@ struct insn {
|
|||||||
|
|
||||||
struct vm_reg {
|
struct vm_reg {
|
||||||
struct insn *setter; /* instruction setting it; NULL if none */
|
struct insn *setter; /* instruction setting it; NULL if none */
|
||||||
|
struct insn *first_setter; /* first setter */
|
||||||
int pfpu_reg; /* underlying PFPU register */
|
int pfpu_reg; /* underlying PFPU register */
|
||||||
int refs; /* usage count */
|
int refs; /* usage count */
|
||||||
};
|
};
|
||||||
@ -95,6 +98,7 @@ static struct sched_ctx {
|
|||||||
struct list unscheduled; /* unscheduled insns */
|
struct list unscheduled; /* unscheduled insns */
|
||||||
struct list waiting; /* insns waiting to be scheduled */
|
struct list waiting; /* insns waiting to be scheduled */
|
||||||
struct list ready[PFPU_PROGSIZE]; /* insns ready at nth cycle */
|
struct list ready[PFPU_PROGSIZE]; /* insns ready at nth cycle */
|
||||||
|
int cycle; /* the current cycle */
|
||||||
#ifdef REG_STATS
|
#ifdef REG_STATS
|
||||||
int max_regs, curr_regs; /* allocation statistics */
|
int max_regs, curr_regs; /* allocation statistics */
|
||||||
#endif
|
#endif
|
||||||
@ -233,20 +237,23 @@ static int alloc_reg(struct insn *setter)
|
|||||||
int vm_reg, pfpu_reg, vm_idx;
|
int vm_reg, pfpu_reg, vm_idx;
|
||||||
|
|
||||||
vm_reg = setter->vm_insn->dest;
|
vm_reg = setter->vm_insn->dest;
|
||||||
if (vm_reg >= 0)
|
if (vm_reg >= 0) {
|
||||||
return vm_reg;
|
pfpu_reg = vm_reg;
|
||||||
reg = list_pop(&sc->unallocated);
|
sc->pfpu_regs[vm_reg].vm_reg = vm_reg; /* @@@ global init */
|
||||||
if (!reg)
|
} else {
|
||||||
abort();
|
reg = list_pop(&sc->unallocated);
|
||||||
|
if (!reg)
|
||||||
|
abort();
|
||||||
|
|
||||||
#ifdef REG_STATS
|
#ifdef REG_STATS
|
||||||
sc->curr_regs++;
|
sc->curr_regs++;
|
||||||
if (sc->curr_regs > sc->max_regs)
|
if (sc->curr_regs > sc->max_regs)
|
||||||
sc->max_regs = sc->curr_regs;
|
sc->max_regs = sc->curr_regs;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
reg->vm_reg = vm_reg;
|
reg->vm_reg = vm_reg;
|
||||||
pfpu_reg = reg-sc->pfpu_regs;
|
pfpu_reg = reg-sc->pfpu_regs;
|
||||||
|
}
|
||||||
|
|
||||||
Dprintf(" alloc reg %d -> %d\n", vm_reg, pfpu_reg);
|
Dprintf(" alloc reg %d -> %d\n", vm_reg, pfpu_reg);
|
||||||
|
|
||||||
@ -291,10 +298,20 @@ static void put_reg(int vm_reg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void put_reg_by_setter(struct insn *setter)
|
static void unblock(struct insn *insn);
|
||||||
|
static void put_reg_by_setter(struct insn *setter, int vm_reg)
|
||||||
{
|
{
|
||||||
if (setter)
|
struct vm_reg *reg;
|
||||||
|
|
||||||
|
if (setter) {
|
||||||
put_reg(setter->vm_insn->dest);
|
put_reg(setter->vm_insn->dest);
|
||||||
|
if (setter->next_setter)
|
||||||
|
unblock(setter->next_setter);
|
||||||
|
} else {
|
||||||
|
reg = sc->regs+vm_reg2idx(vm_reg);
|
||||||
|
if (reg->first_setter && !reg->first_setter->rmw)
|
||||||
|
unblock(reg->first_setter);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -347,7 +364,11 @@ static struct vm_reg *add_data_ref(struct insn *insn, struct data_ref *ref,
|
|||||||
reg = sc->regs+vm_reg2idx(reg_num);
|
reg = sc->regs+vm_reg2idx(reg_num);
|
||||||
ref->insn = insn;
|
ref->insn = insn;
|
||||||
ref->dep = reg->setter;
|
ref->dep = reg->setter;
|
||||||
if (ref->dep) {
|
if (insn->vm_insn->dest == reg_num)
|
||||||
|
insn->rmw = 1;
|
||||||
|
if (!ref->dep)
|
||||||
|
reg->refs++;
|
||||||
|
else {
|
||||||
list_add_tail(&ref->dep->dependants, &ref->more);
|
list_add_tail(&ref->dep->dependants, &ref->more);
|
||||||
ref->dep->num_dependants++;
|
ref->dep->num_dependants++;
|
||||||
insn->unresolved++;
|
insn->unresolved++;
|
||||||
@ -364,6 +385,8 @@ static void init_scheduler(struct fpvm_fragment *frag)
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct insn *insn;
|
struct insn *insn;
|
||||||
|
struct vm_reg *reg;
|
||||||
|
struct data_ref *ref;
|
||||||
|
|
||||||
list_init(&sc->unscheduled);
|
list_init(&sc->unscheduled);
|
||||||
list_init(&sc->waiting);
|
list_init(&sc->waiting);
|
||||||
@ -387,8 +410,20 @@ static void init_scheduler(struct fpvm_fragment *frag)
|
|||||||
add_data_ref(insn, &insn->opa, frag->code[i].opa);
|
add_data_ref(insn, &insn->opa, frag->code[i].opa);
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case 0:
|
case 0:
|
||||||
add_data_ref(insn,
|
reg = sc->regs+vm_reg2idx(frag->code[i].dest);
|
||||||
&insn->dest, frag->code[i].dest)->setter = insn;
|
if (reg->setter) {
|
||||||
|
reg->setter->next_setter = insn;
|
||||||
|
foreach (ref, ®->setter->dependants)
|
||||||
|
if (ref->insn != insn)
|
||||||
|
insn->unresolved++;
|
||||||
|
if (!insn->rmw)
|
||||||
|
insn->unresolved++;
|
||||||
|
} else {
|
||||||
|
if (!insn->rmw)
|
||||||
|
insn->unresolved += reg->refs;
|
||||||
|
reg->first_setter = insn;
|
||||||
|
}
|
||||||
|
reg->setter = insn;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
abort();
|
abort();
|
||||||
@ -413,6 +448,30 @@ static void init_scheduler(struct fpvm_fragment *frag)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void unblock(struct insn *insn)
|
||||||
|
{
|
||||||
|
int slot;
|
||||||
|
|
||||||
|
assert(insn->unresolved);
|
||||||
|
if (--insn->unresolved)
|
||||||
|
return;
|
||||||
|
Dprintf(" unblocked %lu -> %u\n", insn-sc->insns, insn->earliest);
|
||||||
|
list_del(&insn->more);
|
||||||
|
slot = insn->earliest;
|
||||||
|
if (slot <= sc->cycle)
|
||||||
|
slot = sc->cycle+1;
|
||||||
|
list_add_tail(sc->ready+slot, &insn->more);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void unblock_after(struct insn *insn, int cycle)
|
||||||
|
{
|
||||||
|
if (insn->earliest <= cycle)
|
||||||
|
insn->earliest = cycle+1;
|
||||||
|
unblock(insn);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void issue(struct insn *insn, int cycle, unsigned *code)
|
static void issue(struct insn *insn, int cycle, unsigned *code)
|
||||||
{
|
{
|
||||||
struct data_ref *ref;
|
struct data_ref *ref;
|
||||||
@ -425,14 +484,15 @@ static void issue(struct insn *insn, int cycle, unsigned *code)
|
|||||||
|
|
||||||
switch (insn->arity) {
|
switch (insn->arity) {
|
||||||
case 3:
|
case 3:
|
||||||
|
put_reg_by_setter(insn->cond.dep, FPVM_REG_IFB);
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case 2:
|
case 2:
|
||||||
CODE(cycle).opb = lookup_pfpu_reg(insn->vm_insn->opb);
|
CODE(cycle).opb = lookup_pfpu_reg(insn->vm_insn->opb);
|
||||||
put_reg_by_setter(insn->opb.dep);
|
put_reg_by_setter(insn->opb.dep, insn->vm_insn->opb);
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case 1:
|
case 1:
|
||||||
CODE(cycle).opa = lookup_pfpu_reg(insn->vm_insn->opa);
|
CODE(cycle).opa = lookup_pfpu_reg(insn->vm_insn->opa);
|
||||||
put_reg_by_setter(insn->opa.dep);
|
put_reg_by_setter(insn->opa.dep, insn->vm_insn->opa);
|
||||||
break;
|
break;
|
||||||
case 0:
|
case 0:
|
||||||
break;
|
break;
|
||||||
@ -443,18 +503,11 @@ static void issue(struct insn *insn, int cycle, unsigned *code)
|
|||||||
CODE(end).dest = alloc_reg(insn);
|
CODE(end).dest = alloc_reg(insn);
|
||||||
CODE(cycle).opcode = fpvm_to_pfpu(insn->vm_insn->opcode);
|
CODE(cycle).opcode = fpvm_to_pfpu(insn->vm_insn->opcode);
|
||||||
|
|
||||||
foreach (ref, &insn->dependants) {
|
foreach (ref, &insn->dependants)
|
||||||
if (ref->insn->earliest <= end)
|
unblock_after(ref->insn, end);
|
||||||
ref->insn->earliest = end+1;
|
if (insn->next_setter && !insn->next_setter->rmw)
|
||||||
assert(ref->insn->unresolved);
|
unblock_after(insn->next_setter,
|
||||||
if (!--ref->insn->unresolved) {
|
end-insn->next_setter->latency);
|
||||||
Dprintf(" unlocked %lu -> %u\n", ref->insn-sc->insns,
|
|
||||||
ref->insn->earliest);
|
|
||||||
list_del(&ref->insn->more);
|
|
||||||
list_add_tail(sc->ready+ref->insn->earliest,
|
|
||||||
&ref->insn->more);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -485,6 +538,7 @@ static int schedule(unsigned int *code)
|
|||||||
if (i == PFPU_PROGSIZE)
|
if (i == PFPU_PROGSIZE)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
sc->cycle = i;
|
||||||
Dprintf("@%d --- remaining %d, waiting %d + ready %d\n",
|
Dprintf("@%d --- remaining %d, waiting %d + ready %d\n",
|
||||||
i, remaining, count(&sc->waiting), count(&sc->ready[i]));
|
i, remaining, count(&sc->waiting), count(&sc->ready[i]));
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user