make variadic args explicit
[qbe.git] / arm64 / isel.c
blob031ba11e8db626ce365bccdeda59a71b4a36cd58
1 #include "all.h"
3 enum Imm {
4 Iother,
5 Iplo12,
6 Iphi12,
7 Iplo24,
8 Inlo12,
9 Inhi12,
10 Inlo24
13 static enum Imm
14 imm(Con *c, int k, int64_t *pn)
16 int64_t n;
17 int i;
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;
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;
39 int
40 arm64_logimm(uint64_t x, int k)
42 uint64_t n;
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;
65 Check:
66 return (n & (n + (n & -n))) == 0;
69 static void
70 fixarg(Ref *pr, int k, int phi, Fn *fn)
72 char buf[32];
73 Ref r0, r1, r2;
74 int s, n;
75 Con *c;
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);
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;
110 static int
111 selcmp(Ref arg[2], int k, Fn *fn)
113 Ref r, *iarg;
114 Con *c;
115 int swap, cmp, fix;
116 int64_t n;
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;
125 swap = rtype(arg[0]) == RCon;
126 if (swap) {
127 r = arg[1];
128 arg[1] = arg[0];
129 arg[0] = r;
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;
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;
159 static void
160 sel(Ins i, Fn *fn)
162 Ref *iarg;
163 Ins *i0;
164 int ck, cc;
166 if (iscmp(i.op, &ck, &cc)) {
167 emit(Oflag, i.cls, i.to, R, R);
168 i0 = curi;
169 if (selcmp(i.arg, ck, fn))
170 i0->op += cmpop(cc);
171 else
172 i0->op += cc;
173 } else if (i.op != Onop) {
174 emiti(i);
175 iarg = curi->arg; /* fixarg() can change curi */
176 fixarg(&iarg[0], argcls(&i, 0), 0, fn);
177 fixarg(&iarg[1], argcls(&i, 1), 0, fn);
181 static void
182 seljmp(Blk *b, Fn *fn)
184 Ref r;
185 Ins *i, *ir;
186 int ck, cc, use;
188 switch (b->jmp.type) {
189 default:
190 assert(0 && "TODO 2");
191 break;
192 case Jret0:
193 case Jjmp:
194 return;
195 case Jjnz:
196 break;
198 r = b->jmp.arg;
199 use = -1;
200 b->jmp.arg = R;
201 ir = 0;
202 i = &b->ins[b->nins];
203 while (i > b->ins)
204 if (req((--i)->to, r)) {
205 use = fn->tmp[r.val].nuse;
206 ir = i;
207 break;
209 if (ir && use == 1
210 && iscmp(ir->op, &ck, &cc)) {
211 if (selcmp(ir->arg, ck, fn))
212 cc = cmpop(cc);
213 b->jmp.type = Jjf + cc;
214 *ir = (Ins){.op = Onop};
216 else {
217 selcmp((Ref[]){r, CON_Z}, Kw, fn);
218 b->jmp.type = Jjfine;
222 void
223 arm64_isel(Fn *fn)
225 Blk *b, **sb;
226 Ins *i;
227 Phi *p;
228 uint n, al;
229 int64_t sz;
231 /* assign slots to fast allocs */
232 b = fn->start;
233 /* specific to NAlign == 3 */ /* or change n=4 and sz /= 4 below */
234 for (al=Oalloc, n=4; al<=Oalloc1; al++, n*=2)
235 for (i=b->ins; i<&b->ins[b->nins]; i++)
236 if (i->op == al) {
237 if (rtype(i->arg[0]) != RCon)
238 break;
239 sz = fn->con[i->arg[0].val].bits.i;
240 if (sz < 0 || sz >= INT_MAX-15)
241 err("invalid alloc size %"PRId64, sz);
242 sz = (sz + n-1) & -n;
243 sz /= 4;
244 fn->tmp[i->to.val].slot = fn->slot;
245 fn->slot += sz;
246 *i = (Ins){.op = Onop};
249 for (b=fn->start; b; b=b->link) {
250 curi = &insb[NIns];
251 for (sb=(Blk*[3]){b->s1, b->s2, 0}; *sb; sb++)
252 for (p=(*sb)->phi; p; p=p->link) {
253 for (n=0; p->blk[n] != b; n++)
254 assert(n+1 < p->narg);
255 fixarg(&p->arg[n], p->cls, 1, fn);
257 seljmp(b, fn);
258 for (i=&b->ins[b->nins]; i!=b->ins;)
259 sel(*--i, fn);
260 b->nins = &insb[NIns] - curi;
261 idup(&b->ins, curi, b->nins);
264 if (debug['I']) {
265 fprintf(stderr, "\n> After instruction selection:\n");
266 printfn(fn, stderr);