loopopt.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. #include "all.h"
  2. static int
  3. forloop(Blk *bh, Blk *bb)
  4. {
  5. if (bh->npred == 2)
  6. if (bh->jmp.type == Jjnz)
  7. if (bb->npred == 1)
  8. if (bb->jmp.type == Jjmp)
  9. if (bb->jmp.s[0].b == bh)
  10. return 1;
  11. return 0;
  12. }
  13. static int
  14. doloop(Blk *bh)
  15. {
  16. if (bh->npred == 2)
  17. if (bh->jmp.type == Jjnz)
  18. if (bh->jmp.s[0].b == bh || bh->jmp.s[1].b == bh)
  19. return 1;
  20. return 0;
  21. }
  22. static int
  23. loopvar(Fn *fn, Blk *bh, Blk *bb, uint np, Ref *prl, Ref *pr0, Ref *pri)
  24. {
  25. Blk *bp;
  26. Phi *p;
  27. Suc *sb, *sp;
  28. Tmp *t;
  29. Ins *i;
  30. assert(bh->npred == 2);
  31. assert(bh->pred[0] == bb || bh->pred[1] == bb);
  32. bp = bh->pred[bh->pred[0] == bb]; /* pre-header */
  33. assert(np < bh->nphi);
  34. p = &bh->phi[np];
  35. if (KBASE(p->cls) != 0)
  36. return 0; /* not integer */
  37. sp = getsuc(bp, bh);
  38. assert(sp->nr == bh->nphi);
  39. *pr0 = sp->r[np];
  40. sb = getsuc(bb, bh);
  41. assert(sb->nr == bh->nphi);
  42. *prl = sb->r[np];
  43. if (rtype(*prl) != RTmp)
  44. return 0; /* loop var must be an incremented tmp */
  45. t = &fn->tmp[prl->val];
  46. if (t->bid != bb->id || t->def == 0)
  47. return 0; /* loop var must be defined by an add ins in the body */
  48. i = t->def;
  49. if (i->op != Oadd || req(i->arg[0], p->to) == req(i->arg[1], p->to))
  50. return 0;
  51. *pri = i->arg[req(i->arg[0], p->to)];
  52. assert(p->cls == i->cls);
  53. if (rtype(*pri) == RTmp) {
  54. t = &fn->tmp[pri->val];
  55. if (t->bid == bh->id || t->bid == bb->id)
  56. return 0;
  57. return 1;
  58. }
  59. else {
  60. assert(rtype(*pri) == RCon);
  61. return 1;
  62. }
  63. return 0;
  64. }
  65. static void
  66. mulredux(Fn *fn, Blk *bh, Blk *bb, Blk *bp, uint np, Ref rl, Ref r0, Ref ri, Ins **pvins, uint *pnins)
  67. {
  68. Ins *i;
  69. Tmp *t;
  70. Ref r1, rlop;
  71. Phi *p;
  72. Suc *sb, *sp;
  73. /* dead simple case for now... majority case in practice */
  74. if (!req(r0, con01[0]) || !req(ri, con01[1]))
  75. return;
  76. assert(!req(rl, R)); /* rl unused */
  77. assert(np < bh->nphi);
  78. p = &bh->phi[np];
  79. for (i = bb->ins; i < &bb->ins[bb->nins]; i++) {
  80. /* TODO i->cls != p->cls is not necessary? */
  81. if (i->op != Omul || i->cls != p->cls
  82. || req(i->arg[0], p->to) == req(i->arg[1], p->to))
  83. continue;
  84. r1 = i->arg[req(i->arg[0], p->to)];
  85. if (rtype(r1) == RTmp) {
  86. t = &fn->tmp[r1.val];
  87. if (t->bid == bh->id || t->bid == bb->id)
  88. continue;
  89. } else
  90. assert(rtype(r1) == RCon);
  91. assert(KBASE(i->cls) == 0);
  92. rlop = newtmp("lop", i->cls, fn);
  93. vgrow(&bh->phi, ++bh->nphi);
  94. bh->phi[bh->nphi-1] = (Phi){.to = i->to, .cls = i->cls};
  95. sp = getsuc(bp, bh);
  96. vgrow(&sp->r, ++sp->nr);
  97. sp->r[sp->nr-1] = con01[0];
  98. assert(sp->nr == bh->nphi);
  99. sb = getsuc(bb, bh);
  100. vgrow(&sb->r, ++sb->nr);
  101. sb->r[sp->nr-1] = rlop;
  102. assert(sb->nr == bh->nphi);
  103. addins(pvins, pnins, &(Ins){.to = rlop, .op = Oadd, .cls = i->cls,
  104. .arg = {i->to, r1}});
  105. *i = (Ins){.op = Onop};
  106. }
  107. }
  108. static void
  109. addbase(Fn *fn, Blk *bh, Blk *bb, Blk *bp, uint np, Ref rl, Ref r0, Ref ri, Ins **pvins, uint *pnins)
  110. {
  111. Ins *i, *ii, *ib;
  112. Tmp *t, *ti, *tb;
  113. Use *u;
  114. Ref rb;
  115. Phi *p;
  116. Suc *sp;
  117. /* dead simple case for now... majority case in practice */
  118. if (!req(r0, con01[0]))
  119. return;
  120. assert(!req(ri, R)); /* unused */
  121. assert(pvins && pnins); /* unused */
  122. assert(np < bh->nphi);
  123. p = &bh->phi[np];
  124. assert(rtype(p->to) == RTmp);
  125. t = &fn->tmp[p->to.val];
  126. if (t->nuse != 2)
  127. return;
  128. i = ib = 0;
  129. for (u = t->use; u < &t->use[t->nuse]; u++) {
  130. if (u->type != UIns)
  131. return;
  132. i = u->u.ins;
  133. if (i->op != Oadd || i->cls != p->cls || u->bid != bb->id)
  134. return;
  135. assert(req(i->arg[0], p->to) || req(i->arg[1], p->to));
  136. if (req(i->to, rl)) {
  137. assert(rtype(i->to) == RTmp);
  138. ti = &fn->tmp[i->to.val];
  139. if (ti->nuse != 1)
  140. return;
  141. assert(ti->use[0].type == UPhi);
  142. assert(ti->use[0].bid == bh->id);
  143. assert(ti->use[0].u.p.np == np);
  144. assert(ti->use[0].u.p.pbid == bb->id);
  145. ii = i;
  146. continue;
  147. }
  148. rb = i->arg[req(i->arg[0], p->to)];
  149. if (req(rb, p->to))
  150. return;
  151. if (rtype(rb) == RTmp) {
  152. tb = &fn->tmp[rb.val];
  153. if (tb->bid == bh->id || tb->bid == bb->id)
  154. return;
  155. } else
  156. assert(rtype(rb) == RCon);
  157. ib = i;
  158. }
  159. assert(ii);
  160. assert(ib);
  161. sp = getsuc(bp, bh);
  162. assert(sp->nr == bh->nphi);
  163. assert(req(sp->r[np], con01[0]));
  164. sp->r[np] = rb;
  165. assert(req(ii->arg[0], p->to) != req(ii->arg[1], p->to));
  166. ii->arg[!req(ii->arg[0], p->to)] = ib->to;
  167. p->to = ib->to;
  168. *ib = (Ins){.op = Onop};
  169. }
  170. typedef void optfn_t(Fn *, Blk *, Blk *, Blk *, uint, Ref, Ref, Ref, Ins **, uint *);
  171. static void
  172. loopvaropt(Fn *fn, optfn_t *optfn)
  173. {
  174. uint bid;
  175. Blk *bh, *bb, *bp; /* header, body, pre-header */
  176. Phi *p;
  177. Ins *vins;
  178. uint nins, np;
  179. Ref rl, r0, ri; /* loop var, loop var init, loop var inc */
  180. nins = 0;
  181. vins = vnew(nins, sizeof vins[0], PFn); /* TODO use insb */
  182. for (bid = 0; bid < fn->nblk; bid++) {
  183. bh = fn->rpo[bid];
  184. if (forloop(bh, bh->jmp.s[0].b))
  185. bb = bh->jmp.s[0].b;
  186. else if (forloop(bh, bh->jmp.s[1].b))
  187. bb = bh->jmp.s[1].b;
  188. else if (doloop(bh))
  189. bb = bh; /* header and body */
  190. else
  191. continue;
  192. bp = bh->pred[bh->pred[0] == bh];
  193. assert(bh->loop > 1);
  194. assert(bh->loop == bb->loop);
  195. nins = 0;
  196. for (np = 0; np < bh->nphi; np++)
  197. if (loopvar(fn, bh, bb, np, &rl, &r0, &ri)) {
  198. p = &bh->phi[np];
  199. assert(KBASE(p->cls) == 0);
  200. optfn(fn, bh, bb, bp, np, rl, r0, ri, &vins, &nins);
  201. }
  202. addnins(&bb->ins, &bb->nins, vins, nins);
  203. }
  204. }
  205. void
  206. loopopt(Fn *fn)
  207. {
  208. /* encourage simple loops */
  209. ifelim(fn);
  210. fillcfg(fn);
  211. blkmerge(fn);
  212. fillcfg(fn);
  213. filluse(fn);
  214. fillloop(fn);
  215. loopvaropt(fn, mulredux);
  216. filluse(fn);
  217. loopvaropt(fn, addbase);
  218. }