7 E_MEMSP = 1<<4, /* uses offset and size */
8 E_MEMSB = 1<<5, /* uses offset and size */
9 ANYMEM = E_MEM|E_MEMSP|E_MEMSB,
10 DELAY = BRANCH|LOAD|FCMP,
13 typedef struct Sch Sch;
14 typedef struct Dep Dep;
33 void regused(Sch*, Prog*);
34 int depend(Sch*, Sch*);
35 int conflict(Sch*, Sch*);
36 int offoverlap(Sch*, Sch*);
37 void dumpbits(Sch*, Dep*);
40 sched(Prog *p0, Prog *pe)
43 Sch sch[NSCHED], *s, *t, *u, *se, stmp;
46 * build side structure
49 for(p=p0;; p=p->link) {
50 memset(s, 0, sizeof(*s));
54 Bprint(&bso, "%P\t\tset", &s->p);
56 Bprint(&bso, "; used");
57 dumpbits(s, &s->used);
59 Bprint(&bso, "; compound");
61 Bprint(&bso, "; load");
62 if(s->p.mark & BRANCH)
63 Bprint(&bso, "; branch");
65 Bprint(&bso, "; fcmp");
75 * prepass to move things around
76 * does nothing, but tries to make
77 * the actual scheduler work better
79 for(s=sch; s<=se; s++) {
80 if(!(s->p.mark & LOAD))
82 /* always good to put nonconflict loads together */
83 for(t=s+1; t<=se; t++) {
84 if(!(t->p.mark & LOAD))
86 if(t->p.mark & BRANCH)
95 memmove(s+2, u, (uchar*)t - (uchar*)u);
101 /* put schedule fodder above load */
102 for(t=s+1; t<=se; t++) {
103 if(t->p.mark & BRANCH)
105 if(s > sch && conflict(s-1, t))
107 for(u=t-1; u>=s; u--)
111 memmove(s+1, s, (uchar*)t - (uchar*)s);
113 if(!(s->p.mark & LOAD))
119 for(s=se; s>=sch; s--) {
120 if(!(s->p.mark & DELAY))
123 if(!conflict(s, s+1))
126 * s is load, s+1 is immediate use of result or end of block
127 * t is the trial instruction to insert between s and s+1
130 for(t=s-1; t>=sch; t--) {
132 if(s->p.mark & BRANCH)
134 if(t->p.mark & DELAY)
135 if(s >= se || conflict(t, s+1))
137 for(u=t+1; u<=s; u++)
144 Bprint(&bso, "?l%P\n", &s->p);
147 if(s->p.mark & LOAD) {
151 if(s->p.mark & BRANCH) {
155 if(s->p.mark & FCMP) {
164 Bprint(&bso, "!l%P\n", &t->p);
165 Bprint(&bso, "%P\n", &s->p);
168 memmove(t, t+1, (uchar*)s - (uchar*)t);
176 if(s->p.mark & BRANCH)
183 /* Avoid HI/LO use->set */
185 for(s=sch; s<se-1; s++, t++) {
186 if((s->used.cc & E_PSR) == 0)
188 if(t->set.cc & E_PSR)
195 for(s=sch, p=p0; s<=se; s++, p=q) {
211 regused(Sch *s, Prog *realp)
213 int c, ar, ad, ld, sz;
218 s->comp = compound(p);
221 s->set.ireg |= 1<<REGTMP;
222 s->used.ireg |= 1<<REGTMP;
225 ar = 0; /* dest is really reference */
226 ad = 0; /* source/dest is really address */
227 ld = 0; /* opcode is load instruction */
228 sz = 20; /* size of load/store for overlap computation */
231 * flags based on opcode
236 autosize = p->to.offset + 4;
303 if(p->to.type == D_REG || p->to.type == D_FREG)
306 print("botch %P\n", p);
312 * flags based on 'to' field
316 c = aclass(&p->to) + 1;
322 print("unknown class %d %D\n", c, &p->to);
341 s->used.ireg |= 1<<c;
345 s->offset = regoff(&p->to);
360 s->used.ireg |= 1<<REGSP;
364 s->used.ireg |= 1<<REGSB;
368 s->used.ireg |= 1<<p->to.reg;
370 s->set.ireg |= 1<<p->to.reg;
374 s->used.ireg |= 1<<p->to.reg;
375 s->used.ireg |= 1<<p->to.offset;
377 s->set.ireg |= 1<<p->to.reg;
378 s->set.ireg |= 1<<p->to.offset;
382 /* do better -- determine double prec */
384 s->used.freg |= 1<<p->to.reg;
385 s->used.freg |= 1<<(p->to.reg|1);
387 s->set.freg |= 1<<p->to.reg;
388 s->set.freg |= 1<<(p->to.reg|1);
390 if(ld && p->from.type == D_REG)
395 s->used.ireg |= 1<<REGSP;
399 s->offset = regoff(&p->to);
402 s->used.cc |= E_MEMSP;
404 s->set.cc |= E_MEMSP;
408 s->used.ireg |= 1<<REGSB;
412 s->offset = regoff(&p->to);
415 s->used.cc |= E_MEMSB;
417 s->set.cc |= E_MEMSB;
422 * flags based on 'from' field
426 c = aclass(&p->from) + 1;
432 print("unknown class %d %D\n", c, &p->from);
450 s->used.ireg |= 1<<c;
454 s->offset = regoff(&p->from);
466 s->used.ireg |= 1<<REGSP;
470 s->used.ireg |= 1<<REGSB;
473 s->used.ireg |= 1<<p->from.reg;
476 s->used.ireg |= 1<<p->from.reg;
477 s->used.ireg |= 1<<p->from.offset;
480 /* do better -- determine double prec */
481 s->used.freg |= 1<<p->from.reg;
482 s->used.freg |= 1<<(p->from.reg|1);
483 if(ld && p->to.type == D_REG)
488 s->used.ireg |= 1<<REGSP;
494 s->offset = regoff(&p->from);
496 s->used.cc |= E_MEMSP;
500 s->used.ireg |= 1<<REGSB;
506 s->offset = regoff(&p->from);
508 s->used.cc |= E_MEMSB;
514 if(p->from.type == D_FREG || p->to.type == D_FREG) {
515 s->used.freg |= 1<<c;
516 s->used.freg |= 1<<(c|1);
518 s->used.ireg |= 1<<c;
523 * test to see if 2 instrictions can be
524 * interchanged without changing semantics
527 depend(Sch *sa, Sch *sb)
531 if(sa->set.ireg & (sb->set.ireg|sb->used.ireg))
533 if(sb->set.ireg & sa->used.ireg)
536 if(sa->set.freg & (sb->set.freg|sb->used.freg))
538 if(sb->set.freg & sa->used.freg)
543 * loads from same address cannot pass.
544 * this is for hardware fifo's and the like
546 if(sa->used.cc & sb->used.cc & E_MEM)
547 if(sa->p.reg == sb->p.reg)
548 if(regoff(&sa->p.from) == regoff(&sb->p.from))
551 x = (sa->set.cc & (sb->set.cc|sb->used.cc)) |
552 (sb->set.cc & sa->used.cc);
555 * allow SB and SP to pass each other.
556 * allow SB to pass SB iff doffsets are ok
557 * anything else conflicts
559 if(x != E_MEMSP && x != E_MEMSB)
561 x = sa->set.cc | sb->set.cc |
562 sa->used.cc | sb->used.cc;
565 if(offoverlap(sa, sb))
573 offoverlap(Sch *sa, Sch *sb)
576 if(sa->offset < sb->offset) {
577 if(sa->offset+sa->size > sb->offset)
581 if(sb->offset+sb->size > sa->offset)
587 * test 2 adjacent instructions
588 * and find out if inserted instructions
589 * are desired to prevent stalls.
592 conflict(Sch *sa, Sch *sb)
595 if(sa->set.ireg & sb->used.ireg)
597 if(sa->set.freg & sb->used.freg)
599 if(sa->set.cc & sb->used.cc)
613 if(p->to.type == D_REG && p->to.reg == REGSB)
619 dumpbits(Sch *s, Dep *d)
625 Bprint(&bso, " R%d", i);
628 Bprint(&bso, " F%d", i);
630 switch(d->cc & (1<<i)) {
634 Bprint(&bso, " PSR");
637 Bprint(&bso, " MEM%d", s->size);
640 Bprint(&bso, " SB%d", s->size);
643 Bprint(&bso, " SP%d", s->size);