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",
124 assert(s
<= fn
->slot
);
128 return -4 * (fn
->slot
- s
);
132 emitaddr(Con
*c
, FILE *f
)
134 assert(c
->sym
.type
== SGlo
);
135 fputs(str(c
->sym
.id
), f
);
137 fprintf(f
, "+%"PRIi64
, c
->bits
.i
);
141 emitf(char *s
, Ins
*i
, Fn
*fn
, FILE *f
)
143 static char clschr
[] = {'w', 'l', 's', 'd'};
152 while ((c
= *s
++) != '%')
158 switch ((c
= *s
++)) {
160 die("invalid escape");
169 fputc(clschr
[i
->cls
], f
);
173 r
= c
== '=' ? i
->to
: i
->arg
[0];
175 fputs(rname
[r
.val
], f
);
181 die("invalid second argument");
184 fputs(rname
[r
.val
], f
);
187 pc
= &fn
->con
[r
.val
];
188 assert(pc
->type
== CBits
);
189 assert(pc
->bits
.i
>= -2048 && pc
->bits
.i
< 2048);
190 fprintf(f
, "%d", (int)pc
->bits
.i
);
196 assert(c
== '0' || c
== '1');
200 die("invalid address argument");
202 fprintf(f
, "0(%s)", rname
[r
.val
]);
205 pc
= &fn
->con
[r
.val
];
206 assert(pc
->type
== CAddr
);
209 || (isload(i
->op
) && KBASE(i
->cls
) == 1)) {
210 /* store (and float load)
211 * pseudo-instructions need a
212 * temporary register in which to
219 offset
= slot(r
, fn
);
220 assert(offset
>= -2048 && offset
<= 2047);
221 fprintf(f
, "%d(fp)", (int)offset
);
230 loadaddr(Con
*c
, char *rn
, FILE *f
)
234 if (c
->sym
.type
== SThr
) {
236 sprintf(off
, "+%"PRIi64
, c
->bits
.i
);
239 fprintf(f
, "\tlui %s, %%tprel_hi(%s)%s\n",
240 rn
, str(c
->sym
.id
), off
);
241 fprintf(f
, "\tadd %s, %s, tp, %%tprel_add(%s)%s\n",
242 rn
, rn
, str(c
->sym
.id
), off
);
243 fprintf(f
, "\taddi %s, %s, %%tprel_lo(%s)%s\n",
244 rn
, rn
, str(c
->sym
.id
), off
);
246 fprintf(f
, "\tla %s, ", rn
);
253 loadcon(Con
*c
, int r
, int k
, FILE *f
)
267 fprintf(f
, "\tli %s, %"PRIi64
"\n", rn
, n
);
270 die("invalid constant");
275 fixmem(Ref
*pr
, Fn
*fn
, FILE *f
)
282 if (rtype(r
) == RCon
) {
284 if (c
->type
== CAddr
)
285 if (c
->sym
.type
== SThr
) {
286 loadcon(c
, T6
, Kl
, f
);
290 if (rtype(r
) == RSlot
) {
292 if (s
< -2048 || s
> 2047) {
293 fprintf(f
, "\tli t6, %"PRId64
"\n", s
);
294 fprintf(f
, "\tadd t6, fp, t6\n");
301 emitins(Ins
*i
, Fn
*fn
, FILE *f
)
311 fixmem(&i
->arg
[0], fn
, f
);
312 else if (isstore(i
->op
))
313 fixmem(&i
->arg
[1], fn
, f
);
315 /* most instructions are just pulled out of
316 * the table omap[], some special cases are
319 /* this linear search should really be a binary
321 if (omap
[o
].op
== NOp
)
322 die("no match for %s(%c)",
323 optab
[i
->op
].name
, "wlsd"[i
->cls
]);
324 if (omap
[o
].op
== i
->op
)
325 if (omap
[o
].cls
== i
->cls
|| omap
[o
].cls
== Ka
326 || (omap
[o
].cls
== Ki
&& KBASE(i
->cls
) == 0))
329 emitf(omap
[o
].fmt
, i
, fn
, f
);
332 if (req(i
->to
, i
->arg
[0]))
334 if (rtype(i
->to
) == RSlot
) {
335 switch (rtype(i
->arg
[0])) {
338 die("unimplemented");
341 assert(isreg(i
->arg
[0]));
345 case Kw
: i
->op
= Ostorew
; break;
346 case Kl
: i
->op
= Ostorel
; break;
347 case Ks
: i
->op
= Ostores
; break;
348 case Kd
: i
->op
= Ostored
; break;
350 fixmem(&i
->arg
[1], fn
, f
);
355 assert(isreg(i
->to
));
356 switch (rtype(i
->arg
[0])) {
358 loadcon(&fn
->con
[i
->arg
[0].val
], i
->to
.val
, i
->cls
, f
);
362 fixmem(&i
->arg
[0], fn
, f
);
365 assert(isreg(i
->arg
[0]));
372 assert(rtype(i
->arg
[0]) == RSlot
);
373 rn
= rname
[i
->to
.val
];
374 s
= slot(i
->arg
[0], fn
);
376 fprintf(f
, "\tadd %s, fp, %"PRId64
"\n", rn
, s
);
379 "\tli %s, %"PRId64
"\n"
380 "\tadd %s, fp, %s\n",
386 switch (rtype(i
->arg
[0])) {
388 con
= &fn
->con
[i
->arg
[0].val
];
389 if (con
->type
!= CAddr
390 || con
->sym
.type
!= SGlo
393 fprintf(f
, "\tcall %s\n", str(con
->sym
.id
));
396 emitf("jalr %0", i
, fn
, f
);
400 die("invalid call argument");
404 emitf("sub sp, sp, %0", i
, fn
, f
);
406 emitf("mv %=, sp", i
, fn
, f
);
409 emitdbgloc(i
->arg
[0].val
, i
->arg
[1].val
, f
);
424 +-------------+ <- fp
442 rv64_emitfn(Fn
*fn
, FILE *f
)
445 int lbl
, neg
, off
, frame
, *pr
, r
;
449 emitfnlnk(fn
->name
, &fn
->lnk
, f
);
452 /* TODO: only need space for registers
453 * unused by named arguments
455 fprintf(f
, "\tadd sp, sp, -64\n");
456 for (r
=A0
; r
<=A7
; r
++)
459 rname
[r
], 8 * (r
- A0
)
462 fprintf(f
, "\tsd fp, -16(sp)\n");
463 fprintf(f
, "\tsd ra, -8(sp)\n");
464 fprintf(f
, "\tadd fp, sp, -16\n");
466 frame
= (16 + 4 * fn
->slot
+ 15) & ~15;
467 for (pr
=rv64_rclob
; *pr
>=0; pr
++) {
468 if (fn
->reg
& BIT(*pr
))
471 frame
= (frame
+ 15) & ~15;
475 "\tadd sp, sp, -%d\n",
481 "\tsub sp, sp, t6\n",
484 for (pr
=rv64_rclob
, off
=0; *pr
>=0; pr
++) {
485 if (fn
->reg
& BIT(*pr
)) {
488 *pr
< FT0
? "sd" : "fsd",
495 for (lbl
=0, b
=fn
->start
; b
; b
=b
->link
) {
496 if (lbl
|| b
->npred
> 1)
497 fprintf(f
, ".L%d:\n", id0
+b
->id
);
498 for (i
=b
->ins
; i
!=&b
->ins
[b
->nins
]; i
++)
501 switch (b
->jmp
.type
) {
503 fprintf(f
, "\tebreak\n");
507 if (frame
- 16 <= 2048)
509 "\tadd sp, fp, -%d\n",
515 "\tsub sp, fp, t6\n",
519 for (pr
=rv64_rclob
, off
=0; *pr
>=0; pr
++) {
520 if (fn
->reg
& BIT(*pr
)) {
523 *pr
< FT0
? "ld" : "fld",
539 if (b
->s1
!= b
->link
)
540 fprintf(f
, "\tj .L%d\n", id0
+b
->s1
->id
);
546 if (b
->link
== b
->s2
) {
552 assert(isreg(b
->jmp
.arg
));
556 rname
[b
->jmp
.arg
.val
],
563 elf_emitfnfin(fn
->name
, f
);