75a16d83c423c4543af6247f9c522f51e51f8f7a
[platform/upstream/dotnet/runtime.git] / src / coreclr / jit / emitriscv64.cpp
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3
4 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
5 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6 XX                                                                           XX
7 XX                             emitriscv64.cpp                               XX
8 XX                                                                           XX
9 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
11 */
12
13 #include "jitpch.h"
14 #ifdef _MSC_VER
15 #pragma hdrstop
16 #endif
17
18 #if defined(TARGET_RISCV64)
19
20 /*****************************************************************************/
21 /*****************************************************************************/
22
23 #include "instr.h"
24 #include "emit.h"
25 #include "codegen.h"
26
27 /*****************************************************************************/
28
29 const instruction emitJumpKindInstructions[] = {
30     INS_nop,
31
32 #define JMP_SMALL(en, rev, ins) INS_##ins,
33 #include "emitjmps.h"
34 };
35
36 const emitJumpKind emitReverseJumpKinds[] = {
37     EJ_NONE,
38
39 #define JMP_SMALL(en, rev, ins) EJ_##rev,
40 #include "emitjmps.h"
41 };
42
43 /*****************************************************************************
44  * Look up the instruction for a jump kind
45  */
46
47 /*static*/ instruction emitter::emitJumpKindToIns(emitJumpKind jumpKind)
48 {
49     assert((unsigned)jumpKind < ArrLen(emitJumpKindInstructions));
50     return emitJumpKindInstructions[jumpKind];
51 }
52
53 /*****************************************************************************
54  * Reverse the conditional jump
55  */
56
57 /*static*/ emitJumpKind emitter::emitReverseJumpKind(emitJumpKind jumpKind)
58 {
59     assert(jumpKind < EJ_COUNT);
60     return emitReverseJumpKinds[jumpKind];
61 }
62
63 /*****************************************************************************
64  *
65  *  Return the allocated size (in bytes) of the given instruction descriptor.
66  */
67
68 size_t emitter::emitSizeOfInsDsc(instrDesc* id) const
69 {
70     if (emitIsSmallInsDsc(id))
71         return SMALL_IDSC_SIZE;
72
73     insOpts insOp = id->idInsOpt();
74
75     switch (insOp)
76     {
77         case INS_OPTS_JALR:
78         case INS_OPTS_J_cond:
79         case INS_OPTS_J:
80             return sizeof(instrDescJmp);
81
82         case INS_OPTS_C:
83             if (id->idIsLargeCall())
84             {
85                 /* Must be a "fat" call descriptor */
86                 return sizeof(instrDescCGCA);
87             }
88             else
89             {
90                 assert(!id->idIsLargeDsp());
91                 assert(!id->idIsLargeCns());
92                 return sizeof(instrDesc);
93             }
94
95         case INS_OPTS_I:
96         case INS_OPTS_RC:
97         case INS_OPTS_RL:
98         case INS_OPTS_RELOC:
99         case INS_OPTS_NONE:
100             return sizeof(instrDesc);
101         default:
102             NO_WAY("unexpected instruction descriptor format");
103             break;
104     }
105 }
106
107 bool emitter::emitInsWritesToLclVarStackLoc(instrDesc* id)
108 {
109     if (!id->idIsLclVar())
110         return false;
111
112     instruction ins = id->idIns();
113
114     // This list is related to the list of instructions used to store local vars in emitIns_S_R().
115     // We don't accept writing to float local vars.
116
117     switch (ins)
118     {
119         case INS_sd:
120         case INS_sw:
121         case INS_sb:
122         case INS_sh:
123             return true;
124
125         default:
126             return false;
127     }
128 }
129
130 #define LD 1
131 #define ST 2
132
133 // clang-format off
134 /*static*/ const BYTE CodeGenInterface::instInfo[] =
135 {
136     #define INST(id, nm, info, e1) info,
137     #include "instrs.h"
138 };
139 // clang-format on
140
141 inline bool emitter::emitInsMayWriteToGCReg(instruction ins)
142 {
143     assert(ins != INS_invalid);
144     return (ins <= INS_remuw) && (ins >= INS_mov) && !(ins >= INS_jal && ins <= INS_bgeu && ins != INS_jalr) &&
145                    (CodeGenInterface::instInfo[ins] & ST) == 0
146                ? true
147                : false;
148 }
149
150 //------------------------------------------------------------------------
151 // emitInsLoad: Returns true if the instruction is some kind of load instruction.
152 //
153 bool emitter::emitInsIsLoad(instruction ins)
154 {
155     // We have pseudo ins like lea which are not included in emitInsLdStTab.
156     if (ins < ArrLen(CodeGenInterface::instInfo))
157         return (CodeGenInterface::instInfo[ins] & LD) != 0;
158     else
159         return false;
160 }
161
162 //------------------------------------------------------------------------
163 // emitInsIsStore: Returns true if the instruction is some kind of store instruction.
164 //
165 bool emitter::emitInsIsStore(instruction ins)
166 {
167     // We have pseudo ins like lea which are not included in emitInsLdStTab.
168     if (ins < ArrLen(CodeGenInterface::instInfo))
169         return (CodeGenInterface::instInfo[ins] & ST) != 0;
170     else
171         return false;
172 }
173
174 //-------------------------------------------------------------------------
175 // emitInsIsLoadOrStore: Returns true if the instruction is some kind of load/store instruction.
176 //
177 bool emitter::emitInsIsLoadOrStore(instruction ins)
178 {
179     // We have pseudo ins like lea which are not included in emitInsLdStTab.
180     if (ins < ArrLen(CodeGenInterface::instInfo))
181         return (CodeGenInterface::instInfo[ins] & (LD | ST)) != 0;
182     else
183         return false;
184 }
185
186 /*****************************************************************************
187  *
188  *  Returns the specific encoding of the given CPU instruction.
189  */
190
191 inline emitter::code_t emitter::emitInsCode(instruction ins /*, insFormat fmt*/)
192 {
193     code_t code = BAD_CODE;
194
195     // clang-format off
196     const static code_t insCode[] =
197     {
198         #define INST(id, nm, info, e1) e1,
199         #include "instrs.h"
200     };
201     // clang-format on
202
203     code = insCode[ins];
204
205     assert((code != BAD_CODE));
206
207     return code;
208 }
209
210 /****************************************************************************
211  *
212  *  Add an instruction with no operands.
213  */
214
215 void emitter::emitIns(instruction ins)
216 {
217     instrDesc* id = emitNewInstr(EA_8BYTE);
218
219     id->idIns(ins);
220     id->idAddr()->iiaSetInstrEncode(emitInsCode(ins));
221     id->idCodeSize(4);
222
223     appendToCurIG(id);
224 }
225
226 /*****************************************************************************
227  *  emitter::emitIns_S_R(), emitter::emitIns_S_R_R() and emitter::emitIns_R_S():
228  *
229  *  Add an Load/Store instruction(s): base+offset and base-addr-computing if needed.
230  *  For referencing a stack-based local variable and a register
231  *
232  */
233 void emitter::emitIns_S_R(instruction ins, emitAttr attr, regNumber reg1, int varx, int offs)
234 {
235     emitIns_S_R_R(ins, attr, reg1, REG_NA, varx, offs);
236 }
237
238 void emitter::emitIns_S_R_R(instruction ins, emitAttr attr, regNumber reg1, regNumber tmpReg, int varx, int offs)
239 {
240     ssize_t imm;
241
242     assert(tmpReg != codeGen->rsGetRsvdReg());
243     assert(reg1 != codeGen->rsGetRsvdReg());
244
245     emitAttr size = EA_SIZE(attr);
246
247 #ifdef DEBUG
248     switch (ins)
249     {
250         case INS_sd:
251         case INS_sw:
252         case INS_sh:
253         case INS_sb:
254         case INS_fsd:
255         case INS_fsw:
256             break;
257
258         default:
259             NYI_RISCV64("illegal ins within emitIns_S_R_R!");
260             return;
261
262     } // end switch (ins)
263 #endif
264
265     /* Figure out the variable's frame position */
266     int  base;
267     bool FPbased;
268
269     base = emitComp->lvaFrameAddress(varx, &FPbased);
270
271     regNumber regBase = FPbased ? REG_FPBASE : REG_SPBASE;
272     regNumber reg2;
273
274     if (tmpReg == REG_NA)
275     {
276         reg2 = regBase;
277         imm  = base + offs;
278     }
279     else
280     {
281         reg2 = tmpReg;
282         imm  = offs;
283     }
284
285     assert(reg2 != REG_NA && reg2 != codeGen->rsGetRsvdReg());
286
287     if (!isValidSimm12(imm))
288     {
289         // If immediate does not fit to store immediate 12 bits, construct necessary value in rsRsvdReg()
290         // and keep tmpReg hint value unchanged.
291         assert(isValidSimm20((imm + 0x800) >> 12));
292
293         emitIns_R_I(INS_lui, EA_PTRSIZE, codeGen->rsGetRsvdReg(), (imm + 0x800) >> 12);
294         emitIns_R_R_R(INS_add, EA_PTRSIZE, codeGen->rsGetRsvdReg(), codeGen->rsGetRsvdReg(), reg2);
295
296         imm  = imm & 0xfff;
297         reg2 = codeGen->rsGetRsvdReg();
298     }
299
300     instrDesc* id = emitNewInstr(attr);
301
302     id->idReg1(reg1);
303
304     id->idReg2(reg2);
305
306     id->idIns(ins);
307
308     assert(isGeneralRegister(reg2));
309     code_t code = emitInsCode(ins);
310     code |= (code_t)(reg1 & 0x1f) << 20;
311     code |= (code_t)reg2 << 15;
312     code |= (((imm >> 5) & 0x7f) << 25) | ((imm & 0x1f) << 7);
313
314     id->idAddr()->iiaSetInstrEncode(code);
315     id->idAddr()->iiaLclVar.initLclVarAddr(varx, offs);
316     id->idSetIsLclVar();
317     id->idCodeSize(4);
318
319     appendToCurIG(id);
320 }
321
322 /*
323  *  Special notes for `offs`, please see the comment for `emitter::emitIns_S_R`.
324  */
325 void emitter::emitIns_R_S(instruction ins, emitAttr attr, regNumber reg1, int varx, int offs)
326 {
327     ssize_t imm;
328
329     emitAttr size = EA_SIZE(attr);
330
331 #ifdef DEBUG
332     switch (ins)
333     {
334         case INS_lb:
335         case INS_lbu:
336
337         case INS_lh:
338         case INS_lhu:
339
340         case INS_lw:
341         case INS_lwu:
342         case INS_flw:
343
344         case INS_ld:
345         case INS_fld:
346
347             break;
348
349         case INS_lea:
350             assert(size == EA_8BYTE);
351             break;
352
353         default:
354             NYI_RISCV64("illegal ins within emitIns_R_S!");
355             return;
356
357     } // end switch (ins)
358 #endif
359
360     /* Figure out the variable's frame position */
361     int  base;
362     bool FPbased;
363
364     base = emitComp->lvaFrameAddress(varx, &FPbased);
365     imm  = offs < 0 ? -offs - 8 : base + offs;
366
367     regNumber reg2 = FPbased ? REG_FPBASE : REG_SPBASE;
368     assert(offs >= 0);
369     offs = offs < 0 ? -offs - 8 : offs;
370
371     reg1 = (regNumber)((char)reg1 & 0x1f);
372     code_t code;
373     if ((-2048 <= imm) && (imm < 2048))
374     {
375         if (ins == INS_lea)
376         {
377             ins = INS_addi;
378         }
379         code = emitInsCode(ins);
380         code |= (code_t)reg1 << 7;
381         code |= (code_t)reg2 << 15;
382         code |= (imm & 0xfff) << 20;
383     }
384     else
385     {
386         if (ins == INS_lea)
387         {
388             assert(isValidSimm20((imm + 0x800) >> 12));
389             emitIns_R_I(INS_lui, EA_PTRSIZE, codeGen->rsGetRsvdReg(), (imm + 0x800) >> 12);
390             ssize_t imm2 = imm & 0xfff;
391             emitIns_R_R_I(INS_addi, EA_PTRSIZE, codeGen->rsGetRsvdReg(), codeGen->rsGetRsvdReg(), imm2);
392
393             ins  = INS_add;
394             code = emitInsCode(ins);
395             code |= (code_t)reg1 << 7;
396             code |= (code_t)reg2 << 15;
397             code |= (code_t)codeGen->rsGetRsvdReg() << 20;
398         }
399         else
400         {
401             assert(isValidSimm20((imm + 0x800) >> 12));
402             emitIns_R_I(INS_lui, EA_PTRSIZE, codeGen->rsGetRsvdReg(), (imm + 0x800) >> 12);
403
404             emitIns_R_R_R(INS_add, EA_PTRSIZE, codeGen->rsGetRsvdReg(), codeGen->rsGetRsvdReg(), reg2);
405
406             ssize_t imm2 = imm & 0xfff;
407             code         = emitInsCode(ins);
408             code |= (code_t)reg1 << 7;
409             code |= (code_t)codeGen->rsGetRsvdReg() << 15;
410             code |= (code_t)(imm2 & 0xfff) << 20;
411         }
412     }
413
414     instrDesc* id = emitNewInstr(attr);
415
416     id->idReg1(reg1);
417
418     id->idIns(ins);
419
420     id->idAddr()->iiaSetInstrEncode(code);
421     id->idAddr()->iiaLclVar.initLclVarAddr(varx, offs);
422     id->idSetIsLclVar();
423     id->idCodeSize(4);
424
425     appendToCurIG(id);
426 }
427
428 /*****************************************************************************
429  *
430  *  Add an instruction with a single immediate value.
431  */
432
433 void emitter::emitIns_I(instruction ins, emitAttr attr, ssize_t imm)
434 {
435     code_t code = emitInsCode(ins);
436
437     switch (ins)
438     {
439         case INS_fence:
440             code |= ((imm & 0xff) << 20);
441             break;
442         case INS_j:
443             assert(imm >= -1048576 && imm < 1048576);
444             code |= ((imm >> 12) & 0xff) << 12;
445             code |= ((imm >> 11) & 0x1) << 20;
446             code |= ((imm >> 1) & 0x3ff) << 21;
447             code |= ((imm >> 20) & 0x1) << 31;
448             break;
449         default:
450             NO_WAY("illegal ins within emitIns_I!");
451     }
452
453     instrDesc* id = emitNewInstr(attr);
454
455     id->idIns(ins);
456     id->idAddr()->iiaSetInstrEncode(code);
457     id->idCodeSize(4);
458
459     appendToCurIG(id);
460 }
461
462 void emitter::emitIns_I_I(instruction ins, emitAttr attr, ssize_t cc, ssize_t offs)
463 {
464     NYI_RISCV64("emitIns_I_I-----unimplemented/unused on RISCV64 yet----");
465 }
466
467 /*****************************************************************************
468  *
469  *  Add an instruction referencing a register and a constant.
470  */
471
472 void emitter::emitIns_R_I(instruction ins, emitAttr attr, regNumber reg, ssize_t imm, insOpts opt /* = INS_OPTS_NONE */)
473 {
474     code_t code = emitInsCode(ins);
475
476     switch (ins)
477     {
478         case INS_lui:
479         case INS_auipc:
480             assert(reg != REG_R0);
481             assert(isGeneralRegister(reg));
482             assert((((size_t)imm) >> 20) == 0);
483
484             code |= reg << 7;
485             code |= (imm & 0xfffff) << 12;
486             break;
487         case INS_jal:
488             assert(isGeneralRegisterOrR0(reg));
489             assert(isValidSimm21(imm));
490
491             code |= reg << 7;
492             code |= ((imm >> 12) & 0xff) << 12;
493             code |= ((imm >> 11) & 0x1) << 20;
494             code |= ((imm >> 1) & 0x3ff) << 21;
495             code |= ((imm >> 20) & 0x1) << 31;
496             break;
497         default:
498             NO_WAY("illegal ins within emitIns_R_I!");
499             break;
500     } // end switch (ins)
501
502     instrDesc* id = emitNewInstr(attr);
503
504     id->idIns(ins);
505     id->idReg1(reg);
506     id->idAddr()->iiaSetInstrEncode(code);
507     id->idCodeSize(4);
508
509     appendToCurIG(id);
510 }
511
512 //------------------------------------------------------------------------
513 // emitIns_Mov: Emits a move instruction
514 //
515 // Arguments:
516 //    ins       -- The instruction being emitted
517 //    attr      -- The emit attribute
518 //    dstReg    -- The destination register
519 //    srcReg    -- The source register
520 //    canSkip   -- true if the move can be elided when dstReg == srcReg, otherwise false
521 //    insOpts   -- The instruction options
522 //
523 void emitter::emitIns_Mov(
524     instruction ins, emitAttr attr, regNumber dstReg, regNumber srcReg, bool canSkip, insOpts opt /* = INS_OPTS_NONE */)
525 {
526     if (!canSkip || (dstReg != srcReg))
527     {
528         if ((EA_4BYTE == attr) && (INS_mov == ins))
529         {
530             assert(isGeneralRegisterOrR0(srcReg));
531             assert(isGeneralRegisterOrR0(dstReg));
532             emitIns_R_R_I(INS_addiw, attr, dstReg, srcReg, 0);
533         }
534         else if (INS_fsgnj_s == ins || INS_fsgnj_d == ins)
535         {
536             assert(isFloatReg(srcReg));
537             assert(isFloatReg(dstReg));
538             emitIns_R_R_R(ins, attr, dstReg, srcReg, srcReg);
539         }
540         else if (genIsValidFloatReg(srcReg) || genIsValidFloatReg(dstReg))
541         {
542             emitIns_R_R(ins, attr, dstReg, srcReg);
543         }
544         else
545         {
546             assert(isGeneralRegisterOrR0(srcReg));
547             assert(isGeneralRegisterOrR0(dstReg));
548             emitIns_R_R_I(INS_addi, attr, dstReg, srcReg, 0);
549         }
550     }
551 }
552
553 void emitter::emitIns_Mov(emitAttr attr, regNumber dstReg, regNumber srcReg, bool canSkip)
554 {
555     if (!canSkip || dstReg != srcReg)
556     {
557         assert(attr == EA_4BYTE || attr == EA_PTRSIZE);
558         if (isGeneralRegisterOrR0(dstReg) && isGeneralRegisterOrR0(srcReg))
559         {
560             emitIns_R_R_I(attr == EA_4BYTE ? INS_addiw : INS_addi, attr, dstReg, srcReg, 0);
561         }
562         else if (isGeneralRegisterOrR0(dstReg) && genIsValidFloatReg(srcReg))
563         {
564             emitIns_R_R(attr == EA_4BYTE ? INS_fmv_x_w : INS_fmv_x_d, attr, dstReg, srcReg);
565         }
566         else if (genIsValidFloatReg(dstReg) && isGeneralRegisterOrR0(srcReg))
567         {
568             emitIns_R_R(attr == EA_4BYTE ? INS_fmv_w_x : INS_fmv_d_x, attr, dstReg, srcReg);
569         }
570         else if (genIsValidFloatReg(dstReg) && genIsValidFloatReg(srcReg))
571         {
572             emitIns_R_R_R(attr == EA_4BYTE ? INS_fsgnj_s : INS_fsgnj_d, attr, dstReg, srcReg, srcReg);
573         }
574         else
575         {
576             assert(!"Invalid registers in emitIns_Mov()\n");
577         }
578     }
579 }
580
581 /*****************************************************************************
582  *
583  *  Add an instruction referencing two registers
584  */
585
586 void emitter::emitIns_R_R(
587     instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, insOpts opt /* = INS_OPTS_NONE */)
588 {
589     code_t code = emitInsCode(ins);
590
591     if (INS_mov == ins)
592     {
593         assert(isGeneralRegisterOrR0(reg1));
594         assert(isGeneralRegisterOrR0(reg2));
595         code |= reg1 << 7;
596         code |= reg2 << 15;
597     }
598     else if (INS_fmv_x_d == ins || INS_fmv_x_w == ins || INS_fclass_s == ins || INS_fclass_d == ins)
599     {
600         assert(isGeneralRegisterOrR0(reg1));
601         assert(isFloatReg(reg2));
602         code |= reg1 << 7;
603         code |= (reg2 & 0x1f) << 15;
604     }
605     else if (INS_fcvt_w_s == ins || INS_fcvt_wu_s == ins || INS_fcvt_w_d == ins || INS_fcvt_wu_d == ins ||
606              INS_fcvt_l_s == ins || INS_fcvt_lu_s == ins || INS_fcvt_l_d == ins || INS_fcvt_lu_d == ins)
607     {
608         assert(isGeneralRegisterOrR0(reg1));
609         assert(isFloatReg(reg2));
610         code |= reg1 << 7;
611         code |= (reg2 & 0x1f) << 15;
612         code |= 0x1 << 12;
613     }
614     else if (INS_fmv_w_x == ins || INS_fmv_d_x == ins)
615     {
616         assert(isFloatReg(reg1));
617         assert(isGeneralRegisterOrR0(reg2));
618         code |= (reg1 & 0x1f) << 7;
619         code |= reg2 << 15;
620     }
621     else if (INS_fcvt_s_w == ins || INS_fcvt_s_wu == ins || INS_fcvt_d_w == ins || INS_fcvt_d_wu == ins ||
622              INS_fcvt_s_l == ins || INS_fcvt_s_lu == ins || INS_fcvt_d_l == ins || INS_fcvt_d_lu == ins)
623     {
624         assert(isFloatReg(reg1));
625         assert(isGeneralRegisterOrR0(reg2));
626         code |= (reg1 & 0x1f) << 7;
627         code |= reg2 << 15;
628         code |= 0x7 << 12;
629     }
630     else if (INS_fcvt_s_d == ins || INS_fcvt_d_s == ins)
631     {
632         assert(isFloatReg(reg1));
633         assert(isFloatReg(reg2));
634         code |= (reg1 & 0x1f) << 7;
635         code |= (reg2 & 0x1f) << 15;
636         code |= 0x7 << 12;
637     }
638     else
639     {
640         NYI_RISCV64("illegal ins within emitIns_R_R!");
641     }
642
643     instrDesc* id = emitNewInstr(attr);
644
645     id->idIns(ins);
646     id->idReg1(reg1);
647     id->idReg2(reg2);
648     id->idAddr()->iiaSetInstrEncode(code);
649     id->idCodeSize(4);
650
651     appendToCurIG(id);
652 }
653
654 /*****************************************************************************
655  *
656  *  Add an instruction referencing two registers and a constant.
657  */
658
659 void emitter::emitIns_R_R_I(
660     instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, ssize_t imm, insOpts opt /* = INS_OPTS_NONE */)
661 {
662     code_t     code = emitInsCode(ins);
663     instrDesc* id   = emitNewInstr(attr);
664
665     if ((INS_addi <= ins && INS_srai >= ins) || (INS_addiw <= ins && INS_sraiw >= ins) ||
666         (INS_lb <= ins && INS_lhu >= ins) || INS_ld == ins || INS_lw == ins || INS_jalr == ins || INS_fld == ins ||
667         INS_flw == ins)
668     {
669         assert(isGeneralRegister(reg2));
670         code |= (reg1 & 0x1f) << 7; // rd
671         code |= reg2 << 15;         // rs1
672         code |= imm << 20;          // imm
673     }
674     else if (INS_sd == ins || INS_sw == ins || INS_sh == ins || INS_sb == ins || INS_fsw == ins || INS_fsd == ins)
675     {
676         assert(isGeneralRegister(reg2));
677         code |= (reg1 & 0x1f) << 20;                               // rs2
678         code |= reg2 << 15;                                        // rs1
679         code |= (((imm >> 5) & 0x7f) << 25) | ((imm & 0x1f) << 7); // imm
680     }
681     else if (INS_beq <= ins && INS_bgeu >= ins)
682     {
683         assert(isGeneralRegister(reg1));
684         assert(isGeneralRegister(reg2));
685         assert(isValidSimm13(imm));
686         assert(!(imm & 3));
687         code |= reg1 << 15;
688         code |= reg2 << 20;
689         code |= ((imm >> 11) & 0x1) << 7;
690         code |= ((imm >> 1) & 0xf) << 8;
691         code |= ((imm >> 5) & 0x3f) << 25;
692         code |= ((imm >> 12) & 0x1) << 31;
693         // TODO-RISCV64: Move jump logic to emitIns_J
694         id->idAddr()->iiaSetInstrCount(imm / sizeof(code_t));
695     }
696     else if (ins == INS_csrrs || ins == INS_csrrw || ins == INS_csrrc)
697     {
698         assert(isGeneralRegisterOrR0(reg1));
699         assert(isGeneralRegisterOrR0(reg2));
700         assert(isValidUimm12(imm));
701         code |= reg1 << 7;
702         code |= reg2 << 15;
703         code |= imm << 20;
704     }
705     else
706     {
707         NYI_RISCV64("illegal ins within emitIns_R_R_I!");
708     }
709
710     id->idIns(ins);
711     id->idReg1(reg1);
712     id->idReg2(reg2);
713     id->idAddr()->iiaSetInstrEncode(code);
714     id->idCodeSize(4);
715
716     appendToCurIG(id);
717 }
718
719 /*****************************************************************************
720  *
721  *  Add an instruction referencing register and two constants.
722  */
723
724 void emitter::emitIns_R_I_I(
725     instruction ins, emitAttr attr, regNumber reg1, ssize_t imm1, ssize_t imm2, insOpts opt) /* = INS_OPTS_NONE */
726 {
727     code_t code = emitInsCode(ins);
728
729     if (INS_csrrwi <= ins && ins <= INS_csrrci)
730     {
731         assert(isGeneralRegisterOrR0(reg1));
732         assert(isValidUimm5(imm1));
733         assert(isValidUimm12(imm2));
734         code |= reg1 << 7;
735         code |= imm1 << 15;
736         code |= imm2 << 20;
737     }
738     else
739     {
740         NYI_RISCV64("illegal ins within emitIns_R_I_I!");
741     }
742     instrDesc* id = emitNewInstr(attr);
743
744     id->idIns(ins);
745     id->idReg1(reg1);
746     id->idAddr()->iiaSetInstrEncode(code);
747     id->idCodeSize(4);
748
749     appendToCurIG(id);
750 }
751
752 /*****************************************************************************
753  *
754  *  Add an instruction referencing three registers.
755  */
756
757 void emitter::emitIns_R_R_R(
758     instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, regNumber reg3, insOpts opt) /* = INS_OPTS_NONE */
759 {
760     code_t code = emitInsCode(ins);
761
762     if ((INS_add <= ins && ins <= INS_and) || (INS_mul <= ins && ins <= INS_remuw) ||
763         (INS_addw <= ins && ins <= INS_sraw) || (INS_fadd_s <= ins && ins <= INS_fmax_s) ||
764         (INS_fadd_d <= ins && ins <= INS_fmax_d) || (INS_feq_s <= ins && ins <= INS_fle_s) ||
765         (INS_feq_d <= ins && ins <= INS_fle_d) || (INS_lr_w <= ins && ins <= INS_amomaxu_d))
766     {
767 #ifdef DEBUG
768         switch (ins)
769         {
770             case INS_add:
771             case INS_sub:
772             case INS_sll:
773             case INS_slt:
774             case INS_sltu:
775             case INS_xor:
776             case INS_srl:
777             case INS_sra:
778             case INS_or:
779             case INS_and:
780
781             case INS_addw:
782             case INS_subw:
783             case INS_sllw:
784             case INS_srlw:
785             case INS_sraw:
786
787             case INS_mul:
788             case INS_mulh:
789             case INS_mulhsu:
790             case INS_mulhu:
791             case INS_div:
792             case INS_divu:
793             case INS_rem:
794             case INS_remu:
795
796             case INS_mulw:
797             case INS_divw:
798             case INS_divuw:
799             case INS_remw:
800             case INS_remuw:
801
802             case INS_fadd_s:
803             case INS_fsub_s:
804             case INS_fmul_s:
805             case INS_fdiv_s:
806             case INS_fsqrt_s:
807             case INS_fsgnj_s:
808             case INS_fsgnjn_s:
809             case INS_fsgnjx_s:
810             case INS_fmin_s:
811             case INS_fmax_s:
812
813             case INS_feq_s:
814             case INS_flt_s:
815             case INS_fle_s:
816
817             case INS_fadd_d:
818             case INS_fsub_d:
819             case INS_fmul_d:
820             case INS_fdiv_d:
821             case INS_fsqrt_d:
822             case INS_fsgnj_d:
823             case INS_fsgnjn_d:
824             case INS_fsgnjx_d:
825             case INS_fmin_d:
826             case INS_fmax_d:
827
828             case INS_feq_d:
829             case INS_flt_d:
830             case INS_fle_d:
831
832             case INS_lr_w:
833             case INS_lr_d:
834             case INS_sc_w:
835             case INS_sc_d:
836             case INS_amoswap_w:
837             case INS_amoswap_d:
838             case INS_amoadd_w:
839             case INS_amoadd_d:
840             case INS_amoxor_w:
841             case INS_amoxor_d:
842             case INS_amoand_w:
843             case INS_amoand_d:
844             case INS_amoor_w:
845             case INS_amoor_d:
846             case INS_amomin_w:
847             case INS_amomin_d:
848             case INS_amomax_w:
849             case INS_amomax_d:
850             case INS_amominu_w:
851             case INS_amominu_d:
852             case INS_amomaxu_w:
853             case INS_amomaxu_d:
854                 break;
855             default:
856                 NYI_RISCV64("illegal ins within emitIns_R_R_R!");
857         }
858
859 #endif
860         // Src/data register for load reserved should be empty
861         assert((ins != INS_lr_w && ins != INS_lr_d) || reg3 == REG_R0);
862
863         code |= ((reg1 & 0x1f) << 7);
864         code |= ((reg2 & 0x1f) << 15);
865         code |= ((reg3 & 0x1f) << 20);
866         if ((INS_fadd_s <= ins && INS_fsqrt_s >= ins) || (INS_fadd_d <= ins && INS_fsqrt_d >= ins))
867         {
868             code |= 0x7 << 12;
869         }
870         else if (INS_lr_w <= ins && ins <= INS_amomaxu_d)
871         {
872             // For now all atomics are seq. consistent as Interlocked.* APIs don't expose acquire/release ordering
873             code |= 0b11 << 25;
874         }
875     }
876     else
877     {
878         NYI_RISCV64("illegal ins within emitIns_R_R_R!");
879     }
880
881     instrDesc* id = emitNewInstr(attr);
882
883     id->idIns(ins);
884     id->idReg1(reg1);
885     id->idReg2(reg2);
886     id->idReg3(reg3);
887     id->idAddr()->iiaSetInstrEncode(code);
888     id->idCodeSize(4);
889
890     appendToCurIG(id);
891 }
892
893 /*****************************************************************************
894  *
895  *  Add an instruction referencing three registers and a constant.
896  */
897
898 void emitter::emitIns_R_R_R_I(instruction ins,
899                               emitAttr    attr,
900                               regNumber   reg1,
901                               regNumber   reg2,
902                               regNumber   reg3,
903                               ssize_t     imm,
904                               insOpts     opt /* = INS_OPTS_NONE */,
905                               emitAttr    attrReg2 /* = EA_UNKNOWN */)
906 {
907     NYI_RISCV64("emitIns_R_R_R_I-----unimplemented/unused on RISCV64 yet----");
908 }
909
910 /*****************************************************************************
911  *
912  *  Add an instruction referencing two registers and two constants.
913  */
914
915 void emitter::emitIns_R_R_I_I(
916     instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, int imm1, int imm2, insOpts opt)
917 {
918     NYI_RISCV64("emitIns_R_R_I_I-----unimplemented/unused on RISCV64 yet----");
919 }
920
921 /*****************************************************************************
922  *
923  *  Add an instruction referencing four registers.
924  */
925
926 void emitter::emitIns_R_R_R_R(
927     instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, regNumber reg3, regNumber reg4)
928 {
929     NYI_RISCV64("emitIns_R_R_R_R-----unimplemented/unused on RISCV64 yet----");
930 }
931
932 /*****************************************************************************
933  *
934  *  Add an instruction with a register + static member operands.
935  *  Constant is stored into JIT data which is adjacent to code.
936  *
937  */
938 void emitter::emitIns_R_C(
939     instruction ins, emitAttr attr, regNumber reg, regNumber addrReg, CORINFO_FIELD_HANDLE fldHnd, int offs)
940 {
941     assert(offs >= 0);
942     assert(instrDesc::fitsInSmallCns(offs)); // can optimize.
943     instrDesc* id = emitNewInstr(attr);
944
945     id->idIns(ins);
946     assert(reg != REG_R0); // for special. reg Must not be R0.
947     id->idReg1(reg);       // destination register that will get the constant value.
948
949     id->idSmallCns(offs); // usually is 0.
950     id->idInsOpt(INS_OPTS_RC);
951     if (emitComp->opts.compReloc)
952     {
953         id->idSetIsDspReloc();
954         id->idCodeSize(8);
955     }
956     else
957         id->idCodeSize(16);
958
959     if (EA_IS_GCREF(attr))
960     {
961         /* A special value indicates a GCref pointer value */
962         id->idGCref(GCT_GCREF);
963         id->idOpSize(EA_PTRSIZE);
964     }
965     else if (EA_IS_BYREF(attr))
966     {
967         /* A special value indicates a Byref pointer value */
968         id->idGCref(GCT_BYREF);
969         id->idOpSize(EA_PTRSIZE);
970     }
971
972     // TODO-RISCV64: this maybe deleted.
973     id->idSetIsBound(); // We won't patch address since we will know the exact distance
974                         // once JIT code and data are allocated together.
975
976     assert(addrReg == REG_NA); // NOTE: for RISV64, not support addrReg != REG_NA.
977
978     id->idAddr()->iiaFieldHnd = fldHnd;
979
980     appendToCurIG(id);
981 }
982
983 void emitter::emitIns_R_AR(instruction ins, emitAttr attr, regNumber ireg, regNumber reg, int offs)
984 {
985     NYI_RISCV64("emitIns_R_AR-----unimplemented/unused on RISCV64 yet----");
986 }
987
988 // This computes address from the immediate which is relocatable.
989 void emitter::emitIns_R_AI(instruction ins,
990                            emitAttr    attr,
991                            regNumber   reg,
992                            ssize_t addr DEBUGARG(size_t targetHandle) DEBUGARG(GenTreeFlags gtFlags))
993 {
994     assert(EA_IS_RELOC(attr)); // EA_PTR_DSP_RELOC
995     assert(ins == INS_jal);    // for special.
996     assert(isGeneralRegister(reg));
997
998     // INS_OPTS_RELOC: placeholders.  2-ins:
999     //  case:EA_HANDLE_CNS_RELOC
1000     //   auipc  reg, off-hi-20bits
1001     //   addi   reg, reg, off-lo-12bits
1002     //  case:EA_PTR_DSP_RELOC
1003     //   auipc  reg, off-hi-20bits
1004     //   ld     reg, reg, off-lo-12bits
1005
1006     instrDesc* id = emitNewInstr(attr);
1007
1008     id->idIns(ins);
1009     assert(reg != REG_R0); // for special. reg Must not be R0.
1010     id->idReg1(reg);       // destination register that will get the constant value.
1011
1012     id->idInsOpt(INS_OPTS_RELOC);
1013
1014     if (EA_IS_GCREF(attr))
1015     {
1016         /* A special value indicates a GCref pointer value */
1017         id->idGCref(GCT_GCREF);
1018         id->idOpSize(EA_PTRSIZE);
1019     }
1020     else if (EA_IS_BYREF(attr))
1021     {
1022         /* A special value indicates a Byref pointer value */
1023         id->idGCref(GCT_BYREF);
1024         id->idOpSize(EA_PTRSIZE);
1025     }
1026
1027     id->idAddr()->iiaAddr = (BYTE*)addr;
1028     id->idCodeSize(8);
1029
1030     appendToCurIG(id);
1031 }
1032
1033 /*****************************************************************************
1034  *
1035  *  Record that a jump instruction uses the short encoding
1036  *
1037  */
1038 void emitter::emitSetShortJump(instrDescJmp* id)
1039 {
1040     // TODO-RISCV64: maybe delete it on future.
1041     NYI_RISCV64("emitSetShortJump-----unimplemented/unused on RISCV64 yet----");
1042 }
1043
1044 /*****************************************************************************
1045  *
1046  *  Add a label instruction.
1047  */
1048
1049 void emitter::emitIns_R_L(instruction ins, emitAttr attr, BasicBlock* dst, regNumber reg)
1050 {
1051     assert(dst->bbFlags & BBF_HAS_LABEL);
1052
1053     // if for reloc!  4-ins:
1054     //   auipc reg, offset-hi20
1055     //   addi  reg, reg, offset-lo12
1056     //
1057     // else:  3-ins:
1058     //   lui  tmp, dst-hi-20bits
1059     //   addi tmp, tmp, dst-lo-12bits
1060     //   lui  reg, 0xff << 12
1061     //   slli reg, reg, 32
1062     //   add  reg, tmp, reg
1063
1064     instrDesc* id = emitNewInstr(attr);
1065
1066     id->idIns(ins);
1067     id->idInsOpt(INS_OPTS_RL);
1068     id->idAddr()->iiaBBlabel = dst;
1069
1070     if (emitComp->opts.compReloc)
1071     {
1072         id->idSetIsDspReloc();
1073         id->idCodeSize(8);
1074     }
1075     else
1076         id->idCodeSize(20);
1077
1078     id->idReg1(reg);
1079
1080     if (EA_IS_GCREF(attr))
1081     {
1082         /* A special value indicates a GCref pointer value */
1083         id->idGCref(GCT_GCREF);
1084         id->idOpSize(EA_PTRSIZE);
1085     }
1086     else if (EA_IS_BYREF(attr))
1087     {
1088         /* A special value indicates a Byref pointer value */
1089         id->idGCref(GCT_BYREF);
1090         id->idOpSize(EA_PTRSIZE);
1091     }
1092
1093 #ifdef DEBUG
1094     // Mark the catch return
1095     if (emitComp->compCurBB->bbJumpKind == BBJ_EHCATCHRET)
1096     {
1097         id->idDebugOnlyInfo()->idCatchRet = true;
1098     }
1099 #endif // DEBUG
1100
1101     appendToCurIG(id);
1102 }
1103
1104 void emitter::emitIns_J_R(instruction ins, emitAttr attr, BasicBlock* dst, regNumber reg)
1105 {
1106     NYI_RISCV64("emitIns_J_R-----unimplemented/unused on RISCV64 yet----");
1107 }
1108
1109 void emitter::emitIns_J(instruction ins, BasicBlock* dst, int instrCount)
1110 {
1111     assert(dst != nullptr);
1112     //
1113     // INS_OPTS_J: placeholders.  1-ins: if the dst outof-range will be replaced by INS_OPTS_JALR.
1114     // jal/j/jalr/bnez/beqz/beq/bne/blt/bge/bltu/bgeu dst
1115
1116     assert(dst->bbFlags & BBF_HAS_LABEL);
1117
1118     instrDescJmp* id = emitNewInstrJmp();
1119     assert((INS_jal <= ins) && (ins <= INS_bgeu));
1120     id->idIns(ins);
1121     id->idReg1((regNumber)(instrCount & 0x1f));
1122     id->idReg2((regNumber)((instrCount >> 5) & 0x1f));
1123
1124     id->idInsOpt(INS_OPTS_J);
1125     emitCounts_INS_OPTS_J++;
1126     id->idAddr()->iiaBBlabel = dst;
1127
1128     if (emitComp->opts.compReloc)
1129     {
1130         id->idSetIsDspReloc();
1131     }
1132
1133     id->idjShort = false;
1134
1135     // TODO-RISCV64: maybe deleted this.
1136     id->idjKeepLong = emitComp->fgInDifferentRegions(emitComp->compCurBB, dst);
1137 #ifdef DEBUG
1138     if (emitComp->opts.compLongAddress) // Force long branches
1139         id->idjKeepLong = 1;
1140 #endif // DEBUG
1141
1142     /* Record the jump's IG and offset within it */
1143     id->idjIG   = emitCurIG;
1144     id->idjOffs = emitCurIGsize;
1145
1146     /* Append this jump to this IG's jump list */
1147     id->idjNext      = emitCurIGjmpList;
1148     emitCurIGjmpList = id;
1149
1150 #if EMITTER_STATS
1151     emitTotalIGjmps++;
1152 #endif
1153
1154     id->idCodeSize(4);
1155
1156     appendToCurIG(id);
1157 }
1158
1159 void emitter::emitIns_J_cond_la(instruction ins, BasicBlock* dst, regNumber reg1, regNumber reg2)
1160 {
1161     // TODO-RISCV64:
1162     //   Now the emitIns_J_cond_la() is only the short condition branch.
1163     //   There is no long condition branch for RISCV64 so far.
1164     //   For RISCV64 , the long condition branch is like this:
1165     //     --->  branch_condition  condition_target;     //here is the condition branch, short branch is enough.
1166     //     --->  jump jump_target; (this supporting the long jump.)
1167     //     condition_target:
1168     //     ...
1169     //     ...
1170     //     jump_target:
1171     //
1172     //
1173     // INS_OPTS_J_cond: placeholders.  1-ins.
1174     //   ins  reg1, reg2, dst
1175
1176     assert(dst != nullptr);
1177     assert(dst->bbFlags & BBF_HAS_LABEL);
1178
1179     instrDescJmp* id = emitNewInstrJmp();
1180
1181     id->idIns(ins);
1182     id->idReg1(reg1);
1183     id->idReg2(reg2);
1184     id->idjShort = false;
1185
1186     id->idInsOpt(INS_OPTS_J_cond);
1187     id->idAddr()->iiaBBlabel = dst;
1188
1189     id->idjKeepLong = emitComp->fgInDifferentRegions(emitComp->compCurBB, dst);
1190 #ifdef DEBUG
1191     if (emitComp->opts.compLongAddress) // Force long branches
1192         id->idjKeepLong = 1;
1193 #endif // DEBUG
1194
1195     /* Record the jump's IG and offset within it */
1196     id->idjIG   = emitCurIG;
1197     id->idjOffs = emitCurIGsize;
1198
1199     /* Append this jump to this IG's jump list */
1200     id->idjNext      = emitCurIGjmpList;
1201     emitCurIGjmpList = id;
1202
1203 #if EMITTER_STATS
1204     emitTotalIGjmps++;
1205 #endif
1206
1207     id->idCodeSize(4);
1208
1209     appendToCurIG(id);
1210 }
1211
1212 /*****************************************************************************
1213  *
1214  *  Emits load of 64-bit constant to register.
1215  *
1216  */
1217 void emitter::emitLoadImmediate(emitAttr size, regNumber reg, ssize_t imm)
1218 {
1219     // In the worst case a sequence of 8 instructions will be used:
1220     //   LUI + ADDIW + SLLI + ADDI + SLLI + ADDI + SLLI + ADDI
1221     //
1222     // First 2 instructions (LUI + ADDIW) load up to 31 bit. And followed
1223     // sequence of (SLLI + ADDI) is used for loading remaining part by batches
1224     // of up to 11 bits.
1225     //
1226     // Note that LUI, ADDI/W use sign extension so that's why we have to work
1227     // with 31 and 11 bit batches there.
1228
1229     assert(!EA_IS_RELOC(size));
1230     assert(isGeneralRegister(reg));
1231
1232     if (isValidSimm12(imm))
1233     {
1234         emitIns_R_R_I(INS_addi, size, reg, REG_R0, imm & 0xFFF);
1235         return;
1236     }
1237
1238     // TODO-RISCV64: maybe optimized via emitDataConst(), check #86790
1239
1240     UINT32 msb = BitOperations::BitScanReverse((uint64_t)imm);
1241     UINT32 high31;
1242     if (msb > 30)
1243     {
1244         high31 = (imm >> (msb - 30)) & 0x7FffFFff;
1245     }
1246     else
1247     {
1248         high31 = imm & 0x7FffFFff;
1249     }
1250
1251     // Since ADDIW use sign extension fo immediate
1252     // we have to adjust higher 19 bit loaded by LUI
1253     // for case when low part is bigger than 0x800.
1254     UINT32 high19 = (high31 + 0x800) >> 12;
1255
1256     emitIns_R_I(INS_lui, size, reg, high19);
1257     emitIns_R_R_I(INS_addiw, size, reg, reg, high31 & 0xFFF);
1258
1259     // And load remaining part part by batches of 11 bits size.
1260     INT32 remainingShift = msb - 30;
1261     while (remainingShift > 0)
1262     {
1263         UINT32 shift = remainingShift >= 11 ? 11 : remainingShift % 11;
1264         emitIns_R_R_I(INS_slli, size, reg, reg, shift);
1265
1266         UINT32  mask  = 0x7ff >> (11 - shift);
1267         ssize_t low11 = (imm >> (remainingShift - shift)) & mask;
1268         emitIns_R_R_I(INS_addi, size, reg, reg, low11);
1269         remainingShift = remainingShift - shift;
1270     }
1271 }
1272
1273 /*****************************************************************************
1274  *
1275  *  Add a call instruction (direct or indirect).
1276  *      argSize<0 means that the caller will pop the arguments
1277  *
1278  * The other arguments are interpreted depending on callType as shown:
1279  * Unless otherwise specified, ireg,xreg,xmul,disp should have default values.
1280  *
1281  * EC_FUNC_TOKEN       : addr is the method address
1282  *
1283  * If callType is one of these emitCallTypes, addr has to be NULL.
1284  * EC_INDIR_R          : "call ireg".
1285  *
1286  */
1287
1288 void emitter::emitIns_Call(EmitCallType          callType,
1289                            CORINFO_METHOD_HANDLE methHnd,
1290                            INDEBUG_LDISASM_COMMA(CORINFO_SIG_INFO* sigInfo) // used to report call sites to the EE
1291                            void*    addr,
1292                            ssize_t  argSize,
1293                            emitAttr retSize MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize),
1294                            VARSET_VALARG_TP ptrVars,
1295                            regMaskTP        gcrefRegs,
1296                            regMaskTP        byrefRegs,
1297                            const DebugInfo& di /* = DebugInfo() */,
1298                            regNumber        ireg /* = REG_NA */,
1299                            regNumber        xreg /* = REG_NA */,
1300                            unsigned         xmul /* = 0     */,
1301                            ssize_t          disp /* = 0     */,
1302                            bool             isJump /* = false */)
1303 {
1304     /* Sanity check the arguments depending on callType */
1305
1306     assert(callType < EC_COUNT);
1307     assert((callType != EC_FUNC_TOKEN) || (ireg == REG_NA && xreg == REG_NA && xmul == 0 && disp == 0));
1308     assert(callType < EC_INDIR_R || addr == NULL);
1309     assert(callType != EC_INDIR_R || (ireg < REG_COUNT && xreg == REG_NA && xmul == 0 && disp == 0));
1310
1311     // RISCV64 never uses these
1312     assert(xreg == REG_NA && xmul == 0 && disp == 0);
1313
1314     // Our stack level should be always greater than the bytes of arguments we push. Just
1315     // a sanity test.
1316     assert((unsigned)abs(argSize) <= codeGen->genStackLevel);
1317
1318     // Trim out any callee-trashed registers from the live set.
1319     regMaskTP savedSet = emitGetGCRegsSavedOrModified(methHnd);
1320     gcrefRegs &= savedSet;
1321     byrefRegs &= savedSet;
1322
1323 #ifdef DEBUG
1324     if (EMIT_GC_VERBOSE)
1325     {
1326         printf("Call: GCvars=%s ", VarSetOps::ToString(emitComp, ptrVars));
1327         dumpConvertedVarSet(emitComp, ptrVars);
1328         printf(", gcrefRegs=");
1329         printRegMaskInt(gcrefRegs);
1330         emitDispRegSet(gcrefRegs);
1331         printf(", byrefRegs=");
1332         printRegMaskInt(byrefRegs);
1333         emitDispRegSet(byrefRegs);
1334         printf("\n");
1335     }
1336 #endif
1337
1338     /* Managed RetVal: emit sequence point for the call */
1339     if (emitComp->opts.compDbgInfo && di.GetLocation().IsValid())
1340     {
1341         codeGen->genIPmappingAdd(IPmappingDscKind::Normal, di, false);
1342     }
1343
1344     /*
1345         We need to allocate the appropriate instruction descriptor based
1346         on whether this is a direct/indirect call, and whether we need to
1347         record an updated set of live GC variables.
1348      */
1349     instrDesc* id;
1350
1351     assert(argSize % REGSIZE_BYTES == 0);
1352     int argCnt = (int)(argSize / (int)REGSIZE_BYTES);
1353
1354     if (callType >= EC_INDIR_R)
1355     {
1356         /* Indirect call, virtual calls */
1357
1358         assert(callType == EC_INDIR_R);
1359
1360         id = emitNewInstrCallInd(argCnt, disp, ptrVars, gcrefRegs, byrefRegs, retSize, secondRetSize);
1361     }
1362     else
1363     {
1364         /* Helper/static/nonvirtual/function calls (direct or through handle),
1365            and calls to an absolute addr. */
1366
1367         assert(callType == EC_FUNC_TOKEN);
1368
1369         id = emitNewInstrCallDir(argCnt, ptrVars, gcrefRegs, byrefRegs, retSize, secondRetSize);
1370     }
1371
1372     /* Update the emitter's live GC ref sets */
1373
1374     VarSetOps::Assign(emitComp, emitThisGCrefVars, ptrVars);
1375     emitThisGCrefRegs = gcrefRegs;
1376     emitThisByrefRegs = byrefRegs;
1377
1378     id->idSetIsNoGC(emitNoGChelper(methHnd));
1379
1380     /* Set the instruction - special case jumping a function */
1381     instruction ins;
1382
1383     ins = INS_jalr; // jalr
1384     id->idIns(ins);
1385
1386     id->idInsOpt(INS_OPTS_C);
1387     // TODO-RISCV64: maybe optimize.
1388
1389     // INS_OPTS_C: placeholders.  1/2/4-ins:
1390     //   if (callType == EC_INDIR_R)
1391     //      jalr REG_R0/REG_RA, ireg, 0   <---- 1-ins
1392     //   else if (callType == EC_FUNC_TOKEN || callType == EC_FUNC_ADDR)
1393     //     if reloc:
1394     //             //pc + offset_38bits       # only when reloc.
1395     //      auipc t2, addr-hi20
1396     //      jalr r0/1, t2, addr-lo12
1397     //
1398     //     else:
1399     //      lui  t2, dst_offset_lo32-hi
1400     //      ori  t2, t2, dst_offset_lo32-lo
1401     //      lui  t2, dst_offset_hi32-lo
1402     //      jalr REG_R0/REG_RA, t2, 0
1403
1404     /* Record the address: method, indirection, or funcptr */
1405     if (callType == EC_INDIR_R)
1406     {
1407         /* This is an indirect call (either a virtual call or func ptr call) */
1408         // assert(callType == EC_INDIR_R);
1409
1410         id->idSetIsCallRegPtr();
1411
1412         regNumber reg_jalr = isJump ? REG_R0 : REG_RA;
1413         id->idReg4(reg_jalr);
1414         id->idReg3(ireg); // NOTE: for EC_INDIR_R, using idReg3.
1415         assert(xreg == REG_NA);
1416
1417         id->idCodeSize(4);
1418     }
1419     else
1420     {
1421         /* This is a simple direct call: "call helper/method/addr" */
1422
1423         assert(callType == EC_FUNC_TOKEN);
1424         assert(addr != NULL);
1425
1426         addr = (void*)(((size_t)addr) + (isJump ? 0 : 1)); // NOTE: low-bit0 is used for jirl ra/r0,rd,0
1427         id->idAddr()->iiaAddr = (BYTE*)addr;
1428
1429         if (emitComp->opts.compReloc)
1430         {
1431             id->idSetIsDspReloc();
1432             id->idCodeSize(8);
1433         }
1434         else
1435         {
1436             id->idCodeSize(32);
1437         }
1438     }
1439
1440 #ifdef DEBUG
1441     if (EMIT_GC_VERBOSE)
1442     {
1443         if (id->idIsLargeCall())
1444         {
1445             printf("[%02u] Rec call GC vars = %s\n", id->idDebugOnlyInfo()->idNum,
1446                    VarSetOps::ToString(emitComp, ((instrDescCGCA*)id)->idcGCvars));
1447         }
1448     }
1449
1450     id->idDebugOnlyInfo()->idMemCookie = (size_t)methHnd; // method token
1451     id->idDebugOnlyInfo()->idCallSig   = sigInfo;
1452 #endif // DEBUG
1453
1454 #ifdef LATE_DISASM
1455     if (addr != nullptr)
1456     {
1457         codeGen->getDisAssembler().disSetMethod((size_t)addr, methHnd);
1458     }
1459 #endif // LATE_DISASM
1460
1461     appendToCurIG(id);
1462 }
1463
1464 /*****************************************************************************
1465  *
1466  *  Output a call instruction.
1467  */
1468
1469 unsigned emitter::emitOutputCall(insGroup* ig, BYTE* dst, instrDesc* id, code_t code)
1470 {
1471     unsigned char callInstrSize = sizeof(code_t); // 4 bytes
1472     regMaskTP     gcrefRegs;
1473     regMaskTP     byrefRegs;
1474
1475     VARSET_TP GCvars(VarSetOps::UninitVal());
1476
1477     // Is this a "fat" call descriptor?
1478     if (id->idIsLargeCall())
1479     {
1480         instrDescCGCA* idCall = (instrDescCGCA*)id;
1481         gcrefRegs             = idCall->idcGcrefRegs;
1482         byrefRegs             = idCall->idcByrefRegs;
1483         VarSetOps::Assign(emitComp, GCvars, idCall->idcGCvars);
1484     }
1485     else
1486     {
1487         assert(!id->idIsLargeDsp());
1488         assert(!id->idIsLargeCns());
1489
1490         gcrefRegs = emitDecodeCallGCregs(id);
1491         byrefRegs = 0;
1492         VarSetOps::AssignNoCopy(emitComp, GCvars, VarSetOps::MakeEmpty(emitComp));
1493     }
1494
1495     /* We update the GC info before the call as the variables cannot be
1496         used by the call. Killing variables before the call helps with
1497         boundary conditions if the call is CORINFO_HELP_THROW - see bug 50029.
1498         If we ever track aliased variables (which could be used by the
1499         call), we would have to keep them alive past the call. */
1500
1501     emitUpdateLiveGCvars(GCvars, dst);
1502 #ifdef DEBUG
1503     // NOTEADD:
1504     // Output any delta in GC variable info, corresponding to the before-call GC var updates done above.
1505     if (EMIT_GC_VERBOSE || emitComp->opts.disasmWithGC)
1506     {
1507         emitDispGCVarDelta(); // define in emit.cpp
1508     }
1509 #endif // DEBUG
1510
1511     assert(id->idIns() == INS_jalr);
1512     if (id->idIsCallRegPtr())
1513     { // EC_INDIR_R
1514         code = emitInsCode(id->idIns());
1515         code |= (code_t)id->idReg4() << 7;
1516         code |= (code_t)id->idReg3() << 15;
1517         // the offset default is 0;
1518         emitOutput_Instr(dst, code);
1519     }
1520     else if (id->idIsReloc())
1521     {
1522         // pc + offset_32bits
1523         //
1524         //   auipc t2, addr-hi20
1525         //   jalr r0/1,t2,addr-lo12
1526
1527         emitOutput_Instr(dst, 0x00000397);
1528
1529         size_t addr = (size_t)(id->idAddr()->iiaAddr); // get addr.
1530
1531         int reg2 = ((int)addr & 1) + 10;
1532         addr     = addr ^ 1;
1533
1534         assert(isValidSimm32(addr - (ssize_t)dst));
1535         assert((addr & 1) == 0);
1536
1537         dst += 4;
1538         emitGCregDeadUpd(REG_DEFAULT_HELPER_CALL_TARGET, dst);
1539
1540 #ifdef DEBUG
1541         code = emitInsCode(INS_auipc);
1542         assert((code | (REG_DEFAULT_HELPER_CALL_TARGET << 7)) == 0x00000397);
1543         assert((int)REG_DEFAULT_HELPER_CALL_TARGET == 7);
1544         code = emitInsCode(INS_jalr);
1545         assert(code == 0x00000067);
1546 #endif
1547         emitOutput_Instr(dst, 0x00000067 | (REG_DEFAULT_HELPER_CALL_TARGET << 15) | reg2 << 7);
1548
1549         emitRecordRelocation(dst - 4, (BYTE*)addr, IMAGE_REL_RISCV64_JALR);
1550     }
1551     else
1552     {
1553         // lui  t2, dst_offset_hi32-hi
1554         // addi t2, t2, dst_offset_hi32-lo
1555         // slli t2, t2, 11
1556         // addi t2, t2, dst_offset_low32-hi
1557         // slli t2, t2, 11
1558         // addi t2, t2, dst_offset_low32-md
1559         // slli t2, t2, 10
1560         // jalr t2
1561
1562         ssize_t imm = (ssize_t)(id->idAddr()->iiaAddr);
1563         assert((imm >> 32) <= 0xff);
1564
1565         int reg2 = (int)(imm & 1);
1566         imm -= reg2;
1567
1568         UINT32 high = imm >> 32;
1569         code        = emitInsCode(INS_lui);
1570         code |= (code_t)REG_DEFAULT_HELPER_CALL_TARGET << 7;
1571         code |= ((code_t)((high + 0x800) >> 12) & 0xfffff) << 12;
1572         emitOutput_Instr(dst, code);
1573         dst += 4;
1574
1575         emitGCregDeadUpd(REG_DEFAULT_HELPER_CALL_TARGET, dst);
1576
1577         code = emitInsCode(INS_addi);
1578         code |= (code_t)REG_DEFAULT_HELPER_CALL_TARGET << 7;
1579         code |= (code_t)REG_DEFAULT_HELPER_CALL_TARGET << 15;
1580         code |= (code_t)(high & 0xfff) << 20;
1581         emitOutput_Instr(dst, code);
1582         dst += 4;
1583
1584         code = emitInsCode(INS_slli);
1585         code |= (code_t)REG_DEFAULT_HELPER_CALL_TARGET << 7;
1586         code |= (code_t)REG_DEFAULT_HELPER_CALL_TARGET << 15;
1587         code |= (code_t)(11 << 20);
1588         emitOutput_Instr(dst, code);
1589         dst += 4;
1590
1591         UINT32 low = imm & 0xffffffff;
1592
1593         code = emitInsCode(INS_addi);
1594         code |= (code_t)REG_DEFAULT_HELPER_CALL_TARGET << 7;
1595         code |= (code_t)REG_DEFAULT_HELPER_CALL_TARGET << 15;
1596         code |= ((low >> 21) & 0x7ff) << 20;
1597         emitOutput_Instr(dst, code);
1598         dst += 4;
1599
1600         code = emitInsCode(INS_slli);
1601         code |= (code_t)REG_DEFAULT_HELPER_CALL_TARGET << 7;
1602         code |= (code_t)REG_DEFAULT_HELPER_CALL_TARGET << 15;
1603         code |= (code_t)(11 << 20);
1604         emitOutput_Instr(dst, code);
1605         dst += 4;
1606
1607         code = emitInsCode(INS_addi);
1608         code |= (code_t)REG_DEFAULT_HELPER_CALL_TARGET << 7;
1609         code |= (code_t)REG_DEFAULT_HELPER_CALL_TARGET << 15;
1610         code |= ((low >> 10) & 0x7ff) << 20;
1611         emitOutput_Instr(dst, code);
1612         dst += 4;
1613
1614         code = emitInsCode(INS_slli);
1615         code |= (code_t)REG_DEFAULT_HELPER_CALL_TARGET << 7;
1616         code |= (code_t)REG_DEFAULT_HELPER_CALL_TARGET << 15;
1617         code |= (code_t)(10 << 20);
1618         emitOutput_Instr(dst, code);
1619         dst += 4;
1620
1621         code = emitInsCode(INS_jalr);
1622         code |= (code_t)reg2 << 7;
1623         code |= (code_t)REG_DEFAULT_HELPER_CALL_TARGET << 15;
1624         code |= (low & 0x3ff) << 20;
1625         // the offset default is 0;
1626         emitOutput_Instr(dst, code);
1627     }
1628
1629     dst += 4;
1630
1631     // If the method returns a GC ref, mark INTRET (A0) appropriately.
1632     if (id->idGCref() == GCT_GCREF)
1633     {
1634         gcrefRegs |= RBM_INTRET;
1635     }
1636     else if (id->idGCref() == GCT_BYREF)
1637     {
1638         byrefRegs |= RBM_INTRET;
1639     }
1640
1641     // If is a multi-register return method is called, mark INTRET_1 (A1) appropriately
1642     if (id->idIsLargeCall())
1643     {
1644         instrDescCGCA* idCall = (instrDescCGCA*)id;
1645         if (idCall->idSecondGCref() == GCT_GCREF)
1646         {
1647             gcrefRegs |= RBM_INTRET_1;
1648         }
1649         else if (idCall->idSecondGCref() == GCT_BYREF)
1650         {
1651             byrefRegs |= RBM_INTRET_1;
1652         }
1653     }
1654
1655     // If the GC register set has changed, report the new set.
1656     if (gcrefRegs != emitThisGCrefRegs)
1657     {
1658         emitUpdateLiveGCregs(GCT_GCREF, gcrefRegs, dst);
1659     }
1660     // If the Byref register set has changed, report the new set.
1661     if (byrefRegs != emitThisByrefRegs)
1662     {
1663         emitUpdateLiveGCregs(GCT_BYREF, byrefRegs, dst);
1664     }
1665
1666     // Some helper calls may be marked as not requiring GC info to be recorded.
1667     if (!id->idIsNoGC())
1668     {
1669         // On RISCV64, as on AMD64 and LOONGARCH64, we don't change the stack pointer to push/pop args.
1670         // So we're not really doing a "stack pop" here (note that "args" is 0), but we use this mechanism
1671         // to record the call for GC info purposes.  (It might be best to use an alternate call,
1672         // and protect "emitStackPop" under the EMIT_TRACK_STACK_DEPTH preprocessor variable.)
1673         emitStackPop(dst, /*isCall*/ true, callInstrSize, /*args*/ 0);
1674
1675         // Do we need to record a call location for GC purposes?
1676         //
1677         if (!emitFullGCinfo)
1678         {
1679             emitRecordGCcall(dst, callInstrSize);
1680         }
1681     }
1682     if (id->idIsCallRegPtr())
1683     {
1684         callInstrSize = 1 << 2;
1685     }
1686     else
1687     {
1688         callInstrSize = id->idIsReloc() ? (2 << 2) : (8 << 2); // INS_OPTS_C: 2/9-ins.
1689     }
1690
1691     return callInstrSize;
1692 }
1693
1694 void emitter::emitJumpDistBind()
1695 {
1696 #ifdef DEBUG
1697     if (emitComp->verbose)
1698     {
1699         printf("*************** In emitJumpDistBind()\n");
1700     }
1701     if (EMIT_INSTLIST_VERBOSE)
1702     {
1703         printf("\nInstruction list before the jump distance binding:\n\n");
1704         emitDispIGlist(true);
1705     }
1706 #endif
1707
1708 #if DEBUG_EMIT
1709     auto printJmpInfo = [this](const instrDescJmp* jmp, const insGroup* jmpIG, NATIVE_OFFSET extra,
1710                                UNATIVE_OFFSET srcInstrOffs, UNATIVE_OFFSET srcEncodingOffs, UNATIVE_OFFSET dstOffs,
1711                                NATIVE_OFFSET jmpDist, const char* direction) {
1712         assert(jmp->idDebugOnlyInfo() != nullptr);
1713         if (jmp->idDebugOnlyInfo()->idNum == (unsigned)INTERESTING_JUMP_NUM || INTERESTING_JUMP_NUM == 0)
1714         {
1715             const char* dirId = (strcmp(direction, "fwd") == 0) ? "[1]" : "[2]";
1716             if (INTERESTING_JUMP_NUM == 0)
1717             {
1718                 printf("%s Jump %u:\n", dirId, jmp->idDebugOnlyInfo()->idNum);
1719             }
1720             printf("%s Jump  block is at %08X\n", dirId, jmpIG->igOffs);
1721             printf("%s Jump reloffset is %04X\n", dirId, jmp->idjOffs);
1722             printf("%s Jump source is at %08X\n", dirId, srcEncodingOffs);
1723             printf("%s Label block is at %08X\n", dirId, dstOffs);
1724             printf("%s Jump  dist. is    %04X\n", dirId, jmpDist);
1725             if (extra > 0)
1726             {
1727                 printf("%s Dist excess [S] = %d  \n", dirId, extra);
1728             }
1729         }
1730         if (EMITVERBOSE)
1731         {
1732             printf("Estimate of %s jump [%08X/%03u]: %04X -> %04X = %04X\n", direction, dspPtr(jmp),
1733                    jmp->idDebugOnlyInfo()->idNum, srcInstrOffs, dstOffs, jmpDist);
1734         }
1735     };
1736 #endif
1737
1738     instrDescJmp* jmp;
1739
1740     UNATIVE_OFFSET adjIG;
1741     UNATIVE_OFFSET adjSJ;
1742     insGroup*      lstIG;
1743 #ifdef DEBUG
1744     insGroup* prologIG = emitPrologIG;
1745 #endif // DEBUG
1746
1747     // NOTE:
1748     //  bit0 of isLinkingEnd: indicating whether updating the instrDescJmp's size with the type INS_OPTS_J;
1749     //  bit1 of isLinkingEnd: indicating not needed updating the size while emitTotalCodeSize <= 0xfff or had
1750     //  updated;
1751     unsigned int isLinkingEnd = emitTotalCodeSize <= 0xfff ? 2 : 0;
1752
1753     UNATIVE_OFFSET ssz = 0; // relative small jump's delay-slot.
1754     // small  jump max. neg distance
1755     NATIVE_OFFSET nsd = B_DIST_SMALL_MAX_NEG;
1756     // small  jump max. pos distance
1757     NATIVE_OFFSET maxPlaceholderSize =
1758         emitCounts_INS_OPTS_J * (6 << 2); // the max placeholder sizeof(INS_OPTS_JALR) - sizeof(INS_OPTS_J)
1759     NATIVE_OFFSET psd = B_DIST_SMALL_MAX_POS - maxPlaceholderSize;
1760
1761 /*****************************************************************************/
1762 /* If the default small encoding is not enough, we start again here.     */
1763 /*****************************************************************************/
1764
1765 AGAIN:
1766
1767 #ifdef DEBUG
1768     emitCheckIGList();
1769 #endif
1770
1771 #ifdef DEBUG
1772     insGroup*     lastIG = nullptr;
1773     instrDescJmp* lastSJ = nullptr;
1774 #endif
1775
1776     lstIG = nullptr;
1777     adjSJ = 0;
1778     adjIG = 0;
1779
1780     for (jmp = emitJumpList; jmp; jmp = jmp->idjNext)
1781     {
1782         insGroup* jmpIG;
1783         insGroup* tgtIG;
1784
1785         UNATIVE_OFFSET jsz; // size of the jump instruction in bytes
1786
1787         NATIVE_OFFSET  extra;           // How far beyond the short jump range is this jump offset?
1788         UNATIVE_OFFSET srcInstrOffs;    // offset of the source instruction of the jump
1789         UNATIVE_OFFSET srcEncodingOffs; // offset of the source used by the instruction set to calculate the relative
1790                                         // offset of the jump
1791         UNATIVE_OFFSET dstOffs;
1792         NATIVE_OFFSET  jmpDist; // the relative jump distance, as it will be encoded
1793
1794 /* Make sure the jumps are properly ordered */
1795
1796 #ifdef DEBUG
1797         assert(lastSJ == nullptr || lastIG != jmp->idjIG || lastSJ->idjOffs < (jmp->idjOffs + adjSJ));
1798         lastSJ = (lastIG == jmp->idjIG) ? jmp : nullptr;
1799
1800         assert(lastIG == nullptr || lastIG->igNum <= jmp->idjIG->igNum || jmp->idjIG == prologIG ||
1801                emitNxtIGnum > unsigned(0xFFFF)); // igNum might overflow
1802         lastIG = jmp->idjIG;
1803 #endif // DEBUG
1804
1805         /* Get hold of the current jump size */
1806
1807         jsz = jmp->idCodeSize();
1808
1809         /* Get the group the jump is in */
1810
1811         jmpIG = jmp->idjIG;
1812
1813         /* Are we in a group different from the previous jump? */
1814
1815         if (lstIG != jmpIG)
1816         {
1817             /* Were there any jumps before this one? */
1818
1819             if (lstIG)
1820             {
1821                 /* Adjust the offsets of the intervening blocks */
1822
1823                 do
1824                 {
1825                     lstIG = lstIG->igNext;
1826                     assert(lstIG);
1827 #ifdef DEBUG
1828                     if (EMITVERBOSE)
1829                     {
1830                         printf("Adjusted offset of " FMT_BB " from %04X to %04X\n", lstIG->igNum, lstIG->igOffs,
1831                                lstIG->igOffs + adjIG);
1832                     }
1833 #endif // DEBUG
1834                     lstIG->igOffs += adjIG;
1835                     assert(IsCodeAligned(lstIG->igOffs));
1836                 } while (lstIG != jmpIG);
1837             }
1838
1839             /* We've got the first jump in a new group */
1840             adjSJ = 0;
1841             lstIG = jmpIG;
1842         }
1843
1844         /* Apply any local size adjustment to the jump's relative offset */
1845         jmp->idjOffs += adjSJ;
1846
1847         // If this is a jump via register, the instruction size does not change, so we are done.
1848         CLANG_FORMAT_COMMENT_ANCHOR;
1849
1850         /* Have we bound this jump's target already? */
1851
1852         if (jmp->idIsBound())
1853         {
1854             /* Does the jump already have the smallest size? */
1855
1856             if (jmp->idjShort)
1857             {
1858                 // We should not be jumping/branching across funclets/functions
1859                 emitCheckFuncletBranch(jmp, jmpIG);
1860
1861                 continue;
1862             }
1863
1864             tgtIG = jmp->idAddr()->iiaIGlabel;
1865         }
1866         else
1867         {
1868             /* First time we've seen this label, convert its target */
1869             CLANG_FORMAT_COMMENT_ANCHOR;
1870
1871             tgtIG = (insGroup*)emitCodeGetCookie(jmp->idAddr()->iiaBBlabel);
1872
1873 #ifdef DEBUG
1874             if (EMITVERBOSE)
1875             {
1876                 if (tgtIG)
1877                 {
1878                     printf(" to %s\n", emitLabelString(tgtIG));
1879                 }
1880                 else
1881                 {
1882                     printf("-- ERROR, no emitter cookie for " FMT_BB "; it is probably missing BBF_HAS_LABEL.\n",
1883                            jmp->idAddr()->iiaBBlabel->bbNum);
1884                 }
1885             }
1886             assert(tgtIG);
1887 #endif // DEBUG
1888
1889             /* Record the bound target */
1890
1891             jmp->idAddr()->iiaIGlabel = tgtIG;
1892             jmp->idSetIsBound();
1893         }
1894
1895         // We should not be jumping/branching across funclets/functions
1896         emitCheckFuncletBranch(jmp, jmpIG);
1897
1898         /*
1899             In the following distance calculations, if we're not actually
1900             scheduling the code (i.e. reordering instructions), we can
1901             use the actual offset of the jump (rather than the beg/end of
1902             the instruction group) since the jump will not be moved around
1903             and thus its offset is accurate.
1904
1905             First we need to figure out whether this jump is a forward or
1906             backward one; to do this we simply look at the ordinals of the
1907             group that contains the jump and the target.
1908          */
1909
1910         srcInstrOffs = jmpIG->igOffs + jmp->idjOffs;
1911
1912         /* Note that the destination is always the beginning of an IG, so no need for an offset inside it */
1913         dstOffs = tgtIG->igOffs;
1914
1915         srcEncodingOffs = srcInstrOffs + ssz; // Encoding offset of relative offset for small branch
1916
1917         if (jmpIG->igNum < tgtIG->igNum)
1918         {
1919             /* Forward jump */
1920
1921             /* Adjust the target offset by the current delta. This is a worst-case estimate, as jumps between
1922                here and the target could be shortened, causing the actual distance to shrink.
1923              */
1924
1925             dstOffs += adjIG;
1926
1927             /* Compute the distance estimate */
1928
1929             jmpDist = dstOffs - srcEncodingOffs;
1930
1931             /* How much beyond the max. short distance does the jump go? */
1932
1933             extra = jmpDist - psd;
1934
1935 #if DEBUG_EMIT
1936             printJmpInfo(jmp, jmpIG, extra, srcInstrOffs, srcEncodingOffs, dstOffs, jmpDist, "fwd");
1937 #endif // DEBUG_EMIT
1938
1939             assert(jmpDist >= 0); // Forward jump
1940             assert(!(jmpDist & 0x3));
1941
1942             if (!(isLinkingEnd & 0x2) && (extra > 0) &&
1943                 (jmp->idInsOpt() == INS_OPTS_J || jmp->idInsOpt() == INS_OPTS_J_cond))
1944             {
1945                 // transform forward INS_OPTS_J/INS_OPTS_J_cond jump when jmpDist exceed the maximum short distance
1946                 instruction ins = jmp->idIns();
1947                 assert((INS_jal <= ins) && (ins <= INS_bgeu));
1948
1949                 if (ins > INS_jalr ||
1950                     (ins < INS_jalr && ins > INS_j)) // jal < beqz < bnez < jalr < beq/bne/blt/bltu/bge/bgeu
1951                 {
1952                     if (isValidSimm13(jmpDist + maxPlaceholderSize))
1953                     {
1954                         continue;
1955                     }
1956                     else if (isValidSimm21(jmpDist + maxPlaceholderSize))
1957                     {
1958                         // convert to opposite branch and jal
1959                         extra = 4;
1960                     }
1961                     else
1962                     {
1963                         // convert to opposite branch and jalr
1964                         extra = 4 * 6;
1965                     }
1966                 }
1967                 else if (ins == INS_jal || ins == INS_j)
1968                 {
1969                     if (isValidSimm21(jmpDist + maxPlaceholderSize))
1970                     {
1971                         continue;
1972                     }
1973                     else
1974                     {
1975                         // convert to jalr
1976                         extra = 4 * 5;
1977                     }
1978                 }
1979                 else
1980                 {
1981                     assert(ins == INS_jalr);
1982                     assert((jmpDist + maxPlaceholderSize) < 0x800);
1983                     continue;
1984                 }
1985
1986                 jmp->idInsOpt(INS_OPTS_JALR);
1987                 jmp->idCodeSize(jmp->idCodeSize() + extra);
1988                 jmpIG->igSize += (unsigned short)extra; // the placeholder sizeof(INS_OPTS_JALR) - sizeof(INS_OPTS_J).
1989                 adjSJ += (UNATIVE_OFFSET)extra;
1990                 adjIG += (UNATIVE_OFFSET)extra;
1991                 emitTotalCodeSize += (UNATIVE_OFFSET)extra;
1992                 jmpIG->igFlags |= IGF_UPD_ISZ;
1993                 isLinkingEnd |= 0x1;
1994             }
1995             continue;
1996         }
1997         else
1998         {
1999             /* Backward jump */
2000
2001             /* Compute the distance estimate */
2002
2003             jmpDist = srcEncodingOffs - dstOffs;
2004
2005             /* How much beyond the max. short distance does the jump go? */
2006
2007             extra = jmpDist + nsd;
2008
2009 #if DEBUG_EMIT
2010             printJmpInfo(jmp, jmpIG, extra, srcInstrOffs, srcEncodingOffs, dstOffs, jmpDist, "bwd");
2011 #endif // DEBUG_EMIT
2012
2013             assert(jmpDist >= 0); // Backward jump
2014             assert(!(jmpDist & 0x3));
2015
2016             if (!(isLinkingEnd & 0x2) && (extra > 0) &&
2017                 (jmp->idInsOpt() == INS_OPTS_J || jmp->idInsOpt() == INS_OPTS_J_cond))
2018             {
2019                 // transform backward INS_OPTS_J/INS_OPTS_J_cond jump when jmpDist exceed the maximum short distance
2020                 instruction ins = jmp->idIns();
2021                 assert((INS_jal <= ins) && (ins <= INS_bgeu));
2022
2023                 if (ins > INS_jalr ||
2024                     (ins < INS_jalr && ins > INS_j)) // jal < beqz < bnez < jalr < beq/bne/blt/bltu/bge/bgeu
2025                 {
2026                     if (isValidSimm13(jmpDist + maxPlaceholderSize))
2027                     {
2028                         continue;
2029                     }
2030                     else if (isValidSimm21(jmpDist + maxPlaceholderSize))
2031                     {
2032                         // convert to opposite branch and jal
2033                         extra = 4;
2034                     }
2035                     else
2036                     {
2037                         // convert to opposite branch and jalr
2038                         extra = 4 * 6;
2039                     }
2040                 }
2041                 else if (ins == INS_jal || ins == INS_j)
2042                 {
2043                     if (isValidSimm21(jmpDist + maxPlaceholderSize))
2044                     {
2045                         continue;
2046                     }
2047                     else
2048                     {
2049                         // convert to jalr
2050                         extra = 4 * 5;
2051                     }
2052                 }
2053                 else
2054                 {
2055                     assert(ins == INS_jalr);
2056                     assert((jmpDist + maxPlaceholderSize) < 0x800);
2057                     continue;
2058                 }
2059
2060                 jmp->idInsOpt(INS_OPTS_JALR);
2061                 jmp->idCodeSize(jmp->idCodeSize() + extra);
2062                 jmpIG->igSize += (unsigned short)extra; // the placeholder sizeof(INS_OPTS_JALR) - sizeof(INS_OPTS_J).
2063                 adjSJ += (UNATIVE_OFFSET)extra;
2064                 adjIG += (UNATIVE_OFFSET)extra;
2065                 emitTotalCodeSize += (UNATIVE_OFFSET)extra;
2066                 jmpIG->igFlags |= IGF_UPD_ISZ;
2067                 isLinkingEnd |= 0x1;
2068             }
2069             continue;
2070         }
2071     } // end for each jump
2072
2073     if ((isLinkingEnd & 0x3) < 0x2)
2074     {
2075         // indicating the instrDescJmp's size of the type INS_OPTS_J had updated
2076         // after the first round and should iterate again to update.
2077         isLinkingEnd = 0x2;
2078
2079         // Adjust offsets of any remaining blocks.
2080         for (; lstIG;)
2081         {
2082             lstIG = lstIG->igNext;
2083             if (!lstIG)
2084             {
2085                 break;
2086             }
2087 #ifdef DEBUG
2088             if (EMITVERBOSE)
2089             {
2090                 printf("Adjusted offset of " FMT_BB " from %04X to %04X\n", lstIG->igNum, lstIG->igOffs,
2091                        lstIG->igOffs + adjIG);
2092             }
2093 #endif // DEBUG
2094
2095             lstIG->igOffs += adjIG;
2096
2097             assert(IsCodeAligned(lstIG->igOffs));
2098         }
2099         goto AGAIN;
2100     }
2101
2102 #ifdef DEBUG
2103     if (EMIT_INSTLIST_VERBOSE)
2104     {
2105         printf("\nLabels list after the jump distance binding:\n\n");
2106         emitDispIGlist(false);
2107     }
2108
2109     emitCheckIGList();
2110 #endif // DEBUG
2111 }
2112
2113 /*****************************************************************************
2114  *
2115  *  Emit a 32-bit RISCV64 instruction
2116  */
2117
2118 unsigned emitter::emitOutput_Instr(BYTE* dst, code_t code)
2119 {
2120     assert(sizeof(code_t) == 4);
2121     memcpy(dst + writeableOffset, &code, sizeof(code_t));
2122     return sizeof(code_t);
2123 }
2124
2125 void emitter::emitOutputInstrJumpDistanceHelper(const insGroup* ig,
2126                                                 instrDescJmp*   jmp,
2127                                                 UNATIVE_OFFSET& dstOffs,
2128                                                 const BYTE*&    dstAddr) const
2129 {
2130     // TODO-RISCV64-BUG: Currently the iiaEncodedInstrCount is not set by the riscv impl making distinguishing the jump
2131     // to label and an instruction-count based jumps impossible
2132     if (jmp->idAddr()->iiaHasInstrCount())
2133     {
2134         assert(ig != nullptr);
2135         int      instrCount = jmp->idAddr()->iiaGetInstrCount();
2136         unsigned insNum     = emitFindInsNum(ig, jmp);
2137         if (instrCount < 0)
2138         {
2139             // Backward branches using instruction count must be within the same instruction group.
2140             assert(insNum + 1 >= static_cast<unsigned>(-instrCount));
2141         }
2142         dstOffs = ig->igOffs + emitFindOffset(ig, insNum + 1 + instrCount);
2143         dstAddr = emitOffsetToPtr(dstOffs);
2144         return;
2145     }
2146     dstOffs = jmp->idAddr()->iiaIGlabel->igOffs;
2147     dstAddr = emitOffsetToPtr(dstOffs);
2148 }
2149
2150 ssize_t emitter::emitOutputInstrJumpDistance(const BYTE* dst, const BYTE* src, const insGroup* ig, instrDescJmp* jmp)
2151 {
2152     UNATIVE_OFFSET srcOffs = emitCurCodeOffs(src);
2153     const BYTE*    srcAddr = emitOffsetToPtr(srcOffs);
2154
2155     assert(!jmp->idAddr()->iiaIsJitDataOffset()); // not used by riscv64 impl
2156
2157     UNATIVE_OFFSET dstOffs{};
2158     const BYTE*    dstAddr = nullptr;
2159     emitOutputInstrJumpDistanceHelper(ig, jmp, dstOffs, dstAddr);
2160
2161     ssize_t distVal = static_cast<ssize_t>(dstAddr - srcAddr);
2162
2163     if (dstOffs > srcOffs)
2164     {
2165         // This is a forward jump
2166
2167         emitFwdJumps = true;
2168
2169         // The target offset will be closer by at least 'emitOffsAdj', but only if this
2170         // jump doesn't cross the hot-cold boundary.
2171         if (!emitJumpCrossHotColdBoundary(srcOffs, dstOffs))
2172         {
2173             distVal -= emitOffsAdj;
2174             dstOffs -= emitOffsAdj;
2175         }
2176         jmp->idjOffs = dstOffs;
2177         if (jmp->idjOffs != dstOffs)
2178         {
2179             IMPL_LIMITATION("Method is too large");
2180         }
2181     }
2182     return distVal;
2183 }
2184
2185 /*****************************************************************************
2186  *
2187  *  Append the machine code corresponding to the given instruction descriptor
2188  *  to the code block at '*dp'; the base of the code block is 'bp', and 'ig'
2189  *  is the instruction group that contains the instruction. Updates '*dp' to
2190  *  point past the generated code, and returns the size of the instruction
2191  *  descriptor in bytes.
2192  */
2193
2194 size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
2195 {
2196     BYTE* const       dst    = *dp;
2197     BYTE*             dstRW  = *dp + writeableOffset;
2198     BYTE*             dstRW2 = dstRW + 4; // addr for updating gc info if needed.
2199     const BYTE* const odstRW = dstRW;
2200     const BYTE* const odst   = *dp;
2201     code_t            code   = 0;
2202     instruction       ins;
2203     size_t            sz; // = emitSizeOfInsDsc(id);
2204
2205     assert(REG_NA == (int)REG_NA);
2206
2207     insOpts insOp = id->idInsOpt();
2208
2209     switch (insOp)
2210     {
2211         case INS_OPTS_RELOC:
2212         {
2213             regNumber reg1 = id->idReg1();
2214
2215             *(code_t*)dstRW = 0x00000017 | (code_t)(reg1 << 7);
2216
2217             dstRW += 4;
2218
2219 #ifdef DEBUG
2220             code = emitInsCode(INS_auipc);
2221             assert(code == 0x00000017);
2222             code = emitInsCode(INS_addi);
2223             assert(code == 0x00000013);
2224             code = emitInsCode(INS_ld);
2225             assert(code == 0x00003003);
2226 #endif
2227
2228             if (id->idIsCnsReloc())
2229             {
2230                 ins             = INS_addi;
2231                 *(code_t*)dstRW = 0x00000013 | (code_t)(reg1 << 7) | (code_t)(reg1 << 15);
2232             }
2233             else
2234             {
2235                 assert(id->idIsDspReloc());
2236                 ins             = INS_ld;
2237                 *(code_t*)dstRW = 0x00003003 | (code_t)(reg1 << 7) | (code_t)(reg1 << 15);
2238             }
2239
2240             dstRW += 4;
2241
2242             emitRecordRelocation(dstRW - 8 - writeableOffset, id->idAddr()->iiaAddr, IMAGE_REL_RISCV64_PC);
2243
2244             sz = sizeof(instrDesc);
2245         }
2246         break;
2247         case INS_OPTS_I:
2248         {
2249             ssize_t   imm  = (ssize_t)(id->idAddr()->iiaAddr);
2250             regNumber reg1 = id->idReg1();
2251
2252             switch (id->idCodeSize())
2253             {
2254                 case 8:
2255                 {
2256                     if (id->idReg2())
2257                     { // special for INT64_MAX or UINT32_MAX;
2258                         code = emitInsCode(INS_addi);
2259                         code |= (code_t)reg1 << 7;
2260                         code |= (code_t)REG_R0 << 15;
2261                         code |= 0xfff << 10;
2262
2263                         *(code_t*)dstRW = code;
2264                         dstRW += 4;
2265
2266                         ssize_t ui6 = (imm == INT64_MAX) ? 1 : 32;
2267                         code        = emitInsCode(INS_srli);
2268                         code |= ((code_t)(reg1 << 7) | ((code_t)(reg1 << 15)) | (ui6 << 20));
2269                         *(code_t*)dstRW = code;
2270                     }
2271                     else
2272                     {
2273                         code = emitInsCode(INS_lui);
2274                         code |= (code_t)(reg1 << 7);
2275                         code |= ((code_t)((imm + 0x800) >> 12) & 0xfffff) << 12;
2276
2277                         *(code_t*)dstRW = code;
2278                         dstRW += 4;
2279
2280                         code = emitInsCode(INS_addi);
2281                         code |= (code_t)reg1 << 7;
2282                         code |= (code_t)reg1 << 15;
2283                         code |= (code_t)(imm & 0xfff) << 20;
2284                         *(code_t*)dstRW = code;
2285                     }
2286                     break;
2287                 }
2288                 case 32:
2289                 {
2290                     ssize_t high = (imm >> 32) & 0xffffffff;
2291                     code         = emitInsCode(INS_lui);
2292                     code |= (code_t)reg1 << 7;
2293                     code |= ((code_t)((high + 0x800) >> 12) & 0xfffff) << 12;
2294
2295                     *(code_t*)dstRW = code;
2296                     dstRW += 4;
2297
2298                     code = emitInsCode(INS_addi);
2299                     code |= (code_t)reg1 << 7;
2300                     code |= (code_t)reg1 << 15;
2301                     code |= (code_t)(high & 0xfff) << 20;
2302                     *(code_t*)dstRW = code;
2303                     dstRW += 4;
2304
2305                     ssize_t low = imm & 0xffffffff;
2306
2307                     code = emitInsCode(INS_slli);
2308                     code |= (code_t)reg1 << 7;
2309                     code |= (code_t)reg1 << 15;
2310                     code |= (code_t)11 << 20;
2311                     *(code_t*)dstRW = code;
2312                     dstRW += 4;
2313
2314                     code = emitInsCode(INS_addi);
2315                     code |= (code_t)reg1 << 7;
2316                     code |= (code_t)reg1 << 15;
2317                     code |= (code_t)((low >> 21) & 0x7ff) << 20;
2318                     *(code_t*)dstRW = code;
2319                     dstRW += 4;
2320
2321                     code = emitInsCode(INS_slli);
2322                     code |= (code_t)reg1 << 7;
2323                     code |= (code_t)reg1 << 15;
2324                     code |= (code_t)11 << 20;
2325                     *(code_t*)dstRW = code;
2326                     dstRW += 4;
2327
2328                     code = emitInsCode(INS_addi);
2329                     code |= (code_t)reg1 << 7;
2330                     code |= (code_t)reg1 << 15;
2331                     code |= (code_t)((low >> 10) & 0x7ff) << 20;
2332                     *(code_t*)dstRW = code;
2333                     dstRW += 4;
2334
2335                     code = emitInsCode(INS_slli);
2336                     code |= (code_t)reg1 << 7;
2337                     code |= (code_t)reg1 << 15;
2338                     code |= (code_t)10 << 20;
2339                     *(code_t*)dstRW = code;
2340                     dstRW += 4;
2341
2342                     code = emitInsCode(INS_addi);
2343                     code |= (code_t)reg1 << 7;
2344                     code |= (code_t)reg1 << 15;
2345                     code |= (code_t)((low)&0x3ff) << 20;
2346                     *(code_t*)dstRW = code;
2347                     break;
2348                 }
2349                 default:
2350                     unreached();
2351                     break;
2352             }
2353
2354             ins = INS_addi;
2355             dstRW += 4;
2356
2357             sz = sizeof(instrDesc);
2358         }
2359         break;
2360         case INS_OPTS_RC:
2361         {
2362             // Reference to JIT data
2363             assert(id->idAddr()->iiaIsJitDataOffset());
2364             assert(id->idGCref() == GCT_NONE);
2365
2366             int doff = id->idAddr()->iiaGetJitDataOffset();
2367             assert(doff >= 0);
2368
2369             ssize_t imm = emitGetInsSC(id);
2370             assert((imm >= 0) && (imm < 0x4000)); // 0x4000 is arbitrary, currently 'imm' is always 0.
2371
2372             unsigned dataOffs = (unsigned)(doff + imm);
2373
2374             assert(dataOffs < emitDataSize());
2375
2376             ins            = id->idIns();
2377             regNumber reg1 = id->idReg1();
2378
2379             if (id->idIsReloc())
2380             {
2381                 // get the addr-offset of the data.
2382                 imm = (ssize_t)emitConsBlock - (ssize_t)(dstRW - writeableOffset) + dataOffs;
2383                 assert(imm > 0);
2384                 assert(!(imm & 3));
2385
2386                 doff = (int)(imm & 0xfff);
2387                 assert(isValidSimm20((imm + 0x800) >> 12));
2388
2389 #ifdef DEBUG
2390                 code = emitInsCode(INS_auipc);
2391                 assert(code == 0x00000017);
2392 #endif
2393                 code            = 0x00000017 | (codeGen->rsGetRsvdReg() << 7);
2394                 *(code_t*)dstRW = code | ((code_t)((imm + 0x800) & 0xfffff000));
2395                 dstRW += 4;
2396
2397                 if (ins == INS_jal)
2398                 {
2399                     assert(isGeneralRegister(reg1));
2400                     ins = INS_addi;
2401 #ifdef DEBUG
2402                     code = emitInsCode(INS_addi);
2403                     assert(code == 0x00000013);
2404 #endif
2405                     code            = 0x00000013 | (codeGen->rsGetRsvdReg() << 15);
2406                     *(code_t*)dstRW = code | ((code_t)reg1 << 7) | (((code_t)doff & 0xfff) << 20);
2407                 }
2408                 else
2409                 {
2410                     code = emitInsCode(ins);
2411                     code |= (code_t)(reg1 & 0x1f) << 7;
2412                     code |= (code_t)codeGen->rsGetRsvdReg() << 15;
2413                     code |= (code_t)(doff & 0xfff) << 20;
2414                     *(code_t*)dstRW = code;
2415                 }
2416                 dstRW += 4;
2417             }
2418             else
2419             {
2420                 // get the addr of the data.
2421                 imm = (ssize_t)emitConsBlock + dataOffs;
2422
2423                 code = emitInsCode(INS_lui);
2424                 if (ins == INS_jal)
2425                 {
2426                     assert((imm >> 40) == 0);
2427
2428                     doff = imm & 0x7ff;
2429
2430                     UINT32 high = imm >> 11;
2431
2432                     code |= (code_t)codeGen->rsGetRsvdReg() << 7;
2433                     code |= (code_t)(((high + 0x800) >> 12) << 12);
2434                     *(code_t*)dstRW = code;
2435                     dstRW += 4;
2436
2437                     code = emitInsCode(INS_addi);
2438                     code |= (code_t)codeGen->rsGetRsvdReg() << 7;
2439                     code |= (code_t)codeGen->rsGetRsvdReg() << 15;
2440                     code |= (code_t)(high & 0xFFF) << 20;
2441                     *(code_t*)dstRW = code;
2442                     dstRW += 4;
2443
2444                     code = emitInsCode(INS_slli);
2445                     code |= (code_t)codeGen->rsGetRsvdReg() << 7;
2446                     code |= (code_t)codeGen->rsGetRsvdReg() << 15;
2447                     code |= (code_t)11 << 20;
2448                     *(code_t*)dstRW = code;
2449                     dstRW += 4;
2450
2451                     ins  = INS_addi;
2452                     code = emitInsCode(INS_addi);
2453                     code |= (code_t)reg1 << 7;
2454                     code |= (code_t)codeGen->rsGetRsvdReg() << 15;
2455                     code |= (code_t)doff << 20;
2456                     *(code_t*)dstRW = code;
2457                     dstRW += 4;
2458                 }
2459                 else
2460                 {
2461                     assert((imm >> 40) == 0);
2462
2463                     doff        = imm & 0x7ff;
2464                     UINT32 high = imm >> 11;
2465
2466                     code |= (code_t)(codeGen->rsGetRsvdReg() << 7);
2467                     code |= (code_t)(((high + 0x800) >> 12) << 12);
2468                     *(code_t*)dstRW = code;
2469                     dstRW += 4;
2470
2471                     code = emitInsCode(INS_addi);
2472                     code |= (code_t)codeGen->rsGetRsvdReg() << 7;
2473                     code |= (code_t)codeGen->rsGetRsvdReg() << 15;
2474                     code |= (code_t)(high & 0xFFF) << 20;
2475                     *(code_t*)dstRW = code;
2476                     dstRW += 4;
2477
2478                     code = emitInsCode(INS_slli);
2479                     code |= (code_t)codeGen->rsGetRsvdReg() << 7;
2480                     code |= (code_t)codeGen->rsGetRsvdReg() << 15;
2481                     code |= (code_t)11 << 20;
2482                     *(code_t*)dstRW = code;
2483                     dstRW += 4;
2484
2485                     code = emitInsCode(ins);
2486                     code |= (code_t)(reg1 & 0x1f) << 7;
2487                     code |= (code_t)codeGen->rsGetRsvdReg() << 15;
2488                     code |= (code_t)doff << 20;
2489                     *(code_t*)dstRW = code;
2490                     dstRW += 4;
2491                 }
2492             }
2493
2494             sz = sizeof(instrDesc);
2495         }
2496         break;
2497
2498         case INS_OPTS_RL:
2499         {
2500             insGroup* tgtIG          = (insGroup*)emitCodeGetCookie(id->idAddr()->iiaBBlabel);
2501             id->idAddr()->iiaIGlabel = tgtIG;
2502
2503             regNumber reg1 = id->idReg1();
2504             assert(isGeneralRegister(reg1));
2505
2506             if (id->idIsReloc())
2507             {
2508                 ssize_t imm = (ssize_t)tgtIG->igOffs;
2509                 imm         = (ssize_t)emitCodeBlock + imm - (ssize_t)(dstRW - writeableOffset);
2510                 assert((imm & 3) == 0);
2511
2512                 int doff = (int)(imm & 0xfff);
2513                 assert(isValidSimm20((imm + 0x800) >> 12));
2514
2515                 code            = 0x00000017;
2516                 *(code_t*)dstRW = code | (code_t)reg1 << 7 | ((imm + 0x800) & 0xfffff000);
2517                 dstRW += 4;
2518 #ifdef DEBUG
2519                 code = emitInsCode(INS_auipc);
2520                 assert(code == 0x00000017);
2521                 code = emitInsCode(INS_addi);
2522                 assert(code == 0x00000013);
2523 #endif
2524                 ins             = INS_addi;
2525                 *(code_t*)dstRW = 0x00000013 | ((code_t)reg1 << 7) | ((code_t)reg1 << 15) | ((doff & 0xfff) << 20);
2526             }
2527             else
2528             {
2529                 ssize_t imm = (ssize_t)tgtIG->igOffs + (ssize_t)emitCodeBlock;
2530                 assert((imm >> (32 + 20)) == 0);
2531
2532                 code = emitInsCode(INS_lui);
2533                 code |= (code_t)codeGen->rsGetRsvdReg() << 7;
2534                 code |= ((code_t)((imm + 0x800) >> 12) & 0xfffff) << 12;
2535
2536                 *(code_t*)dstRW = code;
2537                 dstRW += 4;
2538
2539                 code = emitInsCode(INS_addi);
2540                 code |= (code_t)codeGen->rsGetRsvdReg() << 7;
2541                 code |= (code_t)codeGen->rsGetRsvdReg() << 15;
2542                 code |= (code_t)(imm & 0xfff) << 20;
2543                 *(code_t*)dstRW = code;
2544                 dstRW += 4;
2545
2546                 code = emitInsCode(INS_addi);
2547                 code |= (code_t)reg1 << 7;
2548                 code |= (((imm + 0x80000800) >> 32) & 0xfff) << 20;
2549                 *(code_t*)dstRW = code;
2550                 dstRW += 4;
2551
2552                 code = emitInsCode(INS_slli);
2553                 code |= (code_t)reg1 << 7;
2554                 code |= (code_t)reg1 << 15;
2555                 code |= (code_t)32 << 20;
2556                 *(code_t*)dstRW = code;
2557                 dstRW += 4;
2558
2559                 ins  = INS_add;
2560                 code = emitInsCode(INS_add);
2561                 code |= (code_t)reg1 << 7;
2562                 code |= (code_t)reg1 << 15;
2563                 code |= (code_t)codeGen->rsGetRsvdReg() << 20;
2564                 *(code_t*)dstRW = code;
2565             }
2566
2567             dstRW += 4;
2568
2569             sz = sizeof(instrDesc);
2570         }
2571         break;
2572         case INS_OPTS_JALR:
2573         {
2574             instrDescJmp* jmp = (instrDescJmp*)id;
2575
2576             regNumber reg1 = id->idReg1();
2577             {
2578                 ssize_t imm = emitOutputInstrJumpDistance(dstRW, dst, ig, jmp);
2579                 imm -= 4;
2580
2581                 assert((imm & 0x3) == 0);
2582
2583                 ins = jmp->idIns();
2584                 assert(jmp->idCodeSize() > 4); // The original INS_OPTS_JALR: not used by now!!!
2585                 switch (jmp->idCodeSize())
2586                 {
2587                     case 8:
2588                     {
2589                         assert((INS_blt <= ins && ins <= INS_bgeu) || (INS_beq == ins) || (INS_bne == ins) ||
2590                                (INS_bnez == ins) || (INS_beqz == ins));
2591                         assert(isValidSimm21(imm));
2592                         assert((emitInsCode(INS_bne) & 0xefff) == emitInsCode(INS_beq));
2593                         assert((emitInsCode(INS_bge) & 0xefff) == emitInsCode(INS_blt));
2594                         assert((emitInsCode(INS_bgeu) & 0xefff) == emitInsCode(INS_bltu));
2595
2596                         regNumber reg2 = REG_R0;
2597                         if (INS_beqz != ins && INS_bnez != ins)
2598                             reg2 = id->idReg2();
2599                         code     = emitInsCode(ins) ^ 0x1000;
2600                         code |= (code_t)reg1 << 15; /* rj */
2601                         code |= (code_t)reg2 << 20; /* rd */
2602                         code |= 0x8 << 7;
2603                         *(code_t*)dstRW = code;
2604                         dstRW += 4;
2605
2606                         code = emitInsCode(INS_jal);
2607                         code |= ((imm >> 12) & 0xff) << 12;
2608                         code |= ((imm >> 11) & 0x1) << 20;
2609                         code |= ((imm >> 1) & 0x3ff) << 21;
2610                         code |= ((imm >> 20) & 0x1) << 31;
2611
2612                         *(code_t*)dstRW = code;
2613                         dstRW += 4;
2614                         break;
2615                     }
2616                     case 24:
2617                     {
2618                         assert(ins == INS_j || ins == INS_jal);
2619                         // Make target address with offset, then jump (JALR) with the target address
2620                         imm               = imm - 2 * 4;
2621                         regNumber tmpReg1 = REG_RA;
2622                         ssize_t   high    = ((imm + 0x80000000) >> 32) & 0xffffffff;
2623                         code              = emitInsCode(INS_lui);
2624                         code |= (code_t)tmpReg1 << 7;
2625                         code |= ((code_t)((high + 0x800) >> 12) & 0xfffff) << 12;
2626
2627                         *(code_t*)dstRW = code;
2628                         dstRW += 4;
2629
2630                         code = emitInsCode(INS_addi);
2631                         code |= (code_t)tmpReg1 << 7;
2632                         code |= (code_t)tmpReg1 << 15;
2633                         code |= (code_t)(high & 0xfff) << 20;
2634                         *(code_t*)dstRW = code;
2635                         dstRW += 4;
2636
2637                         code = emitInsCode(INS_slli);
2638                         code |= (code_t)tmpReg1 << 7;
2639                         code |= (code_t)tmpReg1 << 15;
2640                         code |= (code_t)32 << 20;
2641                         *(code_t*)dstRW = code;
2642                         dstRW += 4;
2643
2644                         regNumber tmpReg2 = codeGen->rsGetRsvdReg();
2645                         ssize_t   low     = imm & 0xffffffff;
2646                         code              = emitInsCode(INS_auipc);
2647                         code |= (code_t)tmpReg2 << 7;
2648                         code |= ((code_t)((low + 0x800) >> 12) & 0xfffff) << 12;
2649
2650                         *(code_t*)dstRW = code;
2651                         dstRW += 4;
2652
2653                         code = emitInsCode(INS_add);
2654                         code |= (code_t)tmpReg2 << 7;
2655                         code |= (code_t)tmpReg1 << 15;
2656                         code |= (code_t)tmpReg2 << 20;
2657                         *(code_t*)dstRW = code;
2658                         dstRW += 4;
2659
2660                         code = emitInsCode(INS_jalr);
2661                         code |= (code_t)REG_RA << 7; // use REG_RA for returning
2662                         code |= (code_t)tmpReg2 << 15;
2663                         code |= (code_t)(low & 0xfff) << 20;
2664                         *(code_t*)dstRW = code;
2665                         dstRW += 4;
2666                         break;
2667                     }
2668                     case 28:
2669                     {
2670                         assert((INS_blt <= ins && ins <= INS_bgeu) || (INS_beq == ins) || (INS_bne == ins) ||
2671                                (INS_bnez == ins) || (INS_beqz == ins));
2672                         assert((emitInsCode(INS_bne) & 0xefff) == emitInsCode(INS_beq));
2673                         assert((emitInsCode(INS_bge) & 0xefff) == emitInsCode(INS_blt));
2674                         assert((emitInsCode(INS_bgeu) & 0xefff) == emitInsCode(INS_bltu));
2675
2676                         regNumber reg2 = REG_R0;
2677                         if (INS_beqz != ins && INS_bnez != ins)
2678                             reg2 = id->idReg2();
2679                         code     = emitInsCode(ins) ^ 0x1000;
2680                         code |= (code_t)reg1 << 15; /* rj */
2681                         code |= (code_t)reg2 << 20; /* rd */
2682                         code |= 28 << 7;
2683                         *(code_t*)dstRW = code;
2684                         dstRW += 4;
2685
2686                         // Make target address with offset, then jump (JALR) with the target address
2687                         imm               = imm - 2 * 4;
2688                         regNumber tmpReg1 = REG_RA;
2689                         ssize_t   high    = ((imm + 0x80000000) >> 32) & 0xffffffff;
2690                         code              = emitInsCode(INS_lui);
2691                         code |= (code_t)tmpReg1 << 7;
2692                         code |= ((code_t)((high + 0x800) >> 12) & 0xfffff) << 12;
2693
2694                         *(code_t*)dstRW = code;
2695                         dstRW += 4;
2696
2697                         code = emitInsCode(INS_addi);
2698                         code |= (code_t)tmpReg1 << 7;
2699                         code |= (code_t)tmpReg1 << 15;
2700                         code |= (code_t)(high & 0xfff) << 20;
2701                         *(code_t*)dstRW = code;
2702                         dstRW += 4;
2703
2704                         code = emitInsCode(INS_slli);
2705                         code |= (code_t)tmpReg1 << 7;
2706                         code |= (code_t)tmpReg1 << 15;
2707                         code |= (code_t)32 << 20;
2708                         *(code_t*)dstRW = code;
2709                         dstRW += 4;
2710
2711                         regNumber tmpReg2 = codeGen->rsGetRsvdReg();
2712                         ssize_t   low     = imm & 0xffffffff;
2713                         code              = emitInsCode(INS_auipc);
2714                         code |= (code_t)tmpReg2 << 7;
2715                         code |= ((code_t)((low + 0x800) >> 12) & 0xfffff) << 12;
2716
2717                         *(code_t*)dstRW = code;
2718                         dstRW += 4;
2719
2720                         code = emitInsCode(INS_add);
2721                         code |= (code_t)tmpReg2 << 7;
2722                         code |= (code_t)tmpReg1 << 15;
2723                         code |= (code_t)tmpReg2 << 20;
2724                         *(code_t*)dstRW = code;
2725                         dstRW += 4;
2726
2727                         code = emitInsCode(INS_jalr);
2728                         code |= (code_t)REG_RA << 7; // use REG_RA for returning
2729                         code |= (code_t)tmpReg2 << 15;
2730                         code |= (code_t)(low & 0xfff) << 20;
2731                         *(code_t*)dstRW = code;
2732                         dstRW += 4;
2733
2734                         break;
2735                     }
2736
2737                     default:
2738                         unreached();
2739                         break;
2740                 }
2741             }
2742             sz = sizeof(instrDescJmp);
2743         }
2744         break;
2745         case INS_OPTS_J_cond:
2746         {
2747             ssize_t imm = emitOutputInstrJumpDistance(dstRW, dst, ig, static_cast<instrDescJmp*>(id));
2748             assert(isValidSimm13(imm));
2749             assert(!(imm & 1));
2750
2751             ins  = id->idIns();
2752             code = emitInsCode(ins);
2753             code |= ((code_t)id->idReg1()) << 15;
2754             code |= ((code_t)id->idReg2()) << 20;
2755             code |= ((imm >> 11) & 0x1) << 7;
2756             code |= ((imm >> 1) & 0xf) << 8;
2757             code |= ((imm >> 5) & 0x3f) << 25;
2758             code |= ((imm >> 12) & 0x1) << 31;
2759             *(code_t*)dstRW = code;
2760             dstRW += 4;
2761
2762             sz = sizeof(instrDescJmp);
2763         }
2764         break;
2765         case INS_OPTS_J:
2766             // jal/j/jalr/bnez/beqz/beq/bne/blt/bge/bltu/bgeu dstRW-relative.
2767             {
2768                 ssize_t imm = emitOutputInstrJumpDistance(dstRW, dst, ig, static_cast<instrDescJmp*>(id));
2769                 assert((imm & 3) == 0);
2770
2771                 ins  = id->idIns();
2772                 code = emitInsCode(ins);
2773                 if (ins == INS_jal)
2774                 {
2775                     assert(isValidSimm21(imm));
2776                     code |= ((imm >> 12) & 0xff) << 12;
2777                     code |= ((imm >> 11) & 0x1) << 20;
2778                     code |= ((imm >> 1) & 0x3ff) << 21;
2779                     code |= ((imm >> 20) & 0x1) << 31;
2780                     code |= REG_RA << 7;
2781                 }
2782                 else if (ins == INS_j)
2783                 {
2784                     assert(isValidSimm21(imm));
2785                     code |= ((imm >> 12) & 0xff) << 12;
2786                     code |= ((imm >> 11) & 0x1) << 20;
2787                     code |= ((imm >> 1) & 0x3ff) << 21;
2788                     code |= ((imm >> 20) & 0x1) << 31;
2789                 }
2790                 else if (ins == INS_jalr)
2791                 {
2792                     assert(isValidSimm12(imm));
2793                     code |= ((code_t)(imm & 0xfff) << 20);
2794                     code |= ((code_t)id->idReg1()) << 7;
2795                     code |= ((code_t)id->idReg2()) << 15;
2796                 }
2797                 else if (ins == INS_bnez || ins == INS_beqz)
2798                 {
2799                     assert(isValidSimm13(imm));
2800                     code |= (code_t)id->idReg1() << 15;
2801                     code |= ((imm >> 11) & 0x1) << 7;
2802                     code |= ((imm >> 1) & 0xf) << 8;
2803                     code |= ((imm >> 5) & 0x3f) << 25;
2804                     code |= ((imm >> 12) & 0x1) << 31;
2805                 }
2806                 else if ((INS_beq <= ins) && (ins <= INS_bgeu))
2807                 {
2808                     assert(isValidSimm13(imm));
2809                     code |= ((code_t)id->idReg1()) << 15;
2810                     code |= ((code_t)id->idReg2()) << 20;
2811                     code |= ((imm >> 11) & 0x1) << 7;
2812                     code |= ((imm >> 1) & 0xf) << 8;
2813                     code |= ((imm >> 5) & 0x3f) << 25;
2814                     code |= ((imm >> 12) & 0x1) << 31;
2815                 }
2816                 else
2817                 {
2818                     unreached();
2819                 }
2820
2821                 *(code_t*)dstRW = code;
2822                 dstRW += 4;
2823
2824                 sz = sizeof(instrDescJmp);
2825             }
2826             break;
2827         case INS_OPTS_C:
2828             if (id->idIsLargeCall())
2829             {
2830                 /* Must be a "fat" call descriptor */
2831                 sz = sizeof(instrDescCGCA);
2832             }
2833             else
2834             {
2835                 assert(!id->idIsLargeDsp());
2836                 assert(!id->idIsLargeCns());
2837                 sz = sizeof(instrDesc);
2838             }
2839             dstRW += emitOutputCall(ig, *dp, id, 0);
2840
2841             dstRW2 = dstRW;
2842             ins    = INS_nop;
2843             break;
2844
2845         // case INS_OPTS_NONE:
2846         default:
2847             *(code_t*)dstRW = id->idAddr()->iiaGetInstrEncode();
2848             dstRW += 4;
2849             ins = id->idIns();
2850             sz  = emitSizeOfInsDsc(id);
2851             break;
2852     }
2853
2854     // Determine if any registers now hold GC refs, or whether a register that was overwritten held a GC ref.
2855     // We assume here that "id->idGCref()" is not GC_NONE only if the instruction described by "id" writes a
2856     // GC ref to register "id->idReg1()".  (It may, apparently, also not be GC_NONE in other cases, such as
2857     // for stores, but we ignore those cases here.)
2858     if (emitInsMayWriteToGCReg(ins)) // True if "id->idIns()" writes to a register than can hold GC ref.
2859     {
2860         // We assume that "idReg1" is the primary destination register for all instructions
2861         if (id->idGCref() != GCT_NONE)
2862         {
2863             emitGCregLiveUpd(id->idGCref(), id->idReg1(), dstRW2 - writeableOffset);
2864         }
2865         else
2866         {
2867             emitGCregDeadUpd(id->idReg1(), dstRW2 - writeableOffset);
2868         }
2869     }
2870
2871     // Now we determine if the instruction has written to a (local variable) stack location, and either written a GC
2872     // ref or overwritten one.
2873     if (emitInsWritesToLclVarStackLoc(id) /*|| emitInsWritesToLclVarStackLocPair(id)*/)
2874     {
2875         int      varNum = id->idAddr()->iiaLclVar.lvaVarNum();
2876         unsigned ofs    = AlignDown(id->idAddr()->iiaLclVar.lvaOffset(), TARGET_POINTER_SIZE);
2877         bool     FPbased;
2878         int      adr = emitComp->lvaFrameAddress(varNum, &FPbased);
2879         if (id->idGCref() != GCT_NONE)
2880         {
2881             emitGCvarLiveUpd(adr + ofs, varNum, id->idGCref(), dstRW2 - writeableOffset DEBUG_ARG(varNum));
2882         }
2883         else
2884         {
2885             // If the type of the local is a gc ref type, update the liveness.
2886             var_types vt;
2887             if (varNum >= 0)
2888             {
2889                 // "Regular" (non-spill-temp) local.
2890                 vt = var_types(emitComp->lvaTable[varNum].lvType);
2891             }
2892             else
2893             {
2894                 TempDsc* tmpDsc = codeGen->regSet.tmpFindNum(varNum);
2895                 vt              = tmpDsc->tdTempType();
2896             }
2897             if (vt == TYP_REF || vt == TYP_BYREF)
2898                 emitGCvarDeadUpd(adr + ofs, dstRW2 - writeableOffset DEBUG_ARG(varNum));
2899         }
2900         // if (emitInsWritesToLclVarStackLocPair(id))
2901         //{
2902         //    unsigned ofs2 = ofs + TARGET_POINTER_SIZE;
2903         //    if (id->idGCrefReg2() != GCT_NONE)
2904         //    {
2905         //        emitGCvarLiveUpd(adr + ofs2, varNum, id->idGCrefReg2(), *dp);
2906         //    }
2907         //    else
2908         //    {
2909         //        // If the type of the local is a gc ref type, update the liveness.
2910         //        var_types vt;
2911         //        if (varNum >= 0)
2912         //        {
2913         //            // "Regular" (non-spill-temp) local.
2914         //            vt = var_types(emitComp->lvaTable[varNum].lvType);
2915         //        }
2916         //        else
2917         //        {
2918         //            TempDsc* tmpDsc = codeGen->regSet.tmpFindNum(varNum);
2919         //            vt              = tmpDsc->tdTempType();
2920         //        }
2921         //        if (vt == TYP_REF || vt == TYP_BYREF)
2922         //            emitGCvarDeadUpd(adr + ofs2, *dp);
2923         //    }
2924         //}
2925     }
2926
2927 #ifdef DEBUG
2928     /* Make sure we set the instruction descriptor size correctly */
2929
2930     if (emitComp->opts.disAsm || emitComp->verbose)
2931     {
2932 #if DUMP_GC_TABLES
2933         bool dspOffs = emitComp->opts.dspGCtbls;
2934 #else  // !DUMP_GC_TABLES
2935         bool dspOffs = !emitComp->opts.disDiffable;
2936 #endif // !DUMP_GC_TABLES
2937         emitDispIns(id, false, dspOffs, true, emitCurCodeOffs(odst), *dp, (dstRW - odstRW), ig);
2938     }
2939
2940     if (emitComp->compDebugBreak)
2941     {
2942         // For example, set JitBreakEmitOutputInstr=a6 will break when this method is called for
2943         // emitting instruction a6, (i.e. IN00a6 in jitdump).
2944         if ((unsigned)JitConfig.JitBreakEmitOutputInstr() == id->idDebugOnlyInfo()->idNum)
2945         {
2946             assert(!"JitBreakEmitOutputInstr reached");
2947         }
2948     }
2949 #else  // !DEBUG
2950     if (emitComp->opts.disAsm)
2951     {
2952         emitDispIns(id, false, false, true, emitCurCodeOffs(odst), *dp, (dstRW - odstRW), ig);
2953     }
2954 #endif // !DEBUG
2955
2956     /* All instructions are expected to generate code */
2957
2958     assert(*dp != (dstRW - writeableOffset));
2959
2960     *dp = dstRW - writeableOffset;
2961
2962     return sz;
2963 }
2964
2965 bool emitter::emitDispBranchInstrType(unsigned opcode2) const
2966 {
2967     switch (opcode2)
2968     {
2969         case 0:
2970             printf("beq ");
2971             break;
2972         case 1:
2973             printf("bne ");
2974             break;
2975         case 4:
2976             printf("blt ");
2977             break;
2978         case 5:
2979             printf("bge ");
2980             break;
2981         case 6:
2982             printf("bltu");
2983             break;
2984         case 7:
2985             printf("bgeu");
2986             break;
2987         default:
2988             return false;
2989     }
2990     return true;
2991 }
2992
2993 void emitter::emitDispBranchOffset(const instrDesc* id, const insGroup* ig) const
2994 {
2995     int instrCount = id->idAddr()->iiaGetInstrCount();
2996     if (ig == nullptr)
2997     {
2998         printf("pc%+d instructions", instrCount);
2999         return;
3000     }
3001     unsigned insNum = emitFindInsNum(ig, id);
3002
3003     if (ig->igInsCnt < insNum + 1 + instrCount)
3004     {
3005         // TODO-RISCV64-BUG: This should be a labeled offset but does not contain an iiaIGlabel
3006         printf("pc%+d instructions", instrCount);
3007         return;
3008     }
3009
3010     UNATIVE_OFFSET srcOffs = ig->igOffs + emitFindOffset(ig, insNum + 1);
3011     UNATIVE_OFFSET dstOffs = ig->igOffs + emitFindOffset(ig, insNum + 1 + instrCount);
3012     ssize_t        relOffs = static_cast<ssize_t>(emitOffsetToPtr(dstOffs) - emitOffsetToPtr(srcOffs));
3013     printf("pc%+d (%d instructions)", static_cast<int>(relOffs), instrCount);
3014 }
3015
3016 void emitter::emitDispBranchLabel(const instrDesc* id) const
3017 {
3018     if (id->idIsBound())
3019     {
3020         return emitPrintLabel(id->idAddr()->iiaIGlabel);
3021     }
3022     printf("L_M%03u_", FMT_BB, emitComp->compMethodID, id->idAddr()->iiaBBlabel->bbNum);
3023 }
3024
3025 bool emitter::emitDispBranch(unsigned         opcode2,
3026                              const char*      register1Name,
3027                              const char*      register2Name,
3028                              const instrDesc* id,
3029                              const insGroup*  ig) const
3030 {
3031     if (!emitDispBranchInstrType(opcode2))
3032     {
3033         return false;
3034     }
3035     printf("           %s, %s, ", register1Name, register2Name);
3036     assert(id != nullptr);
3037     if (id->idAddr()->iiaHasInstrCount())
3038     {
3039         // Branch is jumping to some non-labeled offset
3040         emitDispBranchOffset(id, ig);
3041     }
3042     else
3043     {
3044         // Branch is jumping to the labeled offset
3045         emitDispBranchLabel(id);
3046     }
3047     printf("\n");
3048     return true;
3049 }
3050
3051 void emitter::emitDispIllegalInstruction(code_t instructionCode)
3052 {
3053     printf("RISCV64 illegal instruction: 0x%08X\n", instructionCode);
3054 }
3055
3056 /*****************************************************************************/
3057 /*****************************************************************************/
3058
3059 // clang-format off
3060 static const char* const RegNames[] =
3061 {
3062     #define REGDEF(name, rnum, mask, sname) sname,
3063     #include "register.h"
3064 };
3065 // clang-format on
3066
3067 //----------------------------------------------------------------------------------------
3068 // Disassemble the given instruction.
3069 // The `emitter::emitDispInsName` is focused on the most important for debugging.
3070 // So it implemented as far as simply and independently which is very useful for
3071 // porting easily to the release mode.
3072 //
3073 // Arguments:
3074 //    code - The instruction's encoding.
3075 //    addr - The address of the code.
3076 //    doffs - Flag informing whether the instruction's offset should be displayed.
3077 //    insOffset - The instruction's offset.
3078 //    id   - The instrDesc of the code if needed.
3079 //    ig   - The insGroup of the code if needed
3080 //
3081 // Note:
3082 //    The length of the instruction's name include aligned space is 15.
3083 //
3084
3085 void emitter::emitDispInsName(
3086     code_t code, const BYTE* addr, bool doffs, unsigned insOffset, const instrDesc* id, const insGroup* ig)
3087 {
3088     const BYTE* insAdr = addr - writeableOffset;
3089
3090     unsigned int opcode = code & 0x7f;
3091     assert((opcode & 0x3) == 0x3);
3092
3093     emitDispInsAddr(insAdr);
3094     emitDispInsOffs(insOffset, doffs);
3095
3096     printf("      ");
3097
3098     switch (opcode)
3099     {
3100         case 0x37: // LUI
3101         {
3102             const char* rd    = RegNames[(code >> 7) & 0x1f];
3103             int         imm20 = (code >> 12) & 0xfffff;
3104             if (imm20 & 0x80000)
3105             {
3106                 imm20 |= 0xfff00000;
3107             }
3108             printf("lui            %s, %d\n", rd, imm20);
3109             return;
3110         }
3111         case 0x17: // AUIPC
3112         {
3113             const char* rd    = RegNames[(code >> 7) & 0x1f];
3114             int         imm20 = (code >> 12) & 0xfffff;
3115             if (imm20 & 0x80000)
3116             {
3117                 imm20 |= 0xfff00000;
3118             }
3119             printf("auipc          %s, %d\n", rd, imm20);
3120             return;
3121         }
3122         case 0x13:
3123         {
3124             unsigned int opcode2 = (code >> 12) & 0x7;
3125             const char*  rd      = RegNames[(code >> 7) & 0x1f];
3126             const char*  rs1     = RegNames[(code >> 15) & 0x1f];
3127             int          imm12   = (((int)code) >> 20); // & 0xfff;
3128             // if (imm12 & 0x800)
3129             //{
3130             //    imm12 |= 0xfffff000;
3131             //}
3132             switch (opcode2)
3133             {
3134                 case 0x0: // ADDI
3135                     printf("addi           %s, %s, %d\n", rd, rs1, imm12);
3136                     return;
3137                 case 0x1:                                                         // SLLI
3138                     printf("slli           %s, %s, %d\n", rd, rs1, imm12 & 0x3f); // 6 BITS for SHAMT in RISCV64
3139                     return;
3140                 case 0x2: // SLTI
3141                     printf("slti           %s, %s, %d\n", rd, rs1, imm12);
3142                     return;
3143                 case 0x3: // SLTIU
3144                     printf("sltiu          %s, %s, %d\n", rd, rs1, imm12);
3145                     return;
3146                 case 0x4: // XORI
3147                     printf("xori           %s, %s, 0x%x\n", rd, rs1, imm12);
3148                     return;
3149                 case 0x5: // SRLI & SRAI
3150                     if (((code >> 30) & 0x1) == 0)
3151                     {
3152                         printf("srli           %s, %s, %d\n", rd, rs1, imm12 & 0x3f); // 6BITS for SHAMT in RISCV64
3153                     }
3154                     else
3155                     {
3156                         printf("srai           %s, %s, %d\n", rd, rs1, imm12 & 0x3f); // 6BITS for SHAMT in RISCV64
3157                     }
3158                     return;
3159                 case 0x6: // ORI
3160                     printf("ori            %s, %s, 0x%x\n", rd, rs1, imm12 & 0xfff);
3161                     return;
3162                 case 0x7: // ANDI
3163                     printf("andi           %s, %s, 0x%x\n", rd, rs1, imm12 & 0xfff);
3164                     return;
3165                 default:
3166                     printf("RISCV64 illegal instruction: 0x%08X\n", code);
3167                     return;
3168             }
3169         }
3170         case 0x1b:
3171         {
3172             unsigned int opcode2 = (code >> 12) & 0x7;
3173             const char*  rd      = RegNames[(code >> 7) & 0x1f];
3174             const char*  rs1     = RegNames[(code >> 15) & 0x1f];
3175             int          imm12   = (((int)code) >> 20); // & 0xfff;
3176             // if (imm12 & 0x800)
3177             //{
3178             //    imm12 |= 0xfffff000;
3179             //}
3180             switch (opcode2)
3181             {
3182                 case 0x0: // ADDIW
3183                     printf("addiw          %s, %s, %d\n", rd, rs1, imm12);
3184                     return;
3185                 case 0x1:                                                         // SLLIW
3186                     printf("slliw          %s, %s, %d\n", rd, rs1, imm12 & 0x3f); // 6 BITS for SHAMT in RISCV64
3187                     return;
3188                 case 0x5: // SRLIW & SRAIW
3189                     if (((code >> 30) & 0x1) == 0)
3190                     {
3191                         printf("srliw          %s, %s, %d\n", rd, rs1, imm12 & 0x1f); // 5BITS for SHAMT in RISCV64
3192                     }
3193                     else
3194                     {
3195                         printf("sraiw          %s, %s, %d\n", rd, rs1, imm12 & 0x1f); // 5BITS for SHAMT in RISCV64
3196                     }
3197                     return;
3198                 default:
3199                     printf("RISCV64 illegal instruction: 0x%08X\n", code);
3200                     return;
3201             }
3202         }
3203         case 0x33:
3204         {
3205             unsigned int opcode2 = (code >> 25) & 0x3;
3206             unsigned int opcode3 = (code >> 12) & 0x7;
3207             const char*  rd      = RegNames[(code >> 7) & 0x1f];
3208             const char*  rs1     = RegNames[(code >> 15) & 0x1f];
3209             const char*  rs2     = RegNames[(code >> 20) & 0x1f];
3210             if (opcode2 == 0)
3211             {
3212                 switch (opcode3)
3213                 {
3214                     case 0x0: // ADD & SUB
3215                         if (((code >> 30) & 0x1) == 0)
3216                         {
3217                             printf("add            %s, %s, %s\n", rd, rs1, rs2);
3218                         }
3219                         else
3220                         {
3221                             printf("sub            %s, %s, %s\n", rd, rs1, rs2);
3222                         }
3223                         return;
3224                     case 0x1: // SLL
3225                         printf("sll            %s, %s, %s\n", rd, rs1, rs2);
3226                         return;
3227                     case 0x2: // SLT
3228                         printf("slt            %s, %s, %s\n", rd, rs1, rs2);
3229                         return;
3230                     case 0x3: // SLTU
3231                         printf("sltu           %s, %s, %s\n", rd, rs1, rs2);
3232                         return;
3233                     case 0x4: // XOR
3234                         printf("xor            %s, %s, %s\n", rd, rs1, rs2);
3235                         return;
3236                     case 0x5: // SRL & SRA
3237                         if (((code >> 30) & 0x1) == 0)
3238                         {
3239                             printf("srl            %s, %s, %s\n", rd, rs1, rs2);
3240                         }
3241                         else
3242                         {
3243                             printf("sra            %s, %s, %s\n", rd, rs1, rs2);
3244                         }
3245                         return;
3246                     case 0x6: // OR
3247                         printf("or             %s, %s, %s\n", rd, rs1, rs2);
3248                         return;
3249                     case 0x7: // AND
3250                         printf("and            %s, %s, %s\n", rd, rs1, rs2);
3251                         return;
3252                     default:
3253                         printf("RISCV64 illegal instruction: 0x%08X\n", code);
3254                         return;
3255                 }
3256             }
3257             else if (opcode2 == 0x1)
3258             {
3259                 switch (opcode3)
3260                 {
3261                     case 0x0: // MUL
3262                         printf("mul            %s, %s, %s\n", rd, rs1, rs2);
3263                         return;
3264                     case 0x1: // MULH
3265                         printf("mulh           %s, %s, %s\n", rd, rs1, rs2);
3266                         return;
3267                     case 0x2: // MULHSU
3268                         printf("mulhsu         %s, %s, %s\n", rd, rs1, rs2);
3269                         return;
3270                     case 0x3: // MULHU
3271                         printf("mulhu          %s, %s, %s\n", rd, rs1, rs2);
3272                         return;
3273                     case 0x4: // DIV
3274                         printf("div            %s, %s, %s\n", rd, rs1, rs2);
3275                         return;
3276                     case 0x5: // DIVU
3277                         printf("divu           %s, %s, %s\n", rd, rs1, rs2);
3278                         return;
3279                     case 0x6: // REM
3280                         printf("rem            %s, %s, %s\n", rd, rs1, rs2);
3281                         return;
3282                     case 0x7: // REMU
3283                         printf("remu           %s, %s, %s\n", rd, rs1, rs2);
3284                         return;
3285                     default:
3286                         printf("RISCV64 illegal instruction: 0x%08X\n", code);
3287                         return;
3288                 }
3289             }
3290             else
3291             {
3292                 printf("RISCV64 illegal instruction: 0x%08X\n", code);
3293                 return;
3294             }
3295         }
3296         case 0x3b:
3297         {
3298             unsigned int opcode2 = (code >> 25) & 0x3;
3299             unsigned int opcode3 = (code >> 12) & 0x7;
3300             const char*  rd      = RegNames[(code >> 7) & 0x1f];
3301             const char*  rs1     = RegNames[(code >> 15) & 0x1f];
3302             const char*  rs2     = RegNames[(code >> 20) & 0x1f];
3303
3304             if (opcode2 == 0)
3305             {
3306                 switch (opcode3)
3307                 {
3308                     case 0x0: // ADDW & SUBW
3309                         if (((code >> 30) & 0x1) == 0)
3310                         {
3311                             printf("addw           %s, %s, %s\n", rd, rs1, rs2);
3312                         }
3313                         else
3314                         {
3315                             printf("subw           %s, %s, %s\n", rd, rs1, rs2);
3316                         }
3317                         return;
3318                     case 0x1: // SLLW
3319                         printf("sllw           %s, %s, %s\n", rd, rs1, rs2);
3320                         return;
3321                     case 0x5: // SRLW & SRAW
3322                         if (((code >> 30) & 0x1) == 0)
3323                         {
3324                             printf("srlw           %s, %s, %s\n", rd, rs1, rs2);
3325                         }
3326                         else
3327                         {
3328                             printf("sraw           %s, %s, %s\n", rd, rs1, rs2);
3329                         }
3330                         return;
3331                     default:
3332                         printf("RISCV64 illegal instruction: 0x%08X\n", code);
3333                         return;
3334                 }
3335             }
3336             else if (opcode2 == 1)
3337             {
3338                 switch (opcode3)
3339                 {
3340                     case 0x0: // MULW
3341                         printf("mulw           %s, %s, %s\n", rd, rs1, rs2);
3342                         return;
3343                     case 0x4: // DIVW
3344                         printf("divw           %s, %s, %s\n", rd, rs1, rs2);
3345                         return;
3346                     case 0x5: // DIVUW
3347                         printf("divuw          %s, %s, %s\n", rd, rs1, rs2);
3348                         return;
3349                     case 0x6: // REMW
3350                         printf("remw           %s, %s, %s\n", rd, rs1, rs2);
3351                         return;
3352                     case 0x7: // REMUW
3353                         printf("remuw          %s, %s, %s\n", rd, rs1, rs2);
3354                         return;
3355                     default:
3356                         printf("RISCV64 illegal instruction: 0x%08X\n", code);
3357                         return;
3358                 }
3359             }
3360             else
3361             {
3362                 printf("RISCV64 illegal instruction: 0x%08X\n", code);
3363                 return;
3364             }
3365         }
3366         case 0x23:
3367         {
3368             unsigned int opcode2 = (code >> 12) & 0x7;
3369             const char*  rs1     = RegNames[(code >> 15) & 0x1f];
3370             const char*  rs2     = RegNames[(code >> 20) & 0x1f];
3371             int          offset  = (((code >> 25) & 0x7f) << 5) | ((code >> 7) & 0x1f);
3372             if (offset & 0x800)
3373             {
3374                 offset |= 0xfffff000;
3375             }
3376
3377             switch (opcode2)
3378             {
3379                 case 0: // SB
3380                     printf("sb             %s, %d(%s)\n", rs2, offset, rs1);
3381                     return;
3382                 case 1: // SH
3383                     printf("sh             %s, %d(%s)\n", rs2, offset, rs1);
3384                     return;
3385                 case 2: // SW
3386                     printf("sw             %s, %d(%s)\n", rs2, offset, rs1);
3387                     return;
3388                 case 3: // SD
3389                     printf("sd             %s, %d(%s)\n", rs2, offset, rs1);
3390                     return;
3391                 default:
3392                     printf("RISCV64 illegal instruction: 0x%08X\n", code);
3393                     return;
3394             }
3395         }
3396         case 0x63: // BRANCH
3397         {
3398             unsigned int opcode2 = (code >> 12) & 0x7;
3399             const char*  rs1     = RegNames[(code >> 15) & 0x1f];
3400             const char*  rs2     = RegNames[(code >> 20) & 0x1f];
3401             // int offset = (((code >> 31) & 0x1) << 12) | (((code >> 7) & 0x1) << 11) | (((code >> 25) & 0x3f) << 5) |
3402             //              (((code >> 8) & 0xf) << 1);
3403             // if (offset & 0x800)
3404             // {
3405             //     offset |= 0xfffff000;
3406             // }
3407             if (!emitDispBranch(opcode2, rs1, rs2, id, ig))
3408             {
3409                 emitDispIllegalInstruction(code);
3410             }
3411             return;
3412         }
3413         case 0x03:
3414         {
3415             unsigned int opcode2 = (code >> 12) & 0x7;
3416             const char*  rs1     = RegNames[(code >> 15) & 0x1f];
3417             const char*  rd      = RegNames[(code >> 7) & 0x1f];
3418             int          offset  = ((code >> 20) & 0xfff);
3419             if (offset & 0x800)
3420             {
3421                 offset |= 0xfffff000;
3422             }
3423
3424             switch (opcode2)
3425             {
3426                 case 0: // LB
3427                     printf("lb             %s, %d(%s)\n", rd, offset, rs1);
3428                     return;
3429                 case 1: // LH
3430                     printf("lh             %s, %d(%s)\n", rd, offset, rs1);
3431                     return;
3432                 case 2: // LW
3433                     printf("lw             %s, %d(%s)\n", rd, offset, rs1);
3434                     return;
3435                 case 3: // LD
3436                     printf("ld             %s, %d(%s)\n", rd, offset, rs1);
3437                     return;
3438                 case 4: // LBU
3439                     printf("lbu            %s, %d(%s)\n", rd, offset, rs1);
3440                     return;
3441                 case 5: // LHU
3442                     printf("lhu            %s, %d(%s)\n", rd, offset, rs1);
3443                     return;
3444                 case 6: // LWU
3445                     printf("lwu            %s, %d(%s)\n", rd, offset, rs1);
3446                     return;
3447                 default:
3448                     printf("RISCV64 illegal instruction: 0x%08X\n", code);
3449                     return;
3450             }
3451         }
3452         case 0x67:
3453         {
3454             const char* rs1    = RegNames[(code >> 15) & 0x1f];
3455             const char* rd     = RegNames[(code >> 7) & 0x1f];
3456             int         offset = ((code >> 20) & 0xfff);
3457             if (offset & 0x800)
3458             {
3459                 offset |= 0xfffff000;
3460             }
3461             printf("jalr           %s, %d(%s)", rd, offset, rs1);
3462             CORINFO_METHOD_HANDLE handle = (CORINFO_METHOD_HANDLE)id->idDebugOnlyInfo()->idMemCookie;
3463             // Target for ret call is unclear, e.g.:
3464             //   jalr zero, 0(ra)
3465             // So, skip it
3466             if (handle != 0)
3467             {
3468                 const char* methodName = emitComp->eeGetMethodFullName(handle);
3469                 printf("\t\t// %s", methodName);
3470             }
3471
3472             printf("\n");
3473             return;
3474         }
3475         case 0x6f:
3476         {
3477             const char* rd = RegNames[(code >> 7) & 0x1f];
3478             int offset = (((code >> 31) & 0x1) << 20) | (((code >> 12) & 0xff) << 12) | (((code >> 20) & 0x1) << 11) |
3479                          (((code >> 21) & 0x3ff) << 1);
3480             if (offset & 0x80000)
3481             {
3482                 offset |= 0xfff00000;
3483             }
3484             printf("jal            %s, %d", rd, offset);
3485             CORINFO_METHOD_HANDLE handle = (CORINFO_METHOD_HANDLE)id->idDebugOnlyInfo()->idMemCookie;
3486             if (handle != 0)
3487             {
3488                 const char* methodName = emitComp->eeGetMethodFullName(handle);
3489                 printf("\t\t// %s", methodName);
3490             }
3491
3492             printf("\n");
3493             return;
3494         }
3495         case 0x0f:
3496         {
3497             int pred = ((code) >> 24) & 0xf;
3498             int succ = ((code) >> 20) & 0xf;
3499             printf("fence          %d, %d\n", pred, succ);
3500             return;
3501         }
3502         case 0x73:
3503         {
3504             unsigned int opcode2 = (code >> 12) & 0x7;
3505             if (opcode2 != 0)
3506             {
3507                 const char* rd      = RegNames[(code >> 7) & 0x1f];
3508                 int         csrtype = (code >> 20);
3509                 if (opcode2 <= 0x3)
3510                 {
3511                     const char* rs1 = RegNames[(code >> 15) & 0x1f];
3512                     switch (opcode2)
3513                     {
3514                         case 0x1: // CSRRW
3515                             printf("csrrw           %s, %d, %s\n", rd, csrtype, rs1);
3516                             return;
3517                         case 0x2: // CSRRS
3518                             printf("csrrs           %s, %d, %s\n", rd, csrtype, rs1);
3519                             return;
3520                         case 0x3: // CSRRC
3521                             printf("csrrc           %s, %d, %s\n", rd, csrtype, rs1);
3522                             return;
3523                         default:
3524                             printf("RISCV64 illegal instruction: 0x%08X\n", code);
3525                             break;
3526                     }
3527                 }
3528                 else
3529                 {
3530                     unsigned imm5 = ((code >> 15) & 0x1f);
3531                     switch (opcode2)
3532                     {
3533                         case 0x5: // CSRRWI
3534                             printf("csrrwi           %s, %d, %d\n", rd, csrtype, imm5);
3535                             return;
3536                         case 0x6: // CSRRSI
3537                             printf("csrrsi           %s, %d, %d\n", rd, csrtype, imm5);
3538                             return;
3539                         case 0x7: // CSRRCI
3540                             printf("csrrci           %s, %d, %d\n", rd, csrtype, imm5);
3541                             return;
3542                         default:
3543                             printf("RISCV64 illegal instruction: 0x%08X\n", code);
3544                             break;
3545                     }
3546                 }
3547             }
3548
3549             if (code == emitInsCode(INS_ebreak))
3550             {
3551                 printf("ebreak\n");
3552             }
3553             else
3554             {
3555                 NYI_RISCV64("illegal ins within emitDisInsName!");
3556             }
3557             return;
3558         }
3559         case 0x53:
3560         {
3561             unsigned int opcode2 = (code >> 25) & 0x7f;
3562             unsigned int opcode3 = (code >> 20) & 0x1f;
3563             unsigned int opcode4 = (code >> 12) & 0x7;
3564             const char*  fd      = RegNames[((code >> 7) & 0x1f) | 0x20];
3565             const char*  fs1     = RegNames[((code >> 15) & 0x1f) | 0x20];
3566             const char*  fs2     = RegNames[((code >> 20) & 0x1f) | 0x20];
3567
3568             const char* xd  = RegNames[(code >> 7) & 0x1f];
3569             const char* xs1 = RegNames[(code >> 15) & 0x1f];
3570             const char* xs2 = RegNames[(code >> 20) & 0x1f];
3571
3572             switch (opcode2)
3573             {
3574                 case 0x00: // FADD.S
3575                     printf("fadd.s         %s, %s, %s\n", fd, fs1, fs2);
3576                     return;
3577                 case 0x04: // FSUB.S
3578                     printf("fsub.s         %s, %s, %s\n", fd, fs1, fs2);
3579                     return;
3580                 case 0x08: // FMUL.S
3581                     printf("fmul.s         %s, %s, %s\n", fd, fs1, fs2);
3582                     return;
3583                 case 0x0C: // FDIV.S
3584                     printf("fdiv.s         %s, %s, %s\n", fd, fs1, fs2);
3585                     return;
3586                 case 0x2C: // FSQRT.S
3587                     printf("fsqrt.s        %s, %s\n", fd, fs1);
3588                     return;
3589                 case 0x10:            // FSGNJ.S & FSGNJN.S & FSGNJX.S
3590                     if (opcode4 == 0) // FSGNJ.S
3591                     {
3592                         printf("fsgnj.s        %s, %s, %s\n", fd, fs1, fs2);
3593                     }
3594                     else if (opcode4 == 1) // FSGNJN.S
3595                     {
3596                         printf("fsgnjn.s       %s, %s, %s\n", fd, fs1, fs2);
3597                     }
3598                     else if (opcode4 == 2) // FSGNJX.S
3599                     {
3600                         printf("fsgnjx.s       %s, %s, %s\n", fd, fs1, fs2);
3601                     }
3602                     else
3603                     {
3604                         NYI_RISCV64("illegal ins within emitDisInsName!");
3605                     }
3606                     return;
3607                 case 0x14:            // FMIN.S & FMAX.S
3608                     if (opcode4 == 0) // FMIN.S
3609                     {
3610                         printf("fmin.s         %s, %s, %s\n", fd, fs1, fs2);
3611                     }
3612                     else if (opcode4 == 1) // FMAX.S
3613                     {
3614                         printf("fmax.s         %s, %s, %s\n", fd, fs1, fs2);
3615                     }
3616                     else
3617                     {
3618                         NYI_RISCV64("illegal ins within emitDisInsName!");
3619                     }
3620                     return;
3621                 case 0x60:            // FCVT.W.S & FCVT.WU.S & FCVT.L.S & FCVT.LU.S
3622                     if (opcode3 == 0) // FCVT.W.S
3623                     {
3624                         printf("fcvt.w.s       %s, %s\n", xd, fs1);
3625                     }
3626                     else if (opcode3 == 1) // FCVT.WU.S
3627                     {
3628                         printf("fcvt.wu.s      %s, %s\n", xd, fs1);
3629                     }
3630                     else if (opcode3 == 2) // FCVT.L.S
3631                     {
3632                         printf("fcvt.l.s       %s, %s\n", xd, fs1);
3633                     }
3634                     else if (opcode3 == 3) // FCVT.LU.S
3635                     {
3636                         printf("fcvt.lu.s      %s, %s\n", xd, fs1);
3637                     }
3638                     else
3639                     {
3640                         NYI_RISCV64("illegal ins within emitDisInsName!");
3641                     }
3642                     return;
3643                 case 0x70:            // FMV.X.W & FCLASS.S
3644                     if (opcode4 == 0) // FMV.X.W
3645                     {
3646                         printf("fmv.x.w        %s, %s\n", xd, fs1);
3647                     }
3648                     else if (opcode4 == 1) // FCLASS.S
3649                     {
3650                         printf("fclass.s       %s, %s\n", xd, fs1);
3651                     }
3652                     else
3653                     {
3654                         NYI_RISCV64("illegal ins within emitDisInsName!");
3655                     }
3656                     return;
3657                 case 0x50:            // FLE.S & FLT.S & FEQ.S
3658                     if (opcode4 == 0) // FLE.S
3659                     {
3660                         printf("fle.s          %s, %s, %s\n", xd, fs1, fs2);
3661                     }
3662                     else if (opcode4 == 1) // FLT.S
3663                     {
3664                         printf("flt.s          %s, %s, %s\n", xd, fs1, fs2);
3665                     }
3666                     else if (opcode4 == 2) // FEQ.S
3667                     {
3668                         printf("feq.s          %s, %s, %s\n", xd, fs1, fs2);
3669                     }
3670                     else
3671                     {
3672                         NYI_RISCV64("illegal ins within emitDisInsName!");
3673                     }
3674                     return;
3675                 case 0x68:            // FCVT.S.W & FCVT.S.WU & FCVT.S.L & FCVT.S.LU
3676                     if (opcode3 == 0) // FCVT.S.W
3677                     {
3678                         printf("fcvt.s.w       %s, %s\n", fd, xs1);
3679                     }
3680                     else if (opcode3 == 1) // FCVT.S.WU
3681                     {
3682                         printf("fcvt.s.wu      %s, %s\n", fd, xs1);
3683                     }
3684                     else if (opcode3 == 2) // FCVT.S.L
3685                     {
3686                         printf("fcvt.s.l       %s, %s\n", fd, xs1);
3687                     }
3688                     else if (opcode3 == 3) // FCVT.S.LU
3689                     {
3690                         printf("fcvt.s.lu      %s, %s\n", fd, xs1);
3691                     }
3692
3693                     else
3694                     {
3695                         NYI_RISCV64("illegal ins within emitDisInsName!");
3696                     }
3697                     return;
3698                 case 0x78: // FMV.W.X
3699                     printf("fmv.w.x        %s, %s\n", fd, xs1);
3700                     return;
3701                 case 0x1: // FADD.D
3702                     printf("fadd.d         %s, %s, %s\n", fd, fs1, fs2);
3703                     return;
3704                 case 0x5: // FSUB.D
3705                     printf("fsub.d         %s, %s, %s\n", fd, fs1, fs2);
3706                     return;
3707                 case 0x9: // FMUL.D
3708                     printf("fmul.d         %s, %s, %s\n", fd, fs1, fs2);
3709                     return;
3710                 case 0xd: // FDIV.D
3711                     printf("fdiv.d         %s, %s, %s\n", fd, fs1, fs2);
3712                     return;
3713                 case 0x2d: // FSQRT.D
3714                     printf("fsqrt.d        %s, %s\n", fd, fs1);
3715                     return;
3716                 case 0x11:            // FSGNJ.D & FSGNJN.D & FSGNJX.D
3717                     if (opcode4 == 0) // FSGNJ.D
3718                     {
3719                         printf("fsgnj.d        %s, %s, %s\n", fd, fs1, fs2);
3720                     }
3721                     else if (opcode4 == 1) // FSGNJN.D
3722                     {
3723                         printf("fsgnjn.d       %s, %s, %s\n", fd, fs1, fs2);
3724                     }
3725                     else if (opcode4 == 2) // FSGNJX.D
3726                     {
3727                         printf("fsgnjx.d       %s, %s, %s\n", fd, fs1, fs2);
3728                     }
3729                     else
3730                     {
3731                         NYI_RISCV64("illegal ins within emitDisInsName!");
3732                     }
3733                     return;
3734                 case 0x15:            // FMIN.D & FMAX.D
3735                     if (opcode4 == 0) // FMIN.D
3736                     {
3737                         printf("fmin.d         %s, %s, %s\n", fd, fs1, fs2);
3738                     }
3739                     else if (opcode4 == 1) // FMAX.D
3740                     {
3741                         printf("fmax.d         %s, %s, %s\n", fd, fs1, fs2);
3742                     }
3743                     else
3744                     {
3745                         NYI_RISCV64("illegal ins within emitDisInsName!");
3746                     }
3747                     return;
3748                 case 0x20:            // FCVT.S.D
3749                     if (opcode3 == 1) // FCVT.S.D
3750                     {
3751                         printf("fcvt.s.d       %s, %s\n", fd, fs1);
3752                     }
3753                     else
3754                     {
3755                         NYI_RISCV64("illegal ins within emitDisInsName!");
3756                     }
3757                     return;
3758                 case 0x21:            // FCVT.D.S
3759                     if (opcode3 == 0) // FCVT.D.S
3760                     {
3761                         printf("fcvt.d.s       %s, %s\n", fd, fs1);
3762                     }
3763                     else
3764                     {
3765                         NYI_RISCV64("illegal ins within emitDisInsName!");
3766                     }
3767                     return;
3768                 case 0x51:            // FLE.D & FLT.D & FEQ.D
3769                     if (opcode4 == 0) // FLE.D
3770                     {
3771                         printf("fle.d          %s, %s, %s\n", xd, fs1, fs2);
3772                     }
3773                     else if (opcode4 == 1) // FLT.D
3774                     {
3775                         printf("flt.d          %s, %s, %s\n", xd, fs1, fs2);
3776                     }
3777                     else if (opcode4 == 2) // FEQ.D
3778                     {
3779                         printf("feq.d          %s, %s, %s\n", xd, fs1, fs2);
3780                     }
3781                     else
3782                     {
3783                         NYI_RISCV64("illegal ins within emitDisInsName!");
3784                     }
3785                     return;
3786                 case 0x61: // FCVT.W.D & FCVT.WU.D & FCVT.L.D & FCVT.LU.D
3787
3788                     if (opcode3 == 0) // FCVT.W.D
3789                     {
3790                         printf("fcvt.w.d       %s, %s\n", xd, fs1);
3791                     }
3792                     else if (opcode3 == 1) // FCVT.WU.D
3793                     {
3794                         printf("fcvt.wu.d      %s, %s\n", xd, fs1);
3795                     }
3796                     else if (opcode3 == 2) // FCVT.L.D
3797                     {
3798                         printf("fcvt.l.d       %s, %s\n", xd, fs1);
3799                     }
3800                     else if (opcode3 == 3) // FCVT.LU.D
3801                     {
3802                         printf("fcvt.lu.d      %s, %s\n", xd, fs1);
3803                     }
3804                     else
3805                     {
3806                         NYI_RISCV64("illegal ins within emitDisInsName!");
3807                     }
3808                     return;
3809                 case 0x69:            // FCVT.D.W & FCVT.D.WU & FCVT.D.L & FCVT.D.LU
3810                     if (opcode3 == 0) // FCVT.D.W
3811                     {
3812                         printf("fcvt.d.w       %s, %s\n", fd, xs1);
3813                     }
3814                     else if (opcode3 == 1) // FCVT.D.WU
3815                     {
3816                         printf("fcvt.d.wu      %s, %s\n", fd, xs1);
3817                     }
3818                     else if (opcode3 == 2)
3819                     {
3820                         printf("fcvt.d.l       %s, %s\n", fd, xs1);
3821                     }
3822                     else if (opcode3 == 3)
3823                     {
3824                         printf("fcvt.d.lu      %s, %s\n", fd, xs1);
3825                     }
3826
3827                     else
3828                     {
3829                         NYI_RISCV64("illegal ins within emitDisInsName!");
3830                     }
3831
3832                     return;
3833                 case 0x71:            // FMV.X.D & FCLASS.D
3834                     if (opcode4 == 0) // FMV.X.D
3835                     {
3836                         printf("fmv.x.d        %s, %s\n", xd, fs1);
3837                     }
3838                     else if (opcode4 == 1) // FCLASS.D
3839                     {
3840                         printf("fclass.d       %s, %s\n", xd, fs1);
3841                     }
3842                     else
3843                     {
3844                         NYI_RISCV64("illegal ins within emitDisInsName!");
3845                     }
3846                     return;
3847                 case 0x79: // FMV.D.X
3848                     assert(opcode4 == 0);
3849                     printf("fmv.d.x        %s, %s\n", fd, xs1);
3850                     return;
3851                 default:
3852                     NYI_RISCV64("illegal ins within emitDisInsName!");
3853                     return;
3854             }
3855             return;
3856         }
3857         case 0x27:
3858         {
3859             unsigned int opcode2 = (code >> 12) & 0x7;
3860
3861             const char* rs1    = RegNames[(code >> 15) & 0x1f];
3862             const char* rs2    = RegNames[((code >> 20) & 0x1f) | 0x20];
3863             int         offset = (((code >> 25) & 0x7f) << 5) | ((code >> 7) & 0x1f);
3864             if (offset & 0x800)
3865             {
3866                 offset |= 0xfffff000;
3867             }
3868             if (opcode2 == 2) // FSW
3869             {
3870                 printf("fsw            %s, %d(%s)\n", rs2, offset, rs1);
3871             }
3872             else if (opcode2 == 3) // FSD
3873             {
3874                 printf("fsd            %s, %d(%s)\n", rs2, offset, rs1);
3875             }
3876             else
3877             {
3878                 NYI_RISCV64("illegal ins within emitDisInsName!");
3879             }
3880             return;
3881         }
3882         case 0x7:
3883         {
3884             unsigned int opcode2 = (code >> 12) & 0x7;
3885             const char*  rs1     = RegNames[(code >> 15) & 0x1f];
3886             const char*  rd      = RegNames[((code >> 7) & 0x1f) | 0x20];
3887             int          offset  = ((code >> 20) & 0xfff);
3888             if (offset & 0x800)
3889             {
3890                 offset |= 0xfffff000;
3891             }
3892             if (opcode2 == 2) // FLW
3893             {
3894                 printf("flw            %s, %d(%s)\n", rd, offset, rs1);
3895             }
3896             else if (opcode2 == 3) // FLD
3897             {
3898                 printf("fld            %s, %d(%s)\n", rd, offset, rs1);
3899             }
3900             else
3901             {
3902                 NYI_RISCV64("illegal ins within emitDisInsName!");
3903             }
3904             return;
3905         }
3906         case 0x2f: // AMO - atomic memory operation
3907         {
3908             bool        hasDataReg = true;
3909             const char* name;
3910             switch (code >> 27) // funct5
3911             {
3912                 case 0b00010:
3913                     name       = "lr";
3914                     hasDataReg = false;
3915                     break;
3916                 case 0b00011:
3917                     name = "sc";
3918                     break;
3919                 case 0b00001:
3920                     name = "amoswap";
3921                     break;
3922                 case 0b00000:
3923                     name = "amoadd";
3924                     break;
3925                 case 0b00100:
3926                     name = "amoxor";
3927                     break;
3928                 case 0b01100:
3929                     name = "amoand";
3930                     break;
3931                 case 0b01000:
3932                     name = "amoor";
3933                     break;
3934                 case 0b10000:
3935                     name = "amomin";
3936                     break;
3937                 case 0b10100:
3938                     name = "amomax";
3939                     break;
3940                 case 0b11000:
3941                     name = "amominu";
3942                     break;
3943                 case 0b11100:
3944                     name = "amomaxu";
3945                     break;
3946                 default:
3947                     assert(!"Illegal funct5 within atomic memory operation, emitDisInsName");
3948                     name = "?";
3949             }
3950
3951             char width;
3952             switch ((code >> 12) & 0x7) // funct3: width
3953             {
3954                 case 0x2:
3955                     width = 'w';
3956                     break;
3957                 case 0x3:
3958                     width = 'd';
3959                     break;
3960                 default:
3961                     assert(!"Illegal width tag within atomic memory operation, emitDisInsName");
3962                     width = '?';
3963             }
3964
3965             const char* aq = code & (1 << 25) ? "aq" : "";
3966             const char* rl = code & (1 << 26) ? "rl" : "";
3967
3968             int len = printf("%s.%c.%s%s", name, width, aq, rl);
3969             if (len <= 0)
3970             {
3971                 return;
3972             }
3973             static const int INS_LEN = 14;
3974             assert(len <= INS_LEN);
3975
3976             const char* dest = RegNames[(code >> 7) & 0x1f];
3977             const char* addr = RegNames[(code >> 15) & 0x1f];
3978
3979             int dataReg = (code >> 20) & 0x1f;
3980             if (hasDataReg)
3981             {
3982                 const char* data = RegNames[dataReg];
3983                 printf("%*s %s, %s, (%s)\n", INS_LEN - len, "", dest, data, addr);
3984             }
3985             else
3986             {
3987                 assert(dataReg == REG_R0);
3988                 printf("%*s %s, (%s)\n", INS_LEN - len, "", dest, addr);
3989             }
3990             return;
3991         }
3992         default:
3993             NO_WAY("illegal ins within emitDisInsName!");
3994     }
3995
3996     NO_WAY("illegal ins within emitDisInsName!");
3997 }
3998
3999 /*****************************************************************************
4000  *
4001  *  Display (optionally) the instruction encoding in hex
4002  */
4003
4004 void emitter::emitDispInsHex(instrDesc* id, BYTE* code, size_t sz)
4005 {
4006     if (!emitComp->opts.disCodeBytes)
4007     {
4008         return;
4009     }
4010
4011     // We do not display the instruction hex if we want diff-able disassembly
4012     if (!emitComp->opts.disDiffable)
4013     {
4014         if (sz == 4)
4015         {
4016             printf("  %08X    ", (*((code_t*)code)));
4017         }
4018         else
4019         {
4020             assert(sz == 0);
4021             printf("              ");
4022         }
4023     }
4024 }
4025
4026 void emitter::emitDispInsInstrNum(const instrDesc* id) const
4027 {
4028 #ifdef DEBUG
4029     if (!emitComp->verbose)
4030         return;
4031
4032     printf("IN%04x: ", id->idDebugOnlyInfo()->idNum);
4033 #endif // DEBUG
4034 }
4035
4036 void emitter::emitDispIns(
4037     instrDesc* id, bool isNew, bool doffs, bool asmfm, unsigned offset, BYTE* pCode, size_t sz, insGroup* ig)
4038 {
4039     if (pCode == nullptr)
4040         return;
4041
4042     emitDispInsInstrNum(id);
4043
4044     const BYTE* instr = pCode + writeableOffset;
4045     size_t      instrSize;
4046     for (size_t i = 0; i < sz; instr += instrSize, i += instrSize, offset += instrSize)
4047     {
4048         // TODO-RISCV64: support different size instructions
4049         instrSize = sizeof(code_t);
4050         code_t instruction;
4051         memcpy(&instruction, instr, instrSize);
4052         emitDispInsName(instruction, instr, doffs, offset, id, ig);
4053     }
4054 }
4055
4056 #ifdef DEBUG
4057
4058 /*****************************************************************************
4059  *
4060  *  Display a stack frame reference.
4061  */
4062
4063 void emitter::emitDispFrameRef(int varx, int disp, int offs, bool asmfm)
4064 {
4065     NYI_RISCV64("emitDispFrameRef-----unimplemented/unused on RISCV64 yet----");
4066 }
4067
4068 #endif // DEBUG
4069
4070 // Generate code for a load or store operation with a potentially complex addressing mode
4071 // This method handles the case of a GT_IND with contained GT_LEA op1 of the x86 form [base + index*sccale + offset]
4072 //
4073 void emitter::emitInsLoadStoreOp(instruction ins, emitAttr attr, regNumber dataReg, GenTreeIndir* indir)
4074 {
4075     GenTree* addr = indir->Addr();
4076
4077     if (addr->isContained())
4078     {
4079         assert(addr->OperIs(GT_CLS_VAR_ADDR, GT_LCL_ADDR, GT_LEA));
4080
4081         int   offset = 0;
4082         DWORD lsl    = 0;
4083
4084         if (addr->OperGet() == GT_LEA)
4085         {
4086             offset = addr->AsAddrMode()->Offset();
4087             if (addr->AsAddrMode()->gtScale > 0)
4088             {
4089                 assert(isPow2(addr->AsAddrMode()->gtScale));
4090                 BitScanForward(&lsl, addr->AsAddrMode()->gtScale);
4091             }
4092         }
4093
4094         GenTree* memBase = indir->Base();
4095         emitAttr addType = varTypeIsGC(memBase) ? EA_BYREF : EA_PTRSIZE;
4096
4097         if (indir->HasIndex())
4098         {
4099             GenTree* index = indir->Index();
4100
4101             if (offset != 0)
4102             {
4103                 regNumber tmpReg = indir->GetSingleTempReg();
4104
4105                 if (isValidSimm12(offset))
4106                 {
4107                     if (lsl > 0)
4108                     {
4109                         // Generate code to set tmpReg = base + index*scale
4110                         emitIns_R_R_I(INS_slli, addType, tmpReg, index->GetRegNum(), lsl);
4111                         emitIns_R_R_R(INS_add, addType, tmpReg, memBase->GetRegNum(), tmpReg);
4112                     }
4113                     else // no scale
4114                     {
4115                         // Generate code to set tmpReg = base + index
4116                         emitIns_R_R_R(INS_add, addType, tmpReg, memBase->GetRegNum(), index->GetRegNum());
4117                     }
4118
4119                     noway_assert(emitInsIsLoad(ins) || (tmpReg != dataReg));
4120
4121                     // Then load/store dataReg from/to [tmpReg + offset]
4122                     emitIns_R_R_I(ins, attr, dataReg, tmpReg, offset);
4123                 }
4124                 else // large offset
4125                 {
4126                     // First load/store tmpReg with the large offset constant
4127                     emitLoadImmediate(EA_PTRSIZE, tmpReg,
4128                                       offset); // codeGen->instGen_Set_Reg_To_Imm(EA_PTRSIZE, tmpReg, offset);
4129                     // Then add the base register
4130                     //      rd = rd + base
4131                     emitIns_R_R_R(INS_add, addType, tmpReg, tmpReg, memBase->GetRegNum());
4132
4133                     noway_assert(emitInsIsLoad(ins) || (tmpReg != dataReg));
4134                     noway_assert(tmpReg != index->GetRegNum());
4135
4136                     regNumber scaleReg = indir->GetSingleTempReg();
4137                     // Then load/store dataReg from/to [tmpReg + index*scale]
4138                     emitIns_R_R_I(INS_slli, addType, scaleReg, index->GetRegNum(), lsl);
4139                     emitIns_R_R_R(INS_add, addType, tmpReg, tmpReg, scaleReg);
4140                     emitIns_R_R_I(ins, attr, dataReg, tmpReg, 0);
4141                 }
4142             }
4143             else // (offset == 0)
4144             {
4145                 // Then load/store dataReg from/to [memBase + index]
4146                 switch (EA_SIZE(emitTypeSize(indir->TypeGet())))
4147                 {
4148                     case EA_1BYTE:
4149                         assert(((ins <= INS_lhu) && (ins >= INS_lb)) || ins == INS_lwu || ins == INS_ld ||
4150                                ((ins <= INS_sw) && (ins >= INS_sb)) || ins == INS_sd);
4151                         if (ins <= INS_lhu || ins == INS_lwu || ins == INS_ld)
4152                         {
4153                             if (varTypeIsUnsigned(indir->TypeGet()))
4154                                 ins = INS_lbu;
4155                             else
4156                                 ins = INS_lb;
4157                         }
4158                         else
4159                             ins = INS_sb;
4160                         break;
4161                     case EA_2BYTE:
4162                         assert(((ins <= INS_lhu) && (ins >= INS_lb)) || ins == INS_lwu || ins == INS_ld ||
4163                                ((ins <= INS_sw) && (ins >= INS_sb)) || ins == INS_sd);
4164                         if (ins <= INS_lhu || ins == INS_lwu || ins == INS_ld)
4165                         {
4166                             if (varTypeIsUnsigned(indir->TypeGet()))
4167                                 ins = INS_lhu;
4168                             else
4169                                 ins = INS_lh;
4170                         }
4171                         else
4172                             ins = INS_sh;
4173                         break;
4174                     case EA_4BYTE:
4175                         assert(((ins <= INS_lhu) && (ins >= INS_lb)) || ins == INS_lwu || ins == INS_ld ||
4176                                ((ins <= INS_sw) && (ins >= INS_sb)) || ins == INS_sd || ins == INS_fsw ||
4177                                ins == INS_flw);
4178                         assert(INS_fsw > INS_sd);
4179                         if (ins <= INS_lhu || ins == INS_lwu || ins == INS_ld)
4180                         {
4181                             if (varTypeIsUnsigned(indir->TypeGet()))
4182                                 ins = INS_lwu;
4183                             else
4184                                 ins = INS_lw;
4185                         }
4186                         else if (ins != INS_flw && ins != INS_fsw)
4187                             ins = INS_sw;
4188                         break;
4189                     case EA_8BYTE:
4190                         assert(((ins <= INS_lhu) && (ins >= INS_lb)) || ins == INS_lwu || ins == INS_ld ||
4191                                ((ins <= INS_sw) && (ins >= INS_sb)) || ins == INS_sd || ins == INS_fld ||
4192                                ins == INS_fsd);
4193                         assert(INS_fsd > INS_sd);
4194                         if (ins <= INS_lhu || ins == INS_lwu || ins == INS_ld)
4195                         {
4196                             ins = INS_ld;
4197                         }
4198                         else if (ins != INS_fld && ins != INS_fsd)
4199                             ins = INS_sd;
4200                         break;
4201                     default:
4202                         NO_WAY("illegal ins within emitInsLoadStoreOp!");
4203                 }
4204
4205                 if (lsl > 0)
4206                 {
4207                     // Then load/store dataReg from/to [memBase + index*scale]
4208                     emitIns_R_R_I(INS_slli, emitActualTypeSize(index->TypeGet()), codeGen->rsGetRsvdReg(),
4209                                   index->GetRegNum(), lsl);
4210                     emitIns_R_R_R(INS_add, addType, codeGen->rsGetRsvdReg(), memBase->GetRegNum(),
4211                                   codeGen->rsGetRsvdReg());
4212                     emitIns_R_R_I(ins, attr, dataReg, codeGen->rsGetRsvdReg(), 0);
4213                 }
4214                 else // no scale
4215                 {
4216                     emitIns_R_R_R(INS_add, addType, codeGen->rsGetRsvdReg(), memBase->GetRegNum(), index->GetRegNum());
4217                     emitIns_R_R_I(ins, attr, dataReg, codeGen->rsGetRsvdReg(), 0);
4218                 }
4219             }
4220         }
4221         else // no Index register
4222         {
4223             if (addr->OperGet() == GT_CLS_VAR_ADDR)
4224             {
4225                 // Get a temp integer register to compute long address.
4226                 regNumber addrReg = indir->GetSingleTempReg();
4227
4228                 emitIns_R_C(ins, attr, dataReg, addrReg, addr->AsClsVar()->gtClsVarHnd, 0);
4229             }
4230             else if (addr->OperIs(GT_LCL_ADDR))
4231             {
4232                 GenTreeLclVarCommon* varNode = addr->AsLclVarCommon();
4233                 unsigned             lclNum  = varNode->GetLclNum();
4234                 unsigned             offset  = varNode->GetLclOffs();
4235                 if (emitInsIsStore(ins))
4236                 {
4237                     emitIns_S_R(ins, attr, dataReg, lclNum, offset);
4238                 }
4239                 else
4240                 {
4241                     emitIns_R_S(ins, attr, dataReg, lclNum, offset);
4242                 }
4243             }
4244             else if (isValidSimm12(offset))
4245             {
4246                 // Then load/store dataReg from/to [memBase + offset]
4247                 emitIns_R_R_I(ins, attr, dataReg, memBase->GetRegNum(), offset);
4248             }
4249             else
4250             {
4251                 // We require a tmpReg to hold the offset
4252                 regNumber tmpReg = indir->GetSingleTempReg();
4253
4254                 // First load/store tmpReg with the large offset constant
4255                 emitLoadImmediate(EA_PTRSIZE, tmpReg, offset);
4256                 // codeGen->instGen_Set_Reg_To_Imm(EA_PTRSIZE, tmpReg, offset);
4257
4258                 // Then load/store dataReg from/to [memBase + tmpReg]
4259                 emitIns_R_R_R(INS_add, addType, tmpReg, memBase->GetRegNum(), tmpReg);
4260                 emitIns_R_R_I(ins, attr, dataReg, tmpReg, 0);
4261             }
4262         }
4263     }
4264     else // addr is not contained, so we evaluate it into a register
4265     {
4266 #ifdef DEBUG
4267         if (addr->OperIs(GT_LCL_ADDR))
4268         {
4269             // If the local var is a gcref or byref, the local var better be untracked, because we have
4270             // no logic here to track local variable lifetime changes, like we do in the contained case
4271             // above. E.g., for a `st a0,[a1]` for byref `a1` to local `V01`, we won't store the local
4272             // `V01` and so the emitter can't update the GC lifetime for `V01` if this is a variable birth.
4273             LclVarDsc* varDsc = emitComp->lvaGetDesc(addr->AsLclVarCommon());
4274             assert(!varDsc->lvTracked);
4275         }
4276 #endif // DEBUG
4277
4278         // Then load/store dataReg from/to [addrReg]
4279         emitIns_R_R_I(ins, attr, dataReg, addr->GetRegNum(), 0);
4280     }
4281 }
4282
4283 // The callee must call genConsumeReg() for any non-contained srcs
4284 // and genProduceReg() for any non-contained dsts.
4285
4286 regNumber emitter::emitInsBinary(instruction ins, emitAttr attr, GenTree* dst, GenTree* src)
4287 {
4288     NYI_RISCV64("emitInsBinary-----unimplemented/unused on RISCV64 yet----");
4289     return REG_R0;
4290 }
4291
4292 // The callee must call genConsumeReg() for any non-contained srcs
4293 // and genProduceReg() for any non-contained dsts.
4294 regNumber emitter::emitInsTernary(instruction ins, emitAttr attr, GenTree* dst, GenTree* src1, GenTree* src2)
4295 {
4296     // dst can only be a reg
4297     assert(!dst->isContained());
4298
4299     // find immed (if any) - it cannot be a dst
4300     // Only one src can be an int.
4301     GenTreeIntConCommon* intConst  = nullptr;
4302     GenTree*             nonIntReg = nullptr;
4303
4304     const bool needCheckOv = dst->gtOverflowEx();
4305
4306     if (varTypeIsFloating(dst))
4307     {
4308         // src1 can only be a reg
4309         assert(!src1->isContained());
4310         // src2 can only be a reg
4311         assert(!src2->isContained());
4312     }
4313     else // not floating point
4314     {
4315         // src2 can be immed or reg
4316         assert(!src2->isContained() || src2->isContainedIntOrIImmed());
4317
4318         // Check src2 first as we can always allow it to be a contained immediate
4319         if (src2->isContainedIntOrIImmed())
4320         {
4321             intConst  = src2->AsIntConCommon();
4322             nonIntReg = src1;
4323         }
4324         // Only for commutative operations do we check src1 and allow it to be a contained immediate
4325         else if (dst->OperIsCommutative())
4326         {
4327             // src1 can be immed or reg
4328             assert(!src1->isContained() || src1->isContainedIntOrIImmed());
4329
4330             // Check src1 and allow it to be a contained immediate
4331             if (src1->isContainedIntOrIImmed())
4332             {
4333                 assert(!src2->isContainedIntOrIImmed());
4334                 intConst  = src1->AsIntConCommon();
4335                 nonIntReg = src2;
4336             }
4337         }
4338         else
4339         {
4340             // src1 can only be a reg
4341             assert(!src1->isContained());
4342         }
4343     }
4344
4345 #ifdef DEBUG
4346     if (needCheckOv)
4347     {
4348         if (ins == INS_add)
4349         {
4350             assert(attr == EA_8BYTE);
4351         }
4352         else if (ins == INS_addw) // || ins == INS_add
4353         {
4354             assert(attr == EA_4BYTE);
4355         }
4356         else if (ins == INS_addi)
4357         {
4358             assert(intConst != nullptr);
4359         }
4360         else if (ins == INS_addiw)
4361         {
4362             assert(intConst != nullptr);
4363         }
4364         else if (ins == INS_sub)
4365         {
4366             assert(attr == EA_8BYTE);
4367         }
4368         else if (ins == INS_subw)
4369         {
4370             assert(attr == EA_4BYTE);
4371         }
4372         else if ((ins == INS_mul) || (ins == INS_mulh) || (ins == INS_mulhu))
4373         {
4374             assert(attr == EA_8BYTE);
4375             // NOTE: overflow format doesn't support an int constant operand directly.
4376             assert(intConst == nullptr);
4377         }
4378         else if (ins == INS_mulw)
4379         {
4380             assert(attr == EA_4BYTE);
4381             // NOTE: overflow format doesn't support an int constant operand directly.
4382             assert(intConst == nullptr);
4383         }
4384         else
4385         {
4386             printf("RISCV64-Invalid ins for overflow check: %s\n", codeGen->genInsName(ins));
4387             assert(!"Invalid ins for overflow check");
4388         }
4389     }
4390 #endif // DEBUG
4391
4392     regNumber dstReg  = dst->GetRegNum();
4393     regNumber src1Reg = src1->GetRegNum();
4394     regNumber src2Reg = src2->GetRegNum();
4395
4396     if (intConst != nullptr)
4397     {
4398         ssize_t imm = intConst->IconValue();
4399         assert(isValidSimm12(imm));
4400
4401         if (ins == INS_sub)
4402         {
4403             assert(attr == EA_8BYTE);
4404             assert(imm != -2048);
4405             ins = INS_addi;
4406             imm = -imm;
4407         }
4408         else if (ins == INS_subw)
4409         {
4410             assert(attr == EA_4BYTE);
4411             assert(imm != -2048);
4412             ins = INS_addiw;
4413             imm = -imm;
4414         }
4415
4416         assert(ins == INS_addi || ins == INS_addiw || ins == INS_andi || ins == INS_ori || ins == INS_xori);
4417
4418         regNumber tempReg = needCheckOv ? dst->ExtractTempReg() : REG_NA;
4419
4420         if (needCheckOv)
4421         {
4422             emitIns_R_R(INS_mov, attr, tempReg, nonIntReg->GetRegNum());
4423         }
4424
4425         emitIns_R_R_I(ins, attr, dstReg, nonIntReg->GetRegNum(), imm);
4426
4427         if (needCheckOv)
4428         {
4429             // At this point andi/ori/xori are excluded by previous checks
4430             assert(ins == INS_addi || ins == INS_addiw);
4431
4432             // AS11 = B + C
4433             if ((dst->gtFlags & GTF_UNSIGNED) != 0)
4434             {
4435                 codeGen->genJumpToThrowHlpBlk_la(SCK_OVERFLOW, INS_bltu, dstReg, nullptr, tempReg);
4436             }
4437             else
4438             {
4439                 if (imm > 0)
4440                 {
4441                     // B > 0 and C > 0, if A < B, goto overflow
4442                     BasicBlock* tmpLabel = codeGen->genCreateTempLabel();
4443                     emitIns_J_cond_la(INS_bge, tmpLabel, REG_R0, tempReg);
4444                     emitIns_R_R_I(INS_slti, EA_PTRSIZE, tempReg, dstReg, imm);
4445
4446                     codeGen->genJumpToThrowHlpBlk_la(SCK_OVERFLOW, INS_bne, tempReg);
4447
4448                     codeGen->genDefineTempLabel(tmpLabel);
4449                 }
4450                 else if (imm < 0)
4451                 {
4452                     // B < 0 and C < 0, if A > B, goto overflow
4453                     BasicBlock* tmpLabel = codeGen->genCreateTempLabel();
4454                     emitIns_J_cond_la(INS_bge, tmpLabel, tempReg, REG_R0);
4455                     emitIns_R_R_I(INS_addi, attr, tempReg, REG_R0, imm);
4456
4457                     codeGen->genJumpToThrowHlpBlk_la(SCK_OVERFLOW, INS_blt, tempReg, nullptr, dstReg);
4458
4459                     codeGen->genDefineTempLabel(tmpLabel);
4460                 }
4461             }
4462         }
4463     }
4464     else if (varTypeIsFloating(dst))
4465     {
4466         emitIns_R_R_R(ins, attr, dstReg, src1Reg, src2Reg);
4467     }
4468     else
4469     {
4470         regNumber tempReg = needCheckOv ? dst->ExtractTempReg() : REG_NA;
4471
4472         switch (dst->OperGet())
4473         {
4474             case GT_MUL:
4475             {
4476                 if (!needCheckOv && !(dst->gtFlags & GTF_UNSIGNED))
4477                 {
4478                     emitIns_R_R_R(ins, attr, dstReg, src1Reg, src2Reg);
4479                 }
4480                 else
4481                 {
4482                     if (needCheckOv)
4483                     {
4484                         assert(tempReg != dstReg);
4485                         assert(tempReg != src1Reg);
4486                         assert(tempReg != src2Reg);
4487
4488                         assert(REG_RA != dstReg);
4489                         assert(REG_RA != src1Reg);
4490                         assert(REG_RA != src2Reg);
4491
4492                         if ((dst->gtFlags & GTF_UNSIGNED) != 0)
4493                         {
4494                             if (attr == EA_4BYTE)
4495                             {
4496                                 emitIns_R_R_I(INS_slli, EA_8BYTE, tempReg, src1Reg, 32);
4497                                 emitIns_R_R_I(INS_slli, EA_8BYTE, REG_RA, src2Reg, 32);
4498                                 emitIns_R_R_R(INS_mulhu, EA_8BYTE, tempReg, tempReg, REG_RA);
4499                                 emitIns_R_R_I(INS_srai, attr, tempReg, tempReg, 32);
4500                             }
4501                             else
4502                             {
4503                                 emitIns_R_R_R(INS_mulhu, attr, tempReg, src1Reg, src2Reg);
4504                             }
4505                         }
4506                         else
4507                         {
4508                             if (attr == EA_4BYTE)
4509                             {
4510                                 emitIns_R_R_R(INS_mul, EA_8BYTE, tempReg, src1Reg, src2Reg);
4511                                 emitIns_R_R_I(INS_srai, attr, tempReg, tempReg, 32);
4512                             }
4513                             else
4514                             {
4515                                 emitIns_R_R_R(INS_mulh, attr, tempReg, src1Reg, src2Reg);
4516                             }
4517                         }
4518                     }
4519
4520                     // n * n bytes will store n bytes result
4521                     emitIns_R_R_R(ins, attr, dstReg, src1Reg, src2Reg);
4522
4523                     if ((dst->gtFlags & GTF_UNSIGNED) != 0)
4524                     {
4525                         if (attr == EA_4BYTE)
4526                         {
4527                             emitIns_R_R_I(INS_slli, EA_8BYTE, dstReg, dstReg, 32);
4528                             emitIns_R_R_I(INS_srli, EA_8BYTE, dstReg, dstReg, 32);
4529                         }
4530                     }
4531
4532                     if (needCheckOv)
4533                     {
4534                         assert(tempReg != dstReg);
4535                         assert(tempReg != src1Reg);
4536                         assert(tempReg != src2Reg);
4537
4538                         if ((dst->gtFlags & GTF_UNSIGNED) != 0)
4539                         {
4540                             codeGen->genJumpToThrowHlpBlk_la(SCK_OVERFLOW, INS_bne, tempReg);
4541                         }
4542                         else
4543                         {
4544                             regNumber tempReg2 = dst->ExtractTempReg();
4545                             assert(tempReg2 != dstReg);
4546                             assert(tempReg2 != src1Reg);
4547                             assert(tempReg2 != src2Reg);
4548                             size_t imm = (EA_SIZE(attr) == EA_8BYTE) ? 63 : 31;
4549                             emitIns_R_R_I(EA_SIZE(attr) == EA_8BYTE ? INS_srai : INS_sraiw, attr, tempReg2, dstReg,
4550                                           imm);
4551                             codeGen->genJumpToThrowHlpBlk_la(SCK_OVERFLOW, INS_bne, tempReg, nullptr, tempReg2);
4552                         }
4553                     }
4554                 }
4555             }
4556             break;
4557
4558             case GT_AND:
4559             case GT_AND_NOT:
4560             case GT_OR:
4561             case GT_XOR:
4562             {
4563                 emitIns_R_R_R(ins, attr, dstReg, src1Reg, src2Reg);
4564
4565                 // TODO-RISCV64-CQ: here sign-extend dst when deal with 32bit data is too conservative.
4566                 if (EA_SIZE(attr) == EA_4BYTE)
4567                     emitIns_R_R_I(INS_slliw, attr, dstReg, dstReg, 0);
4568             }
4569             break;
4570
4571             case GT_ADD:
4572             case GT_SUB:
4573             {
4574                 regNumber regOp1       = src1Reg;
4575                 regNumber regOp2       = src2Reg;
4576                 regNumber saveOperReg1 = REG_NA;
4577                 regNumber saveOperReg2 = REG_NA;
4578
4579                 if ((dst->gtFlags & GTF_UNSIGNED) && (attr == EA_8BYTE))
4580                 {
4581                     if (src1->gtType == TYP_INT)
4582                     {
4583                         emitIns_R_R_I(INS_slli, EA_8BYTE, regOp1, regOp1, 32);
4584                         emitIns_R_R_I(INS_srli, EA_8BYTE, regOp1, regOp1, 32);
4585                     }
4586                     if (src2->gtType == TYP_INT)
4587                     {
4588                         emitIns_R_R_I(INS_slli, EA_8BYTE, regOp2, regOp2, 32);
4589                         emitIns_R_R_I(INS_srli, EA_8BYTE, regOp2, regOp2, 32);
4590                     }
4591                 }
4592
4593                 if (needCheckOv)
4594                 {
4595                     assert(!varTypeIsFloating(dst));
4596
4597                     assert(tempReg != dstReg);
4598
4599                     if (dstReg == regOp1)
4600                     {
4601                         assert(tempReg != regOp1);
4602                         assert(REG_RA != regOp1);
4603                         saveOperReg1 = tempReg;
4604                         saveOperReg2 = regOp2;
4605                         emitIns_R_R_I(INS_addi, attr, tempReg, regOp1, 0);
4606                     }
4607                     else if (dstReg == regOp2)
4608                     {
4609                         assert(tempReg != regOp2);
4610                         assert(REG_RA != regOp2);
4611                         saveOperReg1 = regOp1;
4612                         saveOperReg2 = tempReg;
4613                         emitIns_R_R_I(INS_addi, attr, tempReg, regOp2, 0);
4614                     }
4615                     else
4616                     {
4617                         saveOperReg1 = regOp1;
4618                         saveOperReg2 = regOp2;
4619                     }
4620                 }
4621
4622                 emitIns_R_R_R(ins, attr, dstReg, regOp1, regOp2);
4623
4624                 if (needCheckOv)
4625                 {
4626                     ssize_t   imm;
4627                     regNumber tempReg1;
4628                     regNumber tempReg2;
4629                     // ADD : A = B + C
4630                     // SUB : C = A - B
4631                     bool isAdd = (dst->OperGet() == GT_ADD);
4632                     if ((dst->gtFlags & GTF_UNSIGNED) != 0)
4633                     {
4634                         // if A < B, goto overflow
4635                         if (isAdd)
4636                         {
4637                             tempReg1 = dstReg;
4638                             tempReg2 = saveOperReg1;
4639                         }
4640                         else
4641                         {
4642                             tempReg1 = saveOperReg1;
4643                             tempReg2 = saveOperReg2;
4644                         }
4645                         codeGen->genJumpToThrowHlpBlk_la(SCK_OVERFLOW, INS_bltu, tempReg1, nullptr, tempReg2);
4646                     }
4647                     else
4648                     {
4649                         tempReg1 = REG_RA;
4650                         tempReg2 = dst->ExtractTempReg();
4651                         assert(tempReg1 != tempReg2);
4652                         assert(tempReg1 != saveOperReg1);
4653                         assert(tempReg2 != saveOperReg2);
4654
4655                         ssize_t ui6 = (attr == EA_4BYTE) ? 31 : 63;
4656                         emitIns_R_R_I(INS_srli, attr, tempReg1, isAdd ? saveOperReg1 : dstReg, ui6);
4657                         emitIns_R_R_I(INS_srli, attr, tempReg2, saveOperReg2, ui6);
4658
4659                         emitIns_R_R_R(INS_xor, attr, tempReg1, tempReg1, tempReg2);
4660                         if (attr == EA_4BYTE)
4661                         {
4662                             imm = 1;
4663                             emitIns_R_R_I(INS_andi, attr, tempReg1, tempReg1, imm);
4664                             emitIns_R_R_I(INS_andi, attr, tempReg2, tempReg2, imm);
4665                         }
4666                         // if (B > 0 && C < 0) || (B < 0  && C > 0), skip overflow
4667                         BasicBlock* tmpLabel  = codeGen->genCreateTempLabel();
4668                         BasicBlock* tmpLabel2 = codeGen->genCreateTempLabel();
4669                         BasicBlock* tmpLabel3 = codeGen->genCreateTempLabel();
4670
4671                         emitIns_J_cond_la(INS_bne, tmpLabel, tempReg1, REG_R0);
4672
4673                         emitIns_J_cond_la(INS_bne, tmpLabel3, tempReg2, REG_R0);
4674
4675                         // B > 0 and C > 0, if A < B, goto overflow
4676                         emitIns_J_cond_la(INS_bge, tmpLabel, isAdd ? dstReg : saveOperReg1,
4677                                           isAdd ? saveOperReg1 : saveOperReg2);
4678
4679                         codeGen->genDefineTempLabel(tmpLabel2);
4680
4681                         codeGen->genJumpToThrowHlpBlk(EJ_jmp, SCK_OVERFLOW);
4682
4683                         codeGen->genDefineTempLabel(tmpLabel3);
4684
4685                         // B < 0 and C < 0, if A > B, goto overflow
4686                         emitIns_J_cond_la(INS_blt, tmpLabel2, isAdd ? saveOperReg1 : saveOperReg2,
4687                                           isAdd ? dstReg : saveOperReg1);
4688
4689                         codeGen->genDefineTempLabel(tmpLabel);
4690                     }
4691                 }
4692             }
4693             break;
4694
4695             default:
4696                 NO_WAY("unexpected instruction within emitInsTernary!");
4697         }
4698     }
4699
4700     return dstReg;
4701 }
4702
4703 unsigned emitter::get_curTotalCodeSize()
4704 {
4705     return emitTotalCodeSize;
4706 }
4707
4708 #if defined(DEBUG) || defined(LATE_DISASM)
4709
4710 //----------------------------------------------------------------------------------------
4711 // getInsExecutionCharacteristics:
4712 //    Returns the current instruction execution characteristics
4713 //
4714 // Arguments:
4715 //    id  - The current instruction descriptor to be evaluated
4716 //
4717 // Return Value:
4718 //    A struct containing the current instruction execution characteristics
4719 //
4720 // Notes:
4721 //    The instruction latencies and throughput values returned by this function
4722 //    are NOT accurate and just a function feature.
4723 emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(instrDesc* id)
4724 {
4725     insExecutionCharacteristics result;
4726
4727     // TODO-RISCV64: support this function.
4728     result.insThroughput       = PERFSCORE_THROUGHPUT_ZERO;
4729     result.insLatency          = PERFSCORE_LATENCY_ZERO;
4730     result.insMemoryAccessKind = PERFSCORE_MEMORY_NONE;
4731
4732     return result;
4733 }
4734
4735 #endif // defined(DEBUG) || defined(LATE_DISASM)
4736
4737 #ifdef DEBUG
4738 //------------------------------------------------------------------------
4739 // emitRegName: Returns a general-purpose register name or SIMD and floating-point scalar register name.
4740 //
4741 // TODO-RISCV64: supporting SIMD.
4742 // Arguments:
4743 //    reg - A general-purpose register orfloating-point register.
4744 //    size - unused parameter.
4745 //    varName - unused parameter.
4746 //
4747 // Return value:
4748 //    A string that represents a general-purpose register name or floating-point scalar register name.
4749 //
4750 const char* emitter::emitRegName(regNumber reg, emitAttr size, bool varName) const
4751 {
4752     assert(reg < REG_COUNT);
4753
4754     const char* rn = nullptr;
4755
4756     rn = RegNames[reg];
4757     assert(rn != nullptr);
4758
4759     return rn;
4760 }
4761 #endif
4762
4763 //------------------------------------------------------------------------
4764 // IsMovInstruction: Determines whether a give instruction is a move instruction
4765 //
4766 // Arguments:
4767 //    ins       -- The instruction being checked
4768 //
4769 bool emitter::IsMovInstruction(instruction ins)
4770 {
4771     switch (ins)
4772     {
4773         case INS_mov:
4774         case INS_fsgnj_s:
4775         case INS_fsgnj_d:
4776         {
4777             return true;
4778         }
4779
4780         default:
4781         {
4782             return false;
4783         }
4784     }
4785     return false;
4786 }
4787
4788 #endif // defined(TARGET_RISCV64)