sched.c 10 KB

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