[RISC-V] Add DynamicHelpers to riscv64 stubs (#94735)
[platform/upstream/dotnet/runtime.git] / src / coreclr / jit / emitriscv64.h
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 #if defined(TARGET_RISCV64)
5
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.
9 //
10 typedef unsigned int code_t;
11
12 /************************************************************************/
13 /*         Routines that compute the size of / encode instructions      */
14 /************************************************************************/
15
16 struct CnsVal
17 {
18     ssize_t cnsVal;
19     bool    cnsReloc;
20 };
21
22 #ifdef DEBUG
23
24 /************************************************************************/
25 /*             Debug-only routines to display instructions              */
26 /************************************************************************/
27
28 const char* emitFPregName(unsigned reg, bool varName = true);
29 const char* emitVectorRegName(regNumber reg);
30
31 void emitDisInsName(code_t code, const BYTE* addr, instrDesc* id);
32 #endif // DEBUG
33
34 void emitIns_J_cond_la(instruction ins, BasicBlock* dst, regNumber reg1 = REG_R0, regNumber reg2 = REG_R0);
35
36 void emitLoadImmediate(emitAttr attr, regNumber reg, ssize_t imm);
37
38 /************************************************************************/
39 /*  Private members that deal with target-dependent instr. descriptors  */
40 /************************************************************************/
41
42 private:
43 instrDesc* emitNewInstrCallDir(int              argCnt,
44                                VARSET_VALARG_TP GCvars,
45                                regMaskTP        gcrefRegs,
46                                regMaskTP        byrefRegs,
47                                emitAttr retSize MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize));
48
49 instrDesc* emitNewInstrCallInd(int              argCnt,
50                                ssize_t          disp,
51                                VARSET_VALARG_TP GCvars,
52                                regMaskTP        gcrefRegs,
53                                regMaskTP        byrefRegs,
54                                emitAttr retSize MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize));
55
56 /************************************************************************/
57 /*               Private helpers for instruction output                 */
58 /************************************************************************/
59
60 private:
61 bool emitInsIsLoad(instruction ins);
62 bool emitInsIsStore(instruction ins);
63 bool emitInsIsLoadOrStore(instruction ins);
64
65 emitter::code_t emitInsCode(instruction ins /*, insFormat fmt*/);
66
67 // Generate code for a load or store operation and handle the case of contained GT_LEA op1 with [base + offset]
68 void emitInsLoadStoreOp(instruction ins, emitAttr attr, regNumber dataReg, GenTreeIndir* indir);
69
70 //  Emit the 32-bit RISCV64 instruction 'code' into the 'dst'  buffer
71 unsigned emitOutput_Instr(BYTE* dst, code_t code);
72
73 // Method to do check if mov is redundant with respect to the last instruction.
74 // If yes, the caller of this method can choose to omit current mov instruction.
75 static bool IsMovInstruction(instruction ins);
76 bool IsRedundantMov(instruction ins, emitAttr size, regNumber dst, regNumber src, bool canSkip);
77 bool IsRedundantLdStr(
78     instruction ins, regNumber reg1, regNumber reg2, ssize_t imm, emitAttr size, insFormat fmt); // New functions end.
79
80 /************************************************************************/
81 /*           Public inline informational methods                        */
82 /************************************************************************/
83
84 public:
85 // Returns true if 'value' is a legal signed immediate 13 bit encoding.
86 static bool isValidSimm13(ssize_t value)
87 {
88     return -(((int)1) << 12) <= value && value < (((int)1) << 12);
89 };
90
91 // Returns true if 'value' is a legal signed immediate 12 bit encoding.
92 static bool isValidSimm12(ssize_t value)
93 {
94     return -(((int)1) << 11) <= value && value < (((int)1) << 11);
95 };
96
97 // Returns true if 'value' is a legal unsigned immediate 12 bit encoding.
98 static bool isValidUimm12(ssize_t value)
99 {
100     return (0 == (value >> 12));
101 }
102
103 // Returns true if 'value' is a legal unsigned immediate 11 bit encoding.
104 static bool isValidUimm11(ssize_t value)
105 {
106     return (0 == (value >> 11));
107 }
108
109 // Returns true if 'value' is a legal signed immediate 20 bit encoding.
110 static bool isValidSimm20(ssize_t value)
111 {
112     return -(((int)1) << 19) <= value && value < (((int)1) << 19);
113 };
114
115 // Returns true if 'value' is a legal unsigned immediate 20 bit encoding.
116 static bool isValidUimm20(ssize_t value)
117 {
118     return (0 == (value >> 20));
119 };
120
121 // Returns true if 'value' is a legal signed immediate 21 bit encoding.
122 static bool isValidSimm21(ssize_t value)
123 {
124     return -(((int)1) << 20) <= value && value < (((int)1) << 20);
125 };
126
127 // Returns true if 'value' is a legal signed immediate 32 bit encoding.
128 static bool isValidSimm32(ssize_t value)
129 {
130     return -(((ssize_t)1) << 31) <= value && value < (((ssize_t)1) << 31);
131 };
132
133 // Returns the number of bits used by the given 'size'.
134 inline static unsigned getBitWidth(emitAttr size)
135 {
136     assert(size <= EA_8BYTE);
137     return (unsigned)size * BITS_PER_BYTE;
138 }
139
140 inline static bool isGeneralRegister(regNumber reg)
141 {
142     return (reg >= REG_INT_FIRST) && (reg <= REG_INT_LAST);
143 }
144
145 inline static bool isGeneralRegisterOrR0(regNumber reg)
146 {
147     return (reg >= REG_FIRST) && (reg <= REG_INT_LAST);
148 } // Includes REG_R0
149
150 inline static bool isFloatReg(regNumber reg)
151 {
152     return (reg >= REG_FP_FIRST && reg <= REG_FP_LAST);
153 }
154
155 /************************************************************************/
156 /*                   Output target-independent instructions             */
157 /************************************************************************/
158
159 void emitIns_J(instruction ins, BasicBlock* dst, int instrCount = 0);
160
161 /************************************************************************/
162 /*           The public entry points to output instructions             */
163 /************************************************************************/
164
165 public:
166 void emitIns(instruction ins);
167
168 void emitIns_S_R(instruction ins, emitAttr attr, regNumber ireg, int varx, int offs);
169 void emitIns_S_R_R(instruction ins, emitAttr attr, regNumber ireg, regNumber tmpReg, int varx, int offs);
170 void emitIns_R_S(instruction ins, emitAttr attr, regNumber ireg, int varx, int offs);
171
172 void emitIns_I(instruction ins, emitAttr attr, ssize_t imm);
173 void emitIns_I_I(instruction ins, emitAttr attr, ssize_t cc, ssize_t offs);
174
175 void emitIns_R_I(instruction ins, emitAttr attr, regNumber reg, ssize_t imm, insOpts opt = INS_OPTS_NONE);
176
177 void emitIns_Mov(
178     instruction ins, emitAttr attr, regNumber dstReg, regNumber srcReg, bool canSkip, insOpts opt = INS_OPTS_NONE);
179
180 void emitIns_Mov(emitAttr attr, regNumber dstReg, regNumber srcReg, bool canSkip = false);
181
182 void emitIns_R_R(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, insOpts opt = INS_OPTS_NONE);
183
184 void emitIns_R_R(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, insFlags flags)
185 {
186     _ASSERTE(!"RISCV64: NYI");
187 }
188
189 void emitIns_R_R_I(
190     instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, ssize_t imm, insOpts opt = INS_OPTS_NONE);
191
192 void emitIns_R_R_R(
193     instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, regNumber reg3, insOpts opt = INS_OPTS_NONE);
194
195 void emitIns_R_R_R_I(instruction ins,
196                      emitAttr    attr,
197                      regNumber   reg1,
198                      regNumber   reg2,
199                      regNumber   reg3,
200                      ssize_t     imm,
201                      insOpts     opt      = INS_OPTS_NONE,
202                      emitAttr    attrReg2 = EA_UNKNOWN);
203
204 void emitIns_R_R_I_I(
205     instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, int imm1, int imm2, insOpts opt = INS_OPTS_NONE);
206
207 void emitIns_R_R_R_R(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, regNumber reg3, regNumber reg4);
208
209 void emitIns_R_C(
210     instruction ins, emitAttr attr, regNumber reg, regNumber tmpReg, CORINFO_FIELD_HANDLE fldHnd, int offs);
211
212 void emitIns_R_L(instruction ins, emitAttr attr, BasicBlock* dst, regNumber reg);
213
214 void emitIns_J_R(instruction ins, emitAttr attr, BasicBlock* dst, regNumber reg);
215
216 void emitIns_R_AR(instruction ins, emitAttr attr, regNumber ireg, regNumber reg, int offs);
217
218 void emitIns_R_AI(instruction ins,
219                   emitAttr    attr,
220                   regNumber   reg,
221                   ssize_t disp DEBUGARG(size_t targetHandle = 0) DEBUGARG(GenTreeFlags gtFlags = GTF_EMPTY));
222
223 enum EmitCallType
224 {
225
226     // I have included here, but commented out, all the values used by the x86 emitter.
227     // However, RISCV64 has a much reduced instruction set, and so the RISCV64 emitter only
228     // supports a subset of the x86 variants.  By leaving them commented out, it becomes
229     // a compile time error if code tries to use them (and hopefully see this comment
230     // and know why they are unavailable on RISCV64), while making it easier to stay
231     // in-sync with x86 and possibly add them back in if needed.
232
233     EC_FUNC_TOKEN, //   Direct call to a helper/static/nonvirtual/global method
234                    //  EC_FUNC_TOKEN_INDIR,    // Indirect call to a helper/static/nonvirtual/global method
235     // EC_FUNC_ADDR,  // Direct call to an absolute address
236
237     //  EC_FUNC_VIRTUAL,        // Call to a virtual method (using the vtable)
238     EC_INDIR_R, // Indirect call via register
239                 //  EC_INDIR_SR,            // Indirect call via stack-reference (local var)
240                 //  EC_INDIR_C,             // Indirect call via static class var
241                 //  EC_INDIR_ARD,           // Indirect call via an addressing mode
242
243     EC_COUNT
244 };
245
246 void emitIns_Call(EmitCallType          callType,
247                   CORINFO_METHOD_HANDLE methHnd,
248                   INDEBUG_LDISASM_COMMA(CORINFO_SIG_INFO* sigInfo) // used to report call sites to the EE
249                   void*    addr,
250                   ssize_t  argSize,
251                   emitAttr retSize MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize),
252                   VARSET_VALARG_TP ptrVars,
253                   regMaskTP        gcrefRegs,
254                   regMaskTP        byrefRegs,
255                   const DebugInfo& di,
256                   regNumber        ireg   = REG_NA,
257                   regNumber        xreg   = REG_NA,
258                   unsigned         xmul   = 0,
259                   ssize_t          disp   = 0,
260                   bool             isJump = false);
261
262 unsigned emitOutputCall(insGroup* ig, BYTE* dst, instrDesc* id, code_t code);
263
264 unsigned get_curTotalCodeSize(); // bytes of code
265
266 #endif // TARGET_RISCV64