noop.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643
  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. /*
  11. * flag: insert nops to prevent three consecutive stores.
  12. * workaround for 24k erratum #48, costs about 10% in text space,
  13. * so only enable this if you need it. test cases are "hoc -e '7^6'"
  14. * and "{ echo moon; echo plot } | scat".
  15. */
  16. enum {
  17. Mips24k = 0,
  18. };
  19. static int
  20. isdblwrdmov(Prog *p)
  21. {
  22. if(p == nil)
  23. return 0;
  24. switch(p->as){
  25. case AMOVD:
  26. case AMOVDF:
  27. case AMOVDW:
  28. case AMOVFD:
  29. case AMOVWD:
  30. case AMOVV:
  31. case AMOVVL:
  32. case AMOVVR:
  33. case AMOVFV:
  34. case AMOVDV:
  35. case AMOVVF:
  36. case AMOVVD:
  37. return 1;
  38. }
  39. return 0;
  40. }
  41. static int
  42. ismove(Prog *p)
  43. {
  44. if(p == nil)
  45. return 0;
  46. switch(p->as){
  47. case AMOVB:
  48. case AMOVBU:
  49. case AMOVF:
  50. case AMOVFW:
  51. case AMOVH:
  52. case AMOVHU:
  53. case AMOVW:
  54. case AMOVWF:
  55. case AMOVWL:
  56. case AMOVWR:
  57. case AMOVWU:
  58. return 1;
  59. }
  60. if(isdblwrdmov(p))
  61. return 1;
  62. return 0;
  63. }
  64. static int
  65. isstore(Prog *p)
  66. {
  67. if(p == nil)
  68. return 0;
  69. if(ismove(p))
  70. switch(p->to.type) {
  71. case D_OREG:
  72. case D_EXTERN:
  73. case D_STATIC:
  74. case D_AUTO:
  75. case D_PARAM:
  76. return 1;
  77. }
  78. return 0;
  79. }
  80. static int
  81. iscondbranch(Prog *p)
  82. {
  83. if(p == nil)
  84. return 0;
  85. switch(p->as){
  86. case ABEQ:
  87. case ABFPF:
  88. case ABFPT:
  89. case ABGEZ:
  90. case ABGEZAL:
  91. case ABGTZ:
  92. case ABLEZ:
  93. case ABLTZ:
  94. case ABLTZAL:
  95. case ABNE:
  96. return 1;
  97. }
  98. return 0;
  99. }
  100. static int
  101. isbranch(Prog *p)
  102. {
  103. if(p == nil)
  104. return 0;
  105. switch(p->as){
  106. case AJAL:
  107. case AJMP:
  108. case ARET:
  109. case ARFE:
  110. return 1;
  111. }
  112. if(iscondbranch(p))
  113. return 1;
  114. return 0;
  115. }
  116. static void
  117. nopafter(Prog *p)
  118. {
  119. p->mark |= LABEL|SYNC;
  120. addnop(p);
  121. }
  122. /*
  123. * workaround for 24k erratum #48, costs about 0.5% in space.
  124. * inserts a NOP before the last of 3 consecutive stores.
  125. * double-word stores complicate things.
  126. */
  127. static int
  128. no3stores(Prog *p)
  129. {
  130. Prog *p1;
  131. if(!isstore(p))
  132. return 0;
  133. p1 = p->link;
  134. if(!isstore(p1))
  135. return 0;
  136. if(isdblwrdmov(p) || isdblwrdmov(p1)) {
  137. nopafter(p);
  138. nop.store.count++;
  139. nop.store.outof++;
  140. return 1;
  141. }
  142. if(isstore(p1->link)) {
  143. nopafter(p1);
  144. nop.store.count++;
  145. nop.store.outof++;
  146. return 1;
  147. }
  148. return 0;
  149. }
  150. /*
  151. * keep stores out of branch delay slots.
  152. * this is costly in space (the other 9.5%), but makes no3stores effective.
  153. * there is undoubtedly a better way to do this.
  154. */
  155. void
  156. storesnosched(void)
  157. {
  158. Prog *p;
  159. for(p = firstp; p != P; p = p->link)
  160. if(isstore(p))
  161. p->mark |= NOSCHED;
  162. }
  163. int
  164. triplestorenops(void)
  165. {
  166. int r;
  167. Prog *p, *p1;
  168. r = 0;
  169. for(p = firstp; p != P; p = p1) {
  170. p1 = p->link;
  171. // if (p->mark & NOSCHED)
  172. // continue;
  173. if(ismove(p) && isstore(p)) {
  174. if (no3stores(p))
  175. r++;
  176. /*
  177. * given storenosched, the next two
  178. * checks shouldn't be necessary.
  179. */
  180. /*
  181. * add nop after first MOV in `MOV; Bcond; MOV'.
  182. */
  183. else if(isbranch(p1) && isstore(p1->link)) {
  184. nopafter(p);
  185. nop.branch.count++;
  186. nop.branch.outof++;
  187. r++;
  188. }
  189. /*
  190. * this may be a branch target, so insert a nop after,
  191. * in case a branch leading here has a store in its
  192. * delay slot and we have consecutive stores here.
  193. */
  194. if(p->mark & (LABEL|SYNC) && !isnop(p1)) {
  195. nopafter(p);
  196. nop.branch.count++;
  197. nop.branch.outof++;
  198. r++;
  199. }
  200. } else if (isbranch(p))
  201. /*
  202. * can't ignore delay slot of a conditional branch;
  203. * the branch could fail and fall through.
  204. */
  205. if (!iscondbranch(p) && p1)
  206. p1 = p1->link; /* skip its delay slot */
  207. }
  208. return r;
  209. }
  210. void
  211. noops(void)
  212. {
  213. Prog *p, *p1, *q, *q1;
  214. int o, curframe, curbecome, maxbecome;
  215. /*
  216. * find leaf subroutines
  217. * become sizes
  218. * frame sizes
  219. * strip NOPs
  220. * expand RET
  221. * expand BECOME pseudo
  222. */
  223. if(debug['v'])
  224. Bprint(&bso, "%5.2f noops\n", cputime());
  225. Bflush(&bso);
  226. curframe = 0;
  227. curbecome = 0;
  228. maxbecome = 0;
  229. curtext = 0;
  230. q = P;
  231. for(p = firstp; p != P; p = p->link) {
  232. /* find out how much arg space is used in this TEXT */
  233. if(p->to.type == D_OREG && p->to.reg == REGSP)
  234. if(p->to.offset > curframe)
  235. curframe = p->to.offset;
  236. switch(p->as) {
  237. case ATEXT:
  238. if(curtext && curtext->from.sym) {
  239. curtext->from.sym->frame = curframe;
  240. curtext->from.sym->become = curbecome;
  241. if(curbecome > maxbecome)
  242. maxbecome = curbecome;
  243. }
  244. curframe = 0;
  245. curbecome = 0;
  246. p->mark |= LABEL|LEAF|SYNC;
  247. if(p->link)
  248. p->link->mark |= LABEL;
  249. curtext = p;
  250. break;
  251. /* too hard, just leave alone */
  252. case AMOVW:
  253. if(p->to.type == D_FCREG ||
  254. p->to.type == D_MREG) {
  255. p->mark |= LABEL|SYNC;
  256. break;
  257. }
  258. if(p->from.type == D_FCREG ||
  259. p->from.type == D_MREG) {
  260. p->mark |= LABEL|SYNC;
  261. addnop(p);
  262. addnop(p);
  263. nop.mfrom.count += 2;
  264. nop.mfrom.outof += 2;
  265. break;
  266. }
  267. break;
  268. /* too hard, just leave alone */
  269. case ACASE:
  270. case ASYSCALL:
  271. case AWORD:
  272. case ATLBWR:
  273. case ATLBWI:
  274. case ATLBP:
  275. case ATLBR:
  276. p->mark |= LABEL|SYNC;
  277. break;
  278. case ANOR:
  279. if(p->to.type == D_REG && p->to.reg == REGZERO)
  280. p->mark |= LABEL|SYNC;
  281. break;
  282. case ARET:
  283. /* special form of RET is BECOME */
  284. if(p->from.type == D_CONST)
  285. if(p->from.offset > curbecome)
  286. curbecome = p->from.offset;
  287. if(p->link != P)
  288. p->link->mark |= LABEL;
  289. break;
  290. case ANOP:
  291. q1 = p->link;
  292. q->link = q1; /* q is non-nop */
  293. q1->mark |= p->mark;
  294. continue;
  295. case ABCASE:
  296. p->mark |= LABEL|SYNC;
  297. goto dstlab;
  298. case ABGEZAL:
  299. case ABLTZAL:
  300. case AJAL:
  301. if(curtext != P)
  302. curtext->mark &= ~LEAF;
  303. case AJMP:
  304. case ABEQ:
  305. case ABGEZ:
  306. case ABGTZ:
  307. case ABLEZ:
  308. case ABLTZ:
  309. case ABNE:
  310. case ABFPT:
  311. case ABFPF:
  312. p->mark |= BRANCH;
  313. dstlab:
  314. q1 = p->cond;
  315. if(q1 != P) {
  316. while(q1->as == ANOP) {
  317. q1 = q1->link;
  318. p->cond = q1;
  319. }
  320. if(!(q1->mark & LEAF))
  321. q1->mark |= LABEL;
  322. } else
  323. p->mark |= LABEL;
  324. q1 = p->link;
  325. if(q1 != P)
  326. q1->mark |= LABEL;
  327. break;
  328. }
  329. q = p;
  330. }
  331. if(curtext && curtext->from.sym) {
  332. curtext->from.sym->frame = curframe;
  333. curtext->from.sym->become = curbecome;
  334. if(curbecome > maxbecome)
  335. maxbecome = curbecome;
  336. }
  337. if(debug['b'])
  338. print("max become = %d\n", maxbecome);
  339. xdefine("ALEFbecome", STEXT, maxbecome);
  340. curtext = 0;
  341. for(p = firstp; p != P; p = p->link) {
  342. switch(p->as) {
  343. case ATEXT:
  344. curtext = p;
  345. break;
  346. case AJAL:
  347. if(curtext != P && curtext->from.sym != S && curtext->to.offset >= 0) {
  348. o = maxbecome - curtext->from.sym->frame;
  349. if(o <= 0)
  350. break;
  351. /* calling a become or calling a variable */
  352. if(p->to.sym == S || p->to.sym->become) {
  353. curtext->to.offset += o;
  354. if(debug['b']) {
  355. curp = p;
  356. print("%D calling %D increase %d\n",
  357. &curtext->from, &p->to, o);
  358. }
  359. }
  360. }
  361. break;
  362. }
  363. }
  364. for(p = firstp; p != P; p = p->link) {
  365. o = p->as;
  366. switch(o) {
  367. case ATEXT:
  368. curtext = p;
  369. autosize = p->to.offset + 4;
  370. if(autosize <= 4)
  371. if(curtext->mark & LEAF) {
  372. p->to.offset = -4;
  373. autosize = 0;
  374. }
  375. q = p;
  376. if(autosize) {
  377. q = prg();
  378. q->as = AADD;
  379. q->line = p->line;
  380. q->from.type = D_CONST;
  381. q->from.offset = -autosize;
  382. q->to.type = D_REG;
  383. q->to.reg = REGSP;
  384. q->link = p->link;
  385. p->link = q;
  386. } else
  387. if(!(curtext->mark & LEAF)) {
  388. if(debug['v'])
  389. Bprint(&bso, "save suppressed in: %s\n",
  390. curtext->from.sym->name);
  391. Bflush(&bso);
  392. curtext->mark |= LEAF;
  393. }
  394. if(curtext->mark & LEAF) {
  395. if(curtext->from.sym)
  396. curtext->from.sym->type = SLEAF;
  397. break;
  398. }
  399. q1 = prg();
  400. q1->as = AMOVW;
  401. q1->line = p->line;
  402. q1->from.type = D_REG;
  403. q1->from.reg = REGLINK;
  404. q1->to.type = D_OREG;
  405. q1->from.offset = 0;
  406. q1->to.reg = REGSP;
  407. q1->link = q->link;
  408. q->link = q1;
  409. break;
  410. case ARET:
  411. nocache(p);
  412. if(p->from.type == D_CONST)
  413. goto become;
  414. if(curtext->mark & LEAF) {
  415. if(!autosize) {
  416. p->as = AJMP;
  417. p->from = zprg.from;
  418. p->to.type = D_OREG;
  419. p->to.offset = 0;
  420. p->to.reg = REGLINK;
  421. p->mark |= BRANCH;
  422. break;
  423. }
  424. p->as = AADD;
  425. p->from.type = D_CONST;
  426. p->from.offset = autosize;
  427. p->to.type = D_REG;
  428. p->to.reg = REGSP;
  429. q = prg();
  430. q->as = AJMP;
  431. q->line = p->line;
  432. q->to.type = D_OREG;
  433. q->to.offset = 0;
  434. q->to.reg = REGLINK;
  435. q->mark |= BRANCH;
  436. q->link = p->link;
  437. p->link = q;
  438. break;
  439. }
  440. p->as = AMOVW;
  441. p->from.type = D_OREG;
  442. p->from.offset = 0;
  443. p->from.reg = REGSP;
  444. p->to.type = D_REG;
  445. p->to.reg = 2;
  446. q = p;
  447. if(autosize) {
  448. q = prg();
  449. q->as = AADD;
  450. q->line = p->line;
  451. q->from.type = D_CONST;
  452. q->from.offset = autosize;
  453. q->to.type = D_REG;
  454. q->to.reg = REGSP;
  455. q->link = p->link;
  456. p->link = q;
  457. }
  458. q1 = prg();
  459. q1->as = AJMP;
  460. q1->line = p->line;
  461. q1->to.type = D_OREG;
  462. q1->to.offset = 0;
  463. q1->to.reg = 2;
  464. q1->mark |= BRANCH;
  465. q1->link = q->link;
  466. q->link = q1;
  467. break;
  468. become:
  469. if(curtext->mark & LEAF) {
  470. q = prg();
  471. q->line = p->line;
  472. q->as = AJMP;
  473. q->from = zprg.from;
  474. q->to = p->to;
  475. q->cond = p->cond;
  476. q->link = p->link;
  477. q->mark |= BRANCH;
  478. p->link = q;
  479. p->as = AADD;
  480. p->from = zprg.from;
  481. p->from.type = D_CONST;
  482. p->from.offset = autosize;
  483. p->to = zprg.to;
  484. p->to.type = D_REG;
  485. p->to.reg = REGSP;
  486. break;
  487. }
  488. q = prg();
  489. q->line = p->line;
  490. q->as = AJMP;
  491. q->from = zprg.from;
  492. q->to = p->to;
  493. q->cond = p->cond;
  494. q->link = p->link;
  495. q->mark |= BRANCH;
  496. p->link = q;
  497. q = prg();
  498. q->line = p->line;
  499. q->as = AADD;
  500. q->from.type = D_CONST;
  501. q->from.offset = autosize;
  502. q->to.type = D_REG;
  503. q->to.reg = REGSP;
  504. q->link = p->link;
  505. p->link = q;
  506. p->as = AMOVW;
  507. p->from = zprg.from;
  508. p->from.type = D_OREG;
  509. p->from.offset = 0;
  510. p->from.reg = REGSP;
  511. p->to = zprg.to;
  512. p->to.type = D_REG;
  513. p->to.reg = REGLINK;
  514. break;
  515. }
  516. }
  517. if (Mips24k)
  518. storesnosched();
  519. curtext = P;
  520. q = P; /* p - 1 */
  521. q1 = firstp; /* top of block */
  522. o = 0; /* count of instructions */
  523. for(p = firstp; p != P; p = p1) {
  524. p1 = p->link;
  525. o++;
  526. if(p->mark & NOSCHED){
  527. if(q1 != p){
  528. sched(q1, q);
  529. }
  530. for(; p != P; p = p->link){
  531. if(!(p->mark & NOSCHED))
  532. break;
  533. q = p;
  534. }
  535. p1 = p;
  536. q1 = p;
  537. o = 0;
  538. continue;
  539. }
  540. if(p->mark & (LABEL|SYNC)) {
  541. if(q1 != p)
  542. sched(q1, q);
  543. q1 = p;
  544. o = 1;
  545. }
  546. if(p->mark & (BRANCH|SYNC)) {
  547. sched(q1, p);
  548. q1 = p1;
  549. o = 0;
  550. }
  551. if(o >= NSCHED) {
  552. sched(q1, p);
  553. q1 = p1;
  554. o = 0;
  555. }
  556. q = p;
  557. }
  558. if (Mips24k)
  559. triplestorenops();
  560. }
  561. void
  562. addnop(Prog *p)
  563. {
  564. Prog *q;
  565. q = prg();
  566. q->as = ANOR;
  567. q->line = p->line;
  568. q->from.type = D_REG;
  569. q->from.reg = REGZERO;
  570. q->to.type = D_REG;
  571. q->to.reg = REGZERO;
  572. q->link = p->link;
  573. p->link = q;
  574. }
  575. void
  576. nocache(Prog *p)
  577. {
  578. p->optab = 0;
  579. p->from.class = 0;
  580. p->to.class = 0;
  581. }