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 | |
15 | inline UNATIVE_OFFSET emitter::emitInstCodeSz(instrDesc* id) |
16 | { |
17 | return id->idCodeSize(); |
18 | } |
19 | |
20 | inline UNATIVE_OFFSET emitter::emitSizeOfJump(instrDescJmp* jmp) |
21 | { |
22 | return jmp->idCodeSize(); |
23 | } |
24 | |
25 | #ifdef _TARGET_XARCH_ |
26 | |
27 | /* static */ |
28 | inline 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 */ |
38 | inline 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 */ |
48 | inline 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 */ |
57 | inline 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 */ |
84 | inline 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 */ |
101 | inline 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 | |
123 | inline ssize_t emitter::emitGetInsAmd(instrDesc* id) |
124 | { |
125 | return id->idIsLargeDsp() ? ((instrDescAmd*)id)->idaAmdVal : id->idAddr()->iiaAddrMode.amDisp; |
126 | } |
127 | |
128 | inline 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 | |
147 | inline 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 | |
160 | inline 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 | |
191 | inline 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 | |
211 | inline 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_ |
475 | inline 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 | */ |
487 | template <typename Callback> |
488 | bool 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 |