| 1 | #include "all.h" | 
|---|
| 2 |  | 
|---|
| 3 | enum { | 
|---|
| 4 | Ki = -1, /* matches Kw and Kl */ | 
|---|
| 5 | Ka = -2, /* matches all classes */ | 
|---|
| 6 | }; | 
|---|
| 7 |  | 
|---|
| 8 | static struct { | 
|---|
| 9 | short op; | 
|---|
| 10 | short cls; | 
|---|
| 11 | char *asm; | 
|---|
| 12 | } omap[] = { | 
|---|
| 13 | { Oadd,    Ki, "add%k %=, %0, %1"}, | 
|---|
| 14 | { Oadd,    Ka, "fadd.%k %=, %0, %1"}, | 
|---|
| 15 | { Osub,    Ki, "sub%k %=, %0, %1"}, | 
|---|
| 16 | { Osub,    Ka, "fsub.%k %=, %0, %1"}, | 
|---|
| 17 | { Oneg,    Ki, "neg%k %=, %0"}, | 
|---|
| 18 | { Oneg,    Ka, "fneg.%k %=, %0"}, | 
|---|
| 19 | { Odiv,    Ki, "div%k %=, %0, %1"}, | 
|---|
| 20 | { Odiv,    Ka, "fdiv.%k %=, %0, %1"}, | 
|---|
| 21 | { Orem,    Ki, "rem%k %=, %0, %1"}, | 
|---|
| 22 | { Orem,    Kl, "rem %=, %0, %1"}, | 
|---|
| 23 | { Oudiv,   Ki, "divu%k %=, %0, %1"}, | 
|---|
| 24 | { Ourem,   Ki, "remu%k %=, %0, %1"}, | 
|---|
| 25 | { Omul,    Ki, "mul%k %=, %0, %1"}, | 
|---|
| 26 | { Omul,    Ka, "fmul.%k %=, %0, %1"}, | 
|---|
| 27 | { Oand,    Ki, "and %=, %0, %1"}, | 
|---|
| 28 | { Oor,     Ki, "or %=, %0, %1"}, | 
|---|
| 29 | { Oxor,    Ki, "xor %=, %0, %1"}, | 
|---|
| 30 | { Osar,    Ki, "sra%k %=, %0, %1"}, | 
|---|
| 31 | { Oshr,    Ki, "srl%k %=, %0, %1"}, | 
|---|
| 32 | { Oshl,    Ki, "sll%k %=, %0, %1"}, | 
|---|
| 33 | { Ocsltl,  Ki, "slt %=, %0, %1"}, | 
|---|
| 34 | { Ocultl,  Ki, "sltu %=, %0, %1"}, | 
|---|
| 35 | { Oceqs,   Ki, "feq.s %=, %0, %1"}, | 
|---|
| 36 | { Ocges,   Ki, "fge.s %=, %0, %1"}, | 
|---|
| 37 | { Ocgts,   Ki, "fgt.s %=, %0, %1"}, | 
|---|
| 38 | { Ocles,   Ki, "fle.s %=, %0, %1"}, | 
|---|
| 39 | { Oclts,   Ki, "flt.s %=, %0, %1"}, | 
|---|
| 40 | { Oceqd,   Ki, "feq.d %=, %0, %1"}, | 
|---|
| 41 | { Ocged,   Ki, "fge.d %=, %0, %1"}, | 
|---|
| 42 | { Ocgtd,   Ki, "fgt.d %=, %0, %1"}, | 
|---|
| 43 | { Ocled,   Ki, "fle.d %=, %0, %1"}, | 
|---|
| 44 | { Ocltd,   Ki, "flt.d %=, %0, %1"}, | 
|---|
| 45 | { Ostoreb, Kw, "sb %0, %M1"}, | 
|---|
| 46 | { Ostoreh, Kw, "sh %0, %M1"}, | 
|---|
| 47 | { Ostorew, Kw, "sw %0, %M1"}, | 
|---|
| 48 | { Ostorel, Ki, "sd %0, %M1"}, | 
|---|
| 49 | { Ostores, Kw, "fsw %0, %M1"}, | 
|---|
| 50 | { Ostored, Kw, "fsd %0, %M1"}, | 
|---|
| 51 | { Oloadsb, Ki, "lb %=, %M0"}, | 
|---|
| 52 | { Oloadub, Ki, "lbu %=, %M0"}, | 
|---|
| 53 | { Oloadsh, Ki, "lh %=, %M0"}, | 
|---|
| 54 | { Oloaduh, Ki, "lhu %=, %M0"}, | 
|---|
| 55 | { Oloadsw, Ki, "lw %=, %M0"}, | 
|---|
| 56 | /* riscv64 always sign-extends 32-bit | 
|---|
| 57 | * values stored in 64-bit registers | 
|---|
| 58 | */ | 
|---|
| 59 | { Oloaduw, Kw, "lw %=, %M0"}, | 
|---|
| 60 | { Oloaduw, Kl, "lwu %=, %M0"}, | 
|---|
| 61 | { Oload,   Kw, "lw %=, %M0"}, | 
|---|
| 62 | { Oload,   Kl, "ld %=, %M0"}, | 
|---|
| 63 | { Oload,   Ks, "flw %=, %M0"}, | 
|---|
| 64 | { Oload,   Kd, "fld %=, %M0"}, | 
|---|
| 65 | { Oextsb,  Ki, "sext.b %=, %0"}, | 
|---|
| 66 | { Oextub,  Ki, "zext.b %=, %0"}, | 
|---|
| 67 | { Oextsh,  Ki, "sext.h %=, %0"}, | 
|---|
| 68 | { Oextuh,  Ki, "zext.h %=, %0"}, | 
|---|
| 69 | { Oextsw,  Kl, "sext.w %=, %0"}, | 
|---|
| 70 | { Oextuw,  Kl, "zext.w %=, %0"}, | 
|---|
| 71 | { Otruncd, Ks, "fcvt.s.d %=, %0"}, | 
|---|
| 72 | { Oexts,   Kd, "fcvt.d.s %=, %0"}, | 
|---|
| 73 | { Ostosi,  Kw, "fcvt.w.s %=, %0, rtz"}, | 
|---|
| 74 | { Ostosi,  Kl, "fcvt.l.s %=, %0, rtz"}, | 
|---|
| 75 | { Ostoui,  Kw, "fcvt.wu.s %=, %0, rtz"}, | 
|---|
| 76 | { Ostoui,  Kl, "fcvt.lu.s %=, %0, rtz"}, | 
|---|
| 77 | { Odtosi,  Kw, "fcvt.w.d %=, %0, rtz"}, | 
|---|
| 78 | { Odtosi,  Kl, "fcvt.l.d %=, %0, rtz"}, | 
|---|
| 79 | { Odtoui,  Kw, "fcvt.wu.d %=, %0, rtz"}, | 
|---|
| 80 | { Odtoui,  Kl, "fcvt.lu.d %=, %0, rtz"}, | 
|---|
| 81 | { Oswtof,  Ka, "fcvt.%k.w %=, %0"}, | 
|---|
| 82 | { Ouwtof,  Ka, "fcvt.%k.wu %=, %0"}, | 
|---|
| 83 | { Osltof,  Ka, "fcvt.%k.l %=, %0"}, | 
|---|
| 84 | { Oultof,  Ka, "fcvt.%k.lu %=, %0"}, | 
|---|
| 85 | { Ocast,   Kw, "fmv.x.w %=, %0"}, | 
|---|
| 86 | { Ocast,   Kl, "fmv.x.d %=, %0"}, | 
|---|
| 87 | { Ocast,   Ks, "fmv.w.x %=, %0"}, | 
|---|
| 88 | { Ocast,   Kd, "fmv.d.x %=, %0"}, | 
|---|
| 89 | { Ocopy,   Ki, "mv %=, %0"}, | 
|---|
| 90 | { Ocopy,   Ka, "fmv.%k %=, %0"}, | 
|---|
| 91 | { Oswap,   Ki, "mv %?, %0\n\tmv %0, %1\n\tmv %1, %?"}, | 
|---|
| 92 | { Oswap,   Ka, "fmv.%k %?, %0\n\tfmv.%k %0, %1\n\tfmv.%k %1, %?"}, | 
|---|
| 93 | { Oreqz,   Ki, "seqz %=, %0"}, | 
|---|
| 94 | { Ornez,   Ki, "snez %=, %0"}, | 
|---|
| 95 | { Ocall,   Kw, "jalr %0"}, | 
|---|
| 96 | { NOp, 0, 0 } | 
|---|
| 97 | }; | 
|---|
| 98 |  | 
|---|
| 99 | static char *rname[] = { | 
|---|
| 100 | [FP] = "fp", | 
|---|
| 101 | [SP] = "sp", | 
|---|
| 102 | [GP] = "gp", | 
|---|
| 103 | [TP] = "tp", | 
|---|
| 104 | [RA] = "ra", | 
|---|
| 105 | [T0] = "t0", "t1", "t2", "t3", "t4", "t5", | 
|---|
| 106 | [A0] = "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", | 
|---|
| 107 | [S1] = "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", | 
|---|
| 108 | "s9", "s10", "s11", | 
|---|
| 109 | [FT0] = "ft0", "ft1", "ft2", "ft3", "ft4", "ft5", "ft6", "ft7", | 
|---|
| 110 | "ft8", "ft9", "ft10", | 
|---|
| 111 | [FA0] = "fa0", "fa1", "fa2", "fa3", "fa4", "fa5", "fa6", "fa7", | 
|---|
| 112 | [FS0] = "fs0", "fs1", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7", | 
|---|
| 113 | "fs8", "fs9", "fs10", "fs11", | 
|---|
| 114 | [T6] = "t6", | 
|---|
| 115 | [FT11] = "ft11", | 
|---|
| 116 | }; | 
|---|
| 117 |  | 
|---|
| 118 | static int64_t | 
|---|
| 119 | slot(int s, Fn *fn) | 
|---|
| 120 | { | 
|---|
| 121 | s = ((int32_t)s << 3) >> 3; | 
|---|
| 122 | assert(s <= fn->slot); | 
|---|
| 123 | if (s < 0) | 
|---|
| 124 | return 8 * -s; | 
|---|
| 125 | else | 
|---|
| 126 | return -4 * (fn->slot - s); | 
|---|
| 127 | } | 
|---|
| 128 |  | 
|---|
| 129 | static void | 
|---|
| 130 | emitaddr(Con *c, FILE *f) | 
|---|
| 131 | { | 
|---|
| 132 | char off[32], *p; | 
|---|
| 133 |  | 
|---|
| 134 | if (c->bits.i) | 
|---|
| 135 | sprintf(off, "+%"PRIi64, c->bits.i); | 
|---|
| 136 | else | 
|---|
| 137 | off[0] = 0; | 
|---|
| 138 | p = c->local ? ".L": ""; | 
|---|
| 139 | fprintf(f, "%s%s%s", p, str(c->label), off); | 
|---|
| 140 | } | 
|---|
| 141 |  | 
|---|
| 142 | static void | 
|---|
| 143 | emitf(char *s, Ins *i, Fn *fn, FILE *f) | 
|---|
| 144 | { | 
|---|
| 145 | static char clschr[] = {'w', 'l', 's', 'd'}; | 
|---|
| 146 | Ref r; | 
|---|
| 147 | int k, c; | 
|---|
| 148 | Con *pc; | 
|---|
| 149 | int64_t offset; | 
|---|
| 150 |  | 
|---|
| 151 | fputc('\t', f); | 
|---|
| 152 | for (;;) { | 
|---|
| 153 | k = i->cls; | 
|---|
| 154 | while ((c = *s++) != '%') | 
|---|
| 155 | if (!c) { | 
|---|
| 156 | fputc('\n', f); | 
|---|
| 157 | return; | 
|---|
| 158 | } else | 
|---|
| 159 | fputc(c, f); | 
|---|
| 160 | switch ((c = *s++)) { | 
|---|
| 161 | default: | 
|---|
| 162 | die( "invalid escape"); | 
|---|
| 163 | case '?': | 
|---|
| 164 | if (KBASE(k) == 0) | 
|---|
| 165 | fputs( "t6", f); | 
|---|
| 166 | else | 
|---|
| 167 | fputs( "ft11", f); | 
|---|
| 168 | break; | 
|---|
| 169 | case 'k': | 
|---|
| 170 | if (i->cls != Kl) | 
|---|
| 171 | fputc(clschr[i->cls], f); | 
|---|
| 172 | break; | 
|---|
| 173 | case '=': | 
|---|
| 174 | case '0': | 
|---|
| 175 | r = c == '=' ? i->to : i->arg[0]; | 
|---|
| 176 | assert(isreg(r)); | 
|---|
| 177 | fputs(rname[r.val], f); | 
|---|
| 178 | break; | 
|---|
| 179 | case '1': | 
|---|
| 180 | r = i->arg[1]; | 
|---|
| 181 | switch (rtype(r)) { | 
|---|
| 182 | default: | 
|---|
| 183 | die( "invalid second argument"); | 
|---|
| 184 | case RTmp: | 
|---|
| 185 | assert(isreg(r)); | 
|---|
| 186 | fputs(rname[r.val], f); | 
|---|
| 187 | break; | 
|---|
| 188 | case RCon: | 
|---|
| 189 | pc = &fn->con[r.val]; | 
|---|
| 190 | assert(pc->type == CBits); | 
|---|
| 191 | assert(pc->bits.i >= -2048 && pc->bits.i < 2048); | 
|---|
| 192 | fprintf(f, "%d", (int)pc->bits.i); | 
|---|
| 193 | break; | 
|---|
| 194 | } | 
|---|
| 195 | break; | 
|---|
| 196 | case 'M': | 
|---|
| 197 | c = *s++; | 
|---|
| 198 | assert(c == '0' || c == '1'); | 
|---|
| 199 | r = i->arg[c - '0']; | 
|---|
| 200 | switch (rtype(r)) { | 
|---|
| 201 | default: | 
|---|
| 202 | die( "invalid address argument"); | 
|---|
| 203 | case RTmp: | 
|---|
| 204 | fprintf(f, "0(%s)", rname[r.val]); | 
|---|
| 205 | break; | 
|---|
| 206 | case RCon: | 
|---|
| 207 | pc = &fn->con[r.val]; | 
|---|
| 208 | assert(pc->type == CAddr); | 
|---|
| 209 | emitaddr(pc, f); | 
|---|
| 210 | if (isstore(i->op) | 
|---|
| 211 | || (isload(i->op) && KBASE(i->cls) == 1)) { | 
|---|
| 212 | /* store (and float load) | 
|---|
| 213 | * pseudo-instructions need a | 
|---|
| 214 | * temporary register in which to | 
|---|
| 215 | * load the address | 
|---|
| 216 | */ | 
|---|
| 217 | fprintf(f, ", t6"); | 
|---|
| 218 | } | 
|---|
| 219 | break; | 
|---|
| 220 | case RSlot: | 
|---|
| 221 | offset = slot(r.val, fn); | 
|---|
| 222 | assert(offset >= -2048 && offset <= 2047); | 
|---|
| 223 | fprintf(f, "%d(fp)", (int)offset); | 
|---|
| 224 | break; | 
|---|
| 225 | } | 
|---|
| 226 | break; | 
|---|
| 227 | } | 
|---|
| 228 | } | 
|---|
| 229 | } | 
|---|
| 230 |  | 
|---|
| 231 | static void | 
|---|
| 232 | loadcon(Con *c, int r, int k, FILE *f) | 
|---|
| 233 | { | 
|---|
| 234 | char *rn; | 
|---|
| 235 | int64_t n; | 
|---|
| 236 | int w; | 
|---|
| 237 |  | 
|---|
| 238 | w = KWIDE(k); | 
|---|
| 239 | rn = rname[r]; | 
|---|
| 240 | switch (c->type) { | 
|---|
| 241 | case CAddr: | 
|---|
| 242 | fprintf(f, "\tla %s, ", rn); | 
|---|
| 243 | emitaddr(c, f); | 
|---|
| 244 | fputc('\n', f); | 
|---|
| 245 | break; | 
|---|
| 246 | case CBits: | 
|---|
| 247 | n = c->bits.i; | 
|---|
| 248 | if (!w) | 
|---|
| 249 | n = (int32_t)n; | 
|---|
| 250 | fprintf(f, "\tli %s, %"PRIu64 "\n", rn, n); | 
|---|
| 251 | break; | 
|---|
| 252 | default: | 
|---|
| 253 | die( "invalid constant"); | 
|---|
| 254 | } | 
|---|
| 255 | } | 
|---|
| 256 |  | 
|---|
| 257 | static void | 
|---|
| 258 | fixslot(Ref *pr, Fn *fn, FILE *f) | 
|---|
| 259 | { | 
|---|
| 260 | Ref r; | 
|---|
| 261 | int64_t s; | 
|---|
| 262 |  | 
|---|
| 263 | r = *pr; | 
|---|
| 264 | if (rtype(r) == RSlot) { | 
|---|
| 265 | s = slot(r.val, fn); | 
|---|
| 266 | if (s < -2048 || s > 2047) { | 
|---|
| 267 | fprintf(f, "\tli t6, %"PRId64 "\n", s); | 
|---|
| 268 | fprintf(f, "\tadd t6, fp, t6\n"); | 
|---|
| 269 | *pr = TMP(T6); | 
|---|
| 270 | } | 
|---|
| 271 | } | 
|---|
| 272 | } | 
|---|
| 273 |  | 
|---|
| 274 | static void | 
|---|
| 275 | emitins(Ins *i, Fn *fn, FILE *f) | 
|---|
| 276 | { | 
|---|
| 277 | int o; | 
|---|
| 278 | char *rn; | 
|---|
| 279 | int64_t s; | 
|---|
| 280 | Con *con; | 
|---|
| 281 |  | 
|---|
| 282 | switch (i->op) { | 
|---|
| 283 | default: | 
|---|
| 284 | if (isload(i->op)) | 
|---|
| 285 | fixslot(&i->arg[0], fn, f); | 
|---|
| 286 | else if (isstore(i->op)) | 
|---|
| 287 | fixslot(&i->arg[1], fn, f); | 
|---|
| 288 | Table: | 
|---|
| 289 | /* most instructions are just pulled out of | 
|---|
| 290 | * the table omap[], some special cases are | 
|---|
| 291 | * detailed below */ | 
|---|
| 292 | for (o=0;; o++) { | 
|---|
| 293 | /* this linear search should really be a binary | 
|---|
| 294 | * search */ | 
|---|
| 295 | if (omap[o].op == NOp) | 
|---|
| 296 | die( "no match for %s(%c)", | 
|---|
| 297 | optab[i->op].name, "wlsd"[i->cls]); | 
|---|
| 298 | if (omap[o].op == i->op) | 
|---|
| 299 | if (omap[o].cls == i->cls || omap[o].cls == Ka | 
|---|
| 300 | || (omap[o].cls == Ki && KBASE(i->cls) == 0)) | 
|---|
| 301 | break; | 
|---|
| 302 | } | 
|---|
| 303 | emitf(omap[o].asm, i, fn, f); | 
|---|
| 304 | break; | 
|---|
| 305 | case Ocopy: | 
|---|
| 306 | if (req(i->to, i->arg[0])) | 
|---|
| 307 | break; | 
|---|
| 308 | if (rtype(i->to) == RSlot) { | 
|---|
| 309 | switch (rtype(i->arg[0])) { | 
|---|
| 310 | case RSlot: | 
|---|
| 311 | case RCon: | 
|---|
| 312 | die( "unimplemented"); | 
|---|
| 313 | break; | 
|---|
| 314 | default: | 
|---|
| 315 | assert(isreg(i->arg[0])); | 
|---|
| 316 | i->arg[1] = i->to; | 
|---|
| 317 | i->to = R; | 
|---|
| 318 | switch (i->cls) { | 
|---|
| 319 | case Kw: i->op = Ostorew; break; | 
|---|
| 320 | case Kl: i->op = Ostorel; break; | 
|---|
| 321 | case Ks: i->op = Ostores; break; | 
|---|
| 322 | case Kd: i->op = Ostored; break; | 
|---|
| 323 | } | 
|---|
| 324 | fixslot(&i->arg[1], fn, f); | 
|---|
| 325 | goto Table; | 
|---|
| 326 | } | 
|---|
| 327 | break; | 
|---|
| 328 | } | 
|---|
| 329 | assert(isreg(i->to)); | 
|---|
| 330 | switch (rtype(i->arg[0])) { | 
|---|
| 331 | case RCon: | 
|---|
| 332 | loadcon(&fn->con[i->arg[0].val], i->to.val, i->cls, f); | 
|---|
| 333 | break; | 
|---|
| 334 | case RSlot: | 
|---|
| 335 | i->op = Oload; | 
|---|
| 336 | fixslot(&i->arg[0], fn, f); | 
|---|
| 337 | goto Table; | 
|---|
| 338 | default: | 
|---|
| 339 | assert(isreg(i->arg[0])); | 
|---|
| 340 | goto Table; | 
|---|
| 341 | } | 
|---|
| 342 | break; | 
|---|
| 343 | case Onop: | 
|---|
| 344 | break; | 
|---|
| 345 | case Oaddr: | 
|---|
| 346 | assert(rtype(i->arg[0]) == RSlot); | 
|---|
| 347 | rn = rname[i->to.val]; | 
|---|
| 348 | s = slot(i->arg[0].val, fn); | 
|---|
| 349 | if (-s < 2048) { | 
|---|
| 350 | fprintf(f, "\tadd %s, fp, %"PRId64 "\n", rn, s); | 
|---|
| 351 | } else { | 
|---|
| 352 | fprintf(f, | 
|---|
| 353 | "\tli %s, %"PRId64 "\n" | 
|---|
| 354 | "\tadd %s, fp, %s\n", | 
|---|
| 355 | rn, s, rn, rn | 
|---|
| 356 | ); | 
|---|
| 357 | } | 
|---|
| 358 | break; | 
|---|
| 359 | case Ocall: | 
|---|
| 360 | switch (rtype(i->arg[0])) { | 
|---|
| 361 | case RCon: | 
|---|
| 362 | con = &fn->con[i->arg[0].val]; | 
|---|
| 363 | if (con->type != CAddr || con->bits.i) | 
|---|
| 364 | goto invalid; | 
|---|
| 365 | fprintf(f, "\tcall %s\n", str(con->label)); | 
|---|
| 366 | break; | 
|---|
| 367 | case RTmp: | 
|---|
| 368 | emitf( "jalr %0", i, fn, f); | 
|---|
| 369 | break; | 
|---|
| 370 | default: | 
|---|
| 371 | invalid: | 
|---|
| 372 | die( "invalid call argument"); | 
|---|
| 373 | } | 
|---|
| 374 | break; | 
|---|
| 375 | case Osalloc: | 
|---|
| 376 | emitf( "sub sp, sp, %0", i, fn, f); | 
|---|
| 377 | if (!req(i->to, R)) | 
|---|
| 378 | emitf( "mv %=, sp", i, fn, f); | 
|---|
| 379 | break; | 
|---|
| 380 | } | 
|---|
| 381 | } | 
|---|
| 382 |  | 
|---|
| 383 | /* | 
|---|
| 384 |  | 
|---|
| 385 | Stack-frame layout: | 
|---|
| 386 |  | 
|---|
| 387 | +=============+ | 
|---|
| 388 | | varargs     | | 
|---|
| 389 | |  save area  | | 
|---|
| 390 | +-------------+ | 
|---|
| 391 | |  saved ra   | | 
|---|
| 392 | |  saved fp   | | 
|---|
| 393 | +-------------+ <- fp | 
|---|
| 394 | |    ...      | | 
|---|
| 395 | | spill slots | | 
|---|
| 396 | |    ...      | | 
|---|
| 397 | +-------------+ | 
|---|
| 398 | |    ...      | | 
|---|
| 399 | |   locals    | | 
|---|
| 400 | |    ...      | | 
|---|
| 401 | +-------------+ | 
|---|
| 402 | |   padding   | | 
|---|
| 403 | +-------------+ | 
|---|
| 404 | | callee-save | | 
|---|
| 405 | |  registers  | | 
|---|
| 406 | +=============+ | 
|---|
| 407 |  | 
|---|
| 408 | */ | 
|---|
| 409 |  | 
|---|
| 410 | void | 
|---|
| 411 | rv64_emitfn(Fn *fn, FILE *f) | 
|---|
| 412 | { | 
|---|
| 413 | static int id0; | 
|---|
| 414 | int lbl, neg, off, frame, *pr, r; | 
|---|
| 415 | Blk *b, *s; | 
|---|
| 416 | Ins *i; | 
|---|
| 417 |  | 
|---|
| 418 | gasemitlnk(fn->name, &fn->lnk, ".text", f); | 
|---|
| 419 |  | 
|---|
| 420 | if (fn->vararg) { | 
|---|
| 421 | /* TODO: only need space for registers | 
|---|
| 422 | * unused by named arguments | 
|---|
| 423 | */ | 
|---|
| 424 | fprintf(f, "\tadd sp, sp, -64\n"); | 
|---|
| 425 | for (r=A0; r<=A7; r++) | 
|---|
| 426 | fprintf(f, | 
|---|
| 427 | "\tsd %s, %d(sp)\n", | 
|---|
| 428 | rname[r], 8 * (r - A0) | 
|---|
| 429 | ); | 
|---|
| 430 | } | 
|---|
| 431 | fprintf(f, "\tsd fp, -16(sp)\n"); | 
|---|
| 432 | fprintf(f, "\tsd ra, -8(sp)\n"); | 
|---|
| 433 | fprintf(f, "\tadd fp, sp, -16\n"); | 
|---|
| 434 |  | 
|---|
| 435 | frame = (16 + 4 * fn->slot + 15) & ~15; | 
|---|
| 436 | for (pr=rv64_rclob; *pr>=0; pr++) { | 
|---|
| 437 | if (fn->reg & BIT(*pr)) | 
|---|
| 438 | frame += 8; | 
|---|
| 439 | } | 
|---|
| 440 | frame = (frame + 15) & ~15; | 
|---|
| 441 |  | 
|---|
| 442 | if (frame <= 2048) | 
|---|
| 443 | fprintf(f, | 
|---|
| 444 | "\tadd sp, sp, -%d\n", | 
|---|
| 445 | frame | 
|---|
| 446 | ); | 
|---|
| 447 | else | 
|---|
| 448 | fprintf(f, | 
|---|
| 449 | "\tli t6, %d\n" | 
|---|
| 450 | "\tsub sp, sp, t6\n", | 
|---|
| 451 | frame | 
|---|
| 452 | ); | 
|---|
| 453 | for (pr=rv64_rclob, off=0; *pr>=0; pr++) { | 
|---|
| 454 | if (fn->reg & BIT(*pr)) { | 
|---|
| 455 | fprintf(f, | 
|---|
| 456 | "\t%s %s, %d(sp)\n", | 
|---|
| 457 | *pr < FT0 ? "sd": "fsd", | 
|---|
| 458 | rname[*pr], off | 
|---|
| 459 | ); | 
|---|
| 460 | off += 8; | 
|---|
| 461 | } | 
|---|
| 462 | } | 
|---|
| 463 |  | 
|---|
| 464 | for (lbl=0, b=fn->start; b; b=b->link) { | 
|---|
| 465 | if (lbl || b->npred > 1) | 
|---|
| 466 | fprintf(f, ".L%d:\n", id0+b->id); | 
|---|
| 467 | for (i=b->ins; i!=&b->ins[b->nins]; i++) | 
|---|
| 468 | emitins(i, fn, f); | 
|---|
| 469 | lbl = 1; | 
|---|
| 470 | switch (b->jmp.type) { | 
|---|
| 471 | case Jret0: | 
|---|
| 472 | if (fn->dynalloc) { | 
|---|
| 473 | if (frame - 16 <= 2048) | 
|---|
| 474 | fprintf(f, | 
|---|
| 475 | "\tadd sp, fp, -%d\n", | 
|---|
| 476 | frame - 16 | 
|---|
| 477 | ); | 
|---|
| 478 | else | 
|---|
| 479 | fprintf(f, | 
|---|
| 480 | "\tli t6, %d\n" | 
|---|
| 481 | "\tsub sp, fp, t6\n", | 
|---|
| 482 | frame - 16 | 
|---|
| 483 | ); | 
|---|
| 484 | } | 
|---|
| 485 | for (pr=rv64_rclob, off=0; *pr>=0; pr++) { | 
|---|
| 486 | if (fn->reg & BIT(*pr)) { | 
|---|
| 487 | fprintf(f, | 
|---|
| 488 | "\t%s %s, %d(sp)\n", | 
|---|
| 489 | *pr < FT0 ? "ld": "fld", | 
|---|
| 490 | rname[*pr], off | 
|---|
| 491 | ); | 
|---|
| 492 | off += 8; | 
|---|
| 493 | } | 
|---|
| 494 | } | 
|---|
| 495 | fprintf(f, | 
|---|
| 496 | "\tadd sp, fp, %d\n" | 
|---|
| 497 | "\tld ra, 8(fp)\n" | 
|---|
| 498 | "\tld fp, 0(fp)\n" | 
|---|
| 499 | "\tret\n", | 
|---|
| 500 | 16 + fn->vararg * 64 | 
|---|
| 501 | ); | 
|---|
| 502 | break; | 
|---|
| 503 | case Jjmp: | 
|---|
| 504 | Jmp: | 
|---|
| 505 | if (b->s1 != b->link) | 
|---|
| 506 | fprintf(f, "\tj .L%d\n", id0+b->s1->id); | 
|---|
| 507 | else | 
|---|
| 508 | lbl = 0; | 
|---|
| 509 | break; | 
|---|
| 510 | case Jjnz: | 
|---|
| 511 | neg = 0; | 
|---|
| 512 | if (b->link == b->s2) { | 
|---|
| 513 | s = b->s1; | 
|---|
| 514 | b->s1 = b->s2; | 
|---|
| 515 | b->s2 = s; | 
|---|
| 516 | neg = 1; | 
|---|
| 517 | } | 
|---|
| 518 | assert(isreg(b->jmp.arg)); | 
|---|
| 519 | fprintf(f, | 
|---|
| 520 | "\tb%sz %s, .L%d\n", | 
|---|
| 521 | neg ? "ne": "eq", | 
|---|
| 522 | rname[b->jmp.arg.val], | 
|---|
| 523 | id0+b->s2->id | 
|---|
| 524 | ); | 
|---|
| 525 | goto Jmp; | 
|---|
| 526 | } | 
|---|
| 527 | } | 
|---|
| 528 | id0 += fn->nblk; | 
|---|
| 529 | } | 
|---|
| 530 |  | 
|---|