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,
67 const char* register1Name,
68 const char* register2Name,
70 const insGroup* ig) const;
71 void emitDispBranchOffset(const instrDesc* id, const insGroup* ig) const;
72 void emitDispBranchLabel(const instrDesc* id) const;
73 bool emitDispBranchInstrType(unsigned opcode2) const;
74 void emitDispIllegalInstruction(code_t instructionCode);
76 emitter::code_t emitInsCode(instruction ins /*, insFormat fmt*/);
78 // Generate code for a load or store operation and handle the case of contained GT_LEA op1 with [base + offset]
79 void emitInsLoadStoreOp(instruction ins, emitAttr attr, regNumber dataReg, GenTreeIndir* indir);
81 // Emit the 32-bit RISCV64 instruction 'code' into the 'dst' buffer
82 unsigned emitOutput_Instr(BYTE* dst, code_t code);
84 ssize_t emitOutputInstrJumpDistance(const BYTE* dst, const BYTE* src, const insGroup* ig, instrDescJmp* jmp);
85 void emitOutputInstrJumpDistanceHelper(const insGroup* ig,
87 UNATIVE_OFFSET& dstOffs,
88 const BYTE*& dstAddr) const;
90 // Method to do check if mov is redundant with respect to the last instruction.
91 // If yes, the caller of this method can choose to omit current mov instruction.
92 static bool IsMovInstruction(instruction ins);
93 bool IsRedundantMov(instruction ins, emitAttr size, regNumber dst, regNumber src, bool canSkip);
94 bool IsRedundantLdStr(
95 instruction ins, regNumber reg1, regNumber reg2, ssize_t imm, emitAttr size, insFormat fmt); // New functions end.
97 /************************************************************************/
98 /* Public inline informational methods */
99 /************************************************************************/
102 // Returns true if 'value' is a legal signed immediate 13 bit encoding.
103 static bool isValidSimm13(ssize_t value)
105 return -(((int)1) << 12) <= value && value < (((int)1) << 12);
108 // Returns true if 'value' is a legal signed immediate 12 bit encoding.
109 static bool isValidSimm12(ssize_t value)
111 return -(((int)1) << 11) <= value && value < (((int)1) << 11);
114 // Returns true if 'value' is a legal unsigned immediate 12 bit encoding.
115 static bool isValidUimm12(ssize_t value)
117 return (0 == (value >> 12));
120 // Returns true if 'value' is a legal unsigned immediate 11 bit encoding.
121 static bool isValidUimm11(ssize_t value)
123 return (0 == (value >> 11));
126 // Returns true if 'value' is a legal unsigned immediate 5 bit encoding.
127 static bool isValidUimm5(ssize_t value)
129 return (0 == (value >> 5));
132 // Returns true if 'value' is a legal signed immediate 20 bit encoding.
133 static bool isValidSimm20(ssize_t value)
135 return -(((int)1) << 19) <= value && value < (((int)1) << 19);
138 // Returns true if 'value' is a legal unsigned immediate 20 bit encoding.
139 static bool isValidUimm20(ssize_t value)
141 return (0 == (value >> 20));
144 // Returns true if 'value' is a legal signed immediate 21 bit encoding.
145 static bool isValidSimm21(ssize_t value)
147 return -(((int)1) << 20) <= value && value < (((int)1) << 20);
150 // Returns true if 'value' is a legal signed immediate 32 bit encoding.
151 static bool isValidSimm32(ssize_t value)
153 return -(((ssize_t)1) << 31) <= value && value < (((ssize_t)1) << 31);
156 // Returns the number of bits used by the given 'size'.
157 inline static unsigned getBitWidth(emitAttr size)
159 assert(size <= EA_8BYTE);
160 return (unsigned)size * BITS_PER_BYTE;
163 inline static bool isGeneralRegister(regNumber reg)
165 return (reg >= REG_INT_FIRST) && (reg <= REG_INT_LAST);
168 inline static bool isGeneralRegisterOrR0(regNumber reg)
170 return (reg >= REG_FIRST) && (reg <= REG_INT_LAST);
173 inline static bool isFloatReg(regNumber reg)
175 return (reg >= REG_FP_FIRST && reg <= REG_FP_LAST);
178 /************************************************************************/
179 /* Output target-independent instructions */
180 /************************************************************************/
182 void emitIns_J(instruction ins, BasicBlock* dst, int instrCount = 0);
184 /************************************************************************/
185 /* The public entry points to output instructions */
186 /************************************************************************/
189 void emitIns(instruction ins);
191 void emitIns_S_R(instruction ins, emitAttr attr, regNumber ireg, int varx, int offs);
192 void emitIns_S_R_R(instruction ins, emitAttr attr, regNumber ireg, regNumber tmpReg, int varx, int offs);
193 void emitIns_R_S(instruction ins, emitAttr attr, regNumber ireg, int varx, int offs);
195 void emitIns_I(instruction ins, emitAttr attr, ssize_t imm);
196 void emitIns_I_I(instruction ins, emitAttr attr, ssize_t cc, ssize_t offs);
198 void emitIns_R_I(instruction ins, emitAttr attr, regNumber reg, ssize_t imm, insOpts opt = INS_OPTS_NONE);
201 instruction ins, emitAttr attr, regNumber dstReg, regNumber srcReg, bool canSkip, insOpts opt = INS_OPTS_NONE);
203 void emitIns_Mov(emitAttr attr, regNumber dstReg, regNumber srcReg, bool canSkip = false);
205 void emitIns_R_R(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, insOpts opt = INS_OPTS_NONE);
207 void emitIns_R_R(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, insFlags flags)
209 _ASSERTE(!"RISCV64: NYI");
213 instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, ssize_t imm, insOpts opt = INS_OPTS_NONE);
216 instruction ins, emitAttr attr, regNumber reg1, ssize_t imm1, ssize_t imm2, insOpts opt = INS_OPTS_NONE);
219 instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, regNumber reg3, insOpts opt = INS_OPTS_NONE);
221 void emitIns_R_R_R_I(instruction ins,
227 insOpts opt = INS_OPTS_NONE,
228 emitAttr attrReg2 = EA_UNKNOWN);
230 void emitIns_R_R_I_I(
231 instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, int imm1, int imm2, insOpts opt = INS_OPTS_NONE);
233 void emitIns_R_R_R_R(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, regNumber reg3, regNumber reg4);
236 instruction ins, emitAttr attr, regNumber reg, regNumber tmpReg, CORINFO_FIELD_HANDLE fldHnd, int offs);
238 void emitIns_R_L(instruction ins, emitAttr attr, BasicBlock* dst, regNumber reg);
240 void emitIns_J_R(instruction ins, emitAttr attr, BasicBlock* dst, regNumber reg);
242 void emitIns_R_AR(instruction ins, emitAttr attr, regNumber ireg, regNumber reg, int offs);
244 void emitIns_R_AI(instruction ins,
247 ssize_t disp DEBUGARG(size_t targetHandle = 0) DEBUGARG(GenTreeFlags gtFlags = GTF_EMPTY));
252 // I have included here, but commented out, all the values used by the x86 emitter.
253 // However, RISCV64 has a much reduced instruction set, and so the RISCV64 emitter only
254 // supports a subset of the x86 variants. By leaving them commented out, it becomes
255 // a compile time error if code tries to use them (and hopefully see this comment
256 // and know why they are unavailable on RISCV64), while making it easier to stay
257 // in-sync with x86 and possibly add them back in if needed.
259 EC_FUNC_TOKEN, // Direct call to a helper/static/nonvirtual/global method
260 // EC_FUNC_TOKEN_INDIR, // Indirect call to a helper/static/nonvirtual/global method
261 // EC_FUNC_ADDR, // Direct call to an absolute address
263 // EC_FUNC_VIRTUAL, // Call to a virtual method (using the vtable)
264 EC_INDIR_R, // Indirect call via register
265 // EC_INDIR_SR, // Indirect call via stack-reference (local var)
266 // EC_INDIR_C, // Indirect call via static class var
267 // EC_INDIR_ARD, // Indirect call via an addressing mode
272 void emitIns_Call(EmitCallType callType,
273 CORINFO_METHOD_HANDLE methHnd,
274 INDEBUG_LDISASM_COMMA(CORINFO_SIG_INFO* sigInfo) // used to report call sites to the EE
277 emitAttr retSize MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize),
278 VARSET_VALARG_TP ptrVars,
282 regNumber ireg = REG_NA,
283 regNumber xreg = REG_NA,
286 bool isJump = false);
288 unsigned emitOutputCall(insGroup* ig, BYTE* dst, instrDesc* id, code_t code);
290 unsigned get_curTotalCodeSize(); // bytes of code
292 #endif // TARGET_RISCV64