fold.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. #include "all.h"
  2. /* boring folding code */
  3. static int
  4. iscon(Con *c, int w, uint64_t k)
  5. {
  6. if (c->type != CBits)
  7. return 0;
  8. if (w)
  9. return (uint64_t)c->bits.i == k;
  10. else
  11. return (uint32_t)c->bits.i == (uint32_t)k;
  12. }
  13. int
  14. foldint(Con *res, int op, int w, Con *cl, Con *cr)
  15. {
  16. union {
  17. int64_t s;
  18. uint64_t u;
  19. float fs;
  20. double fd;
  21. } l, r;
  22. uint64_t x;
  23. Sym sym;
  24. int typ;
  25. memset(&sym, 0, sizeof sym);
  26. typ = CBits;
  27. l.s = cl->bits.i;
  28. r.s = cr->bits.i;
  29. if (op == Oadd) {
  30. if (cl->type == CAddr) {
  31. if (cr->type == CAddr)
  32. return 1;
  33. typ = CAddr;
  34. sym = cl->sym;
  35. }
  36. else if (cr->type == CAddr) {
  37. typ = CAddr;
  38. sym = cr->sym;
  39. }
  40. }
  41. else if (op == Osub) {
  42. if (cl->type == CAddr) {
  43. if (cr->type != CAddr) {
  44. typ = CAddr;
  45. sym = cl->sym;
  46. } else if (!symeq(cl->sym, cr->sym))
  47. return 1;
  48. }
  49. else if (cr->type == CAddr)
  50. return 1;
  51. }
  52. else if (cl->type == CAddr || cr->type == CAddr)
  53. return 1;
  54. if (op == Odiv || op == Orem || op == Oudiv || op == Ourem) {
  55. if (iscon(cr, w, 0))
  56. return 1;
  57. if (op == Odiv || op == Orem) {
  58. x = w ? INT64_MIN : INT32_MIN;
  59. if (iscon(cr, w, -1))
  60. if (iscon(cl, w, x))
  61. return 1;
  62. }
  63. }
  64. switch (op) {
  65. case Oadd: x = l.u + r.u; break;
  66. case Osub: x = l.u - r.u; break;
  67. case Oneg: x = -l.u; break;
  68. case Odiv: x = w ? l.s / r.s : (int32_t)l.s / (int32_t)r.s; break;
  69. case Orem: x = w ? l.s % r.s : (int32_t)l.s % (int32_t)r.s; break;
  70. case Oudiv: x = w ? l.u / r.u : (uint32_t)l.u / (uint32_t)r.u; break;
  71. case Ourem: x = w ? l.u % r.u : (uint32_t)l.u % (uint32_t)r.u; break;
  72. case Omul: x = l.u * r.u; break;
  73. case Oand: x = l.u & r.u; break;
  74. case Oor: x = l.u | r.u; break;
  75. case Oxor: x = l.u ^ r.u; break;
  76. case Osar: x = (w ? l.s : (int32_t)l.s) >> (r.u & (31|w<<5)); break;
  77. case Oshr: x = (w ? l.u : (uint32_t)l.u) >> (r.u & (31|w<<5)); break;
  78. case Oshl: x = l.u << (r.u & (31|w<<5)); break;
  79. case Oextsb: x = (int8_t)l.u; break;
  80. case Oextub: x = (uint8_t)l.u; break;
  81. case Oextsh: x = (int16_t)l.u; break;
  82. case Oextuh: x = (uint16_t)l.u; break;
  83. case Oextsw: x = (int32_t)l.u; break;
  84. case Oextuw: x = (uint32_t)l.u; break;
  85. case Ostosi: x = w ? (int64_t)cl->bits.s : (int32_t)cl->bits.s; break;
  86. case Ostoui: x = w ? (uint64_t)cl->bits.s : (uint32_t)cl->bits.s; break;
  87. case Odtosi: x = w ? (int64_t)cl->bits.d : (int32_t)cl->bits.d; break;
  88. case Odtoui: x = w ? (uint64_t)cl->bits.d : (uint32_t)cl->bits.d; break;
  89. case Ocast:
  90. x = l.u;
  91. if (cl->type == CAddr) {
  92. typ = CAddr;
  93. sym = cl->sym;
  94. }
  95. break;
  96. default:
  97. if (Ocmpw <= op && op <= Ocmpl1) {
  98. if (op <= Ocmpw1) {
  99. l.u = (int32_t)l.u;
  100. r.u = (int32_t)r.u;
  101. } else
  102. op -= Ocmpl - Ocmpw;
  103. switch (op - Ocmpw) {
  104. case Ciule: x = l.u <= r.u; break;
  105. case Ciult: x = l.u < r.u; break;
  106. case Cisle: x = l.s <= r.s; break;
  107. case Cislt: x = l.s < r.s; break;
  108. case Cisgt: x = l.s > r.s; break;
  109. case Cisge: x = l.s >= r.s; break;
  110. case Ciugt: x = l.u > r.u; break;
  111. case Ciuge: x = l.u >= r.u; break;
  112. case Cieq: x = l.u == r.u; break;
  113. case Cine: x = l.u != r.u; break;
  114. default: die("unreachable");
  115. }
  116. }
  117. else if (Ocmps <= op && op <= Ocmps1) {
  118. switch (op - Ocmps) {
  119. case Cfle: x = l.fs <= r.fs; break;
  120. case Cflt: x = l.fs < r.fs; break;
  121. case Cfgt: x = l.fs > r.fs; break;
  122. case Cfge: x = l.fs >= r.fs; break;
  123. case Cfne: x = l.fs != r.fs; break;
  124. case Cfeq: x = l.fs == r.fs; break;
  125. case Cfo: x = l.fs < r.fs || l.fs >= r.fs; break;
  126. case Cfuo: x = !(l.fs < r.fs || l.fs >= r.fs); break;
  127. default: die("unreachable");
  128. }
  129. }
  130. else if (Ocmpd <= op && op <= Ocmpd1) {
  131. switch (op - Ocmpd) {
  132. case Cfle: x = l.fd <= r.fd; break;
  133. case Cflt: x = l.fd < r.fd; break;
  134. case Cfgt: x = l.fd > r.fd; break;
  135. case Cfge: x = l.fd >= r.fd; break;
  136. case Cfne: x = l.fd != r.fd; break;
  137. case Cfeq: x = l.fd == r.fd; break;
  138. case Cfo: x = l.fd < r.fd || l.fd >= r.fd; break;
  139. case Cfuo: x = !(l.fd < r.fd || l.fd >= r.fd); break;
  140. default: die("unreachable");
  141. }
  142. }
  143. else
  144. die("unreachable");
  145. }
  146. *res = (Con){.type=typ, .sym=sym, .bits={.i=x}};
  147. return 0;
  148. }
  149. static void
  150. foldflt(Con *res, int op, int w, Con *cl, Con *cr)
  151. {
  152. float xs, ls, rs;
  153. double xd, ld, rd;
  154. if (cl->type != CBits || cr->type != CBits)
  155. err("invalid address operand for '%s'", optab[op].name);
  156. *res = (Con){.type = CBits};
  157. memset(&res->bits, 0, sizeof(res->bits));
  158. if (w) {
  159. ld = cl->bits.d;
  160. rd = cr->bits.d;
  161. switch (op) {
  162. case Oadd: xd = ld + rd; break;
  163. case Osub: xd = ld - rd; break;
  164. case Oneg: xd = -ld; break;
  165. case Odiv: xd = ld / rd; break;
  166. case Omul: xd = ld * rd; break;
  167. case Oswtof: xd = (int32_t)cl->bits.i; break;
  168. case Ouwtof: xd = (uint32_t)cl->bits.i; break;
  169. case Osltof: xd = (int64_t)cl->bits.i; break;
  170. case Oultof: xd = (uint64_t)cl->bits.i; break;
  171. case Oexts: xd = cl->bits.s; break;
  172. case Ocast: xd = ld; break;
  173. default: die("unreachable");
  174. }
  175. res->bits.d = xd;
  176. res->flt = 2;
  177. } else {
  178. ls = cl->bits.s;
  179. rs = cr->bits.s;
  180. switch (op) {
  181. case Oadd: xs = ls + rs; break;
  182. case Osub: xs = ls - rs; break;
  183. case Oneg: xs = -ls; break;
  184. case Odiv: xs = ls / rs; break;
  185. case Omul: xs = ls * rs; break;
  186. case Oswtof: xs = (int32_t)cl->bits.i; break;
  187. case Ouwtof: xs = (uint32_t)cl->bits.i; break;
  188. case Osltof: xs = (int64_t)cl->bits.i; break;
  189. case Oultof: xs = (uint64_t)cl->bits.i; break;
  190. case Otruncd: xs = cl->bits.d; break;
  191. case Ocast: xs = ls; break;
  192. default: die("unreachable");
  193. }
  194. res->bits.s = xs;
  195. res->flt = 1;
  196. }
  197. }
  198. static Ref
  199. opfold(int op, int cls, Con *cl, Con *cr, Fn *fn)
  200. {
  201. Ref r;
  202. Con c;
  203. if (cls == Kw || cls == Kl) {
  204. if (foldint(&c, op, cls == Kl, cl, cr))
  205. return R;
  206. } else
  207. foldflt(&c, op, cls == Kd, cl, cr);
  208. if (!KWIDE(cls))
  209. c.bits.i &= 0xffffffff;
  210. r = newcon(&c, fn);
  211. assert(!(cls == Ks || cls == Kd) || c.flt);
  212. return r;
  213. }
  214. /* used by GVN */
  215. Ref
  216. foldref(Fn *fn, Ins *i)
  217. {
  218. Ref rr;
  219. Con *cl, *cr;
  220. if (rtype(i->to) != RTmp)
  221. return R;
  222. if (optab[i->op].canfold) {
  223. if (rtype(i->arg[0]) != RCon)
  224. return R;
  225. cl = &fn->con[i->arg[0].val];
  226. rr = i->arg[1];
  227. if (req(rr, R))
  228. rr = CON_Z;
  229. if (rtype(rr) != RCon)
  230. return R;
  231. cr = &fn->con[rr.val];
  232. return opfold(i->op, i->cls, cl, cr, fn);
  233. }
  234. return R;
  235. }