4 Ki
= -1, /* matches Kw and Kl */
5 Ka
= -2, /* matches all classes */
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
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" },
99 static char *rname
[] = {
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",
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",
121 s
= ((int32_t)s
<< 3) >> 3;
122 assert(s
<= fn
->slot
);
126 return -4 * (fn
->slot
- s
);
130 emitaddr(Con
*c
, FILE *f
)
132 assert(c
->reloc
== RelDef
);
133 fputs(str(c
->label
), f
);
135 fprintf(f
, "+%"PRIi64
, c
->bits
.i
);
139 emitf(char *s
, Ins
*i
, Fn
*fn
, FILE *f
)
141 static char clschr
[] = {'w', 'l', 's', 'd'};
150 while ((c
= *s
++) != '%')
156 switch ((c
= *s
++)) {
158 die("invalid escape");
167 fputc(clschr
[i
->cls
], f
);
171 r
= c
== '=' ? i
->to
: i
->arg
[0];
173 fputs(rname
[r
.val
], f
);
179 die("invalid second argument");
182 fputs(rname
[r
.val
], f
);
185 pc
= &fn
->con
[r
.val
];
186 assert(pc
->type
== CBits
);
187 assert(pc
->bits
.i
>= -2048 && pc
->bits
.i
< 2048);
188 fprintf(f
, "%d", (int)pc
->bits
.i
);
194 assert(c
== '0' || c
== '1');
198 die("invalid address argument");
200 fprintf(f
, "0(%s)", rname
[r
.val
]);
203 pc
= &fn
->con
[r
.val
];
204 assert(pc
->type
== CAddr
);
207 || (isload(i
->op
) && KBASE(i
->cls
) == 1)) {
208 /* store (and float load)
209 * pseudo-instructions need a
210 * temporary register in which to
217 offset
= slot(r
.val
, fn
);
218 assert(offset
>= -2048 && offset
<= 2047);
219 fprintf(f
, "%d(fp)", (int)offset
);
228 loadaddr(Con
*c
, char *rn
, FILE *f
)
232 if (c
->reloc
== RelThr
) {
234 sprintf(off
, "+%"PRIi64
, c
->bits
.i
);
237 fprintf(f
, "\tlui %s, %%tprel_hi(%s)%s\n",
238 rn
, str(c
->label
), off
);
239 fprintf(f
, "\tadd %s, %s, tp, %%tprel_add(%s)%s\n",
240 rn
, rn
, str(c
->label
), off
);
241 fprintf(f
, "\taddi %s, %s, %%tprel_lo(%s)%s\n",
242 rn
, rn
, str(c
->label
), off
);
244 fprintf(f
, "\tla %s, ", rn
);
251 loadcon(Con
*c
, int r
, int k
, FILE *f
)
265 fprintf(f
, "\tli %s, %"PRIi64
"\n", rn
, n
);
268 die("invalid constant");
273 fixmem(Ref
*pr
, Fn
*fn
, FILE *f
)
280 if (rtype(r
) == RCon
) {
282 if (c
->type
== CAddr
&& c
->reloc
== RelThr
) {
283 loadcon(c
, T6
, Kl
, f
);
287 if (rtype(r
) == RSlot
) {
289 if (s
< -2048 || s
> 2047) {
290 fprintf(f
, "\tli t6, %"PRId64
"\n", s
);
291 fprintf(f
, "\tadd t6, fp, t6\n");
298 emitins(Ins
*i
, Fn
*fn
, FILE *f
)
308 fixmem(&i
->arg
[0], fn
, f
);
309 else if (isstore(i
->op
))
310 fixmem(&i
->arg
[1], fn
, f
);
312 /* most instructions are just pulled out of
313 * the table omap[], some special cases are
316 /* this linear search should really be a binary
318 if (omap
[o
].op
== NOp
)
319 die("no match for %s(%c)",
320 optab
[i
->op
].name
, "wlsd"[i
->cls
]);
321 if (omap
[o
].op
== i
->op
)
322 if (omap
[o
].cls
== i
->cls
|| omap
[o
].cls
== Ka
323 || (omap
[o
].cls
== Ki
&& KBASE(i
->cls
) == 0))
326 emitf(omap
[o
].asm, i
, fn
, f
);
329 if (req(i
->to
, i
->arg
[0]))
331 if (rtype(i
->to
) == RSlot
) {
332 switch (rtype(i
->arg
[0])) {
335 die("unimplemented");
338 assert(isreg(i
->arg
[0]));
342 case Kw
: i
->op
= Ostorew
; break;
343 case Kl
: i
->op
= Ostorel
; break;
344 case Ks
: i
->op
= Ostores
; break;
345 case Kd
: i
->op
= Ostored
; break;
347 fixmem(&i
->arg
[1], fn
, f
);
352 assert(isreg(i
->to
));
353 switch (rtype(i
->arg
[0])) {
355 loadcon(&fn
->con
[i
->arg
[0].val
], i
->to
.val
, i
->cls
, f
);
359 fixmem(&i
->arg
[0], fn
, f
);
362 assert(isreg(i
->arg
[0]));
369 assert(rtype(i
->arg
[0]) == RSlot
);
370 rn
= rname
[i
->to
.val
];
371 s
= slot(i
->arg
[0].val
, fn
);
373 fprintf(f
, "\tadd %s, fp, %"PRId64
"\n", rn
, s
);
376 "\tli %s, %"PRId64
"\n"
377 "\tadd %s, fp, %s\n",
383 switch (rtype(i
->arg
[0])) {
385 con
= &fn
->con
[i
->arg
[0].val
];
386 if (con
->type
!= CAddr
|| con
->bits
.i
)
388 fprintf(f
, "\tcall %s\n", str(con
->label
));
391 emitf("jalr %0", i
, fn
, f
);
395 die("invalid call argument");
399 emitf("sub sp, sp, %0", i
, fn
, f
);
401 emitf("mv %=, sp", i
, fn
, f
);
416 +-------------+ <- fp
434 rv64_emitfn(Fn
*fn
, FILE *f
)
437 int lbl
, neg
, off
, frame
, *pr
, r
;
441 emitfnlnk(fn
->name
, &fn
->lnk
, f
);
444 /* TODO: only need space for registers
445 * unused by named arguments
447 fprintf(f
, "\tadd sp, sp, -64\n");
448 for (r
=A0
; r
<=A7
; r
++)
451 rname
[r
], 8 * (r
- A0
)
454 fprintf(f
, "\tsd fp, -16(sp)\n");
455 fprintf(f
, "\tsd ra, -8(sp)\n");
456 fprintf(f
, "\tadd fp, sp, -16\n");
458 frame
= (16 + 4 * fn
->slot
+ 15) & ~15;
459 for (pr
=rv64_rclob
; *pr
>=0; pr
++) {
460 if (fn
->reg
& BIT(*pr
))
463 frame
= (frame
+ 15) & ~15;
467 "\tadd sp, sp, -%d\n",
473 "\tsub sp, sp, t6\n",
476 for (pr
=rv64_rclob
, off
=0; *pr
>=0; pr
++) {
477 if (fn
->reg
& BIT(*pr
)) {
480 *pr
< FT0
? "sd" : "fsd",
487 for (lbl
=0, b
=fn
->start
; b
; b
=b
->link
) {
488 if (lbl
|| b
->npred
> 1)
489 fprintf(f
, ".L%d:\n", id0
+b
->id
);
490 for (i
=b
->ins
; i
!=&b
->ins
[b
->nins
]; i
++)
493 switch (b
->jmp
.type
) {
496 if (frame
- 16 <= 2048)
498 "\tadd sp, fp, -%d\n",
504 "\tsub sp, fp, t6\n",
508 for (pr
=rv64_rclob
, off
=0; *pr
>=0; pr
++) {
509 if (fn
->reg
& BIT(*pr
)) {
512 *pr
< FT0
? "ld" : "fld",
528 if (b
->s1
!= b
->link
)
529 fprintf(f
, "\tj .L%d\n", id0
+b
->s1
->id
);
535 if (b
->link
== b
->s2
) {
541 assert(isreg(b
->jmp
.arg
));
545 rname
[b
->jmp
.arg
.val
],