Simplify int mul/udiv/urem of 2^N into shl/shr/and.
[qbe.git] / simpl.c
blobf22d491f2ddfe12ce1989d507f5f0cda6004be6d
1 #include "all.h"
3 static void
4 blit(Ref sd[2], int sz, Fn *fn)
6 struct { int st, ld, cls, size; } *p, tbl[] = {
7 { Ostorel, Oload, Kl, 8 },
8 { Ostorew, Oload, Kw, 4 },
9 { Ostoreh, Oloaduh, Kw, 2 },
10 { Ostoreb, Oloadub, Kw, 1 }
12 Ref r, r1, ro;
13 int off, fwd, n;
15 fwd = sz >= 0;
16 sz = abs(sz);
17 off = fwd ? sz : 0;
18 for (p=tbl; sz; p++)
19 for (n=p->size; sz>=n; sz-=n) {
20 off -= fwd ? n : 0;
21 r = newtmp("blt", Kl, fn);
22 r1 = newtmp("blt", Kl, fn);
23 ro = getcon(off, fn);
24 emit(p->st, 0, R, r, r1);
25 emit(Oadd, Kl, r1, sd[1], ro);
26 r1 = newtmp("blt", Kl, fn);
27 emit(p->ld, p->cls, r, r1, R);
28 emit(Oadd, Kl, r1, sd[0], ro);
29 off += fwd ? 0 : n;
33 static int
34 ulog2_tab64[64] = {
35 63, 0, 58, 1, 59, 47, 53, 2,
36 60, 39, 48, 27, 54, 33, 42, 3,
37 61, 51, 37, 40, 49, 18, 28, 20,
38 55, 30, 34, 11, 43, 14, 22, 4,
39 62, 57, 46, 52, 38, 26, 32, 41,
40 50, 36, 17, 19, 29, 10, 13, 21,
41 56, 45, 25, 31, 35, 16, 9, 12,
42 44, 24, 15, 8, 23, 7, 6, 5
45 static int
46 ulog2(uint64_t pow2)
48 return ulog2_tab64[(pow2 * 0x07EDD5E59A4E28C2) >> 58];
51 static int
52 ispow2(uint64_t v)
54 return (v & (v - 1)) == 0;
57 static void
58 ins(Ins **pi, int *new, Blk *b, Fn *fn)
60 ulong ni;
61 Con *c;
62 Ins *i;
63 Ref r;
64 int n;
66 i = *pi;
67 /* simplify more instructions here;
68 * copy 0 into xor bit rotations,
69 * etc. */
70 switch (i->op) {
71 case Oblit1:
72 assert(i > b->ins);
73 assert((i-1)->op == Oblit0);
74 if (!*new) {
75 curi = &insb[NIns];
76 ni = &b->ins[b->nins] - (i+1);
77 curi -= ni;
78 icpy(curi, i+1, ni);
79 *new = 1;
81 blit((i-1)->arg, rsval(i->arg[0]), fn);
82 *pi = i-1;
83 break;
84 case Omul:
85 case Oudiv:
86 case Ourem:
87 r = i->arg[1];
88 if (KBASE(i->cls) == 0)
89 if (rtype(r) == RCon) {
90 c = &fn->con[r.val];
91 if (c->type == CBits)
92 if (ispow2(c->bits.i)) {
93 n = ulog2(c->bits.i);
94 if (i->op == Ourem) {
95 i->op = Oand;
96 i->arg[1] = getcon((1ull<<n) - 1, fn);
97 } else if (i->op == Oudiv) {
98 i->op = Oshr;
99 i->arg[1] = getcon(n, fn);
100 } else if (i->op == Omul) {
101 i->op = Oshl;
102 i->arg[1] = getcon(n, fn);
106 /* fall through */
107 default:
108 if (*new)
109 emiti(*i);
110 break;
114 void
115 simpl(Fn *fn)
117 Blk *b;
118 Ins *i;
119 int new;
121 for (b=fn->start; b; b=b->link) {
122 new = 0;
123 for (i=&b->ins[b->nins]; i!=b->ins;) {
124 --i;
125 ins(&i, &new, b, fn);
127 if (new) {
128 b->nins = &insb[NIns] - curi;
129 idup(&b->ins, curi, b->nins);