| 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 |  | 
|---|