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 | // code_t is a type used to accumulate bits of opcode + prefixes. On amd64, it must be 64 bits |
32 | // to support the REX prefixes. On both x86 and amd64, it must be 64 bits to support AVX, with |
33 | // its 3-byte VEX prefix. |
34 | typedef unsigned __int64 code_t; |
35 | |
36 | struct CnsVal |
37 | { |
38 | ssize_t cnsVal; |
39 | bool cnsReloc; |
40 | }; |
41 | |
42 | UNATIVE_OFFSET emitInsSize(code_t code); |
43 | UNATIVE_OFFSET emitInsSizeRM(instruction ins); |
44 | UNATIVE_OFFSET emitInsSizeSV(code_t code, int var, int dsp); |
45 | UNATIVE_OFFSET emitInsSizeSV(instrDesc* id, code_t code, int var, int dsp); |
46 | UNATIVE_OFFSET emitInsSizeSV(instrDesc* id, code_t code, int var, int dsp, int val); |
47 | UNATIVE_OFFSET emitInsSizeRR(instruction ins, regNumber reg1, regNumber reg2, emitAttr attr); |
48 | UNATIVE_OFFSET emitInsSizeAM(instrDesc* id, code_t code); |
49 | UNATIVE_OFFSET emitInsSizeAM(instrDesc* id, code_t code, int val); |
50 | UNATIVE_OFFSET emitInsSizeCV(instrDesc* id, code_t code); |
51 | UNATIVE_OFFSET emitInsSizeCV(instrDesc* id, code_t code, int val); |
52 | |
53 | BYTE* emitOutputAM(BYTE* dst, instrDesc* id, code_t code, CnsVal* addc = nullptr); |
54 | BYTE* emitOutputSV(BYTE* dst, instrDesc* id, code_t code, CnsVal* addc = nullptr); |
55 | BYTE* emitOutputCV(BYTE* dst, instrDesc* id, code_t code, CnsVal* addc = nullptr); |
56 | |
57 | BYTE* emitOutputR(BYTE* dst, instrDesc* id); |
58 | BYTE* emitOutputRI(BYTE* dst, instrDesc* id); |
59 | BYTE* emitOutputRR(BYTE* dst, instrDesc* id); |
60 | BYTE* emitOutputIV(BYTE* dst, instrDesc* id); |
61 | |
62 | BYTE* emitOutputRRR(BYTE* dst, instrDesc* id); |
63 | |
64 | BYTE* emitOutputLJ(BYTE* dst, instrDesc* id); |
65 | |
66 | unsigned emitOutputRexOrVexPrefixIfNeeded(instruction ins, BYTE* dst, code_t& code); |
67 | unsigned emitGetRexPrefixSize(instruction ins); |
68 | unsigned emitGetVexPrefixSize(instruction ins, emitAttr attr); |
69 | unsigned emitGetPrefixSize(code_t code); |
70 | unsigned emitGetVexPrefixAdjustedSize(instruction ins, emitAttr attr, code_t code); |
71 | |
72 | unsigned insEncodeReg012(instruction ins, regNumber reg, emitAttr size, code_t* code); |
73 | unsigned insEncodeReg345(instruction ins, regNumber reg, emitAttr size, code_t* code); |
74 | code_t insEncodeReg3456(instruction ins, regNumber reg, emitAttr size, code_t code); |
75 | unsigned insEncodeRegSIB(instruction ins, regNumber reg, code_t* code); |
76 | |
77 | code_t insEncodeMRreg(instruction ins, code_t code); |
78 | code_t insEncodeRMreg(instruction ins, code_t code); |
79 | code_t insEncodeMRreg(instruction ins, regNumber reg, emitAttr size, code_t code); |
80 | code_t insEncodeRRIb(instruction ins, regNumber reg, emitAttr size); |
81 | code_t insEncodeOpreg(instruction ins, regNumber reg, emitAttr size); |
82 | |
83 | unsigned insSSval(unsigned scale); |
84 | |
85 | bool IsAVXInstruction(instruction ins); |
86 | code_t insEncodeMIreg(instruction ins, regNumber reg, emitAttr size, code_t code); |
87 | |
88 | code_t AddRexWPrefix(instruction ins, code_t code); |
89 | code_t AddRexRPrefix(instruction ins, code_t code); |
90 | code_t AddRexXPrefix(instruction ins, code_t code); |
91 | code_t AddRexBPrefix(instruction ins, code_t code); |
92 | code_t AddRexPrefix(instruction ins, code_t code); |
93 | |
94 | bool (instruction ins); |
95 | bool Is4ByteSSEInstruction(instruction ins); |
96 | |
97 | bool hasRexPrefix(code_t code) |
98 | { |
99 | #ifdef _TARGET_AMD64_ |
100 | const code_t REX_PREFIX_MASK = 0xFF00000000LL; |
101 | return (code & REX_PREFIX_MASK) != 0; |
102 | #else // !_TARGET_AMD64_ |
103 | return false; |
104 | #endif // !_TARGET_AMD64_ |
105 | } |
106 | |
107 | // 3-byte VEX prefix starts with byte 0xC4 |
108 | #define VEX_PREFIX_MASK_3BYTE 0xFF000000000000ULL |
109 | #define VEX_PREFIX_CODE_3BYTE 0xC4000000000000ULL |
110 | |
111 | bool TakesVexPrefix(instruction ins); |
112 | |
113 | // Returns true if the instruction encoding already contains VEX prefix |
114 | bool hasVexPrefix(code_t code) |
115 | { |
116 | return (code & VEX_PREFIX_MASK_3BYTE) == VEX_PREFIX_CODE_3BYTE; |
117 | } |
118 | code_t AddVexPrefix(instruction ins, code_t code, emitAttr attr); |
119 | code_t AddVexPrefixIfNeeded(instruction ins, code_t code, emitAttr size) |
120 | { |
121 | if (TakesVexPrefix(ins)) |
122 | { |
123 | code = AddVexPrefix(ins, code, size); |
124 | } |
125 | return code; |
126 | } |
127 | code_t AddVexPrefixIfNeededAndNotPresent(instruction ins, code_t code, emitAttr size) |
128 | { |
129 | if (TakesVexPrefix(ins) && !hasVexPrefix(code)) |
130 | { |
131 | code = AddVexPrefix(ins, code, size); |
132 | } |
133 | return code; |
134 | } |
135 | |
136 | bool useVEXEncodings; |
137 | bool UseVEXEncoding() |
138 | { |
139 | return useVEXEncodings; |
140 | } |
141 | void SetUseVEXEncoding(bool value) |
142 | { |
143 | useVEXEncodings = value; |
144 | } |
145 | |
146 | bool containsAVXInstruction = false; |
147 | bool ContainsAVX() |
148 | { |
149 | return containsAVXInstruction; |
150 | } |
151 | void SetContainsAVX(bool value) |
152 | { |
153 | containsAVXInstruction = value; |
154 | } |
155 | |
156 | bool contains256bitAVXInstruction = false; |
157 | bool Contains256bitAVX() |
158 | { |
159 | return contains256bitAVXInstruction; |
160 | } |
161 | void SetContains256bitAVX(bool value) |
162 | { |
163 | contains256bitAVXInstruction = value; |
164 | } |
165 | |
166 | bool IsDstDstSrcAVXInstruction(instruction ins); |
167 | bool IsDstSrcSrcAVXInstruction(instruction ins); |
168 | bool IsThreeOperandAVXInstruction(instruction ins) |
169 | { |
170 | return (IsDstDstSrcAVXInstruction(ins) || IsDstSrcSrcAVXInstruction(ins)); |
171 | } |
172 | bool isAvxBlendv(instruction ins) |
173 | { |
174 | return ins == INS_vblendvps || ins == INS_vblendvpd || ins == INS_vpblendvb; |
175 | } |
176 | bool isSse41Blendv(instruction ins) |
177 | { |
178 | return ins == INS_blendvps || ins == INS_blendvpd || ins == INS_pblendvb; |
179 | } |
180 | bool isPrefetch(instruction ins) |
181 | { |
182 | return (ins == INS_prefetcht0) || (ins == INS_prefetcht1) || (ins == INS_prefetcht2) || (ins == INS_prefetchnta); |
183 | } |
184 | |
185 | /************************************************************************/ |
186 | /* Debug-only routines to display instructions */ |
187 | /************************************************************************/ |
188 | |
189 | #ifdef DEBUG |
190 | |
191 | const char* emitFPregName(unsigned reg, bool varName = true); |
192 | |
193 | void emitDispReloc(ssize_t value); |
194 | void emitDispAddrMode(instrDesc* id, bool noDetail = false); |
195 | void emitDispShift(instruction ins, int cnt = 0); |
196 | |
197 | void emitDispIns(instrDesc* id, |
198 | bool isNew, |
199 | bool doffs, |
200 | bool asmfm, |
201 | unsigned offs = 0, |
202 | BYTE* code = nullptr, |
203 | size_t sz = 0, |
204 | insGroup* ig = nullptr); |
205 | |
206 | const char* emitXMMregName(unsigned reg); |
207 | const char* emitYMMregName(unsigned reg); |
208 | |
209 | #endif |
210 | |
211 | /************************************************************************/ |
212 | /* Private members that deal with target-dependent instr. descriptors */ |
213 | /************************************************************************/ |
214 | |
215 | private: |
216 | void emitSetAmdDisp(instrDescAmd* id, ssize_t dsp); |
217 | instrDesc* emitNewInstrAmd(emitAttr attr, ssize_t dsp); |
218 | instrDesc* emitNewInstrAmdCns(emitAttr attr, ssize_t dsp, int cns); |
219 | |
220 | instrDesc* emitNewInstrCallDir(int argCnt, |
221 | VARSET_VALARG_TP GCvars, |
222 | regMaskTP gcrefRegs, |
223 | regMaskTP byrefRegs, |
224 | emitAttr retSize MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize)); |
225 | |
226 | instrDesc* emitNewInstrCallInd(int argCnt, |
227 | ssize_t disp, |
228 | VARSET_VALARG_TP GCvars, |
229 | regMaskTP gcrefRegs, |
230 | regMaskTP byrefRegs, |
231 | emitAttr retSize MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize)); |
232 | |
233 | void emitGetInsCns(instrDesc* id, CnsVal* cv); |
234 | ssize_t emitGetInsAmdCns(instrDesc* id, CnsVal* cv); |
235 | void emitGetInsDcmCns(instrDesc* id, CnsVal* cv); |
236 | ssize_t emitGetInsAmdAny(instrDesc* id); |
237 | |
238 | /************************************************************************/ |
239 | /* Private helpers for instruction output */ |
240 | /************************************************************************/ |
241 | |
242 | private: |
243 | insFormat emitInsModeFormat(instruction ins, insFormat base, insFormat FPld, insFormat FPst); |
244 | |
245 | bool emitVerifyEncodable(instruction ins, emitAttr size, regNumber reg1, regNumber reg2 = REG_NA); |
246 | |
247 | bool emitInsCanOnlyWriteSSE2OrAVXReg(instrDesc* id); |
248 | |
249 | #if FEATURE_FIXED_OUT_ARGS |
250 | void emitAdjustStackDepthPushPop(instruction ins) |
251 | { |
252 | } |
253 | void emitAdjustStackDepth(instruction ins, ssize_t val) |
254 | { |
255 | } |
256 | #else // !FEATURE_FIXED_OUT_ARGS |
257 | void emitAdjustStackDepthPushPop(instruction ins); |
258 | void emitAdjustStackDepth(instruction ins, ssize_t val); |
259 | #endif // !FEATURE_FIXED_OUT_ARGS |
260 | |
261 | /***************************************************************************** |
262 | * |
263 | * Convert between an index scale in bytes to a smaller encoding used for |
264 | * storage in instruction descriptors. |
265 | */ |
266 | |
267 | inline emitter::opSize emitEncodeScale(size_t scale) |
268 | { |
269 | assert(scale == 1 || scale == 2 || scale == 4 || scale == 8); |
270 | |
271 | return emitSizeEncode[scale - 1]; |
272 | } |
273 | |
274 | inline emitAttr emitDecodeScale(unsigned ensz) |
275 | { |
276 | assert(ensz < 4); |
277 | |
278 | return emitter::emitSizeDecode[ensz]; |
279 | } |
280 | |
281 | /************************************************************************/ |
282 | /* The public entry points to output instructions */ |
283 | /************************************************************************/ |
284 | |
285 | public: |
286 | void emitLoopAlign(); |
287 | |
288 | void emitIns(instruction ins); |
289 | |
290 | void emitIns(instruction ins, emitAttr attr); |
291 | |
292 | void emitInsRMW(instruction inst, emitAttr attr, GenTreeStoreInd* storeInd, GenTree* src); |
293 | |
294 | void emitInsRMW(instruction inst, emitAttr attr, GenTreeStoreInd* storeInd); |
295 | |
296 | void emitIns_Nop(unsigned size); |
297 | |
298 | void emitIns_I(instruction ins, emitAttr attr, int val); |
299 | |
300 | void emitIns_R(instruction ins, emitAttr attr, regNumber reg); |
301 | |
302 | void emitIns_C(instruction ins, emitAttr attr, CORINFO_FIELD_HANDLE fdlHnd, int offs); |
303 | |
304 | void emitIns_R_I(instruction ins, emitAttr attr, regNumber reg, ssize_t val); |
305 | |
306 | void emitIns_R_R(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2); |
307 | |
308 | void emitIns_R_R_I(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, int ival); |
309 | |
310 | void emitIns_AR(instruction ins, emitAttr attr, regNumber base, int offs); |
311 | |
312 | void emitIns_AR_R_R(instruction ins, emitAttr attr, regNumber op2Reg, regNumber op3Reg, regNumber base, int offs); |
313 | |
314 | void emitIns_R_A(instruction ins, emitAttr attr, regNumber reg1, GenTreeIndir* indir); |
315 | |
316 | void emitIns_R_A_I(instruction ins, emitAttr attr, regNumber reg1, GenTreeIndir* indir, int ival); |
317 | |
318 | void emitIns_R_AR_I(instruction ins, emitAttr attr, regNumber reg1, regNumber base, int offs, int ival); |
319 | |
320 | void emitIns_R_C_I(instruction ins, emitAttr attr, regNumber reg1, CORINFO_FIELD_HANDLE fldHnd, int offs, int ival); |
321 | |
322 | void emitIns_R_S_I(instruction ins, emitAttr attr, regNumber reg1, int varx, int offs, int ival); |
323 | |
324 | void emitIns_R_R_A(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, GenTreeIndir* indir); |
325 | |
326 | void emitIns_R_R_AR(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, regNumber base, int offs); |
327 | |
328 | void emitIns_R_AR_R(instruction ins, |
329 | emitAttr attr, |
330 | regNumber reg1, |
331 | regNumber reg2, |
332 | regNumber base, |
333 | regNumber index, |
334 | int scale, |
335 | int offs); |
336 | |
337 | void emitIns_R_R_C( |
338 | instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, CORINFO_FIELD_HANDLE fldHnd, int offs); |
339 | |
340 | void emitIns_R_R_S(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, int varx, int offs); |
341 | |
342 | void emitIns_R_R_R(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, regNumber reg3); |
343 | |
344 | void emitIns_R_R_A_I( |
345 | instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, GenTreeIndir* indir, int ival, insFormat fmt); |
346 | void emitIns_R_R_AR_I( |
347 | instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, regNumber base, int offs, int ival); |
348 | void emitIns_AR_R_I(instruction ins, emitAttr attr, regNumber base, int disp, regNumber ireg, int ival); |
349 | |
350 | void emitIns_R_R_C_I( |
351 | instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, CORINFO_FIELD_HANDLE fldHnd, int offs, int ival); |
352 | |
353 | void emitIns_R_R_R_I(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, regNumber reg3, int ival); |
354 | |
355 | void emitIns_R_R_S_I(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, int varx, int offs, int ival); |
356 | |
357 | void emitIns_R_R_A_R( |
358 | instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, regNumber op3Reg, GenTreeIndir* indir); |
359 | |
360 | void emitIns_R_R_AR_R( |
361 | instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, regNumber op3Reg, regNumber base, int offs); |
362 | |
363 | void emitIns_R_R_C_R(instruction ins, |
364 | emitAttr attr, |
365 | regNumber targetReg, |
366 | regNumber op1Reg, |
367 | regNumber op3Reg, |
368 | CORINFO_FIELD_HANDLE fldHnd, |
369 | int offs); |
370 | |
371 | void emitIns_R_R_S_R( |
372 | instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, regNumber op3Reg, int varx, int offs); |
373 | |
374 | void emitIns_R_R_R_R(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, regNumber reg3, regNumber reg4); |
375 | |
376 | void emitIns_S(instruction ins, emitAttr attr, int varx, int offs); |
377 | |
378 | void emitIns_S_R(instruction ins, emitAttr attr, regNumber ireg, int varx, int offs); |
379 | |
380 | void emitIns_R_S(instruction ins, emitAttr attr, regNumber ireg, int varx, int offs); |
381 | |
382 | void emitIns_S_I(instruction ins, emitAttr attr, int varx, int offs, int val); |
383 | |
384 | void emitIns_R_C(instruction ins, emitAttr attr, regNumber reg, CORINFO_FIELD_HANDLE fldHnd, int offs); |
385 | |
386 | void emitIns_C_R(instruction ins, emitAttr attr, CORINFO_FIELD_HANDLE fldHnd, regNumber reg, int offs); |
387 | |
388 | void emitIns_C_I(instruction ins, emitAttr attr, CORINFO_FIELD_HANDLE fdlHnd, int offs, int val); |
389 | |
390 | void emitIns_IJ(emitAttr attr, regNumber reg, unsigned base); |
391 | |
392 | void emitIns_J_S(instruction ins, emitAttr attr, BasicBlock* dst, int varx, int offs); |
393 | |
394 | void emitIns_R_L(instruction ins, emitAttr attr, BasicBlock* dst, regNumber reg); |
395 | |
396 | void emitIns_R_D(instruction ins, emitAttr attr, unsigned offs, regNumber reg); |
397 | |
398 | void emitIns_I_AR(instruction ins, emitAttr attr, int val, regNumber reg, int offs); |
399 | |
400 | void emitIns_I_AI(instruction ins, emitAttr attr, int val, ssize_t disp); |
401 | |
402 | void emitIns_R_AR(instruction ins, emitAttr attr, regNumber ireg, regNumber reg, int offs); |
403 | |
404 | void emitIns_R_AI(instruction ins, emitAttr attr, regNumber ireg, ssize_t disp); |
405 | |
406 | void emitIns_AR_R(instruction ins, emitAttr attr, regNumber ireg, regNumber reg, int offs); |
407 | |
408 | void emitIns_AI_R(instruction ins, emitAttr attr, regNumber ireg, ssize_t disp); |
409 | |
410 | void emitIns_I_ARR(instruction ins, emitAttr attr, int val, regNumber reg, regNumber rg2, int disp); |
411 | |
412 | void emitIns_R_ARR(instruction ins, emitAttr attr, regNumber ireg, regNumber reg, regNumber rg2, int disp); |
413 | |
414 | void emitIns_ARR_R(instruction ins, emitAttr attr, regNumber ireg, regNumber reg, regNumber rg2, int disp); |
415 | |
416 | void emitIns_I_ARX(instruction ins, emitAttr attr, int val, regNumber reg, regNumber rg2, unsigned mul, int disp); |
417 | |
418 | void emitIns_R_ARX( |
419 | instruction ins, emitAttr attr, regNumber ireg, regNumber reg, regNumber rg2, unsigned mul, int disp); |
420 | |
421 | void emitIns_ARX_R( |
422 | instruction ins, emitAttr attr, regNumber ireg, regNumber reg, regNumber rg2, unsigned mul, int disp); |
423 | |
424 | void emitIns_I_AX(instruction ins, emitAttr attr, int val, regNumber reg, unsigned mul, int disp); |
425 | |
426 | void emitIns_R_AX(instruction ins, emitAttr attr, regNumber ireg, regNumber reg, unsigned mul, int disp); |
427 | |
428 | void emitIns_AX_R(instruction ins, emitAttr attr, regNumber ireg, regNumber reg, unsigned mul, int disp); |
429 | |
430 | #ifdef FEATURE_HW_INTRINSICS |
431 | void emitIns_SIMD_R_R_I(instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, int ival); |
432 | |
433 | void emitIns_SIMD_R_R_A(instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, GenTreeIndir* indir); |
434 | void emitIns_SIMD_R_R_AR(instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, regNumber base); |
435 | void emitIns_SIMD_R_R_C( |
436 | instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, CORINFO_FIELD_HANDLE fldHnd, int offs); |
437 | void emitIns_SIMD_R_R_R(instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, regNumber op2Reg); |
438 | void emitIns_SIMD_R_R_S(instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, int varx, int offs); |
439 | |
440 | void emitIns_SIMD_R_R_A_I( |
441 | instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, GenTreeIndir* indir, int ival); |
442 | void emitIns_SIMD_R_R_AR_I( |
443 | instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, regNumber base, int ival); |
444 | void emitIns_SIMD_R_R_C_I(instruction ins, |
445 | emitAttr attr, |
446 | regNumber targetReg, |
447 | regNumber op1Reg, |
448 | CORINFO_FIELD_HANDLE fldHnd, |
449 | int offs, |
450 | int ival); |
451 | void emitIns_SIMD_R_R_R_I( |
452 | instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, regNumber op2Reg, int ival); |
453 | void emitIns_SIMD_R_R_S_I( |
454 | instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, int varx, int offs, int ival); |
455 | |
456 | void emitIns_SIMD_R_R_R_A( |
457 | instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, regNumber op2Reg, GenTreeIndir* indir); |
458 | void emitIns_SIMD_R_R_R_AR( |
459 | instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, regNumber op2Reg, regNumber base); |
460 | void emitIns_SIMD_R_R_R_C(instruction ins, |
461 | emitAttr attr, |
462 | regNumber targetReg, |
463 | regNumber op1Reg, |
464 | regNumber op2Reg, |
465 | CORINFO_FIELD_HANDLE fldHnd, |
466 | int offs); |
467 | void emitIns_SIMD_R_R_R_R( |
468 | instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, regNumber op2Reg, regNumber op3Reg); |
469 | void emitIns_SIMD_R_R_R_S( |
470 | instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, regNumber op2Reg, int varx, int offs); |
471 | |
472 | void emitIns_SIMD_R_R_A_R( |
473 | instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, regNumber op2Reg, GenTreeIndir* indir); |
474 | void emitIns_SIMD_R_R_AR_R( |
475 | instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, regNumber op2Reg, regNumber base); |
476 | void emitIns_SIMD_R_R_C_R(instruction ins, |
477 | emitAttr attr, |
478 | regNumber targetReg, |
479 | regNumber op1Reg, |
480 | regNumber op2Reg, |
481 | CORINFO_FIELD_HANDLE fldHnd, |
482 | int offs); |
483 | void emitIns_SIMD_R_R_S_R( |
484 | instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, regNumber op2Reg, int varx, int offs); |
485 | #endif // FEATURE_HW_INTRINSICS |
486 | |
487 | enum EmitCallType |
488 | { |
489 | EC_FUNC_TOKEN, // Direct call to a helper/static/nonvirtual/global method |
490 | EC_FUNC_TOKEN_INDIR, // Indirect call to a helper/static/nonvirtual/global method |
491 | EC_FUNC_ADDR, // Direct call to an absolute address |
492 | |
493 | EC_FUNC_VIRTUAL, // Call to a virtual method (using the vtable) |
494 | EC_INDIR_R, // Indirect call via register |
495 | EC_INDIR_SR, // Indirect call via stack-reference (local var) |
496 | EC_INDIR_C, // Indirect call via static class var |
497 | EC_INDIR_ARD, // Indirect call via an addressing mode |
498 | |
499 | EC_COUNT |
500 | }; |
501 | |
502 | // clang-format off |
503 | void emitIns_Call(EmitCallType callType, |
504 | CORINFO_METHOD_HANDLE methHnd, |
505 | INDEBUG_LDISASM_COMMA(CORINFO_SIG_INFO* sigInfo) // used to report call sites to the EE |
506 | void* addr, |
507 | ssize_t argSize, |
508 | emitAttr retSize |
509 | MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize), |
510 | VARSET_VALARG_TP ptrVars, |
511 | regMaskTP gcrefRegs, |
512 | regMaskTP byrefRegs, |
513 | IL_OFFSETX ilOffset = BAD_IL_OFFSET, |
514 | regNumber ireg = REG_NA, |
515 | regNumber xreg = REG_NA, |
516 | unsigned xmul = 0, |
517 | ssize_t disp = 0, |
518 | bool isJump = false); |
519 | // clang-format on |
520 | |
521 | #ifdef _TARGET_AMD64_ |
522 | // Is the last instruction emitted a call instruction? |
523 | bool emitIsLastInsCall(); |
524 | |
525 | // Insert a NOP at the end of the the current instruction group if the last emitted instruction was a 'call', |
526 | // because the next instruction group will be an epilog. |
527 | void emitOutputPreEpilogNOP(); |
528 | #endif // _TARGET_AMD64_ |
529 | |
530 | /***************************************************************************** |
531 | * |
532 | * Given a jump, return true if it's a conditional jump. |
533 | */ |
534 | |
535 | inline bool emitIsCondJump(instrDesc* jmp) |
536 | { |
537 | instruction ins = jmp->idIns(); |
538 | |
539 | assert(jmp->idInsFmt() == IF_LABEL); |
540 | |
541 | return (ins != INS_call && ins != INS_jmp); |
542 | } |
543 | |
544 | /***************************************************************************** |
545 | * |
546 | * Given a jump, return true if it's an unconditional jump. |
547 | */ |
548 | |
549 | inline bool emitIsUncondJump(instrDesc* jmp) |
550 | { |
551 | instruction ins = jmp->idIns(); |
552 | |
553 | assert(jmp->idInsFmt() == IF_LABEL); |
554 | |
555 | return (ins == INS_jmp); |
556 | } |
557 | |
558 | #endif // _TARGET_XARCH_ |
559 | |