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
6#ifndef _EMITINL_H_
7#define _EMITINL_H_
8/*****************************************************************************/
9/*****************************************************************************
10 *
11 * Return the number of bytes of machine code the given instruction will
12 * produce.
13 */
14
15inline UNATIVE_OFFSET emitter::emitInstCodeSz(instrDesc* id)
16{
17 return id->idCodeSize();
18}
19
20inline UNATIVE_OFFSET emitter::emitSizeOfJump(instrDescJmp* jmp)
21{
22 return jmp->idCodeSize();
23}
24
25#ifdef _TARGET_XARCH_
26
27/* static */
28inline bool emitter::instrIs3opImul(instruction ins)
29{
30#ifdef _TARGET_X86_
31 return ((ins >= INS_imul_AX) && (ins <= INS_imul_DI));
32#else // _TARGET_AMD64
33 return ((ins >= INS_imul_AX) && (ins <= INS_imul_15));
34#endif
35}
36
37/* static */
38inline bool emitter::instrIsExtendedReg3opImul(instruction ins)
39{
40#ifdef _TARGET_X86_
41 return false;
42#else // _TARGET_AMD64
43 return ((ins >= INS_imul_08) && (ins <= INS_imul_15));
44#endif
45}
46
47/* static */
48inline bool emitter::instrHasImplicitRegPairDest(instruction ins)
49{
50 return (ins == INS_mulEAX) || (ins == INS_imulEAX) || (ins == INS_div) || (ins == INS_idiv);
51}
52
53// Because we don't actually have support for encoding these 3-op
54// multiplies we fake it with special opcodes. Make sure they are
55// contiguous.
56/* static */
57inline void emitter::check3opImulValues()
58{
59 assert(INS_imul_AX - INS_imul_AX == REG_EAX);
60 assert(INS_imul_BX - INS_imul_AX == REG_EBX);
61 assert(INS_imul_CX - INS_imul_AX == REG_ECX);
62 assert(INS_imul_DX - INS_imul_AX == REG_EDX);
63 assert(INS_imul_BP - INS_imul_AX == REG_EBP);
64 assert(INS_imul_SI - INS_imul_AX == REG_ESI);
65 assert(INS_imul_DI - INS_imul_AX == REG_EDI);
66#ifdef _TARGET_AMD64_
67 assert(INS_imul_08 - INS_imul_AX == REG_R8);
68 assert(INS_imul_09 - INS_imul_AX == REG_R9);
69 assert(INS_imul_10 - INS_imul_AX == REG_R10);
70 assert(INS_imul_11 - INS_imul_AX == REG_R11);
71 assert(INS_imul_12 - INS_imul_AX == REG_R12);
72 assert(INS_imul_13 - INS_imul_AX == REG_R13);
73 assert(INS_imul_14 - INS_imul_AX == REG_R14);
74 assert(INS_imul_15 - INS_imul_AX == REG_R15);
75#endif
76}
77
78/*****************************************************************************
79 *
80 * Return the instruction that uses the given register in the imul instruction
81 */
82
83/* static */
84inline instruction emitter::inst3opImulForReg(regNumber reg)
85{
86 assert(genIsValidIntReg(reg));
87
88 instruction ins = instruction(reg + INS_imul_AX);
89 check3opImulValues();
90 assert(instrIs3opImul(ins));
91
92 return ins;
93}
94
95/*****************************************************************************
96 *
97 * Return the register which is used implicitly by the IMUL_REG instruction
98 */
99
100/* static */
101inline regNumber emitter::inst3opImulReg(instruction ins)
102{
103 regNumber reg = ((regNumber)(ins - INS_imul_AX));
104
105 assert(genIsValidIntReg(reg));
106
107 /* Make sure we return the appropriate register */
108
109 check3opImulValues();
110
111 return reg;
112}
113#endif
114
115/*****************************************************************************
116 *
117 * The following helpers should be used to access the various values that
118 * get stored in different places within the instruction descriptor.
119 */
120
121#ifdef _TARGET_XARCH_
122
123inline ssize_t emitter::emitGetInsAmd(instrDesc* id)
124{
125 return id->idIsLargeDsp() ? ((instrDescAmd*)id)->idaAmdVal : id->idAddr()->iiaAddrMode.amDisp;
126}
127
128inline int emitter::emitGetInsCDinfo(instrDesc* id)
129{
130 if (id->idIsLargeCall())
131 {
132 return ((instrDescCGCA*)id)->idcArgCnt;
133 }
134 else
135 {
136 assert(!id->idIsLargeDsp());
137 assert(!id->idIsLargeCns());
138 ssize_t cns = emitGetInsCns(id);
139
140 // We only encode 32-bit ints, so this is safe
141 noway_assert((int)cns == cns);
142
143 return (int)cns;
144 }
145}
146
147inline void emitter::emitGetInsCns(instrDesc* id, CnsVal* cv)
148{
149 cv->cnsReloc = id->idIsCnsReloc();
150 if (id->idIsLargeCns())
151 {
152 cv->cnsVal = ((instrDescCns*)id)->idcCnsVal;
153 }
154 else
155 {
156 cv->cnsVal = id->idSmallCns();
157 }
158}
159
160inline ssize_t emitter::emitGetInsAmdCns(instrDesc* id, CnsVal* cv)
161{
162 cv->cnsReloc = id->idIsCnsReloc();
163 if (id->idIsLargeDsp())
164 {
165 if (id->idIsLargeCns())
166 {
167 cv->cnsVal = ((instrDescCnsAmd*)id)->idacCnsVal;
168 return ((instrDescCnsAmd*)id)->idacAmdVal;
169 }
170 else
171 {
172 cv->cnsVal = id->idSmallCns();
173 return ((instrDescAmd*)id)->idaAmdVal;
174 }
175 }
176 else
177 {
178 if (id->idIsLargeCns())
179 {
180 cv->cnsVal = ((instrDescCns*)id)->idcCnsVal;
181 }
182 else
183 {
184 cv->cnsVal = id->idSmallCns();
185 }
186
187 return id->idAddr()->iiaAddrMode.amDisp;
188 }
189}
190
191inline void emitter::emitGetInsDcmCns(instrDesc* id, CnsVal* cv)
192{
193 cv->cnsReloc = id->idIsCnsReloc();
194 if (id->idIsLargeCns())
195 {
196 if (id->idIsLargeDsp())
197 {
198 cv->cnsVal = ((instrDescCnsDsp*)id)->iddcCnsVal;
199 }
200 else
201 {
202 cv->cnsVal = ((instrDescCns*)id)->idcCnsVal;
203 }
204 }
205 else
206 {
207 cv->cnsVal = id->idSmallCns();
208 }
209}
210
211inline ssize_t emitter::emitGetInsAmdAny(instrDesc* id)
212{
213 if (id->idIsLargeDsp())
214 {
215 if (id->idIsLargeCns())
216 {
217 return ((instrDescCnsAmd*)id)->idacAmdVal;
218 }
219 return ((instrDescAmd*)id)->idaAmdVal;
220 }
221
222 return id->idAddr()->iiaAddrMode.amDisp;
223}
224
225#endif // _TARGET_XARCH_
226
227/*****************************************************************************
228 *
229 * Convert between a register mask and a smaller version for storage.
230 */
231
232/*static*/ inline void emitter::emitEncodeCallGCregs(regMaskTP regmask, instrDesc* id)
233{
234 assert((regmask & RBM_CALLEE_TRASH) == 0);
235
236 unsigned encodeMask;
237
238#ifdef _TARGET_X86_
239 assert(REGNUM_BITS >= 3);
240 encodeMask = 0;
241
242 if ((regmask & RBM_ESI) != RBM_NONE)
243 encodeMask |= 0x01;
244 if ((regmask & RBM_EDI) != RBM_NONE)
245 encodeMask |= 0x02;
246 if ((regmask & RBM_EBX) != RBM_NONE)
247 encodeMask |= 0x04;
248
249 id->idReg1((regNumber)encodeMask); // Save in idReg1
250
251#elif defined(_TARGET_AMD64_)
252 assert(REGNUM_BITS >= 4);
253 encodeMask = 0;
254
255 if ((regmask & RBM_RSI) != RBM_NONE)
256 {
257 encodeMask |= 0x01;
258 }
259 if ((regmask & RBM_RDI) != RBM_NONE)
260 {
261 encodeMask |= 0x02;
262 }
263 if ((regmask & RBM_RBX) != RBM_NONE)
264 {
265 encodeMask |= 0x04;
266 }
267 if ((regmask & RBM_RBP) != RBM_NONE)
268 {
269 encodeMask |= 0x08;
270 }
271
272 id->idReg1((regNumber)encodeMask); // Save in idReg1
273
274 encodeMask = 0;
275
276 if ((regmask & RBM_R12) != RBM_NONE)
277 {
278 encodeMask |= 0x01;
279 }
280 if ((regmask & RBM_R13) != RBM_NONE)
281 {
282 encodeMask |= 0x02;
283 }
284 if ((regmask & RBM_R14) != RBM_NONE)
285 {
286 encodeMask |= 0x04;
287 }
288 if ((regmask & RBM_R15) != RBM_NONE)
289 {
290 encodeMask |= 0x08;
291 }
292
293 id->idReg2((regNumber)encodeMask); // Save in idReg2
294
295#elif defined(_TARGET_ARM_)
296 assert(REGNUM_BITS >= 4);
297 encodeMask = 0;
298
299 if ((regmask & RBM_R4) != RBM_NONE)
300 encodeMask |= 0x01;
301 if ((regmask & RBM_R5) != RBM_NONE)
302 encodeMask |= 0x02;
303 if ((regmask & RBM_R6) != RBM_NONE)
304 encodeMask |= 0x04;
305 if ((regmask & RBM_R7) != RBM_NONE)
306 encodeMask |= 0x08;
307
308 id->idReg1((regNumber)encodeMask); // Save in idReg1
309
310 encodeMask = 0;
311
312 if ((regmask & RBM_R8) != RBM_NONE)
313 encodeMask |= 0x01;
314 if ((regmask & RBM_R9) != RBM_NONE)
315 encodeMask |= 0x02;
316 if ((regmask & RBM_R10) != RBM_NONE)
317 encodeMask |= 0x04;
318 if ((regmask & RBM_R11) != RBM_NONE)
319 encodeMask |= 0x08;
320
321 id->idReg2((regNumber)encodeMask); // Save in idReg2
322
323#elif defined(_TARGET_ARM64_)
324 assert(REGNUM_BITS >= 5);
325 encodeMask = 0;
326
327 if ((regmask & RBM_R19) != RBM_NONE)
328 encodeMask |= 0x01;
329 if ((regmask & RBM_R20) != RBM_NONE)
330 encodeMask |= 0x02;
331 if ((regmask & RBM_R21) != RBM_NONE)
332 encodeMask |= 0x04;
333 if ((regmask & RBM_R22) != RBM_NONE)
334 encodeMask |= 0x08;
335 if ((regmask & RBM_R23) != RBM_NONE)
336 encodeMask |= 0x10;
337
338 id->idReg1((regNumber)encodeMask); // Save in idReg1
339
340 encodeMask = 0;
341
342 if ((regmask & RBM_R24) != RBM_NONE)
343 encodeMask |= 0x01;
344 if ((regmask & RBM_R25) != RBM_NONE)
345 encodeMask |= 0x02;
346 if ((regmask & RBM_R26) != RBM_NONE)
347 encodeMask |= 0x04;
348 if ((regmask & RBM_R27) != RBM_NONE)
349 encodeMask |= 0x08;
350 if ((regmask & RBM_R28) != RBM_NONE)
351 encodeMask |= 0x10;
352
353 id->idReg2((regNumber)encodeMask); // Save in idReg2
354
355#else
356 NYI("unknown target");
357#endif
358}
359
360/*static*/ inline unsigned emitter::emitDecodeCallGCregs(instrDesc* id)
361{
362 unsigned regmask = 0;
363 unsigned encodeMask;
364
365#ifdef _TARGET_X86_
366 assert(REGNUM_BITS >= 3);
367 encodeMask = id->idReg1();
368
369 if ((encodeMask & 0x01) != 0)
370 regmask |= RBM_ESI;
371 if ((encodeMask & 0x02) != 0)
372 regmask |= RBM_EDI;
373 if ((encodeMask & 0x04) != 0)
374 regmask |= RBM_EBX;
375#elif defined(_TARGET_AMD64_)
376 assert(REGNUM_BITS >= 4);
377 encodeMask = id->idReg1();
378
379 if ((encodeMask & 0x01) != 0)
380 {
381 regmask |= RBM_RSI;
382 }
383 if ((encodeMask & 0x02) != 0)
384 {
385 regmask |= RBM_RDI;
386 }
387 if ((encodeMask & 0x04) != 0)
388 {
389 regmask |= RBM_RBX;
390 }
391 if ((encodeMask & 0x08) != 0)
392 {
393 regmask |= RBM_RBP;
394 }
395
396 encodeMask = id->idReg2();
397
398 if ((encodeMask & 0x01) != 0)
399 {
400 regmask |= RBM_R12;
401 }
402 if ((encodeMask & 0x02) != 0)
403 {
404 regmask |= RBM_R13;
405 }
406 if ((encodeMask & 0x04) != 0)
407 {
408 regmask |= RBM_R14;
409 }
410 if ((encodeMask & 0x08) != 0)
411 {
412 regmask |= RBM_R15;
413 }
414
415#elif defined(_TARGET_ARM_)
416 assert(REGNUM_BITS >= 4);
417 encodeMask = id->idReg1();
418
419 if ((encodeMask & 0x01) != 0)
420 regmask |= RBM_R4;
421 if ((encodeMask & 0x02) != 0)
422 regmask |= RBM_R5;
423 if ((encodeMask & 0x04) != 0)
424 regmask |= RBM_R6;
425 if ((encodeMask & 0x08) != 0)
426 regmask |= RBM_R7;
427
428 encodeMask = id->idReg2();
429
430 if ((encodeMask & 0x01) != 0)
431 regmask |= RBM_R8;
432 if ((encodeMask & 0x02) != 0)
433 regmask |= RBM_R9;
434 if ((encodeMask & 0x04) != 0)
435 regmask |= RBM_R10;
436 if ((encodeMask & 0x08) != 0)
437 regmask |= RBM_R11;
438
439#elif defined(_TARGET_ARM64_)
440 assert(REGNUM_BITS >= 5);
441 encodeMask = id->idReg1();
442
443 if ((encodeMask & 0x01) != 0)
444 regmask |= RBM_R19;
445 if ((encodeMask & 0x02) != 0)
446 regmask |= RBM_R20;
447 if ((encodeMask & 0x04) != 0)
448 regmask |= RBM_R21;
449 if ((encodeMask & 0x08) != 0)
450 regmask |= RBM_R22;
451 if ((encodeMask & 0x10) != 0)
452 regmask |= RBM_R23;
453
454 encodeMask = id->idReg2();
455
456 if ((encodeMask & 0x01) != 0)
457 regmask |= RBM_R24;
458 if ((encodeMask & 0x02) != 0)
459 regmask |= RBM_R25;
460 if ((encodeMask & 0x04) != 0)
461 regmask |= RBM_R26;
462 if ((encodeMask & 0x08) != 0)
463 regmask |= RBM_R27;
464 if ((encodeMask & 0x10) != 0)
465 regmask |= RBM_R28;
466
467#else
468 NYI("unknown target");
469#endif
470
471 return regmask;
472}
473
474#ifdef _TARGET_XARCH_
475inline bool insIsCMOV(instruction ins)
476{
477 return ((ins >= INS_cmovo) && (ins <= INS_cmovg));
478}
479#endif
480
481/*****************************************************************************
482 *
483 * Call the specified function pointer for each insGroup in the current
484 * method that is marked IGF_NOGCINTERRUPT. Stops if the callback returns
485 * false. Returns the final result of the callback.
486 */
487template <typename Callback>
488bool emitter::emitGenNoGCLst(Callback& cb)
489{
490 for (insGroup* ig = emitIGlist; ig; ig = ig->igNext)
491 {
492 if (ig->igFlags & IGF_NOGCINTERRUPT)
493 {
494 if (!cb(ig->igFuncIdx, ig->igOffs, ig->igSize))
495 {
496 return false;
497 }
498 }
499 }
500
501 return true;
502}
503
504/*****************************************************************************/
505#endif //_EMITINL_H_
506/*****************************************************************************/
507