Sync may31 release/8.0-tizen (#510)
[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, 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);
71
72 emitter::code_t emitInsCode(instruction ins /*, insFormat fmt*/) const;
73
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);
76
77 // Emit the 32-bit RISCV64 instruction 'code' into the 'dst'  buffer
78 unsigned emitOutput_Instr(BYTE* dst, code_t code) const;
79
80 ssize_t emitOutputInstrJumpDistance(const BYTE* src, const insGroup* ig, instrDescJmp* jmp);
81 void emitOutputInstrJumpDistanceHelper(const insGroup* ig,
82                                        instrDescJmp*   jmp,
83                                        UNATIVE_OFFSET& dstOffs,
84                                        const BYTE*&    dstAddr) const;
85
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.
92
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);
100
101 #ifdef DEBUG
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);
109 #endif // DEBUG
110
111 static unsigned castFloatOrIntegralReg(regNumber reg);
112
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;
121
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);
139
140 static unsigned TrimSignedToImm12(int imm12);
141 static unsigned TrimSignedToImm13(int imm13);
142 static unsigned TrimSignedToImm20(int imm20);
143 static unsigned TrimSignedToImm21(int imm21);
144
145 /************************************************************************/
146 /*           Public inline informational methods                        */
147 /************************************************************************/
148
149 public:
150 // Returns true if 'value' is a legal signed immediate 13 bit encoding.
151 static bool isValidSimm13(ssize_t value)
152 {
153     return -(((int)1) << 12) <= value && value < (((int)1) << 12);
154 };
155
156 // Returns true if 'value' is a legal signed immediate 12 bit encoding.
157 static bool isValidSimm12(ssize_t value)
158 {
159     return -(((int)1) << 11) <= value && value < (((int)1) << 11);
160 };
161
162 // Returns true if 'value' is a legal unsigned immediate 12 bit encoding.
163 static bool isValidUimm12(ssize_t value)
164 {
165     return (0 == (value >> 12));
166 }
167
168 // Returns true if 'value' is a legal unsigned immediate 11 bit encoding.
169 static bool isValidUimm11(ssize_t value)
170 {
171     return (0 == (value >> 11));
172 }
173
174 // Returns true if 'value' is a legal unsigned immediate 5 bit encoding.
175 static bool isValidUimm5(ssize_t value)
176 {
177     return (0 == (value >> 5));
178 }
179
180 // Returns true if 'value' is a legal signed immediate 20 bit encoding.
181 static bool isValidSimm20(ssize_t value)
182 {
183     return -(((int)1) << 19) <= value && value < (((int)1) << 19);
184 };
185
186 // Returns true if 'value' is a legal unsigned immediate 20 bit encoding.
187 static bool isValidUimm20(ssize_t value)
188 {
189     return (0 == (value >> 20));
190 };
191
192 // Returns true if 'value' is a legal signed immediate 21 bit encoding.
193 static bool isValidSimm21(ssize_t value)
194 {
195     return -(((int)1) << 20) <= value && value < (((int)1) << 20);
196 };
197
198 // Returns true if 'value' is a legal signed immediate 32 bit encoding.
199 static bool isValidSimm32(ssize_t value)
200 {
201     return -(((ssize_t)1) << 31) <= value && value < (((ssize_t)1) << 31);
202 };
203
204 // Returns the number of bits used by the given 'size'.
205 inline static unsigned getBitWidth(emitAttr size)
206 {
207     assert(size <= EA_8BYTE);
208     return (unsigned)size * BITS_PER_BYTE;
209 }
210
211 inline static bool isGeneralRegister(regNumber reg)
212 {
213     return (reg >= REG_INT_FIRST) && (reg <= REG_INT_LAST);
214 }
215
216 inline static bool isGeneralRegisterOrR0(regNumber reg)
217 {
218     return (reg >= REG_FIRST) && (reg <= REG_INT_LAST);
219 } // Includes REG_R0
220
221 inline static bool isFloatReg(regNumber reg)
222 {
223     return (reg >= REG_FP_FIRST && reg <= REG_FP_LAST);
224 }
225
226 /************************************************************************/
227 /*                   Output target-independent instructions             */
228 /************************************************************************/
229
230 void emitIns_J(instruction ins, BasicBlock* dst, int instrCount = 0);
231
232 /************************************************************************/
233 /*           The public entry points to output instructions             */
234 /************************************************************************/
235
236 public:
237 void emitIns(instruction ins);
238
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);
242
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);
245
246 void emitIns_R_I(instruction ins, emitAttr attr, regNumber reg, ssize_t imm, insOpts opt = INS_OPTS_NONE);
247
248 void emitIns_Mov(
249     instruction ins, emitAttr attr, regNumber dstReg, regNumber srcReg, bool canSkip, insOpts opt = INS_OPTS_NONE);
250
251 void emitIns_Mov(emitAttr attr, regNumber dstReg, regNumber srcReg, bool canSkip = false);
252
253 void emitIns_R_R(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, insOpts opt = INS_OPTS_NONE);
254
255 void emitIns_R_R(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, insFlags flags)
256 {
257     _ASSERTE(!"RISCV64: NYI");
258 }
259
260 void emitIns_R_R_I(
261     instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, ssize_t imm, insOpts opt = INS_OPTS_NONE);
262
263 void emitIns_R_I_I(
264     instruction ins, emitAttr attr, regNumber reg1, ssize_t imm1, ssize_t imm2, insOpts opt = INS_OPTS_NONE);
265
266 void emitIns_R_R_R(
267     instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, regNumber reg3, insOpts opt = INS_OPTS_NONE);
268
269 void emitIns_R_R_R_I(instruction ins,
270                      emitAttr    attr,
271                      regNumber   reg1,
272                      regNumber   reg2,
273                      regNumber   reg3,
274                      ssize_t     imm,
275                      insOpts     opt      = INS_OPTS_NONE,
276                      emitAttr    attrReg2 = EA_UNKNOWN);
277
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);
280
281 void emitIns_R_R_R_R(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, regNumber reg3, regNumber reg4);
282
283 void emitIns_R_C(
284     instruction ins, emitAttr attr, regNumber reg, regNumber tmpReg, CORINFO_FIELD_HANDLE fldHnd, int offs);
285
286 void emitIns_R_L(instruction ins, emitAttr attr, BasicBlock* dst, regNumber reg);
287
288 void emitIns_J_R(instruction ins, emitAttr attr, BasicBlock* dst, regNumber reg);
289
290 void emitIns_R_AR(instruction ins, emitAttr attr, regNumber ireg, regNumber reg, int offs);
291
292 void emitIns_R_AI(instruction ins,
293                   emitAttr    attr,
294                   regNumber   reg,
295                   ssize_t disp DEBUGARG(size_t targetHandle = 0) DEBUGARG(GenTreeFlags gtFlags = GTF_EMPTY));
296
297 enum EmitCallType
298 {
299
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.
306
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
310
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
316
317     EC_COUNT
318 };
319
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
323                   void*    addr,
324                   ssize_t  argSize,
325                   emitAttr retSize MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize),
326                   VARSET_VALARG_TP ptrVars,
327                   regMaskTP        gcrefRegs,
328                   regMaskTP        byrefRegs,
329                   const DebugInfo& di,
330                   regNumber        ireg   = REG_NA,
331                   regNumber        xreg   = REG_NA,
332                   unsigned         xmul   = 0,
333                   ssize_t          disp   = 0,
334                   bool             isJump = false);
335
336 unsigned emitOutputCall(const insGroup* ig, BYTE* dst, instrDesc* id, code_t code);
337
338 unsigned get_curTotalCodeSize(); // bytes of code
339
340 #endif // TARGET_RISCV64