d3b00b2d1043564c9e0e7bd91ccd5b5a62f7cb94
[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 #endif // DEBUG
31
32 void emitIns_J_cond_la(instruction ins, BasicBlock* dst, regNumber reg1 = REG_R0, regNumber reg2 = REG_R0);
33
34 void emitLoadImmediate(emitAttr attr, regNumber reg, ssize_t imm);
35
36 /************************************************************************/
37 /*  Private members that deal with target-dependent instr. descriptors  */
38 /************************************************************************/
39
40 private:
41 instrDesc* emitNewInstrCallDir(int              argCnt,
42                                VARSET_VALARG_TP GCvars,
43                                regMaskTP        gcrefRegs,
44                                regMaskTP        byrefRegs,
45                                emitAttr retSize MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize));
46
47 instrDesc* emitNewInstrCallInd(int              argCnt,
48                                ssize_t          disp,
49                                VARSET_VALARG_TP GCvars,
50                                regMaskTP        gcrefRegs,
51                                regMaskTP        byrefRegs,
52                                emitAttr retSize MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize));
53
54 /************************************************************************/
55 /*               Private helpers for instruction output                 */
56 /************************************************************************/
57
58 private:
59 bool emitInsIsLoad(instruction ins);
60 bool emitInsIsStore(instruction ins);
61 bool emitInsIsLoadOrStore(instruction ins);
62
63 void emitDispInsName(
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,
69                     const instrDesc* id,
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);
75
76 emitter::code_t emitInsCode(instruction ins /*, insFormat fmt*/);
77
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);
80
81 // Emit the 32-bit RISCV64 instruction 'code' into the 'dst'  buffer
82 unsigned emitOutput_Instr(BYTE* dst, code_t code);
83
84 ssize_t emitOutputInstrJumpDistance(const BYTE* dst, const BYTE* src, const insGroup* ig, instrDescJmp* jmp);
85 void emitOutputInstrJumpDistanceHelper(const insGroup* ig,
86                                        instrDescJmp*   jmp,
87                                        UNATIVE_OFFSET& dstOffs,
88                                        const BYTE*&    dstAddr) const;
89
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.
96
97 /************************************************************************/
98 /*           Public inline informational methods                        */
99 /************************************************************************/
100
101 public:
102 // Returns true if 'value' is a legal signed immediate 13 bit encoding.
103 static bool isValidSimm13(ssize_t value)
104 {
105     return -(((int)1) << 12) <= value && value < (((int)1) << 12);
106 };
107
108 // Returns true if 'value' is a legal signed immediate 12 bit encoding.
109 static bool isValidSimm12(ssize_t value)
110 {
111     return -(((int)1) << 11) <= value && value < (((int)1) << 11);
112 };
113
114 // Returns true if 'value' is a legal unsigned immediate 12 bit encoding.
115 static bool isValidUimm12(ssize_t value)
116 {
117     return (0 == (value >> 12));
118 }
119
120 // Returns true if 'value' is a legal unsigned immediate 11 bit encoding.
121 static bool isValidUimm11(ssize_t value)
122 {
123     return (0 == (value >> 11));
124 }
125
126 // Returns true if 'value' is a legal unsigned immediate 5 bit encoding.
127 static bool isValidUimm5(ssize_t value)
128 {
129     return (0 == (value >> 5));
130 }
131
132 // Returns true if 'value' is a legal signed immediate 20 bit encoding.
133 static bool isValidSimm20(ssize_t value)
134 {
135     return -(((int)1) << 19) <= value && value < (((int)1) << 19);
136 };
137
138 // Returns true if 'value' is a legal unsigned immediate 20 bit encoding.
139 static bool isValidUimm20(ssize_t value)
140 {
141     return (0 == (value >> 20));
142 };
143
144 // Returns true if 'value' is a legal signed immediate 21 bit encoding.
145 static bool isValidSimm21(ssize_t value)
146 {
147     return -(((int)1) << 20) <= value && value < (((int)1) << 20);
148 };
149
150 // Returns true if 'value' is a legal signed immediate 32 bit encoding.
151 static bool isValidSimm32(ssize_t value)
152 {
153     return -(((ssize_t)1) << 31) <= value && value < (((ssize_t)1) << 31);
154 };
155
156 // Returns the number of bits used by the given 'size'.
157 inline static unsigned getBitWidth(emitAttr size)
158 {
159     assert(size <= EA_8BYTE);
160     return (unsigned)size * BITS_PER_BYTE;
161 }
162
163 inline static bool isGeneralRegister(regNumber reg)
164 {
165     return (reg >= REG_INT_FIRST) && (reg <= REG_INT_LAST);
166 }
167
168 inline static bool isGeneralRegisterOrR0(regNumber reg)
169 {
170     return (reg >= REG_FIRST) && (reg <= REG_INT_LAST);
171 } // Includes REG_R0
172
173 inline static bool isFloatReg(regNumber reg)
174 {
175     return (reg >= REG_FP_FIRST && reg <= REG_FP_LAST);
176 }
177
178 /************************************************************************/
179 /*                   Output target-independent instructions             */
180 /************************************************************************/
181
182 void emitIns_J(instruction ins, BasicBlock* dst, int instrCount = 0);
183
184 /************************************************************************/
185 /*           The public entry points to output instructions             */
186 /************************************************************************/
187
188 public:
189 void emitIns(instruction ins);
190
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);
194
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);
197
198 void emitIns_R_I(instruction ins, emitAttr attr, regNumber reg, ssize_t imm, insOpts opt = INS_OPTS_NONE);
199
200 void emitIns_Mov(
201     instruction ins, emitAttr attr, regNumber dstReg, regNumber srcReg, bool canSkip, insOpts opt = INS_OPTS_NONE);
202
203 void emitIns_Mov(emitAttr attr, regNumber dstReg, regNumber srcReg, bool canSkip = false);
204
205 void emitIns_R_R(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, insOpts opt = INS_OPTS_NONE);
206
207 void emitIns_R_R(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, insFlags flags)
208 {
209     _ASSERTE(!"RISCV64: NYI");
210 }
211
212 void emitIns_R_R_I(
213     instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, ssize_t imm, insOpts opt = INS_OPTS_NONE);
214
215 void emitIns_R_I_I(
216     instruction ins, emitAttr attr, regNumber reg1, ssize_t imm1, ssize_t imm2, insOpts opt = INS_OPTS_NONE);
217
218 void emitIns_R_R_R(
219     instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, regNumber reg3, insOpts opt = INS_OPTS_NONE);
220
221 void emitIns_R_R_R_I(instruction ins,
222                      emitAttr    attr,
223                      regNumber   reg1,
224                      regNumber   reg2,
225                      regNumber   reg3,
226                      ssize_t     imm,
227                      insOpts     opt      = INS_OPTS_NONE,
228                      emitAttr    attrReg2 = EA_UNKNOWN);
229
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);
232
233 void emitIns_R_R_R_R(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, regNumber reg3, regNumber reg4);
234
235 void emitIns_R_C(
236     instruction ins, emitAttr attr, regNumber reg, regNumber tmpReg, CORINFO_FIELD_HANDLE fldHnd, int offs);
237
238 void emitIns_R_L(instruction ins, emitAttr attr, BasicBlock* dst, regNumber reg);
239
240 void emitIns_J_R(instruction ins, emitAttr attr, BasicBlock* dst, regNumber reg);
241
242 void emitIns_R_AR(instruction ins, emitAttr attr, regNumber ireg, regNumber reg, int offs);
243
244 void emitIns_R_AI(instruction ins,
245                   emitAttr    attr,
246                   regNumber   reg,
247                   ssize_t disp DEBUGARG(size_t targetHandle = 0) DEBUGARG(GenTreeFlags gtFlags = GTF_EMPTY));
248
249 enum EmitCallType
250 {
251
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.
258
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
262
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
268
269     EC_COUNT
270 };
271
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
275                   void*    addr,
276                   ssize_t  argSize,
277                   emitAttr retSize MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize),
278                   VARSET_VALARG_TP ptrVars,
279                   regMaskTP        gcrefRegs,
280                   regMaskTP        byrefRegs,
281                   const DebugInfo& di,
282                   regNumber        ireg   = REG_NA,
283                   regNumber        xreg   = REG_NA,
284                   unsigned         xmul   = 0,
285                   ssize_t          disp   = 0,
286                   bool             isJump = false);
287
288 unsigned emitOutputCall(insGroup* ig, BYTE* dst, instrDesc* id, code_t code);
289
290 unsigned get_curTotalCodeSize(); // bytes of code
291
292 #endif // TARGET_RISCV64