1#include "all.h"
2
3enum Imm {
4 Iother,
5 Iplo12,
6 Iphi12,
7 Iplo24,
8 Inlo12,
9 Inhi12,
10 Inlo24
11};
12
13static enum Imm
14imm(Con *c, int k, int64_t *pn)
15{
16 int64_t n;
17 int i;
18
19 if (c->type != CBits)
20 return Iother;
21 n = c->bits.i;
22 if (k == Kw)
23 n = (int32_t)n;
24 i = Iplo12;
25 if (n < 0) {
26 i = Inlo12;
27 n = -n;
28 }
29 *pn = n;
30 if ((n & 0x000fff) == n)
31 return i;
32 if ((n & 0xfff000) == n)
33 return i + 1;
34 if ((n & 0xffffff) == n)
35 return i + 2;
36 return Iother;
37}
38
39int
40arm64_logimm(uint64_t x, int k)
41{
42 uint64_t n;
43
44 if (k == Kw)
45 x = (x & 0xffffffff) | x << 32;
46 if (x & 1)
47 x = ~x;
48 if (x == 0)
49 return 0;
50 if (x == 0xaaaaaaaaaaaaaaaa)
51 return 1;
52 n = x & 0xf;
53 if (0x1111111111111111 * n == x)
54 goto Check;
55 n = x & 0xff;
56 if (0x0101010101010101 * n == x)
57 goto Check;
58 n = x & 0xffff;
59 if (0x0001000100010001 * n == x)
60 goto Check;
61 n = x & 0xffffffff;
62 if (0x0000000100000001 * n == x)
63 goto Check;
64 n = x;
65Check:
66 return (n & (n + (n & -n))) == 0;
67}
68
69static void
70fixarg(Ref *pr, int k, int phi, Fn *fn)
71{
72 char buf[32];
73 Ref r0, r1, r2;
74 int s, n;
75 Con *c;
76
77 r0 = *pr;
78 switch (rtype(r0)) {
79 case RCon:
80 if (KBASE(k) == 0 && phi)
81 return;
82 r1 = newtmp("isel", k, fn);
83 if (KBASE(k) == 0) {
84 emit(Ocopy, k, r1, r0, R);
85 } else {
86 c = &fn->con[r0.val];
87 n = gasstash(&c->bits, KWIDE(k) ? 8 : 4);
88 vgrow(&fn->con, ++fn->ncon);
89 c = &fn->con[fn->ncon-1];
90 sprintf(buf, "fp%d", n);
91 *c = (Con){.type = CAddr, .local = 1};
92 c->label = intern(buf);
93 r2 = newtmp("isel", Kl, fn);
94 emit(Oload, k, r1, r2, R);
95 emit(Ocopy, Kl, r2, CON(c-fn->con), R);
96 }
97 *pr = r1;
98 break;
99 case RTmp:
100 s = fn->tmp[r0.val].slot;
101 if (s == -1)
102 break;
103 r1 = newtmp("isel", Kl, fn);
104 emit(Oaddr, Kl, r1, SLOT(s), R);
105 *pr = r1;
106 break;
107 }
108}
109
110static int
111selcmp(Ref arg[2], int k, Fn *fn)
112{
113 Ref r, *iarg;
114 Con *c;
115 int swap, cmp, fix;
116 int64_t n;
117
118 if (KBASE(k) == 1) {
119 emit(Oafcmp, k, R, arg[0], arg[1]);
120 iarg = curi->arg;
121 fixarg(&iarg[0], k, 0, fn);
122 fixarg(&iarg[1], k, 0, fn);
123 return 0;
124 }
125 swap = rtype(arg[0]) == RCon;
126 if (swap) {
127 r = arg[1];
128 arg[1] = arg[0];
129 arg[0] = r;
130 }
131 fix = 1;
132 cmp = Oacmp;
133 r = arg[1];
134 if (rtype(r) == RCon) {
135 c = &fn->con[r.val];
136 switch (imm(c, k, &n)) {
137 default:
138 break;
139 case Iplo12:
140 case Iphi12:
141 fix = 0;
142 break;
143 case Inlo12:
144 case Inhi12:
145 cmp = Oacmn;
146 r = getcon(n, fn);
147 fix = 0;
148 break;
149 }
150 }
151 emit(cmp, k, R, arg[0], r);
152 iarg = curi->arg;
153 fixarg(&iarg[0], k, 0, fn);
154 if (fix)
155 fixarg(&iarg[1], k, 0, fn);
156 return swap;
157}
158
159static void
160sel(Ins i, Fn *fn)
161{
162 Ref *iarg;
163 Ins *i0;
164 int ck, cc;
165
166 if (INRANGE(i.op, Oalloc, Oalloc1)) {
167 i0 = curi - 1;
168 salloc(i.to, i.arg[0], fn);
169 fixarg(&i0->arg[0], Kl, 0, fn);
170 return;
171 }
172 if (iscmp(i.op, &ck, &cc)) {
173 emit(Oflag, i.cls, i.to, R, R);
174 i0 = curi;
175 if (selcmp(i.arg, ck, fn))
176 i0->op += cmpop(cc);
177 else
178 i0->op += cc;
179 return;
180 }
181 if (i.op != Onop) {
182 emiti(i);
183 iarg = curi->arg; /* fixarg() can change curi */
184 fixarg(&iarg[0], argcls(&i, 0), 0, fn);
185 fixarg(&iarg[1], argcls(&i, 1), 0, fn);
186 }
187}
188
189static void
190seljmp(Blk *b, Fn *fn)
191{
192 Ref r;
193 Ins *i, *ir;
194 int ck, cc, use;
195
196 switch (b->jmp.type) {
197 default:
198 assert(0 && "TODO 2");
199 break;
200 case Jret0:
201 case Jjmp:
202 return;
203 case Jjnz:
204 break;
205 }
206 r = b->jmp.arg;
207 use = -1;
208 b->jmp.arg = R;
209 ir = 0;
210 i = &b->ins[b->nins];
211 while (i > b->ins)
212 if (req((--i)->to, r)) {
213 use = fn->tmp[r.val].nuse;
214 ir = i;
215 break;
216 }
217 if (ir && use == 1
218 && iscmp(ir->op, &ck, &cc)) {
219 if (selcmp(ir->arg, ck, fn))
220 cc = cmpop(cc);
221 b->jmp.type = Jjf + cc;
222 *ir = (Ins){.op = Onop};
223 }
224 else {
225 selcmp((Ref[]){r, CON_Z}, Kw, fn);
226 b->jmp.type = Jjfine;
227 }
228}
229
230void
231arm64_isel(Fn *fn)
232{
233 Blk *b, **sb;
234 Ins *i;
235 Phi *p;
236 uint n, al;
237 int64_t sz;
238
239 /* assign slots to fast allocs */
240 b = fn->start;
241 /* specific to NAlign == 3 */ /* or change n=4 and sz /= 4 below */
242 for (al=Oalloc, n=4; al<=Oalloc1; al++, n*=2)
243 for (i=b->ins; i<&b->ins[b->nins]; i++)
244 if (i->op == al) {
245 if (rtype(i->arg[0]) != RCon)
246 break;
247 sz = fn->con[i->arg[0].val].bits.i;
248 if (sz < 0 || sz >= INT_MAX-15)
249 err("invalid alloc size %"PRId64, sz);
250 sz = (sz + n-1) & -n;
251 sz /= 4;
252 fn->tmp[i->to.val].slot = fn->slot;
253 fn->slot += sz;
254 *i = (Ins){.op = Onop};
255 }
256
257 for (b=fn->start; b; b=b->link) {
258 curi = &insb[NIns];
259 for (sb=(Blk*[3]){b->s1, b->s2, 0}; *sb; sb++)
260 for (p=(*sb)->phi; p; p=p->link) {
261 for (n=0; p->blk[n] != b; n++)
262 assert(n+1 < p->narg);
263 fixarg(&p->arg[n], p->cls, 1, fn);
264 }
265 seljmp(b, fn);
266 for (i=&b->ins[b->nins]; i!=b->ins;)
267 sel(*--i, fn);
268 b->nins = &insb[NIns] - curi;
269 idup(&b->ins, curi, b->nins);
270 }
271
272 if (debug['I']) {
273 fprintf(stderr, "\n> After instruction selection:\n");
274 printfn(fn, stderr);
275 }
276}
277