dfd7e6ec5053b8ef5fc649f12bfccdeedd0cb140
[platform/upstream/coreclr.git] / src / jit / emitxarch.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 // See the LICENSE file in the project root for more information.
4
5 #if defined(_TARGET_XARCH_)
6
7 /************************************************************************/
8 /*           Public inline informational methods                        */
9 /************************************************************************/
10
11 public:
12 inline static bool isGeneralRegister(regNumber reg)
13 {
14     return (reg <= REG_INT_LAST);
15 }
16
17 inline static bool isFloatReg(regNumber reg)
18 {
19     return (reg >= REG_FP_FIRST && reg <= REG_FP_LAST);
20 }
21
22 inline static bool isDoubleReg(regNumber reg)
23 {
24     return isFloatReg(reg);
25 }
26
27 /************************************************************************/
28 /*         Routines that compute the size of / encode instructions      */
29 /************************************************************************/
30
31 struct CnsVal
32 {
33     ssize_t cnsVal;
34 #ifdef RELOC_SUPPORT
35     bool cnsReloc;
36 #endif
37 };
38
39 UNATIVE_OFFSET emitInsSize(size_t code);
40 UNATIVE_OFFSET emitInsSizeRM(instruction ins);
41 UNATIVE_OFFSET emitInsSizeSV(size_t code, int var, int dsp);
42 UNATIVE_OFFSET emitInsSizeSV(instrDesc* id, int var, int dsp, int val);
43 UNATIVE_OFFSET emitInsSizeRR(instruction ins, regNumber reg1, regNumber reg2, emitAttr attr);
44 UNATIVE_OFFSET emitInsSizeAM(instrDesc* id, size_t code);
45 UNATIVE_OFFSET emitInsSizeAM(instrDesc* id, size_t code, int val);
46 UNATIVE_OFFSET emitInsSizeCV(instrDesc* id, size_t code);
47 UNATIVE_OFFSET emitInsSizeCV(instrDesc* id, size_t code, int val);
48
49 BYTE* emitOutputAM(BYTE* dst, instrDesc* id, size_t code, CnsVal* addc = nullptr);
50 BYTE* emitOutputSV(BYTE* dst, instrDesc* id, size_t code, CnsVal* addc = nullptr);
51 BYTE* emitOutputCV(BYTE* dst, instrDesc* id, size_t code, CnsVal* addc = nullptr);
52
53 BYTE* emitOutputR(BYTE* dst, instrDesc* id);
54 BYTE* emitOutputRI(BYTE* dst, instrDesc* id);
55 BYTE* emitOutputRR(BYTE* dst, instrDesc* id);
56 BYTE* emitOutputIV(BYTE* dst, instrDesc* id);
57
58 #ifdef FEATURE_AVX_SUPPORT
59 BYTE* emitOutputRRR(BYTE* dst, instrDesc* id);
60 #endif
61
62 BYTE* emitOutputLJ(BYTE* dst, instrDesc* id);
63
64 unsigned emitOutputRexOrVexPrefixIfNeeded(instruction ins, BYTE* dst, size_t& code);
65 unsigned emitGetRexPrefixSize(instruction ins);
66 unsigned emitGetVexPrefixSize(instruction ins, emitAttr attr);
67 unsigned emitGetPrefixSize(size_t code);
68 unsigned emitGetVexPrefixAdjustedSize(instruction ins, emitAttr attr, size_t code);
69
70 unsigned insEncodeReg345(instruction ins, regNumber reg, emitAttr size, size_t* code);
71 unsigned insEncodeReg012(instruction ins, regNumber reg, emitAttr size, size_t* code);
72 size_t insEncodeReg3456(instruction ins, regNumber reg, emitAttr size, size_t code);
73 unsigned insEncodeRegSIB(instruction ins, regNumber reg, size_t* code);
74
75 size_t insEncodeMRreg(instruction ins, size_t code);
76 size_t insEncodeMRreg(instruction ins, regNumber reg, emitAttr size, size_t code);
77 size_t insEncodeRRIb(instruction ins, regNumber reg, emitAttr size);
78 size_t insEncodeOpreg(instruction ins, regNumber reg, emitAttr size);
79
80 bool IsAVXInstruction(instruction ins);
81 size_t insEncodeMIreg(instruction ins, regNumber reg, emitAttr size, size_t code);
82
83 size_t AddRexWPrefix(instruction ins, size_t code);
84 size_t AddRexRPrefix(instruction ins, size_t code);
85 size_t AddRexXPrefix(instruction ins, size_t code);
86 size_t AddRexBPrefix(instruction ins, size_t code);
87 size_t AddRexPrefix(instruction ins, size_t code);
88
89 #ifdef FEATURE_AVX_SUPPORT
90 // 3-byte VEX prefix starts with byte 0xC4
91 #define VEX_PREFIX_MASK_3BYTE 0xC4000000000000LL
92 bool TakesVexPrefix(instruction ins);
93 // Returns true if the instruction encoding already contains VEX prefix
94 bool hasVexPrefix(size_t code)
95 {
96     return (code & VEX_PREFIX_MASK_3BYTE) != 0;
97 }
98 size_t AddVexPrefix(instruction ins, size_t code, emitAttr attr);
99 size_t AddVexPrefixIfNeeded(instruction ins, size_t code, emitAttr size)
100 {
101     if (TakesVexPrefix(ins))
102     {
103         code = AddVexPrefix(ins, code, size);
104     }
105     return code;
106 }
107 size_t AddVexPrefixIfNeededAndNotPresent(instruction ins, size_t code, emitAttr size)
108 {
109     if (TakesVexPrefix(ins) && !hasVexPrefix(code))
110     {
111         code = AddVexPrefix(ins, code, size);
112     }
113     return code;
114 }
115 bool useAVXEncodings;
116 bool UseAVX()
117 {
118     return useAVXEncodings;
119 }
120 void SetUseAVX(bool value)
121 {
122     useAVXEncodings = value;
123 }
124 bool IsThreeOperandBinaryAVXInstruction(instruction ins);
125 bool IsThreeOperandMoveAVXInstruction(instruction ins);
126 bool IsThreeOperandAVXInstruction(instruction ins)
127 {
128     return (IsThreeOperandBinaryAVXInstruction(ins) || IsThreeOperandMoveAVXInstruction(ins));
129 }
130 #else  // !FEATURE_AVX_SUPPORT
131 bool UseAVX()
132 {
133     return false;
134 }
135 bool hasVexPrefix(size_t code)
136 {
137     return false;
138 }
139 bool IsThreeOperandBinaryAVXInstruction(instruction ins)
140 {
141     return false;
142 }
143 bool IsThreeOperandMoveAVXInstruction(instruction ins)
144 {
145     return false;
146 }
147 bool IsThreeOperandAVXInstruction(instruction ins)
148 {
149     return false;
150 }
151 bool TakesVexPrefix(instruction ins)
152 {
153     return false;
154 }
155 size_t AddVexPrefixIfNeeded(instruction ins, size_t code, emitAttr attr)
156 {
157     return code;
158 }
159 size_t AddVexPrefixIfNeededAndNotPresent(instruction ins, size_t code, emitAttr size)
160 {
161     return code;
162 }
163 #endif // !FEATURE_AVX_SUPPORT
164
165 /************************************************************************/
166 /*             Debug-only routines to display instructions              */
167 /************************************************************************/
168
169 #ifdef DEBUG
170
171 const char* emitFPregName(unsigned reg, bool varName = true);
172
173 void emitDispReloc(ssize_t value);
174 void emitDispAddrMode(instrDesc* id, bool noDetail = false);
175 void emitDispShift(instruction ins, int cnt = 0);
176
177 void emitDispIns(instrDesc* id,
178                  bool       isNew,
179                  bool       doffs,
180                  bool       asmfm,
181                  unsigned   offs = 0,
182                  BYTE*      code = nullptr,
183                  size_t     sz   = 0,
184                  insGroup*  ig   = nullptr);
185
186 const char* emitXMMregName(unsigned reg);
187 const char* emitYMMregName(unsigned reg);
188
189 #endif
190
191 /************************************************************************/
192 /*  Private members that deal with target-dependent instr. descriptors  */
193 /************************************************************************/
194
195 private:
196 void emitSetAmdDisp(instrDescAmd* id, ssize_t dsp);
197 instrDesc* emitNewInstrAmd(emitAttr attr, ssize_t dsp);
198 instrDesc* emitNewInstrAmdCns(emitAttr attr, ssize_t dsp, int cns);
199
200 instrDesc* emitNewInstrCallDir(int              argCnt,
201                                VARSET_VALARG_TP GCvars,
202                                regMaskTP        gcrefRegs,
203                                regMaskTP        byrefRegs,
204                                emitAttr retSize MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize));
205
206 instrDesc* emitNewInstrCallInd(int              argCnt,
207                                ssize_t          disp,
208                                VARSET_VALARG_TP GCvars,
209                                regMaskTP        gcrefRegs,
210                                regMaskTP        byrefRegs,
211                                emitAttr retSize MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize));
212
213 void emitGetInsCns(instrDesc* id, CnsVal* cv);
214 ssize_t emitGetInsAmdCns(instrDesc* id, CnsVal* cv);
215 void emitGetInsDcmCns(instrDesc* id, CnsVal* cv);
216 ssize_t emitGetInsAmdAny(instrDesc* id);
217
218 /************************************************************************/
219 /*               Private helpers for instruction output                 */
220 /************************************************************************/
221
222 private:
223 insFormat emitInsModeFormat(instruction ins, insFormat base, insFormat FPld, insFormat FPst);
224
225 bool emitVerifyEncodable(instruction ins, emitAttr size, regNumber reg1, regNumber reg2 = REG_NA);
226
227 bool emitInsCanOnlyWriteSSE2OrAVXReg(instrDesc* id);
228
229 /*****************************************************************************
230 *
231 *  Convert between an index scale in bytes to a smaller encoding used for
232 *  storage in instruction descriptors.
233 */
234
235 inline emitter::opSize emitEncodeScale(size_t scale)
236 {
237     assert(scale == 1 || scale == 2 || scale == 4 || scale == 8);
238
239     return emitSizeEncode[scale - 1];
240 }
241
242 inline emitAttr emitDecodeScale(unsigned ensz)
243 {
244     assert(ensz < 4);
245
246     return emitter::emitSizeDecode[ensz];
247 }
248
249 /************************************************************************/
250 /*           The public entry points to output instructions             */
251 /************************************************************************/
252
253 public:
254 void emitLoopAlign();
255
256 void emitIns(instruction ins);
257
258 void emitIns(instruction ins, emitAttr attr);
259
260 void emitInsRMW(instruction inst, emitAttr attr, GenTreeStoreInd* storeInd, GenTreePtr src);
261
262 void emitInsRMW(instruction inst, emitAttr attr, GenTreeStoreInd* storeInd);
263
264 void emitIns_Nop(unsigned size);
265
266 void emitIns_I(instruction ins, emitAttr attr, int val);
267
268 void emitIns_R(instruction ins, emitAttr attr, regNumber reg);
269
270 void emitIns_C(instruction ins, emitAttr attr, CORINFO_FIELD_HANDLE fdlHnd, int offs);
271
272 void emitIns_R_I(instruction ins, emitAttr attr, regNumber reg, ssize_t val);
273
274 void emitIns_R_R(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2);
275
276 void emitIns_R_R_I(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, int ival);
277
278 #ifdef FEATURE_AVX_SUPPORT
279 void emitIns_R_R_R(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, regNumber reg3);
280 #endif
281
282 void emitIns_S(instruction ins, emitAttr attr, int varx, int offs);
283
284 void emitIns_S_R(instruction ins, emitAttr attr, regNumber ireg, int varx, int offs);
285
286 void emitIns_R_S(instruction ins, emitAttr attr, regNumber ireg, int varx, int offs);
287
288 void emitIns_S_I(instruction ins, emitAttr attr, int varx, int offs, int val);
289
290 void emitIns_R_C(instruction ins, emitAttr attr, regNumber reg, CORINFO_FIELD_HANDLE fldHnd, int offs);
291
292 void emitIns_C_R(instruction ins, emitAttr attr, CORINFO_FIELD_HANDLE fldHnd, regNumber reg, int offs);
293
294 void emitIns_C_I(instruction ins, emitAttr attr, CORINFO_FIELD_HANDLE fdlHnd, int offs, int val);
295
296 void emitIns_IJ(emitAttr attr, regNumber reg, unsigned base);
297
298 void emitIns_J_S(instruction ins, emitAttr attr, BasicBlock* dst, int varx, int offs);
299
300 void emitIns_R_L(instruction ins, emitAttr attr, BasicBlock* dst, regNumber reg);
301
302 void emitIns_R_D(instruction ins, emitAttr attr, unsigned offs, regNumber reg);
303
304 void emitIns_I_AR(
305     instruction ins, emitAttr attr, int val, regNumber reg, int offs, int memCookie = 0, void* clsCookie = nullptr);
306
307 void emitIns_I_AI(instruction ins, emitAttr attr, int val, ssize_t disp);
308
309 void emitIns_R_AR(instruction ins,
310                   emitAttr    attr,
311                   regNumber   ireg,
312                   regNumber   reg,
313                   int         offs,
314                   int         memCookie = 0,
315                   void*       clsCookie = nullptr);
316
317 void emitIns_R_AI(instruction ins, emitAttr attr, regNumber ireg, ssize_t disp);
318
319 void emitIns_AR_R(instruction ins,
320                   emitAttr    attr,
321                   regNumber   ireg,
322                   regNumber   reg,
323                   int         offs,
324                   int         memCookie = 0,
325                   void*       clsCookie = nullptr);
326
327 void emitIns_AI_R(instruction ins, emitAttr attr, regNumber ireg, ssize_t disp);
328
329 void emitIns_I_ARR(instruction ins, emitAttr attr, int val, regNumber reg, regNumber rg2, int disp);
330
331 void emitIns_R_ARR(instruction ins, emitAttr attr, regNumber ireg, regNumber reg, regNumber rg2, int disp);
332
333 void emitIns_ARR_R(instruction ins, emitAttr attr, regNumber ireg, regNumber reg, regNumber rg2, int disp);
334
335 void emitIns_I_ARX(instruction ins, emitAttr attr, int val, regNumber reg, regNumber rg2, unsigned mul, int disp);
336
337 void emitIns_R_ARX(
338     instruction ins, emitAttr attr, regNumber ireg, regNumber reg, regNumber rg2, unsigned mul, int disp);
339
340 void emitIns_ARX_R(
341     instruction ins, emitAttr attr, regNumber ireg, regNumber reg, regNumber rg2, unsigned mul, int disp);
342
343 void emitIns_I_AX(instruction ins, emitAttr attr, int val, regNumber reg, unsigned mul, int disp);
344
345 void emitIns_R_AX(instruction ins, emitAttr attr, regNumber ireg, regNumber reg, unsigned mul, int disp);
346
347 void emitIns_AX_R(instruction ins, emitAttr attr, regNumber ireg, regNumber reg, unsigned mul, int disp);
348
349 #if FEATURE_STACK_FP_X87
350 void emitIns_F_F0(instruction ins, unsigned fpreg);
351
352 void emitIns_F0_F(instruction ins, unsigned fpreg);
353 #endif // FEATURE_STACK_FP_X87
354
355 enum EmitCallType
356 {
357     EC_FUNC_TOKEN,       //   Direct call to a helper/static/nonvirtual/global method
358     EC_FUNC_TOKEN_INDIR, // Indirect call to a helper/static/nonvirtual/global method
359     EC_FUNC_ADDR,        // Direct call to an absolute address
360
361     EC_FUNC_VIRTUAL, // Call to a virtual method (using the vtable)
362     EC_INDIR_R,      // Indirect call via register
363     EC_INDIR_SR,     // Indirect call via stack-reference (local var)
364     EC_INDIR_C,      // Indirect call via static class var
365     EC_INDIR_ARD,    // Indirect call via an addressing mode
366
367     EC_COUNT
368 };
369
370 void emitIns_Call(EmitCallType          callType,
371                   CORINFO_METHOD_HANDLE methHnd,
372                   CORINFO_SIG_INFO*     sigInfo, // used to report call sites to the EE
373                   void*                 addr,
374                   ssize_t               argSize,
375                   emitAttr retSize MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize),
376                   VARSET_VALARG_TP ptrVars,
377                   regMaskTP        gcrefRegs,
378                   regMaskTP        byrefRegs,
379                   GenTreeIndir*    indir,
380                   bool             isJump = false,
381                   bool             isNoGC = false);
382
383 void emitIns_Call(EmitCallType          callType,
384                   CORINFO_METHOD_HANDLE methHnd,
385                   INDEBUG_LDISASM_COMMA(CORINFO_SIG_INFO* sigInfo) // used to report call sites to the EE
386                   void*    addr,
387                   ssize_t  argSize,
388                   emitAttr retSize MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize),
389                   VARSET_VALARG_TP ptrVars,
390                   regMaskTP        gcrefRegs,
391                   regMaskTP        byrefRegs,
392                   IL_OFFSETX       ilOffset = BAD_IL_OFFSET,
393                   regNumber        ireg     = REG_NA,
394                   regNumber        xreg     = REG_NA,
395                   unsigned         xmul     = 0,
396                   ssize_t          disp     = 0,
397                   bool             isJump   = false,
398                   bool             isNoGC   = false);
399
400 #ifdef _TARGET_AMD64_
401 // Is the last instruction emitted a call instruction?
402 bool emitIsLastInsCall();
403
404 // Insert a NOP at the end of the the current instruction group if the last emitted instruction was a 'call',
405 // because the next instruction group will be an epilog.
406 void emitOutputPreEpilogNOP();
407 #endif // _TARGET_AMD64_
408
409 /*****************************************************************************
410  *
411  *  Given a jump, return true if it's a conditional jump.
412  */
413
414 inline bool emitIsCondJump(instrDesc* jmp)
415 {
416     instruction ins = jmp->idIns();
417
418     assert(jmp->idInsFmt() == IF_LABEL);
419
420     return (ins != INS_call && ins != INS_jmp);
421 }
422
423 /*****************************************************************************
424  *
425  *  Given a jump, return true if it's an unconditional jump.
426  */
427
428 inline bool emitIsUncondJump(instrDesc* jmp)
429 {
430     instruction ins = jmp->idIns();
431
432     assert(jmp->idInsFmt() == IF_LABEL);
433
434     return (ins == INS_jmp);
435 }
436
437 #endif // _TARGET_XARCH_