sched.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include "l.h"
  10. enum
  11. {
  12. E_HILO = 1<<0,
  13. E_FCR = 1<<1,
  14. E_MCR = 1<<2,
  15. E_MEM = 1<<3,
  16. E_MEMSP = 1<<4, /* uses offset and size */
  17. E_MEMSB = 1<<5, /* uses offset and size */
  18. ANYMEM = E_MEM|E_MEMSP|E_MEMSB,
  19. DELAY = BRANCH|LOAD|FCMP,
  20. };
  21. typedef struct Sch Sch;
  22. typedef struct Dep Dep;
  23. struct Dep
  24. {
  25. uint32_t ireg;
  26. uint32_t freg;
  27. uint32_t cc;
  28. };
  29. struct Sch
  30. {
  31. Prog p;
  32. Dep set;
  33. Dep used;
  34. int32_t soffset;
  35. char size;
  36. char nop;
  37. char comp;
  38. };
  39. void regsused(Sch*, Prog*);
  40. int depend(Sch*, Sch*);
  41. int conflict(Sch*, Sch*);
  42. int offoverlap(Sch*, Sch*);
  43. void dumpbits(Sch*, Dep*);
  44. void
  45. sched(Prog *p0, Prog *pe)
  46. {
  47. Prog *p, *q;
  48. Sch sch[NSCHED], *s, *t, *u, *se, stmp;
  49. /*
  50. * build side structure
  51. */
  52. s = sch;
  53. for(p=p0;; p=p->link) {
  54. memset(s, 0, sizeof(*s));
  55. s->p = *p;
  56. regsused(s, p);
  57. if(debug['X']) {
  58. Bprint(&bso, "%P\t\tset", &s->p);
  59. dumpbits(s, &s->set);
  60. Bprint(&bso, "; used");
  61. dumpbits(s, &s->used);
  62. if(s->comp)
  63. Bprint(&bso, "; compound");
  64. if(s->p.mark & LOAD)
  65. Bprint(&bso, "; load");
  66. if(s->p.mark & BRANCH)
  67. Bprint(&bso, "; branch");
  68. if(s->p.mark & FCMP)
  69. Bprint(&bso, "; fcmp");
  70. Bprint(&bso, "\n");
  71. }
  72. if(p == pe)
  73. break;
  74. s++;
  75. }
  76. se = s;
  77. /*
  78. * prepass to move things around
  79. * does nothing, but tries to make
  80. * the actual scheduler work better
  81. */
  82. for(s=sch; s<=se; s++) {
  83. if(!(s->p.mark & LOAD))
  84. continue;
  85. /* always good to put nonconflict loads together */
  86. for(t=s+1; t<=se; t++) {
  87. if(!(t->p.mark & LOAD))
  88. continue;
  89. if(t->p.mark & BRANCH)
  90. break;
  91. if(conflict(s, t))
  92. break;
  93. for(u=t-1; u>s; u--)
  94. if(depend(u, t))
  95. goto no11;
  96. u = s+1;
  97. stmp = *t;
  98. memmove(s+2, u, (uint8_t*)t - (uint8_t*)u);
  99. *u = stmp;
  100. break;
  101. }
  102. no11:
  103. /* put schedule fodder above load */
  104. for(t=s+1; t<=se; t++) {
  105. if(t->p.mark & BRANCH)
  106. break;
  107. if(s > sch && conflict(s-1, t))
  108. continue;
  109. for(u=t-1; u>=s; u--)
  110. if(depend(t, u))
  111. goto no1;
  112. stmp = *t;
  113. memmove(s+1, s, (uint8_t*)t - (uint8_t*)s);
  114. *s = stmp;
  115. if(!(s->p.mark & LOAD))
  116. break;
  117. no1:;
  118. }
  119. }
  120. for(s=se; s>=sch; s--) {
  121. if(!(s->p.mark & DELAY))
  122. continue;
  123. if(s < se)
  124. if(!conflict(s, s+1))
  125. goto out3;
  126. /*
  127. * s is load, s+1 is immediate use of result or end of block
  128. * t is the trial instruction to insert between s and s+1
  129. */
  130. if(!debug['Y'])
  131. for(t=s-1; t>=sch; t--) {
  132. if(t->comp)
  133. if(s->p.mark & BRANCH)
  134. goto no2;
  135. if(t->p.mark & DELAY)
  136. if(s >= se || conflict(t, s+1))
  137. goto no2;
  138. for(u=t+1; u<=s; u++)
  139. if(depend(u, t))
  140. goto no2;
  141. goto out2;
  142. no2:;
  143. }
  144. if(debug['X'])
  145. Bprint(&bso, "?l%P\n", &s->p);
  146. s->nop = 1;
  147. if(debug['v']) {
  148. if(s->p.mark & LOAD) {
  149. nop.load.count++;
  150. nop.load.outof++;
  151. }
  152. if(s->p.mark & BRANCH) {
  153. nop.branch.count++;
  154. nop.branch.outof++;
  155. }
  156. if(s->p.mark & FCMP) {
  157. nop.fcmp.count++;
  158. nop.fcmp.outof++;
  159. }
  160. }
  161. continue;
  162. out2:
  163. if(debug['X']) {
  164. Bprint(&bso, "!l%P\n", &t->p);
  165. Bprint(&bso, "%P\n", &s->p);
  166. }
  167. stmp = *t;
  168. memmove(t, t+1, (uint8_t*)s - (uint8_t*)t);
  169. *s = stmp;
  170. s--;
  171. out3:
  172. if(debug['v']) {
  173. if(s->p.mark & LOAD)
  174. nop.load.outof++;
  175. if(s->p.mark & BRANCH)
  176. nop.branch.outof++;
  177. if(s->p.mark & FCMP)
  178. nop.fcmp.outof++;
  179. }
  180. }
  181. /* Avoid HI/LO use->set */
  182. t = sch+1;
  183. for(s=sch; s<se-1; s++, t++) {
  184. if((s->used.cc & E_HILO) == 0)
  185. continue;
  186. if(t->set.cc & E_HILO)
  187. s->nop = 2;
  188. }
  189. /*
  190. * put it all back
  191. */
  192. for(s=sch, p=p0; s<=se; s++, p=q) {
  193. q = p->link;
  194. if(q != s->p.link) {
  195. *p = s->p;
  196. p->link = q;
  197. }
  198. while(s->nop--)
  199. addnop(p);
  200. }
  201. if(debug['X']) {
  202. Bprint(&bso, "\n");
  203. Bflush(&bso);
  204. }
  205. }
  206. void
  207. regsused(Sch *s, Prog *realp)
  208. {
  209. int c, ar, ad, ld, sz;
  210. uint32_t m;
  211. Prog *p;
  212. p = &s->p;
  213. s->comp = compound(p);
  214. s->nop = 0;
  215. if(s->comp) {
  216. s->set.ireg |= 1<<REGTMP;
  217. s->used.ireg |= 1<<REGTMP;
  218. }
  219. ar = 0; /* dest is really reference */
  220. ad = 0; /* source/dest is really address */
  221. ld = 0; /* opcode is load instruction */
  222. sz = 20; /* size of load/store for overlap computation */
  223. /*
  224. * flags based on opcode
  225. */
  226. switch(p->as) {
  227. case ATEXT:
  228. curtext = realp;
  229. autosize = p->to.offset + 4;
  230. ad = 1;
  231. break;
  232. case AJAL:
  233. c = p->reg;
  234. if(c == NREG)
  235. c = REGLINK;
  236. s->set.ireg |= 1<<c;
  237. ar = 1;
  238. ad = 1;
  239. break;
  240. case ABGEZAL:
  241. case ABLTZAL:
  242. s->set.ireg |= 1<<REGLINK;
  243. case ABEQ:
  244. case ABGEZ:
  245. case ABGTZ:
  246. case ABLEZ:
  247. case ABLTZ:
  248. case ABNE:
  249. ar = 1;
  250. ad = 1;
  251. break;
  252. case ABFPT:
  253. case ABFPF:
  254. ad = 1;
  255. s->used.cc |= E_FCR;
  256. break;
  257. case ACMPEQD:
  258. case ACMPEQF:
  259. case ACMPGED:
  260. case ACMPGEF:
  261. case ACMPGTD:
  262. case ACMPGTF:
  263. ar = 1;
  264. s->set.cc |= E_FCR;
  265. p->mark |= FCMP;
  266. break;
  267. case AJMP:
  268. ar = 1;
  269. ad = 1;
  270. break;
  271. case AMOVB:
  272. case AMOVBU:
  273. sz = 1;
  274. ld = 1;
  275. break;
  276. case AMOVH:
  277. case AMOVHU:
  278. sz = 2;
  279. ld = 1;
  280. break;
  281. case AMOVF:
  282. case AMOVW:
  283. case AMOVWL:
  284. case AMOVWR:
  285. sz = 4;
  286. ld = 1;
  287. break;
  288. case AMOVD:
  289. case AMOVV:
  290. case AMOVVL:
  291. case AMOVVR:
  292. sz = 8;
  293. ld = 1;
  294. break;
  295. case ADIV:
  296. case ADIVU:
  297. case AMUL:
  298. case AMULU:
  299. case AREM:
  300. case AREMU:
  301. s->set.cc = E_HILO;
  302. case AADD:
  303. case AADDU:
  304. case AAND:
  305. case ANOR:
  306. case AOR:
  307. case ASGT:
  308. case ASGTU:
  309. case ASLL:
  310. case ASRA:
  311. case ASRL:
  312. case ASUB:
  313. case ASUBU:
  314. case AXOR:
  315. case AADDD:
  316. case AADDF:
  317. case AADDW:
  318. case ASUBD:
  319. case ASUBF:
  320. case ASUBW:
  321. case AMULF:
  322. case AMULD:
  323. case AMULW:
  324. case ADIVF:
  325. case ADIVD:
  326. case ADIVW:
  327. if(p->reg == NREG) {
  328. if(p->to.type == D_REG || p->to.type == D_FREG)
  329. p->reg = p->to.reg;
  330. if(p->reg == NREG)
  331. print("botch %P\n", p);
  332. }
  333. break;
  334. }
  335. /*
  336. * flags based on 'to' field
  337. */
  338. c = p->to.class;
  339. if(c == 0) {
  340. c = aclass(&p->to) + 1;
  341. p->to.class = c;
  342. }
  343. c--;
  344. switch(c) {
  345. default:
  346. print("unknown class %d %D\n", c, &p->to);
  347. case C_ZCON:
  348. case C_SCON:
  349. case C_ADD0CON:
  350. case C_AND0CON:
  351. case C_ADDCON:
  352. case C_ANDCON:
  353. case C_UCON:
  354. case C_LCON:
  355. case C_NONE:
  356. case C_SBRA:
  357. case C_LBRA:
  358. break;
  359. case C_HI:
  360. case C_LO:
  361. s->set.cc |= E_HILO;
  362. break;
  363. case C_FCREG:
  364. s->set.cc |= E_FCR;
  365. break;
  366. case C_MREG:
  367. s->set.cc |= E_MCR;
  368. break;
  369. case C_ZOREG:
  370. case C_SOREG:
  371. case C_LOREG:
  372. c = p->to.reg;
  373. s->used.ireg |= 1<<c;
  374. if(ad)
  375. break;
  376. s->size = sz;
  377. s->soffset = regoff(&p->to);
  378. m = ANYMEM;
  379. if(c == REGSB)
  380. m = E_MEMSB;
  381. if(c == REGSP)
  382. m = E_MEMSP;
  383. if(ar)
  384. s->used.cc |= m;
  385. else
  386. s->set.cc |= m;
  387. break;
  388. case C_SACON:
  389. case C_LACON:
  390. s->used.ireg |= 1<<REGSP;
  391. break;
  392. case C_SECON:
  393. case C_LECON:
  394. s->used.ireg |= 1<<REGSB;
  395. break;
  396. case C_REG:
  397. if(ar)
  398. s->used.ireg |= 1<<p->to.reg;
  399. else
  400. s->set.ireg |= 1<<p->to.reg;
  401. break;
  402. case C_FREG:
  403. /* do better -- determine double prec */
  404. if(ar) {
  405. s->used.freg |= 1<<p->to.reg;
  406. s->used.freg |= 1<<(p->to.reg|1);
  407. } else {
  408. s->set.freg |= 1<<p->to.reg;
  409. s->set.freg |= 1<<(p->to.reg|1);
  410. }
  411. if(ld && p->from.type == D_REG)
  412. p->mark |= LOAD;
  413. break;
  414. case C_SAUTO:
  415. case C_LAUTO:
  416. s->used.ireg |= 1<<REGSP;
  417. if(ad)
  418. break;
  419. s->size = sz;
  420. s->soffset = regoff(&p->to);
  421. if(ar)
  422. s->used.cc |= E_MEMSP;
  423. else
  424. s->set.cc |= E_MEMSP;
  425. break;
  426. case C_SEXT:
  427. case C_LEXT:
  428. s->used.ireg |= 1<<REGSB;
  429. if(ad)
  430. break;
  431. s->size = sz;
  432. s->soffset = regoff(&p->to);
  433. if(ar)
  434. s->used.cc |= E_MEMSB;
  435. else
  436. s->set.cc |= E_MEMSB;
  437. break;
  438. }
  439. /*
  440. * flags based on 'from' field
  441. */
  442. c = p->from.class;
  443. if(c == 0) {
  444. c = aclass(&p->from) + 1;
  445. p->from.class = c;
  446. }
  447. c--;
  448. switch(c) {
  449. default:
  450. print("unknown class %d %D\n", c, &p->from);
  451. case C_ZCON:
  452. case C_SCON:
  453. case C_ADD0CON:
  454. case C_AND0CON:
  455. case C_ADDCON:
  456. case C_ANDCON:
  457. case C_UCON:
  458. case C_LCON:
  459. case C_NONE:
  460. case C_SBRA:
  461. case C_LBRA:
  462. break;
  463. case C_HI:
  464. case C_LO:
  465. s->used.cc |= E_HILO;
  466. break;
  467. case C_FCREG:
  468. s->used.cc |= E_FCR;
  469. break;
  470. case C_MREG:
  471. s->used.cc |= E_MCR;
  472. break;
  473. case C_ZOREG:
  474. case C_SOREG:
  475. case C_LOREG:
  476. c = p->from.reg;
  477. s->used.ireg |= 1<<c;
  478. if(ld)
  479. p->mark |= LOAD;
  480. s->size = sz;
  481. s->soffset = regoff(&p->from);
  482. m = ANYMEM;
  483. if(c == REGSB)
  484. m = E_MEMSB;
  485. if(c == REGSP)
  486. m = E_MEMSP;
  487. s->used.cc |= m;
  488. break;
  489. case C_SACON:
  490. case C_LACON:
  491. s->used.ireg |= 1<<REGSP;
  492. break;
  493. case C_SECON:
  494. case C_LECON:
  495. s->used.ireg |= 1<<REGSB;
  496. break;
  497. case C_REG:
  498. s->used.ireg |= 1<<p->from.reg;
  499. break;
  500. case C_FREG:
  501. /* do better -- determine double prec */
  502. s->used.freg |= 1<<p->from.reg;
  503. s->used.freg |= 1<<(p->from.reg|1);
  504. if(ld && p->to.type == D_REG)
  505. p->mark |= LOAD;
  506. break;
  507. case C_SAUTO:
  508. case C_LAUTO:
  509. s->used.ireg |= 1<<REGSP;
  510. if(ld)
  511. p->mark |= LOAD;
  512. if(ad)
  513. break;
  514. s->size = sz;
  515. s->soffset = regoff(&p->from);
  516. s->used.cc |= E_MEMSP;
  517. break;
  518. case C_SEXT:
  519. case C_LEXT:
  520. s->used.ireg |= 1<<REGSB;
  521. if(ld)
  522. p->mark |= LOAD;
  523. if(ad)
  524. break;
  525. s->size = sz;
  526. s->soffset = regoff(&p->from);
  527. s->used.cc |= E_MEMSB;
  528. break;
  529. }
  530. c = p->reg;
  531. if(c != NREG) {
  532. if(p->from.type == D_FREG || p->to.type == D_FREG) {
  533. s->used.freg |= 1<<c;
  534. s->used.freg |= 1<<(c|1);
  535. } else
  536. s->used.ireg |= 1<<c;
  537. }
  538. s->set.ireg &= ~(1<<REGZERO); /* R0 cant be set */
  539. }
  540. /*
  541. * test to see if 2 instrictions can be
  542. * interchanged without changing semantics
  543. */
  544. int
  545. depend(Sch *sa, Sch *sb)
  546. {
  547. uint32_t x;
  548. if(sa->set.ireg & (sb->set.ireg|sb->used.ireg))
  549. return 1;
  550. if(sb->set.ireg & sa->used.ireg)
  551. return 1;
  552. if(sa->set.freg & (sb->set.freg|sb->used.freg))
  553. return 1;
  554. if(sb->set.freg & sa->used.freg)
  555. return 1;
  556. /*
  557. * special case.
  558. * loads from same address cannot pass.
  559. * this is for hardware fifo's and the like
  560. */
  561. if(sa->used.cc & sb->used.cc & E_MEM)
  562. if(sa->p.reg == sb->p.reg)
  563. if(regoff(&sa->p.from) == regoff(&sb->p.from))
  564. return 1;
  565. x = (sa->set.cc & (sb->set.cc|sb->used.cc)) |
  566. (sb->set.cc & sa->used.cc);
  567. if(x) {
  568. /*
  569. * allow SB and SP to pass each other.
  570. * allow SB to pass SB iff doffsets are ok
  571. * anything else conflicts
  572. */
  573. if(x != E_MEMSP && x != E_MEMSB)
  574. return 1;
  575. x = sa->set.cc | sb->set.cc |
  576. sa->used.cc | sb->used.cc;
  577. if(x & E_MEM)
  578. return 1;
  579. if(offoverlap(sa, sb))
  580. return 1;
  581. }
  582. return 0;
  583. }
  584. int
  585. offoverlap(Sch *sa, Sch *sb)
  586. {
  587. if(sa->soffset < sb->soffset) {
  588. if(sa->soffset+sa->size > sb->soffset)
  589. return 1;
  590. return 0;
  591. }
  592. if(sb->soffset+sb->size > sa->soffset)
  593. return 1;
  594. return 0;
  595. }
  596. /*
  597. * test 2 adjacent instructions
  598. * and find out if inserted instructions
  599. * are desired to prevent stalls.
  600. */
  601. int
  602. conflict(Sch *sa, Sch *sb)
  603. {
  604. if(sa->set.ireg & sb->used.ireg)
  605. return 1;
  606. if(sa->set.freg & sb->used.freg)
  607. return 1;
  608. if(sa->set.cc & sb->used.cc)
  609. return 1;
  610. return 0;
  611. }
  612. int
  613. compound(Prog *p)
  614. {
  615. Optab *o;
  616. o = oplook(p);
  617. if(o->size != 4)
  618. return 1;
  619. if(p->to.type == D_REG && p->to.reg == REGSB)
  620. return 1;
  621. return 0;
  622. }
  623. void
  624. dumpbits(Sch *s, Dep *d)
  625. {
  626. int i;
  627. for(i=0; i<32; i++)
  628. if(d->ireg & (1<<i))
  629. Bprint(&bso, " R%d", i);
  630. for(i=0; i<32; i++)
  631. if(d->freg & (1<<i))
  632. Bprint(&bso, " F%d", i);
  633. for(i=0; i<32; i++)
  634. switch(d->cc & (1<<i)) {
  635. default:
  636. break;
  637. case E_HILO:
  638. Bprint(&bso, " HILO");
  639. break;
  640. case E_FCR:
  641. Bprint(&bso, " FCR");
  642. break;
  643. case E_MCR:
  644. Bprint(&bso, " MCR");
  645. break;
  646. case E_MEM:
  647. Bprint(&bso, " MEM%d", s->size);
  648. break;
  649. case E_MEMSB:
  650. Bprint(&bso, " SB%d", s->size);
  651. break;
  652. case E_MEMSP:
  653. Bprint(&bso, " SP%d", s->size);
  654. break;
  655. }
  656. }