1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
4 #if defined(TARGET_RISCV64)
6 // The RISCV64 instructions are all 32 bits in size.
7 // we use an unsigned int to hold the encoded instructions.
8 // This typedef defines the type that we use to hold encoded instructions.
10 typedef unsigned int code_t;
12 /************************************************************************/
13 /* Routines that compute the size of / encode instructions */
14 /************************************************************************/
24 /************************************************************************/
25 /* Debug-only routines to display instructions */
26 /************************************************************************/
28 const char* emitFPregName(unsigned reg, bool varName = true);
29 const char* emitVectorRegName(regNumber reg);
32 void emitIns_J_cond_la(instruction ins, BasicBlock* dst, regNumber reg1 = REG_R0, regNumber reg2 = REG_R0);
34 void emitLoadImmediate(emitAttr attr, regNumber reg, ssize_t imm);
36 /************************************************************************/
37 /* Private members that deal with target-dependent instr. descriptors */
38 /************************************************************************/
41 instrDesc* emitNewInstrCallDir(int argCnt,
42 VARSET_VALARG_TP GCvars,
45 emitAttr retSize MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize));
47 instrDesc* emitNewInstrCallInd(int argCnt,
49 VARSET_VALARG_TP GCvars,
52 emitAttr retSize MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize));
54 /************************************************************************/
55 /* Private helpers for instruction output */
56 /************************************************************************/
59 bool emitInsIsLoad(instruction ins);
60 bool emitInsIsStore(instruction ins);
61 bool emitInsIsLoadOrStore(instruction ins);
64 code_t code, const BYTE* addr, bool doffs, unsigned insOffset, const instrDesc* id, const insGroup* ig);
65 void emitDispInsInstrNum(const instrDesc* id) const;
66 bool emitDispBranch(unsigned opcode2, unsigned rs1, unsigned rs2, const instrDesc* id, const insGroup* ig) const;
67 void emitDispBranchOffset(const instrDesc* id, const insGroup* ig) const;
68 void emitDispBranchLabel(const instrDesc* id) const;
69 bool emitDispBranchInstrType(unsigned opcode2, bool is_zero_reg, bool& print_second_reg) const;
70 void emitDispIllegalInstruction(code_t instructionCode);
72 emitter::code_t emitInsCode(instruction ins /*, insFormat fmt*/) const;
74 // Generate code for a load or store operation and handle the case of contained GT_LEA op1 with [base + offset]
75 void emitInsLoadStoreOp(instruction ins, emitAttr attr, regNumber dataReg, GenTreeIndir* indir);
77 // Emit the 32-bit RISCV64 instruction 'code' into the 'dst' buffer
78 unsigned emitOutput_Instr(BYTE* dst, code_t code) const;
80 ssize_t emitOutputInstrJumpDistance(const BYTE* src, const insGroup* ig, instrDescJmp* jmp);
81 void emitOutputInstrJumpDistanceHelper(const insGroup* ig,
83 UNATIVE_OFFSET& dstOffs,
84 const BYTE*& dstAddr) const;
86 // Method to do check if mov is redundant with respect to the last instruction.
87 // If yes, the caller of this method can choose to omit current mov instruction.
88 static bool IsMovInstruction(instruction ins);
89 bool IsRedundantMov(instruction ins, emitAttr size, regNumber dst, regNumber src, bool canSkip);
90 bool IsRedundantLdStr(
91 instruction ins, regNumber reg1, regNumber reg2, ssize_t imm, emitAttr size, insFormat fmt); // New functions end.
93 static code_t insEncodeRTypeInstr(
94 unsigned opcode, unsigned rd, unsigned funct3, unsigned rs1, unsigned rs2, unsigned funct7);
95 static code_t insEncodeITypeInstr(unsigned opcode, unsigned rd, unsigned funct3, unsigned rs1, unsigned imm12);
96 static code_t insEncodeSTypeInstr(unsigned opcode, unsigned funct3, unsigned rs1, unsigned rs2, unsigned imm12);
97 static code_t insEncodeUTypeInstr(unsigned opcode, unsigned rd, unsigned imm20);
98 static code_t insEncodeBTypeInstr(unsigned opcode, unsigned funct3, unsigned rs1, unsigned rs2, unsigned imm13);
99 static code_t insEncodeJTypeInstr(unsigned opcode, unsigned rd, unsigned imm21);
102 static void emitOutput_RTypeInstr_SanityCheck(instruction ins, regNumber rd, regNumber rs1, regNumber rs2);
103 static void emitOutput_ITypeInstr_SanityCheck(
104 instruction ins, regNumber rd, regNumber rs1, unsigned immediate, unsigned opcode);
105 static void emitOutput_STypeInstr_SanityCheck(instruction ins, regNumber rs1, regNumber rs2);
106 static void emitOutput_UTypeInstr_SanityCheck(instruction ins, regNumber rd);
107 static void emitOutput_BTypeInstr_SanityCheck(instruction ins, regNumber rs1, regNumber rs2);
108 static void emitOutput_JTypeInstr_SanityCheck(instruction ins, regNumber rd);
111 static unsigned castFloatOrIntegralReg(regNumber reg);
113 unsigned emitOutput_RTypeInstr(BYTE* dst, instruction ins, regNumber rd, regNumber rs1, regNumber rs2) const;
114 unsigned emitOutput_ITypeInstr(BYTE* dst, instruction ins, regNumber rd, regNumber rs1, unsigned imm12) const;
115 unsigned emitOutput_STypeInstr(BYTE* dst, instruction ins, regNumber rs1, regNumber rs2, unsigned imm12) const;
116 unsigned emitOutput_UTypeInstr(BYTE* dst, instruction ins, regNumber rd, unsigned imm20) const;
117 unsigned emitOutput_BTypeInstr(BYTE* dst, instruction ins, regNumber rs1, regNumber rs2, unsigned imm13) const;
118 unsigned emitOutput_BTypeInstr_InvertComparation(
119 BYTE* dst, instruction ins, regNumber rs1, regNumber rs2, unsigned imm13) const;
120 unsigned emitOutput_JTypeInstr(BYTE* dst, instruction ins, regNumber rd, unsigned imm21) const;
122 BYTE* emitOutputInstr_OptsReloc(BYTE* dst, const instrDesc* id, instruction* ins);
123 BYTE* emitOutputInstr_OptsI(BYTE* dst, const instrDesc* id);
124 BYTE* emitOutputInstr_OptsI8(BYTE* dst, const instrDesc* id, ssize_t immediate, regNumber reg1);
125 BYTE* emitOutputInstr_OptsI32(BYTE* dst, ssize_t immediate, regNumber reg1);
126 BYTE* emitOutputInstr_OptsRc(BYTE* dst, const instrDesc* id, instruction* ins);
127 BYTE* emitOutputInstr_OptsRcReloc(BYTE* dst, instruction* ins, unsigned offset, regNumber reg1);
128 BYTE* emitOutputInstr_OptsRcNoReloc(BYTE* dst, instruction* ins, unsigned offset, regNumber reg1);
129 BYTE* emitOutputInstr_OptsRl(BYTE* dst, instrDesc* id, instruction* ins);
130 BYTE* emitOutputInstr_OptsRlReloc(BYTE* dst, ssize_t igOffs, regNumber reg1);
131 BYTE* emitOutputInstr_OptsRlNoReloc(BYTE* dst, ssize_t igOffs, regNumber reg1);
132 BYTE* emitOutputInstr_OptsJalr(BYTE* dst, instrDescJmp* jmp, const insGroup* ig, instruction* ins);
133 BYTE* emitOutputInstr_OptsJalr8(BYTE* dst, const instrDescJmp* jmp, ssize_t immediate);
134 BYTE* emitOutputInstr_OptsJalr24(BYTE* dst, ssize_t immediate);
135 BYTE* emitOutputInstr_OptsJalr28(BYTE* dst, const instrDescJmp* jmp, ssize_t immediate);
136 BYTE* emitOutputInstr_OptsJCond(BYTE* dst, instrDesc* id, const insGroup* ig, instruction* ins);
137 BYTE* emitOutputInstr_OptsJ(BYTE* dst, instrDesc* id, const insGroup* ig, instruction* ins);
138 BYTE* emitOutputInstr_OptsC(BYTE* dst, instrDesc* id, const insGroup* ig, size_t* size);
140 static unsigned TrimSignedToImm12(int imm12);
141 static unsigned TrimSignedToImm13(int imm13);
142 static unsigned TrimSignedToImm20(int imm20);
143 static unsigned TrimSignedToImm21(int imm21);
145 /************************************************************************/
146 /* Public inline informational methods */
147 /************************************************************************/
150 // Returns true if 'value' is a legal signed immediate 13 bit encoding.
151 static bool isValidSimm13(ssize_t value)
153 return -(((int)1) << 12) <= value && value < (((int)1) << 12);
156 // Returns true if 'value' is a legal signed immediate 12 bit encoding.
157 static bool isValidSimm12(ssize_t value)
159 return -(((int)1) << 11) <= value && value < (((int)1) << 11);
162 // Returns true if 'value' is a legal unsigned immediate 12 bit encoding.
163 static bool isValidUimm12(ssize_t value)
165 return (0 == (value >> 12));
168 // Returns true if 'value' is a legal unsigned immediate 11 bit encoding.
169 static bool isValidUimm11(ssize_t value)
171 return (0 == (value >> 11));
174 // Returns true if 'value' is a legal unsigned immediate 5 bit encoding.
175 static bool isValidUimm5(ssize_t value)
177 return (0 == (value >> 5));
180 // Returns true if 'value' is a legal signed immediate 20 bit encoding.
181 static bool isValidSimm20(ssize_t value)
183 return -(((int)1) << 19) <= value && value < (((int)1) << 19);
186 // Returns true if 'value' is a legal unsigned immediate 20 bit encoding.
187 static bool isValidUimm20(ssize_t value)
189 return (0 == (value >> 20));
192 // Returns true if 'value' is a legal signed immediate 21 bit encoding.
193 static bool isValidSimm21(ssize_t value)
195 return -(((int)1) << 20) <= value && value < (((int)1) << 20);
198 // Returns true if 'value' is a legal signed immediate 32 bit encoding.
199 static bool isValidSimm32(ssize_t value)
201 return -(((ssize_t)1) << 31) <= value && value < (((ssize_t)1) << 31);
204 // Returns the number of bits used by the given 'size'.
205 inline static unsigned getBitWidth(emitAttr size)
207 assert(size <= EA_8BYTE);
208 return (unsigned)size * BITS_PER_BYTE;
211 inline static bool isGeneralRegister(regNumber reg)
213 return (reg >= REG_INT_FIRST) && (reg <= REG_INT_LAST);
216 inline static bool isGeneralRegisterOrR0(regNumber reg)
218 return (reg >= REG_FIRST) && (reg <= REG_INT_LAST);
221 inline static bool isFloatReg(regNumber reg)
223 return (reg >= REG_FP_FIRST && reg <= REG_FP_LAST);
226 /************************************************************************/
227 /* Output target-independent instructions */
228 /************************************************************************/
230 void emitIns_J(instruction ins, BasicBlock* dst, int instrCount = 0);
232 /************************************************************************/
233 /* The public entry points to output instructions */
234 /************************************************************************/
237 void emitIns(instruction ins);
239 void emitIns_S_R(instruction ins, emitAttr attr, regNumber ireg, int varx, int offs);
240 void emitIns_S_R_R(instruction ins, emitAttr attr, regNumber ireg, regNumber tmpReg, int varx, int offs);
241 void emitIns_R_S(instruction ins, emitAttr attr, regNumber ireg, int varx, int offs);
243 void emitIns_I(instruction ins, emitAttr attr, ssize_t imm);
244 void emitIns_I_I(instruction ins, emitAttr attr, ssize_t cc, ssize_t offs);
246 void emitIns_R_I(instruction ins, emitAttr attr, regNumber reg, ssize_t imm, insOpts opt = INS_OPTS_NONE);
249 instruction ins, emitAttr attr, regNumber dstReg, regNumber srcReg, bool canSkip, insOpts opt = INS_OPTS_NONE);
251 void emitIns_Mov(emitAttr attr, regNumber dstReg, regNumber srcReg, bool canSkip = false);
253 void emitIns_R_R(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, insOpts opt = INS_OPTS_NONE);
255 void emitIns_R_R(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, insFlags flags)
257 _ASSERTE(!"RISCV64: NYI");
261 instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, ssize_t imm, insOpts opt = INS_OPTS_NONE);
264 instruction ins, emitAttr attr, regNumber reg1, ssize_t imm1, ssize_t imm2, insOpts opt = INS_OPTS_NONE);
267 instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, regNumber reg3, insOpts opt = INS_OPTS_NONE);
269 void emitIns_R_R_R_I(instruction ins,
275 insOpts opt = INS_OPTS_NONE,
276 emitAttr attrReg2 = EA_UNKNOWN);
278 void emitIns_R_R_I_I(
279 instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, int imm1, int imm2, insOpts opt = INS_OPTS_NONE);
281 void emitIns_R_R_R_R(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, regNumber reg3, regNumber reg4);
284 instruction ins, emitAttr attr, regNumber reg, regNumber tmpReg, CORINFO_FIELD_HANDLE fldHnd, int offs);
286 void emitIns_R_L(instruction ins, emitAttr attr, BasicBlock* dst, regNumber reg);
288 void emitIns_J_R(instruction ins, emitAttr attr, BasicBlock* dst, regNumber reg);
290 void emitIns_R_AR(instruction ins, emitAttr attr, regNumber ireg, regNumber reg, int offs);
292 void emitIns_R_AI(instruction ins,
295 ssize_t disp DEBUGARG(size_t targetHandle = 0) DEBUGARG(GenTreeFlags gtFlags = GTF_EMPTY));
300 // I have included here, but commented out, all the values used by the x86 emitter.
301 // However, RISCV64 has a much reduced instruction set, and so the RISCV64 emitter only
302 // supports a subset of the x86 variants. By leaving them commented out, it becomes
303 // a compile time error if code tries to use them (and hopefully see this comment
304 // and know why they are unavailable on RISCV64), while making it easier to stay
305 // in-sync with x86 and possibly add them back in if needed.
307 EC_FUNC_TOKEN, // Direct call to a helper/static/nonvirtual/global method
308 // EC_FUNC_TOKEN_INDIR, // Indirect call to a helper/static/nonvirtual/global method
309 // EC_FUNC_ADDR, // Direct call to an absolute address
311 // EC_FUNC_VIRTUAL, // Call to a virtual method (using the vtable)
312 EC_INDIR_R, // Indirect call via register
313 // EC_INDIR_SR, // Indirect call via stack-reference (local var)
314 // EC_INDIR_C, // Indirect call via static class var
315 // EC_INDIR_ARD, // Indirect call via an addressing mode
320 void emitIns_Call(EmitCallType callType,
321 CORINFO_METHOD_HANDLE methHnd,
322 INDEBUG_LDISASM_COMMA(CORINFO_SIG_INFO* sigInfo) // used to report call sites to the EE
325 emitAttr retSize MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize),
326 VARSET_VALARG_TP ptrVars,
330 regNumber ireg = REG_NA,
331 regNumber xreg = REG_NA,
334 bool isJump = false);
336 unsigned emitOutputCall(const insGroup* ig, BYTE* dst, instrDesc* id, code_t code);
338 unsigned get_curTotalCodeSize(); // bytes of code
340 #endif // TARGET_RISCV64