1 | #include "all.h" |
2 | |
3 | enum Imm { |
4 | Iother, |
5 | Iplo12, |
6 | Iphi12, |
7 | Iplo24, |
8 | Inlo12, |
9 | Inhi12, |
10 | Inlo24 |
11 | }; |
12 | |
13 | static enum Imm |
14 | imm(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 | |
39 | int |
40 | arm64_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; |
65 | Check: |
66 | return (n & (n + (n & -n))) == 0; |
67 | } |
68 | |
69 | static void |
70 | fixarg(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 | |
110 | static int |
111 | selcmp(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 | |
159 | static void |
160 | sel(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 | |
189 | static void |
190 | seljmp(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 | |
230 | void |
231 | arm64_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 | |