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/*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7XX XX
8XX emitArm64.cpp XX
9XX XX
10XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
11XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
12*/
13
14#include "jitpch.h"
15#ifdef _MSC_VER
16#pragma hdrstop
17#endif
18
19#if defined(_TARGET_ARM64_)
20
21/*****************************************************************************/
22/*****************************************************************************/
23
24#include "instr.h"
25#include "emit.h"
26#include "codegen.h"
27
28/* static */ bool emitter::strictArmAsm = true;
29
30/*****************************************************************************/
31
32const instruction emitJumpKindInstructions[] = {
33 INS_nop,
34
35#define JMP_SMALL(en, rev, ins) INS_##ins,
36#include "emitjmps.h"
37};
38
39const emitJumpKind emitReverseJumpKinds[] = {
40 EJ_NONE,
41
42#define JMP_SMALL(en, rev, ins) EJ_##rev,
43#include "emitjmps.h"
44};
45
46/*****************************************************************************
47 * Look up the instruction for a jump kind
48 */
49
50/*static*/ instruction emitter::emitJumpKindToIns(emitJumpKind jumpKind)
51{
52 assert((unsigned)jumpKind < ArrLen(emitJumpKindInstructions));
53 return emitJumpKindInstructions[jumpKind];
54}
55
56/*****************************************************************************
57* Look up the jump kind for an instruction. It better be a conditional
58* branch instruction with a jump kind!
59*/
60
61/*static*/ emitJumpKind emitter::emitInsToJumpKind(instruction ins)
62{
63 for (unsigned i = 0; i < ArrLen(emitJumpKindInstructions); i++)
64 {
65 if (ins == emitJumpKindInstructions[i])
66 {
67 emitJumpKind ret = (emitJumpKind)i;
68 assert(EJ_NONE < ret && ret < EJ_COUNT);
69 return ret;
70 }
71 }
72 unreached();
73}
74
75/*****************************************************************************
76 * Reverse the conditional jump
77 */
78
79/*static*/ emitJumpKind emitter::emitReverseJumpKind(emitJumpKind jumpKind)
80{
81 assert(jumpKind < EJ_COUNT);
82 return emitReverseJumpKinds[jumpKind];
83}
84
85/*****************************************************************************
86 *
87 * Return the allocated size (in bytes) of the given instruction descriptor.
88 */
89
90size_t emitter::emitSizeOfInsDsc(instrDesc* id)
91{
92 if (emitIsScnsInsDsc(id))
93 return SMALL_IDSC_SIZE;
94
95 assert((unsigned)id->idInsFmt() < emitFmtCount);
96
97 ID_OPS idOp = (ID_OPS)emitFmtToOps[id->idInsFmt()];
98 bool isCallIns = (id->idIns() == INS_bl) || (id->idIns() == INS_blr) || (id->idIns() == INS_b_tail) ||
99 (id->idIns() == INS_br_tail);
100 bool maybeCallIns = (id->idIns() == INS_b) || (id->idIns() == INS_br);
101
102 switch (idOp)
103 {
104 case ID_OP_NONE:
105 break;
106
107 case ID_OP_JMP:
108 return sizeof(instrDescJmp);
109
110 case ID_OP_CALL:
111 assert(isCallIns || maybeCallIns);
112 if (id->idIsLargeCall())
113 {
114 /* Must be a "fat" call descriptor */
115 return sizeof(instrDescCGCA);
116 }
117 else
118 {
119 assert(!id->idIsLargeDsp());
120 assert(!id->idIsLargeCns());
121 return sizeof(instrDesc);
122 }
123 break;
124
125 default:
126 NO_WAY("unexpected instruction descriptor format");
127 break;
128 }
129
130 if (id->idIsLargeCns())
131 {
132 if (id->idIsLargeDsp())
133 return sizeof(instrDescCnsDsp);
134 else
135 return sizeof(instrDescCns);
136 }
137 else
138 {
139 if (id->idIsLargeDsp())
140 return sizeof(instrDescDsp);
141 else
142 return sizeof(instrDesc);
143 }
144}
145
146#ifdef DEBUG
147/*****************************************************************************
148 *
149 * The following called for each recorded instruction -- use for debugging.
150 */
151void emitter::emitInsSanityCheck(instrDesc* id)
152{
153 /* What instruction format have we got? */
154
155 switch (id->idInsFmt())
156 {
157 instruction ins;
158 emitAttr elemsize;
159 emitAttr datasize;
160 emitAttr dstsize;
161 emitAttr srcsize;
162 ssize_t imm;
163 unsigned immShift;
164 ssize_t index;
165 ssize_t index2;
166
167 case IF_BI_0A: // BI_0A ......iiiiiiiiii iiiiiiiiiiiiiiii simm26:00
168 break;
169
170 case IF_BI_0B: // BI_0B ......iiiiiiiiii iiiiiiiiiiii.... simm19:00
171 break;
172
173 case IF_LARGEJMP:
174 case IF_LARGEADR:
175 case IF_LARGELDC:
176 break;
177
178 case IF_BI_0C: // BI_0C ......iiiiiiiiii iiiiiiiiiiiiiiii simm26:00
179 break;
180
181 case IF_BI_1A: // BI_1A ......iiiiiiiiii iiiiiiiiiiittttt Rt simm19:00
182 assert(isValidGeneralDatasize(id->idOpSize()));
183 assert(isGeneralRegister(id->idReg1()));
184 break;
185
186 case IF_BI_1B: // BI_1B B.......bbbbbiii iiiiiiiiiiittttt Rt imm6, simm14:00
187 assert(isValidGeneralDatasize(id->idOpSize()));
188 assert(isGeneralRegister(id->idReg1()));
189 assert(isValidImmShift(emitGetInsSC(id), id->idOpSize()));
190 break;
191
192 case IF_BR_1A: // BR_1A ................ ......nnnnn..... Rn
193 assert(isGeneralRegister(id->idReg1()));
194 break;
195
196 case IF_BR_1B: // BR_1B ................ ......nnnnn..... Rn
197 assert(isGeneralRegister(id->idReg3()));
198 break;
199
200 case IF_LS_1A: // LS_1A .X......iiiiiiii iiiiiiiiiiittttt Rt PC imm(1MB)
201 assert(isGeneralRegister(id->idReg1()) || isVectorRegister(id->idReg1()));
202 assert(insOptsNone(id->idInsOpt()));
203 break;
204
205 case IF_LS_2A: // LS_2A .X.......X...... ......nnnnnttttt Rt Rn
206 assert(isIntegerRegister(id->idReg1()) || // ZR
207 isVectorRegister(id->idReg1()));
208 assert(isIntegerRegister(id->idReg2())); // SP
209 assert(emitGetInsSC(id) == 0);
210 assert(insOptsNone(id->idInsOpt()));
211 break;
212
213 case IF_LS_2B: // LS_2B .X.......Xiiiiii iiiiiinnnnnttttt Rt Rn imm(0-4095)
214 assert(isIntegerRegister(id->idReg1()) || // ZR
215 isVectorRegister(id->idReg1()));
216 assert(isIntegerRegister(id->idReg2())); // SP
217 assert(isValidUimm12(emitGetInsSC(id)));
218 assert(insOptsNone(id->idInsOpt()));
219 break;
220
221 case IF_LS_2C: // LS_2C .X.......X.iiiii iiiiPPnnnnnttttt Rt Rn imm(-256..+255) no/pre/post inc
222 assert(isIntegerRegister(id->idReg1()) || // ZR
223 isVectorRegister(id->idReg1()));
224 assert(isIntegerRegister(id->idReg2())); // SP
225 assert(emitGetInsSC(id) >= -0x100);
226 assert(emitGetInsSC(id) < 0x100);
227 assert(insOptsNone(id->idInsOpt()) || insOptsIndexed(id->idInsOpt()));
228 break;
229
230 case IF_LS_3A: // LS_3A .X.......X.mmmmm oooS..nnnnnttttt Rt Rn Rm ext(Rm) LSL {}
231 assert(isIntegerRegister(id->idReg1()) || // ZR
232 isVectorRegister(id->idReg1()));
233 assert(isIntegerRegister(id->idReg2())); // SP
234 if (id->idIsLclVar())
235 {
236 assert(isGeneralRegister(codeGen->rsGetRsvdReg()));
237 }
238 else
239 {
240 assert(isGeneralRegister(id->idReg3()));
241 }
242 assert(insOptsLSExtend(id->idInsOpt()));
243 break;
244
245 case IF_LS_3B: // LS_3B X............... .aaaaannnnnttttt Rt Ra Rn
246 assert((isValidGeneralDatasize(id->idOpSize()) && isIntegerRegister(id->idReg1())) ||
247 (isValidVectorLSPDatasize(id->idOpSize()) && isVectorRegister(id->idReg1())));
248 assert(isIntegerRegister(id->idReg1()) || // ZR
249 isVectorRegister(id->idReg1()));
250 assert(isIntegerRegister(id->idReg2()) || // ZR
251 isVectorRegister(id->idReg2()));
252 assert(isIntegerRegister(id->idReg3())); // SP
253 assert(emitGetInsSC(id) == 0);
254 assert(insOptsNone(id->idInsOpt()));
255 break;
256
257 case IF_LS_3C: // LS_3C X.........iiiiii iaaaaannnnnttttt Rt Ra Rn imm(im7,sh)
258 assert((isValidGeneralDatasize(id->idOpSize()) && isIntegerRegister(id->idReg1())) ||
259 (isValidVectorLSPDatasize(id->idOpSize()) && isVectorRegister(id->idReg1())));
260 assert(isIntegerRegister(id->idReg1()) || // ZR
261 isVectorRegister(id->idReg1()));
262 assert(isIntegerRegister(id->idReg2()) || // ZR
263 isVectorRegister(id->idReg2()));
264 assert(isIntegerRegister(id->idReg3())); // SP
265 assert(emitGetInsSC(id) >= -0x40);
266 assert(emitGetInsSC(id) < 0x40);
267 assert(insOptsNone(id->idInsOpt()) || insOptsIndexed(id->idInsOpt()));
268 break;
269
270 case IF_LS_3D: // LS_3D .X.......X.mmmmm ......nnnnnttttt Wm Rt Rn
271 assert(isIntegerRegister(id->idReg1()));
272 assert(isIntegerRegister(id->idReg2()));
273 assert(isIntegerRegister(id->idReg3()));
274 assert(emitGetInsSC(id) == 0);
275 assert(!id->idIsLclVar());
276 assert(insOptsNone(id->idInsOpt()));
277 break;
278
279 case IF_LS_3E: // LS_3E .X.........mmmmm ......nnnnnttttt Rm Rt Rn ARMv8.1 LSE Atomics
280 assert(isIntegerRegister(id->idReg1()));
281 assert(isIntegerRegister(id->idReg2()));
282 assert(isIntegerRegister(id->idReg3()));
283 assert(emitGetInsSC(id) == 0);
284 assert(!id->idIsLclVar());
285 assert(insOptsNone(id->idInsOpt()));
286 break;
287
288 case IF_DI_1A: // DI_1A X.......shiiiiii iiiiiinnnnn..... Rn imm(i12,sh)
289 assert(isValidGeneralDatasize(id->idOpSize()));
290 assert(isGeneralRegister(id->idReg1()));
291 assert(isValidUimm12(emitGetInsSC(id)));
292 assert(insOptsNone(id->idInsOpt()) || insOptsLSL12(id->idInsOpt()));
293 break;
294
295 case IF_DI_1B: // DI_1B X........hwiiiii iiiiiiiiiiiddddd Rd imm(i16,hw)
296 assert(isValidGeneralDatasize(id->idOpSize()));
297 assert(isGeneralRegister(id->idReg1()));
298 assert(isValidImmHWVal(emitGetInsSC(id), id->idOpSize()));
299 break;
300
301 case IF_DI_1C: // DI_1C X........Nrrrrrr ssssssnnnnn..... Rn imm(N,r,s)
302 assert(isValidGeneralDatasize(id->idOpSize()));
303 assert(isGeneralRegister(id->idReg1()));
304 assert(isValidImmNRS(emitGetInsSC(id), id->idOpSize()));
305 break;
306
307 case IF_DI_1D: // DI_1D X........Nrrrrrr ssssss.....ddddd Rd imm(N,r,s)
308 assert(isValidGeneralDatasize(id->idOpSize()));
309 assert(isIntegerRegister(id->idReg1())); // SP
310 assert(isValidImmNRS(emitGetInsSC(id), id->idOpSize()));
311 break;
312
313 case IF_DI_1E: // DI_1E .ii.....iiiiiiii iiiiiiiiiiiddddd Rd simm21
314 assert(isGeneralRegister(id->idReg1()));
315 break;
316
317 case IF_DI_1F: // DI_1F X..........iiiii cccc..nnnnn.nzcv Rn imm5 nzcv cond
318 assert(isValidGeneralDatasize(id->idOpSize()));
319 assert(isGeneralRegister(id->idReg1()));
320 assert(isValidImmCondFlagsImm5(emitGetInsSC(id)));
321 break;
322
323 case IF_DI_2A: // DI_2A X.......shiiiiii iiiiiinnnnnddddd Rd Rn imm(i12,sh)
324 assert(isValidGeneralDatasize(id->idOpSize()));
325 assert(isIntegerRegister(id->idReg1())); // SP
326 assert(isIntegerRegister(id->idReg2())); // SP
327 assert(isValidUimm12(emitGetInsSC(id)));
328 assert(insOptsNone(id->idInsOpt()) || insOptsLSL12(id->idInsOpt()));
329 break;
330
331 case IF_DI_2B: // DI_2B X.........Xnnnnn ssssssnnnnnddddd Rd Rn imm(0-63)
332 assert(isValidGeneralDatasize(id->idOpSize()));
333 assert(isGeneralRegister(id->idReg1()));
334 assert(isGeneralRegister(id->idReg2()));
335 assert(isValidImmShift(emitGetInsSC(id), id->idOpSize()));
336 break;
337
338 case IF_DI_2C: // DI_2C X........Nrrrrrr ssssssnnnnnddddd Rd Rn imm(N,r,s)
339 assert(isValidGeneralDatasize(id->idOpSize()));
340 assert(isIntegerRegister(id->idReg1())); // SP
341 assert(isGeneralRegister(id->idReg2()));
342 assert(isValidImmNRS(emitGetInsSC(id), id->idOpSize()));
343 break;
344
345 case IF_DI_2D: // DI_2D X........Nrrrrrr ssssssnnnnnddddd Rd Rn imr, imms (N,r,s)
346 assert(isValidGeneralDatasize(id->idOpSize()));
347 assert(isGeneralRegister(id->idReg1()));
348 assert(isGeneralRegister(id->idReg2()));
349 assert(isValidImmNRS(emitGetInsSC(id), id->idOpSize()));
350 break;
351
352 case IF_DR_1D: // DR_1D X............... cccc.......ddddd Rd cond
353 assert(isValidGeneralDatasize(id->idOpSize()));
354 assert(isGeneralRegister(id->idReg1()));
355 assert(isValidImmCond(emitGetInsSC(id)));
356 break;
357
358 case IF_DR_2A: // DR_2A X..........mmmmm ......nnnnn..... Rn Rm
359 assert(isValidGeneralDatasize(id->idOpSize()));
360 assert(isGeneralRegister(id->idReg1()));
361 assert(isGeneralRegister(id->idReg2()));
362 break;
363
364 case IF_DR_2B: // DR_2B X.......sh.mmmmm ssssssnnnnn..... Rn Rm {LSL,LSR,ASR,ROR} imm(0-63)
365 assert(isValidGeneralDatasize(id->idOpSize()));
366 assert(isIntegerRegister(id->idReg1())); // ZR
367 assert(isGeneralRegister(id->idReg2()));
368 assert(isValidImmShift(emitGetInsSC(id), id->idOpSize()));
369 if (!insOptsNone(id->idInsOpt()))
370 {
371 if (id->idIns() == INS_tst) // tst allows ROR, cmp/cmn don't
372 {
373 assert(insOptsAnyShift(id->idInsOpt()));
374 }
375 else
376 {
377 assert(insOptsAluShift(id->idInsOpt()));
378 }
379 }
380 assert(insOptsNone(id->idInsOpt()) || (emitGetInsSC(id) > 0));
381 break;
382
383 case IF_DR_2C: // DR_2C X..........mmmmm ooosssnnnnn..... Rn Rm ext(Rm) LSL imm(0-4)
384 assert(isValidGeneralDatasize(id->idOpSize()));
385 assert(isIntegerRegister(id->idReg1())); // SP
386 assert(isGeneralRegister(id->idReg2()));
387 assert(insOptsNone(id->idInsOpt()) || insOptsLSL(id->idInsOpt()) || insOptsAnyExtend(id->idInsOpt()));
388 assert(emitGetInsSC(id) >= 0);
389 assert(emitGetInsSC(id) <= 4);
390 if (insOptsLSL(id->idInsOpt()))
391 {
392 assert(emitGetInsSC(id) > 0);
393 }
394 break;
395
396 case IF_DR_2D: // DR_2D X..........nnnnn cccc..nnnnnmmmmm Rd Rn cond
397 assert(isValidGeneralDatasize(id->idOpSize()));
398 assert(isGeneralRegister(id->idReg1()));
399 assert(isGeneralRegister(id->idReg2()));
400 assert(isValidImmCond(emitGetInsSC(id)));
401 break;
402
403 case IF_DR_2E: // DR_2E X..........mmmmm ...........ddddd Rd Rm
404 assert(isValidGeneralDatasize(id->idOpSize()));
405 assert(isGeneralRegister(id->idReg1()));
406 assert(isIntegerRegister(id->idReg2())); // ZR
407 break;
408
409 case IF_DR_2F: // DR_2F X.......sh.mmmmm ssssss.....ddddd Rd Rm {LSL,LSR,ASR} imm(0-63)
410 assert(isValidGeneralDatasize(id->idOpSize()));
411 assert(isGeneralRegister(id->idReg1()));
412 assert(isGeneralRegister(id->idReg2()));
413 assert(isValidImmShift(emitGetInsSC(id), id->idOpSize()));
414 assert(insOptsNone(id->idInsOpt()) || insOptsAluShift(id->idInsOpt()));
415 assert(insOptsNone(id->idInsOpt()) || (emitGetInsSC(id) > 0));
416 break;
417
418 case IF_DR_2G: // DR_2G X............... ......nnnnnddddd Rd Rm
419 assert(isValidGeneralDatasize(id->idOpSize()));
420 assert(isIntegerRegister(id->idReg1())); // SP
421 assert(isIntegerRegister(id->idReg2())); // SP
422 break;
423
424 case IF_DR_2H: // DR_2H X........X...... ......nnnnnddddd Rd Rn
425 assert(isValidGeneralDatasize(id->idOpSize()));
426 assert(isGeneralRegister(id->idReg1()));
427 assert(isGeneralRegister(id->idReg2()));
428 break;
429
430 case IF_DR_2I: // DR_2I X..........mmmmm cccc..nnnnn.nzcv Rn Rm nzcv cond
431 assert(isValidGeneralDatasize(id->idOpSize()));
432 assert(isGeneralRegister(id->idReg1()));
433 assert(isGeneralRegister(id->idReg2()));
434 assert(isValidImmCondFlags(emitGetInsSC(id)));
435 break;
436
437 case IF_DR_2J: // DR_2J ................ ......nnnnnddddd Sd Sn (sha1h)
438 assert(isValidGeneralDatasize(id->idOpSize()));
439 assert(isVectorRegister(id->idReg1()));
440 assert(isVectorRegister(id->idReg2()));
441 break;
442
443 case IF_DR_3A: // DR_3A X..........mmmmm ......nnnnnmmmmm Rd Rn Rm
444 assert(isValidGeneralDatasize(id->idOpSize()));
445 assert(isIntegerRegister(id->idReg1())); // SP
446 assert(isIntegerRegister(id->idReg2())); // SP
447 if (id->idIsLclVar())
448 {
449 assert(isGeneralRegister(codeGen->rsGetRsvdReg()));
450 }
451 else
452 {
453 assert(isGeneralRegister(id->idReg3()));
454 }
455 assert(insOptsNone(id->idInsOpt()));
456 break;
457
458 case IF_DR_3B: // DR_3B X.......sh.mmmmm ssssssnnnnnddddd Rd Rn Rm {LSL,LSR,ASR,ROR} imm(0-63)
459 assert(isValidGeneralDatasize(id->idOpSize()));
460 assert(isGeneralRegister(id->idReg1()));
461 assert(isGeneralRegister(id->idReg2()));
462 assert(isGeneralRegister(id->idReg3()));
463 assert(isValidImmShift(emitGetInsSC(id), id->idOpSize()));
464 assert(insOptsNone(id->idInsOpt()) || insOptsAnyShift(id->idInsOpt()));
465 assert(insOptsNone(id->idInsOpt()) || (emitGetInsSC(id) > 0));
466 break;
467
468 case IF_DR_3C: // DR_3C X..........mmmmm ooosssnnnnnddddd Rd Rn Rm ext(Rm) LSL imm(0-4)
469 assert(isValidGeneralDatasize(id->idOpSize()));
470 assert(isIntegerRegister(id->idReg1())); // SP
471 assert(isIntegerRegister(id->idReg2())); // SP
472 assert(isGeneralRegister(id->idReg3()));
473 assert(insOptsNone(id->idInsOpt()) || insOptsLSL(id->idInsOpt()) || insOptsAnyExtend(id->idInsOpt()));
474 assert(emitGetInsSC(id) >= 0);
475 assert(emitGetInsSC(id) <= 4);
476 if (insOptsLSL(id->idInsOpt()))
477 {
478 assert((emitGetInsSC(id) > 0) ||
479 (id->idReg2() == REG_ZR)); // REG_ZR encodes SP and we allow a shift of zero
480 }
481 break;
482
483 case IF_DR_3D: // DR_3D X..........mmmmm cccc..nnnnnmmmmm Rd Rn Rm cond
484 assert(isValidGeneralDatasize(id->idOpSize()));
485 assert(isGeneralRegister(id->idReg1()));
486 assert(isGeneralRegister(id->idReg2()));
487 assert(isGeneralRegister(id->idReg3()));
488 assert(isValidImmCond(emitGetInsSC(id)));
489 break;
490
491 case IF_DR_3E: // DR_3E X........X.mmmmm ssssssnnnnnddddd Rd Rn Rm imm(0-63)
492 assert(isValidGeneralDatasize(id->idOpSize()));
493 assert(isGeneralRegister(id->idReg1()));
494 assert(isGeneralRegister(id->idReg2()));
495 assert(isGeneralRegister(id->idReg3()));
496 assert(isValidImmShift(emitGetInsSC(id), id->idOpSize()));
497 assert(insOptsNone(id->idInsOpt()));
498 break;
499
500 case IF_DR_4A: // DR_4A X..........mmmmm .aaaaannnnnddddd Rd Rn Rm Ra
501 assert(isValidGeneralDatasize(id->idOpSize()));
502 assert(isGeneralRegister(id->idReg1()));
503 assert(isGeneralRegister(id->idReg2()));
504 assert(isGeneralRegister(id->idReg3()));
505 assert(isGeneralRegister(id->idReg4()));
506 break;
507
508 case IF_DV_1A: // DV_1A .........X.iiiii iii........ddddd Vd imm8 (fmov - immediate scalar)
509 assert(insOptsNone(id->idInsOpt()));
510 elemsize = id->idOpSize();
511 assert(isValidVectorElemsizeFloat(elemsize));
512 assert(isVectorRegister(id->idReg1()));
513 assert(isValidUimm8(emitGetInsSC(id)));
514 break;
515
516 case IF_DV_1B: // DV_1B .QX..........iii cmod..iiiiiddddd Vd imm8 (immediate vector)
517 ins = id->idIns();
518 imm = emitGetInsSC(id) & 0x0ff;
519 immShift = (emitGetInsSC(id) & 0x700) >> 8;
520 assert(immShift >= 0);
521 datasize = id->idOpSize();
522 assert(isValidVectorDatasize(datasize));
523 assert(isValidArrangement(datasize, id->idInsOpt()));
524 elemsize = optGetElemsize(id->idInsOpt());
525 if (ins == INS_fmov)
526 {
527 assert(isValidVectorElemsizeFloat(elemsize));
528 assert(id->idInsOpt() != INS_OPTS_1D); // Reserved encoding
529 assert(immShift == 0);
530 }
531 else
532 {
533 assert(isValidVectorElemsize(elemsize));
534 assert((immShift != 4) && (immShift != 7)); // always invalid values
535 if (ins != INS_movi) // INS_mvni, INS_orr, INS_bic
536 {
537 assert((elemsize != EA_1BYTE) && (elemsize != EA_8BYTE)); // only H or S
538 if (elemsize == EA_2BYTE)
539 {
540 assert(immShift < 2);
541 }
542 else // (elemsize == EA_4BYTE)
543 {
544 if (ins != INS_mvni)
545 {
546 assert(immShift < 4);
547 }
548 }
549 }
550 }
551 assert(isVectorRegister(id->idReg1()));
552 assert(isValidUimm8(imm));
553 break;
554
555 case IF_DV_1C: // DV_1C .........X...... ......nnnnn..... Vn #0.0 (fcmp - with zero)
556 assert(insOptsNone(id->idInsOpt()));
557 elemsize = id->idOpSize();
558 assert(isValidVectorElemsizeFloat(elemsize));
559 assert(isVectorRegister(id->idReg1()));
560 break;
561
562 case IF_DV_2A: // DV_2A .Q.......X...... ......nnnnnddddd Vd Vn (fabs, fcvt - vector)
563 case IF_DV_2M: // DV_2M .Q......XX...... ......nnnnnddddd Vd Vn (abs, neg - vector)
564 case IF_DV_2P: // DV_2P ................ ......nnnnnddddd Vd Vn (aes*, sha1su1)
565 assert(isValidVectorDatasize(id->idOpSize()));
566 assert(isValidArrangement(id->idOpSize(), id->idInsOpt()));
567 assert(isVectorRegister(id->idReg1()));
568 assert(isVectorRegister(id->idReg2()));
569 break;
570
571 case IF_DV_2N: // DV_2N .........iiiiiii ......nnnnnddddd Vd Vn imm (shift - scalar)
572 assert(id->idOpSize() == EA_8BYTE);
573 assert(insOptsNone(id->idInsOpt()));
574 assert(isVectorRegister(id->idReg1()));
575 assert(isVectorRegister(id->idReg2()));
576 assert(isValidImmShift(emitGetInsSC(id), EA_8BYTE));
577 break;
578
579 case IF_DV_2O: // DV_2O .Q.......iiiiiii ......nnnnnddddd Vd Vn imm (shift - vector)
580 assert(isValidVectorDatasize(id->idOpSize()));
581 assert(isValidArrangement(id->idOpSize(), id->idInsOpt()));
582 assert(isVectorRegister(id->idReg1()));
583 assert(isVectorRegister(id->idReg2()));
584 elemsize = optGetElemsize(id->idInsOpt());
585 assert(isValidImmShift(emitGetInsSC(id), elemsize));
586 break;
587
588 case IF_DV_2B: // DV_2B .Q.........iiiii ......nnnnnddddd Rd Vn[] (umov/smov - to general)
589 elemsize = id->idOpSize();
590 index = emitGetInsSC(id);
591 assert(insOptsNone(id->idInsOpt()));
592 assert(isValidVectorIndex(EA_16BYTE, elemsize, index));
593 assert(isValidVectorElemsize(elemsize));
594 assert(isGeneralRegister(id->idReg1()));
595 assert(isVectorRegister(id->idReg2()));
596 break;
597
598 case IF_DV_2C: // DV_2C .Q.........iiiii ......nnnnnddddd Vd Rn (dup/ins - vector from general)
599 if (id->idIns() == INS_dup)
600 {
601 datasize = id->idOpSize();
602 assert(isValidVectorDatasize(datasize));
603 assert(isValidArrangement(datasize, id->idInsOpt()));
604 elemsize = optGetElemsize(id->idInsOpt());
605 }
606 else // INS_ins
607 {
608 datasize = EA_16BYTE;
609 elemsize = id->idOpSize();
610 assert(isValidVectorElemsize(elemsize));
611 }
612 assert(isVectorRegister(id->idReg1()));
613 assert(isGeneralRegisterOrZR(id->idReg2()));
614 break;
615
616 case IF_DV_2D: // DV_2D .Q.........iiiii ......nnnnnddddd Vd Vn[] (dup - vector)
617 datasize = id->idOpSize();
618 assert(isValidVectorDatasize(datasize));
619 assert(isValidArrangement(datasize, id->idInsOpt()));
620 elemsize = optGetElemsize(id->idInsOpt());
621 index = emitGetInsSC(id);
622 assert(isValidVectorIndex(datasize, elemsize, index));
623 assert(isVectorRegister(id->idReg1()));
624 assert(isVectorRegister(id->idReg2()));
625 break;
626
627 case IF_DV_2E: // DV_2E ...........iiiii ......nnnnnddddd Vd Vn[] (dup - scalar)
628 elemsize = id->idOpSize();
629 index = emitGetInsSC(id);
630 assert(isValidVectorIndex(EA_16BYTE, elemsize, index));
631 assert(isValidVectorElemsize(elemsize));
632 assert(isVectorRegister(id->idReg1()));
633 assert(isVectorRegister(id->idReg2()));
634 break;
635
636 case IF_DV_2F: // DV_2F ...........iiiii .jjjj.nnnnnddddd Vd[] Vn[] (ins - element)
637 imm = emitGetInsSC(id);
638 index = (imm >> 4) & 0xf;
639 index2 = imm & 0xf;
640 elemsize = id->idOpSize();
641 assert(isValidVectorElemsize(elemsize));
642 assert(isValidVectorIndex(EA_16BYTE, elemsize, index));
643 assert(isValidVectorIndex(EA_16BYTE, elemsize, index2));
644 assert(isVectorRegister(id->idReg1()));
645 assert(isVectorRegister(id->idReg2()));
646 break;
647
648 case IF_DV_2L: // DV_2L ........XX...... ......nnnnnddddd Vd Vn (abs, neg - scalar)
649 assert(id->idOpSize() == EA_8BYTE); // only type D is supported
650 __fallthrough;
651
652 case IF_DV_2G: // DV_2G .........X...... ......nnnnnddddd Vd Vn (fmov, fcvtXX - register)
653 case IF_DV_2K: // DV_2K .........X.mmmmm ......nnnnn..... Vn Vm (fcmp)
654 assert(insOptsNone(id->idInsOpt()));
655 assert(isValidVectorElemsizeFloat(id->idOpSize()));
656 assert(isVectorRegister(id->idReg1()));
657 assert(isVectorRegister(id->idReg2()));
658 break;
659
660 case IF_DV_2H: // DV_2H X........X...... ......nnnnnddddd Rd Vn (fmov/fcvtXX - to general)
661 assert(insOptsConvertFloatToInt(id->idInsOpt()));
662 dstsize = optGetDstsize(id->idInsOpt());
663 srcsize = optGetSrcsize(id->idInsOpt());
664 assert(isValidGeneralDatasize(dstsize));
665 assert(isValidVectorElemsizeFloat(srcsize));
666 assert(dstsize == id->idOpSize());
667 assert(isGeneralRegister(id->idReg1()));
668 assert(isVectorRegister(id->idReg2()));
669 break;
670
671 case IF_DV_2I: // DV_2I X........X...... ......nnnnnddddd Vd Rn (fmov/Xcvtf - from general)
672 assert(insOptsConvertIntToFloat(id->idInsOpt()));
673 dstsize = optGetDstsize(id->idInsOpt());
674 srcsize = optGetSrcsize(id->idInsOpt());
675 assert(isValidGeneralDatasize(srcsize));
676 assert(isValidVectorElemsizeFloat(dstsize));
677 assert(dstsize == id->idOpSize());
678 assert(isVectorRegister(id->idReg1()));
679 assert(isGeneralRegister(id->idReg2()));
680 break;
681
682 case IF_DV_2J: // DV_2J ........SS.....D D.....nnnnnddddd Vd Vn (fcvt)
683 assert(insOptsConvertFloatToFloat(id->idInsOpt()));
684 dstsize = optGetDstsize(id->idInsOpt());
685 srcsize = optGetSrcsize(id->idInsOpt());
686 assert(isValidVectorFcvtsize(srcsize));
687 assert(isValidVectorFcvtsize(dstsize));
688 assert(dstsize == id->idOpSize());
689 assert(isVectorRegister(id->idReg1()));
690 assert(isVectorRegister(id->idReg2()));
691 break;
692
693 case IF_DV_3A: // DV_3A .Q......XX.mmmmm ......nnnnnddddd Vd Vn Vm (vector)
694 assert(isValidVectorDatasize(id->idOpSize()));
695 assert(isValidArrangement(id->idOpSize(), id->idInsOpt()));
696 assert(isVectorRegister(id->idReg1()));
697 assert(isVectorRegister(id->idReg2()));
698 assert(isVectorRegister(id->idReg3()));
699 elemsize = optGetElemsize(id->idInsOpt());
700 ins = id->idIns();
701 if (ins == INS_mul)
702 {
703 assert(elemsize != EA_8BYTE); // can't use 2D or 1D
704 }
705 else if (ins == INS_pmul)
706 {
707 assert(elemsize == EA_1BYTE); // only supports 8B or 16B
708 }
709 break;
710
711 case IF_DV_3AI: // DV_3AI .Q......XXLMmmmm ....H.nnnnnddddd Vd Vn Vm[] (vector by elem)
712 assert(isValidVectorDatasize(id->idOpSize()));
713 assert(isValidArrangement(id->idOpSize(), id->idInsOpt()));
714 assert(isVectorRegister(id->idReg1()));
715 assert(isVectorRegister(id->idReg2()));
716 assert(isVectorRegister(id->idReg3()));
717 elemsize = optGetElemsize(id->idInsOpt());
718 assert(isValidVectorIndex(EA_16BYTE, elemsize, emitGetInsSC(id)));
719 // Only has encodings for H or S elemsize
720 assert((elemsize == EA_2BYTE) || (elemsize == EA_4BYTE));
721 break;
722
723 case IF_DV_3B: // DV_3B .Q.......X.mmmmm ......nnnnnddddd Vd Vn Vm (vector)
724 assert(isValidVectorDatasize(id->idOpSize()));
725 assert(isValidArrangement(id->idOpSize(), id->idInsOpt()));
726 assert(isVectorRegister(id->idReg1()));
727 assert(isVectorRegister(id->idReg2()));
728 assert(isVectorRegister(id->idReg3()));
729 break;
730
731 case IF_DV_3BI: // DV_3BI .Q.......XLmmmmm ....H.nnnnnddddd Vd Vn Vm[] (vector by elem)
732 assert(isValidVectorDatasize(id->idOpSize()));
733 assert(isValidArrangement(id->idOpSize(), id->idInsOpt()));
734 assert(isVectorRegister(id->idReg1()));
735 assert(isVectorRegister(id->idReg2()));
736 assert(isVectorRegister(id->idReg3()));
737 elemsize = optGetElemsize(id->idInsOpt());
738 assert(isValidVectorIndex(id->idOpSize(), elemsize, emitGetInsSC(id)));
739 break;
740
741 case IF_DV_3C: // DV_3C .Q.........mmmmm ......nnnnnddddd Vd Vn Vm (vector)
742 assert(isValidVectorDatasize(id->idOpSize()));
743 assert(isValidArrangement(id->idOpSize(), id->idInsOpt()));
744 assert(isVectorRegister(id->idReg1()));
745 assert(isVectorRegister(id->idReg2()));
746 assert(isVectorRegister(id->idReg3()));
747 break;
748
749 case IF_DV_3D: // DV_3D .........X.mmmmm ......nnnnnddddd Vd Vn Vm (scalar)
750 assert(isValidScalarDatasize(id->idOpSize()));
751 assert(insOptsNone(id->idInsOpt()));
752 assert(isVectorRegister(id->idReg1()));
753 assert(isVectorRegister(id->idReg2()));
754 assert(isVectorRegister(id->idReg3()));
755 break;
756
757 case IF_DV_3DI: // DV_3DI .........XLmmmmm ....H.nnnnnddddd Vd Vn Vm[] (scalar by elem)
758 assert(isValidScalarDatasize(id->idOpSize()));
759 assert(insOptsNone(id->idInsOpt()));
760 assert(isVectorRegister(id->idReg1()));
761 assert(isVectorRegister(id->idReg2()));
762 assert(isVectorRegister(id->idReg3()));
763 elemsize = id->idOpSize();
764 assert(isValidVectorIndex(EA_16BYTE, elemsize, emitGetInsSC(id)));
765 break;
766
767 case IF_DV_3E: // DV_3E ...........mmmmm ......nnnnnddddd Vd Vn Vm (scalar)
768 assert(insOptsNone(id->idInsOpt()));
769 assert(id->idOpSize() == EA_8BYTE);
770 assert(isVectorRegister(id->idReg1()));
771 assert(isVectorRegister(id->idReg2()));
772 assert(isVectorRegister(id->idReg3()));
773 break;
774
775 case IF_DV_3F: // DV_3F ...........mmmmm ......nnnnnddddd Vd Vn Vm
776 assert(isValidVectorDatasize(id->idOpSize()));
777 assert(isValidArrangement(id->idOpSize(), id->idInsOpt()));
778 assert(isVectorRegister(id->idReg1()));
779 assert(isVectorRegister(id->idReg2()));
780 assert(isVectorRegister(id->idReg3()));
781 break;
782
783 case IF_DV_4A: // DR_4A .........X.mmmmm .aaaaannnnnddddd Rd Rn Rm Ra (scalar)
784 assert(isValidGeneralDatasize(id->idOpSize()));
785 assert(isVectorRegister(id->idReg1()));
786 assert(isVectorRegister(id->idReg2()));
787 assert(isVectorRegister(id->idReg3()));
788 assert(isVectorRegister(id->idReg4()));
789 break;
790
791 case IF_SN_0A: // SN_0A ................ ................
792 case IF_SI_0A: // SI_0A ...........iiiii iiiiiiiiiii..... imm16
793 case IF_SI_0B: // SI_0B ................ ....bbbb........ imm4 - barrier
794 break;
795
796 default:
797 printf("unexpected format %s\n", emitIfName(id->idInsFmt()));
798 assert(!"Unexpected format");
799 break;
800 }
801}
802#endif // DEBUG
803
804bool emitter::emitInsMayWriteToGCReg(instrDesc* id)
805{
806 instruction ins = id->idIns();
807 insFormat fmt = id->idInsFmt();
808
809 switch (fmt)
810 {
811
812 // These are the formats with "destination" registers:
813
814 case IF_DI_1B: // DI_1B X........hwiiiii iiiiiiiiiiiddddd Rd imm(i16,hw)
815 case IF_DI_1D: // DI_1D X........Nrrrrrr ssssss.....ddddd Rd imm(N,r,s)
816 case IF_DI_1E: // DI_1E .ii.....iiiiiiii iiiiiiiiiiiddddd Rd simm21
817
818 case IF_DI_2A: // DI_2A X.......shiiiiii iiiiiinnnnnddddd Rd Rn imm(i12,sh)
819 case IF_DI_2B: // DI_2B X.........Xnnnnn ssssssnnnnnddddd Rd Rn imm(0-63)
820 case IF_DI_2C: // DI_2C X........Nrrrrrr ssssssnnnnnddddd Rd Rn imm(N,r,s)
821 case IF_DI_2D: // DI_2D X........Nrrrrrr ssssssnnnnnddddd Rd Rn imr, imms (N,r,s)
822
823 case IF_DR_1D: // DR_1D X............... cccc.......ddddd Rd cond
824
825 case IF_DR_2D: // DR_2D X..........nnnnn cccc..nnnnnddddd Rd Rn cond
826 case IF_DR_2E: // DR_2E X..........mmmmm ...........ddddd Rd Rm
827 case IF_DR_2F: // DR_2F X.......sh.mmmmm ssssss.....ddddd Rd Rm {LSL,LSR,ASR} imm(0-63)
828 case IF_DR_2G: // DR_2G X............... ......nnnnnddddd Rd Rn
829 case IF_DR_2H: // DR_2H X........X...... ......nnnnnddddd Rd Rn
830
831 case IF_DR_3A: // DR_3A X..........mmmmm ......nnnnnddddd Rd Rn Rm
832 case IF_DR_3B: // DR_3B X.......sh.mmmmm ssssssnnnnnddddd Rd Rn Rm {LSL,LSR,ASR} imm(0-63)
833 case IF_DR_3C: // DR_3C X..........mmmmm xxxsssnnnnnddddd Rd Rn Rm ext(Rm) LSL imm(0-4)
834 case IF_DR_3D: // DR_3D X..........mmmmm cccc..nnnnnddddd Rd Rn Rm cond
835 case IF_DR_3E: // DR_3E X........X.mmmmm ssssssnnnnnddddd Rd Rn Rm imm(0-63)
836 case IF_DV_3F: // DV_3F ...........mmmmm ......nnnnnddddd Vd Vn Vm (vector) - Vd both source and dest
837
838 case IF_DR_4A: // DR_4A X..........mmmmm .aaaaannnnnddddd Rd Rn Rm Ra
839
840 case IF_DV_2B: // DV_2B .Q.........iiiii ......nnnnnddddd Rd Vn[] (umov - to general)
841 case IF_DV_2H: // DV_2H X........X...... ......nnnnnddddd Rd Vn (fmov - to general)
842
843 return true;
844
845 case IF_DV_2C: // DV_2C .Q.........iiiii ......nnnnnddddd Vd Rn (dup/ins - vector from general)
846 case IF_DV_2D: // DV_2D .Q.........iiiii ......nnnnnddddd Vd Vn[] (dup - vector)
847 case IF_DV_2E: // DV_2E ...........iiiii ......nnnnnddddd Vd Vn[] (dup - scalar)
848 case IF_DV_2F: // DV_2F ...........iiiii .jjjj.nnnnnddddd Vd[] Vn[] (ins - element)
849 case IF_DV_2G: // DV_2G .........X...... ......nnnnnddddd Vd Vn (fmov, fcvtXX - register)
850 case IF_DV_2I: // DV_2I X........X...... ......nnnnnddddd Vd Rn (fmov - from general)
851 case IF_DV_2J: // DV_2J ........SS.....D D.....nnnnnddddd Vd Vn (fcvt)
852 case IF_DV_2K: // DV_2K .........X.mmmmm ......nnnnn..... Vn Vm (fcmp)
853 case IF_DV_2L: // DV_2L ........XX...... ......nnnnnddddd Vd Vn (abs, neg - scalar)
854 case IF_DV_2M: // DV_2M .Q......XX...... ......nnnnnddddd Vd Vn (abs, neg - vector)
855 case IF_DV_2P: // DV_2P ................ ......nnnnnddddd Vd Vn (aes*, sha1su1) - Vd both source and
856 // destination
857
858 case IF_DV_3A: // DV_3A .Q......XX.mmmmm ......nnnnnddddd Vd Vn Vm (vector)
859 case IF_DV_3AI: // DV_3AI .Q......XXLMmmmm ....H.nnnnnddddd Vd Vn Vm[] (vector)
860 case IF_DV_3B: // DV_3B .Q.......X.mmmmm ......nnnnnddddd Vd Vn Vm (vector)
861 case IF_DV_3BI: // DV_3BI .Q.......XLmmmmm ....H.nnnnnddddd Vd Vn Vm[] (vector by elem)
862 case IF_DV_3C: // DV_3C .Q.........mmmmm ......nnnnnddddd Vd Vn Vm (vector)
863 case IF_DV_3D: // DV_3D .........X.mmmmm ......nnnnnddddd Vd Vn Vm (scalar)
864 case IF_DV_3DI: // DV_3DI .........XLmmmmm ....H.nnnnnddddd Vd Vn Vm[] (scalar by elem)
865 case IF_DV_3E: // DV_3E ...........mmmmm ......nnnnnddddd Vd Vn Vm (scalar)
866 case IF_DV_4A: // DV_4A .........X.mmmmm .aaaaannnnnddddd Vd Va Vn Vm (scalar)
867 // Tracked GC pointers cannot be placed into the SIMD registers.
868 return false;
869
870 // These are the load/store formats with "target" registers:
871
872 case IF_LS_1A: // LS_1A XX...V..iiiiiiii iiiiiiiiiiittttt Rt PC imm(1MB)
873 case IF_LS_2A: // LS_2A .X.......X...... ......nnnnnttttt Rt Rn
874 case IF_LS_2B: // LS_2B .X.......Xiiiiii iiiiiinnnnnttttt Rt Rn imm(0-4095)
875 case IF_LS_2C: // LS_2C .X.......X.iiiii iiiiP.nnnnnttttt Rt Rn imm(-256..+255) pre/post inc
876 case IF_LS_3A: // LS_3A .X.......X.mmmmm xxxS..nnnnnttttt Rt Rn Rm ext(Rm) LSL {}
877 case IF_LS_3B: // LS_3B X............... .aaaaannnnnttttt Rt Ra Rn
878 case IF_LS_3C: // LS_3C X.........iiiiii iaaaaannnnnttttt Rt Ra Rn imm(im7,sh)
879 case IF_LS_3D: // LS_3D .X.......X.mmmmm ......nnnnnttttt Wm Rt Rn
880
881 // For the Store instructions the "target" register is actually a "source" value
882
883 if (emitInsIsStore(ins))
884 {
885 return false;
886 }
887 else
888 {
889 assert(emitInsIsLoad(ins));
890 return true;
891 }
892
893 case IF_LS_3E: // LS_3E .X.........mmmmm ......nnnnnttttt Rm Rt Rn ARMv8.1 LSE Atomics
894 // ARMv8.1 Atomics
895 assert(emitInsIsStore(ins));
896 assert(emitInsIsLoad(ins));
897 return true;
898
899 default:
900 return false;
901 }
902}
903
904bool emitter::emitInsWritesToLclVarStackLoc(instrDesc* id)
905{
906 if (!id->idIsLclVar())
907 return false;
908
909 instruction ins = id->idIns();
910
911 // This list is related to the list of instructions used to store local vars in emitIns_S_R().
912 // We don't accept writing to float local vars.
913
914 switch (ins)
915 {
916 case INS_strb:
917 case INS_strh:
918 case INS_str:
919 case INS_stur:
920 case INS_sturb:
921 case INS_sturh:
922 return true;
923 default:
924 return false;
925 }
926}
927
928bool emitter::emitInsWritesToLclVarStackLocPair(instrDesc* id)
929{
930 if (!id->idIsLclVar())
931 return false;
932
933 instruction ins = id->idIns();
934
935 // This list is related to the list of instructions used to store local vars in emitIns_S_S_R_R().
936 // We don't accept writing to float local vars.
937
938 switch (ins)
939 {
940 case INS_stnp:
941 case INS_stp:
942 return true;
943 default:
944 return false;
945 }
946}
947
948bool emitter::emitInsMayWriteMultipleRegs(instrDesc* id)
949{
950 instruction ins = id->idIns();
951
952 switch (ins)
953 {
954 case INS_ldp:
955 case INS_ldpsw:
956 case INS_ldnp:
957 return true;
958 default:
959 return false;
960 }
961}
962
963// For the small loads/store instruction we adjust the size 'attr'
964// depending upon whether we have a load or a store
965//
966emitAttr emitter::emitInsAdjustLoadStoreAttr(instruction ins, emitAttr attr)
967{
968 if (EA_SIZE(attr) <= EA_4BYTE)
969 {
970 if (emitInsIsLoad(ins))
971 {
972 // The value of 'ins' encodes the size to load
973 // we use EA_8BYTE here because it is the size we will write (into dataReg)
974 // it is also required when ins is INS_ldrsw
975 //
976 attr = EA_8BYTE;
977 }
978 else
979 {
980 assert(emitInsIsStore(ins));
981
982 // The value of 'ins' encodes the size to store
983 // we use EA_4BYTE here because it is the size of the register
984 // that we want to display when storing small values
985 //
986 attr = EA_4BYTE;
987 }
988 }
989 return attr;
990}
991
992// Takes an instrDesc 'id' and uses the instruction 'ins' to determine the
993// size of the target register that is written or read by the instruction.
994// Note that even if EA_4BYTE is returned a load instruction will still
995// always zero the upper 4 bytes of the target register.
996// This method is required so that we can distinguish between loads that are
997// sign-extending as they can have two different sizes for their target register.
998// Additionally for instructions like 'ldr' and 'str' these can load/store
999// either 4 byte or 8 bytes to/from the target register.
1000// By convention the small unsigned load instructions are considered to write
1001// a 4 byte sized target register, though since these also zero the upper 4 bytes
1002// they could equally be considered to write the unsigned value to full 8 byte register.
1003//
1004emitAttr emitter::emitInsTargetRegSize(instrDesc* id)
1005{
1006 instruction ins = id->idIns();
1007 emitAttr result = EA_UNKNOWN;
1008
1009 // This is used to determine the size of the target registers for a load/store instruction
1010
1011 switch (ins)
1012 {
1013 case INS_ldxrb:
1014 case INS_ldarb:
1015 case INS_ldaxrb:
1016 case INS_stxrb:
1017 case INS_stlrb:
1018 case INS_stlxrb:
1019 case INS_ldrb:
1020 case INS_strb:
1021 case INS_ldurb:
1022 case INS_sturb:
1023 result = EA_4BYTE;
1024 break;
1025
1026 case INS_ldxrh:
1027 case INS_ldarh:
1028 case INS_ldaxrh:
1029 case INS_stxrh:
1030 case INS_stlrh:
1031 case INS_stlxrh:
1032 case INS_ldrh:
1033 case INS_strh:
1034 case INS_ldurh:
1035 case INS_sturh:
1036 result = EA_4BYTE;
1037 break;
1038
1039 case INS_ldrsb:
1040 case INS_ldursb:
1041 case INS_ldrsh:
1042 case INS_ldursh:
1043 if (id->idOpSize() == EA_8BYTE)
1044 result = EA_8BYTE;
1045 else
1046 result = EA_4BYTE;
1047 break;
1048
1049 case INS_ldrsw:
1050 case INS_ldursw:
1051 case INS_ldpsw:
1052 result = EA_8BYTE;
1053 break;
1054
1055 case INS_ldp:
1056 case INS_stp:
1057 case INS_ldnp:
1058 case INS_stnp:
1059 result = id->idOpSize();
1060 break;
1061
1062 case INS_ldxr:
1063 case INS_ldar:
1064 case INS_ldaxr:
1065 case INS_stxr:
1066 case INS_stlr:
1067 case INS_stlxr:
1068 case INS_ldr:
1069 case INS_str:
1070 case INS_ldur:
1071 case INS_stur:
1072 result = id->idOpSize();
1073 break;
1074
1075 default:
1076 NO_WAY("unexpected instruction");
1077 break;
1078 }
1079 return result;
1080}
1081
1082// Takes an instrDesc and uses the instruction to determine the 'size' of the
1083// data that is loaded from memory.
1084//
1085emitAttr emitter::emitInsLoadStoreSize(instrDesc* id)
1086{
1087 instruction ins = id->idIns();
1088 emitAttr result = EA_UNKNOWN;
1089
1090 // The 'result' returned is the 'size' of the data that is loaded from memory.
1091
1092 switch (ins)
1093 {
1094 case INS_ldarb:
1095 case INS_stlrb:
1096 case INS_ldrb:
1097 case INS_strb:
1098 case INS_ldurb:
1099 case INS_sturb:
1100 case INS_ldrsb:
1101 case INS_ldursb:
1102 result = EA_1BYTE;
1103 break;
1104
1105 case INS_ldarh:
1106 case INS_stlrh:
1107 case INS_ldrh:
1108 case INS_strh:
1109 case INS_ldurh:
1110 case INS_sturh:
1111 case INS_ldrsh:
1112 case INS_ldursh:
1113 result = EA_2BYTE;
1114 break;
1115
1116 case INS_ldrsw:
1117 case INS_ldursw:
1118 case INS_ldpsw:
1119 result = EA_4BYTE;
1120 break;
1121
1122 case INS_ldp:
1123 case INS_stp:
1124 case INS_ldnp:
1125 case INS_stnp:
1126 result = id->idOpSize();
1127 break;
1128
1129 case INS_ldar:
1130 case INS_stlr:
1131 case INS_ldr:
1132 case INS_str:
1133 case INS_ldur:
1134 case INS_stur:
1135 result = id->idOpSize();
1136 break;
1137
1138 default:
1139 NO_WAY("unexpected instruction");
1140 break;
1141 }
1142 return result;
1143}
1144
1145/*****************************************************************************/
1146#ifdef DEBUG
1147
1148// clang-format off
1149static const char * const xRegNames[] =
1150{
1151 #define REGDEF(name, rnum, mask, xname, wname) xname,
1152 #include "register.h"
1153};
1154
1155static const char * const wRegNames[] =
1156{
1157 #define REGDEF(name, rnum, mask, xname, wname) wname,
1158 #include "register.h"
1159};
1160
1161static const char * const vRegNames[] =
1162{
1163 "v0", "v1", "v2", "v3", "v4",
1164 "v5", "v6", "v7", "v8", "v9",
1165 "v10", "v11", "v12", "v13", "v14",
1166 "v15", "v16", "v17", "v18", "v19",
1167 "v20", "v21", "v22", "v23", "v24",
1168 "v25", "v26", "v27", "v28", "v29",
1169 "v30", "v31"
1170};
1171
1172static const char * const qRegNames[] =
1173{
1174 "q0", "q1", "q2", "q3", "q4",
1175 "q5", "q6", "q7", "q8", "q9",
1176 "q10", "q11", "q12", "q13", "q14",
1177 "q15", "q16", "q17", "q18", "q19",
1178 "q20", "q21", "q22", "q23", "q24",
1179 "q25", "q26", "q27", "q28", "q29",
1180 "q30", "q31"
1181};
1182
1183static const char * const hRegNames[] =
1184{
1185 "h0", "h1", "h2", "h3", "h4",
1186 "h5", "h6", "h7", "h8", "h9",
1187 "h10", "h11", "h12", "h13", "h14",
1188 "h15", "h16", "h17", "h18", "h19",
1189 "h20", "h21", "h22", "h23", "h24",
1190 "h25", "h26", "h27", "h28", "h29",
1191 "h30", "h31"
1192};
1193static const char * const bRegNames[] =
1194{
1195 "b0", "b1", "b2", "b3", "b4",
1196 "b5", "b6", "b7", "b8", "b9",
1197 "b10", "b11", "b12", "b13", "b14",
1198 "b15", "b16", "b17", "b18", "b19",
1199 "b20", "b21", "b22", "b23", "b24",
1200 "b25", "b26", "b27", "b28", "b29",
1201 "b30", "b31"
1202};
1203// clang-format on
1204
1205/*****************************************************************************
1206 *
1207 * Return a string that represents the given register.
1208 */
1209
1210const char* emitter::emitRegName(regNumber reg, emitAttr size, bool varName)
1211{
1212 assert(reg < REG_COUNT);
1213
1214 const char* rn = nullptr;
1215
1216 if (size == EA_8BYTE)
1217 {
1218 rn = xRegNames[reg];
1219 }
1220 else if (size == EA_4BYTE)
1221 {
1222 rn = wRegNames[reg];
1223 }
1224 else if (isVectorRegister(reg))
1225 {
1226 if (size == EA_16BYTE)
1227 {
1228 rn = qRegNames[reg - REG_V0];
1229 }
1230 else if (size == EA_2BYTE)
1231 {
1232 rn = hRegNames[reg - REG_V0];
1233 }
1234 else if (size == EA_1BYTE)
1235 {
1236 rn = bRegNames[reg - REG_V0];
1237 }
1238 }
1239
1240 assert(rn != nullptr);
1241
1242 return rn;
1243}
1244
1245/*****************************************************************************
1246 *
1247 * Return a string that represents the given register.
1248 */
1249
1250const char* emitter::emitVectorRegName(regNumber reg)
1251{
1252 assert((reg >= REG_V0) && (reg <= REG_V31));
1253
1254 int index = (int)reg - (int)REG_V0;
1255
1256 return vRegNames[index];
1257}
1258#endif // DEBUG
1259
1260/*****************************************************************************
1261 *
1262 * Returns the base encoding of the given CPU instruction.
1263 */
1264
1265emitter::insFormat emitter::emitInsFormat(instruction ins)
1266{
1267 // clang-format off
1268 const static insFormat insFormats[] =
1269 {
1270 #define INST1(id, nm, fp, ldst, fmt, e1 ) fmt,
1271 #define INST2(id, nm, fp, ldst, fmt, e1, e2 ) fmt,
1272 #define INST3(id, nm, fp, ldst, fmt, e1, e2, e3 ) fmt,
1273 #define INST4(id, nm, fp, ldst, fmt, e1, e2, e3, e4 ) fmt,
1274 #define INST5(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5 ) fmt,
1275 #define INST6(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6 ) fmt,
1276 #define INST9(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6, e7, e8, e9) fmt,
1277 #include "instrs.h"
1278 };
1279 // clang-format on
1280
1281 assert(ins < ArrLen(insFormats));
1282 assert((insFormats[ins] != IF_NONE));
1283
1284 return insFormats[ins];
1285}
1286
1287// INST_FP is 1
1288#define LD 2
1289#define ST 4
1290#define CMP 8
1291
1292// clang-format off
1293/*static*/ const BYTE CodeGenInterface::instInfo[] =
1294{
1295 #define INST1(id, nm, fp, ldst, fmt, e1 ) ldst | INST_FP*fp,
1296 #define INST2(id, nm, fp, ldst, fmt, e1, e2 ) ldst | INST_FP*fp,
1297 #define INST3(id, nm, fp, ldst, fmt, e1, e2, e3 ) ldst | INST_FP*fp,
1298 #define INST4(id, nm, fp, ldst, fmt, e1, e2, e3, e4 ) ldst | INST_FP*fp,
1299 #define INST5(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5 ) ldst | INST_FP*fp,
1300 #define INST6(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6 ) ldst | INST_FP*fp,
1301 #define INST9(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6, e7, e8, e9) ldst | INST_FP*fp,
1302 #include "instrs.h"
1303};
1304// clang-format on
1305
1306/*****************************************************************************
1307 *
1308 * Returns true if the instruction is some kind of compare or test instruction
1309 */
1310
1311bool emitter::emitInsIsCompare(instruction ins)
1312{
1313 // We have pseudo ins like lea which are not included in emitInsLdStTab.
1314 if (ins < ArrLen(CodeGenInterface::instInfo))
1315 return (CodeGenInterface::instInfo[ins] & CMP) ? true : false;
1316 else
1317 return false;
1318}
1319
1320/*****************************************************************************
1321 *
1322 * Returns true if the instruction is some kind of load instruction
1323 */
1324
1325bool emitter::emitInsIsLoad(instruction ins)
1326{
1327 // We have pseudo ins like lea which are not included in emitInsLdStTab.
1328 if (ins < ArrLen(CodeGenInterface::instInfo))
1329 return (CodeGenInterface::instInfo[ins] & LD) ? true : false;
1330 else
1331 return false;
1332}
1333/*****************************************************************************
1334 *
1335 * Returns true if the instruction is some kind of store instruction
1336 */
1337
1338bool emitter::emitInsIsStore(instruction ins)
1339{
1340 // We have pseudo ins like lea which are not included in emitInsLdStTab.
1341 if (ins < ArrLen(CodeGenInterface::instInfo))
1342 return (CodeGenInterface::instInfo[ins] & ST) ? true : false;
1343 else
1344 return false;
1345}
1346
1347/*****************************************************************************
1348 *
1349 * Returns true if the instruction is some kind of load/store instruction
1350 */
1351
1352bool emitter::emitInsIsLoadOrStore(instruction ins)
1353{
1354 // We have pseudo ins like lea which are not included in emitInsLdStTab.
1355 if (ins < ArrLen(CodeGenInterface::instInfo))
1356 return (CodeGenInterface::instInfo[ins] & (LD | ST)) ? true : false;
1357 else
1358 return false;
1359}
1360
1361#undef LD
1362#undef ST
1363#undef CMP
1364
1365/*****************************************************************************
1366 *
1367 * Returns the specific encoding of the given CPU instruction and format
1368 */
1369
1370emitter::code_t emitter::emitInsCode(instruction ins, insFormat fmt)
1371{
1372 // clang-format off
1373 const static code_t insCodes1[] =
1374 {
1375 #define INST1(id, nm, fp, ldst, fmt, e1 ) e1,
1376 #define INST2(id, nm, fp, ldst, fmt, e1, e2 ) e1,
1377 #define INST3(id, nm, fp, ldst, fmt, e1, e2, e3 ) e1,
1378 #define INST4(id, nm, fp, ldst, fmt, e1, e2, e3, e4 ) e1,
1379 #define INST5(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5 ) e1,
1380 #define INST6(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6 ) e1,
1381 #define INST9(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6, e7, e8, e9) e1,
1382 #include "instrs.h"
1383 };
1384 const static code_t insCodes2[] =
1385 {
1386 #define INST1(id, nm, fp, ldst, fmt, e1 )
1387 #define INST2(id, nm, fp, ldst, fmt, e1, e2 ) e2,
1388 #define INST3(id, nm, fp, ldst, fmt, e1, e2, e3 ) e2,
1389 #define INST4(id, nm, fp, ldst, fmt, e1, e2, e3, e4 ) e2,
1390 #define INST5(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5 ) e2,
1391 #define INST6(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6 ) e2,
1392 #define INST9(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6, e7, e8, e9) e2,
1393 #include "instrs.h"
1394 };
1395 const static code_t insCodes3[] =
1396 {
1397 #define INST1(id, nm, fp, ldst, fmt, e1 )
1398 #define INST2(id, nm, fp, ldst, fmt, e1, e2 )
1399 #define INST3(id, nm, fp, ldst, fmt, e1, e2, e3 ) e3,
1400 #define INST4(id, nm, fp, ldst, fmt, e1, e2, e3, e4 ) e3,
1401 #define INST5(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5 ) e3,
1402 #define INST6(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6 ) e3,
1403 #define INST9(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6, e7, e8, e9) e3,
1404 #include "instrs.h"
1405 };
1406 const static code_t insCodes4[] =
1407 {
1408 #define INST1(id, nm, fp, ldst, fmt, e1 )
1409 #define INST2(id, nm, fp, ldst, fmt, e1, e2 )
1410 #define INST3(id, nm, fp, ldst, fmt, e1, e2, e3 )
1411 #define INST4(id, nm, fp, ldst, fmt, e1, e2, e3, e4 ) e4,
1412 #define INST5(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5 ) e4,
1413 #define INST6(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6 ) e4,
1414 #define INST9(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6, e7, e8, e9) e4,
1415 #include "instrs.h"
1416 };
1417 const static code_t insCodes5[] =
1418 {
1419 #define INST1(id, nm, fp, ldst, fmt, e1 )
1420 #define INST2(id, nm, fp, ldst, fmt, e1, e2 )
1421 #define INST3(id, nm, fp, ldst, fmt, e1, e2, e3 )
1422 #define INST4(id, nm, fp, ldst, fmt, e1, e2, e3, e4 )
1423 #define INST5(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5 ) e5,
1424 #define INST6(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6 ) e5,
1425 #define INST9(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6, e7, e8, e9) e5,
1426 #include "instrs.h"
1427 };
1428 const static code_t insCodes6[] =
1429 {
1430 #define INST1(id, nm, fp, ldst, fmt, e1 )
1431 #define INST2(id, nm, fp, ldst, fmt, e1, e2 )
1432 #define INST3(id, nm, fp, ldst, fmt, e1, e2, e3 )
1433 #define INST4(id, nm, fp, ldst, fmt, e1, e2, e3, e4 )
1434 #define INST5(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5 )
1435 #define INST6(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6 ) e6,
1436 #define INST9(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6, e7, e8, e9) e6,
1437 #include "instrs.h"
1438 };
1439 const static code_t insCodes7[] =
1440 {
1441 #define INST1(id, nm, fp, ldst, fmt, e1 )
1442 #define INST2(id, nm, fp, ldst, fmt, e1, e2 )
1443 #define INST3(id, nm, fp, ldst, fmt, e1, e2, e3 )
1444 #define INST4(id, nm, fp, ldst, fmt, e1, e2, e3, e4 )
1445 #define INST5(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5 )
1446 #define INST6(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6 )
1447 #define INST9(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6, e7, e8, e9) e7,
1448 #include "instrs.h"
1449 };
1450 const static code_t insCodes8[] =
1451 {
1452 #define INST1(id, nm, fp, ldst, fmt, e1 )
1453 #define INST2(id, nm, fp, ldst, fmt, e1, e2 )
1454 #define INST3(id, nm, fp, ldst, fmt, e1, e2, e3 )
1455 #define INST4(id, nm, fp, ldst, fmt, e1, e2, e3, e4 )
1456 #define INST5(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5 )
1457 #define INST6(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6 )
1458 #define INST9(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6, e7, e8, e9) e8,
1459 #include "instrs.h"
1460 };
1461 const static code_t insCodes9[] =
1462 {
1463 #define INST1(id, nm, fp, ldst, fmt, e1 )
1464 #define INST2(id, nm, fp, ldst, fmt, e1, e2 )
1465 #define INST3(id, nm, fp, ldst, fmt, e1, e2, e3 )
1466 #define INST4(id, nm, fp, ldst, fmt, e1, e2, e3, e4 )
1467 #define INST5(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5 )
1468 #define INST6(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6 )
1469 #define INST9(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6, e7, e8, e9) e9,
1470 #include "instrs.h"
1471 };
1472 // clang-format on
1473
1474 const static insFormat formatEncode9[9] = {IF_DR_2E, IF_DR_2G, IF_DI_1B, IF_DI_1D, IF_DV_3C,
1475 IF_DV_2B, IF_DV_2C, IF_DV_2E, IF_DV_2F};
1476 const static insFormat formatEncode6A[6] = {IF_DR_3A, IF_DR_3B, IF_DR_3C, IF_DI_2A, IF_DV_3A, IF_DV_3E};
1477 const static insFormat formatEncode5A[5] = {IF_LS_2A, IF_LS_2B, IF_LS_2C, IF_LS_3A, IF_LS_1A};
1478 const static insFormat formatEncode5B[5] = {IF_DV_2G, IF_DV_2H, IF_DV_2I, IF_DV_1A, IF_DV_1B};
1479 const static insFormat formatEncode5C[5] = {IF_DR_3A, IF_DR_3B, IF_DI_2C, IF_DV_3C, IF_DV_1B};
1480 const static insFormat formatEncode4A[4] = {IF_LS_2A, IF_LS_2B, IF_LS_2C, IF_LS_3A};
1481 const static insFormat formatEncode4B[4] = {IF_DR_3A, IF_DR_3B, IF_DR_3C, IF_DI_2A};
1482 const static insFormat formatEncode4C[4] = {IF_DR_2A, IF_DR_2B, IF_DR_2C, IF_DI_1A};
1483 const static insFormat formatEncode4D[4] = {IF_DV_3B, IF_DV_3D, IF_DV_3BI, IF_DV_3DI};
1484 const static insFormat formatEncode4E[4] = {IF_DR_3A, IF_DR_3B, IF_DI_2C, IF_DV_3C};
1485 const static insFormat formatEncode4F[4] = {IF_DR_3A, IF_DR_3B, IF_DV_3C, IF_DV_1B};
1486 const static insFormat formatEncode4G[4] = {IF_DR_2E, IF_DR_2F, IF_DV_2M, IF_DV_2L};
1487 const static insFormat formatEncode4H[4] = {IF_DV_3E, IF_DV_3A, IF_DV_2L, IF_DV_2M};
1488 const static insFormat formatEncode4I[4] = {IF_DV_3D, IF_DV_3B, IF_DV_2G, IF_DV_2A};
1489 const static insFormat formatEncode3A[3] = {IF_DR_3A, IF_DR_3B, IF_DI_2C};
1490 const static insFormat formatEncode3B[3] = {IF_DR_2A, IF_DR_2B, IF_DI_1C};
1491 const static insFormat formatEncode3C[3] = {IF_DR_3A, IF_DR_3B, IF_DV_3C};
1492 const static insFormat formatEncode3D[3] = {IF_DV_2C, IF_DV_2D, IF_DV_2E};
1493 const static insFormat formatEncode3E[3] = {IF_DV_3B, IF_DV_3BI, IF_DV_3DI};
1494 const static insFormat formatEncode3F[3] = {IF_DV_2A, IF_DV_2G, IF_DV_2H};
1495 const static insFormat formatEncode3G[3] = {IF_DV_2A, IF_DV_2G, IF_DV_2I};
1496 const static insFormat formatEncode3H[3] = {IF_DR_3A, IF_DV_3A, IF_DV_3AI};
1497 const static insFormat formatEncode3I[3] = {IF_DR_2E, IF_DR_2F, IF_DV_2M};
1498 const static insFormat formatEncode2A[2] = {IF_DR_2E, IF_DR_2F};
1499 const static insFormat formatEncode2B[2] = {IF_DR_3A, IF_DR_3B};
1500 const static insFormat formatEncode2C[2] = {IF_DR_3A, IF_DI_2D};
1501 const static insFormat formatEncode2D[2] = {IF_DR_3A, IF_DI_2B};
1502 const static insFormat formatEncode2E[2] = {IF_LS_3B, IF_LS_3C};
1503 const static insFormat formatEncode2F[2] = {IF_DR_2I, IF_DI_1F};
1504 const static insFormat formatEncode2G[2] = {IF_DV_3B, IF_DV_3D};
1505 const static insFormat formatEncode2H[2] = {IF_DV_2C, IF_DV_2F};
1506 const static insFormat formatEncode2I[2] = {IF_DV_2K, IF_DV_1C};
1507 const static insFormat formatEncode2J[2] = {IF_DV_2A, IF_DV_2G};
1508 const static insFormat formatEncode2K[2] = {IF_DV_2M, IF_DV_2L};
1509 const static insFormat formatEncode2L[2] = {IF_DR_2G, IF_DV_2M};
1510 const static insFormat formatEncode2M[2] = {IF_DV_3A, IF_DV_3AI};
1511 const static insFormat formatEncode2N[2] = {IF_DV_2N, IF_DV_2O};
1512 const static insFormat formatEncode2O[2] = {IF_DV_3E, IF_DV_3A};
1513 const static insFormat formatEncode2P[2] = {IF_DV_2G, IF_DV_3B};
1514
1515 code_t code = BAD_CODE;
1516 insFormat insFmt = emitInsFormat(ins);
1517 bool encoding_found = false;
1518 int index = -1;
1519
1520 switch (insFmt)
1521 {
1522 case IF_EN9:
1523 for (index = 0; index < 9; index++)
1524 {
1525 if (fmt == formatEncode9[index])
1526 {
1527 encoding_found = true;
1528 break;
1529 }
1530 }
1531 break;
1532
1533 case IF_EN6A:
1534 for (index = 0; index < 6; index++)
1535 {
1536 if (fmt == formatEncode6A[index])
1537 {
1538 encoding_found = true;
1539 break;
1540 }
1541 }
1542 break;
1543
1544 case IF_EN5A:
1545 for (index = 0; index < 5; index++)
1546 {
1547 if (fmt == formatEncode5A[index])
1548 {
1549 encoding_found = true;
1550 break;
1551 }
1552 }
1553 break;
1554
1555 case IF_EN5B:
1556 for (index = 0; index < 5; index++)
1557 {
1558 if (fmt == formatEncode5B[index])
1559 {
1560 encoding_found = true;
1561 break;
1562 }
1563 }
1564 break;
1565
1566 case IF_EN5C:
1567 for (index = 0; index < 5; index++)
1568 {
1569 if (fmt == formatEncode5C[index])
1570 {
1571 encoding_found = true;
1572 break;
1573 }
1574 }
1575 break;
1576
1577 case IF_EN4A:
1578 for (index = 0; index < 4; index++)
1579 {
1580 if (fmt == formatEncode4A[index])
1581 {
1582 encoding_found = true;
1583 break;
1584 }
1585 }
1586 break;
1587
1588 case IF_EN4B:
1589 for (index = 0; index < 4; index++)
1590 {
1591 if (fmt == formatEncode4B[index])
1592 {
1593 encoding_found = true;
1594 break;
1595 }
1596 }
1597 break;
1598
1599 case IF_EN4C:
1600 for (index = 0; index < 4; index++)
1601 {
1602 if (fmt == formatEncode4C[index])
1603 {
1604 encoding_found = true;
1605 break;
1606 }
1607 }
1608 break;
1609
1610 case IF_EN4D:
1611 for (index = 0; index < 4; index++)
1612 {
1613 if (fmt == formatEncode4D[index])
1614 {
1615 encoding_found = true;
1616 break;
1617 }
1618 }
1619 break;
1620
1621 case IF_EN4E:
1622 for (index = 0; index < 4; index++)
1623 {
1624 if (fmt == formatEncode4E[index])
1625 {
1626 encoding_found = true;
1627 break;
1628 }
1629 }
1630 break;
1631
1632 case IF_EN4F:
1633 for (index = 0; index < 4; index++)
1634 {
1635 if (fmt == formatEncode4F[index])
1636 {
1637 encoding_found = true;
1638 break;
1639 }
1640 }
1641 break;
1642
1643 case IF_EN4G:
1644 for (index = 0; index < 4; index++)
1645 {
1646 if (fmt == formatEncode4G[index])
1647 {
1648 encoding_found = true;
1649 break;
1650 }
1651 }
1652 break;
1653
1654 case IF_EN4H:
1655 for (index = 0; index < 4; index++)
1656 {
1657 if (fmt == formatEncode4H[index])
1658 {
1659 encoding_found = true;
1660 break;
1661 }
1662 }
1663 break;
1664
1665 case IF_EN4I:
1666 for (index = 0; index < 4; index++)
1667 {
1668 if (fmt == formatEncode4I[index])
1669 {
1670 encoding_found = true;
1671 break;
1672 }
1673 }
1674 break;
1675
1676 case IF_EN3A:
1677 for (index = 0; index < 3; index++)
1678 {
1679 if (fmt == formatEncode3A[index])
1680 {
1681 encoding_found = true;
1682 break;
1683 }
1684 }
1685 break;
1686
1687 case IF_EN3B:
1688 for (index = 0; index < 3; index++)
1689 {
1690 if (fmt == formatEncode3B[index])
1691 {
1692 encoding_found = true;
1693 break;
1694 }
1695 }
1696 break;
1697
1698 case IF_EN3C:
1699 for (index = 0; index < 3; index++)
1700 {
1701 if (fmt == formatEncode3C[index])
1702 {
1703 encoding_found = true;
1704 break;
1705 }
1706 }
1707 break;
1708
1709 case IF_EN3D:
1710 for (index = 0; index < 3; index++)
1711 {
1712 if (fmt == formatEncode3D[index])
1713 {
1714 encoding_found = true;
1715 break;
1716 }
1717 }
1718 break;
1719
1720 case IF_EN3E:
1721 for (index = 0; index < 3; index++)
1722 {
1723 if (fmt == formatEncode3E[index])
1724 {
1725 encoding_found = true;
1726 break;
1727 }
1728 }
1729 break;
1730
1731 case IF_EN3F:
1732 for (index = 0; index < 3; index++)
1733 {
1734 if (fmt == formatEncode3F[index])
1735 {
1736 encoding_found = true;
1737 break;
1738 }
1739 }
1740 break;
1741
1742 case IF_EN3G:
1743 for (index = 0; index < 3; index++)
1744 {
1745 if (fmt == formatEncode3G[index])
1746 {
1747 encoding_found = true;
1748 break;
1749 }
1750 }
1751 break;
1752
1753 case IF_EN3H:
1754 for (index = 0; index < 3; index++)
1755 {
1756 if (fmt == formatEncode3H[index])
1757 {
1758 encoding_found = true;
1759 break;
1760 }
1761 }
1762 break;
1763
1764 case IF_EN3I:
1765 for (index = 0; index < 3; index++)
1766 {
1767 if (fmt == formatEncode3I[index])
1768 {
1769 encoding_found = true;
1770 break;
1771 }
1772 }
1773 break;
1774
1775 case IF_EN2A:
1776 for (index = 0; index < 2; index++)
1777 {
1778 if (fmt == formatEncode2A[index])
1779 {
1780 encoding_found = true;
1781 break;
1782 }
1783 }
1784 break;
1785
1786 case IF_EN2B:
1787 for (index = 0; index < 2; index++)
1788 {
1789 if (fmt == formatEncode2B[index])
1790 {
1791 encoding_found = true;
1792 break;
1793 }
1794 }
1795 break;
1796
1797 case IF_EN2C:
1798 for (index = 0; index < 2; index++)
1799 {
1800 if (fmt == formatEncode2C[index])
1801 {
1802 encoding_found = true;
1803 break;
1804 }
1805 }
1806 break;
1807
1808 case IF_EN2D:
1809 for (index = 0; index < 2; index++)
1810 {
1811 if (fmt == formatEncode2D[index])
1812 {
1813 encoding_found = true;
1814 break;
1815 }
1816 }
1817 break;
1818
1819 case IF_EN2E:
1820 for (index = 0; index < 2; index++)
1821 {
1822 if (fmt == formatEncode2E[index])
1823 {
1824 encoding_found = true;
1825 break;
1826 }
1827 }
1828 break;
1829
1830 case IF_EN2F:
1831 for (index = 0; index < 2; index++)
1832 {
1833 if (fmt == formatEncode2F[index])
1834 {
1835 encoding_found = true;
1836 break;
1837 }
1838 }
1839 break;
1840
1841 case IF_EN2G:
1842 for (index = 0; index < 2; index++)
1843 {
1844 if (fmt == formatEncode2G[index])
1845 {
1846 encoding_found = true;
1847 break;
1848 }
1849 }
1850 break;
1851
1852 case IF_EN2H:
1853 for (index = 0; index < 2; index++)
1854 {
1855 if (fmt == formatEncode2H[index])
1856 {
1857 encoding_found = true;
1858 break;
1859 }
1860 }
1861 break;
1862
1863 case IF_EN2I:
1864 for (index = 0; index < 2; index++)
1865 {
1866 if (fmt == formatEncode2I[index])
1867 {
1868 encoding_found = true;
1869 break;
1870 }
1871 }
1872 break;
1873
1874 case IF_EN2J:
1875 for (index = 0; index < 2; index++)
1876 {
1877 if (fmt == formatEncode2J[index])
1878 {
1879 encoding_found = true;
1880 break;
1881 }
1882 }
1883 break;
1884
1885 case IF_EN2K:
1886 for (index = 0; index < 2; index++)
1887 {
1888 if (fmt == formatEncode2K[index])
1889 {
1890 encoding_found = true;
1891 break;
1892 }
1893 }
1894 break;
1895
1896 case IF_EN2L:
1897 for (index = 0; index < 2; index++)
1898 {
1899 if (fmt == formatEncode2L[index])
1900 {
1901 encoding_found = true;
1902 break;
1903 }
1904 }
1905 break;
1906
1907 case IF_EN2M:
1908 for (index = 0; index < 2; index++)
1909 {
1910 if (fmt == formatEncode2M[index])
1911 {
1912 encoding_found = true;
1913 break;
1914 }
1915 }
1916 break;
1917
1918 case IF_EN2N:
1919 for (index = 0; index < 2; index++)
1920 {
1921 if (fmt == formatEncode2N[index])
1922 {
1923 encoding_found = true;
1924 break;
1925 }
1926 }
1927 break;
1928
1929 case IF_EN2O:
1930 for (index = 0; index < 2; index++)
1931 {
1932 if (fmt == formatEncode2O[index])
1933 {
1934 encoding_found = true;
1935 break;
1936 }
1937 }
1938 break;
1939
1940 case IF_EN2P:
1941 for (index = 0; index < 2; index++)
1942 {
1943 if (fmt == formatEncode2P[index])
1944 {
1945 encoding_found = true;
1946 break;
1947 }
1948 }
1949 break;
1950
1951 case IF_BI_0A:
1952 case IF_BI_0B:
1953 case IF_BI_0C:
1954 case IF_BI_1A:
1955 case IF_BI_1B:
1956 case IF_BR_1A:
1957 case IF_BR_1B:
1958 case IF_LS_1A:
1959 case IF_LS_2A:
1960 case IF_LS_2B:
1961 case IF_LS_2C:
1962 case IF_LS_3A:
1963 case IF_LS_3B:
1964 case IF_LS_3C:
1965 case IF_LS_3D:
1966 case IF_LS_3E:
1967 case IF_DI_1A:
1968 case IF_DI_1B:
1969 case IF_DI_1C:
1970 case IF_DI_1D:
1971 case IF_DI_1E:
1972 case IF_DI_1F:
1973 case IF_DI_2A:
1974 case IF_DI_2B:
1975 case IF_DI_2C:
1976 case IF_DI_2D:
1977 case IF_DR_1D:
1978 case IF_DR_2A:
1979 case IF_DR_2B:
1980 case IF_DR_2C:
1981 case IF_DR_2D:
1982 case IF_DR_2E:
1983 case IF_DR_2F:
1984 case IF_DR_2G:
1985 case IF_DR_2H:
1986 case IF_DR_2I:
1987 case IF_DR_2J:
1988 case IF_DR_3A:
1989 case IF_DR_3B:
1990 case IF_DR_3C:
1991 case IF_DR_3D:
1992 case IF_DR_3E:
1993 case IF_DR_4A:
1994 case IF_DV_1A:
1995 case IF_DV_1B:
1996 case IF_DV_1C:
1997 case IF_DV_2A:
1998 case IF_DV_2B:
1999 case IF_DV_2C:
2000 case IF_DV_2D:
2001 case IF_DV_2E:
2002 case IF_DV_2F:
2003 case IF_DV_2G:
2004 case IF_DV_2H:
2005 case IF_DV_2I:
2006 case IF_DV_2J:
2007 case IF_DV_2K:
2008 case IF_DV_2L:
2009 case IF_DV_2M:
2010 case IF_DV_2N:
2011 case IF_DV_2O:
2012 case IF_DV_2P:
2013 case IF_DV_3A:
2014 case IF_DV_3AI:
2015 case IF_DV_3B:
2016 case IF_DV_3BI:
2017 case IF_DV_3C:
2018 case IF_DV_3D:
2019 case IF_DV_3DI:
2020 case IF_DV_3E:
2021 case IF_DV_3F:
2022 case IF_DV_4A:
2023 case IF_SN_0A:
2024 case IF_SI_0A:
2025 case IF_SI_0B:
2026
2027 index = 0;
2028 encoding_found = true;
2029 break;
2030
2031 default:
2032
2033 encoding_found = false;
2034 break;
2035 }
2036
2037 assert(encoding_found);
2038
2039 switch (index)
2040 {
2041 case 0:
2042 assert(ins < ArrLen(insCodes1));
2043 code = insCodes1[ins];
2044 break;
2045 case 1:
2046 assert(ins < ArrLen(insCodes2));
2047 code = insCodes2[ins];
2048 break;
2049 case 2:
2050 assert(ins < ArrLen(insCodes3));
2051 code = insCodes3[ins];
2052 break;
2053 case 3:
2054 assert(ins < ArrLen(insCodes4));
2055 code = insCodes4[ins];
2056 break;
2057 case 4:
2058 assert(ins < ArrLen(insCodes5));
2059 code = insCodes5[ins];
2060 break;
2061 case 5:
2062 assert(ins < ArrLen(insCodes6));
2063 code = insCodes6[ins];
2064 break;
2065 case 6:
2066 assert(ins < ArrLen(insCodes7));
2067 code = insCodes7[ins];
2068 break;
2069 case 7:
2070 assert(ins < ArrLen(insCodes8));
2071 code = insCodes8[ins];
2072 break;
2073 case 8:
2074 assert(ins < ArrLen(insCodes9));
2075 code = insCodes9[ins];
2076 break;
2077 }
2078
2079 assert((code != BAD_CODE));
2080
2081 return code;
2082}
2083
2084// true if this 'imm' can be encoded as a input operand to a mov instruction
2085/*static*/ bool emitter::emitIns_valid_imm_for_mov(INT64 imm, emitAttr size)
2086{
2087 // Check for "MOV (wide immediate)".
2088 if (canEncodeHalfwordImm(imm, size))
2089 return true;
2090
2091 // Next try the ones-complement form of 'halfword immediate' imm(i16,hw),
2092 // namely "MOV (inverted wide immediate)".
2093 ssize_t notOfImm = NOT_helper(imm, getBitWidth(size));
2094 if (canEncodeHalfwordImm(notOfImm, size))
2095 return true;
2096
2097 // Finally try "MOV (bitmask immediate)" imm(N,r,s)
2098 if (canEncodeBitMaskImm(imm, size))
2099 return true;
2100
2101 return false;
2102}
2103
2104// true if this 'imm' can be encoded as a input operand to a vector movi instruction
2105/*static*/ bool emitter::emitIns_valid_imm_for_movi(INT64 imm, emitAttr elemsize)
2106{
2107 if (elemsize == EA_8BYTE)
2108 {
2109 UINT64 uimm = imm;
2110 while (uimm != 0)
2111 {
2112 INT64 loByte = uimm & 0xFF;
2113 if ((loByte == 0) || (loByte == 0xFF))
2114 {
2115 uimm >>= 8;
2116 }
2117 else
2118 {
2119 return false;
2120 }
2121 }
2122 assert(uimm == 0);
2123 return true;
2124 }
2125 else
2126 {
2127 // First try the standard 'byteShifted immediate' imm(i8,bySh)
2128 if (canEncodeByteShiftedImm(imm, elemsize, true))
2129 return true;
2130
2131 // Next try the ones-complement form of the 'immediate' imm(i8,bySh)
2132 ssize_t notOfImm = NOT_helper(imm, getBitWidth(elemsize));
2133 if (canEncodeByteShiftedImm(notOfImm, elemsize, true))
2134 return true;
2135 }
2136 return false;
2137}
2138
2139// true if this 'imm' can be encoded as a input operand to a fmov instruction
2140/*static*/ bool emitter::emitIns_valid_imm_for_fmov(double immDbl)
2141{
2142 if (canEncodeFloatImm8(immDbl))
2143 return true;
2144
2145 return false;
2146}
2147
2148// true if this 'imm' can be encoded as a input operand to an add instruction
2149/*static*/ bool emitter::emitIns_valid_imm_for_add(INT64 imm, emitAttr size)
2150{
2151 if (unsigned_abs(imm) <= 0x0fff)
2152 return true;
2153 else if (canEncodeWithShiftImmBy12(imm)) // Try the shifted by 12 encoding
2154 return true;
2155
2156 return false;
2157}
2158
2159// true if this 'imm' can be encoded as a input operand to an non-add/sub alu instruction
2160/*static*/ bool emitter::emitIns_valid_imm_for_cmp(INT64 imm, emitAttr size)
2161{
2162 return emitIns_valid_imm_for_add(imm, size);
2163}
2164
2165// true if this 'imm' can be encoded as a input operand to an non-add/sub alu instruction
2166/*static*/ bool emitter::emitIns_valid_imm_for_alu(INT64 imm, emitAttr size)
2167{
2168 if (canEncodeBitMaskImm(imm, size))
2169 return true;
2170
2171 return false;
2172}
2173
2174// true if this 'imm' can be encoded as the offset in a ldr/str instruction
2175/*static*/ bool emitter::emitIns_valid_imm_for_ldst_offset(INT64 imm, emitAttr attr)
2176{
2177 if (imm == 0)
2178 return true; // Encodable using IF_LS_2A
2179
2180 if ((imm >= -256) && (imm <= 255))
2181 return true; // Encodable using IF_LS_2C (or possibly IF_LS_2B)
2182
2183 if (imm < 0)
2184 return false; // not encodable
2185
2186 emitAttr size = EA_SIZE(attr);
2187 unsigned scale = NaturalScale_helper(size);
2188 ssize_t mask = size - 1; // the mask of low bits that must be zero to encode the immediate
2189
2190 if (((imm & mask) == 0) && ((imm >> scale) < 0x1000))
2191 return true; // Encodable using IF_LS_2B
2192
2193 return false; // not encodable
2194}
2195
2196/************************************************************************
2197 *
2198 * A helper method to return the natural scale for an EA 'size'
2199 */
2200
2201/*static*/ unsigned emitter::NaturalScale_helper(emitAttr size)
2202{
2203 assert(size == EA_1BYTE || size == EA_2BYTE || size == EA_4BYTE || size == EA_8BYTE || size == EA_16BYTE);
2204
2205 unsigned result = 0;
2206 unsigned utemp = (unsigned)size;
2207
2208 // Compute log base 2 of utemp (aka 'size')
2209 while (utemp > 1)
2210 {
2211 result++;
2212 utemp >>= 1;
2213 }
2214
2215 return result;
2216}
2217
2218/************************************************************************
2219 *
2220 * A helper method to perform a Rotate-Right shift operation
2221 * the source is 'value' and it is rotated right by 'sh' bits
2222 * 'value' is considered to be a fixed size 'width' set of bits.
2223 *
2224 * Example
2225 * value is '00001111', sh is 2 and width is 8
2226 * result is '11000011'
2227 */
2228
2229/*static*/ UINT64 emitter::ROR_helper(UINT64 value, unsigned sh, unsigned width)
2230{
2231 assert(width <= 64);
2232 // Check that 'value' fits in 'width' bits
2233 assert((width == 64) || (value < (1ULL << width)));
2234 // We don't support shifts >= width
2235 assert(sh < width);
2236
2237 UINT64 result;
2238
2239 unsigned rsh = sh;
2240 unsigned lsh = width - rsh;
2241
2242 result = (value >> rsh);
2243 result |= (value << lsh);
2244
2245 if (width < 64)
2246 {
2247 // mask off any extra bits that we got from the left shift
2248 result &= ((1ULL << width) - 1);
2249 }
2250 return result;
2251}
2252/************************************************************************
2253 *
2254 * A helper method to perform a 'NOT' bitwise complement operation.
2255 * 'value' is considered to be a fixed size 'width' set of bits.
2256 *
2257 * Example
2258 * value is '01001011', and width is 8
2259 * result is '10110100'
2260 */
2261
2262/*static*/ UINT64 emitter::NOT_helper(UINT64 value, unsigned width)
2263{
2264 assert(width <= 64);
2265
2266 UINT64 result = ~value;
2267
2268 if (width < 64)
2269 {
2270 // Check that 'value' fits in 'width' bits. Don't consider "sign" bits above width.
2271 UINT64 maxVal = 1ULL << width;
2272 UINT64 lowBitsMask = maxVal - 1;
2273 UINT64 signBitsMask = ~lowBitsMask | (1ULL << (width - 1)); // The high bits must be set, and the top bit
2274 // (sign bit) must be set.
2275 assert((value < maxVal) || ((value & signBitsMask) == signBitsMask));
2276
2277 // mask off any extra bits that we got from the complement operation
2278 result &= lowBitsMask;
2279 }
2280
2281 return result;
2282}
2283
2284/************************************************************************
2285 *
2286 * A helper method to perform a bit Replicate operation
2287 * the source is 'value' with a fixed size 'width' set of bits.
2288 * value is replicated to fill out 32 or 64 bits as determined by 'size'.
2289 *
2290 * Example
2291 * value is '11000011' (0xE3), width is 8 and size is EA_8BYTE
2292 * result is '11000011 11000011 11000011 11000011 11000011 11000011 11000011 11000011'
2293 * 0xE3E3E3E3E3E3E3E3
2294 */
2295
2296/*static*/ UINT64 emitter::Replicate_helper(UINT64 value, unsigned width, emitAttr size)
2297{
2298 assert(emitter::isValidGeneralDatasize(size));
2299
2300 unsigned immWidth = (size == EA_8BYTE) ? 64 : 32;
2301 assert(width <= immWidth);
2302
2303 UINT64 result = value;
2304 unsigned filledBits = width;
2305
2306 while (filledBits < immWidth)
2307 {
2308 value <<= width;
2309 result |= value;
2310 filledBits += width;
2311 }
2312 return result;
2313}
2314
2315/************************************************************************
2316 *
2317 * Convert an imm(N,r,s) into a 64-bit immediate
2318 * inputs 'bmImm' a bitMaskImm struct
2319 * 'size' specifies the size of the result (64 or 32 bits)
2320 */
2321
2322/*static*/ INT64 emitter::emitDecodeBitMaskImm(const emitter::bitMaskImm bmImm, emitAttr size)
2323{
2324 assert(isValidGeneralDatasize(size)); // Only EA_4BYTE or EA_8BYTE forms
2325
2326 unsigned N = bmImm.immN; // read the N,R and S values from the 'bitMaskImm' encoding
2327 unsigned R = bmImm.immR;
2328 unsigned S = bmImm.immS;
2329
2330 unsigned elemWidth = 64; // used when immN == 1
2331
2332 if (bmImm.immN == 0) // find the smaller elemWidth when immN == 0
2333 {
2334 // Scan S for the highest bit not set
2335 elemWidth = 32;
2336 for (unsigned bitNum = 5; bitNum > 0; bitNum--)
2337 {
2338 unsigned oneBit = elemWidth;
2339 if ((S & oneBit) == 0)
2340 break;
2341 elemWidth /= 2;
2342 }
2343 }
2344 else
2345 {
2346 assert(size == EA_8BYTE);
2347 }
2348
2349 unsigned maskSR = elemWidth - 1;
2350
2351 S &= maskSR;
2352 R &= maskSR;
2353
2354 // encoding for S is one less than the number of consecutive one bits
2355 S++; // Number of consecutive ones to generate in 'welem'
2356
2357 // At this point:
2358 //
2359 // 'elemWidth' is the number of bits that we will use for the ROR and Replicate operations
2360 // 'S' is the number of consecutive 1 bits for the immediate
2361 // 'R' is the number of bits that we will Rotate Right the immediate
2362 // 'size' selects the final size of the immedate that we return (64 or 32 bits)
2363
2364 assert(S < elemWidth); // 'elemWidth' consecutive one's is a reserved encoding
2365
2366 UINT64 welem;
2367 UINT64 wmask;
2368
2369 welem = (1ULL << S) - 1;
2370
2371 wmask = ROR_helper(welem, R, elemWidth);
2372 wmask = Replicate_helper(wmask, elemWidth, size);
2373
2374 return wmask;
2375}
2376
2377/*****************************************************************************
2378 *
2379 * Check if an immediate can use the left shifted by 12 bits encoding
2380 */
2381
2382/*static*/ bool emitter::canEncodeWithShiftImmBy12(INT64 imm)
2383{
2384 if (imm < 0)
2385 {
2386 imm = -imm; // convert to unsigned
2387 }
2388
2389 if (imm < 0)
2390 {
2391 return false; // Must be MIN_INT64
2392 }
2393
2394 if ((imm & 0xfff) != 0) // Now the low 12 bits all have to be zero
2395 {
2396 return false;
2397 }
2398
2399 imm >>= 12; // shift right by 12 bits
2400
2401 return (imm <= 0x0fff); // Does it fit in 12 bits
2402}
2403
2404/*****************************************************************************
2405 *
2406 * Normalize the 'imm' so that the upper bits, as defined by 'size' are zero
2407 */
2408
2409/*static*/ INT64 emitter::normalizeImm64(INT64 imm, emitAttr size)
2410{
2411 unsigned immWidth = getBitWidth(size);
2412 INT64 result = imm;
2413
2414 if (immWidth < 64)
2415 {
2416 // Check that 'imm' fits in 'immWidth' bits. Don't consider "sign" bits above width.
2417 INT64 maxVal = 1LL << immWidth;
2418 INT64 lowBitsMask = maxVal - 1;
2419 INT64 hiBitsMask = ~lowBitsMask;
2420 INT64 signBitsMask =
2421 hiBitsMask | (1LL << (immWidth - 1)); // The high bits must be set, and the top bit (sign bit) must be set.
2422 assert((imm < maxVal) || ((imm & signBitsMask) == signBitsMask));
2423
2424 // mask off the hiBits
2425 result &= lowBitsMask;
2426 }
2427 return result;
2428}
2429
2430/*****************************************************************************
2431 *
2432 * Normalize the 'imm' so that the upper bits, as defined by 'size' are zero
2433 */
2434
2435/*static*/ INT32 emitter::normalizeImm32(INT32 imm, emitAttr size)
2436{
2437 unsigned immWidth = getBitWidth(size);
2438 INT32 result = imm;
2439
2440 if (immWidth < 32)
2441 {
2442 // Check that 'imm' fits in 'immWidth' bits. Don't consider "sign" bits above width.
2443 INT32 maxVal = 1 << immWidth;
2444 INT32 lowBitsMask = maxVal - 1;
2445 INT32 hiBitsMask = ~lowBitsMask;
2446 INT32 signBitsMask = hiBitsMask | (1 << (immWidth - 1)); // The high bits must be set, and the top bit
2447 // (sign bit) must be set.
2448 assert((imm < maxVal) || ((imm & signBitsMask) == signBitsMask));
2449
2450 // mask off the hiBits
2451 result &= lowBitsMask;
2452 }
2453 return result;
2454}
2455
2456/************************************************************************
2457 *
2458 * returns true if 'imm' of 'size bits (32/64) can be encoded
2459 * using the ARM64 'bitmask immediate' form.
2460 * When a non-null value is passed for 'wbBMI' then this method
2461 * writes back the 'N','S' and 'R' values use to encode this immediate
2462 *
2463 */
2464
2465/*static*/ bool emitter::canEncodeBitMaskImm(INT64 imm, emitAttr size, emitter::bitMaskImm* wbBMI)
2466{
2467 assert(isValidGeneralDatasize(size)); // Only EA_4BYTE or EA_8BYTE forms
2468
2469 unsigned immWidth = (size == EA_8BYTE) ? 64 : 32;
2470 unsigned maxLen = (size == EA_8BYTE) ? 6 : 5;
2471
2472 imm = normalizeImm64(imm, size);
2473
2474 // Starting with len=1, elemWidth is 2 bits
2475 // len=2, elemWidth is 4 bits
2476 // len=3, elemWidth is 8 bits
2477 // len=4, elemWidth is 16 bits
2478 // len=5, elemWidth is 32 bits
2479 // (optionally) len=6, elemWidth is 64 bits
2480 //
2481 for (unsigned len = 1; (len <= maxLen); len++)
2482 {
2483 unsigned elemWidth = 1 << len;
2484 UINT64 elemMask = ((UINT64)-1) >> (64 - elemWidth);
2485 UINT64 tempImm = (UINT64)imm; // A working copy of 'imm' that we can mutate
2486 UINT64 elemVal = tempImm & elemMask; // The low 'elemWidth' bits of 'imm'
2487
2488 // Check for all 1's or 0's as these can't be encoded
2489 if ((elemVal == 0) || (elemVal == elemMask))
2490 continue;
2491
2492 // 'checkedBits' is the count of bits that are known to match 'elemVal' when replicated
2493 unsigned checkedBits = elemWidth; // by definition the first 'elemWidth' bits match
2494
2495 // Now check to see if each of the next bits match...
2496 //
2497 while (checkedBits < immWidth)
2498 {
2499 tempImm >>= elemWidth;
2500
2501 UINT64 nextElem = tempImm & elemMask;
2502 if (nextElem != elemVal)
2503 {
2504 // Not matching, exit this loop and checkedBits will not be equal to immWidth
2505 break;
2506 }
2507
2508 // The 'nextElem' is matching, so increment 'checkedBits'
2509 checkedBits += elemWidth;
2510 }
2511
2512 // Did the full immediate contain bits that can be formed by repeating 'elemVal'?
2513 if (checkedBits == immWidth)
2514 {
2515 // We are not quite done, since the only values that we can encode as a
2516 // 'bitmask immediate' are those that can be formed by starting with a
2517 // bit string of 0*1* that is rotated by some number of bits.
2518 //
2519 // We check to see if 'elemVal' can be formed using these restrictions.
2520 //
2521 // Observation:
2522 // Rotating by one bit any value that passes these restrictions
2523 // can be xor-ed with the original value and will result it a string
2524 // of bits that have exactly two 1 bits: 'elemRorXor'
2525 // Further the distance between the two one bits tells us the value
2526 // of S and the location of the 1 bits tells us the value of R
2527 //
2528 // Some examples: (immWidth is 8)
2529 //
2530 // S=4,R=0 S=5,R=3 S=3,R=6
2531 // elemVal: 00001111 11100011 00011100
2532 // elemRor: 10000111 11110001 00001110
2533 // elemRorXor: 10001000 00010010 00010010
2534 // compute S 45678--- ---5678- ---3210-
2535 // compute R 01234567 ---34567 ------67
2536
2537 UINT64 elemRor = ROR_helper(elemVal, 1, elemWidth); // Rotate 'elemVal' Right by one bit
2538 UINT64 elemRorXor = elemVal ^ elemRor; // Xor elemVal and elemRor
2539
2540 // If we only have a two-bit change in elemROR then we can form a mask for this value
2541 unsigned bitCount = 0;
2542 UINT64 oneBit = 0x1;
2543 unsigned R = elemWidth; // R is shift count for ROR (rotate right shift)
2544 unsigned S = 0; // S is number of consecutive one bits
2545 int incr = -1;
2546
2547 // Loop over the 'elemWidth' bits in 'elemRorXor'
2548 //
2549 for (unsigned bitNum = 0; bitNum < elemWidth; bitNum++)
2550 {
2551 if (incr == -1)
2552 {
2553 R--; // We decrement R by one whenever incr is -1
2554 }
2555 if (bitCount == 1)
2556 {
2557 S += incr; // We incr/decr S, after we find the first one bit in 'elemRorXor'
2558 }
2559
2560 // Is this bit position a 1 bit in 'elemRorXor'?
2561 //
2562 if (oneBit & elemRorXor)
2563 {
2564 bitCount++;
2565 // Is this the first 1 bit that we found in 'elemRorXor'?
2566 if (bitCount == 1)
2567 {
2568 // Does this 1 bit represent a transition to zero bits?
2569 bool toZeros = ((oneBit & elemVal) != 0);
2570 if (toZeros)
2571 {
2572 // S :: Count down from elemWidth
2573 S = elemWidth;
2574 incr = -1;
2575 }
2576 else // this 1 bit represent a transition to one bits.
2577 {
2578 // S :: Count up from zero
2579 S = 0;
2580 incr = +1;
2581 }
2582 }
2583 else // bitCount > 1
2584 {
2585 // We found the second (or third...) 1 bit in 'elemRorXor'
2586 incr = 0; // stop decrementing 'R'
2587
2588 if (bitCount > 2)
2589 {
2590 // More than 2 transitions from 0/1 in 'elemVal'
2591 // This means that 'elemVal' can't be encoded
2592 // using a 'bitmask immediate'.
2593 //
2594 // Furthermore, it will continue to fail
2595 // with any larger 'len' that we try.
2596 // so just return false.
2597 //
2598 return false;
2599 }
2600 }
2601 }
2602
2603 // shift oneBit left by one bit to test the next position
2604 oneBit <<= 1;
2605 }
2606
2607 // We expect that bitCount will always be two at this point
2608 // but just in case return false for any bad cases.
2609 //
2610 assert(bitCount == 2);
2611 if (bitCount != 2)
2612 return false;
2613
2614 // Perform some sanity checks on the values of 'S' and 'R'
2615 assert(S > 0);
2616 assert(S < elemWidth);
2617 assert(R < elemWidth);
2618
2619 // Does the caller want us to return the N,R,S encoding values?
2620 //
2621 if (wbBMI != nullptr)
2622 {
2623
2624 // The encoding used for S is one less than the
2625 // number of consecutive one bits
2626 S--;
2627
2628 if (len == 6)
2629 {
2630 wbBMI->immN = 1;
2631 }
2632 else
2633 {
2634 wbBMI->immN = 0;
2635 // The encoding used for 'S' here is a bit peculiar.
2636 //
2637 // The upper bits need to be complemented, followed by a zero bit
2638 // then the value of 'S-1'
2639 //
2640 unsigned upperBitsOfS = 64 - (1 << (len + 1));
2641 S |= upperBitsOfS;
2642 }
2643 wbBMI->immR = R;
2644 wbBMI->immS = S;
2645
2646 // Verify that what we are returning is correct.
2647 assert(imm == emitDecodeBitMaskImm(*wbBMI, size));
2648 }
2649 // Tell the caller that we can successfully encode this immediate
2650 // using a 'bitmask immediate'.
2651 //
2652 return true;
2653 }
2654 }
2655 return false;
2656}
2657
2658/************************************************************************
2659 *
2660 * Convert a 64-bit immediate into its 'bitmask immediate' representation imm(N,r,s)
2661 */
2662
2663/*static*/ emitter::bitMaskImm emitter::emitEncodeBitMaskImm(INT64 imm, emitAttr size)
2664{
2665 emitter::bitMaskImm result;
2666 result.immNRS = 0;
2667
2668 bool canEncode = canEncodeBitMaskImm(imm, size, &result);
2669 assert(canEncode);
2670
2671 return result;
2672}
2673
2674/************************************************************************
2675 *
2676 * Convert an imm(i16,hw) into a 32/64-bit immediate
2677 * inputs 'hwImm' a halfwordImm struct
2678 * 'size' specifies the size of the result (64 or 32 bits)
2679 */
2680
2681/*static*/ INT64 emitter::emitDecodeHalfwordImm(const emitter::halfwordImm hwImm, emitAttr size)
2682{
2683 assert(isValidGeneralDatasize(size)); // Only EA_4BYTE or EA_8BYTE forms
2684
2685 unsigned hw = hwImm.immHW;
2686 INT64 val = (INT64)hwImm.immVal;
2687
2688 assert((hw <= 1) || (size == EA_8BYTE));
2689
2690 INT64 result = val << (16 * hw);
2691 return result;
2692}
2693
2694/************************************************************************
2695 *
2696 * returns true if 'imm' of 'size' bits (32/64) can be encoded
2697 * using the ARM64 'halfword immediate' form.
2698 * When a non-null value is passed for 'wbHWI' then this method
2699 * writes back the 'immHW' and 'immVal' values use to encode this immediate
2700 *
2701 */
2702
2703/*static*/ bool emitter::canEncodeHalfwordImm(INT64 imm, emitAttr size, emitter::halfwordImm* wbHWI)
2704{
2705 assert(isValidGeneralDatasize(size)); // Only EA_4BYTE or EA_8BYTE forms
2706
2707 unsigned immWidth = (size == EA_8BYTE) ? 64 : 32;
2708 unsigned maxHW = (size == EA_8BYTE) ? 4 : 2;
2709
2710 // setup immMask to a (EA_4BYTE) 0x00000000_FFFFFFFF or (EA_8BYTE) 0xFFFFFFFF_FFFFFFFF
2711 const UINT64 immMask = ((UINT64)-1) >> (64 - immWidth);
2712 const INT64 mask16 = (INT64)0xFFFF;
2713
2714 imm = normalizeImm64(imm, size);
2715
2716 // Try each of the valid hw shift sizes
2717 for (unsigned hw = 0; (hw < maxHW); hw++)
2718 {
2719 INT64 curMask = mask16 << (hw * 16); // Represents the mask of the bits in the current halfword
2720 INT64 checkBits = immMask & ~curMask;
2721
2722 // Excluding the current halfword (using ~curMask)
2723 // does the immediate have zero bits in every other bit that we care about?
2724 // note we care about all 64-bits for EA_8BYTE
2725 // and we care about the lowest 32 bits for EA_4BYTE
2726 //
2727 if ((imm & checkBits) == 0)
2728 {
2729 // Does the caller want us to return the imm(i16,hw) encoding values?
2730 //
2731 if (wbHWI != nullptr)
2732 {
2733 INT64 val = ((imm & curMask) >> (hw * 16)) & mask16;
2734 wbHWI->immHW = hw;
2735 wbHWI->immVal = val;
2736
2737 // Verify that what we are returning is correct.
2738 assert(imm == emitDecodeHalfwordImm(*wbHWI, size));
2739 }
2740 // Tell the caller that we can successfully encode this immediate
2741 // using a 'halfword immediate'.
2742 //
2743 return true;
2744 }
2745 }
2746 return false;
2747}
2748
2749/************************************************************************
2750 *
2751 * Convert a 64-bit immediate into its 'halfword immediate' representation imm(i16,hw)
2752 */
2753
2754/*static*/ emitter::halfwordImm emitter::emitEncodeHalfwordImm(INT64 imm, emitAttr size)
2755{
2756 emitter::halfwordImm result;
2757 result.immHWVal = 0;
2758
2759 bool canEncode = canEncodeHalfwordImm(imm, size, &result);
2760 assert(canEncode);
2761
2762 return result;
2763}
2764
2765/************************************************************************
2766 *
2767 * Convert an imm(i8,sh) into a 16/32-bit immediate
2768 * inputs 'bsImm' a byteShiftedImm struct
2769 * 'size' specifies the size of the result (16 or 32 bits)
2770 */
2771
2772/*static*/ INT32 emitter::emitDecodeByteShiftedImm(const emitter::byteShiftedImm bsImm, emitAttr size)
2773{
2774 bool onesShift = (bsImm.immOnes == 1);
2775 unsigned bySh = bsImm.immBY; // Num Bytes to shift 0,1,2,3
2776 INT32 val = (INT32)bsImm.immVal; // 8-bit immediate
2777 INT32 result = val;
2778
2779 if (bySh > 0)
2780 {
2781 assert((size == EA_2BYTE) || (size == EA_4BYTE)); // Only EA_2BYTE or EA_4BYTE forms
2782 if (size == EA_2BYTE)
2783 {
2784 assert(bySh < 2);
2785 }
2786 else
2787 {
2788 assert(bySh < 4);
2789 }
2790
2791 result <<= (8 * bySh);
2792
2793 if (onesShift)
2794 {
2795 result |= ((1 << (8 * bySh)) - 1);
2796 }
2797 }
2798 return result;
2799}
2800
2801/************************************************************************
2802 *
2803 * returns true if 'imm' of 'size' bits (16/32) can be encoded
2804 * using the ARM64 'byteShifted immediate' form.
2805 * When a non-null value is passed for 'wbBSI' then this method
2806 * writes back the 'immBY' and 'immVal' values use to encode this immediate
2807 *
2808 */
2809
2810/*static*/ bool emitter::canEncodeByteShiftedImm(INT64 imm,
2811 emitAttr size,
2812 bool allow_MSL,
2813 emitter::byteShiftedImm* wbBSI)
2814{
2815 bool canEncode = false;
2816 bool onesShift = false; // true if we use the shifting ones variant
2817 unsigned bySh = 0; // number of bytes to shift: 0, 1, 2, 3
2818 unsigned imm8 = 0; // immediate to use in the encoding
2819
2820 imm = normalizeImm64(imm, size);
2821
2822 if (size == EA_1BYTE)
2823 {
2824 imm8 = (unsigned)imm;
2825 assert(imm8 < 0x100);
2826 canEncode = true;
2827 }
2828 else if (size == EA_8BYTE)
2829 {
2830 imm8 = (unsigned)imm;
2831 assert(imm8 < 0x100);
2832 canEncode = true;
2833 }
2834 else
2835 {
2836 assert((size == EA_2BYTE) || (size == EA_4BYTE)); // Only EA_2BYTE or EA_4BYTE forms
2837
2838 unsigned immWidth = (size == EA_4BYTE) ? 32 : 16;
2839 unsigned maxBY = (size == EA_4BYTE) ? 4 : 2;
2840
2841 // setup immMask to a (EA_2BYTE) 0x0000FFFF or (EA_4BYTE) 0xFFFFFFFF
2842 const UINT32 immMask = ((UINT32)-1) >> (32 - immWidth);
2843 const INT32 mask8 = (INT32)0xFF;
2844
2845 // Try each of the valid by shift sizes
2846 for (bySh = 0; (bySh < maxBY); bySh++)
2847 {
2848 INT32 curMask = mask8 << (bySh * 8); // Represents the mask of the bits in the current byteShifted
2849 INT32 checkBits = immMask & ~curMask;
2850 INT32 immCheck = (imm & checkBits);
2851
2852 // Excluding the current byte (using ~curMask)
2853 // does the immediate have zero bits in every other bit that we care about?
2854 // or can be use the shifted one variant?
2855 // note we care about all 32-bits for EA_4BYTE
2856 // and we care about the lowest 16 bits for EA_2BYTE
2857 //
2858 if (immCheck == 0)
2859 {
2860 canEncode = true;
2861 }
2862 if (allow_MSL)
2863 {
2864 if ((bySh == 1) && (immCheck == 0xFF))
2865 {
2866 canEncode = true;
2867 onesShift = true;
2868 }
2869 else if ((bySh == 2) && (immCheck == 0xFFFF))
2870 {
2871 canEncode = true;
2872 onesShift = true;
2873 }
2874 }
2875 if (canEncode)
2876 {
2877 imm8 = (unsigned)(((imm & curMask) >> (bySh * 8)) & mask8);
2878 break;
2879 }
2880 }
2881 }
2882
2883 if (canEncode)
2884 {
2885 // Does the caller want us to return the imm(i8,bySh) encoding values?
2886 //
2887 if (wbBSI != nullptr)
2888 {
2889 wbBSI->immOnes = onesShift;
2890 wbBSI->immBY = bySh;
2891 wbBSI->immVal = imm8;
2892
2893 // Verify that what we are returning is correct.
2894 assert(imm == emitDecodeByteShiftedImm(*wbBSI, size));
2895 }
2896 // Tell the caller that we can successfully encode this immediate
2897 // using a 'byteShifted immediate'.
2898 //
2899 return true;
2900 }
2901 return false;
2902}
2903
2904/************************************************************************
2905 *
2906 * Convert a 32-bit immediate into its 'byteShifted immediate' representation imm(i8,by)
2907 */
2908
2909/*static*/ emitter::byteShiftedImm emitter::emitEncodeByteShiftedImm(INT64 imm, emitAttr size, bool allow_MSL)
2910{
2911 emitter::byteShiftedImm result;
2912 result.immBSVal = 0;
2913
2914 bool canEncode = canEncodeByteShiftedImm(imm, size, allow_MSL, &result);
2915 assert(canEncode);
2916
2917 return result;
2918}
2919
2920/************************************************************************
2921 *
2922 * Convert a 'float 8-bit immediate' into a double.
2923 * inputs 'fpImm' a floatImm8 struct
2924 */
2925
2926/*static*/ double emitter::emitDecodeFloatImm8(const emitter::floatImm8 fpImm)
2927{
2928 unsigned sign = fpImm.immSign;
2929 unsigned exp = fpImm.immExp ^ 0x4;
2930 unsigned mant = fpImm.immMant + 16;
2931 unsigned scale = 16 * 8;
2932
2933 while (exp > 0)
2934 {
2935 scale /= 2;
2936 exp--;
2937 }
2938
2939 double result = ((double)mant) / ((double)scale);
2940 if (sign == 1)
2941 {
2942 result = -result;
2943 }
2944
2945 return result;
2946}
2947
2948/************************************************************************
2949 *
2950 * returns true if the 'immDbl' can be encoded using the 'float 8-bit immediate' form.
2951 * also returns the encoding if wbFPI is non-null
2952 *
2953 */
2954
2955/*static*/ bool emitter::canEncodeFloatImm8(double immDbl, emitter::floatImm8* wbFPI)
2956{
2957 bool canEncode = false;
2958 double val = immDbl;
2959
2960 int sign = 0;
2961 if (val < 0.0)
2962 {
2963 val = -val;
2964 sign = 1;
2965 }
2966
2967 int exp = 0;
2968 while ((val < 1.0) && (exp >= -4))
2969 {
2970 val *= 2.0;
2971 exp--;
2972 }
2973 while ((val >= 2.0) && (exp <= 5))
2974 {
2975 val *= 0.5;
2976 exp++;
2977 }
2978 exp += 3;
2979 val *= 16.0;
2980 int ival = (int)val;
2981
2982 if ((exp >= 0) && (exp <= 7))
2983 {
2984 if (val == (double)ival)
2985 {
2986 canEncode = true;
2987
2988 if (wbFPI != nullptr)
2989 {
2990 ival -= 16;
2991 assert((ival >= 0) && (ival <= 15));
2992
2993 wbFPI->immSign = sign;
2994 wbFPI->immExp = exp ^ 0x4;
2995 wbFPI->immMant = ival;
2996 unsigned imm8 = wbFPI->immFPIVal;
2997 assert((imm8 >= 0) && (imm8 <= 0xff));
2998 }
2999 }
3000 }
3001
3002 return canEncode;
3003}
3004
3005/************************************************************************
3006 *
3007 * Convert a double into its 'float 8-bit immediate' representation
3008 */
3009
3010/*static*/ emitter::floatImm8 emitter::emitEncodeFloatImm8(double immDbl)
3011{
3012 emitter::floatImm8 result;
3013 result.immFPIVal = 0;
3014
3015 bool canEncode = canEncodeFloatImm8(immDbl, &result);
3016 assert(canEncode);
3017
3018 return result;
3019}
3020
3021/*****************************************************************************
3022 *
3023 * For the given 'ins' returns the reverse instruction
3024 * if one exists, otherwise returns INS_INVALID
3025 */
3026
3027/*static*/ instruction emitter::insReverse(instruction ins)
3028{
3029 switch (ins)
3030 {
3031 case INS_add:
3032 return INS_sub;
3033 case INS_adds:
3034 return INS_subs;
3035
3036 case INS_sub:
3037 return INS_add;
3038 case INS_subs:
3039 return INS_adds;
3040
3041 case INS_cmp:
3042 return INS_cmn;
3043 case INS_cmn:
3044 return INS_cmp;
3045
3046 case INS_ccmp:
3047 return INS_ccmn;
3048 case INS_ccmn:
3049 return INS_ccmp;
3050
3051 default:
3052 return INS_invalid;
3053 }
3054}
3055
3056/*****************************************************************************
3057 *
3058 * For the given 'datasize' and 'elemsize', make the proper arrangement option
3059 * returns the insOpts that specifies the vector register arrangement
3060 * if one does not exist returns INS_OPTS_NONE
3061 */
3062
3063/*static*/ insOpts emitter::optMakeArrangement(emitAttr datasize, emitAttr elemsize)
3064{
3065 insOpts result = INS_OPTS_NONE;
3066
3067 if (datasize == EA_8BYTE)
3068 {
3069 switch (elemsize)
3070 {
3071 case EA_1BYTE:
3072 result = INS_OPTS_8B;
3073 break;
3074 case EA_2BYTE:
3075 result = INS_OPTS_4H;
3076 break;
3077 case EA_4BYTE:
3078 result = INS_OPTS_2S;
3079 break;
3080 case EA_8BYTE:
3081 result = INS_OPTS_1D;
3082 break;
3083 default:
3084 unreached();
3085 break;
3086 }
3087 }
3088 else if (datasize == EA_16BYTE)
3089 {
3090 switch (elemsize)
3091 {
3092 case EA_1BYTE:
3093 result = INS_OPTS_16B;
3094 break;
3095 case EA_2BYTE:
3096 result = INS_OPTS_8H;
3097 break;
3098 case EA_4BYTE:
3099 result = INS_OPTS_4S;
3100 break;
3101 case EA_8BYTE:
3102 result = INS_OPTS_2D;
3103 break;
3104 default:
3105 unreached();
3106 break;
3107 }
3108 }
3109 return result;
3110}
3111
3112/*****************************************************************************
3113 *
3114 * For the given 'datasize' and arrangement 'opts'
3115 * returns true is the pair spcifies a valid arrangement
3116 */
3117/*static*/ bool emitter::isValidArrangement(emitAttr datasize, insOpts opt)
3118{
3119 if (datasize == EA_8BYTE)
3120 {
3121 if ((opt == INS_OPTS_8B) || (opt == INS_OPTS_4H) || (opt == INS_OPTS_2S) || (opt == INS_OPTS_1D))
3122 {
3123 return true;
3124 }
3125 }
3126 else if (datasize == EA_16BYTE)
3127 {
3128 if ((opt == INS_OPTS_16B) || (opt == INS_OPTS_8H) || (opt == INS_OPTS_4S) || (opt == INS_OPTS_2D))
3129 {
3130 return true;
3131 }
3132 }
3133 return false;
3134}
3135
3136// For the given 'arrangement' returns the 'datasize' specified by the vector register arrangement
3137// asserts and returns EA_UNKNOWN if an invalid 'arrangement' value is passed
3138//
3139/*static*/ emitAttr emitter::optGetDatasize(insOpts arrangement)
3140{
3141 if ((arrangement == INS_OPTS_8B) || (arrangement == INS_OPTS_4H) || (arrangement == INS_OPTS_2S) ||
3142 (arrangement == INS_OPTS_1D))
3143 {
3144 return EA_8BYTE;
3145 }
3146 else if ((arrangement == INS_OPTS_16B) || (arrangement == INS_OPTS_8H) || (arrangement == INS_OPTS_4S) ||
3147 (arrangement == INS_OPTS_2D))
3148 {
3149 return EA_16BYTE;
3150 }
3151 else
3152 {
3153 assert(!" invalid 'arrangement' value");
3154 return EA_UNKNOWN;
3155 }
3156}
3157
3158// For the given 'arrangement' returns the 'elemsize' specified by the vector register arrangement
3159// asserts and returns EA_UNKNOWN if an invalid 'arrangement' value is passed
3160//
3161/*static*/ emitAttr emitter::optGetElemsize(insOpts arrangement)
3162{
3163 if ((arrangement == INS_OPTS_8B) || (arrangement == INS_OPTS_16B))
3164 {
3165 return EA_1BYTE;
3166 }
3167 else if ((arrangement == INS_OPTS_4H) || (arrangement == INS_OPTS_8H))
3168 {
3169 return EA_2BYTE;
3170 }
3171 else if ((arrangement == INS_OPTS_2S) || (arrangement == INS_OPTS_4S))
3172 {
3173 return EA_4BYTE;
3174 }
3175 else if ((arrangement == INS_OPTS_1D) || (arrangement == INS_OPTS_2D))
3176 {
3177 return EA_8BYTE;
3178 }
3179 else
3180 {
3181 assert(!" invalid 'arrangement' value");
3182 return EA_UNKNOWN;
3183 }
3184}
3185
3186// For the given 'arrangement' returns the 'widen-arrangement' specified by the vector register arrangement
3187// asserts and returns INS_OPTS_NONE if an invalid 'arrangement' value is passed
3188//
3189/*static*/ insOpts emitter::optWidenElemsize(insOpts arrangement)
3190{
3191 if ((arrangement == INS_OPTS_8B) || (arrangement == INS_OPTS_16B))
3192 {
3193 return INS_OPTS_8H;
3194 }
3195 else if ((arrangement == INS_OPTS_4H) || (arrangement == INS_OPTS_8H))
3196 {
3197 return INS_OPTS_4S;
3198 }
3199 else if ((arrangement == INS_OPTS_2S) || (arrangement == INS_OPTS_4S))
3200 {
3201 return INS_OPTS_2D;
3202 }
3203 else
3204 {
3205 assert(!" invalid 'arrangement' value");
3206 return INS_OPTS_NONE;
3207 }
3208}
3209
3210// For the given 'conversion' returns the 'dstsize' specified by the conversion option
3211/*static*/ emitAttr emitter::optGetDstsize(insOpts conversion)
3212{
3213 switch (conversion)
3214 {
3215 case INS_OPTS_S_TO_8BYTE:
3216 case INS_OPTS_D_TO_8BYTE:
3217 case INS_OPTS_4BYTE_TO_D:
3218 case INS_OPTS_8BYTE_TO_D:
3219 case INS_OPTS_S_TO_D:
3220 case INS_OPTS_H_TO_D:
3221
3222 return EA_8BYTE;
3223
3224 case INS_OPTS_S_TO_4BYTE:
3225 case INS_OPTS_D_TO_4BYTE:
3226 case INS_OPTS_4BYTE_TO_S:
3227 case INS_OPTS_8BYTE_TO_S:
3228 case INS_OPTS_D_TO_S:
3229 case INS_OPTS_H_TO_S:
3230
3231 return EA_4BYTE;
3232
3233 case INS_OPTS_S_TO_H:
3234 case INS_OPTS_D_TO_H:
3235
3236 return EA_2BYTE;
3237
3238 default:
3239 assert(!" invalid 'conversion' value");
3240 return EA_UNKNOWN;
3241 }
3242}
3243
3244// For the given 'conversion' returns the 'srcsize' specified by the conversion option
3245/*static*/ emitAttr emitter::optGetSrcsize(insOpts conversion)
3246{
3247 switch (conversion)
3248 {
3249 case INS_OPTS_D_TO_8BYTE:
3250 case INS_OPTS_D_TO_4BYTE:
3251 case INS_OPTS_8BYTE_TO_D:
3252 case INS_OPTS_8BYTE_TO_S:
3253 case INS_OPTS_D_TO_S:
3254 case INS_OPTS_D_TO_H:
3255
3256 return EA_8BYTE;
3257
3258 case INS_OPTS_S_TO_8BYTE:
3259 case INS_OPTS_S_TO_4BYTE:
3260 case INS_OPTS_4BYTE_TO_S:
3261 case INS_OPTS_4BYTE_TO_D:
3262 case INS_OPTS_S_TO_D:
3263 case INS_OPTS_S_TO_H:
3264
3265 return EA_4BYTE;
3266
3267 case INS_OPTS_H_TO_S:
3268 case INS_OPTS_H_TO_D:
3269
3270 return EA_2BYTE;
3271
3272 default:
3273 assert(!" invalid 'conversion' value");
3274 return EA_UNKNOWN;
3275 }
3276}
3277
3278// For the given 'size' and 'index' returns true if it specifies a valid index for a vector register of 'size'
3279/*static*/ bool emitter::isValidVectorIndex(emitAttr datasize, emitAttr elemsize, ssize_t index)
3280{
3281 assert(isValidVectorDatasize(datasize));
3282 assert(isValidVectorElemsize(elemsize));
3283
3284 bool result = false;
3285 if (index >= 0)
3286 {
3287 if (datasize == EA_8BYTE)
3288 {
3289 switch (elemsize)
3290 {
3291 case EA_1BYTE:
3292 result = (index < 8);
3293 break;
3294 case EA_2BYTE:
3295 result = (index < 4);
3296 break;
3297 case EA_4BYTE:
3298 result = (index < 2);
3299 break;
3300 case EA_8BYTE:
3301 result = (index < 1);
3302 break;
3303 default:
3304 unreached();
3305 break;
3306 }
3307 }
3308 else if (datasize == EA_16BYTE)
3309 {
3310 switch (elemsize)
3311 {
3312 case EA_1BYTE:
3313 result = (index < 16);
3314 break;
3315 case EA_2BYTE:
3316 result = (index < 8);
3317 break;
3318 case EA_4BYTE:
3319 result = (index < 4);
3320 break;
3321 case EA_8BYTE:
3322 result = (index < 2);
3323 break;
3324 default:
3325 unreached();
3326 break;
3327 }
3328 }
3329 }
3330 return result;
3331}
3332
3333/*****************************************************************************
3334 *
3335 * Add an instruction with no operands.
3336 */
3337
3338void emitter::emitIns(instruction ins)
3339{
3340 instrDesc* id = emitNewInstrSmall(EA_8BYTE);
3341 insFormat fmt = emitInsFormat(ins);
3342
3343 assert(fmt == IF_SN_0A);
3344
3345 id->idIns(ins);
3346 id->idInsFmt(fmt);
3347
3348 dispIns(id);
3349 appendToCurIG(id);
3350}
3351
3352/*****************************************************************************
3353 *
3354 * Add an instruction with a single immediate value.
3355 */
3356
3357void emitter::emitIns_I(instruction ins, emitAttr attr, ssize_t imm)
3358{
3359 insFormat fmt = IF_NONE;
3360
3361 /* Figure out the encoding format of the instruction */
3362 switch (ins)
3363 {
3364 case INS_brk:
3365 if ((imm & 0x0000ffff) == imm)
3366 {
3367 fmt = IF_SI_0A;
3368 }
3369 else
3370 {
3371 assert(!"Instruction cannot be encoded: IF_SI_0A");
3372 }
3373 break;
3374 default:
3375 unreached();
3376 break;
3377 }
3378 assert(fmt != IF_NONE);
3379
3380 instrDesc* id = emitNewInstrSC(attr, imm);
3381
3382 id->idIns(ins);
3383 id->idInsFmt(fmt);
3384
3385 dispIns(id);
3386 appendToCurIG(id);
3387}
3388
3389/*****************************************************************************
3390 *
3391 * Add an instruction referencing a single register.
3392 */
3393
3394void emitter::emitIns_R(instruction ins, emitAttr attr, regNumber reg)
3395{
3396 emitAttr size = EA_SIZE(attr);
3397 insFormat fmt = IF_NONE;
3398 instrDesc* id = nullptr;
3399
3400 /* Figure out the encoding format of the instruction */
3401 switch (ins)
3402 {
3403 case INS_br:
3404 case INS_ret:
3405 assert(isGeneralRegister(reg));
3406 id = emitNewInstrSmall(attr);
3407 id->idReg1(reg);
3408 fmt = IF_BR_1A;
3409 break;
3410
3411 default:
3412 unreached();
3413 }
3414
3415 assert(fmt != IF_NONE);
3416
3417 id->idIns(ins);
3418 id->idInsFmt(fmt);
3419
3420 dispIns(id);
3421 appendToCurIG(id);
3422}
3423
3424/*****************************************************************************
3425 *
3426 * Add an instruction referencing a register and a constant.
3427 */
3428
3429void emitter::emitIns_R_I(instruction ins, emitAttr attr, regNumber reg, ssize_t imm, insOpts opt /* = INS_OPTS_NONE */)
3430{
3431 emitAttr size = EA_SIZE(attr);
3432 emitAttr elemsize = EA_UNKNOWN;
3433 insFormat fmt = IF_NONE;
3434 bool canEncode = false;
3435
3436 /* Figure out the encoding format of the instruction */
3437 switch (ins)
3438 {
3439 bitMaskImm bmi;
3440 halfwordImm hwi;
3441 byteShiftedImm bsi;
3442 ssize_t notOfImm;
3443
3444 case INS_tst:
3445 assert(insOptsNone(opt));
3446 assert(isGeneralRegister(reg));
3447 bmi.immNRS = 0;
3448 canEncode = canEncodeBitMaskImm(imm, size, &bmi);
3449 if (canEncode)
3450 {
3451 imm = bmi.immNRS;
3452 assert(isValidImmNRS(imm, size));
3453 fmt = IF_DI_1C;
3454 }
3455 break;
3456
3457 case INS_movk:
3458 case INS_movn:
3459 case INS_movz:
3460 assert(isValidGeneralDatasize(size));
3461 assert(insOptsNone(opt)); // No LSL here (you must use emitIns_R_I_I if a shift is needed)
3462 assert(isGeneralRegister(reg));
3463 assert(isValidUimm16(imm));
3464
3465 hwi.immHW = 0;
3466 hwi.immVal = imm;
3467 assert(imm == emitDecodeHalfwordImm(hwi, size));
3468
3469 imm = hwi.immHWVal;
3470 canEncode = true;
3471 fmt = IF_DI_1B;
3472 break;
3473
3474 case INS_mov:
3475 assert(isValidGeneralDatasize(size));
3476 assert(insOptsNone(opt)); // No explicit LSL here
3477 // We will automatically determine the shift based upon the imm
3478
3479 // First try the standard 'halfword immediate' imm(i16,hw)
3480 hwi.immHWVal = 0;
3481 canEncode = canEncodeHalfwordImm(imm, size, &hwi);
3482 if (canEncode)
3483 {
3484 // uses a movz encoding
3485 assert(isGeneralRegister(reg));
3486 imm = hwi.immHWVal;
3487 assert(isValidImmHWVal(imm, size));
3488 fmt = IF_DI_1B;
3489 break;
3490 }
3491
3492 // Next try the ones-complement form of 'halfword immediate' imm(i16,hw)
3493 notOfImm = NOT_helper(imm, getBitWidth(size));
3494 canEncode = canEncodeHalfwordImm(notOfImm, size, &hwi);
3495 if (canEncode)
3496 {
3497 assert(isGeneralRegister(reg));
3498 imm = hwi.immHWVal;
3499 ins = INS_movn; // uses a movn encoding
3500 assert(isValidImmHWVal(imm, size));
3501 fmt = IF_DI_1B;
3502 break;
3503 }
3504
3505 // Finally try the 'bitmask immediate' imm(N,r,s)
3506 bmi.immNRS = 0;
3507 canEncode = canEncodeBitMaskImm(imm, size, &bmi);
3508 if (canEncode)
3509 {
3510 assert(isGeneralRegisterOrSP(reg));
3511 reg = encodingSPtoZR(reg);
3512 imm = bmi.immNRS;
3513 assert(isValidImmNRS(imm, size));
3514 fmt = IF_DI_1D;
3515 break;
3516 }
3517 else
3518 {
3519 assert(!"Instruction cannot be encoded: mov imm");
3520 }
3521
3522 break;
3523
3524 case INS_movi:
3525 assert(isValidVectorDatasize(size));
3526 assert(isVectorRegister(reg));
3527 if (insOptsNone(opt) && (size == EA_8BYTE))
3528 {
3529 opt = INS_OPTS_1D;
3530 }
3531 assert(isValidArrangement(size, opt));
3532 elemsize = optGetElemsize(opt);
3533
3534 if (elemsize == EA_8BYTE)
3535 {
3536 size_t uimm = imm;
3537 ssize_t imm8 = 0;
3538 unsigned pos = 0;
3539 canEncode = true;
3540 bool failed = false;
3541 while (uimm != 0)
3542 {
3543 INT64 loByte = uimm & 0xFF;
3544 if (((loByte == 0) || (loByte == 0xFF)) && (pos < 8))
3545 {
3546 if (loByte == 0xFF)
3547 {
3548 imm8 |= (ssize_t{1} << pos);
3549 }
3550 uimm >>= 8;
3551 pos++;
3552 }
3553 else
3554 {
3555 canEncode = false;
3556 break;
3557 }
3558 }
3559 imm = imm8;
3560 assert(isValidUimm8(imm));
3561 fmt = IF_DV_1B;
3562 break;
3563 }
3564 else
3565 {
3566 // Vector operation
3567
3568 // No explicit LSL/MSL is used for the immediate
3569 // We will automatically determine the shift based upon the value of imm
3570
3571 // First try the standard 'byteShifted immediate' imm(i8,bySh)
3572 bsi.immBSVal = 0;
3573 canEncode = canEncodeByteShiftedImm(imm, elemsize, true, &bsi);
3574 if (canEncode)
3575 {
3576 imm = bsi.immBSVal;
3577 assert(isValidImmBSVal(imm, size));
3578 fmt = IF_DV_1B;
3579 break;
3580 }
3581
3582 // Next try the ones-complement form of the 'immediate' imm(i8,bySh)
3583 if ((elemsize == EA_2BYTE) || (elemsize == EA_4BYTE)) // Only EA_2BYTE or EA_4BYTE forms
3584 {
3585 notOfImm = NOT_helper(imm, getBitWidth(elemsize));
3586 canEncode = canEncodeByteShiftedImm(notOfImm, elemsize, true, &bsi);
3587 if (canEncode)
3588 {
3589 imm = bsi.immBSVal;
3590 ins = INS_mvni; // uses a mvni encoding
3591 assert(isValidImmBSVal(imm, size));
3592 fmt = IF_DV_1B;
3593 break;
3594 }
3595 }
3596 }
3597 break;
3598
3599 case INS_orr:
3600 case INS_bic:
3601 case INS_mvni:
3602 assert(isValidVectorDatasize(size));
3603 assert(isVectorRegister(reg));
3604 assert(isValidArrangement(size, opt));
3605 elemsize = optGetElemsize(opt);
3606 assert((elemsize == EA_2BYTE) || (elemsize == EA_4BYTE)); // Only EA_2BYTE or EA_4BYTE forms
3607
3608 // Vector operation
3609
3610 // No explicit LSL/MSL is used for the immediate
3611 // We will automatically determine the shift based upon the value of imm
3612
3613 // First try the standard 'byteShifted immediate' imm(i8,bySh)
3614 bsi.immBSVal = 0;
3615 canEncode = canEncodeByteShiftedImm(imm, elemsize,
3616 (ins == INS_mvni), // mvni supports the ones shifting variant (aka MSL)
3617 &bsi);
3618 if (canEncode)
3619 {
3620 imm = bsi.immBSVal;
3621 assert(isValidImmBSVal(imm, size));
3622 fmt = IF_DV_1B;
3623 break;
3624 }
3625 break;
3626
3627 case INS_cmp:
3628 case INS_cmn:
3629 assert(insOptsNone(opt));
3630 assert(isGeneralRegister(reg));
3631
3632 if (unsigned_abs(imm) <= 0x0fff)
3633 {
3634 if (imm < 0)
3635 {
3636 ins = insReverse(ins);
3637 imm = -imm;
3638 }
3639 assert(isValidUimm12(imm));
3640 canEncode = true;
3641 fmt = IF_DI_1A;
3642 }
3643 else if (canEncodeWithShiftImmBy12(imm)) // Try the shifted by 12 encoding
3644 {
3645 // Encoding will use a 12-bit left shift of the immediate
3646 opt = INS_OPTS_LSL12;
3647 if (imm < 0)
3648 {
3649 ins = insReverse(ins);
3650 imm = -imm;
3651 }
3652 assert((imm & 0xfff) == 0);
3653 imm >>= 12;
3654 assert(isValidUimm12(imm));
3655 canEncode = true;
3656 fmt = IF_DI_1A;
3657 }
3658 else
3659 {
3660 assert(!"Instruction cannot be encoded: IF_DI_1A");
3661 }
3662 break;
3663
3664 default:
3665 unreached();
3666 break;
3667
3668 } // end switch (ins)
3669
3670 assert(canEncode);
3671 assert(fmt != IF_NONE);
3672
3673 instrDesc* id = emitNewInstrSC(attr, imm);
3674
3675 id->idIns(ins);
3676 id->idInsFmt(fmt);
3677 id->idInsOpt(opt);
3678
3679 id->idReg1(reg);
3680
3681 dispIns(id);
3682 appendToCurIG(id);
3683}
3684
3685/*****************************************************************************
3686 *
3687 * Add an instruction referencing a register and a floating point constant.
3688 */
3689
3690void emitter::emitIns_R_F(
3691 instruction ins, emitAttr attr, regNumber reg, double immDbl, insOpts opt /* = INS_OPTS_NONE */)
3692
3693{
3694 emitAttr size = EA_SIZE(attr);
3695 emitAttr elemsize = EA_UNKNOWN;
3696 insFormat fmt = IF_NONE;
3697 ssize_t imm = 0;
3698 bool canEncode = false;
3699
3700 /* Figure out the encoding format of the instruction */
3701 switch (ins)
3702 {
3703 floatImm8 fpi;
3704
3705 case INS_fcmp:
3706 case INS_fcmpe:
3707 assert(insOptsNone(opt));
3708 assert(isValidVectorElemsizeFloat(size));
3709 assert(isVectorRegister(reg));
3710 if (immDbl == 0.0)
3711 {
3712 canEncode = true;
3713 fmt = IF_DV_1C;
3714 }
3715 break;
3716
3717 case INS_fmov:
3718 assert(isVectorRegister(reg));
3719 fpi.immFPIVal = 0;
3720 canEncode = canEncodeFloatImm8(immDbl, &fpi);
3721
3722 if (insOptsAnyArrangement(opt))
3723 {
3724 // Vector operation
3725 assert(isValidVectorDatasize(size));
3726 assert(isValidArrangement(size, opt));
3727 elemsize = optGetElemsize(opt);
3728 assert(isValidVectorElemsizeFloat(elemsize));
3729 assert(opt != INS_OPTS_1D); // Reserved encoding
3730
3731 if (canEncode)
3732 {
3733 imm = fpi.immFPIVal;
3734 assert((imm >= 0) && (imm <= 0xff));
3735 fmt = IF_DV_1B;
3736 }
3737 }
3738 else
3739 {
3740 // Scalar operation
3741 assert(insOptsNone(opt));
3742 assert(isValidVectorElemsizeFloat(size));
3743
3744 if (canEncode)
3745 {
3746 imm = fpi.immFPIVal;
3747 assert((imm >= 0) && (imm <= 0xff));
3748 fmt = IF_DV_1A;
3749 }
3750 }
3751 break;
3752
3753 default:
3754 unreached();
3755 break;
3756
3757 } // end switch (ins)
3758
3759 assert(canEncode);
3760 assert(fmt != IF_NONE);
3761
3762 instrDesc* id = emitNewInstrSC(attr, imm);
3763
3764 id->idIns(ins);
3765 id->idInsFmt(fmt);
3766 id->idInsOpt(opt);
3767
3768 id->idReg1(reg);
3769
3770 dispIns(id);
3771 appendToCurIG(id);
3772}
3773
3774/*****************************************************************************
3775 *
3776 * Add an instruction referencing two registers
3777 */
3778
3779void emitter::emitIns_R_R(
3780 instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, insOpts opt /* = INS_OPTS_NONE */)
3781{
3782 emitAttr size = EA_SIZE(attr);
3783 emitAttr elemsize = EA_UNKNOWN;
3784 insFormat fmt = IF_NONE;
3785
3786 /* Figure out the encoding format of the instruction */
3787 switch (ins)
3788 {
3789 case INS_mov:
3790 assert(insOptsNone(opt));
3791 // Is the mov even necessary?
3792 if (reg1 == reg2)
3793 {
3794 // A mov with a EA_4BYTE has the side-effect of clearing the upper bits
3795 // So only eliminate mov instructions that are not clearing the upper bits
3796 //
3797 if (isGeneralRegisterOrSP(reg1) && (size == EA_8BYTE))
3798 {
3799 return;
3800 }
3801 else if (isVectorRegister(reg1) && (size == EA_16BYTE))
3802 {
3803 return;
3804 }
3805 }
3806
3807 // Check for the 'mov' aliases for the vector registers
3808 if (isVectorRegister(reg1))
3809 {
3810 if (isVectorRegister(reg2) && isValidVectorDatasize(size))
3811 {
3812 return emitIns_R_R_R(INS_mov, size, reg1, reg2, reg2);
3813 }
3814 else
3815 {
3816 return emitIns_R_R_I(INS_mov, size, reg1, reg2, 0);
3817 }
3818 }
3819 else
3820 {
3821 if (isVectorRegister(reg2))
3822 {
3823 assert(isGeneralRegister(reg1));
3824 return emitIns_R_R_I(INS_mov, size, reg1, reg2, 0);
3825 }
3826 }
3827
3828 // Is this a MOV to/from SP instruction?
3829 if ((reg1 == REG_SP) || (reg2 == REG_SP))
3830 {
3831 assert(isGeneralRegisterOrSP(reg1));
3832 assert(isGeneralRegisterOrSP(reg2));
3833 reg1 = encodingSPtoZR(reg1);
3834 reg2 = encodingSPtoZR(reg2);
3835 fmt = IF_DR_2G;
3836 }
3837 else
3838 {
3839 assert(insOptsNone(opt));
3840 assert(isGeneralRegister(reg1));
3841 assert(isGeneralRegisterOrZR(reg2));
3842 fmt = IF_DR_2E;
3843 }
3844 break;
3845
3846 case INS_dup:
3847 // Vector operation
3848 assert(insOptsAnyArrangement(opt));
3849 assert(isVectorRegister(reg1));
3850 assert(isGeneralRegisterOrZR(reg2));
3851 assert(isValidVectorDatasize(size));
3852 assert(isValidArrangement(size, opt));
3853 fmt = IF_DV_2C;
3854 break;
3855
3856 case INS_abs:
3857 case INS_not:
3858 assert(isVectorRegister(reg1));
3859 assert(isVectorRegister(reg2));
3860 if (ins == INS_not)
3861 {
3862 assert(isValidVectorDatasize(size));
3863 // Bitwise behavior is independent of element size, but is always encoded as 1 Byte
3864 opt = optMakeArrangement(size, EA_1BYTE);
3865 }
3866 if (insOptsNone(opt))
3867 {
3868 // Scalar operation
3869 assert(size == EA_8BYTE); // Only type D is supported
3870 fmt = IF_DV_2L;
3871 }
3872 else
3873 {
3874 // Vector operation
3875 assert(insOptsAnyArrangement(opt));
3876 assert(isValidVectorDatasize(size));
3877 assert(isValidArrangement(size, opt));
3878 elemsize = optGetElemsize(opt);
3879 fmt = IF_DV_2M;
3880 }
3881 break;
3882
3883 case INS_mvn:
3884 case INS_neg:
3885 if (isVectorRegister(reg1))
3886 {
3887 assert(isVectorRegister(reg2));
3888 if (ins == INS_mvn)
3889 {
3890 assert(isValidVectorDatasize(size));
3891 // Bitwise behavior is independent of element size, but is always encoded as 1 Byte
3892 opt = optMakeArrangement(size, EA_1BYTE);
3893 }
3894 if (insOptsNone(opt))
3895 {
3896 // Scalar operation
3897 assert(size == EA_8BYTE); // Only type D is supported
3898 fmt = IF_DV_2L;
3899 }
3900 else
3901 {
3902 // Vector operation
3903 assert(isValidVectorDatasize(size));
3904 assert(isValidArrangement(size, opt));
3905 elemsize = optGetElemsize(opt);
3906 fmt = IF_DV_2M;
3907 }
3908 break;
3909 }
3910 __fallthrough;
3911
3912 case INS_negs:
3913 assert(insOptsNone(opt));
3914 assert(isGeneralRegister(reg1));
3915 assert(isGeneralRegisterOrZR(reg2));
3916 fmt = IF_DR_2E;
3917 break;
3918
3919 case INS_sxtw:
3920 assert(size == EA_8BYTE);
3921 __fallthrough;
3922
3923 case INS_sxtb:
3924 case INS_sxth:
3925 case INS_uxtb:
3926 case INS_uxth:
3927 assert(insOptsNone(opt));
3928 assert(isValidGeneralDatasize(size));
3929 assert(isGeneralRegister(reg1));
3930 assert(isGeneralRegister(reg2));
3931 fmt = IF_DR_2H;
3932 break;
3933
3934 case INS_sxtl:
3935 case INS_sxtl2:
3936 case INS_uxtl:
3937 case INS_uxtl2:
3938 return emitIns_R_R_I(ins, size, reg1, reg2, 0, opt);
3939
3940 case INS_cls:
3941 case INS_clz:
3942 case INS_rbit:
3943 case INS_rev16:
3944 case INS_rev32:
3945 case INS_cnt:
3946 if (isVectorRegister(reg1))
3947 {
3948 assert(isVectorRegister(reg2));
3949 assert(isValidVectorDatasize(size));
3950 assert(isValidArrangement(size, opt));
3951 elemsize = optGetElemsize(opt);
3952 if ((ins == INS_cls) || (ins == INS_clz))
3953 {
3954 assert(elemsize != EA_8BYTE); // No encoding for type D
3955 }
3956 else if (ins == INS_rev32)
3957 {
3958 assert((elemsize == EA_2BYTE) || (elemsize == EA_1BYTE));
3959 }
3960 else
3961 {
3962 assert(elemsize == EA_1BYTE); // Only supports 8B or 16B
3963 }
3964 fmt = IF_DV_2M;
3965 break;
3966 }
3967 if (ins == INS_cnt)
3968 {
3969 // Doesn't have general register version(s)
3970 break;
3971 }
3972
3973 __fallthrough;
3974
3975 case INS_rev:
3976 assert(insOptsNone(opt));
3977 assert(isGeneralRegister(reg1));
3978 assert(isGeneralRegister(reg2));
3979 if (ins == INS_rev32)
3980 {
3981 assert(size == EA_8BYTE);
3982 }
3983 else
3984 {
3985 assert(isValidGeneralDatasize(size));
3986 }
3987 fmt = IF_DR_2G;
3988 break;
3989
3990 case INS_addv:
3991 case INS_saddlv:
3992 case INS_smaxv:
3993 case INS_sminv:
3994 case INS_uaddlv:
3995 case INS_umaxv:
3996 case INS_uminv:
3997 case INS_rev64:
3998 assert(isVectorRegister(reg1));
3999 assert(isVectorRegister(reg2));
4000 assert(isValidVectorDatasize(size));
4001 assert(isValidArrangement(size, opt));
4002 elemsize = optGetElemsize(opt);
4003 assert(elemsize != EA_8BYTE); // No encoding for type D
4004 fmt = IF_DV_2M;
4005 break;
4006
4007 case INS_xtn:
4008 case INS_xtn2:
4009 assert(isVectorRegister(reg1));
4010 assert(isVectorRegister(reg2));
4011 assert(isValidVectorDatasize(size));
4012 assert(isValidArrangement(size, opt));
4013 elemsize = optGetElemsize(opt);
4014 // size is determined by instruction
4015 if (ins == INS_xtn)
4016 {
4017 assert(size == EA_8BYTE);
4018 }
4019 else // ins == INS_xtn2
4020 {
4021 assert(size == EA_16BYTE);
4022 }
4023 assert(elemsize != EA_8BYTE); // Narrowing must not end with 8 byte data
4024 fmt = IF_DV_2M;
4025 break;
4026
4027 case INS_ldar:
4028 case INS_ldaxr:
4029 case INS_ldxr:
4030 case INS_stlr:
4031 assert(isValidGeneralDatasize(size));
4032
4033 __fallthrough;
4034
4035 case INS_ldarb:
4036 case INS_ldaxrb:
4037 case INS_ldxrb:
4038 case INS_ldarh:
4039 case INS_ldaxrh:
4040 case INS_ldxrh:
4041 case INS_stlrb:
4042 case INS_stlrh:
4043 assert(isValidGeneralLSDatasize(size));
4044 assert(isGeneralRegisterOrZR(reg1));
4045 assert(isGeneralRegisterOrSP(reg2));
4046 assert(insOptsNone(opt));
4047
4048 reg2 = encodingSPtoZR(reg2);
4049
4050 fmt = IF_LS_2A;
4051 break;
4052
4053 case INS_ldr:
4054 case INS_ldrb:
4055 case INS_ldrh:
4056 case INS_ldrsb:
4057 case INS_ldrsh:
4058 case INS_ldrsw:
4059 case INS_str:
4060 case INS_strb:
4061 case INS_strh:
4062
4063 case INS_cmp:
4064 case INS_cmn:
4065 case INS_tst:
4066 assert(insOptsNone(opt));
4067 emitIns_R_R_I(ins, attr, reg1, reg2, 0, INS_OPTS_NONE);
4068 return;
4069
4070 case INS_staddb:
4071 emitIns_R_R_R(INS_ldaddb, attr, reg1, REG_ZR, reg2);
4072 return;
4073 case INS_staddlb:
4074 emitIns_R_R_R(INS_ldaddlb, attr, reg1, REG_ZR, reg2);
4075 return;
4076 case INS_staddh:
4077 emitIns_R_R_R(INS_ldaddh, attr, reg1, REG_ZR, reg2);
4078 return;
4079 case INS_staddlh:
4080 emitIns_R_R_R(INS_ldaddlh, attr, reg1, REG_ZR, reg2);
4081 return;
4082 case INS_stadd:
4083 emitIns_R_R_R(INS_ldadd, attr, reg1, REG_ZR, reg2);
4084 return;
4085 case INS_staddl:
4086 emitIns_R_R_R(INS_ldaddl, attr, reg1, REG_ZR, reg2);
4087 return;
4088
4089 case INS_fmov:
4090 assert(isValidVectorElemsizeFloat(size));
4091
4092 // Is the mov even necessary?
4093 if (reg1 == reg2)
4094 {
4095 return;
4096 }
4097
4098 if (isVectorRegister(reg1))
4099 {
4100 if (isVectorRegister(reg2))
4101 {
4102 assert(insOptsNone(opt));
4103 fmt = IF_DV_2G;
4104 }
4105 else
4106 {
4107 assert(isGeneralRegister(reg2));
4108
4109 // if the optional conversion specifier is not present we calculate it
4110 if (opt == INS_OPTS_NONE)
4111 {
4112 opt = (size == EA_4BYTE) ? INS_OPTS_4BYTE_TO_S : INS_OPTS_8BYTE_TO_D;
4113 }
4114 assert(insOptsConvertIntToFloat(opt));
4115
4116 fmt = IF_DV_2I;
4117 }
4118 }
4119 else
4120 {
4121 assert(isGeneralRegister(reg1));
4122 assert(isVectorRegister(reg2));
4123
4124 // if the optional conversion specifier is not present we calculate it
4125 if (opt == INS_OPTS_NONE)
4126 {
4127 opt = (size == EA_4BYTE) ? INS_OPTS_S_TO_4BYTE : INS_OPTS_D_TO_8BYTE;
4128 }
4129 assert(insOptsConvertFloatToInt(opt));
4130
4131 fmt = IF_DV_2H;
4132 }
4133 break;
4134
4135 case INS_fcmp:
4136 case INS_fcmpe:
4137 assert(insOptsNone(opt));
4138 assert(isValidVectorElemsizeFloat(size));
4139 assert(isVectorRegister(reg1));
4140 assert(isVectorRegister(reg2));
4141 fmt = IF_DV_2K;
4142 break;
4143
4144 case INS_fcvtns:
4145 case INS_fcvtnu:
4146 case INS_fcvtas:
4147 case INS_fcvtau:
4148 case INS_fcvtps:
4149 case INS_fcvtpu:
4150 case INS_fcvtms:
4151 case INS_fcvtmu:
4152 case INS_fcvtzs:
4153 case INS_fcvtzu:
4154 if (insOptsAnyArrangement(opt))
4155 {
4156 // Vector operation
4157 assert(isVectorRegister(reg1));
4158 assert(isVectorRegister(reg2));
4159 assert(isValidVectorDatasize(size));
4160 assert(isValidArrangement(size, opt));
4161 elemsize = optGetElemsize(opt);
4162 assert(isValidVectorElemsizeFloat(elemsize));
4163 assert(opt != INS_OPTS_1D); // Reserved encoding
4164 fmt = IF_DV_2A;
4165 }
4166 else
4167 {
4168 // Scalar operation
4169 assert(isVectorRegister(reg2));
4170 if (isVectorRegister(reg1))
4171 {
4172 assert(insOptsNone(opt));
4173 assert(isValidVectorElemsizeFloat(size));
4174 fmt = IF_DV_2G;
4175 }
4176 else
4177 {
4178 assert(isGeneralRegister(reg1));
4179 assert(insOptsConvertFloatToInt(opt));
4180 assert(isValidVectorElemsizeFloat(size));
4181 fmt = IF_DV_2H;
4182 }
4183 }
4184 break;
4185
4186 case INS_fcvtl:
4187 case INS_fcvtl2:
4188 case INS_fcvtn:
4189 case INS_fcvtn2:
4190 assert(isVectorRegister(reg1));
4191 assert(isVectorRegister(reg2));
4192 assert(isValidVectorDatasize(size));
4193 assert(insOptsNone(opt));
4194 assert(size == EA_8BYTE); // Narrowing from Double or Widening to Double (Half not supported)
4195 fmt = IF_DV_2G;
4196 break;
4197
4198 case INS_scvtf:
4199 case INS_ucvtf:
4200 if (insOptsAnyArrangement(opt))
4201 {
4202 // Vector operation
4203 assert(isVectorRegister(reg1));
4204 assert(isVectorRegister(reg2));
4205 assert(isValidVectorDatasize(size));
4206 assert(isValidArrangement(size, opt));
4207 elemsize = optGetElemsize(opt);
4208 assert(isValidVectorElemsizeFloat(elemsize));
4209 assert(opt != INS_OPTS_1D); // Reserved encoding
4210 fmt = IF_DV_2A;
4211 }
4212 else
4213 {
4214 // Scalar operation
4215 assert(isVectorRegister(reg1));
4216 if (isVectorRegister(reg2))
4217 {
4218 assert(insOptsNone(opt));
4219 assert(isValidVectorElemsizeFloat(size));
4220 fmt = IF_DV_2G;
4221 }
4222 else
4223 {
4224 assert(isGeneralRegister(reg2));
4225 assert(insOptsConvertIntToFloat(opt));
4226 assert(isValidVectorElemsizeFloat(size));
4227 fmt = IF_DV_2I;
4228 }
4229 }
4230 break;
4231
4232 case INS_fabs:
4233 case INS_fneg:
4234 case INS_fsqrt:
4235 case INS_frinta:
4236 case INS_frinti:
4237 case INS_frintm:
4238 case INS_frintn:
4239 case INS_frintp:
4240 case INS_frintx:
4241 case INS_frintz:
4242 if (insOptsAnyArrangement(opt))
4243 {
4244 // Vector operation
4245 assert(isVectorRegister(reg1));
4246 assert(isVectorRegister(reg2));
4247 assert(isValidVectorDatasize(size));
4248 assert(isValidArrangement(size, opt));
4249 elemsize = optGetElemsize(opt);
4250 assert(isValidVectorElemsizeFloat(elemsize));
4251 assert(opt != INS_OPTS_1D); // Reserved encoding
4252 fmt = IF_DV_2A;
4253 }
4254 else
4255 {
4256 // Scalar operation
4257 assert(insOptsNone(opt));
4258 assert(isValidVectorElemsizeFloat(size));
4259 assert(isVectorRegister(reg1));
4260 assert(isVectorRegister(reg2));
4261 fmt = IF_DV_2G;
4262 }
4263 break;
4264
4265 case INS_faddp:
4266 // Scalar operation
4267 assert(insOptsNone(opt));
4268 assert(isValidVectorElemsizeFloat(size));
4269 assert(isVectorRegister(reg1));
4270 assert(isVectorRegister(reg2));
4271 fmt = IF_DV_2G;
4272 break;
4273
4274 case INS_fcvt:
4275 assert(insOptsConvertFloatToFloat(opt));
4276 assert(isValidVectorFcvtsize(size));
4277 assert(isVectorRegister(reg1));
4278 assert(isVectorRegister(reg2));
4279 fmt = IF_DV_2J;
4280 break;
4281
4282 case INS_cmeq:
4283 case INS_cmge:
4284 case INS_cmgt:
4285 case INS_cmle:
4286 case INS_cmlt:
4287 assert(isVectorRegister(reg1));
4288 assert(isVectorRegister(reg2));
4289
4290 if (isValidVectorDatasize(size))
4291 {
4292 // Vector operation
4293 assert(insOptsAnyArrangement(opt));
4294 assert(isValidArrangement(size, opt));
4295 elemsize = optGetElemsize(opt);
4296 fmt = IF_DV_2M;
4297 }
4298 else
4299 {
4300 NYI("Untested");
4301 // Scalar operation
4302 assert(size == EA_8BYTE); // Only Double supported
4303 fmt = IF_DV_2L;
4304 }
4305 break;
4306
4307 case INS_fcmeq:
4308 case INS_fcmge:
4309 case INS_fcmgt:
4310 case INS_fcmle:
4311 case INS_fcmlt:
4312 assert(isVectorRegister(reg1));
4313 assert(isVectorRegister(reg2));
4314
4315 if (isValidVectorDatasize(size))
4316 {
4317 // Vector operation
4318 assert(insOptsAnyArrangement(opt));
4319 assert(isValidArrangement(size, opt));
4320 elemsize = optGetElemsize(opt);
4321 assert((elemsize == EA_8BYTE) || (elemsize == EA_4BYTE)); // Only Double/Float supported
4322 assert(opt != INS_OPTS_1D); // Reserved encoding
4323 fmt = IF_DV_2A;
4324 }
4325 else
4326 {
4327 NYI("Untested");
4328 // Scalar operation
4329 assert((size == EA_8BYTE) || (size == EA_4BYTE)); // Only Double/Float supported
4330 fmt = IF_DV_2G;
4331 }
4332 break;
4333 case INS_aesd:
4334 case INS_aese:
4335 case INS_aesmc:
4336 case INS_aesimc:
4337 assert(isVectorRegister(reg1));
4338 assert(isVectorRegister(reg2));
4339 assert(isValidVectorDatasize(size));
4340 elemsize = optGetElemsize(opt);
4341 assert(elemsize == EA_1BYTE);
4342 fmt = IF_DV_2P;
4343 break;
4344
4345 case INS_sha1h:
4346 assert(insOptsNone(opt));
4347 assert(isVectorRegister(reg1));
4348 assert(isVectorRegister(reg2));
4349 fmt = IF_DR_2J;
4350 break;
4351
4352 case INS_sha256su0:
4353 case INS_sha1su1:
4354 assert(isVectorRegister(reg1));
4355 assert(isVectorRegister(reg2));
4356 assert(isValidVectorDatasize(size));
4357 elemsize = optGetElemsize(opt);
4358 assert(elemsize == EA_4BYTE);
4359 fmt = IF_DV_2P;
4360 break;
4361
4362 default:
4363 unreached();
4364 break;
4365
4366 } // end switch (ins)
4367
4368 assert(fmt != IF_NONE);
4369
4370 instrDesc* id = emitNewInstrSmall(attr);
4371
4372 id->idIns(ins);
4373 id->idInsFmt(fmt);
4374 id->idInsOpt(opt);
4375
4376 id->idReg1(reg1);
4377 id->idReg2(reg2);
4378
4379 dispIns(id);
4380 appendToCurIG(id);
4381}
4382
4383/*****************************************************************************
4384 *
4385 * Add an instruction referencing a register and two constants.
4386 */
4387
4388void emitter::emitIns_R_I_I(
4389 instruction ins, emitAttr attr, regNumber reg, ssize_t imm1, ssize_t imm2, insOpts opt /* = INS_OPTS_NONE */)
4390{
4391 emitAttr size = EA_SIZE(attr);
4392 insFormat fmt = IF_NONE;
4393 size_t immOut = 0; // composed from imm1 and imm2 and stored in the instrDesc
4394
4395 /* Figure out the encoding format of the instruction */
4396 switch (ins)
4397 {
4398 bool canEncode;
4399 halfwordImm hwi;
4400
4401 case INS_mov:
4402 ins = INS_movz; // INS_mov with LSL is an alias for INS_movz LSL
4403 __fallthrough;
4404
4405 case INS_movk:
4406 case INS_movn:
4407 case INS_movz:
4408 assert(isValidGeneralDatasize(size));
4409 assert(isGeneralRegister(reg));
4410 assert(isValidUimm16(imm1));
4411 assert(insOptsLSL(opt)); // Must be INS_OPTS_LSL
4412
4413 if (size == EA_8BYTE)
4414 {
4415 assert((imm2 == 0) || (imm2 == 16) || // shift amount: 0, 16, 32 or 48
4416 (imm2 == 32) || (imm2 == 48));
4417 }
4418 else // EA_4BYTE
4419 {
4420 assert((imm2 == 0) || (imm2 == 16)); // shift amount: 0 or 16
4421 }
4422
4423 hwi.immHWVal = 0;
4424
4425 switch (imm2)
4426 {
4427 case 0:
4428 hwi.immHW = 0;
4429 canEncode = true;
4430 break;
4431
4432 case 16:
4433 hwi.immHW = 1;
4434 canEncode = true;
4435 break;
4436
4437 case 32:
4438 hwi.immHW = 2;
4439 canEncode = true;
4440 break;
4441
4442 case 48:
4443 hwi.immHW = 3;
4444 canEncode = true;
4445 break;
4446
4447 default:
4448 canEncode = false;
4449 }
4450
4451 if (canEncode)
4452 {
4453 hwi.immVal = imm1;
4454
4455 immOut = hwi.immHWVal;
4456 assert(isValidImmHWVal(immOut, size));
4457 fmt = IF_DI_1B;
4458 }
4459 break;
4460
4461 default:
4462 unreached();
4463 break;
4464
4465 } // end switch (ins)
4466
4467 assert(fmt != IF_NONE);
4468
4469 instrDesc* id = emitNewInstrSC(attr, immOut);
4470
4471 id->idIns(ins);
4472 id->idInsFmt(fmt);
4473
4474 id->idReg1(reg);
4475
4476 dispIns(id);
4477 appendToCurIG(id);
4478}
4479
4480/*****************************************************************************
4481 *
4482 * Add an instruction referencing two registers and a constant.
4483 */
4484
4485void emitter::emitIns_R_R_I(
4486 instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, ssize_t imm, insOpts opt /* = INS_OPTS_NONE */)
4487{
4488 emitAttr size = EA_SIZE(attr);
4489 emitAttr elemsize = EA_UNKNOWN;
4490 insFormat fmt = IF_NONE;
4491 bool isLdSt = false;
4492 bool isSIMD = false;
4493 bool isAddSub = false;
4494 bool setFlags = false;
4495 unsigned scale = 0;
4496 bool unscaledOp = false;
4497
4498 /* Figure out the encoding format of the instruction */
4499 switch (ins)
4500 {
4501 bool canEncode;
4502 bitMaskImm bmi;
4503
4504 case INS_mov:
4505 // Check for the 'mov' aliases for the vector registers
4506 assert(insOptsNone(opt));
4507 assert(isValidVectorElemsize(size));
4508 elemsize = size;
4509 assert(isValidVectorIndex(EA_16BYTE, elemsize, imm));
4510
4511 if (isVectorRegister(reg1))
4512 {
4513 if (isGeneralRegisterOrZR(reg2))
4514 {
4515 fmt = IF_DV_2C; // Alias for 'ins'
4516 break;
4517 }
4518 else if (isVectorRegister(reg2))
4519 {
4520 fmt = IF_DV_2E; // Alias for 'dup'
4521 break;
4522 }
4523 }
4524 else // isGeneralRegister(reg1)
4525 {
4526 assert(isGeneralRegister(reg1));
4527 if (isVectorRegister(reg2))
4528 {
4529 fmt = IF_DV_2B; // Alias for 'umov'
4530 break;
4531 }
4532 }
4533 assert(!" invalid INS_mov operands");
4534 break;
4535
4536 case INS_lsl:
4537 case INS_lsr:
4538 case INS_asr:
4539 assert(insOptsNone(opt));
4540 assert(isValidGeneralDatasize(size));
4541 assert(isGeneralRegister(reg1));
4542 assert(isGeneralRegister(reg2));
4543 assert(isValidImmShift(imm, size));
4544 fmt = IF_DI_2D;
4545 break;
4546
4547 case INS_ror:
4548 assert(insOptsNone(opt));
4549 assert(isValidGeneralDatasize(size));
4550 assert(isGeneralRegister(reg1));
4551 assert(isGeneralRegister(reg2));
4552 assert(isValidImmShift(imm, size));
4553 fmt = IF_DI_2B;
4554 break;
4555
4556 case INS_sshr:
4557 case INS_ssra:
4558 case INS_srshr:
4559 case INS_srsra:
4560 case INS_shl:
4561 case INS_ushr:
4562 case INS_usra:
4563 case INS_urshr:
4564 case INS_ursra:
4565 case INS_sri:
4566 case INS_sli:
4567 assert(isVectorRegister(reg1));
4568 assert(isVectorRegister(reg2));
4569 if (insOptsAnyArrangement(opt))
4570 {
4571 // Vector operation
4572 assert(isValidVectorDatasize(size));
4573 assert(isValidArrangement(size, opt));
4574 elemsize = optGetElemsize(opt);
4575 assert(isValidVectorElemsize(elemsize));
4576 assert(isValidImmShift(imm, elemsize));
4577 assert(opt != INS_OPTS_1D); // Reserved encoding
4578 fmt = IF_DV_2O;
4579 break;
4580 }
4581 else
4582 {
4583 // Scalar operation
4584 assert(insOptsNone(opt));
4585 assert(size == EA_8BYTE); // only supported size
4586 assert(isValidImmShift(imm, size));
4587 fmt = IF_DV_2N;
4588 }
4589 break;
4590
4591 case INS_sxtl:
4592 case INS_uxtl:
4593 assert(imm == 0);
4594 __fallthrough;
4595
4596 case INS_shrn:
4597 case INS_rshrn:
4598 case INS_sshll:
4599 case INS_ushll:
4600 assert(isVectorRegister(reg1));
4601 assert(isVectorRegister(reg2));
4602 // Vector operation
4603 assert(size == EA_8BYTE);
4604 assert(isValidArrangement(size, opt));
4605 elemsize = optGetElemsize(opt);
4606 assert(elemsize != EA_8BYTE); // Reserved encodings
4607 assert(isValidVectorElemsize(elemsize));
4608 assert(isValidImmShift(imm, elemsize));
4609 fmt = IF_DV_2O;
4610 break;
4611
4612 case INS_sxtl2:
4613 case INS_uxtl2:
4614 assert(imm == 0);
4615 __fallthrough;
4616
4617 case INS_shrn2:
4618 case INS_rshrn2:
4619 case INS_sshll2:
4620 case INS_ushll2:
4621 assert(isVectorRegister(reg1));
4622 assert(isVectorRegister(reg2));
4623 // Vector operation
4624 assert(size == EA_16BYTE);
4625 assert(isValidArrangement(size, opt));
4626 elemsize = optGetElemsize(opt);
4627 assert(elemsize != EA_8BYTE); // Reserved encodings
4628 assert(isValidVectorElemsize(elemsize));
4629 assert(isValidImmShift(imm, elemsize));
4630 fmt = IF_DV_2O;
4631 break;
4632
4633 case INS_mvn:
4634 case INS_neg:
4635 case INS_negs:
4636 assert(isValidGeneralDatasize(size));
4637 assert(isGeneralRegister(reg1));
4638 assert(isGeneralRegisterOrZR(reg2));
4639
4640 if (imm == 0)
4641 {
4642 assert(insOptsNone(opt)); // a zero imm, means no alu shift kind
4643
4644 fmt = IF_DR_2E;
4645 }
4646 else
4647 {
4648 if (ins == INS_mvn)
4649 {
4650 assert(insOptsAnyShift(opt)); // a non-zero imm, must select shift kind
4651 }
4652 else // neg or negs
4653 {
4654 assert(insOptsAluShift(opt)); // a non-zero imm, must select shift kind, can't use ROR
4655 }
4656 assert(isValidImmShift(imm, size));
4657 fmt = IF_DR_2F;
4658 }
4659 break;
4660
4661 case INS_tst:
4662 assert(isValidGeneralDatasize(size));
4663 assert(isGeneralRegisterOrZR(reg1));
4664 assert(isGeneralRegister(reg2));
4665
4666 if (insOptsAnyShift(opt))
4667 {
4668 assert(isValidImmShift(imm, size) && (imm != 0));
4669 fmt = IF_DR_2B;
4670 }
4671 else
4672 {
4673 assert(insOptsNone(opt)); // a zero imm, means no alu shift kind
4674 assert(imm == 0);
4675 fmt = IF_DR_2A;
4676 }
4677 break;
4678
4679 case INS_cmp:
4680 case INS_cmn:
4681 assert(isValidGeneralDatasize(size));
4682 assert(isGeneralRegisterOrSP(reg1));
4683 assert(isGeneralRegister(reg2));
4684
4685 reg1 = encodingSPtoZR(reg1);
4686 if (insOptsAnyExtend(opt))
4687 {
4688 assert((imm >= 0) && (imm <= 4));
4689
4690 fmt = IF_DR_2C;
4691 }
4692 else if (imm == 0)
4693 {
4694 assert(insOptsNone(opt)); // a zero imm, means no alu shift kind
4695
4696 fmt = IF_DR_2A;
4697 }
4698 else
4699 {
4700 assert(insOptsAnyShift(opt)); // a non-zero imm, must select shift kind
4701 assert(isValidImmShift(imm, size));
4702 fmt = IF_DR_2B;
4703 }
4704 break;
4705
4706 case INS_ands:
4707 case INS_and:
4708 case INS_eor:
4709 case INS_orr:
4710 assert(insOptsNone(opt));
4711 assert(isGeneralRegister(reg2));
4712 if (ins == INS_ands)
4713 {
4714 assert(isGeneralRegister(reg1));
4715 }
4716 else
4717 {
4718 assert(isGeneralRegisterOrSP(reg1));
4719 reg1 = encodingSPtoZR(reg1);
4720 }
4721
4722 bmi.immNRS = 0;
4723 canEncode = canEncodeBitMaskImm(imm, size, &bmi);
4724 if (canEncode)
4725 {
4726 imm = bmi.immNRS;
4727 assert(isValidImmNRS(imm, size));
4728 fmt = IF_DI_2C;
4729 }
4730 break;
4731
4732 case INS_dup: // by element, imm selects the element of reg2
4733 assert(isVectorRegister(reg1));
4734 if (isVectorRegister(reg2))
4735 {
4736 if (insOptsAnyArrangement(opt))
4737 {
4738 // Vector operation
4739 assert(isValidVectorDatasize(size));
4740 assert(isValidArrangement(size, opt));
4741 elemsize = optGetElemsize(opt);
4742 assert(isValidVectorElemsize(elemsize));
4743 assert(isValidVectorIndex(size, elemsize, imm));
4744 assert(opt != INS_OPTS_1D); // Reserved encoding
4745 fmt = IF_DV_2D;
4746 break;
4747 }
4748 else
4749 {
4750 // Scalar operation
4751 assert(insOptsNone(opt));
4752 elemsize = size;
4753 assert(isValidVectorElemsize(elemsize));
4754 assert(isValidVectorIndex(EA_16BYTE, elemsize, imm));
4755 fmt = IF_DV_2E;
4756 break;
4757 }
4758 }
4759 __fallthrough;
4760
4761 case INS_ins: // (MOV from general)
4762 assert(insOptsNone(opt));
4763 assert(isValidVectorElemsize(size));
4764 assert(isVectorRegister(reg1));
4765 assert(isGeneralRegisterOrZR(reg2));
4766 elemsize = size;
4767 assert(isValidVectorIndex(EA_16BYTE, elemsize, imm));
4768 fmt = IF_DV_2C;
4769 break;
4770
4771 case INS_umov: // (MOV to general)
4772 assert(insOptsNone(opt));
4773 assert(isValidVectorElemsize(size));
4774 assert(isGeneralRegister(reg1));
4775 assert(isVectorRegister(reg2));
4776 elemsize = size;
4777 assert(isValidVectorIndex(EA_16BYTE, elemsize, imm));
4778 fmt = IF_DV_2B;
4779 break;
4780
4781 case INS_smov:
4782 assert(insOptsNone(opt));
4783 assert(isValidVectorElemsize(size));
4784 assert(size != EA_8BYTE); // no encoding, use INS_umov
4785 assert(isGeneralRegister(reg1));
4786 assert(isVectorRegister(reg2));
4787 elemsize = size;
4788 assert(isValidVectorIndex(EA_16BYTE, elemsize, imm));
4789 fmt = IF_DV_2B;
4790 break;
4791
4792 case INS_add:
4793 case INS_sub:
4794 setFlags = false;
4795 isAddSub = true;
4796 break;
4797
4798 case INS_adds:
4799 case INS_subs:
4800 setFlags = true;
4801 isAddSub = true;
4802 break;
4803
4804 case INS_ldrsb:
4805 case INS_ldursb:
4806 // 'size' specifies how we sign-extend into 4 or 8 bytes of the target register
4807 assert(isValidGeneralDatasize(size));
4808 unscaledOp = (ins == INS_ldursb);
4809 scale = 0;
4810 isLdSt = true;
4811 break;
4812
4813 case INS_ldrsh:
4814 case INS_ldursh:
4815 // 'size' specifies how we sign-extend into 4 or 8 bytes of the target register
4816 assert(isValidGeneralDatasize(size));
4817 unscaledOp = (ins == INS_ldursh);
4818 scale = 1;
4819 isLdSt = true;
4820 break;
4821
4822 case INS_ldrsw:
4823 case INS_ldursw:
4824 // 'size' specifies how we sign-extend into 4 or 8 bytes of the target register
4825 assert(size == EA_8BYTE);
4826 unscaledOp = (ins == INS_ldursw);
4827 scale = 2;
4828 isLdSt = true;
4829 break;
4830
4831 case INS_ldrb:
4832 case INS_strb:
4833 // size is ignored
4834 unscaledOp = false;
4835 scale = 0;
4836 isLdSt = true;
4837 break;
4838
4839 case INS_ldurb:
4840 case INS_sturb:
4841 // size is ignored
4842 unscaledOp = true;
4843 scale = 0;
4844 isLdSt = true;
4845 break;
4846
4847 case INS_ldrh:
4848 case INS_strh:
4849 // size is ignored
4850 unscaledOp = false;
4851 scale = 1;
4852 isLdSt = true;
4853 break;
4854
4855 case INS_ldurh:
4856 case INS_sturh:
4857 // size is ignored
4858 unscaledOp = true;
4859 scale = 0;
4860 isLdSt = true;
4861 break;
4862
4863 case INS_ldr:
4864 case INS_str:
4865 // Is the target a vector register?
4866 if (isVectorRegister(reg1))
4867 {
4868 assert(isValidVectorLSDatasize(size));
4869 assert(isGeneralRegisterOrSP(reg2));
4870 isSIMD = true;
4871 }
4872 else
4873 {
4874 assert(isValidGeneralDatasize(size));
4875 }
4876 unscaledOp = false;
4877 scale = NaturalScale_helper(size);
4878 isLdSt = true;
4879 break;
4880
4881 case INS_ldur:
4882 case INS_stur:
4883 // Is the target a vector register?
4884 if (isVectorRegister(reg1))
4885 {
4886 assert(isValidVectorLSDatasize(size));
4887 assert(isGeneralRegisterOrSP(reg2));
4888 isSIMD = true;
4889 }
4890 else
4891 {
4892 assert(isValidGeneralDatasize(size));
4893 }
4894 unscaledOp = true;
4895 scale = 0;
4896 isLdSt = true;
4897 break;
4898
4899 default:
4900 unreached();
4901 break;
4902
4903 } // end switch (ins)
4904
4905 if (isLdSt)
4906 {
4907 assert(!isAddSub);
4908
4909 if (isSIMD)
4910 {
4911 assert(isValidVectorLSDatasize(size));
4912 assert(isVectorRegister(reg1));
4913 assert((scale >= 0) && (scale <= 4));
4914 }
4915 else
4916 {
4917 assert(isValidGeneralLSDatasize(size));
4918 assert(isGeneralRegisterOrZR(reg1));
4919 assert((scale >= 0) && (scale <= 3));
4920 }
4921
4922 assert(isGeneralRegisterOrSP(reg2));
4923
4924 // Load/Store reserved encodings:
4925 if (insOptsIndexed(opt))
4926 {
4927 assert(reg1 != reg2);
4928 }
4929
4930 reg2 = encodingSPtoZR(reg2);
4931
4932 ssize_t mask = (1 << scale) - 1; // the mask of low bits that must be zero to encode the immediate
4933 if (imm == 0)
4934 {
4935 assert(insOptsNone(opt)); // PRE/POST Index doesn't make sense with an immediate of zero
4936
4937 fmt = IF_LS_2A;
4938 }
4939 else if (insOptsIndexed(opt) || unscaledOp || (imm < 0) || ((imm & mask) != 0))
4940 {
4941 if ((imm >= -256) && (imm <= 255))
4942 {
4943 fmt = IF_LS_2C;
4944 }
4945 else
4946 {
4947 assert(!"Instruction cannot be encoded: IF_LS_2C");
4948 }
4949 }
4950 else if (imm > 0)
4951 {
4952 assert(insOptsNone(opt));
4953 assert(!unscaledOp);
4954
4955 if (((imm & mask) == 0) && ((imm >> scale) < 0x1000))
4956 {
4957 imm >>= scale; // The immediate is scaled by the size of the ld/st
4958
4959 fmt = IF_LS_2B;
4960 }
4961 else
4962 {
4963 assert(!"Instruction cannot be encoded: IF_LS_2B");
4964 }
4965 }
4966 }
4967 else if (isAddSub)
4968 {
4969 assert(!isLdSt);
4970 assert(insOptsNone(opt));
4971
4972 if (setFlags) // Can't encode SP with setFlags
4973 {
4974 assert(isGeneralRegister(reg1));
4975 assert(isGeneralRegister(reg2));
4976 }
4977 else
4978 {
4979 assert(isGeneralRegisterOrSP(reg1));
4980 assert(isGeneralRegisterOrSP(reg2));
4981
4982 // Is it just a mov?
4983 if (imm == 0)
4984 {
4985 // Is the mov even necessary?
4986 if (reg1 != reg2)
4987 {
4988 emitIns_R_R(INS_mov, attr, reg1, reg2);
4989 }
4990 return;
4991 }
4992
4993 reg1 = encodingSPtoZR(reg1);
4994 reg2 = encodingSPtoZR(reg2);
4995 }
4996
4997 if (unsigned_abs(imm) <= 0x0fff)
4998 {
4999 if (imm < 0)
5000 {
5001 ins = insReverse(ins);
5002 imm = -imm;
5003 }
5004 assert(isValidUimm12(imm));
5005 fmt = IF_DI_2A;
5006 }
5007 else if (canEncodeWithShiftImmBy12(imm)) // Try the shifted by 12 encoding
5008 {
5009 // Encoding will use a 12-bit left shift of the immediate
5010 opt = INS_OPTS_LSL12;
5011 if (imm < 0)
5012 {
5013 ins = insReverse(ins);
5014 imm = -imm;
5015 }
5016 assert((imm & 0xfff) == 0);
5017 imm >>= 12;
5018 assert(isValidUimm12(imm));
5019 fmt = IF_DI_2A;
5020 }
5021 else
5022 {
5023 assert(!"Instruction cannot be encoded: IF_DI_2A");
5024 }
5025 }
5026
5027 assert(fmt != IF_NONE);
5028
5029 instrDesc* id = emitNewInstrSC(attr, imm);
5030
5031 id->idIns(ins);
5032 id->idInsFmt(fmt);
5033 id->idInsOpt(opt);
5034
5035 id->idReg1(reg1);
5036 id->idReg2(reg2);
5037
5038 dispIns(id);
5039 appendToCurIG(id);
5040}
5041
5042/*****************************************************************************
5043*
5044* Add an instruction referencing two registers and a constant.
5045* Also checks for a large immediate that needs a second instruction
5046* and will load it in reg1
5047*
5048* - Supports instructions: add, adds, sub, subs, and, ands, eor and orr
5049* - Requires that reg1 is a general register and not SP or ZR
5050* - Requires that reg1 != reg2
5051*/
5052void emitter::emitIns_R_R_Imm(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, ssize_t imm)
5053{
5054 assert(isGeneralRegister(reg1));
5055 assert(reg1 != reg2);
5056
5057 bool immFits = true;
5058
5059 switch (ins)
5060 {
5061 case INS_add:
5062 case INS_adds:
5063 case INS_sub:
5064 case INS_subs:
5065 immFits = emitter::emitIns_valid_imm_for_add(imm, attr);
5066 break;
5067
5068 case INS_ands:
5069 case INS_and:
5070 case INS_eor:
5071 case INS_orr:
5072 immFits = emitter::emitIns_valid_imm_for_alu(imm, attr);
5073 break;
5074
5075 default:
5076 assert(!"Unsupported instruction in emitIns_R_R_Imm");
5077 }
5078
5079 if (immFits)
5080 {
5081 emitIns_R_R_I(ins, attr, reg1, reg2, imm);
5082 }
5083 else
5084 {
5085 // Load 'imm' into the reg1 register
5086 // then issue: 'ins' reg1, reg2, reg1
5087 //
5088 codeGen->instGen_Set_Reg_To_Imm(attr, reg1, imm);
5089 emitIns_R_R_R(ins, attr, reg1, reg2, reg1);
5090 }
5091}
5092
5093/*****************************************************************************
5094 *
5095 * Add an instruction referencing three registers.
5096 */
5097
5098void emitter::emitIns_R_R_R(
5099 instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, regNumber reg3, insOpts opt) /* = INS_OPTS_NONE */
5100{
5101 emitAttr size = EA_SIZE(attr);
5102 emitAttr elemsize = EA_UNKNOWN;
5103 insFormat fmt = IF_NONE;
5104
5105 /* Figure out the encoding format of the instruction */
5106 switch (ins)
5107 {
5108 case INS_lsl:
5109 case INS_lsr:
5110 case INS_asr:
5111 case INS_ror:
5112 case INS_adc:
5113 case INS_adcs:
5114 case INS_sbc:
5115 case INS_sbcs:
5116 case INS_udiv:
5117 case INS_sdiv:
5118 case INS_mneg:
5119 case INS_smull:
5120 case INS_smnegl:
5121 case INS_smulh:
5122 case INS_umull:
5123 case INS_umnegl:
5124 case INS_umulh:
5125 case INS_lslv:
5126 case INS_lsrv:
5127 case INS_asrv:
5128 case INS_rorv:
5129 assert(insOptsNone(opt));
5130 assert(isValidGeneralDatasize(size));
5131 assert(isGeneralRegister(reg1));
5132 assert(isGeneralRegister(reg2));
5133 assert(isGeneralRegister(reg3));
5134 fmt = IF_DR_3A;
5135 break;
5136
5137 case INS_mul:
5138 if (insOptsNone(opt))
5139 {
5140 // general register
5141 assert(isValidGeneralDatasize(size));
5142 assert(isGeneralRegister(reg1));
5143 assert(isGeneralRegister(reg2));
5144 assert(isGeneralRegister(reg3));
5145 fmt = IF_DR_3A;
5146 break;
5147 }
5148 __fallthrough;
5149
5150 case INS_mla:
5151 case INS_mls:
5152 case INS_pmul:
5153 assert(insOptsAnyArrangement(opt));
5154 assert(isVectorRegister(reg1));
5155 assert(isVectorRegister(reg2));
5156 assert(isVectorRegister(reg3));
5157 assert(isValidVectorDatasize(size));
5158 assert(isValidArrangement(size, opt));
5159 elemsize = optGetElemsize(opt);
5160 if (ins == INS_pmul)
5161 {
5162 assert(elemsize == EA_1BYTE); // only supports 8B or 16B
5163 }
5164 else // INS_mul, INS_mla, INS_mls
5165 {
5166 assert(elemsize != EA_8BYTE); // can't use 2D or 1D
5167 }
5168 fmt = IF_DV_3A;
5169 break;
5170
5171 case INS_add:
5172 case INS_sub:
5173 if (isVectorRegister(reg1))
5174 {
5175 assert(isVectorRegister(reg2));
5176 assert(isVectorRegister(reg3));
5177
5178 if (insOptsAnyArrangement(opt))
5179 {
5180 // Vector operation
5181 assert(opt != INS_OPTS_1D); // Reserved encoding
5182 assert(isValidVectorDatasize(size));
5183 assert(isValidArrangement(size, opt));
5184 fmt = IF_DV_3A;
5185 }
5186 else
5187 {
5188 // Scalar operation
5189 assert(insOptsNone(opt));
5190 assert(size == EA_8BYTE);
5191 fmt = IF_DV_3E;
5192 }
5193 break;
5194 }
5195 __fallthrough;
5196
5197 case INS_adds:
5198 case INS_subs:
5199 emitIns_R_R_R_I(ins, attr, reg1, reg2, reg3, 0, INS_OPTS_NONE);
5200 return;
5201
5202 case INS_cmeq:
5203 case INS_cmge:
5204 case INS_cmgt:
5205 case INS_cmhi:
5206 case INS_cmhs:
5207 case INS_ctst:
5208 assert(isVectorRegister(reg1));
5209 assert(isVectorRegister(reg2));
5210 assert(isVectorRegister(reg3));
5211
5212 if (isValidVectorDatasize(size))
5213 {
5214 // Vector operation
5215 assert(insOptsAnyArrangement(opt));
5216 assert(isValidArrangement(size, opt));
5217 elemsize = optGetElemsize(opt);
5218 fmt = IF_DV_3A;
5219 }
5220 else
5221 {
5222 NYI("Untested");
5223 // Scalar operation
5224 assert(size == EA_8BYTE); // Only Double supported
5225 fmt = IF_DV_3E;
5226 }
5227 break;
5228
5229 case INS_fcmeq:
5230 case INS_fcmge:
5231 case INS_fcmgt:
5232 assert(isVectorRegister(reg1));
5233 assert(isVectorRegister(reg2));
5234 assert(isVectorRegister(reg3));
5235
5236 if (isValidVectorDatasize(size))
5237 {
5238 // Vector operation
5239 assert(insOptsAnyArrangement(opt));
5240 assert(isValidArrangement(size, opt));
5241 elemsize = optGetElemsize(opt);
5242 assert((elemsize == EA_8BYTE) || (elemsize == EA_4BYTE)); // Only Double/Float supported
5243 assert(opt != INS_OPTS_1D); // Reserved encoding
5244 fmt = IF_DV_3B;
5245 }
5246 else
5247 {
5248 NYI("Untested");
5249 // Scalar operation
5250 assert((size == EA_8BYTE) || (size == EA_4BYTE)); // Only Double/Float supported
5251 fmt = IF_DV_3D;
5252 }
5253 break;
5254
5255 case INS_saba:
5256 case INS_sabd:
5257 case INS_smax:
5258 case INS_smin:
5259 case INS_uaba:
5260 case INS_uabd:
5261 case INS_umax:
5262 case INS_umin:
5263 assert(isVectorRegister(reg1));
5264 assert(isVectorRegister(reg2));
5265 assert(isVectorRegister(reg3));
5266 assert(insOptsAnyArrangement(opt));
5267
5268 // Vector operation
5269 assert(isValidVectorDatasize(size));
5270 assert(isValidArrangement(size, opt));
5271 elemsize = optGetElemsize(opt);
5272 assert(elemsize != EA_8BYTE); // can't use 2D or 1D
5273
5274 fmt = IF_DV_3A;
5275 break;
5276
5277 case INS_mov:
5278 assert(isVectorRegister(reg1));
5279 assert(isVectorRegister(reg2));
5280 assert(reg2 == reg3);
5281 assert(isValidVectorDatasize(size));
5282 // INS_mov is an alias for INS_orr (vector register)
5283 if (opt == INS_OPTS_NONE)
5284 {
5285 elemsize = EA_1BYTE;
5286 opt = optMakeArrangement(size, elemsize);
5287 }
5288 assert(isValidArrangement(size, opt));
5289 fmt = IF_DV_3C;
5290 break;
5291
5292 case INS_and:
5293 case INS_bic:
5294 case INS_eor:
5295 case INS_orr:
5296 case INS_orn:
5297 if (isVectorRegister(reg1))
5298 {
5299 assert(isValidVectorDatasize(size));
5300 assert(isVectorRegister(reg2));
5301 assert(isVectorRegister(reg3));
5302 if (opt == INS_OPTS_NONE)
5303 {
5304 elemsize = EA_1BYTE;
5305 opt = optMakeArrangement(size, elemsize);
5306 }
5307 assert(isValidArrangement(size, opt));
5308 fmt = IF_DV_3C;
5309 break;
5310 }
5311 __fallthrough;
5312
5313 case INS_ands:
5314 case INS_bics:
5315 case INS_eon:
5316 emitIns_R_R_R_I(ins, attr, reg1, reg2, reg3, 0, INS_OPTS_NONE);
5317 return;
5318
5319 case INS_bsl:
5320 case INS_bit:
5321 case INS_bif:
5322 assert(isValidVectorDatasize(size));
5323 assert(isVectorRegister(reg1));
5324 assert(isVectorRegister(reg2));
5325 assert(isVectorRegister(reg3));
5326 if (opt == INS_OPTS_NONE)
5327 {
5328 elemsize = EA_1BYTE;
5329 opt = optMakeArrangement(size, elemsize);
5330 }
5331 assert(isValidArrangement(size, opt));
5332 fmt = IF_DV_3C;
5333 break;
5334
5335 case INS_fadd:
5336 case INS_fsub:
5337 case INS_fdiv:
5338 case INS_fmax:
5339 case INS_fmin:
5340 case INS_fabd:
5341 case INS_fmul:
5342 case INS_fmulx:
5343 assert(isVectorRegister(reg1));
5344 assert(isVectorRegister(reg2));
5345 assert(isVectorRegister(reg3));
5346 if (insOptsAnyArrangement(opt))
5347 {
5348 // Vector operation
5349 assert(isValidVectorDatasize(size));
5350 assert(isValidArrangement(size, opt));
5351 elemsize = optGetElemsize(opt);
5352 assert(isValidVectorElemsizeFloat(elemsize));
5353 assert(opt != INS_OPTS_1D); // Reserved encoding
5354 fmt = IF_DV_3B;
5355 }
5356 else
5357 {
5358 // Scalar operation
5359 assert(insOptsNone(opt));
5360 assert(isValidScalarDatasize(size));
5361 fmt = IF_DV_3D;
5362 }
5363 break;
5364
5365 case INS_fnmul:
5366 // Scalar operation
5367 assert(insOptsNone(opt));
5368 assert(isVectorRegister(reg1));
5369 assert(isVectorRegister(reg2));
5370 assert(isVectorRegister(reg3));
5371 assert(isValidScalarDatasize(size));
5372 fmt = IF_DV_3D;
5373 break;
5374
5375 case INS_faddp:
5376 case INS_fmla:
5377 case INS_fmls:
5378 assert(isVectorRegister(reg1));
5379 assert(isVectorRegister(reg2));
5380 assert(isVectorRegister(reg3));
5381 assert(insOptsAnyArrangement(opt)); // no scalar encoding, use 4-operand 'fmadd' or 'fmsub'
5382
5383 // Vector operation
5384 assert(isValidVectorDatasize(size));
5385 assert(isValidArrangement(size, opt));
5386 elemsize = optGetElemsize(opt);
5387 assert(isValidVectorElemsizeFloat(elemsize));
5388 assert(opt != INS_OPTS_1D); // Reserved encoding
5389 fmt = IF_DV_3B;
5390 break;
5391
5392 case INS_ldr:
5393 case INS_ldrb:
5394 case INS_ldrh:
5395 case INS_ldrsb:
5396 case INS_ldrsh:
5397 case INS_ldrsw:
5398 case INS_str:
5399 case INS_strb:
5400 case INS_strh:
5401 emitIns_R_R_R_Ext(ins, attr, reg1, reg2, reg3, opt);
5402 return;
5403
5404 case INS_ldp:
5405 case INS_ldpsw:
5406 case INS_ldnp:
5407 case INS_stp:
5408 case INS_stnp:
5409 emitIns_R_R_R_I(ins, attr, reg1, reg2, reg3, 0);
5410 return;
5411
5412 case INS_stxr:
5413 case INS_stxrb:
5414 case INS_stxrh:
5415 case INS_stlxr:
5416 case INS_stlxrb:
5417 case INS_stlxrh:
5418 assert(isGeneralRegisterOrZR(reg1));
5419 assert(isGeneralRegisterOrZR(reg2));
5420 assert(isGeneralRegisterOrSP(reg3));
5421 fmt = IF_LS_3D;
5422 break;
5423
5424 case INS_casb:
5425 case INS_casab:
5426 case INS_casalb:
5427 case INS_caslb:
5428 case INS_cash:
5429 case INS_casah:
5430 case INS_casalh:
5431 case INS_caslh:
5432 case INS_cas:
5433 case INS_casa:
5434 case INS_casal:
5435 case INS_casl:
5436 case INS_ldaddb:
5437 case INS_ldaddab:
5438 case INS_ldaddalb:
5439 case INS_ldaddlb:
5440 case INS_ldaddh:
5441 case INS_ldaddah:
5442 case INS_ldaddalh:
5443 case INS_ldaddlh:
5444 case INS_ldadd:
5445 case INS_ldadda:
5446 case INS_ldaddal:
5447 case INS_ldaddl:
5448 case INS_swpb:
5449 case INS_swpab:
5450 case INS_swpalb:
5451 case INS_swplb:
5452 case INS_swph:
5453 case INS_swpah:
5454 case INS_swpalh:
5455 case INS_swplh:
5456 case INS_swp:
5457 case INS_swpa:
5458 case INS_swpal:
5459 case INS_swpl:
5460 assert(isGeneralRegisterOrZR(reg1));
5461 assert(isGeneralRegisterOrZR(reg2));
5462 assert(isGeneralRegisterOrSP(reg3));
5463 fmt = IF_LS_3E;
5464 break;
5465
5466 case INS_sha256h:
5467 case INS_sha256h2:
5468 case INS_sha256su1:
5469 case INS_sha1su0:
5470 case INS_sha1c:
5471 case INS_sha1p:
5472 case INS_sha1m:
5473 assert(isValidVectorDatasize(size));
5474 assert(isVectorRegister(reg1));
5475 assert(isVectorRegister(reg2));
5476 assert(isVectorRegister(reg3));
5477 if (opt == INS_OPTS_NONE)
5478 {
5479 elemsize = EA_4BYTE;
5480 opt = optMakeArrangement(size, elemsize);
5481 }
5482 assert(isValidArrangement(size, opt));
5483 fmt = IF_DV_3F;
5484 break;
5485
5486 default:
5487 unreached();
5488 break;
5489
5490 } // end switch (ins)
5491
5492 assert(fmt != IF_NONE);
5493
5494 instrDesc* id = emitNewInstr(attr);
5495
5496 id->idIns(ins);
5497 id->idInsFmt(fmt);
5498 id->idInsOpt(opt);
5499
5500 id->idReg1(reg1);
5501 id->idReg2(reg2);
5502 id->idReg3(reg3);
5503
5504 dispIns(id);
5505 appendToCurIG(id);
5506}
5507
5508/*****************************************************************************
5509 *
5510 * Add an instruction referencing three registers and a constant.
5511 */
5512
5513void emitter::emitIns_R_R_R_I(instruction ins,
5514 emitAttr attr,
5515 regNumber reg1,
5516 regNumber reg2,
5517 regNumber reg3,
5518 ssize_t imm,
5519 insOpts opt /* = INS_OPTS_NONE */,
5520 emitAttr attrReg2 /* = EA_UNKNOWN */)
5521{
5522 emitAttr size = EA_SIZE(attr);
5523 emitAttr elemsize = EA_UNKNOWN;
5524 insFormat fmt = IF_NONE;
5525 bool isLdSt = false;
5526 bool isSIMD = false;
5527 bool isAddSub = false;
5528 bool setFlags = false;
5529 unsigned scale = 0;
5530
5531 /* Figure out the encoding format of the instruction */
5532 switch (ins)
5533 {
5534 case INS_extr:
5535 assert(insOptsNone(opt));
5536 assert(isValidGeneralDatasize(size));
5537 assert(isGeneralRegister(reg1));
5538 assert(isGeneralRegister(reg2));
5539 assert(isGeneralRegister(reg3));
5540 assert(isValidImmShift(imm, size));
5541 fmt = IF_DR_3E;
5542 break;
5543
5544 case INS_and:
5545 case INS_ands:
5546 case INS_eor:
5547 case INS_orr:
5548 case INS_bic:
5549 case INS_bics:
5550 case INS_eon:
5551 case INS_orn:
5552 assert(isValidGeneralDatasize(size));
5553 assert(isGeneralRegister(reg1));
5554 assert(isGeneralRegister(reg2));
5555 assert(isGeneralRegister(reg3));
5556 assert(isValidImmShift(imm, size));
5557 if (imm == 0)
5558 {
5559 assert(insOptsNone(opt)); // a zero imm, means no shift kind
5560 fmt = IF_DR_3A;
5561 }
5562 else
5563 {
5564 assert(insOptsAnyShift(opt)); // a non-zero imm, must select shift kind
5565 fmt = IF_DR_3B;
5566 }
5567 break;
5568
5569 case INS_fmul: // by element, imm[0..3] selects the element of reg3
5570 case INS_fmla:
5571 case INS_fmls:
5572 case INS_fmulx:
5573 assert(isVectorRegister(reg1));
5574 assert(isVectorRegister(reg2));
5575 assert(isVectorRegister(reg3));
5576 if (insOptsAnyArrangement(opt))
5577 {
5578 // Vector operation
5579 assert(isValidVectorDatasize(size));
5580 assert(isValidArrangement(size, opt));
5581 elemsize = optGetElemsize(opt);
5582 assert(isValidVectorElemsizeFloat(elemsize));
5583 assert(isValidVectorIndex(size, elemsize, imm));
5584 assert(opt != INS_OPTS_1D); // Reserved encoding
5585 fmt = IF_DV_3BI;
5586 }
5587 else
5588 {
5589 // Scalar operation
5590 assert(insOptsNone(opt));
5591 assert(isValidScalarDatasize(size));
5592 elemsize = size;
5593 assert(isValidVectorIndex(EA_16BYTE, elemsize, imm));
5594 fmt = IF_DV_3DI;
5595 }
5596 break;
5597
5598 case INS_mul: // by element, imm[0..7] selects the element of reg3
5599 case INS_mla:
5600 case INS_mls:
5601 assert(isVectorRegister(reg1));
5602 assert(isVectorRegister(reg2));
5603 assert(isVectorRegister(reg3));
5604 // Vector operation
5605 assert(insOptsAnyArrangement(opt));
5606 assert(isValidVectorDatasize(size));
5607 assert(isValidArrangement(size, opt));
5608 elemsize = optGetElemsize(opt);
5609 assert(isValidVectorIndex(EA_16BYTE, elemsize, imm));
5610 // Only has encodings for H or S elemsize
5611 assert((elemsize == EA_2BYTE) || (elemsize == EA_4BYTE));
5612 // Only has encodings for V0..V15
5613 if ((elemsize == EA_2BYTE) && (reg3 >= REG_V16))
5614 {
5615 noway_assert(!"Invalid reg3");
5616 }
5617 fmt = IF_DV_3AI;
5618 break;
5619
5620 case INS_add:
5621 case INS_sub:
5622 setFlags = false;
5623 isAddSub = true;
5624 break;
5625
5626 case INS_adds:
5627 case INS_subs:
5628 setFlags = true;
5629 isAddSub = true;
5630 break;
5631
5632 case INS_ldpsw:
5633 scale = 2;
5634 isLdSt = true;
5635 break;
5636
5637 case INS_ldnp:
5638 case INS_stnp:
5639 assert(insOptsNone(opt)); // Can't use Pre/Post index on these two instructions
5640 __fallthrough;
5641
5642 case INS_ldp:
5643 case INS_stp:
5644 // Is the target a vector register?
5645 if (isVectorRegister(reg1))
5646 {
5647 scale = NaturalScale_helper(size);
5648 isSIMD = true;
5649 }
5650 else
5651 {
5652 scale = (size == EA_8BYTE) ? 3 : 2;
5653 }
5654 isLdSt = true;
5655 break;
5656
5657 default:
5658 unreached();
5659 break;
5660
5661 } // end switch (ins)
5662
5663 if (isLdSt)
5664 {
5665 assert(!isAddSub);
5666 assert(isGeneralRegisterOrSP(reg3));
5667 assert(insOptsNone(opt) || insOptsIndexed(opt));
5668
5669 if (isSIMD)
5670 {
5671 assert(isValidVectorLSPDatasize(size));
5672 assert(isVectorRegister(reg1));
5673 assert(isVectorRegister(reg2));
5674 assert((scale >= 2) && (scale <= 4));
5675 }
5676 else
5677 {
5678 assert(isValidGeneralDatasize(size));
5679 assert(isGeneralRegisterOrZR(reg1));
5680 assert(isGeneralRegisterOrZR(reg2));
5681 assert((scale == 2) || (scale == 3));
5682 }
5683
5684 // Load/Store Pair reserved encodings:
5685 if (emitInsIsLoad(ins))
5686 {
5687 assert(reg1 != reg2);
5688 }
5689 if (insOptsIndexed(opt))
5690 {
5691 assert(reg1 != reg3);
5692 assert(reg2 != reg3);
5693 }
5694
5695 reg3 = encodingSPtoZR(reg3);
5696
5697 ssize_t mask = (1 << scale) - 1; // the mask of low bits that must be zero to encode the immediate
5698 if (imm == 0)
5699 {
5700 assert(insOptsNone(opt)); // PRE/POST Index doesn't make sense with an immediate of zero
5701
5702 fmt = IF_LS_3B;
5703 }
5704 else
5705 {
5706 if ((imm & mask) == 0)
5707 {
5708 imm >>= scale; // The immediate is scaled by the size of the ld/st
5709
5710 if ((imm >= -64) && (imm <= 63))
5711 {
5712 fmt = IF_LS_3C;
5713 }
5714 }
5715#ifdef DEBUG
5716 if (fmt != IF_LS_3C)
5717 {
5718 assert(!"Instruction cannot be encoded: IF_LS_3C");
5719 }
5720#endif
5721 }
5722 }
5723 else if (isAddSub)
5724 {
5725 bool reg2IsSP = (reg2 == REG_SP);
5726 assert(!isLdSt);
5727 assert(isValidGeneralDatasize(size));
5728 assert(isGeneralRegister(reg3));
5729
5730 if (setFlags || insOptsAluShift(opt)) // Can't encode SP in reg1 with setFlags or AluShift option
5731 {
5732 assert(isGeneralRegisterOrZR(reg1));
5733 }
5734 else
5735 {
5736 assert(isGeneralRegisterOrSP(reg1));
5737 reg1 = encodingSPtoZR(reg1);
5738 }
5739
5740 if (insOptsAluShift(opt)) // Can't encode SP in reg2 with AluShift option
5741 {
5742 assert(isGeneralRegister(reg2));
5743 }
5744 else
5745 {
5746 assert(isGeneralRegisterOrSP(reg2));
5747 reg2 = encodingSPtoZR(reg2);
5748 }
5749
5750 if (insOptsAnyExtend(opt))
5751 {
5752 assert((imm >= 0) && (imm <= 4));
5753
5754 fmt = IF_DR_3C;
5755 }
5756 else if (insOptsAluShift(opt))
5757 {
5758 // imm should be non-zero and in [1..63]
5759 assert(isValidImmShift(imm, size) && (imm != 0));
5760 fmt = IF_DR_3B;
5761 }
5762 else if (imm == 0)
5763 {
5764 assert(insOptsNone(opt));
5765
5766 if (reg2IsSP)
5767 {
5768 // To encode the SP register as reg2 we must use the IF_DR_3C encoding
5769 // and also specify a LSL of zero (imm == 0)
5770 opt = INS_OPTS_LSL;
5771 fmt = IF_DR_3C;
5772 }
5773 else
5774 {
5775 fmt = IF_DR_3A;
5776 }
5777 }
5778 else
5779 {
5780 assert(!"Instruction cannot be encoded: Add/Sub IF_DR_3A");
5781 }
5782 }
5783 assert(fmt != IF_NONE);
5784
5785 instrDesc* id = emitNewInstrCns(attr, imm);
5786
5787 id->idIns(ins);
5788 id->idInsFmt(fmt);
5789 id->idInsOpt(opt);
5790
5791 id->idReg1(reg1);
5792 id->idReg2(reg2);
5793 id->idReg3(reg3);
5794
5795 // Record the attribute for the second register in the pair
5796 id->idGCrefReg2(GCT_NONE);
5797 if (attrReg2 != EA_UNKNOWN)
5798 {
5799 // Record the attribute for the second register in the pair
5800 assert((fmt == IF_LS_3B) || (fmt == IF_LS_3C));
5801 if (EA_IS_GCREF(attrReg2))
5802 {
5803 id->idGCrefReg2(GCT_GCREF);
5804 }
5805 else if (EA_IS_BYREF(attrReg2))
5806 {
5807 id->idGCrefReg2(GCT_BYREF);
5808 }
5809 }
5810
5811 dispIns(id);
5812 appendToCurIG(id);
5813}
5814
5815/*****************************************************************************
5816 *
5817 * Add an instruction referencing three registers, with an extend option
5818 */
5819
5820void emitter::emitIns_R_R_R_Ext(instruction ins,
5821 emitAttr attr,
5822 regNumber reg1,
5823 regNumber reg2,
5824 regNumber reg3,
5825 insOpts opt, /* = INS_OPTS_NONE */
5826 int shiftAmount) /* = -1 -- unset */
5827{
5828 emitAttr size = EA_SIZE(attr);
5829 insFormat fmt = IF_NONE;
5830 bool isSIMD = false;
5831 int scale = -1;
5832
5833 /* Figure out the encoding format of the instruction */
5834 switch (ins)
5835 {
5836 case INS_ldrb:
5837 case INS_ldrsb:
5838 case INS_strb:
5839 scale = 0;
5840 break;
5841
5842 case INS_ldrh:
5843 case INS_ldrsh:
5844 case INS_strh:
5845 scale = 1;
5846 break;
5847
5848 case INS_ldrsw:
5849 scale = 2;
5850 break;
5851
5852 case INS_ldr:
5853 case INS_str:
5854 // Is the target a vector register?
5855 if (isVectorRegister(reg1))
5856 {
5857 assert(isValidVectorLSDatasize(size));
5858 scale = NaturalScale_helper(size);
5859 isSIMD = true;
5860 }
5861 else
5862 {
5863 assert(isValidGeneralDatasize(size));
5864 scale = (size == EA_8BYTE) ? 3 : 2;
5865 }
5866
5867 break;
5868
5869 default:
5870 unreached();
5871 break;
5872
5873 } // end switch (ins)
5874
5875 assert(scale != -1);
5876 assert(insOptsLSExtend(opt));
5877
5878 if (isSIMD)
5879 {
5880 assert(isValidVectorLSDatasize(size));
5881 assert(isVectorRegister(reg1));
5882 }
5883 else
5884 {
5885 assert(isValidGeneralLSDatasize(size));
5886 assert(isGeneralRegisterOrZR(reg1));
5887 }
5888
5889 assert(isGeneralRegisterOrSP(reg2));
5890 assert(isGeneralRegister(reg3));
5891
5892 // Load/Store reserved encodings:
5893 if (insOptsIndexed(opt))
5894 {
5895 assert(reg1 != reg2);
5896 }
5897
5898 if (shiftAmount == -1)
5899 {
5900 shiftAmount = insOptsLSL(opt) ? scale : 0;
5901 }
5902 assert((shiftAmount == scale) || (shiftAmount == 0));
5903
5904 reg2 = encodingSPtoZR(reg2);
5905 fmt = IF_LS_3A;
5906
5907 instrDesc* id = emitNewInstr(attr);
5908
5909 id->idIns(ins);
5910 id->idInsFmt(fmt);
5911 id->idInsOpt(opt);
5912
5913 id->idReg1(reg1);
5914 id->idReg2(reg2);
5915 id->idReg3(reg3);
5916 id->idReg3Scaled(shiftAmount == scale);
5917
5918 dispIns(id);
5919 appendToCurIG(id);
5920}
5921
5922/*****************************************************************************
5923 *
5924 * Add an instruction referencing two registers and two constants.
5925 */
5926
5927void emitter::emitIns_R_R_I_I(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, int imm1, int imm2)
5928{
5929 emitAttr size = EA_SIZE(attr);
5930 emitAttr elemsize = EA_UNKNOWN;
5931 insFormat fmt = IF_NONE;
5932 size_t immOut = 0; // composed from imm1 and imm2 and stored in the instrDesc
5933
5934 /* Figure out the encoding format of the instruction */
5935 switch (ins)
5936 {
5937 int lsb;
5938 int width;
5939 bitMaskImm bmi;
5940
5941 case INS_bfm:
5942 case INS_sbfm:
5943 case INS_ubfm:
5944 assert(isGeneralRegister(reg1));
5945 assert(isGeneralRegister(reg2));
5946 assert(isValidImmShift(imm1, size));
5947 assert(isValidImmShift(imm2, size));
5948 bmi.immNRS = 0;
5949 bmi.immN = (size == EA_8BYTE);
5950 bmi.immR = imm1;
5951 bmi.immS = imm2;
5952 immOut = bmi.immNRS;
5953 fmt = IF_DI_2D;
5954 break;
5955
5956 case INS_bfi:
5957 case INS_sbfiz:
5958 case INS_ubfiz:
5959 assert(isGeneralRegister(reg1));
5960 assert(isGeneralRegister(reg2));
5961 lsb = getBitWidth(size) - imm1;
5962 width = imm2 - 1;
5963 assert(isValidImmShift(lsb, size));
5964 assert(isValidImmShift(width, size));
5965 bmi.immNRS = 0;
5966 bmi.immN = (size == EA_8BYTE);
5967 bmi.immR = lsb;
5968 bmi.immS = width;
5969 immOut = bmi.immNRS;
5970 fmt = IF_DI_2D;
5971 break;
5972
5973 case INS_bfxil:
5974 case INS_sbfx:
5975 case INS_ubfx:
5976 assert(isGeneralRegister(reg1));
5977 assert(isGeneralRegister(reg2));
5978 lsb = imm1;
5979 width = imm2 + imm1 - 1;
5980 assert(isValidImmShift(lsb, size));
5981 assert(isValidImmShift(width, size));
5982 bmi.immNRS = 0;
5983 bmi.immN = (size == EA_8BYTE);
5984 bmi.immR = imm1;
5985 bmi.immS = imm2 + imm1 - 1;
5986 immOut = bmi.immNRS;
5987 fmt = IF_DI_2D;
5988 break;
5989
5990 case INS_mov:
5991 case INS_ins:
5992 assert(isVectorRegister(reg1));
5993 assert(isVectorRegister(reg2));
5994 elemsize = size;
5995 assert(isValidVectorElemsize(elemsize));
5996 assert(isValidVectorIndex(EA_16BYTE, elemsize, imm1));
5997 assert(isValidVectorIndex(EA_16BYTE, elemsize, imm2));
5998 immOut = (imm1 << 4) + imm2;
5999 fmt = IF_DV_2F;
6000 break;
6001
6002 default:
6003 unreached();
6004 break;
6005 }
6006 assert(fmt != IF_NONE);
6007
6008 instrDesc* id = emitNewInstrSC(attr, immOut);
6009
6010 id->idIns(ins);
6011 id->idInsFmt(fmt);
6012
6013 id->idReg1(reg1);
6014 id->idReg2(reg2);
6015
6016 dispIns(id);
6017 appendToCurIG(id);
6018}
6019
6020/*****************************************************************************
6021 *
6022 * Add an instruction referencing four registers.
6023 */
6024
6025void emitter::emitIns_R_R_R_R(
6026 instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, regNumber reg3, regNumber reg4)
6027{
6028 emitAttr size = EA_SIZE(attr);
6029 insFormat fmt = IF_NONE;
6030
6031 /* Figure out the encoding format of the instruction */
6032 switch (ins)
6033 {
6034 case INS_madd:
6035 case INS_msub:
6036 case INS_smaddl:
6037 case INS_smsubl:
6038 case INS_umaddl:
6039 case INS_umsubl:
6040 assert(isValidGeneralDatasize(size));
6041 assert(isGeneralRegister(reg1));
6042 assert(isGeneralRegister(reg2));
6043 assert(isGeneralRegister(reg3));
6044 assert(isGeneralRegister(reg4));
6045 fmt = IF_DR_4A;
6046 break;
6047
6048 case INS_fmadd:
6049 case INS_fmsub:
6050 case INS_fnmadd:
6051 case INS_fnmsub:
6052 // Scalar operation
6053 assert(isValidScalarDatasize(size));
6054 assert(isVectorRegister(reg1));
6055 assert(isVectorRegister(reg2));
6056 assert(isVectorRegister(reg3));
6057 assert(isVectorRegister(reg4));
6058 fmt = IF_DV_4A;
6059 break;
6060
6061 case INS_invalid:
6062 fmt = IF_NONE;
6063 break;
6064
6065 default:
6066 unreached();
6067 break;
6068 }
6069 assert(fmt != IF_NONE);
6070
6071 instrDesc* id = emitNewInstr(attr);
6072
6073 id->idIns(ins);
6074 id->idInsFmt(fmt);
6075
6076 id->idReg1(reg1);
6077 id->idReg2(reg2);
6078 id->idReg3(reg3);
6079 id->idReg4(reg4);
6080
6081 dispIns(id);
6082 appendToCurIG(id);
6083}
6084
6085/*****************************************************************************
6086 *
6087 * Add an instruction referencing a register and a condition code
6088 */
6089
6090void emitter::emitIns_R_COND(instruction ins, emitAttr attr, regNumber reg, insCond cond)
6091{
6092 emitAttr size = EA_SIZE(attr);
6093 insFormat fmt = IF_NONE;
6094 condFlagsImm cfi;
6095 cfi.immCFVal = 0;
6096
6097 /* Figure out the encoding format of the instruction */
6098 switch (ins)
6099 {
6100 case INS_cset:
6101 case INS_csetm:
6102 assert(isGeneralRegister(reg));
6103 cfi.cond = cond;
6104 fmt = IF_DR_1D;
6105 break;
6106
6107 default:
6108 unreached();
6109 break;
6110
6111 } // end switch (ins)
6112
6113 assert(fmt != IF_NONE);
6114 assert(isValidImmCond(cfi.immCFVal));
6115
6116 instrDesc* id = emitNewInstrSC(attr, cfi.immCFVal);
6117
6118 id->idIns(ins);
6119 id->idInsFmt(fmt);
6120 id->idInsOpt(INS_OPTS_NONE);
6121
6122 id->idReg1(reg);
6123
6124 dispIns(id);
6125 appendToCurIG(id);
6126}
6127
6128/*****************************************************************************
6129 *
6130 * Add an instruction referencing two registers and a condition code
6131 */
6132
6133void emitter::emitIns_R_R_COND(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, insCond cond)
6134{
6135 emitAttr size = EA_SIZE(attr);
6136 insFormat fmt = IF_NONE;
6137 condFlagsImm cfi;
6138 cfi.immCFVal = 0;
6139
6140 /* Figure out the encoding format of the instruction */
6141 switch (ins)
6142 {
6143 case INS_cinc:
6144 case INS_cinv:
6145 case INS_cneg:
6146 assert(isGeneralRegister(reg1));
6147 assert(isGeneralRegister(reg2));
6148 cfi.cond = cond;
6149 fmt = IF_DR_2D;
6150 break;
6151 default:
6152 unreached();
6153 break;
6154
6155 } // end switch (ins)
6156
6157 assert(fmt != IF_NONE);
6158 assert(isValidImmCond(cfi.immCFVal));
6159
6160 instrDesc* id = emitNewInstrSC(attr, cfi.immCFVal);
6161
6162 id->idIns(ins);
6163 id->idInsFmt(fmt);
6164 id->idInsOpt(INS_OPTS_NONE);
6165
6166 id->idReg1(reg1);
6167 id->idReg2(reg2);
6168
6169 dispIns(id);
6170 appendToCurIG(id);
6171}
6172
6173/*****************************************************************************
6174 *
6175 * Add an instruction referencing two registers and a condition code
6176 */
6177
6178void emitter::emitIns_R_R_R_COND(
6179 instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, regNumber reg3, insCond cond)
6180{
6181 emitAttr size = EA_SIZE(attr);
6182 insFormat fmt = IF_NONE;
6183 condFlagsImm cfi;
6184 cfi.immCFVal = 0;
6185
6186 /* Figure out the encoding format of the instruction */
6187 switch (ins)
6188 {
6189 case INS_csel:
6190 case INS_csinc:
6191 case INS_csinv:
6192 case INS_csneg:
6193 assert(isGeneralRegister(reg1));
6194 assert(isGeneralRegister(reg2));
6195 assert(isGeneralRegister(reg3));
6196 cfi.cond = cond;
6197 fmt = IF_DR_3D;
6198 break;
6199
6200 default:
6201 unreached();
6202 break;
6203
6204 } // end switch (ins)
6205
6206 assert(fmt != IF_NONE);
6207 assert(isValidImmCond(cfi.immCFVal));
6208
6209 instrDesc* id = emitNewInstr(attr);
6210
6211 id->idIns(ins);
6212 id->idInsFmt(fmt);
6213 id->idInsOpt(INS_OPTS_NONE);
6214
6215 id->idReg1(reg1);
6216 id->idReg2(reg2);
6217 id->idReg3(reg3);
6218 id->idSmallCns(cfi.immCFVal);
6219
6220 dispIns(id);
6221 appendToCurIG(id);
6222}
6223
6224/*****************************************************************************
6225 *
6226 * Add an instruction referencing two registers the flags and a condition code
6227 */
6228
6229void emitter::emitIns_R_R_FLAGS_COND(
6230 instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, insCflags flags, insCond cond)
6231{
6232 emitAttr size = EA_SIZE(attr);
6233 insFormat fmt = IF_NONE;
6234 condFlagsImm cfi;
6235 cfi.immCFVal = 0;
6236
6237 /* Figure out the encoding format of the instruction */
6238 switch (ins)
6239 {
6240 case INS_ccmp:
6241 case INS_ccmn:
6242 assert(isGeneralRegister(reg1));
6243 assert(isGeneralRegister(reg2));
6244 cfi.flags = flags;
6245 cfi.cond = cond;
6246 fmt = IF_DR_2I;
6247 break;
6248 default:
6249 unreached();
6250 break;
6251 } // end switch (ins)
6252
6253 assert(fmt != IF_NONE);
6254 assert(isValidImmCondFlags(cfi.immCFVal));
6255
6256 instrDesc* id = emitNewInstrSC(attr, cfi.immCFVal);
6257
6258 id->idIns(ins);
6259 id->idInsFmt(fmt);
6260 id->idInsOpt(INS_OPTS_NONE);
6261
6262 id->idReg1(reg1);
6263 id->idReg2(reg2);
6264
6265 dispIns(id);
6266 appendToCurIG(id);
6267}
6268
6269/*****************************************************************************
6270 *
6271 * Add an instruction referencing a register, an immediate, the flags and a condition code
6272 */
6273
6274void emitter::emitIns_R_I_FLAGS_COND(
6275 instruction ins, emitAttr attr, regNumber reg, int imm, insCflags flags, insCond cond)
6276{
6277 emitAttr size = EA_SIZE(attr);
6278 insFormat fmt = IF_NONE;
6279 condFlagsImm cfi;
6280 cfi.immCFVal = 0;
6281
6282 /* Figure out the encoding format of the instruction */
6283 switch (ins)
6284 {
6285 case INS_ccmp:
6286 case INS_ccmn:
6287 assert(isGeneralRegister(reg));
6288 if (imm < 0)
6289 {
6290 ins = insReverse(ins);
6291 imm = -imm;
6292 }
6293 if ((imm >= 0) && (imm <= 31))
6294 {
6295 cfi.imm5 = imm;
6296 cfi.flags = flags;
6297 cfi.cond = cond;
6298 fmt = IF_DI_1F;
6299 }
6300 else
6301 {
6302 assert(!"Instruction cannot be encoded: ccmp/ccmn imm5");
6303 }
6304 break;
6305 default:
6306 unreached();
6307 break;
6308 } // end switch (ins)
6309
6310 assert(fmt != IF_NONE);
6311 assert(isValidImmCondFlagsImm5(cfi.immCFVal));
6312
6313 instrDesc* id = emitNewInstrSC(attr, cfi.immCFVal);
6314
6315 id->idIns(ins);
6316 id->idInsFmt(fmt);
6317 id->idInsOpt(INS_OPTS_NONE);
6318
6319 id->idReg1(reg);
6320
6321 dispIns(id);
6322 appendToCurIG(id);
6323}
6324
6325/*****************************************************************************
6326 *
6327 * Add a memory barrier instruction with a 'barrier' immediate
6328 */
6329
6330void emitter::emitIns_BARR(instruction ins, insBarrier barrier)
6331{
6332 insFormat fmt = IF_NONE;
6333 ssize_t imm = 0;
6334
6335 /* Figure out the encoding format of the instruction */
6336 switch (ins)
6337 {
6338 case INS_dsb:
6339 case INS_dmb:
6340 case INS_isb:
6341
6342 fmt = IF_SI_0B;
6343 imm = (ssize_t)barrier;
6344 break;
6345 default:
6346 unreached();
6347 break;
6348 } // end switch (ins)
6349
6350 assert(fmt != IF_NONE);
6351
6352 instrDesc* id = emitNewInstrSC(EA_8BYTE, imm);
6353
6354 id->idIns(ins);
6355 id->idInsFmt(fmt);
6356 id->idInsOpt(INS_OPTS_NONE);
6357
6358 dispIns(id);
6359 appendToCurIG(id);
6360}
6361
6362/*****************************************************************************
6363 *
6364 * Add an instruction with a static data member operand. If 'size' is 0, the
6365 * instruction operates on the address of the static member instead of its
6366 * value (e.g. "push offset clsvar", rather than "push dword ptr [clsvar]").
6367 */
6368
6369void emitter::emitIns_C(instruction ins, emitAttr attr, CORINFO_FIELD_HANDLE fldHnd, int offs)
6370{
6371 NYI("emitIns_C");
6372}
6373
6374/*****************************************************************************
6375 *
6376 * Add an instruction referencing stack-based local variable.
6377 */
6378
6379void emitter::emitIns_S(instruction ins, emitAttr attr, int varx, int offs)
6380{
6381 NYI("emitIns_S");
6382}
6383
6384/*****************************************************************************
6385 *
6386 * Add an instruction referencing a register and a stack-based local variable.
6387 */
6388void emitter::emitIns_R_S(instruction ins, emitAttr attr, regNumber reg1, int varx, int offs)
6389{
6390 emitAttr size = EA_SIZE(attr);
6391 insFormat fmt = IF_NONE;
6392 int disp = 0;
6393 unsigned scale = 0;
6394
6395 assert(offs >= 0);
6396
6397 // TODO-ARM64-CQ: use unscaled loads?
6398 /* Figure out the encoding format of the instruction */
6399 switch (ins)
6400 {
6401 case INS_strb:
6402 case INS_ldrb:
6403 case INS_ldrsb:
6404 scale = 0;
6405 break;
6406
6407 case INS_strh:
6408 case INS_ldrh:
6409 case INS_ldrsh:
6410 scale = 1;
6411 break;
6412
6413 case INS_ldrsw:
6414 scale = 2;
6415 break;
6416
6417 case INS_str:
6418 case INS_ldr:
6419 assert(isValidGeneralDatasize(size) || isValidVectorDatasize(size));
6420 scale = genLog2(EA_SIZE_IN_BYTES(size));
6421 break;
6422
6423 case INS_lea:
6424 assert(size == EA_8BYTE);
6425 scale = 0;
6426 break;
6427
6428 default:
6429 NYI("emitIns_R_S"); // FP locals?
6430 return;
6431
6432 } // end switch (ins)
6433
6434 /* Figure out the variable's frame position */
6435 ssize_t imm;
6436 int base;
6437 bool FPbased;
6438
6439 base = emitComp->lvaFrameAddress(varx, &FPbased);
6440 disp = base + offs;
6441 assert((scale >= 0) && (scale <= 4));
6442
6443 regNumber reg2 = FPbased ? REG_FPBASE : REG_SPBASE;
6444 reg2 = encodingSPtoZR(reg2);
6445
6446 if (ins == INS_lea)
6447 {
6448 if (disp >= 0)
6449 {
6450 ins = INS_add;
6451 imm = disp;
6452 }
6453 else
6454 {
6455 ins = INS_sub;
6456 imm = -disp;
6457 }
6458
6459 if (imm <= 0x0fff)
6460 {
6461 fmt = IF_DI_2A; // add reg1,reg2,#disp
6462 }
6463 else
6464 {
6465 regNumber rsvdReg = codeGen->rsGetRsvdReg();
6466 codeGen->instGen_Set_Reg_To_Imm(EA_PTRSIZE, rsvdReg, imm);
6467 fmt = IF_DR_3A; // add reg1,reg2,rsvdReg
6468 }
6469 }
6470 else
6471 {
6472 bool useRegForImm = false;
6473 ssize_t mask = (1 << scale) - 1; // the mask of low bits that must be zero to encode the immediate
6474
6475 imm = disp;
6476 if (imm == 0)
6477 {
6478 fmt = IF_LS_2A;
6479 }
6480 else if ((imm < 0) || ((imm & mask) != 0))
6481 {
6482 if ((imm >= -256) && (imm <= 255))
6483 {
6484 fmt = IF_LS_2C;
6485 }
6486 else
6487 {
6488 useRegForImm = true;
6489 }
6490 }
6491 else if (imm > 0)
6492 {
6493 if (((imm & mask) == 0) && ((imm >> scale) < 0x1000))
6494 {
6495 imm >>= scale; // The immediate is scaled by the size of the ld/st
6496
6497 fmt = IF_LS_2B;
6498 }
6499 else
6500 {
6501 useRegForImm = true;
6502 }
6503 }
6504
6505 if (useRegForImm)
6506 {
6507 regNumber rsvdReg = codeGen->rsGetRsvdReg();
6508 codeGen->instGen_Set_Reg_To_Imm(EA_PTRSIZE, rsvdReg, imm);
6509 fmt = IF_LS_3A;
6510 }
6511 }
6512
6513 assert(fmt != IF_NONE);
6514
6515 instrDesc* id = emitNewInstrCns(attr, imm);
6516
6517 id->idIns(ins);
6518 id->idInsFmt(fmt);
6519 id->idInsOpt(INS_OPTS_NONE);
6520
6521 id->idReg1(reg1);
6522 id->idReg2(reg2);
6523 id->idAddr()->iiaLclVar.initLclVarAddr(varx, offs);
6524 id->idSetIsLclVar();
6525
6526#ifdef DEBUG
6527 id->idDebugOnlyInfo()->idVarRefOffs = emitVarRefOffs;
6528#endif
6529
6530 dispIns(id);
6531 appendToCurIG(id);
6532}
6533
6534/*****************************************************************************
6535 *
6536 * Add an instruction referencing two register and consectutive stack-based local variable slots.
6537 */
6538void emitter::emitIns_R_R_S_S(
6539 instruction ins, emitAttr attr1, emitAttr attr2, regNumber reg1, regNumber reg2, int varx, int offs)
6540{
6541 assert((ins == INS_ldp) || (ins == INS_ldnp));
6542 assert(EA_8BYTE == EA_SIZE(attr1));
6543 assert(EA_8BYTE == EA_SIZE(attr2));
6544 assert(isGeneralRegisterOrZR(reg1));
6545 assert(isGeneralRegisterOrZR(reg2));
6546 assert(offs >= 0);
6547
6548 insFormat fmt = IF_LS_3B;
6549 int disp = 0;
6550 const unsigned scale = 3;
6551
6552 /* Figure out the variable's frame position */
6553 int base;
6554 bool FPbased;
6555
6556 base = emitComp->lvaFrameAddress(varx, &FPbased);
6557 disp = base + offs;
6558
6559 // TODO-ARM64-CQ: with compLocallocUsed, should we use REG_SAVED_LOCALLOC_SP instead?
6560 regNumber reg3 = FPbased ? REG_FPBASE : REG_SPBASE;
6561 reg3 = encodingSPtoZR(reg3);
6562
6563 bool useRegForAdr = true;
6564 ssize_t imm = disp;
6565 ssize_t mask = (1 << scale) - 1; // the mask of low bits that must be zero to encode the immediate
6566 if (imm == 0)
6567 {
6568 useRegForAdr = false;
6569 }
6570 else
6571 {
6572 if ((imm & mask) == 0)
6573 {
6574 ssize_t immShift = imm >> scale; // The immediate is scaled by the size of the ld/st
6575
6576 if ((immShift >= -64) && (immShift <= 63))
6577 {
6578 fmt = IF_LS_3C;
6579 useRegForAdr = false;
6580 imm = immShift;
6581 }
6582 }
6583 }
6584
6585 if (useRegForAdr)
6586 {
6587 regNumber rsvd = codeGen->rsGetRsvdReg();
6588 emitIns_R_R_Imm(INS_add, EA_PTRSIZE, rsvd, reg3, imm);
6589 reg3 = rsvd;
6590 imm = 0;
6591 }
6592
6593 assert(fmt != IF_NONE);
6594
6595 instrDesc* id = emitNewInstrCns(attr1, imm);
6596
6597 id->idIns(ins);
6598 id->idInsFmt(fmt);
6599 id->idInsOpt(INS_OPTS_NONE);
6600
6601 // Record the attribute for the second register in the pair
6602 if (EA_IS_GCREF(attr2))
6603 {
6604 id->idGCrefReg2(GCT_GCREF);
6605 }
6606 else if (EA_IS_BYREF(attr2))
6607 {
6608 id->idGCrefReg2(GCT_BYREF);
6609 }
6610 else
6611 {
6612 id->idGCrefReg2(GCT_NONE);
6613 }
6614
6615 id->idReg1(reg1);
6616 id->idReg2(reg2);
6617 id->idReg3(reg3);
6618 id->idAddr()->iiaLclVar.initLclVarAddr(varx, offs);
6619 id->idSetIsLclVar();
6620
6621#ifdef DEBUG
6622 id->idDebugOnlyInfo()->idVarRefOffs = emitVarRefOffs;
6623#endif
6624
6625 dispIns(id);
6626 appendToCurIG(id);
6627}
6628
6629/*****************************************************************************
6630 *
6631 * Add an instruction referencing a stack-based local variable and a register
6632 */
6633void emitter::emitIns_S_R(instruction ins, emitAttr attr, regNumber reg1, int varx, int offs)
6634{
6635 assert(offs >= 0);
6636 emitAttr size = EA_SIZE(attr);
6637 insFormat fmt = IF_NONE;
6638 int disp = 0;
6639 unsigned scale = 0;
6640 bool isVectorStore = false;
6641
6642 // TODO-ARM64-CQ: use unscaled loads?
6643 /* Figure out the encoding format of the instruction */
6644 switch (ins)
6645 {
6646 case INS_strb:
6647 scale = 0;
6648 assert(isGeneralRegisterOrZR(reg1));
6649 break;
6650
6651 case INS_strh:
6652 scale = 1;
6653 assert(isGeneralRegisterOrZR(reg1));
6654 break;
6655
6656 case INS_str:
6657 if (isGeneralRegisterOrZR(reg1))
6658 {
6659 assert(isValidGeneralDatasize(size));
6660 scale = (size == EA_8BYTE) ? 3 : 2;
6661 }
6662 else
6663 {
6664 assert(isVectorRegister(reg1));
6665 assert(isValidVectorLSDatasize(size));
6666 scale = NaturalScale_helper(size);
6667 isVectorStore = true;
6668 }
6669 break;
6670
6671 default:
6672 NYI("emitIns_S_R"); // FP locals?
6673 return;
6674
6675 } // end switch (ins)
6676
6677 /* Figure out the variable's frame position */
6678 int base;
6679 bool FPbased;
6680
6681 base = emitComp->lvaFrameAddress(varx, &FPbased);
6682 disp = base + offs;
6683 assert(scale >= 0);
6684 if (isVectorStore)
6685 {
6686 assert(scale <= 4);
6687 }
6688 else
6689 {
6690 assert(scale <= 3);
6691 }
6692
6693 // TODO-ARM64-CQ: with compLocallocUsed, should we use REG_SAVED_LOCALLOC_SP instead?
6694 regNumber reg2 = FPbased ? REG_FPBASE : REG_SPBASE;
6695 reg2 = encodingSPtoZR(reg2);
6696
6697 bool useRegForImm = false;
6698 ssize_t imm = disp;
6699 ssize_t mask = (1 << scale) - 1; // the mask of low bits that must be zero to encode the immediate
6700 if (imm == 0)
6701 {
6702 fmt = IF_LS_2A;
6703 }
6704 else if ((imm < 0) || ((imm & mask) != 0))
6705 {
6706 if ((imm >= -256) && (imm <= 255))
6707 {
6708 fmt = IF_LS_2C;
6709 }
6710 else
6711 {
6712 useRegForImm = true;
6713 }
6714 }
6715 else if (imm > 0)
6716 {
6717 if (((imm & mask) == 0) && ((imm >> scale) < 0x1000))
6718 {
6719 imm >>= scale; // The immediate is scaled by the size of the ld/st
6720
6721 fmt = IF_LS_2B;
6722 }
6723 else
6724 {
6725 useRegForImm = true;
6726 }
6727 }
6728
6729 if (useRegForImm)
6730 {
6731 // The reserved register is not stored in idReg3() since that field overlaps with iiaLclVar.
6732 // It is instead implicit when idSetIsLclVar() is set, with this encoding format.
6733 regNumber rsvdReg = codeGen->rsGetRsvdReg();
6734 codeGen->instGen_Set_Reg_To_Imm(EA_PTRSIZE, rsvdReg, imm);
6735 fmt = IF_LS_3A;
6736 }
6737
6738 assert(fmt != IF_NONE);
6739
6740 instrDesc* id = emitNewInstrCns(attr, imm);
6741
6742 id->idIns(ins);
6743 id->idInsFmt(fmt);
6744 id->idInsOpt(INS_OPTS_NONE);
6745
6746 id->idReg1(reg1);
6747 id->idReg2(reg2);
6748 id->idAddr()->iiaLclVar.initLclVarAddr(varx, offs);
6749 id->idSetIsLclVar();
6750
6751#ifdef DEBUG
6752 id->idDebugOnlyInfo()->idVarRefOffs = emitVarRefOffs;
6753#endif
6754
6755 dispIns(id);
6756 appendToCurIG(id);
6757}
6758
6759/*****************************************************************************
6760 *
6761 * Add an instruction referencing consecutive stack-based local variable slots and two registers
6762 */
6763void emitter::emitIns_S_S_R_R(
6764 instruction ins, emitAttr attr1, emitAttr attr2, regNumber reg1, regNumber reg2, int varx, int offs)
6765{
6766 assert((ins == INS_stp) || (ins == INS_stnp));
6767 assert(EA_8BYTE == EA_SIZE(attr1));
6768 assert(EA_8BYTE == EA_SIZE(attr2));
6769 assert(isGeneralRegisterOrZR(reg1));
6770 assert(isGeneralRegisterOrZR(reg2));
6771 assert(offs >= 0);
6772
6773 insFormat fmt = IF_LS_3B;
6774 int disp = 0;
6775 const unsigned scale = 3;
6776
6777 /* Figure out the variable's frame position */
6778 int base;
6779 bool FPbased;
6780
6781 base = emitComp->lvaFrameAddress(varx, &FPbased);
6782 disp = base + offs;
6783
6784 // TODO-ARM64-CQ: with compLocallocUsed, should we use REG_SAVED_LOCALLOC_SP instead?
6785 regNumber reg3 = FPbased ? REG_FPBASE : REG_SPBASE;
6786
6787 bool useRegForAdr = true;
6788 ssize_t imm = disp;
6789 ssize_t mask = (1 << scale) - 1; // the mask of low bits that must be zero to encode the immediate
6790 if (imm == 0)
6791 {
6792 useRegForAdr = false;
6793 }
6794 else
6795 {
6796 if ((imm & mask) == 0)
6797 {
6798 ssize_t immShift = imm >> scale; // The immediate is scaled by the size of the ld/st
6799
6800 if ((immShift >= -64) && (immShift <= 63))
6801 {
6802 fmt = IF_LS_3C;
6803 useRegForAdr = false;
6804 imm = immShift;
6805 }
6806 }
6807 }
6808
6809 if (useRegForAdr)
6810 {
6811 regNumber rsvd = codeGen->rsGetRsvdReg();
6812 emitIns_R_R_Imm(INS_add, EA_PTRSIZE, rsvd, reg3, imm);
6813 reg3 = rsvd;
6814 imm = 0;
6815 }
6816
6817 assert(fmt != IF_NONE);
6818
6819 instrDesc* id = emitNewInstrCns(attr1, imm);
6820
6821 id->idIns(ins);
6822 id->idInsFmt(fmt);
6823 id->idInsOpt(INS_OPTS_NONE);
6824
6825 // Record the attribute for the second register in the pair
6826 if (EA_IS_GCREF(attr2))
6827 {
6828 id->idGCrefReg2(GCT_GCREF);
6829 }
6830 else if (EA_IS_BYREF(attr2))
6831 {
6832 id->idGCrefReg2(GCT_BYREF);
6833 }
6834 else
6835 {
6836 id->idGCrefReg2(GCT_NONE);
6837 }
6838
6839 reg3 = encodingSPtoZR(reg3);
6840
6841 id->idReg1(reg1);
6842 id->idReg2(reg2);
6843 id->idReg3(reg3);
6844 id->idAddr()->iiaLclVar.initLclVarAddr(varx, offs);
6845 id->idSetIsLclVar();
6846
6847#ifdef DEBUG
6848 id->idDebugOnlyInfo()->idVarRefOffs = emitVarRefOffs;
6849#endif
6850
6851 dispIns(id);
6852 appendToCurIG(id);
6853}
6854
6855/*****************************************************************************
6856 *
6857 * Add an instruction referencing stack-based local variable and an immediate
6858 */
6859void emitter::emitIns_S_I(instruction ins, emitAttr attr, int varx, int offs, int val)
6860{
6861 NYI("emitIns_S_I");
6862}
6863
6864/*****************************************************************************
6865 *
6866 * Add an instruction with a register + static member operands.
6867 * Constant is stored into JIT data which is adjacent to code.
6868 * No relocation is needed. PC-relative offset will be encoded directly into instruction.
6869 *
6870 */
6871void emitter::emitIns_R_C(
6872 instruction ins, emitAttr attr, regNumber reg, regNumber addrReg, CORINFO_FIELD_HANDLE fldHnd, int offs)
6873{
6874 assert(offs >= 0);
6875 assert(instrDesc::fitsInSmallCns(offs));
6876
6877 emitAttr size = EA_SIZE(attr);
6878 insFormat fmt = IF_NONE;
6879 int disp = 0;
6880 instrDescJmp* id = emitNewInstrJmp();
6881
6882 switch (ins)
6883 {
6884 case INS_adr:
6885 // This is case to get address to the constant data.
6886 fmt = IF_LARGEADR;
6887 assert(isGeneralRegister(reg));
6888 assert(isValidGeneralDatasize(size));
6889 break;
6890
6891 case INS_ldr:
6892 fmt = IF_LARGELDC;
6893 if (isVectorRegister(reg))
6894 {
6895 assert(isValidScalarDatasize(size));
6896 // For vector (float/double) register, we should have an integer address reg to
6897 // compute long address which consists of page address and page offset.
6898 // For integer constant, this is not needed since the dest reg can be used to
6899 // compute address as well as contain the final contents.
6900 assert(isGeneralRegister(reg) || (addrReg != REG_NA));
6901 }
6902 else
6903 {
6904 assert(isGeneralRegister(reg));
6905 assert(isValidGeneralDatasize(size));
6906 }
6907 break;
6908 default:
6909 unreached();
6910 }
6911
6912 assert(fmt != IF_NONE);
6913
6914 id->idIns(ins);
6915 id->idInsFmt(fmt);
6916 id->idInsOpt(INS_OPTS_NONE);
6917 id->idSmallCns(offs);
6918 id->idOpSize(size);
6919 id->idAddr()->iiaFieldHnd = fldHnd;
6920 id->idSetIsBound(); // We won't patch address since we will know the exact distance once JIT code and data are
6921 // allocated together.
6922
6923 id->idReg1(reg); // destination register that will get the constant value.
6924 if (addrReg != REG_NA)
6925 {
6926 id->idReg2(addrReg); // integer register to compute long address (used for vector dest when we end up with long
6927 // address)
6928 }
6929 id->idjShort = false; // Assume loading constant from long address
6930
6931 // Keep it long if it's in cold code.
6932 id->idjKeepLong = emitComp->fgIsBlockCold(emitComp->compCurBB);
6933
6934#ifdef DEBUG
6935 if (emitComp->opts.compLongAddress)
6936 id->idjKeepLong = 1;
6937#endif // DEBUG
6938
6939 // If it's possible to be shortened, then put it in jump list
6940 // to be revisited by emitJumpDistBind.
6941 if (!id->idjKeepLong)
6942 {
6943 /* Record the jump's IG and offset within it */
6944 id->idjIG = emitCurIG;
6945 id->idjOffs = emitCurIGsize;
6946
6947 /* Append this jump to this IG's jump list */
6948 id->idjNext = emitCurIGjmpList;
6949 emitCurIGjmpList = id;
6950
6951#if EMITTER_STATS
6952 emitTotalIGjmps++;
6953#endif
6954 }
6955
6956 dispIns(id);
6957 appendToCurIG(id);
6958}
6959
6960/*****************************************************************************
6961 *
6962 * Add an instruction with a static member + constant.
6963 */
6964
6965void emitter::emitIns_C_I(instruction ins, emitAttr attr, CORINFO_FIELD_HANDLE fldHnd, ssize_t offs, ssize_t val)
6966{
6967 NYI("emitIns_C_I");
6968}
6969
6970/*****************************************************************************
6971 *
6972 * Add an instruction with a static member + register operands.
6973 */
6974
6975void emitter::emitIns_C_R(instruction ins, emitAttr attr, CORINFO_FIELD_HANDLE fldHnd, regNumber reg, int offs)
6976{
6977 assert(!"emitIns_C_R not supported for RyuJIT backend");
6978}
6979
6980void emitter::emitIns_R_AR(instruction ins, emitAttr attr, regNumber ireg, regNumber reg, int offs)
6981{
6982 NYI("emitIns_R_AR");
6983}
6984
6985// This computes address from the immediate which is relocatable.
6986void emitter::emitIns_R_AI(instruction ins, emitAttr attr, regNumber ireg, ssize_t addr)
6987{
6988 assert(EA_IS_RELOC(attr));
6989 emitAttr size = EA_SIZE(attr);
6990 insFormat fmt = IF_DI_1E;
6991 bool needAdd = false;
6992 instrDescJmp* id = emitNewInstrJmp();
6993
6994 switch (ins)
6995 {
6996 case INS_adrp:
6997 // This computes page address.
6998 // page offset is needed using add.
6999 needAdd = true;
7000 break;
7001 case INS_adr:
7002 break;
7003 default:
7004 unreached();
7005 }
7006
7007 id->idIns(ins);
7008 id->idInsFmt(fmt);
7009 id->idInsOpt(INS_OPTS_NONE);
7010 id->idOpSize(size);
7011 id->idAddr()->iiaAddr = (BYTE*)addr;
7012 id->idReg1(ireg);
7013 id->idSetIsDspReloc();
7014
7015 dispIns(id);
7016 appendToCurIG(id);
7017
7018 if (needAdd)
7019 {
7020 // add reg, reg, imm
7021 ins = INS_add;
7022 fmt = IF_DI_2A;
7023 instrDesc* id = emitAllocInstr(attr);
7024 assert(id->idIsReloc());
7025
7026 id->idIns(ins);
7027 id->idInsFmt(fmt);
7028 id->idInsOpt(INS_OPTS_NONE);
7029 id->idOpSize(size);
7030 id->idAddr()->iiaAddr = (BYTE*)addr;
7031 id->idReg1(ireg);
7032 id->idReg2(ireg);
7033
7034 dispIns(id);
7035 appendToCurIG(id);
7036 }
7037}
7038
7039void emitter::emitIns_AR_R(instruction ins, emitAttr attr, regNumber ireg, regNumber reg, int offs)
7040{
7041 NYI("emitIns_AR_R");
7042}
7043
7044void emitter::emitIns_R_ARR(instruction ins, emitAttr attr, regNumber ireg, regNumber reg, regNumber rg2, int disp)
7045{
7046 NYI("emitIns_R_ARR");
7047}
7048
7049void emitter::emitIns_ARR_R(instruction ins, emitAttr attr, regNumber ireg, regNumber reg, regNumber rg2, int disp)
7050{
7051 NYI("emitIns_R_ARR");
7052}
7053
7054void emitter::emitIns_R_ARX(
7055 instruction ins, emitAttr attr, regNumber ireg, regNumber reg, regNumber rg2, unsigned mul, int disp)
7056{
7057 NYI("emitIns_R_ARR");
7058}
7059
7060/*****************************************************************************
7061 *
7062 * Record that a jump instruction uses the short encoding
7063 *
7064 */
7065void emitter::emitSetShortJump(instrDescJmp* id)
7066{
7067 if (id->idjKeepLong)
7068 return;
7069
7070 insFormat fmt = IF_NONE;
7071 if (emitIsCondJump(id))
7072 {
7073 switch (id->idIns())
7074 {
7075 case INS_cbz:
7076 case INS_cbnz:
7077 fmt = IF_BI_1A;
7078 break;
7079 case INS_tbz:
7080 case INS_tbnz:
7081 fmt = IF_BI_1B;
7082 break;
7083 default:
7084 fmt = IF_BI_0B;
7085 break;
7086 }
7087 }
7088 else if (emitIsLoadLabel(id))
7089 {
7090 fmt = IF_DI_1E;
7091 }
7092 else if (emitIsLoadConstant(id))
7093 {
7094 fmt = IF_LS_1A;
7095 }
7096 else
7097 {
7098 unreached();
7099 }
7100
7101 id->idInsFmt(fmt);
7102 id->idjShort = true;
7103}
7104
7105/*****************************************************************************
7106 *
7107 * Add a label instruction.
7108 */
7109
7110void emitter::emitIns_R_L(instruction ins, emitAttr attr, BasicBlock* dst, regNumber reg)
7111{
7112 assert(dst->bbFlags & BBF_JMP_TARGET);
7113
7114 insFormat fmt = IF_NONE;
7115
7116 switch (ins)
7117 {
7118 case INS_adr:
7119 fmt = IF_LARGEADR;
7120 break;
7121 default:
7122 unreached();
7123 }
7124
7125 instrDescJmp* id = emitNewInstrJmp();
7126
7127 id->idIns(ins);
7128 id->idInsFmt(fmt);
7129 id->idjShort = false;
7130 id->idAddr()->iiaBBlabel = dst;
7131 id->idReg1(reg);
7132 id->idOpSize(EA_PTRSIZE);
7133
7134#ifdef DEBUG
7135 // Mark the catch return
7136 if (emitComp->compCurBB->bbJumpKind == BBJ_EHCATCHRET)
7137 {
7138 id->idDebugOnlyInfo()->idCatchRet = true;
7139 }
7140#endif // DEBUG
7141
7142 id->idjKeepLong = emitComp->fgInDifferentRegions(emitComp->compCurBB, dst);
7143
7144#ifdef DEBUG
7145 if (emitComp->opts.compLongAddress)
7146 id->idjKeepLong = 1;
7147#endif // DEBUG
7148
7149 /* Record the jump's IG and offset within it */
7150
7151 id->idjIG = emitCurIG;
7152 id->idjOffs = emitCurIGsize;
7153
7154 /* Append this jump to this IG's jump list */
7155
7156 id->idjNext = emitCurIGjmpList;
7157 emitCurIGjmpList = id;
7158
7159#if EMITTER_STATS
7160 emitTotalIGjmps++;
7161#endif
7162
7163 dispIns(id);
7164 appendToCurIG(id);
7165}
7166
7167/*****************************************************************************
7168 *
7169 * Add a data label instruction.
7170 */
7171
7172void emitter::emitIns_R_D(instruction ins, emitAttr attr, unsigned offs, regNumber reg)
7173{
7174 NYI("emitIns_R_D");
7175}
7176
7177void emitter::emitIns_J_R(instruction ins, emitAttr attr, BasicBlock* dst, regNumber reg)
7178{
7179 assert((ins == INS_cbz) || (ins == INS_cbnz));
7180
7181 assert(dst != nullptr);
7182 assert((dst->bbFlags & BBF_JMP_TARGET) != 0);
7183
7184 insFormat fmt = IF_LARGEJMP;
7185
7186 instrDescJmp* id = emitNewInstrJmp();
7187
7188 id->idIns(ins);
7189 id->idInsFmt(fmt);
7190 id->idReg1(reg);
7191 id->idjShort = false;
7192 id->idOpSize(EA_SIZE(attr));
7193
7194 id->idAddr()->iiaBBlabel = dst;
7195 id->idjKeepLong = emitComp->fgInDifferentRegions(emitComp->compCurBB, dst);
7196
7197 /* Record the jump's IG and offset within it */
7198
7199 id->idjIG = emitCurIG;
7200 id->idjOffs = emitCurIGsize;
7201
7202 /* Append this jump to this IG's jump list */
7203
7204 id->idjNext = emitCurIGjmpList;
7205 emitCurIGjmpList = id;
7206
7207#if EMITTER_STATS
7208 emitTotalIGjmps++;
7209#endif
7210
7211 dispIns(id);
7212 appendToCurIG(id);
7213}
7214
7215void emitter::emitIns_J_R_I(instruction ins, emitAttr attr, BasicBlock* dst, regNumber reg, int imm)
7216{
7217 assert((ins == INS_tbz) || (ins == INS_tbnz));
7218
7219 assert(dst != nullptr);
7220 assert((dst->bbFlags & BBF_JMP_TARGET) != 0);
7221 assert((EA_SIZE(attr) == EA_4BYTE) || (EA_SIZE(attr) == EA_8BYTE));
7222 assert(imm < ((EA_SIZE(attr) == EA_4BYTE) ? 32 : 64));
7223
7224 insFormat fmt = IF_LARGEJMP;
7225
7226 instrDescJmp* id = emitNewInstrJmp();
7227
7228 id->idIns(ins);
7229 id->idInsFmt(fmt);
7230 id->idReg1(reg);
7231 id->idjShort = false;
7232 id->idSmallCns(imm);
7233 id->idOpSize(EA_SIZE(attr));
7234
7235 id->idAddr()->iiaBBlabel = dst;
7236 id->idjKeepLong = emitComp->fgInDifferentRegions(emitComp->compCurBB, dst);
7237
7238 /* Record the jump's IG and offset within it */
7239
7240 id->idjIG = emitCurIG;
7241 id->idjOffs = emitCurIGsize;
7242
7243 /* Append this jump to this IG's jump list */
7244
7245 id->idjNext = emitCurIGjmpList;
7246 emitCurIGjmpList = id;
7247
7248#if EMITTER_STATS
7249 emitTotalIGjmps++;
7250#endif
7251
7252 dispIns(id);
7253 appendToCurIG(id);
7254}
7255
7256void emitter::emitIns_J(instruction ins, BasicBlock* dst, int instrCount)
7257{
7258 insFormat fmt = IF_NONE;
7259
7260 if (dst != nullptr)
7261 {
7262 assert(dst->bbFlags & BBF_JMP_TARGET);
7263 }
7264 else
7265 {
7266 assert(instrCount != 0);
7267 }
7268
7269 /* Figure out the encoding format of the instruction */
7270
7271 bool idjShort = false;
7272 switch (ins)
7273 {
7274 case INS_bl_local:
7275 case INS_b:
7276 // Unconditional jump is a single form.
7277 idjShort = true;
7278 fmt = IF_BI_0A;
7279 break;
7280
7281 case INS_beq:
7282 case INS_bne:
7283 case INS_bhs:
7284 case INS_blo:
7285 case INS_bmi:
7286 case INS_bpl:
7287 case INS_bvs:
7288 case INS_bvc:
7289 case INS_bhi:
7290 case INS_bls:
7291 case INS_bge:
7292 case INS_blt:
7293 case INS_bgt:
7294 case INS_ble:
7295 // Assume conditional jump is long.
7296 fmt = IF_LARGEJMP;
7297 break;
7298
7299 default:
7300 unreached();
7301 break;
7302 }
7303
7304 instrDescJmp* id = emitNewInstrJmp();
7305
7306 id->idIns(ins);
7307 id->idInsFmt(fmt);
7308 id->idjShort = idjShort;
7309
7310#ifdef DEBUG
7311 // Mark the finally call
7312 if (ins == INS_bl_local && emitComp->compCurBB->bbJumpKind == BBJ_CALLFINALLY)
7313 {
7314 id->idDebugOnlyInfo()->idFinallyCall = true;
7315 }
7316#endif // DEBUG
7317
7318 if (dst != nullptr)
7319 {
7320 id->idAddr()->iiaBBlabel = dst;
7321
7322 // Skip unconditional jump that has a single form.
7323 // TODO-ARM64-NYI: enable hot/cold splittingNYI.
7324 // The target needs to be relocated.
7325 if (!idjShort)
7326 {
7327 id->idjKeepLong = emitComp->fgInDifferentRegions(emitComp->compCurBB, dst);
7328
7329#ifdef DEBUG
7330 if (emitComp->opts.compLongAddress) // Force long branches
7331 id->idjKeepLong = 1;
7332#endif // DEBUG
7333 }
7334 }
7335 else
7336 {
7337 id->idAddr()->iiaSetInstrCount(instrCount);
7338 id->idjKeepLong = false;
7339 /* This jump must be short */
7340 emitSetShortJump(id);
7341 id->idSetIsBound();
7342 }
7343
7344 /* Record the jump's IG and offset within it */
7345
7346 id->idjIG = emitCurIG;
7347 id->idjOffs = emitCurIGsize;
7348
7349 /* Append this jump to this IG's jump list */
7350
7351 id->idjNext = emitCurIGjmpList;
7352 emitCurIGjmpList = id;
7353
7354#if EMITTER_STATS
7355 emitTotalIGjmps++;
7356#endif
7357
7358 dispIns(id);
7359 appendToCurIG(id);
7360}
7361
7362/*****************************************************************************
7363 *
7364 * Add a call instruction (direct or indirect).
7365 * argSize<0 means that the caller will pop the arguments
7366 *
7367 * The other arguments are interpreted depending on callType as shown:
7368 * Unless otherwise specified, ireg,xreg,xmul,disp should have default values.
7369 *
7370 * EC_FUNC_TOKEN : addr is the method address
7371 * EC_FUNC_ADDR : addr is the absolute address of the function
7372 *
7373 * If callType is one of these emitCallTypes, addr has to be NULL.
7374 * EC_INDIR_R : "call ireg".
7375 *
7376 * For ARM xreg, xmul and disp are never used and should always be 0/REG_NA.
7377 *
7378 * Please consult the "debugger team notification" comment in genFnProlog().
7379 */
7380
7381void emitter::emitIns_Call(EmitCallType callType,
7382 CORINFO_METHOD_HANDLE methHnd,
7383 INDEBUG_LDISASM_COMMA(CORINFO_SIG_INFO* sigInfo) // used to report call sites to the EE
7384 void* addr,
7385 ssize_t argSize,
7386 emitAttr retSize,
7387 emitAttr secondRetSize,
7388 VARSET_VALARG_TP ptrVars,
7389 regMaskTP gcrefRegs,
7390 regMaskTP byrefRegs,
7391 IL_OFFSETX ilOffset /* = BAD_IL_OFFSET */,
7392 regNumber ireg /* = REG_NA */,
7393 regNumber xreg /* = REG_NA */,
7394 unsigned xmul /* = 0 */,
7395 ssize_t disp /* = 0 */,
7396 bool isJump /* = false */)
7397{
7398 /* Sanity check the arguments depending on callType */
7399
7400 assert(callType < EC_COUNT);
7401 assert((callType != EC_FUNC_TOKEN && callType != EC_FUNC_ADDR) ||
7402 (ireg == REG_NA && xreg == REG_NA && xmul == 0 && disp == 0));
7403 assert(callType < EC_INDIR_R || addr == NULL);
7404 assert(callType != EC_INDIR_R || (ireg < REG_COUNT && xreg == REG_NA && xmul == 0 && disp == 0));
7405
7406 // ARM never uses these
7407 assert(xreg == REG_NA && xmul == 0 && disp == 0);
7408
7409 // Our stack level should be always greater than the bytes of arguments we push. Just
7410 // a sanity test.
7411 assert((unsigned)abs(argSize) <= codeGen->genStackLevel);
7412
7413 // Trim out any callee-trashed registers from the live set.
7414 regMaskTP savedSet = emitGetGCRegsSavedOrModified(methHnd);
7415 gcrefRegs &= savedSet;
7416 byrefRegs &= savedSet;
7417
7418#ifdef DEBUG
7419 if (EMIT_GC_VERBOSE)
7420 {
7421 printf("Call: GCvars=%s ", VarSetOps::ToString(emitComp, ptrVars));
7422 dumpConvertedVarSet(emitComp, ptrVars);
7423 printf(", gcrefRegs=");
7424 printRegMaskInt(gcrefRegs);
7425 emitDispRegSet(gcrefRegs);
7426 printf(", byrefRegs=");
7427 printRegMaskInt(byrefRegs);
7428 emitDispRegSet(byrefRegs);
7429 printf("\n");
7430 }
7431#endif
7432
7433 /* Managed RetVal: emit sequence point for the call */
7434 if (emitComp->opts.compDbgInfo && ilOffset != BAD_IL_OFFSET)
7435 {
7436 codeGen->genIPmappingAdd(ilOffset, false);
7437 }
7438
7439 /*
7440 We need to allocate the appropriate instruction descriptor based
7441 on whether this is a direct/indirect call, and whether we need to
7442 record an updated set of live GC variables.
7443 */
7444 instrDesc* id;
7445
7446 assert(argSize % REGSIZE_BYTES == 0);
7447 int argCnt = (int)(argSize / (int)REGSIZE_BYTES);
7448
7449 if (callType >= EC_INDIR_R)
7450 {
7451 /* Indirect call, virtual calls */
7452
7453 assert(callType == EC_INDIR_R);
7454
7455 id = emitNewInstrCallInd(argCnt, disp, ptrVars, gcrefRegs, byrefRegs, retSize, secondRetSize);
7456 }
7457 else
7458 {
7459 /* Helper/static/nonvirtual/function calls (direct or through handle),
7460 and calls to an absolute addr. */
7461
7462 assert(callType == EC_FUNC_TOKEN || callType == EC_FUNC_ADDR);
7463
7464 id = emitNewInstrCallDir(argCnt, ptrVars, gcrefRegs, byrefRegs, retSize, secondRetSize);
7465 }
7466
7467 /* Update the emitter's live GC ref sets */
7468
7469 VarSetOps::Assign(emitComp, emitThisGCrefVars, ptrVars);
7470 emitThisGCrefRegs = gcrefRegs;
7471 emitThisByrefRegs = byrefRegs;
7472
7473 id->idSetIsNoGC(emitNoGChelper(methHnd));
7474
7475 /* Set the instruction - special case jumping a function */
7476 instruction ins;
7477 insFormat fmt = IF_NONE;
7478
7479 /* Record the address: method, indirection, or funcptr */
7480
7481 if (callType > EC_FUNC_ADDR)
7482 {
7483 /* This is an indirect call (either a virtual call or func ptr call) */
7484
7485 switch (callType)
7486 {
7487 case EC_INDIR_R: // the address is in a register
7488
7489 id->idSetIsCallRegPtr();
7490
7491 if (isJump)
7492 {
7493 ins = INS_br_tail; // INS_br_tail Reg
7494 }
7495 else
7496 {
7497 ins = INS_blr; // INS_blr Reg
7498 }
7499 fmt = IF_BR_1B;
7500
7501 id->idIns(ins);
7502 id->idInsFmt(fmt);
7503
7504 id->idReg3(ireg);
7505 assert(xreg == REG_NA);
7506 break;
7507
7508 default:
7509 NO_WAY("unexpected instruction");
7510 break;
7511 }
7512 }
7513 else
7514 {
7515 /* This is a simple direct call: "call helper/method/addr" */
7516
7517 assert(callType == EC_FUNC_TOKEN || callType == EC_FUNC_ADDR);
7518
7519 assert(addr != NULL);
7520
7521 if (isJump)
7522 {
7523 ins = INS_b_tail; // INS_b_tail imm28
7524 }
7525 else
7526 {
7527 ins = INS_bl; // INS_bl imm28
7528 }
7529 fmt = IF_BI_0C;
7530
7531 id->idIns(ins);
7532 id->idInsFmt(fmt);
7533
7534 id->idAddr()->iiaAddr = (BYTE*)addr;
7535
7536 if (callType == EC_FUNC_ADDR)
7537 {
7538 id->idSetIsCallAddr();
7539 }
7540
7541 if (emitComp->opts.compReloc)
7542 {
7543 id->idSetIsDspReloc();
7544 }
7545 }
7546
7547#ifdef DEBUG
7548 if (EMIT_GC_VERBOSE)
7549 {
7550 if (id->idIsLargeCall())
7551 {
7552 printf("[%02u] Rec call GC vars = %s\n", id->idDebugOnlyInfo()->idNum,
7553 VarSetOps::ToString(emitComp, ((instrDescCGCA*)id)->idcGCvars));
7554 }
7555 }
7556
7557 id->idDebugOnlyInfo()->idMemCookie = (size_t)methHnd; // method token
7558 id->idDebugOnlyInfo()->idCallSig = sigInfo;
7559#endif // DEBUG
7560
7561#ifdef LATE_DISASM
7562 if (addr != nullptr)
7563 {
7564 codeGen->getDisAssembler().disSetMethod((size_t)addr, methHnd);
7565 }
7566#endif // LATE_DISASM
7567
7568 dispIns(id);
7569 appendToCurIG(id);
7570}
7571
7572/*****************************************************************************
7573 *
7574 * Returns true if 'imm' is valid Cond encoding
7575 */
7576
7577/*static*/ bool emitter::isValidImmCond(ssize_t imm)
7578{
7579 // range check the ssize_t value, to make sure it is a small unsigned value
7580 // and that only the bits in the cfi.cond are set
7581 if ((imm < 0) || (imm > 0xF))
7582 return false;
7583
7584 condFlagsImm cfi;
7585 cfi.immCFVal = (unsigned)imm;
7586
7587 return (cfi.cond <= INS_COND_LE); // Don't allow 14 & 15 (AL & NV).
7588}
7589
7590/*****************************************************************************
7591 *
7592 * Returns true if 'imm' is valid Cond/Flags encoding
7593 */
7594
7595/*static*/ bool emitter::isValidImmCondFlags(ssize_t imm)
7596{
7597 // range check the ssize_t value, to make sure it is a small unsigned value
7598 // and that only the bits in the cfi.cond or cfi.flags are set
7599 if ((imm < 0) || (imm > 0xFF))
7600 return false;
7601
7602 condFlagsImm cfi;
7603 cfi.immCFVal = (unsigned)imm;
7604
7605 return (cfi.cond <= INS_COND_LE); // Don't allow 14 & 15 (AL & NV).
7606}
7607
7608/*****************************************************************************
7609 *
7610 * Returns true if 'imm' is valid Cond/Flags/Imm5 encoding
7611 */
7612
7613/*static*/ bool emitter::isValidImmCondFlagsImm5(ssize_t imm)
7614{
7615 // range check the ssize_t value, to make sure it is a small unsigned value
7616 // and that only the bits in the cfi.cond, cfi.flags or cfi.imm5 are set
7617 if ((imm < 0) || (imm > 0x1FFF))
7618 return false;
7619
7620 condFlagsImm cfi;
7621 cfi.immCFVal = (unsigned)imm;
7622
7623 return (cfi.cond <= INS_COND_LE); // Don't allow 14 & 15 (AL & NV).
7624}
7625
7626/*****************************************************************************
7627 *
7628 * Returns an encoding for the specified register used in the 'Rd' position
7629 */
7630
7631/*static*/ emitter::code_t emitter::insEncodeReg_Rd(regNumber reg)
7632{
7633 assert(isIntegerRegister(reg));
7634 emitter::code_t ureg = (emitter::code_t)reg;
7635 assert((ureg >= 0) && (ureg <= 31));
7636 return ureg;
7637}
7638
7639/*****************************************************************************
7640 *
7641 * Returns an encoding for the specified register used in the 'Rt' position
7642 */
7643
7644/*static*/ emitter::code_t emitter::insEncodeReg_Rt(regNumber reg)
7645{
7646 assert(isIntegerRegister(reg));
7647 emitter::code_t ureg = (emitter::code_t)reg;
7648 assert((ureg >= 0) && (ureg <= 31));
7649 return ureg;
7650}
7651
7652/*****************************************************************************
7653 *
7654 * Returns an encoding for the specified register used in the 'Rn' position
7655 */
7656
7657/*static*/ emitter::code_t emitter::insEncodeReg_Rn(regNumber reg)
7658{
7659 assert(isIntegerRegister(reg));
7660 emitter::code_t ureg = (emitter::code_t)reg;
7661 assert((ureg >= 0) && (ureg <= 31));
7662 return ureg << 5;
7663}
7664
7665/*****************************************************************************
7666 *
7667 * Returns an encoding for the specified register used in the 'Rm' position
7668 */
7669
7670/*static*/ emitter::code_t emitter::insEncodeReg_Rm(regNumber reg)
7671{
7672 assert(isIntegerRegister(reg));
7673 emitter::code_t ureg = (emitter::code_t)reg;
7674 assert((ureg >= 0) && (ureg <= 31));
7675 return ureg << 16;
7676}
7677
7678/*****************************************************************************
7679 *
7680 * Returns an encoding for the specified register used in the 'Ra' position
7681 */
7682
7683/*static*/ emitter::code_t emitter::insEncodeReg_Ra(regNumber reg)
7684{
7685 assert(isIntegerRegister(reg));
7686 emitter::code_t ureg = (emitter::code_t)reg;
7687 assert((ureg >= 0) && (ureg <= 31));
7688 return ureg << 10;
7689}
7690
7691/*****************************************************************************
7692 *
7693 * Returns an encoding for the specified register used in the 'Vd' position
7694 */
7695
7696/*static*/ emitter::code_t emitter::insEncodeReg_Vd(regNumber reg)
7697{
7698 assert(emitter::isVectorRegister(reg));
7699 emitter::code_t ureg = (emitter::code_t)reg - (emitter::code_t)REG_V0;
7700 assert((ureg >= 0) && (ureg <= 31));
7701 return ureg;
7702}
7703
7704/*****************************************************************************
7705 *
7706 * Returns an encoding for the specified register used in the 'Vt' position
7707 */
7708
7709/*static*/ emitter::code_t emitter::insEncodeReg_Vt(regNumber reg)
7710{
7711 assert(emitter::isVectorRegister(reg));
7712 emitter::code_t ureg = (emitter::code_t)reg - (emitter::code_t)REG_V0;
7713 assert((ureg >= 0) && (ureg <= 31));
7714 return ureg;
7715}
7716
7717/*****************************************************************************
7718 *
7719 * Returns an encoding for the specified register used in the 'Vn' position
7720 */
7721
7722/*static*/ emitter::code_t emitter::insEncodeReg_Vn(regNumber reg)
7723{
7724 assert(emitter::isVectorRegister(reg));
7725 emitter::code_t ureg = (emitter::code_t)reg - (emitter::code_t)REG_V0;
7726 assert((ureg >= 0) && (ureg <= 31));
7727 return ureg << 5;
7728}
7729
7730/*****************************************************************************
7731 *
7732 * Returns an encoding for the specified register used in the 'Vm' position
7733 */
7734
7735/*static*/ emitter::code_t emitter::insEncodeReg_Vm(regNumber reg)
7736{
7737 assert(emitter::isVectorRegister(reg));
7738 emitter::code_t ureg = (emitter::code_t)reg - (emitter::code_t)REG_V0;
7739 assert((ureg >= 0) && (ureg <= 31));
7740 return ureg << 16;
7741}
7742
7743/*****************************************************************************
7744 *
7745 * Returns an encoding for the specified register used in the 'Va' position
7746 */
7747
7748/*static*/ emitter::code_t emitter::insEncodeReg_Va(regNumber reg)
7749{
7750 assert(emitter::isVectorRegister(reg));
7751 emitter::code_t ureg = (emitter::code_t)reg - (emitter::code_t)REG_V0;
7752 assert((ureg >= 0) && (ureg <= 31));
7753 return ureg << 10;
7754}
7755
7756/*****************************************************************************
7757 *
7758 * Returns an encoding for the specified condition code.
7759 */
7760
7761/*static*/ emitter::code_t emitter::insEncodeCond(insCond cond)
7762{
7763 emitter::code_t uimm = (emitter::code_t)cond;
7764 return uimm << 12;
7765}
7766
7767/*****************************************************************************
7768 *
7769 * Returns an encoding for the condition code with the lowest bit inverted (marked by invert(<cond>) in the
7770 * architecture manual).
7771 */
7772
7773/*static*/ emitter::code_t emitter::insEncodeInvertedCond(insCond cond)
7774{
7775 emitter::code_t uimm = (emitter::code_t)cond;
7776 uimm ^= 1; // invert the lowest bit
7777 return uimm << 12;
7778}
7779
7780/*****************************************************************************
7781 *
7782 * Returns an encoding for the specified flags.
7783 */
7784
7785/*static*/ emitter::code_t emitter::insEncodeFlags(insCflags flags)
7786{
7787 emitter::code_t uimm = (emitter::code_t)flags;
7788 return uimm;
7789}
7790
7791/*****************************************************************************
7792 *
7793 * Returns the encoding for the Shift Count bits to be used for Arm64 encodings
7794 */
7795
7796/*static*/ emitter::code_t emitter::insEncodeShiftCount(ssize_t imm, emitAttr size)
7797{
7798 assert((imm & 0x003F) == imm);
7799 assert(((imm & 0x0020) == 0) || (size == EA_8BYTE));
7800
7801 return (emitter::code_t)imm << 10;
7802}
7803
7804/*****************************************************************************
7805 *
7806 * Returns the encoding to select a 64-bit datasize for an Arm64 instruction
7807 */
7808
7809/*static*/ emitter::code_t emitter::insEncodeDatasize(emitAttr size)
7810{
7811 if (size == EA_8BYTE)
7812 {
7813 return 0x80000000; // set the bit at location 31
7814 }
7815 else
7816 {
7817 assert(size == EA_4BYTE);
7818 return 0;
7819 }
7820}
7821
7822/*****************************************************************************
7823 *
7824 * Returns the encoding to select the datasize for the general load/store Arm64 instructions
7825 *
7826 */
7827
7828/*static*/ emitter::code_t emitter::insEncodeDatasizeLS(emitter::code_t code, emitAttr size)
7829{
7830 bool exclusive = ((code & 0x35000000) == 0);
7831 bool atomic = ((code & 0x31200C00) == 0x30200000);
7832
7833 if ((code & 0x00800000) && !exclusive && !atomic) // Is this a sign-extending opcode? (i.e. ldrsw, ldrsh, ldrsb)
7834 {
7835 if ((code & 0x80000000) == 0) // Is it a ldrsh or ldrsb and not ldrsw ?
7836 {
7837 if (EA_SIZE(size) != EA_8BYTE) // Do we need to encode the 32-bit Rt size bit?
7838 {
7839 return 0x00400000; // set the bit at location 22
7840 }
7841 }
7842 }
7843 else if (code & 0x80000000) // Is this a ldr/str/ldur/stur opcode?
7844 {
7845 if (EA_SIZE(size) == EA_8BYTE) // Do we need to encode the 64-bit size bit?
7846 {
7847 return 0x40000000; // set the bit at location 30
7848 }
7849 }
7850 return 0;
7851}
7852
7853/*****************************************************************************
7854 *
7855 * Returns the encoding to select the datasize for the vector load/store Arm64 instructions
7856 *
7857 */
7858
7859/*static*/ emitter::code_t emitter::insEncodeDatasizeVLS(emitter::code_t code, emitAttr size)
7860{
7861 code_t result = 0;
7862
7863 // Check bit 29
7864 if ((code & 0x20000000) == 0)
7865 {
7866 // LDR literal
7867
7868 if (size == EA_16BYTE)
7869 {
7870 // set the operation size in bit 31
7871 result = 0x80000000;
7872 }
7873 else if (size == EA_8BYTE)
7874 {
7875 // set the operation size in bit 30
7876 result = 0x40000000;
7877 }
7878 else
7879 {
7880 assert(size == EA_4BYTE);
7881 // no bits are set
7882 result = 0x00000000;
7883 }
7884 }
7885 else
7886 {
7887 // LDR non-literal
7888
7889 if (size == EA_16BYTE)
7890 {
7891 // The operation size in bits 31 and 30 are zero
7892 // Bit 23 specifies a 128-bit Load/Store
7893 result = 0x00800000;
7894 }
7895 else if (size == EA_8BYTE)
7896 {
7897 // set the operation size in bits 31 and 30
7898 result = 0xC0000000;
7899 }
7900 else if (size == EA_4BYTE)
7901 {
7902 // set the operation size in bit 31
7903 result = 0x80000000;
7904 }
7905 else if (size == EA_2BYTE)
7906 {
7907 // set the operation size in bit 30
7908 result = 0x40000000;
7909 }
7910 else
7911 {
7912 assert(size == EA_1BYTE);
7913 // The operation size in bits 31 and 30 are zero
7914 result = 0x00000000;
7915 }
7916 }
7917
7918 // Or in bit 26 to indicate a Vector register is used as 'target'
7919 result |= 0x04000000;
7920
7921 return result;
7922}
7923
7924/*****************************************************************************
7925 *
7926 * Returns the encoding to select the datasize for the vector load/store Arm64 instructions
7927 *
7928 */
7929
7930/*static*/ emitter::code_t emitter::insEncodeDatasizeVPLS(emitter::code_t code, emitAttr size)
7931{
7932 code_t result = 0;
7933
7934 if (size == EA_16BYTE)
7935 {
7936 // The operation size in bits 31 and 30 are zero
7937 // Bit 23 specifies a 128-bit Load/Store
7938 result = 0x80000000;
7939 }
7940 else if (size == EA_8BYTE)
7941 {
7942 // set the operation size in bits 31 and 30
7943 result = 0x40000000;
7944 }
7945 else if (size == EA_4BYTE)
7946 {
7947 // set the operation size in bit 31
7948 result = 0x00000000;
7949 }
7950
7951 // Or in bit 26 to indicate a Vector register is used as 'target'
7952 result |= 0x04000000;
7953
7954 return result;
7955}
7956
7957/*****************************************************************************
7958 *
7959 * Returns the encoding to set the size bit and the N bits for a 'bitfield' instruction
7960 *
7961 */
7962
7963/*static*/ emitter::code_t emitter::insEncodeDatasizeBF(emitter::code_t code, emitAttr size)
7964{
7965 // is bit 30 equal to 0?
7966 if ((code & 0x40000000) == 0) // is the opcode one of extr, sxtb, sxth or sxtw
7967 {
7968 if (size == EA_8BYTE) // Do we need to set the sf and N bits?
7969 {
7970 return 0x80400000; // set the sf-bit at location 31 and the N-bit at location 22
7971 }
7972 }
7973 return 0; // don't set any bits
7974}
7975
7976/*****************************************************************************
7977 *
7978 * Returns the encoding to select the 64/128-bit datasize for an Arm64 vector instruction
7979 */
7980
7981/*static*/ emitter::code_t emitter::insEncodeVectorsize(emitAttr size)
7982{
7983 if (size == EA_16BYTE)
7984 {
7985 return 0x40000000; // set the bit at location 30
7986 }
7987 else
7988 {
7989 assert(size == EA_8BYTE);
7990 return 0;
7991 }
7992}
7993
7994/*****************************************************************************
7995 *
7996 * Returns the encoding to select 'index' for an Arm64 vector elem instruction
7997 */
7998/*static*/ emitter::code_t emitter::insEncodeVectorIndex(emitAttr elemsize, ssize_t index)
7999{
8000 code_t bits = (code_t)index;
8001 if (elemsize == EA_1BYTE)
8002 {
8003 bits <<= 1;
8004 bits |= 1;
8005 }
8006 else if (elemsize == EA_2BYTE)
8007 {
8008 bits <<= 2;
8009 bits |= 2;
8010 }
8011 else if (elemsize == EA_4BYTE)
8012 {
8013 bits <<= 3;
8014 bits |= 4;
8015 }
8016 else
8017 {
8018 assert(elemsize == EA_8BYTE);
8019 bits <<= 4;
8020 bits |= 8;
8021 }
8022 assert((bits >= 1) && (bits <= 0x1f));
8023
8024 return (bits << 16); // bits at locations [20,19,18,17,16]
8025}
8026
8027/*****************************************************************************
8028 *
8029 * Returns the encoding to select 'index2' for an Arm64 'ins' elem instruction
8030 */
8031/*static*/ emitter::code_t emitter::insEncodeVectorIndex2(emitAttr elemsize, ssize_t index2)
8032{
8033 code_t bits = (code_t)index2;
8034 if (elemsize == EA_1BYTE)
8035 {
8036 // bits are correct
8037 }
8038 else if (elemsize == EA_2BYTE)
8039 {
8040 bits <<= 1;
8041 }
8042 else if (elemsize == EA_4BYTE)
8043 {
8044 bits <<= 2;
8045 }
8046 else
8047 {
8048 assert(elemsize == EA_8BYTE);
8049 bits <<= 3;
8050 }
8051 assert((bits >= 0) && (bits <= 0xf));
8052
8053 return (bits << 11); // bits at locations [14,13,12,11]
8054}
8055
8056/*****************************************************************************
8057 *
8058 * Returns the encoding to select the 'index' for an Arm64 'mul' by elem instruction
8059 */
8060/*static*/ emitter::code_t emitter::insEncodeVectorIndexLMH(emitAttr elemsize, ssize_t index)
8061{
8062 code_t bits = 0;
8063
8064 if (elemsize == EA_2BYTE)
8065 {
8066 assert((index >= 0) && (index <= 7));
8067 if (index & 0x4)
8068 {
8069 bits |= (1 << 11); // set bit 11 'H'
8070 }
8071 if (index & 0x2)
8072 {
8073 bits |= (1 << 21); // set bit 21 'L'
8074 }
8075 if (index & 0x1)
8076 {
8077 bits |= (1 << 20); // set bit 20 'M'
8078 }
8079 }
8080 else if (elemsize == EA_4BYTE)
8081 {
8082 assert((index >= 0) && (index <= 3));
8083 if (index & 0x2)
8084 {
8085 bits |= (1 << 11); // set bit 11 'H'
8086 }
8087 if (index & 0x1)
8088 {
8089 bits |= (1 << 21); // set bit 21 'L'
8090 }
8091 }
8092 else
8093 {
8094 assert(!"Invalid 'elemsize' value");
8095 }
8096
8097 return bits;
8098}
8099
8100/*****************************************************************************
8101 *
8102 * Returns the encoding to shift by 'shift' for an Arm64 vector or scalar instruction
8103 */
8104
8105/*static*/ emitter::code_t emitter::insEncodeVectorShift(emitAttr size, ssize_t shift)
8106{
8107 assert(shift < getBitWidth(size));
8108
8109 code_t imm = (code_t)(getBitWidth(size) + shift);
8110
8111 return imm << 16;
8112}
8113
8114/*****************************************************************************
8115 *
8116 * Returns the encoding to select the 1/2/4/8 byte elemsize for an Arm64 vector instruction
8117 */
8118
8119/*static*/ emitter::code_t emitter::insEncodeElemsize(emitAttr size)
8120{
8121 if (size == EA_8BYTE)
8122 {
8123 return 0x00C00000; // set the bit at location 23 and 22
8124 }
8125 else if (size == EA_4BYTE)
8126 {
8127 return 0x00800000; // set the bit at location 23
8128 }
8129 else if (size == EA_2BYTE)
8130 {
8131 return 0x00400000; // set the bit at location 22
8132 }
8133 assert(size == EA_1BYTE);
8134 return 0x00000000;
8135}
8136
8137/*****************************************************************************
8138 *
8139 * Returns the encoding to select the 4/8 byte elemsize for an Arm64 float vector instruction
8140 */
8141
8142/*static*/ emitter::code_t emitter::insEncodeFloatElemsize(emitAttr size)
8143{
8144 if (size == EA_8BYTE)
8145 {
8146 return 0x00400000; // set the bit at location 22
8147 }
8148 assert(size == EA_4BYTE);
8149 return 0x00000000;
8150}
8151
8152// Returns the encoding to select the index for an Arm64 float vector by elem instruction
8153/*static*/ emitter::code_t emitter::insEncodeFloatIndex(emitAttr elemsize, ssize_t index)
8154{
8155 code_t result = 0x00000000;
8156 if (elemsize == EA_8BYTE)
8157 {
8158 assert((index >= 0) && (index <= 1));
8159 if (index == 1)
8160 {
8161 result |= 0x00000800; // 'H' - set the bit at location 11
8162 }
8163 }
8164 else
8165 {
8166 assert(elemsize == EA_4BYTE);
8167 assert((index >= 0) && (index <= 3));
8168 if (index & 2)
8169 {
8170 result |= 0x00000800; // 'H' - set the bit at location 11
8171 }
8172 if (index & 1)
8173 {
8174 result |= 0x00200000; // 'L' - set the bit at location 21
8175 }
8176 }
8177 return result;
8178}
8179
8180/*****************************************************************************
8181 *
8182 * Returns the encoding to select the fcvt operation for Arm64 instructions
8183 */
8184/*static*/ emitter::code_t emitter::insEncodeConvertOpt(insFormat fmt, insOpts conversion)
8185{
8186 code_t result = 0;
8187 switch (conversion)
8188 {
8189 case INS_OPTS_S_TO_D: // Single to Double
8190 assert(fmt == IF_DV_2J);
8191 result = 0x00008000; // type=00, opc=01
8192 break;
8193
8194 case INS_OPTS_D_TO_S: // Double to Single
8195 assert(fmt == IF_DV_2J);
8196 result = 0x00400000; // type=01, opc=00
8197 break;
8198
8199 case INS_OPTS_H_TO_S: // Half to Single
8200 assert(fmt == IF_DV_2J);
8201 result = 0x00C00000; // type=11, opc=00
8202 break;
8203
8204 case INS_OPTS_H_TO_D: // Half to Double
8205 assert(fmt == IF_DV_2J);
8206 result = 0x00C08000; // type=11, opc=01
8207 break;
8208
8209 case INS_OPTS_S_TO_H: // Single to Half
8210 assert(fmt == IF_DV_2J);
8211 result = 0x00018000; // type=00, opc=11
8212 break;
8213
8214 case INS_OPTS_D_TO_H: // Double to Half
8215 assert(fmt == IF_DV_2J);
8216 result = 0x00418000; // type=01, opc=11
8217 break;
8218
8219 case INS_OPTS_S_TO_4BYTE: // Single to INT32
8220 assert(fmt == IF_DV_2H);
8221 result = 0x00000000; // sf=0, type=00
8222 break;
8223
8224 case INS_OPTS_D_TO_4BYTE: // Double to INT32
8225 assert(fmt == IF_DV_2H);
8226 result = 0x00400000; // sf=0, type=01
8227 break;
8228
8229 case INS_OPTS_S_TO_8BYTE: // Single to INT64
8230 assert(fmt == IF_DV_2H);
8231 result = 0x80000000; // sf=1, type=00
8232 break;
8233
8234 case INS_OPTS_D_TO_8BYTE: // Double to INT64
8235 assert(fmt == IF_DV_2H);
8236 result = 0x80400000; // sf=1, type=01
8237 break;
8238
8239 case INS_OPTS_4BYTE_TO_S: // INT32 to Single
8240 assert(fmt == IF_DV_2I);
8241 result = 0x00000000; // sf=0, type=00
8242 break;
8243
8244 case INS_OPTS_4BYTE_TO_D: // INT32 to Double
8245 assert(fmt == IF_DV_2I);
8246 result = 0x00400000; // sf=0, type=01
8247 break;
8248
8249 case INS_OPTS_8BYTE_TO_S: // INT64 to Single
8250 assert(fmt == IF_DV_2I);
8251 result = 0x80000000; // sf=1, type=00
8252 break;
8253
8254 case INS_OPTS_8BYTE_TO_D: // INT64 to Double
8255 assert(fmt == IF_DV_2I);
8256 result = 0x80400000; // sf=1, type=01
8257 break;
8258
8259 default:
8260 assert(!"Invalid 'conversion' value");
8261 break;
8262 }
8263 return result;
8264}
8265
8266/*****************************************************************************
8267 *
8268 * Returns the encoding to have the Rn register be updated Pre/Post indexed
8269 * or not updated
8270 */
8271
8272/*static*/ emitter::code_t emitter::insEncodeIndexedOpt(insOpts opt)
8273{
8274 assert(emitter::insOptsNone(opt) || emitter::insOptsIndexed(opt));
8275
8276 if (emitter::insOptsIndexed(opt))
8277 {
8278 if (emitter::insOptsPostIndex(opt))
8279 {
8280 return 0x00000400; // set the bit at location 10
8281 }
8282 else
8283 {
8284 assert(emitter::insOptsPreIndex(opt));
8285 return 0x00000C00; // set the bit at location 10 and 11
8286 }
8287 }
8288 else
8289 {
8290 assert(emitter::insOptsNone(opt));
8291 return 0; // bits 10 and 11 are zero
8292 }
8293}
8294
8295/*****************************************************************************
8296 *
8297 * Returns the encoding for a ldp/stp instruction to have the Rn register
8298 * be updated Pre/Post indexed or not updated
8299 */
8300
8301/*static*/ emitter::code_t emitter::insEncodePairIndexedOpt(instruction ins, insOpts opt)
8302{
8303 assert(emitter::insOptsNone(opt) || emitter::insOptsIndexed(opt));
8304
8305 if ((ins == INS_ldnp) || (ins == INS_stnp))
8306 {
8307 assert(emitter::insOptsNone(opt));
8308 return 0; // bits 23 and 24 are zero
8309 }
8310 else
8311 {
8312 if (emitter::insOptsIndexed(opt))
8313 {
8314 if (emitter::insOptsPostIndex(opt))
8315 {
8316 return 0x00800000; // set the bit at location 23
8317 }
8318 else
8319 {
8320 assert(emitter::insOptsPreIndex(opt));
8321 return 0x01800000; // set the bit at location 24 and 23
8322 }
8323 }
8324 else
8325 {
8326 assert(emitter::insOptsNone(opt));
8327 return 0x01000000; // set the bit at location 24
8328 }
8329 }
8330}
8331
8332/*****************************************************************************
8333 *
8334 * Returns the encoding to apply a Shift Type on the Rm register
8335 */
8336
8337/*static*/ emitter::code_t emitter::insEncodeShiftType(insOpts opt)
8338{
8339 if (emitter::insOptsNone(opt))
8340 {
8341 // None implies the we encode LSL (with a zero immediate)
8342 opt = INS_OPTS_LSL;
8343 }
8344 assert(emitter::insOptsAnyShift(opt));
8345
8346 emitter::code_t option = (emitter::code_t)opt - (emitter::code_t)INS_OPTS_LSL;
8347 assert(option <= 3);
8348
8349 return option << 22; // bits 23, 22
8350}
8351
8352/*****************************************************************************
8353 *
8354 * Returns the encoding to apply a 12 bit left shift to the immediate
8355 */
8356
8357/*static*/ emitter::code_t emitter::insEncodeShiftImm12(insOpts opt)
8358{
8359 if (emitter::insOptsLSL12(opt))
8360 {
8361 return 0x00400000; // set the bit at location 22
8362 }
8363 return 0;
8364}
8365
8366/*****************************************************************************
8367 *
8368 * Returns the encoding to have the Rm register use an extend operation
8369 */
8370
8371/*static*/ emitter::code_t emitter::insEncodeExtend(insOpts opt)
8372{
8373 if (emitter::insOptsNone(opt) || (opt == INS_OPTS_LSL))
8374 {
8375 // None or LSL implies the we encode UXTX
8376 opt = INS_OPTS_UXTX;
8377 }
8378 assert(emitter::insOptsAnyExtend(opt));
8379
8380 emitter::code_t option = (emitter::code_t)opt - (emitter::code_t)INS_OPTS_UXTB;
8381 assert(option <= 7);
8382
8383 return option << 13; // bits 15,14,13
8384}
8385
8386/*****************************************************************************
8387 *
8388 * Returns the encoding to scale the Rm register by {0,1,2,3,4}
8389 * when using an extend operation
8390 */
8391
8392/*static*/ emitter::code_t emitter::insEncodeExtendScale(ssize_t imm)
8393{
8394 assert((imm >= 0) && (imm <= 4));
8395
8396 return (emitter::code_t)imm << 10; // bits 12,11,10
8397}
8398
8399/*****************************************************************************
8400 *
8401 * Returns the encoding to have the Rm register be auto scaled by the ld/st size
8402 */
8403
8404/*static*/ emitter::code_t emitter::insEncodeReg3Scale(bool isScaled)
8405{
8406 if (isScaled)
8407 {
8408 return 0x00001000; // set the bit at location 12
8409 }
8410 else
8411 {
8412 return 0;
8413 }
8414}
8415
8416BYTE* emitter::emitOutputLoadLabel(BYTE* dst, BYTE* srcAddr, BYTE* dstAddr, instrDescJmp* id)
8417{
8418 instruction ins = id->idIns();
8419 insFormat fmt = id->idInsFmt();
8420 regNumber dstReg = id->idReg1();
8421 if (id->idjShort)
8422 {
8423 // adr x, [rel addr] -- compute address: current addr(ip) + rel addr.
8424 assert(ins == INS_adr);
8425 assert(fmt == IF_DI_1E);
8426 ssize_t distVal = (ssize_t)(dstAddr - srcAddr);
8427 dst = emitOutputShortAddress(dst, ins, fmt, distVal, dstReg);
8428 }
8429 else
8430 {
8431 // adrp x, [rel page addr] -- compute page address: current page addr + rel page addr
8432 assert(fmt == IF_LARGEADR);
8433 ssize_t relPageAddr =
8434 (((ssize_t)dstAddr & 0xFFFFFFFFFFFFF000LL) - ((ssize_t)srcAddr & 0xFFFFFFFFFFFFF000LL)) >> 12;
8435 dst = emitOutputShortAddress(dst, INS_adrp, IF_DI_1E, relPageAddr, dstReg);
8436
8437 // add x, x, page offs -- compute address = page addr + page offs
8438 ssize_t imm12 = (ssize_t)dstAddr & 0xFFF; // 12 bits
8439 assert(isValidUimm12(imm12));
8440 code_t code =
8441 emitInsCode(INS_add, IF_DI_2A); // DI_2A X0010001shiiiiii iiiiiinnnnnddddd 1100 0000 imm(i12, sh)
8442 code |= insEncodeDatasize(EA_8BYTE); // X
8443 code |= ((code_t)imm12 << 10); // iiiiiiiiiiii
8444 code |= insEncodeReg_Rd(dstReg); // ddddd
8445 code |= insEncodeReg_Rn(dstReg); // nnnnn
8446 dst += emitOutput_Instr(dst, code);
8447 }
8448 return dst;
8449}
8450
8451/*****************************************************************************
8452 *
8453 * Output a local jump or other instruction with a pc-relative immediate.
8454 * Note that this may be invoked to overwrite an existing jump instruction at 'dst'
8455 * to handle forward branch patching.
8456 */
8457
8458BYTE* emitter::emitOutputLJ(insGroup* ig, BYTE* dst, instrDesc* i)
8459{
8460 instrDescJmp* id = (instrDescJmp*)i;
8461
8462 unsigned srcOffs;
8463 unsigned dstOffs;
8464 BYTE* srcAddr;
8465 BYTE* dstAddr;
8466 ssize_t distVal;
8467
8468 // Set default ins/fmt from id.
8469 instruction ins = id->idIns();
8470 insFormat fmt = id->idInsFmt();
8471
8472 bool loadLabel = false;
8473 bool isJump = false;
8474 bool loadConstant = false;
8475
8476 switch (ins)
8477 {
8478 default:
8479 isJump = true;
8480 break;
8481
8482 case INS_tbz:
8483 case INS_tbnz:
8484 case INS_cbz:
8485 case INS_cbnz:
8486 isJump = true;
8487 break;
8488
8489 case INS_ldr:
8490 case INS_ldrsw:
8491 loadConstant = true;
8492 break;
8493
8494 case INS_adr:
8495 case INS_adrp:
8496 loadLabel = true;
8497 break;
8498 }
8499
8500 /* Figure out the distance to the target */
8501
8502 srcOffs = emitCurCodeOffs(dst);
8503 srcAddr = emitOffsetToPtr(srcOffs);
8504
8505 if (id->idAddr()->iiaIsJitDataOffset())
8506 {
8507 assert(loadConstant || loadLabel);
8508 int doff = id->idAddr()->iiaGetJitDataOffset();
8509 assert(doff >= 0);
8510 ssize_t imm = emitGetInsSC(id);
8511 assert((imm >= 0) && (imm < 0x1000)); // 0x1000 is arbitrary, currently 'imm' is always 0
8512
8513 unsigned dataOffs = (unsigned)(doff + imm);
8514 assert(dataOffs < emitDataSize());
8515 dstAddr = emitDataOffsetToPtr(dataOffs);
8516
8517 regNumber dstReg = id->idReg1();
8518 regNumber addrReg = dstReg; // an integer register to compute long address.
8519 emitAttr opSize = id->idOpSize();
8520
8521 if (loadConstant)
8522 {
8523 if (id->idjShort)
8524 {
8525 // ldr x/v, [rel addr] -- load constant from current addr(ip) + rel addr.
8526 assert(ins == INS_ldr);
8527 assert(fmt == IF_LS_1A);
8528 distVal = (ssize_t)(dstAddr - srcAddr);
8529 dst = emitOutputShortConstant(dst, ins, fmt, distVal, dstReg, opSize);
8530 }
8531 else
8532 {
8533 // adrp x, [rel page addr] -- compute page address: current page addr + rel page addr
8534 assert(fmt == IF_LARGELDC);
8535 ssize_t relPageAddr =
8536 (((ssize_t)dstAddr & 0xFFFFFFFFFFFFF000LL) - ((ssize_t)srcAddr & 0xFFFFFFFFFFFFF000LL)) >> 12;
8537 if (isVectorRegister(dstReg))
8538 {
8539 // Update addrReg with the reserved integer register
8540 // since we cannot use dstReg (vector) to load constant directly from memory.
8541 addrReg = id->idReg2();
8542 assert(isGeneralRegister(addrReg));
8543 }
8544 ins = INS_adrp;
8545 fmt = IF_DI_1E;
8546 dst = emitOutputShortAddress(dst, ins, fmt, relPageAddr, addrReg);
8547
8548 // ldr x, [x, page offs] -- load constant from page address + page offset into integer register.
8549 ssize_t imm12 = (ssize_t)dstAddr & 0xFFF; // 12 bits
8550 assert(isValidUimm12(imm12));
8551 ins = INS_ldr;
8552 fmt = IF_LS_2B;
8553 dst = emitOutputShortConstant(dst, ins, fmt, imm12, addrReg, opSize);
8554
8555 // fmov v, d -- copy constant in integer register to vector register.
8556 // This is needed only for vector constant.
8557 if (addrReg != dstReg)
8558 {
8559 // fmov Vd,Rn DV_2I X00111100X100111 000000nnnnnddddd 1E27 0000 Vd,Rn
8560 // (scalar, from general)
8561 assert(isVectorRegister(dstReg) && isGeneralRegister(addrReg));
8562 ins = INS_fmov;
8563 fmt = IF_DV_2I;
8564 code_t code = emitInsCode(ins, fmt);
8565
8566 code |= insEncodeReg_Vd(dstReg); // ddddd
8567 code |= insEncodeReg_Rn(addrReg); // nnnnn
8568 if (id->idOpSize() == EA_8BYTE)
8569 {
8570 code |= 0x80400000; // X ... X
8571 }
8572 dst += emitOutput_Instr(dst, code);
8573 }
8574 }
8575 }
8576 else
8577 {
8578 assert(loadLabel);
8579 dst = emitOutputLoadLabel(dst, srcAddr, dstAddr, id);
8580 }
8581
8582 return dst;
8583 }
8584
8585 assert(loadLabel || isJump);
8586
8587 if (id->idAddr()->iiaHasInstrCount())
8588 {
8589 assert(ig != NULL);
8590 int instrCount = id->idAddr()->iiaGetInstrCount();
8591 unsigned insNum = emitFindInsNum(ig, id);
8592 if (instrCount < 0)
8593 {
8594 // Backward branches using instruction count must be within the same instruction group.
8595 assert(insNum + 1 >= (unsigned)(-instrCount));
8596 }
8597 dstOffs = ig->igOffs + emitFindOffset(ig, (insNum + 1 + instrCount));
8598 dstAddr = emitOffsetToPtr(dstOffs);
8599 }
8600 else
8601 {
8602 dstOffs = id->idAddr()->iiaIGlabel->igOffs;
8603 dstAddr = emitOffsetToPtr(dstOffs);
8604 }
8605
8606 distVal = (ssize_t)(dstAddr - srcAddr);
8607
8608 if (dstOffs <= srcOffs)
8609 {
8610#if DEBUG_EMIT
8611 /* This is a backward jump - distance is known at this point */
8612
8613 if (id->idDebugOnlyInfo()->idNum == (unsigned)INTERESTING_JUMP_NUM || INTERESTING_JUMP_NUM == 0)
8614 {
8615 size_t blkOffs = id->idjIG->igOffs;
8616
8617 if (INTERESTING_JUMP_NUM == 0)
8618 printf("[3] Jump %u:\n", id->idDebugOnlyInfo()->idNum);
8619 printf("[3] Jump block is at %08X - %02X = %08X\n", blkOffs, emitOffsAdj, blkOffs - emitOffsAdj);
8620 printf("[3] Jump is at %08X - %02X = %08X\n", srcOffs, emitOffsAdj, srcOffs - emitOffsAdj);
8621 printf("[3] Label block is at %08X - %02X = %08X\n", dstOffs, emitOffsAdj, dstOffs - emitOffsAdj);
8622 }
8623#endif
8624 }
8625 else
8626 {
8627 /* This is a forward jump - distance will be an upper limit */
8628
8629 emitFwdJumps = true;
8630
8631 /* The target offset will be closer by at least 'emitOffsAdj', but only if this
8632 jump doesn't cross the hot-cold boundary. */
8633
8634 if (!emitJumpCrossHotColdBoundary(srcOffs, dstOffs))
8635 {
8636 dstOffs -= emitOffsAdj;
8637 distVal -= emitOffsAdj;
8638 }
8639
8640 /* Record the location of the jump for later patching */
8641
8642 id->idjOffs = dstOffs;
8643
8644 /* Are we overflowing the id->idjOffs bitfield? */
8645 if (id->idjOffs != dstOffs)
8646 IMPL_LIMITATION("Method is too large");
8647
8648#if DEBUG_EMIT
8649 if (id->idDebugOnlyInfo()->idNum == (unsigned)INTERESTING_JUMP_NUM || INTERESTING_JUMP_NUM == 0)
8650 {
8651 size_t blkOffs = id->idjIG->igOffs;
8652
8653 if (INTERESTING_JUMP_NUM == 0)
8654 printf("[4] Jump %u:\n", id->idDebugOnlyInfo()->idNum);
8655 printf("[4] Jump block is at %08X\n", blkOffs);
8656 printf("[4] Jump is at %08X\n", srcOffs);
8657 printf("[4] Label block is at %08X - %02X = %08X\n", dstOffs + emitOffsAdj, emitOffsAdj, dstOffs);
8658 }
8659#endif
8660 }
8661
8662#ifdef DEBUG
8663 if (0 && emitComp->verbose)
8664 {
8665 size_t sz = 4;
8666 int distValSize = id->idjShort ? 4 : 8;
8667 printf("; %s jump [%08X/%03u] from %0*X to %0*X: dist = %08XH\n", (dstOffs <= srcOffs) ? "Fwd" : "Bwd",
8668 dspPtr(id), id->idDebugOnlyInfo()->idNum, distValSize, srcOffs + sz, distValSize, dstOffs, distVal);
8669 }
8670#endif
8671
8672 /* For forward jumps, record the address of the distance value */
8673 id->idjTemp.idjAddr = (distVal > 0) ? dst : NULL;
8674
8675 if (emitJumpCrossHotColdBoundary(srcOffs, dstOffs))
8676 {
8677 assert(!id->idjShort);
8678 NYI_ARM64("Relocation Support for long address");
8679 }
8680
8681 assert(insOptsNone(id->idInsOpt()));
8682
8683 if (isJump)
8684 {
8685 if (id->idjShort)
8686 {
8687 // Short conditional/unconditional jump
8688 assert(!id->idjKeepLong);
8689 assert(emitJumpCrossHotColdBoundary(srcOffs, dstOffs) == false);
8690 assert((fmt == IF_BI_0A) || (fmt == IF_BI_0B) || (fmt == IF_BI_1A) || (fmt == IF_BI_1B));
8691 }
8692 else
8693 {
8694 // Long conditional jump
8695 assert(fmt == IF_LARGEJMP);
8696 // This is a pseudo-instruction format representing a large conditional branch, to allow
8697 // us to get a greater branch target range than we can get by using a straightforward conditional
8698 // branch. It is encoded as a short conditional branch that branches around a long unconditional
8699 // branch.
8700 //
8701 // Conceptually, we have:
8702 //
8703 // b<cond> L_target
8704 //
8705 // The code we emit is:
8706 //
8707 // b<!cond> L_not // 4 bytes. Note that we reverse the condition.
8708 // b L_target // 4 bytes
8709 // L_not:
8710 //
8711 // Note that we don't actually insert any blocks: we simply encode "b <!cond> L_not" as a branch with
8712 // the correct offset. Note also that this works for both integer and floating-point conditions, because
8713 // the condition inversion takes ordered/unordered into account, preserving NaN behavior. For example,
8714 // "GT" (greater than) is inverted to "LE" (less than, equal, or unordered).
8715
8716 instruction reverseIns;
8717 insFormat reverseFmt;
8718
8719 switch (ins)
8720 {
8721 case INS_cbz:
8722 reverseIns = INS_cbnz;
8723 reverseFmt = IF_BI_1A;
8724 break;
8725 case INS_cbnz:
8726 reverseIns = INS_cbz;
8727 reverseFmt = IF_BI_1A;
8728 break;
8729 case INS_tbz:
8730 reverseIns = INS_tbnz;
8731 reverseFmt = IF_BI_1B;
8732 break;
8733 case INS_tbnz:
8734 reverseIns = INS_tbz;
8735 reverseFmt = IF_BI_1B;
8736 break;
8737 default:
8738 reverseIns = emitJumpKindToIns(emitReverseJumpKind(emitInsToJumpKind(ins)));
8739 reverseFmt = IF_BI_0B;
8740 }
8741
8742 dst =
8743 emitOutputShortBranch(dst,
8744 reverseIns, // reverse the conditional instruction
8745 reverseFmt,
8746 8, /* 8 bytes from start of this large conditional pseudo-instruction to L_not. */
8747 id);
8748
8749 // Now, pretend we've got a normal unconditional branch, and fall through to the code to emit that.
8750 ins = INS_b;
8751 fmt = IF_BI_0A;
8752
8753 // The distVal was computed based on the beginning of the pseudo-instruction,
8754 // So subtract the size of the conditional branch so that it is relative to the
8755 // unconditional branch.
8756 distVal -= 4;
8757 }
8758
8759 dst = emitOutputShortBranch(dst, ins, fmt, distVal, id);
8760 }
8761 else if (loadLabel)
8762 {
8763 dst = emitOutputLoadLabel(dst, srcAddr, dstAddr, id);
8764 }
8765
8766 return dst;
8767}
8768
8769/*****************************************************************************
8770*
8771* Output a short branch instruction.
8772*/
8773BYTE* emitter::emitOutputShortBranch(BYTE* dst, instruction ins, insFormat fmt, ssize_t distVal, instrDescJmp* id)
8774{
8775 code_t code = emitInsCode(ins, fmt);
8776
8777 ssize_t loBits = (distVal & 3);
8778 noway_assert(loBits == 0);
8779 distVal >>= 2; // branch offset encodings are scaled by 4.
8780
8781 if (fmt == IF_BI_0A)
8782 {
8783 // INS_b or INS_bl_local
8784 noway_assert(isValidSimm26(distVal));
8785 distVal &= 0x3FFFFFFLL;
8786 code |= distVal;
8787 }
8788 else if (fmt == IF_BI_0B) // BI_0B 01010100iiiiiiii iiiiiiiiiiiXXXXX simm19:00
8789 {
8790 // INS_beq, INS_bne, etc...
8791 noway_assert(isValidSimm19(distVal));
8792 distVal &= 0x7FFFFLL;
8793 code |= distVal << 5;
8794 }
8795 else if (fmt == IF_BI_1A) // BI_1A X.......iiiiiiii iiiiiiiiiiittttt Rt simm19:00
8796 {
8797 // INS_cbz or INS_cbnz
8798 assert(id != nullptr);
8799 code |= insEncodeDatasize(id->idOpSize()); // X
8800 code |= insEncodeReg_Rt(id->idReg1()); // ttttt
8801
8802 noway_assert(isValidSimm19(distVal));
8803 distVal &= 0x7FFFFLL; // 19 bits
8804 code |= distVal << 5;
8805 }
8806 else if (fmt == IF_BI_1B) // BI_1B B.......bbbbbiii iiiiiiiiiiittttt Rt imm6, simm14:00
8807 {
8808 // INS_tbz or INS_tbnz
8809 assert(id != nullptr);
8810 ssize_t imm = emitGetInsSC(id);
8811 assert(isValidImmShift(imm, id->idOpSize()));
8812
8813 if (imm & 0x20) // test bit 32-63 ?
8814 {
8815 code |= 0x80000000; // B
8816 }
8817 code |= ((imm & 0x1F) << 19); // bbbbb
8818 code |= insEncodeReg_Rt(id->idReg1()); // ttttt
8819
8820 noway_assert(isValidSimm14(distVal));
8821 distVal &= 0x3FFFLL; // 14 bits
8822 code |= distVal << 5;
8823 }
8824 else
8825 {
8826 assert(!"Unknown fmt for emitOutputShortBranch");
8827 }
8828
8829 dst += emitOutput_Instr(dst, code);
8830
8831 return dst;
8832}
8833
8834/*****************************************************************************
8835*
8836* Output a short address instruction.
8837*/
8838BYTE* emitter::emitOutputShortAddress(BYTE* dst, instruction ins, insFormat fmt, ssize_t distVal, regNumber reg)
8839{
8840 ssize_t loBits = (distVal & 3);
8841 distVal >>= 2;
8842
8843 code_t code = emitInsCode(ins, fmt);
8844 if (fmt == IF_DI_1E) // DI_1E .ii.....iiiiiiii iiiiiiiiiiiddddd Rd simm21
8845 {
8846 // INS_adr or INS_adrp
8847 code |= insEncodeReg_Rd(reg); // ddddd
8848
8849 noway_assert(isValidSimm19(distVal));
8850 distVal &= 0x7FFFFLL; // 19 bits
8851 code |= distVal << 5;
8852 code |= loBits << 29; // 2 bits
8853 }
8854 else
8855 {
8856 assert(!"Unknown fmt for emitOutputShortAddress");
8857 }
8858
8859 dst += emitOutput_Instr(dst, code);
8860
8861 return dst;
8862}
8863
8864/*****************************************************************************
8865*
8866* Output a short constant instruction.
8867*/
8868BYTE* emitter::emitOutputShortConstant(
8869 BYTE* dst, instruction ins, insFormat fmt, ssize_t imm, regNumber reg, emitAttr opSize)
8870{
8871 code_t code = emitInsCode(ins, fmt);
8872
8873 if (fmt == IF_LS_1A)
8874 {
8875 // LS_1A XX...V..iiiiiiii iiiiiiiiiiittttt Rt simm21
8876 // INS_ldr or INS_ldrsw (PC-Relative)
8877
8878 ssize_t loBits = (imm & 3);
8879 noway_assert(loBits == 0);
8880 ssize_t distVal = imm >>= 2; // load offset encodings are scaled by 4.
8881
8882 noway_assert(isValidSimm19(distVal));
8883
8884 // Is the target a vector register?
8885 if (isVectorRegister(reg))
8886 {
8887 code |= insEncodeDatasizeVLS(code, opSize); // XX V
8888 code |= insEncodeReg_Vt(reg); // ttttt
8889 }
8890 else
8891 {
8892 assert(isGeneralRegister(reg));
8893 // insEncodeDatasizeLS is not quite right for this case.
8894 // So just specialize it.
8895 if ((ins == INS_ldr) && (opSize == EA_8BYTE))
8896 {
8897 // set the operation size in bit 30
8898 code |= 0x40000000;
8899 }
8900
8901 code |= insEncodeReg_Rt(reg); // ttttt
8902 }
8903
8904 distVal &= 0x7FFFFLL; // 19 bits
8905 code |= distVal << 5;
8906 }
8907 else if (fmt == IF_LS_2B)
8908 {
8909 // ldr Rt,[Xn+pimm12] LS_2B 1X11100101iiiiii iiiiiinnnnnttttt B940 0000 imm(0-4095<<{2,3})
8910 // INS_ldr or INS_ldrsw (PC-Relative)
8911 noway_assert(isValidUimm12(imm));
8912 assert(isGeneralRegister(reg));
8913
8914 if (opSize == EA_8BYTE)
8915 {
8916 // insEncodeDatasizeLS is not quite right for this case.
8917 // So just specialize it.
8918 if (ins == INS_ldr)
8919 {
8920 // set the operation size in bit 30
8921 code |= 0x40000000;
8922 }
8923 // Low 3 bits should be 0 -- 8 byte JIT data should be aligned on 8 byte.
8924 assert((imm & 7) == 0);
8925 imm >>= 3;
8926 }
8927 else
8928 {
8929 assert(opSize == EA_4BYTE);
8930 // Low 2 bits should be 0 -- 4 byte aligned data.
8931 assert((imm & 3) == 0);
8932 imm >>= 2;
8933 }
8934
8935 code |= insEncodeReg_Rt(reg); // ttttt
8936 code |= insEncodeReg_Rn(reg); // nnnnn
8937 code |= imm << 10;
8938 }
8939 else
8940 {
8941 assert(!"Unknown fmt for emitOutputShortConstant");
8942 }
8943
8944 dst += emitOutput_Instr(dst, code);
8945
8946 return dst;
8947}
8948/*****************************************************************************
8949 *
8950 * Output a call instruction.
8951 */
8952
8953unsigned emitter::emitOutputCall(insGroup* ig, BYTE* dst, instrDesc* id, code_t code)
8954{
8955 const unsigned char callInstrSize = sizeof(code_t); // 4 bytes
8956 regMaskTP gcrefRegs;
8957 regMaskTP byrefRegs;
8958
8959 VARSET_TP GCvars(VarSetOps::UninitVal());
8960
8961 // Is this a "fat" call descriptor?
8962 if (id->idIsLargeCall())
8963 {
8964 instrDescCGCA* idCall = (instrDescCGCA*)id;
8965 gcrefRegs = idCall->idcGcrefRegs;
8966 byrefRegs = idCall->idcByrefRegs;
8967 VarSetOps::Assign(emitComp, GCvars, idCall->idcGCvars);
8968 }
8969 else
8970 {
8971 assert(!id->idIsLargeDsp());
8972 assert(!id->idIsLargeCns());
8973
8974 gcrefRegs = emitDecodeCallGCregs(id);
8975 byrefRegs = 0;
8976 VarSetOps::AssignNoCopy(emitComp, GCvars, VarSetOps::MakeEmpty(emitComp));
8977 }
8978
8979 /* We update the GC info before the call as the variables cannot be
8980 used by the call. Killing variables before the call helps with
8981 boundary conditions if the call is CORINFO_HELP_THROW - see bug 50029.
8982 If we ever track aliased variables (which could be used by the
8983 call), we would have to keep them alive past the call. */
8984
8985 emitUpdateLiveGCvars(GCvars, dst);
8986
8987 // Now output the call instruction and update the 'dst' pointer
8988 //
8989 unsigned outputInstrSize = emitOutput_Instr(dst, code);
8990 dst += outputInstrSize;
8991
8992 // All call instructions are 4-byte in size on ARM64
8993 //
8994 assert(outputInstrSize == callInstrSize);
8995
8996 // If the method returns a GC ref, mark INTRET (R0) appropriately.
8997 if (id->idGCref() == GCT_GCREF)
8998 {
8999 gcrefRegs |= RBM_INTRET;
9000 }
9001 else if (id->idGCref() == GCT_BYREF)
9002 {
9003 byrefRegs |= RBM_INTRET;
9004 }
9005
9006 // If is a multi-register return method is called, mark INTRET_1 (X1) appropriately
9007 if (id->idIsLargeCall())
9008 {
9009 instrDescCGCA* idCall = (instrDescCGCA*)id;
9010 if (idCall->idSecondGCref() == GCT_GCREF)
9011 {
9012 gcrefRegs |= RBM_INTRET_1;
9013 }
9014 else if (idCall->idSecondGCref() == GCT_BYREF)
9015 {
9016 byrefRegs |= RBM_INTRET_1;
9017 }
9018 }
9019
9020 // If the GC register set has changed, report the new set.
9021 if (gcrefRegs != emitThisGCrefRegs)
9022 {
9023 emitUpdateLiveGCregs(GCT_GCREF, gcrefRegs, dst);
9024 }
9025 // If the Byref register set has changed, report the new set.
9026 if (byrefRegs != emitThisByrefRegs)
9027 {
9028 emitUpdateLiveGCregs(GCT_BYREF, byrefRegs, dst);
9029 }
9030
9031 // Some helper calls may be marked as not requiring GC info to be recorded.
9032 if ((!id->idIsNoGC()))
9033 {
9034 // On ARM64, as on AMD64, we don't change the stack pointer to push/pop args.
9035 // So we're not really doing a "stack pop" here (note that "args" is 0), but we use this mechanism
9036 // to record the call for GC info purposes. (It might be best to use an alternate call,
9037 // and protect "emitStackPop" under the EMIT_TRACK_STACK_DEPTH preprocessor variable.)
9038 emitStackPop(dst, /*isCall*/ true, callInstrSize, /*args*/ 0);
9039
9040 // Do we need to record a call location for GC purposes?
9041 //
9042 if (!emitFullGCinfo)
9043 {
9044 emitRecordGCcall(dst, callInstrSize);
9045 }
9046 }
9047 return callInstrSize;
9048}
9049
9050/*****************************************************************************
9051 *
9052 * Emit a 32-bit Arm64 instruction
9053 */
9054
9055/*static*/ unsigned emitter::emitOutput_Instr(BYTE* dst, code_t code)
9056{
9057 assert(sizeof(code_t) == 4);
9058 *((code_t*)dst) = code;
9059
9060 return sizeof(code_t);
9061}
9062
9063/*****************************************************************************
9064*
9065 * Append the machine code corresponding to the given instruction descriptor
9066 * to the code block at '*dp'; the base of the code block is 'bp', and 'ig'
9067 * is the instruction group that contains the instruction. Updates '*dp' to
9068 * point past the generated code, and returns the size of the instruction
9069 * descriptor in bytes.
9070 */
9071
9072size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
9073{
9074 BYTE* dst = *dp;
9075 BYTE* odst = dst;
9076 code_t code = 0;
9077 size_t sz = emitGetInstrDescSize(id); // TODO-ARM64-Cleanup: on ARM, this is set in each case. why?
9078 instruction ins = id->idIns();
9079 insFormat fmt = id->idInsFmt();
9080 emitAttr size = id->idOpSize();
9081 unsigned char callInstrSize = 0;
9082
9083#ifdef DEBUG
9084#if DUMP_GC_TABLES
9085 bool dspOffs = emitComp->opts.dspGCtbls;
9086#else
9087 bool dspOffs = !emitComp->opts.disDiffable;
9088#endif
9089#endif // DEBUG
9090
9091 assert(REG_NA == (int)REG_NA);
9092
9093 VARSET_TP GCvars(VarSetOps::UninitVal());
9094
9095 /* What instruction format have we got? */
9096
9097 switch (fmt)
9098 {
9099 ssize_t imm;
9100 ssize_t index;
9101 ssize_t index2;
9102 unsigned cmode;
9103 unsigned immShift;
9104 emitAttr elemsize;
9105 emitAttr datasize;
9106
9107 case IF_BI_0A: // BI_0A ......iiiiiiiiii iiiiiiiiiiiiiiii simm26:00
9108 case IF_BI_0B: // BI_0B ......iiiiiiiiii iiiiiiiiiii..... simm19:00
9109 case IF_LARGEJMP:
9110 assert(id->idGCref() == GCT_NONE);
9111 assert(id->idIsBound());
9112 dst = emitOutputLJ(ig, dst, id);
9113 sz = sizeof(instrDescJmp);
9114 break;
9115
9116 case IF_BI_0C: // BI_0C ......iiiiiiiiii iiiiiiiiiiiiiiii simm26:00
9117 code = emitInsCode(ins, fmt);
9118 sz = id->idIsLargeCall() ? sizeof(instrDescCGCA) : sizeof(instrDesc);
9119 dst += emitOutputCall(ig, dst, id, code);
9120 // Always call RecordRelocation so that we wire in a JumpStub when we don't reach
9121 emitRecordRelocation(odst, id->idAddr()->iiaAddr, IMAGE_REL_ARM64_BRANCH26);
9122 break;
9123
9124 case IF_BI_1A: // BI_1A ......iiiiiiiiii iiiiiiiiiiittttt Rt simm19:00
9125 assert(insOptsNone(id->idInsOpt()));
9126 assert(id->idIsBound());
9127
9128 dst = emitOutputLJ(ig, dst, id);
9129 sz = sizeof(instrDescJmp);
9130 break;
9131
9132 case IF_BI_1B: // BI_1B B.......bbbbbiii iiiiiiiiiiittttt Rt imm6, simm14:00
9133 assert(insOptsNone(id->idInsOpt()));
9134 assert(id->idIsBound());
9135
9136 dst = emitOutputLJ(ig, dst, id);
9137 sz = sizeof(instrDescJmp);
9138 break;
9139
9140 case IF_BR_1A: // BR_1A ................ ......nnnnn..... Rn
9141 assert(insOptsNone(id->idInsOpt()));
9142 assert((ins == INS_ret) || (ins == INS_br));
9143 code = emitInsCode(ins, fmt);
9144 code |= insEncodeReg_Rn(id->idReg1()); // nnnnn
9145
9146 dst += emitOutput_Instr(dst, code);
9147 break;
9148
9149 case IF_BR_1B: // BR_1B ................ ......nnnnn..... Rn
9150 assert(insOptsNone(id->idInsOpt()));
9151 assert((ins == INS_br_tail) || (ins == INS_blr));
9152 code = emitInsCode(ins, fmt);
9153 code |= insEncodeReg_Rn(id->idReg3()); // nnnnn
9154
9155 sz = id->idIsLargeCall() ? sizeof(instrDescCGCA) : sizeof(instrDesc);
9156 dst += emitOutputCall(ig, dst, id, code);
9157 break;
9158
9159 case IF_LS_1A: // LS_1A XX...V..iiiiiiii iiiiiiiiiiittttt Rt PC imm(1MB)
9160 case IF_LARGELDC:
9161 assert(insOptsNone(id->idInsOpt()));
9162 assert(id->idIsBound());
9163
9164 dst = emitOutputLJ(ig, dst, id);
9165 sz = sizeof(instrDescJmp);
9166 break;
9167
9168 case IF_LS_2A: // LS_2A .X.......X...... ......nnnnnttttt Rt Rn
9169 assert(insOptsNone(id->idInsOpt()));
9170 code = emitInsCode(ins, fmt);
9171 // Is the target a vector register?
9172 if (isVectorRegister(id->idReg1()))
9173 {
9174 code &= 0x3FFFFFFF; // clear the size bits
9175 code |= insEncodeDatasizeVLS(code, id->idOpSize()); // XX
9176 code |= insEncodeReg_Vt(id->idReg1()); // ttttt
9177 }
9178 else
9179 {
9180 code |= insEncodeDatasizeLS(code, id->idOpSize()); // .X.......X
9181 code |= insEncodeReg_Rt(id->idReg1()); // ttttt
9182 }
9183 code |= insEncodeReg_Rn(id->idReg2()); // nnnnn
9184 dst += emitOutput_Instr(dst, code);
9185 break;
9186
9187 case IF_LS_2B: // LS_2B .X.......Xiiiiii iiiiiinnnnnttttt Rt Rn imm(0-4095)
9188 assert(insOptsNone(id->idInsOpt()));
9189 imm = emitGetInsSC(id);
9190 assert(isValidUimm12(imm));
9191 code = emitInsCode(ins, fmt);
9192 // Is the target a vector register?
9193 if (isVectorRegister(id->idReg1()))
9194 {
9195 code &= 0x3FFFFFFF; // clear the size bits
9196 code |= insEncodeDatasizeVLS(code, id->idOpSize()); // XX
9197 code |= insEncodeReg_Vt(id->idReg1()); // ttttt
9198 }
9199 else
9200 {
9201 code |= insEncodeDatasizeLS(code, id->idOpSize()); // .X.......X
9202 code |= insEncodeReg_Rt(id->idReg1()); // ttttt
9203 }
9204 code |= ((code_t)imm << 10); // iiiiiiiiiiii
9205 code |= insEncodeReg_Rn(id->idReg2()); // nnnnn
9206 dst += emitOutput_Instr(dst, code);
9207 break;
9208
9209 case IF_LS_2C: // LS_2C .X.......X.iiiii iiiiPPnnnnnttttt Rt Rn imm(-256..+255) no/pre/post inc
9210 assert(insOptsNone(id->idInsOpt()) || insOptsIndexed(id->idInsOpt()));
9211 imm = emitGetInsSC(id);
9212 assert((imm >= -256) && (imm <= 255)); // signed 9 bits
9213 imm &= 0x1ff; // force into unsigned 9 bit representation
9214 code = emitInsCode(ins, fmt);
9215 // Is the target a vector register?
9216 if (isVectorRegister(id->idReg1()))
9217 {
9218 code &= 0x3FFFFFFF; // clear the size bits
9219 code |= insEncodeDatasizeVLS(code, id->idOpSize()); // XX
9220 code |= insEncodeReg_Vt(id->idReg1()); // ttttt
9221 }
9222 else
9223 {
9224 code |= insEncodeDatasizeLS(code, id->idOpSize()); // .X.......X
9225 code |= insEncodeReg_Rt(id->idReg1()); // ttttt
9226 }
9227 code |= insEncodeIndexedOpt(id->idInsOpt()); // PP
9228 code |= ((code_t)imm << 12); // iiiiiiiii
9229 code |= insEncodeReg_Rn(id->idReg2()); // nnnnn
9230 dst += emitOutput_Instr(dst, code);
9231 break;
9232
9233 case IF_LS_3A: // LS_3A .X.......X.mmmmm oooS..nnnnnttttt Rt Rn Rm ext(Rm) LSL {}
9234 assert(insOptsLSExtend(id->idInsOpt()));
9235 code = emitInsCode(ins, fmt);
9236 // Is the target a vector register?
9237 if (isVectorRegister(id->idReg1()))
9238 {
9239 code &= 0x3FFFFFFF; // clear the size bits
9240 code |= insEncodeDatasizeVLS(code, id->idOpSize()); // XX
9241 code |= insEncodeReg_Vt(id->idReg1()); // ttttt
9242 }
9243 else
9244 {
9245 code |= insEncodeDatasizeLS(code, id->idOpSize()); // .X.......X
9246 code |= insEncodeReg_Rt(id->idReg1()); // ttttt
9247 }
9248 code |= insEncodeExtend(id->idInsOpt()); // ooo
9249 code |= insEncodeReg_Rn(id->idReg2()); // nnnnn
9250 if (id->idIsLclVar())
9251 {
9252 code |= insEncodeReg_Rm(codeGen->rsGetRsvdReg()); // mmmmm
9253 }
9254 else
9255 {
9256 code |= insEncodeReg3Scale(id->idReg3Scaled()); // S
9257 code |= insEncodeReg_Rm(id->idReg3()); // mmmmm
9258 }
9259 dst += emitOutput_Instr(dst, code);
9260 break;
9261
9262 case IF_LS_3B: // LS_3B X............... .aaaaannnnnddddd Rd Ra Rn
9263 assert(insOptsNone(id->idInsOpt()));
9264 code = emitInsCode(ins, fmt);
9265 // Is the target a vector register?
9266 if (isVectorRegister(id->idReg1()))
9267 {
9268 code &= 0x3FFFFFFF; // clear the size bits
9269 code |= insEncodeDatasizeVPLS(code, id->idOpSize()); // XX
9270 code |= insEncodeReg_Vt(id->idReg1()); // ttttt
9271 code |= insEncodeReg_Va(id->idReg2()); // aaaaa
9272 }
9273 else
9274 {
9275 code |= insEncodeDatasize(id->idOpSize()); // X
9276 code |= insEncodeReg_Rt(id->idReg1()); // ttttt
9277 code |= insEncodeReg_Ra(id->idReg2()); // aaaaa
9278 }
9279 code |= insEncodeReg_Rn(id->idReg3()); // nnnnn
9280 dst += emitOutput_Instr(dst, code);
9281 break;
9282
9283 case IF_LS_3C: // LS_3C X......PP.iiiiii iaaaaannnnnddddd Rd Ra Rn imm(im7,sh)
9284 assert(insOptsNone(id->idInsOpt()) || insOptsIndexed(id->idInsOpt()));
9285 imm = emitGetInsSC(id);
9286 assert((imm >= -64) && (imm <= 63)); // signed 7 bits
9287 imm &= 0x7f; // force into unsigned 7 bit representation
9288 code = emitInsCode(ins, fmt);
9289 // Is the target a vector register?
9290 if (isVectorRegister(id->idReg1()))
9291 {
9292 code &= 0x3FFFFFFF; // clear the size bits
9293 code |= insEncodeDatasizeVPLS(code, id->idOpSize()); // XX
9294 code |= insEncodeReg_Vt(id->idReg1()); // ttttt
9295 code |= insEncodeReg_Va(id->idReg2()); // aaaaa
9296 }
9297 else
9298 {
9299 code |= insEncodeDatasize(id->idOpSize()); // X
9300 code |= insEncodeReg_Rt(id->idReg1()); // ttttt
9301 code |= insEncodeReg_Ra(id->idReg2()); // aaaaa
9302 }
9303 code |= insEncodePairIndexedOpt(ins, id->idInsOpt()); // PP
9304 code |= ((code_t)imm << 15); // iiiiiiiii
9305 code |= insEncodeReg_Rn(id->idReg3()); // nnnnn
9306 dst += emitOutput_Instr(dst, code);
9307 break;
9308
9309 case IF_LS_3D: // LS_3D .X.......X.mmmmm ......nnnnnttttt Wm Rt Rn
9310 code = emitInsCode(ins, fmt);
9311 // Arm64 store exclusive unpredictable cases
9312 assert(id->idReg1() != id->idReg2());
9313 assert(id->idReg1() != id->idReg3());
9314 code |= insEncodeDatasizeLS(code, id->idOpSize()); // X
9315 code |= insEncodeReg_Rm(id->idReg1()); // mmmmm
9316 code |= insEncodeReg_Rt(id->idReg2()); // ttttt
9317 code |= insEncodeReg_Rn(id->idReg3()); // nnnnn
9318 dst += emitOutput_Instr(dst, code);
9319 break;
9320
9321 case IF_LS_3E: // LS_3E .X.........mmmmm ......nnnnnttttt Rm Rt Rn ARMv8.1 LSE Atomics
9322 code = emitInsCode(ins, fmt);
9323 code |= insEncodeDatasizeLS(code, id->idOpSize()); // X
9324 code |= insEncodeReg_Rm(id->idReg1()); // mmmmm
9325 code |= insEncodeReg_Rt(id->idReg2()); // ttttt
9326 code |= insEncodeReg_Rn(id->idReg3()); // nnnnn
9327 dst += emitOutput_Instr(dst, code);
9328 break;
9329
9330 case IF_DI_1A: // DI_1A X.......shiiiiii iiiiiinnnnn..... Rn imm(i12,sh)
9331 assert(insOptsNone(id->idInsOpt()) || insOptsLSL12(id->idInsOpt()));
9332 imm = emitGetInsSC(id);
9333 assert(isValidUimm12(imm));
9334 code = emitInsCode(ins, fmt);
9335 code |= insEncodeDatasize(id->idOpSize()); // X
9336 code |= insEncodeShiftImm12(id->idInsOpt()); // sh
9337 code |= ((code_t)imm << 10); // iiiiiiiiiiii
9338 code |= insEncodeReg_Rn(id->idReg1()); // nnnnn
9339 dst += emitOutput_Instr(dst, code);
9340 break;
9341
9342 case IF_DI_1B: // DI_1B X........hwiiiii iiiiiiiiiiiddddd Rd imm(i16,hw)
9343 imm = emitGetInsSC(id);
9344 assert(isValidImmHWVal(imm, id->idOpSize()));
9345 code = emitInsCode(ins, fmt);
9346 code |= insEncodeDatasize(id->idOpSize()); // X
9347 code |= ((code_t)imm << 5); // hwiiiii iiiiiiiiiii
9348 code |= insEncodeReg_Rd(id->idReg1()); // ddddd
9349 dst += emitOutput_Instr(dst, code);
9350 break;
9351
9352 case IF_DI_1C: // DI_1C X........Nrrrrrr ssssssnnnnn..... Rn imm(N,r,s)
9353 imm = emitGetInsSC(id);
9354 assert(isValidImmNRS(imm, id->idOpSize()));
9355 code = emitInsCode(ins, fmt);
9356 code |= ((code_t)imm << 10); // Nrrrrrrssssss
9357 code |= insEncodeDatasize(id->idOpSize()); // X
9358 code |= insEncodeReg_Rn(id->idReg1()); // nnnnn
9359 dst += emitOutput_Instr(dst, code);
9360 break;
9361
9362 case IF_DI_1D: // DI_1D X........Nrrrrrr ssssss.....ddddd Rd imm(N,r,s)
9363 imm = emitGetInsSC(id);
9364 assert(isValidImmNRS(imm, id->idOpSize()));
9365 code = emitInsCode(ins, fmt);
9366 code |= ((code_t)imm << 10); // Nrrrrrrssssss
9367 code |= insEncodeDatasize(id->idOpSize()); // X
9368 code |= insEncodeReg_Rd(id->idReg1()); // ddddd
9369 dst += emitOutput_Instr(dst, code);
9370 break;
9371
9372 case IF_DI_1E: // DI_1E .ii.....iiiiiiii iiiiiiiiiiiddddd Rd simm21
9373 case IF_LARGEADR:
9374 assert(insOptsNone(id->idInsOpt()));
9375 if (id->idIsReloc())
9376 {
9377 code = emitInsCode(ins, fmt);
9378 code |= insEncodeReg_Rd(id->idReg1()); // ddddd
9379 dst += emitOutput_Instr(dst, code);
9380 emitRecordRelocation(odst, id->idAddr()->iiaAddr, IMAGE_REL_ARM64_PAGEBASE_REL21);
9381 }
9382 else
9383 {
9384 // Local jmp/load case which does not need a relocation.
9385 assert(id->idIsBound());
9386 dst = emitOutputLJ(ig, dst, id);
9387 }
9388 sz = sizeof(instrDescJmp);
9389 break;
9390
9391 case IF_DI_1F: // DI_1F X..........iiiii cccc..nnnnn.nzcv Rn imm5 nzcv cond
9392 imm = emitGetInsSC(id);
9393 assert(isValidImmCondFlagsImm5(imm));
9394 {
9395 condFlagsImm cfi;
9396 cfi.immCFVal = (unsigned)imm;
9397 code = emitInsCode(ins, fmt);
9398 code |= insEncodeDatasize(id->idOpSize()); // X
9399 code |= insEncodeReg_Rn(id->idReg1()); // nnnnn
9400 code |= ((code_t)cfi.imm5 << 16); // iiiii
9401 code |= insEncodeFlags(cfi.flags); // nzcv
9402 code |= insEncodeCond(cfi.cond); // cccc
9403 dst += emitOutput_Instr(dst, code);
9404 }
9405 break;
9406
9407 case IF_DI_2A: // DI_2A X.......shiiiiii iiiiiinnnnnddddd Rd Rn imm(i12,sh)
9408 assert(insOptsNone(id->idInsOpt()) || insOptsLSL12(id->idInsOpt()));
9409 imm = emitGetInsSC(id);
9410 assert(isValidUimm12(imm));
9411 code = emitInsCode(ins, fmt);
9412 code |= insEncodeDatasize(id->idOpSize()); // X
9413 code |= insEncodeShiftImm12(id->idInsOpt()); // sh
9414 code |= ((code_t)imm << 10); // iiiiiiiiiiii
9415 code |= insEncodeReg_Rd(id->idReg1()); // ddddd
9416 code |= insEncodeReg_Rn(id->idReg2()); // nnnnn
9417 dst += emitOutput_Instr(dst, code);
9418
9419 if (id->idIsReloc())
9420 {
9421 assert(sz == sizeof(instrDesc));
9422 assert(id->idAddr()->iiaAddr != nullptr);
9423 emitRecordRelocation(odst, id->idAddr()->iiaAddr, IMAGE_REL_ARM64_PAGEOFFSET_12A);
9424 }
9425 break;
9426
9427 case IF_DI_2B: // DI_2B X.........Xnnnnn ssssssnnnnnddddd Rd Rn imm(0-63)
9428 code = emitInsCode(ins, fmt);
9429 imm = emitGetInsSC(id);
9430 assert(isValidImmShift(imm, id->idOpSize()));
9431 code |= insEncodeDatasizeBF(code, id->idOpSize()); // X........X
9432 code |= insEncodeReg_Rd(id->idReg1()); // ddddd
9433 code |= insEncodeReg_Rn(id->idReg2()); // nnnnn
9434 code |= insEncodeReg_Rm(id->idReg2()); // Reg2 also in mmmmm
9435 code |= insEncodeShiftCount(imm, id->idOpSize()); // ssssss
9436 dst += emitOutput_Instr(dst, code);
9437 break;
9438
9439 case IF_DI_2C: // DI_2C X........Nrrrrrr ssssssnnnnnddddd Rd Rn imm(N,r,s)
9440 imm = emitGetInsSC(id);
9441 assert(isValidImmNRS(imm, id->idOpSize()));
9442 code = emitInsCode(ins, fmt);
9443 code |= ((code_t)imm << 10); // Nrrrrrrssssss
9444 code |= insEncodeDatasize(id->idOpSize()); // X
9445 code |= insEncodeReg_Rd(id->idReg1()); // ddddd
9446 code |= insEncodeReg_Rn(id->idReg2()); // nnnnn
9447 dst += emitOutput_Instr(dst, code);
9448 break;
9449
9450 case IF_DI_2D: // DI_2D X........Nrrrrrr ssssssnnnnnddddd Rd Rn imr, imms (N,r,s)
9451 if (ins == INS_asr || ins == INS_lsl || ins == INS_lsr)
9452 {
9453 imm = emitGetInsSC(id);
9454 assert(isValidImmShift(imm, id->idOpSize()));
9455
9456 // Shift immediates are aliases of the SBFM/UBFM instructions
9457 // that actually take 2 registers and 2 constants,
9458 // Since we stored the shift immediate value
9459 // we need to calculate the N,R and S values here.
9460
9461 bitMaskImm bmi;
9462 bmi.immNRS = 0;
9463
9464 bmi.immN = (size == EA_8BYTE) ? 1 : 0;
9465 bmi.immR = imm;
9466 bmi.immS = (size == EA_8BYTE) ? 0x3f : 0x1f;
9467
9468 // immR and immS are now set correctly for INS_asr and INS_lsr
9469 // but for INS_lsl we have to adjust the values for immR and immS
9470 //
9471 if (ins == INS_lsl)
9472 {
9473 bmi.immR = -imm & bmi.immS;
9474 bmi.immS = bmi.immS - imm;
9475 }
9476
9477 // setup imm with the proper 13 bit value N:R:S
9478 //
9479 imm = bmi.immNRS;
9480 }
9481 else
9482 {
9483 // The other instructions have already have encoded N,R and S values
9484 imm = emitGetInsSC(id);
9485 }
9486 assert(isValidImmNRS(imm, id->idOpSize()));
9487
9488 code = emitInsCode(ins, fmt);
9489 code |= ((code_t)imm << 10); // Nrrrrrrssssss
9490 code |= insEncodeDatasize(id->idOpSize()); // X
9491 code |= insEncodeReg_Rd(id->idReg1()); // ddddd
9492 code |= insEncodeReg_Rn(id->idReg2()); // nnnnn
9493 dst += emitOutput_Instr(dst, code);
9494 break;
9495
9496 case IF_DR_1D: // DR_1D X............... cccc.......ddddd Rd cond
9497 imm = emitGetInsSC(id);
9498 assert(isValidImmCond(imm));
9499 {
9500 condFlagsImm cfi;
9501 cfi.immCFVal = (unsigned)imm;
9502 code = emitInsCode(ins, fmt);
9503 code |= insEncodeDatasize(id->idOpSize()); // X
9504 code |= insEncodeReg_Rd(id->idReg1()); // ddddd
9505 code |= insEncodeInvertedCond(cfi.cond); // cccc
9506 dst += emitOutput_Instr(dst, code);
9507 }
9508 break;
9509
9510 case IF_DR_2A: // DR_2A X..........mmmmm ......nnnnn..... Rn Rm
9511 assert(insOptsNone(id->idInsOpt()));
9512 code = emitInsCode(ins, fmt);
9513 code |= insEncodeDatasize(id->idOpSize()); // X
9514 code |= insEncodeReg_Rn(id->idReg1()); // nnnnn
9515 code |= insEncodeReg_Rm(id->idReg2()); // mmmmm
9516 dst += emitOutput_Instr(dst, code);
9517 break;
9518
9519 case IF_DR_2B: // DR_2B X.......sh.mmmmm ssssssnnnnn..... Rn Rm {LSL,LSR,ASR,ROR} imm(0-63)
9520 code = emitInsCode(ins, fmt);
9521 imm = emitGetInsSC(id);
9522 assert(isValidImmShift(imm, id->idOpSize()));
9523 code |= insEncodeDatasize(id->idOpSize()); // X
9524 code |= insEncodeShiftType(id->idInsOpt()); // sh
9525 code |= insEncodeShiftCount(imm, id->idOpSize()); // ssssss
9526 code |= insEncodeReg_Rn(id->idReg1()); // nnnnn
9527 code |= insEncodeReg_Rm(id->idReg2()); // mmmmm
9528 dst += emitOutput_Instr(dst, code);
9529 break;
9530
9531 case IF_DR_2C: // DR_2C X..........mmmmm ooosssnnnnn..... Rn Rm ext(Rm) LSL imm(0-4)
9532 code = emitInsCode(ins, fmt);
9533 imm = emitGetInsSC(id);
9534 assert((imm >= 0) && (imm <= 4)); // imm [0..4]
9535 code |= insEncodeDatasize(id->idOpSize()); // X
9536 code |= insEncodeExtend(id->idInsOpt()); // ooo
9537 code |= insEncodeExtendScale(imm); // sss
9538 code |= insEncodeReg_Rn(id->idReg1()); // nnnnn
9539 code |= insEncodeReg_Rm(id->idReg2()); // mmmmm
9540 dst += emitOutput_Instr(dst, code);
9541 break;
9542
9543 case IF_DR_2D: // DR_2D X..........nnnnn cccc..nnnnnddddd Rd Rn cond
9544 imm = emitGetInsSC(id);
9545 assert(isValidImmCond(imm));
9546 {
9547 condFlagsImm cfi;
9548 cfi.immCFVal = (unsigned)imm;
9549 code = emitInsCode(ins, fmt);
9550 code |= insEncodeDatasize(id->idOpSize()); // X
9551 code |= insEncodeReg_Rd(id->idReg1()); // ddddd
9552 code |= insEncodeReg_Rn(id->idReg2()); // nnnnn
9553 code |= insEncodeReg_Rm(id->idReg2()); // mmmmm
9554 code |= insEncodeInvertedCond(cfi.cond); // cccc
9555 dst += emitOutput_Instr(dst, code);
9556 }
9557 break;
9558
9559 case IF_DR_2E: // DR_2E X..........mmmmm ...........ddddd Rd Rm
9560 code = emitInsCode(ins, fmt);
9561 code |= insEncodeDatasize(id->idOpSize()); // X
9562 code |= insEncodeReg_Rd(id->idReg1()); // ddddd
9563 code |= insEncodeReg_Rm(id->idReg2()); // mmmmm
9564 dst += emitOutput_Instr(dst, code);
9565 break;
9566
9567 case IF_DR_2F: // DR_2F X.......sh.mmmmm ssssss.....ddddd Rd Rm {LSL,LSR,ASR} imm(0-63)
9568 code = emitInsCode(ins, fmt);
9569 imm = emitGetInsSC(id);
9570 assert(isValidImmShift(imm, id->idOpSize()));
9571 code |= insEncodeDatasize(id->idOpSize()); // X
9572 code |= insEncodeShiftType(id->idInsOpt()); // sh
9573 code |= insEncodeShiftCount(imm, id->idOpSize()); // ssssss
9574 code |= insEncodeReg_Rd(id->idReg1()); // ddddd
9575 code |= insEncodeReg_Rm(id->idReg2()); // mmmmm
9576 dst += emitOutput_Instr(dst, code);
9577 break;
9578
9579 case IF_DR_2G: // DR_2G X............... .....xnnnnnddddd Rd Rn
9580 code = emitInsCode(ins, fmt);
9581 code |= insEncodeDatasize(id->idOpSize()); // X
9582 if (ins == INS_rev)
9583 {
9584 if (size == EA_8BYTE)
9585 {
9586 code |= 0x00000400; // x - bit at location 10
9587 }
9588 }
9589 code |= insEncodeReg_Rd(id->idReg1()); // ddddd
9590 code |= insEncodeReg_Rn(id->idReg2()); // nnnnn
9591 dst += emitOutput_Instr(dst, code);
9592 break;
9593
9594 case IF_DR_2H: // DR_2H X........X...... ......nnnnnddddd Rd Rn
9595 code = emitInsCode(ins, fmt);
9596 code |= insEncodeDatasizeBF(code, id->idOpSize()); // X........X
9597 code |= insEncodeReg_Rd(id->idReg1()); // ddddd
9598 code |= insEncodeReg_Rn(id->idReg2()); // nnnnn
9599 dst += emitOutput_Instr(dst, code);
9600 break;
9601
9602 case IF_DR_2I: // DR_2I X..........mmmmm cccc..nnnnn.nzcv Rn Rm nzcv cond
9603 imm = emitGetInsSC(id);
9604 assert(isValidImmCondFlags(imm));
9605 {
9606 condFlagsImm cfi;
9607 cfi.immCFVal = (unsigned)imm;
9608 code = emitInsCode(ins, fmt);
9609 code |= insEncodeDatasize(id->idOpSize()); // X
9610 code |= insEncodeReg_Rn(id->idReg1()); // nnnnn
9611 code |= insEncodeReg_Rm(id->idReg2()); // mmmmm
9612 code |= insEncodeFlags(cfi.flags); // nzcv
9613 code |= insEncodeCond(cfi.cond); // cccc
9614 dst += emitOutput_Instr(dst, code);
9615 }
9616 break;
9617
9618 case IF_DR_2J: // DR_2J ................ ......nnnnnddddd Sd Sn (sha1h)
9619 code = emitInsCode(ins, fmt);
9620 code |= insEncodeReg_Vd(id->idReg1()); // ddddd
9621 code |= insEncodeReg_Vn(id->idReg2()); // nnnnn
9622 dst += emitOutput_Instr(dst, code);
9623 break;
9624
9625 case IF_DR_3A: // DR_3A X..........mmmmm ......nnnnnmmmmm Rd Rn Rm
9626 code = emitInsCode(ins, fmt);
9627 code |= insEncodeDatasize(id->idOpSize()); // X
9628 code |= insEncodeReg_Rd(id->idReg1()); // ddddd
9629 code |= insEncodeReg_Rn(id->idReg2()); // nnnnn
9630 if (id->idIsLclVar())
9631 {
9632 code |= insEncodeReg_Rm(codeGen->rsGetRsvdReg()); // mmmmm
9633 }
9634 else
9635 {
9636 code |= insEncodeReg_Rm(id->idReg3()); // mmmmm
9637 }
9638 dst += emitOutput_Instr(dst, code);
9639 break;
9640
9641 case IF_DR_3B: // DR_3B X.......sh.mmmmm ssssssnnnnnddddd Rd Rn Rm {LSL,LSR,ASR} imm(0-63)
9642 code = emitInsCode(ins, fmt);
9643 imm = emitGetInsSC(id);
9644 assert(isValidImmShift(imm, id->idOpSize()));
9645 code |= insEncodeDatasize(id->idOpSize()); // X
9646 code |= insEncodeReg_Rd(id->idReg1()); // ddddd
9647 code |= insEncodeReg_Rn(id->idReg2()); // nnnnn
9648 code |= insEncodeReg_Rm(id->idReg3()); // mmmmm
9649 code |= insEncodeShiftType(id->idInsOpt()); // sh
9650 code |= insEncodeShiftCount(imm, id->idOpSize()); // ssssss
9651 dst += emitOutput_Instr(dst, code);
9652 break;
9653
9654 case IF_DR_3C: // DR_3C X..........mmmmm ooosssnnnnnddddd Rd Rn Rm ext(Rm) LSL imm(0-4)
9655 code = emitInsCode(ins, fmt);
9656 imm = emitGetInsSC(id);
9657 assert((imm >= 0) && (imm <= 4)); // imm [0..4]
9658 code |= insEncodeDatasize(id->idOpSize()); // X
9659 code |= insEncodeExtend(id->idInsOpt()); // ooo
9660 code |= insEncodeExtendScale(imm); // sss
9661 code |= insEncodeReg_Rd(id->idReg1()); // ddddd
9662 code |= insEncodeReg_Rn(id->idReg2()); // nnnnn
9663 code |= insEncodeReg_Rm(id->idReg3()); // mmmmm
9664 dst += emitOutput_Instr(dst, code);
9665 break;
9666
9667 case IF_DR_3D: // DR_3D X..........mmmmm cccc..nnnnnddddd Rd Rn Rm cond
9668 imm = emitGetInsSC(id);
9669 assert(isValidImmCond(imm));
9670 {
9671 condFlagsImm cfi;
9672 cfi.immCFVal = (unsigned)imm;
9673 code = emitInsCode(ins, fmt);
9674 code |= insEncodeDatasize(id->idOpSize()); // X
9675 code |= insEncodeReg_Rd(id->idReg1()); // ddddd
9676 code |= insEncodeReg_Rn(id->idReg2()); // nnnnn
9677 code |= insEncodeReg_Rm(id->idReg3()); // mmmmm
9678 code |= insEncodeCond(cfi.cond); // cccc
9679 dst += emitOutput_Instr(dst, code);
9680 }
9681 break;
9682
9683 case IF_DR_3E: // DR_3E X........X.mmmmm ssssssnnnnnddddd Rd Rn Rm imm(0-63)
9684 code = emitInsCode(ins, fmt);
9685 imm = emitGetInsSC(id);
9686 assert(isValidImmShift(imm, id->idOpSize()));
9687 code |= insEncodeDatasizeBF(code, id->idOpSize()); // X........X
9688 code |= insEncodeReg_Rd(id->idReg1()); // ddddd
9689 code |= insEncodeReg_Rn(id->idReg2()); // nnnnn
9690 code |= insEncodeReg_Rm(id->idReg3()); // mmmmm
9691 code |= insEncodeShiftCount(imm, id->idOpSize()); // ssssss
9692 dst += emitOutput_Instr(dst, code);
9693 break;
9694
9695 case IF_DR_4A: // DR_4A X..........mmmmm .aaaaannnnnmmmmm Rd Rn Rm Ra
9696 code = emitInsCode(ins, fmt);
9697 code |= insEncodeDatasize(id->idOpSize()); // X
9698 code |= insEncodeReg_Rd(id->idReg1()); // ddddd
9699 code |= insEncodeReg_Rn(id->idReg2()); // nnnnn
9700 code |= insEncodeReg_Rm(id->idReg3()); // mmmmm
9701 code |= insEncodeReg_Ra(id->idReg4()); // aaaaa
9702 dst += emitOutput_Instr(dst, code);
9703 break;
9704
9705 case IF_DV_1A: // DV_1A .........X.iiiii iii........ddddd Vd imm8 (fmov - immediate scalar)
9706 imm = emitGetInsSC(id);
9707 elemsize = id->idOpSize();
9708 code = emitInsCode(ins, fmt);
9709 code |= insEncodeFloatElemsize(elemsize); // X
9710 code |= ((code_t)imm << 13); // iiiii iii
9711 code |= insEncodeReg_Vd(id->idReg1()); // ddddd
9712 dst += emitOutput_Instr(dst, code);
9713 break;
9714
9715 case IF_DV_1B: // DV_1B .QX..........iii cmod..iiiiiddddd Vd imm8 (immediate vector)
9716 imm = emitGetInsSC(id) & 0x0ff;
9717 immShift = (emitGetInsSC(id) & 0x700) >> 8;
9718 elemsize = optGetElemsize(id->idInsOpt());
9719 cmode = 0;
9720 switch (elemsize)
9721 { // cmode
9722 case EA_1BYTE:
9723 cmode = 0xE; // 1110
9724 break;
9725 case EA_2BYTE:
9726 cmode = 0x8;
9727 cmode |= (immShift << 1); // 10x0
9728 break;
9729 case EA_4BYTE:
9730 if (immShift < 4)
9731 {
9732 cmode = 0x0;
9733 cmode |= (immShift << 1); // 0xx0
9734 }
9735 else // MSL
9736 {
9737 cmode = 0xC;
9738 if (immShift & 2)
9739 cmode |= 1; // 110x
9740 }
9741 break;
9742 case EA_8BYTE:
9743 cmode = 0xE; // 1110
9744 break;
9745 default:
9746 unreached();
9747 break;
9748 }
9749
9750 code = emitInsCode(ins, fmt);
9751 code |= insEncodeVectorsize(id->idOpSize()); // Q
9752 if ((ins == INS_fmov) || (ins == INS_movi))
9753 {
9754 if (elemsize == EA_8BYTE)
9755 {
9756 code |= 0x20000000; // X
9757 }
9758 }
9759 if (ins != INS_fmov)
9760 {
9761 assert((cmode >= 0) && (cmode <= 0xF));
9762 code |= (cmode << 12); // cmod
9763 }
9764 code |= (((code_t)imm >> 5) << 16); // iii
9765 code |= (((code_t)imm & 0x1f) << 5); // iiiii
9766 code |= insEncodeReg_Vd(id->idReg1()); // ddddd
9767 dst += emitOutput_Instr(dst, code);
9768 break;
9769
9770 case IF_DV_1C: // DV_1C .........X...... ......nnnnn..... Vn #0.0 (fcmp - with zero)
9771 elemsize = id->idOpSize();
9772 code = emitInsCode(ins, fmt);
9773 code |= insEncodeFloatElemsize(elemsize); // X
9774 code |= insEncodeReg_Vn(id->idReg1()); // nnnnn
9775 dst += emitOutput_Instr(dst, code);
9776 break;
9777
9778 case IF_DV_2A: // DV_2A .Q.......X...... ......nnnnnddddd Vd Vn (fabs, fcvt - vector)
9779 elemsize = optGetElemsize(id->idInsOpt());
9780 code = emitInsCode(ins, fmt);
9781 code |= insEncodeVectorsize(id->idOpSize()); // Q
9782 code |= insEncodeFloatElemsize(elemsize); // X
9783 code |= insEncodeReg_Vd(id->idReg1()); // ddddd
9784 code |= insEncodeReg_Vn(id->idReg2()); // nnnnn
9785 dst += emitOutput_Instr(dst, code);
9786 break;
9787
9788 case IF_DV_2B: // DV_2B .Q.........iiiii ......nnnnnddddd Rd Vn[] (umov/smov - to general)
9789 elemsize = id->idOpSize();
9790 index = emitGetInsSC(id);
9791 datasize = (elemsize == EA_8BYTE) ? EA_16BYTE : EA_8BYTE;
9792 if (ins == INS_smov)
9793 {
9794 datasize = EA_16BYTE;
9795 }
9796 code = emitInsCode(ins, fmt);
9797 code |= insEncodeVectorsize(datasize); // Q
9798 code |= insEncodeVectorIndex(elemsize, index); // iiiii
9799 code |= insEncodeReg_Rd(id->idReg1()); // ddddd
9800 code |= insEncodeReg_Vn(id->idReg2()); // nnnnn
9801 dst += emitOutput_Instr(dst, code);
9802 break;
9803
9804 case IF_DV_2C: // DV_2C .Q.........iiiii ......nnnnnddddd Vd Rn (dup/ins - vector from general)
9805 if (ins == INS_dup)
9806 {
9807 datasize = id->idOpSize();
9808 elemsize = optGetElemsize(id->idInsOpt());
9809 index = 0;
9810 }
9811 else // INS_ins
9812 {
9813 datasize = EA_16BYTE;
9814 elemsize = id->idOpSize();
9815 index = emitGetInsSC(id);
9816 }
9817 code = emitInsCode(ins, fmt);
9818 code |= insEncodeVectorsize(datasize); // Q
9819 code |= insEncodeVectorIndex(elemsize, index); // iiiii
9820 code |= insEncodeReg_Vd(id->idReg1()); // ddddd
9821 code |= insEncodeReg_Rn(id->idReg2()); // nnnnn
9822 dst += emitOutput_Instr(dst, code);
9823 break;
9824
9825 case IF_DV_2D: // DV_2D .Q.........iiiii ......nnnnnddddd Vd Vn[] (dup - vector)
9826 index = emitGetInsSC(id);
9827 elemsize = optGetElemsize(id->idInsOpt());
9828 code = emitInsCode(ins, fmt);
9829 code |= insEncodeVectorsize(id->idOpSize()); // Q
9830 code |= insEncodeVectorIndex(elemsize, index); // iiiii
9831 code |= insEncodeReg_Vd(id->idReg1()); // ddddd
9832 code |= insEncodeReg_Vn(id->idReg2()); // nnnnn
9833 dst += emitOutput_Instr(dst, code);
9834 break;
9835
9836 case IF_DV_2E: // DV_2E ...........iiiii ......nnnnnddddd Vd Vn[] (dup - scalar)
9837 index = emitGetInsSC(id);
9838 elemsize = id->idOpSize();
9839 code = emitInsCode(ins, fmt);
9840 code |= insEncodeVectorIndex(elemsize, index); // iiiii
9841 code |= insEncodeReg_Vd(id->idReg1()); // ddddd
9842 code |= insEncodeReg_Vn(id->idReg2()); // nnnnn
9843 dst += emitOutput_Instr(dst, code);
9844 break;
9845
9846 case IF_DV_2F: // DV_2F ...........iiiii .jjjj.nnnnnddddd Vd[] Vn[] (ins - element)
9847 elemsize = id->idOpSize();
9848 imm = emitGetInsSC(id);
9849 index = (imm >> 4) & 0xf;
9850 index2 = imm & 0xf;
9851 code = emitInsCode(ins, fmt);
9852 code |= insEncodeVectorIndex(elemsize, index); // iiiii
9853 code |= insEncodeVectorIndex2(elemsize, index2); // jjjj
9854 code |= insEncodeReg_Vd(id->idReg1()); // ddddd
9855 code |= insEncodeReg_Vn(id->idReg2()); // nnnnn
9856 dst += emitOutput_Instr(dst, code);
9857 break;
9858
9859 case IF_DV_2G: // DV_2G .........X...... ......nnnnnddddd Vd Vn (fmov,fcvtXX - register)
9860 elemsize = id->idOpSize();
9861 code = emitInsCode(ins, fmt);
9862 code |= insEncodeFloatElemsize(elemsize); // X
9863 code |= insEncodeReg_Vd(id->idReg1()); // ddddd
9864 code |= insEncodeReg_Vn(id->idReg2()); // nnnnn
9865 dst += emitOutput_Instr(dst, code);
9866 break;
9867
9868 case IF_DV_2H: // DV_2H X........X...... ......nnnnnddddd Rd Vn (fmov - to general)
9869 elemsize = id->idOpSize();
9870 code = emitInsCode(ins, fmt);
9871 code |= insEncodeConvertOpt(fmt, id->idInsOpt()); // X X
9872 code |= insEncodeReg_Rd(id->idReg1()); // ddddd
9873 code |= insEncodeReg_Vn(id->idReg2()); // nnnnn
9874 dst += emitOutput_Instr(dst, code);
9875 break;
9876
9877 case IF_DV_2I: // DV_2I X........X...... ......nnnnnddddd Vd Rn (fmov - from general)
9878 elemsize = id->idOpSize();
9879 code = emitInsCode(ins, fmt);
9880 code |= insEncodeConvertOpt(fmt, id->idInsOpt()); // X X
9881 code |= insEncodeReg_Vd(id->idReg1()); // ddddd
9882 code |= insEncodeReg_Rn(id->idReg2()); // nnnnn
9883 dst += emitOutput_Instr(dst, code);
9884 break;
9885
9886 case IF_DV_2J: // DV_2J ........SS.....D D.....nnnnnddddd Vd Vn (fcvt)
9887 code = emitInsCode(ins, fmt);
9888 code |= insEncodeConvertOpt(fmt, id->idInsOpt()); // SS DD
9889 code |= insEncodeReg_Vd(id->idReg1()); // ddddd
9890 code |= insEncodeReg_Vn(id->idReg2()); // nnnnn
9891 dst += emitOutput_Instr(dst, code);
9892 break;
9893
9894 case IF_DV_2K: // DV_2K .........X.mmmmm ......nnnnn..... Vn Vm (fcmp)
9895 elemsize = id->idOpSize();
9896 code = emitInsCode(ins, fmt);
9897 code |= insEncodeFloatElemsize(elemsize); // X
9898 code |= insEncodeReg_Vn(id->idReg1()); // nnnnn
9899 code |= insEncodeReg_Vm(id->idReg2()); // mmmmm
9900 dst += emitOutput_Instr(dst, code);
9901 break;
9902
9903 case IF_DV_2L: // DV_2L ........XX...... ......nnnnnddddd Vd Vn (abs, neg - scalar)
9904 elemsize = id->idOpSize();
9905 code = emitInsCode(ins, fmt);
9906 code |= insEncodeElemsize(elemsize); // XX
9907 code |= insEncodeReg_Vd(id->idReg1()); // ddddd
9908 code |= insEncodeReg_Vn(id->idReg2()); // nnnnn
9909 dst += emitOutput_Instr(dst, code);
9910 break;
9911
9912 case IF_DV_2M: // DV_2M .Q......XX...... ......nnnnnddddd Vd Vn (abs, neg - vector)
9913 elemsize = optGetElemsize(id->idInsOpt());
9914 code = emitInsCode(ins, fmt);
9915 code |= insEncodeVectorsize(id->idOpSize()); // Q
9916 code |= insEncodeElemsize(elemsize); // XX
9917 code |= insEncodeReg_Vd(id->idReg1()); // ddddd
9918 code |= insEncodeReg_Vn(id->idReg2()); // nnnnn
9919 dst += emitOutput_Instr(dst, code);
9920 break;
9921
9922 case IF_DV_2N: // DV_2N .........iiiiiii ......nnnnnddddd Vd Vn imm (shift - scalar)
9923 imm = emitGetInsSC(id);
9924 code = emitInsCode(ins, fmt);
9925 code |= insEncodeVectorShift(EA_8BYTE, imm); // iiiiiii
9926 code |= insEncodeReg_Vd(id->idReg1()); // ddddd
9927 code |= insEncodeReg_Vn(id->idReg2()); // nnnnn
9928 dst += emitOutput_Instr(dst, code);
9929 break;
9930
9931 case IF_DV_2O: // DV_2O .Q.......iiiiiii ......nnnnnddddd Vd Vn imm (shift - vector)
9932 imm = emitGetInsSC(id);
9933 elemsize = optGetElemsize(id->idInsOpt());
9934 code = emitInsCode(ins, fmt);
9935 code |= insEncodeVectorsize(id->idOpSize()); // Q
9936 code |= insEncodeVectorShift(elemsize, imm); // iiiiiii
9937 code |= insEncodeReg_Vd(id->idReg1()); // ddddd
9938 code |= insEncodeReg_Vn(id->idReg2()); // nnnnn
9939 dst += emitOutput_Instr(dst, code);
9940 break;
9941
9942 case IF_DV_2P: // DV_2P ............... ......nnnnnddddd Vd Vn (aes*, sha1su1)
9943 elemsize = optGetElemsize(id->idInsOpt());
9944 code = emitInsCode(ins, fmt);
9945 code |= insEncodeReg_Vd(id->idReg1()); // ddddd
9946 code |= insEncodeReg_Vn(id->idReg2()); // nnnnn
9947 dst += emitOutput_Instr(dst, code);
9948 break;
9949
9950 case IF_DV_3A: // DV_3A .Q......XX.mmmmm ......nnnnnddddd Vd Vn Vm (vector)
9951 code = emitInsCode(ins, fmt);
9952 elemsize = optGetElemsize(id->idInsOpt());
9953 code |= insEncodeVectorsize(id->idOpSize()); // Q
9954 code |= insEncodeElemsize(elemsize); // XX
9955 code |= insEncodeReg_Vd(id->idReg1()); // ddddd
9956 code |= insEncodeReg_Vn(id->idReg2()); // nnnnn
9957 code |= insEncodeReg_Vm(id->idReg3()); // mmmmm
9958 dst += emitOutput_Instr(dst, code);
9959 break;
9960
9961 case IF_DV_3AI: // DV_3AI .Q......XXLMmmmm ....H.nnnnnddddd Vd Vn Vm[] (vector)
9962 code = emitInsCode(ins, fmt);
9963 imm = emitGetInsSC(id);
9964 elemsize = optGetElemsize(id->idInsOpt());
9965 assert(isValidVectorIndex(EA_16BYTE, elemsize, imm));
9966 code |= insEncodeVectorsize(id->idOpSize()); // Q
9967 code |= insEncodeElemsize(elemsize); // XX
9968 code |= insEncodeVectorIndexLMH(elemsize, imm); // LM H
9969 code |= insEncodeReg_Vd(id->idReg1()); // ddddd
9970 code |= insEncodeReg_Vn(id->idReg2()); // nnnnn
9971 code |= insEncodeReg_Vm(id->idReg3()); // mmmmm
9972 dst += emitOutput_Instr(dst, code);
9973 break;
9974
9975 case IF_DV_3B: // DV_3B .Q.......X.mmmmm ......nnnnnddddd Vd Vn Vm (vector)
9976 code = emitInsCode(ins, fmt);
9977 elemsize = optGetElemsize(id->idInsOpt());
9978 code |= insEncodeVectorsize(id->idOpSize()); // Q
9979 code |= insEncodeFloatElemsize(elemsize); // X
9980 code |= insEncodeReg_Vd(id->idReg1()); // ddddd
9981 code |= insEncodeReg_Vn(id->idReg2()); // nnnnn
9982 code |= insEncodeReg_Vm(id->idReg3()); // mmmmm
9983 dst += emitOutput_Instr(dst, code);
9984 break;
9985
9986 case IF_DV_3BI: // DV_3BI .Q.......XLmmmmm ....H.nnnnnddddd Vd Vn Vm[] (vector by elem)
9987 code = emitInsCode(ins, fmt);
9988 imm = emitGetInsSC(id);
9989 elemsize = optGetElemsize(id->idInsOpt());
9990 assert(isValidVectorIndex(id->idOpSize(), elemsize, imm));
9991 code |= insEncodeVectorsize(id->idOpSize()); // Q
9992 code |= insEncodeFloatElemsize(elemsize); // X
9993 code |= insEncodeFloatIndex(elemsize, imm); // L H
9994 code |= insEncodeReg_Vd(id->idReg1()); // ddddd
9995 code |= insEncodeReg_Vn(id->idReg2()); // nnnnn
9996 code |= insEncodeReg_Vm(id->idReg3()); // mmmmm
9997 dst += emitOutput_Instr(dst, code);
9998 break;
9999
10000 case IF_DV_3C: // DV_3C .Q.........mmmmm ......nnnnnddddd Vd Vn Vm (vector)
10001 code = emitInsCode(ins, fmt);
10002 code |= insEncodeVectorsize(id->idOpSize()); // Q
10003 code |= insEncodeReg_Vd(id->idReg1()); // ddddd
10004 code |= insEncodeReg_Vn(id->idReg2()); // nnnnn
10005 code |= insEncodeReg_Vm(id->idReg3()); // mmmmm
10006 dst += emitOutput_Instr(dst, code);
10007 break;
10008
10009 case IF_DV_3D: // DV_3D .........X.mmmmm ......nnnnnddddd Vd Vn Vm (scalar)
10010 code = emitInsCode(ins, fmt);
10011 code |= insEncodeFloatElemsize(id->idOpSize()); // X
10012 code |= insEncodeReg_Vd(id->idReg1()); // ddddd
10013 code |= insEncodeReg_Vn(id->idReg2()); // nnnnn
10014 code |= insEncodeReg_Vm(id->idReg3()); // mmmmm
10015 dst += emitOutput_Instr(dst, code);
10016 break;
10017
10018 case IF_DV_3DI: // DV_3DI .........XLmmmmm ....H.nnnnnddddd Vd Vn Vm[] (scalar by elem)
10019 code = emitInsCode(ins, fmt);
10020 imm = emitGetInsSC(id);
10021 elemsize = id->idOpSize();
10022 assert(isValidVectorIndex(EA_16BYTE, elemsize, imm));
10023 code |= insEncodeFloatElemsize(elemsize); // X
10024 code |= insEncodeFloatIndex(elemsize, imm); // L H
10025 code |= insEncodeReg_Vd(id->idReg1()); // ddddd
10026 code |= insEncodeReg_Vn(id->idReg2()); // nnnnn
10027 code |= insEncodeReg_Vm(id->idReg3()); // mmmmm
10028 dst += emitOutput_Instr(dst, code);
10029 break;
10030
10031 case IF_DV_3E: // DV_3E ...........mmmmm ......nnnnnddddd Vd Vn Vm (scalar)
10032 case IF_DV_3F: // DV_3F ...........mmmmm ......nnnnnddddd Vd Vn Vm (vector) - source dest regs overlap
10033 code = emitInsCode(ins, fmt);
10034 code |= insEncodeReg_Vd(id->idReg1()); // ddddd
10035 code |= insEncodeReg_Vn(id->idReg2()); // nnnnn
10036 code |= insEncodeReg_Vm(id->idReg3()); // mmmmm
10037 dst += emitOutput_Instr(dst, code);
10038 break;
10039
10040 case IF_DV_4A: // DV_4A .........X.mmmmm .aaaaannnnnddddd Vd Va Vn Vm (scalar)
10041 code = emitInsCode(ins, fmt);
10042 elemsize = id->idOpSize();
10043 code |= insEncodeFloatElemsize(elemsize); // X
10044 code |= insEncodeReg_Vd(id->idReg1()); // ddddd
10045 code |= insEncodeReg_Vn(id->idReg2()); // nnnnn
10046 code |= insEncodeReg_Vm(id->idReg3()); // mmmmm
10047 code |= insEncodeReg_Va(id->idReg4()); // aaaaa
10048 dst += emitOutput_Instr(dst, code);
10049 break;
10050
10051 case IF_SN_0A: // SN_0A ................ ................
10052 code = emitInsCode(ins, fmt);
10053 dst += emitOutput_Instr(dst, code);
10054 break;
10055
10056 case IF_SI_0A: // SI_0A ...........iiiii iiiiiiiiiii..... imm16
10057 imm = emitGetInsSC(id);
10058 assert(isValidUimm16(imm));
10059 code = emitInsCode(ins, fmt);
10060 code |= ((code_t)imm << 5); // iiiii iiiiiiiiiii
10061 dst += emitOutput_Instr(dst, code);
10062 break;
10063
10064 case IF_SI_0B: // SI_0B ................ ....bbbb........ imm4 - barrier
10065 imm = emitGetInsSC(id);
10066 assert((imm >= 0) && (imm <= 15));
10067 code = emitInsCode(ins, fmt);
10068 code |= ((code_t)imm << 8); // bbbb
10069 dst += emitOutput_Instr(dst, code);
10070 break;
10071
10072 default:
10073 assert(!"Unexpected format");
10074 break;
10075 }
10076
10077 // Determine if any registers now hold GC refs, or whether a register that was overwritten held a GC ref.
10078 // We assume here that "id->idGCref()" is not GC_NONE only if the instruction described by "id" writes a
10079 // GC ref to register "id->idReg1()". (It may, apparently, also not be GC_NONE in other cases, such as
10080 // for stores, but we ignore those cases here.)
10081 if (emitInsMayWriteToGCReg(id)) // True if "id->idIns()" writes to a register than can hold GC ref.
10082 {
10083 // We assume that "idReg1" is the primary destination register for all instructions
10084 if (id->idGCref() != GCT_NONE)
10085 {
10086 emitGCregLiveUpd(id->idGCref(), id->idReg1(), dst);
10087 }
10088 else
10089 {
10090 emitGCregDeadUpd(id->idReg1(), dst);
10091 }
10092
10093 if (emitInsMayWriteMultipleRegs(id))
10094 {
10095 // INS_ldp etc...
10096 // "idReg2" is the secondary destination register
10097 if (id->idGCrefReg2() != GCT_NONE)
10098 {
10099 emitGCregLiveUpd(id->idGCrefReg2(), id->idReg2(), dst);
10100 }
10101 else
10102 {
10103 emitGCregDeadUpd(id->idReg2(), dst);
10104 }
10105 }
10106 }
10107
10108 // Now we determine if the instruction has written to a (local variable) stack location, and either written a GC
10109 // ref or overwritten one.
10110 if (emitInsWritesToLclVarStackLoc(id) || emitInsWritesToLclVarStackLocPair(id))
10111 {
10112 int varNum = id->idAddr()->iiaLclVar.lvaVarNum();
10113 unsigned ofs = AlignDown(id->idAddr()->iiaLclVar.lvaOffset(), TARGET_POINTER_SIZE);
10114 bool FPbased;
10115 int adr = emitComp->lvaFrameAddress(varNum, &FPbased);
10116 if (id->idGCref() != GCT_NONE)
10117 {
10118 emitGCvarLiveUpd(adr + ofs, varNum, id->idGCref(), dst);
10119 }
10120 else
10121 {
10122 // If the type of the local is a gc ref type, update the liveness.
10123 var_types vt;
10124 if (varNum >= 0)
10125 {
10126 // "Regular" (non-spill-temp) local.
10127 vt = var_types(emitComp->lvaTable[varNum].lvType);
10128 }
10129 else
10130 {
10131 TempDsc* tmpDsc = codeGen->regSet.tmpFindNum(varNum);
10132 vt = tmpDsc->tdTempType();
10133 }
10134 if (vt == TYP_REF || vt == TYP_BYREF)
10135 emitGCvarDeadUpd(adr + ofs, dst);
10136 }
10137 if (emitInsWritesToLclVarStackLocPair(id))
10138 {
10139 unsigned ofs2 = ofs + TARGET_POINTER_SIZE;
10140 if (id->idGCrefReg2() != GCT_NONE)
10141 {
10142 emitGCvarLiveUpd(adr + ofs2, varNum, id->idGCrefReg2(), dst);
10143 }
10144 else
10145 {
10146 // If the type of the local is a gc ref type, update the liveness.
10147 var_types vt;
10148 if (varNum >= 0)
10149 {
10150 // "Regular" (non-spill-temp) local.
10151 vt = var_types(emitComp->lvaTable[varNum].lvType);
10152 }
10153 else
10154 {
10155 TempDsc* tmpDsc = codeGen->regSet.tmpFindNum(varNum);
10156 vt = tmpDsc->tdTempType();
10157 }
10158 if (vt == TYP_REF || vt == TYP_BYREF)
10159 emitGCvarDeadUpd(adr + ofs2, dst);
10160 }
10161 }
10162 }
10163
10164#ifdef DEBUG
10165 /* Make sure we set the instruction descriptor size correctly */
10166
10167 size_t expected = emitSizeOfInsDsc(id);
10168 assert(sz == expected);
10169
10170 if (emitComp->opts.disAsm || emitComp->opts.dspEmit || emitComp->verbose)
10171 {
10172 emitDispIns(id, false, dspOffs, true, emitCurCodeOffs(odst), *dp, (dst - *dp), ig);
10173 }
10174
10175 if (emitComp->compDebugBreak)
10176 {
10177 // For example, set JitBreakEmitOutputInstr=a6 will break when this method is called for
10178 // emitting instruction a6, (i.e. IN00a6 in jitdump).
10179 if ((unsigned)JitConfig.JitBreakEmitOutputInstr() == id->idDebugOnlyInfo()->idNum)
10180 {
10181 assert(!"JitBreakEmitOutputInstr reached");
10182 }
10183 }
10184#endif
10185
10186 /* All instructions are expected to generate code */
10187
10188 assert(*dp != dst);
10189
10190 *dp = dst;
10191
10192 return sz;
10193}
10194
10195/*****************************************************************************/
10196/*****************************************************************************/
10197
10198#ifdef DEBUG
10199
10200/*****************************************************************************
10201 *
10202 * Display the instruction name
10203 */
10204void emitter::emitDispInst(instruction ins)
10205{
10206 const char* insstr = codeGen->genInsName(ins);
10207 size_t len = strlen(insstr);
10208
10209 /* Display the instruction name */
10210
10211 printf("%s", insstr);
10212
10213 //
10214 // Add at least one space after the instruction name
10215 // and add spaces until we have reach the normal size of 8
10216 do
10217 {
10218 printf(" ");
10219 len++;
10220 } while (len < 8);
10221}
10222
10223/*****************************************************************************
10224 *
10225 * Display an immediate value
10226 */
10227void emitter::emitDispImm(ssize_t imm, bool addComma, bool alwaysHex /* =false */)
10228{
10229 if (strictArmAsm)
10230 {
10231 printf("#");
10232 }
10233
10234 // Munge any pointers if we want diff-able disassembly.
10235 // Since some may be emitted as partial words, print as diffable anything that has
10236 // significant bits beyond the lowest 8-bits.
10237 if (emitComp->opts.disDiffable)
10238 {
10239 ssize_t top56bits = (imm >> 8);
10240 if ((top56bits != 0) && (top56bits != -1))
10241 imm = 0xD1FFAB1E;
10242 }
10243
10244 if (!alwaysHex && (imm > -1000) && (imm < 1000))
10245 {
10246 printf("%d", imm);
10247 }
10248 else
10249 {
10250 if ((imm < 0) && ((imm & 0xFFFFFFFF00000000LL) == 0xFFFFFFFF00000000LL))
10251 {
10252 printf("-");
10253 imm = -imm;
10254 }
10255
10256 if ((imm & 0xFFFFFFFF00000000LL) != 0)
10257 {
10258 printf("0x%llx", imm);
10259 }
10260 else
10261 {
10262 printf("0x%02x", imm);
10263 }
10264 }
10265
10266 if (addComma)
10267 printf(", ");
10268}
10269
10270/*****************************************************************************
10271 *
10272 * Display a float zero constant
10273 */
10274void emitter::emitDispFloatZero()
10275{
10276 if (strictArmAsm)
10277 {
10278 printf("#");
10279 }
10280 printf("0.0");
10281}
10282
10283/*****************************************************************************
10284 *
10285 * Display an encoded float constant value
10286 */
10287void emitter::emitDispFloatImm(ssize_t imm8)
10288{
10289 assert((0 <= imm8) && (imm8 <= 0x0ff));
10290 if (strictArmAsm)
10291 {
10292 printf("#");
10293 }
10294
10295 floatImm8 fpImm;
10296 fpImm.immFPIVal = (unsigned)imm8;
10297 double result = emitDecodeFloatImm8(fpImm);
10298
10299 printf("%.4f", result);
10300}
10301
10302/*****************************************************************************
10303 *
10304 * Display an immediate that is optionally LSL12.
10305 */
10306void emitter::emitDispImmOptsLSL12(ssize_t imm, insOpts opt)
10307{
10308 if (!strictArmAsm && insOptsLSL12(opt))
10309 {
10310 imm <<= 12;
10311 }
10312 emitDispImm(imm, false);
10313 if (strictArmAsm && insOptsLSL12(opt))
10314 {
10315 printf(", LSL #12");
10316 }
10317}
10318
10319/*****************************************************************************
10320 *
10321 * Display an ARM64 condition code for the conditional instructions
10322 */
10323void emitter::emitDispCond(insCond cond)
10324{
10325 const static char* armCond[16] = {"eq", "ne", "hs", "lo", "mi", "pl", "vs", "vc",
10326 "hi", "ls", "ge", "lt", "gt", "le", "AL", "NV"}; // The last two are invalid
10327 unsigned imm = (unsigned)cond;
10328 assert((0 <= imm) && (imm < ArrLen(armCond)));
10329 printf(armCond[imm]);
10330}
10331
10332/*****************************************************************************
10333 *
10334 * Display an ARM64 flags for the conditional instructions
10335 */
10336void emitter::emitDispFlags(insCflags flags)
10337{
10338 const static char* armFlags[16] = {"0", "v", "c", "cv", "z", "zv", "zc", "zcv",
10339 "n", "nv", "nc", "ncv", "nz", "nzv", "nzc", "nzcv"};
10340 unsigned imm = (unsigned)flags;
10341 assert((0 <= imm) && (imm < ArrLen(armFlags)));
10342 printf(armFlags[imm]);
10343}
10344
10345/*****************************************************************************
10346 *
10347 * Display an ARM64 'barrier' for the memory barrier instructions
10348 */
10349void emitter::emitDispBarrier(insBarrier barrier)
10350{
10351 const static char* armBarriers[16] = {"#0", "oshld", "oshst", "osh", "#4", "nshld", "nshst", "nsh",
10352 "#8", "ishld", "ishst", "ish", "#12", "ld", "st", "sy"};
10353 unsigned imm = (unsigned)barrier;
10354 assert((0 <= imm) && (imm < ArrLen(armBarriers)));
10355 printf(armBarriers[imm]);
10356}
10357
10358/*****************************************************************************
10359 *
10360 * Prints the encoding for the Shift Type encoding
10361 */
10362
10363void emitter::emitDispShiftOpts(insOpts opt)
10364{
10365 if (opt == INS_OPTS_LSL)
10366 printf(" LSL ");
10367 else if (opt == INS_OPTS_LSR)
10368 printf(" LSR ");
10369 else if (opt == INS_OPTS_ASR)
10370 printf(" ASR ");
10371 else if (opt == INS_OPTS_ROR)
10372 printf(" ROR ");
10373 else if (opt == INS_OPTS_MSL)
10374 printf(" MSL ");
10375 else
10376 assert(!"Bad value");
10377}
10378
10379/*****************************************************************************
10380 *
10381 * Prints the encoding for the Extend Type encoding
10382 */
10383
10384void emitter::emitDispExtendOpts(insOpts opt)
10385{
10386 if (opt == INS_OPTS_UXTB)
10387 printf("UXTB");
10388 else if (opt == INS_OPTS_UXTH)
10389 printf("UXTH");
10390 else if (opt == INS_OPTS_UXTW)
10391 printf("UXTW");
10392 else if (opt == INS_OPTS_UXTX)
10393 printf("UXTX");
10394 else if (opt == INS_OPTS_SXTB)
10395 printf("SXTB");
10396 else if (opt == INS_OPTS_SXTH)
10397 printf("SXTH");
10398 else if (opt == INS_OPTS_SXTW)
10399 printf("SXTW");
10400 else if (opt == INS_OPTS_SXTX)
10401 printf("SXTX");
10402 else
10403 assert(!"Bad value");
10404}
10405
10406/*****************************************************************************
10407 *
10408 * Prints the encoding for the Extend Type encoding in loads/stores
10409 */
10410
10411void emitter::emitDispLSExtendOpts(insOpts opt)
10412{
10413 if (opt == INS_OPTS_LSL)
10414 printf("LSL");
10415 else if (opt == INS_OPTS_UXTW)
10416 printf("UXTW");
10417 else if (opt == INS_OPTS_UXTX)
10418 printf("UXTX");
10419 else if (opt == INS_OPTS_SXTW)
10420 printf("SXTW");
10421 else if (opt == INS_OPTS_SXTX)
10422 printf("SXTX");
10423 else
10424 assert(!"Bad value");
10425}
10426
10427/*****************************************************************************
10428 *
10429 * Display a register
10430 */
10431void emitter::emitDispReg(regNumber reg, emitAttr attr, bool addComma)
10432{
10433 emitAttr size = EA_SIZE(attr);
10434 printf(emitRegName(reg, size));
10435
10436 if (addComma)
10437 printf(", ");
10438}
10439
10440/*****************************************************************************
10441 *
10442 * Display a vector register with an arrangement suffix
10443 */
10444void emitter::emitDispVectorReg(regNumber reg, insOpts opt, bool addComma)
10445{
10446 assert(isVectorRegister(reg));
10447 printf(emitVectorRegName(reg));
10448 emitDispArrangement(opt);
10449
10450 if (addComma)
10451 printf(", ");
10452}
10453
10454/*****************************************************************************
10455 *
10456 * Display an vector register index suffix
10457 */
10458void emitter::emitDispVectorRegIndex(regNumber reg, emitAttr elemsize, ssize_t index, bool addComma)
10459{
10460 assert(isVectorRegister(reg));
10461 printf(emitVectorRegName(reg));
10462
10463 switch (elemsize)
10464 {
10465 case EA_1BYTE:
10466 printf(".b");
10467 break;
10468 case EA_2BYTE:
10469 printf(".h");
10470 break;
10471 case EA_4BYTE:
10472 printf(".s");
10473 break;
10474 case EA_8BYTE:
10475 printf(".d");
10476 break;
10477 default:
10478 assert(!"invalid elemsize");
10479 break;
10480 }
10481
10482 printf("[%d]", index);
10483
10484 if (addComma)
10485 printf(", ");
10486}
10487
10488/*****************************************************************************
10489 *
10490 * Display an arrangement suffix
10491 */
10492void emitter::emitDispArrangement(insOpts opt)
10493{
10494 const char* str = "???";
10495
10496 switch (opt)
10497 {
10498 case INS_OPTS_8B:
10499 str = "8b";
10500 break;
10501 case INS_OPTS_16B:
10502 str = "16b";
10503 break;
10504 case INS_OPTS_4H:
10505 str = "4h";
10506 break;
10507 case INS_OPTS_8H:
10508 str = "8h";
10509 break;
10510 case INS_OPTS_2S:
10511 str = "2s";
10512 break;
10513 case INS_OPTS_4S:
10514 str = "4s";
10515 break;
10516 case INS_OPTS_1D:
10517 str = "1d";
10518 break;
10519 case INS_OPTS_2D:
10520 str = "2d";
10521 break;
10522
10523 default:
10524 assert(!"Invalid insOpt for vector register");
10525 }
10526 printf(".");
10527 printf(str);
10528}
10529
10530/*****************************************************************************
10531 *
10532 * Display a register with an optional shift operation
10533 */
10534void emitter::emitDispShiftedReg(regNumber reg, insOpts opt, ssize_t imm, emitAttr attr)
10535{
10536 emitAttr size = EA_SIZE(attr);
10537 assert((imm & 0x003F) == imm);
10538 assert(((imm & 0x0020) == 0) || (size == EA_8BYTE));
10539
10540 printf(emitRegName(reg, size));
10541
10542 if (imm > 0)
10543 {
10544 if (strictArmAsm)
10545 {
10546 printf(",");
10547 }
10548 emitDispShiftOpts(opt);
10549 emitDispImm(imm, false);
10550 }
10551}
10552
10553/*****************************************************************************
10554 *
10555 * Display a register with an optional extend and scale operations
10556 */
10557void emitter::emitDispExtendReg(regNumber reg, insOpts opt, ssize_t imm)
10558{
10559 assert((imm >= 0) && (imm <= 4));
10560 assert(insOptsNone(opt) || insOptsAnyExtend(opt) || (opt == INS_OPTS_LSL));
10561
10562 // size is based on the extend option, not the instr size.
10563 emitAttr size = insOpts32BitExtend(opt) ? EA_4BYTE : EA_8BYTE;
10564
10565 if (strictArmAsm)
10566 {
10567 if (insOptsNone(opt))
10568 {
10569 emitDispReg(reg, size, false);
10570 }
10571 else
10572 {
10573 emitDispReg(reg, size, true);
10574 if (opt == INS_OPTS_LSL)
10575 printf("LSL");
10576 else
10577 emitDispExtendOpts(opt);
10578 if ((imm > 0) || (opt == INS_OPTS_LSL))
10579 {
10580 printf(" ");
10581 emitDispImm(imm, false);
10582 }
10583 }
10584 }
10585 else // !strictArmAsm
10586 {
10587 if (insOptsNone(opt))
10588 {
10589 emitDispReg(reg, size, false);
10590 }
10591 else
10592 {
10593 if (opt != INS_OPTS_LSL)
10594 {
10595 emitDispExtendOpts(opt);
10596 printf("(");
10597 emitDispReg(reg, size, false);
10598 printf(")");
10599 }
10600 }
10601 if (imm > 0)
10602 {
10603 printf("*");
10604 emitDispImm(ssize_t{1} << imm, false);
10605 }
10606 }
10607}
10608
10609/*****************************************************************************
10610 *
10611 * Display an addressing operand [reg + imm]
10612 */
10613void emitter::emitDispAddrRI(regNumber reg, insOpts opt, ssize_t imm)
10614{
10615 reg = encodingZRtoSP(reg); // ZR (R31) encodes the SP register
10616
10617 if (strictArmAsm)
10618 {
10619 printf("[");
10620
10621 emitDispReg(reg, EA_8BYTE, false);
10622
10623 if (!insOptsPostIndex(opt) && (imm != 0))
10624 {
10625 printf(",");
10626 emitDispImm(imm, false);
10627 }
10628 printf("]");
10629
10630 if (insOptsPreIndex(opt))
10631 {
10632 printf("!");
10633 }
10634 else if (insOptsPostIndex(opt))
10635 {
10636 printf(",");
10637 emitDispImm(imm, false);
10638 }
10639 }
10640 else // !strictArmAsm
10641 {
10642 printf("[");
10643
10644 const char* operStr = "++";
10645 if (imm < 0)
10646 {
10647 operStr = "--";
10648 imm = -imm;
10649 }
10650
10651 if (insOptsPreIndex(opt))
10652 {
10653 printf(operStr);
10654 }
10655
10656 emitDispReg(reg, EA_8BYTE, false);
10657
10658 if (insOptsPostIndex(opt))
10659 {
10660 printf(operStr);
10661 }
10662
10663 if (insOptsIndexed(opt))
10664 {
10665 printf(", ");
10666 }
10667 else
10668 {
10669 printf("%c", operStr[1]);
10670 }
10671 emitDispImm(imm, false);
10672 printf("]");
10673 }
10674}
10675
10676/*****************************************************************************
10677 *
10678 * Display an addressing operand [reg + extended reg]
10679 */
10680void emitter::emitDispAddrRRExt(regNumber reg1, regNumber reg2, insOpts opt, bool isScaled, emitAttr size)
10681{
10682 reg1 = encodingZRtoSP(reg1); // ZR (R31) encodes the SP register
10683
10684 unsigned scale = 0;
10685 if (isScaled)
10686 {
10687 scale = NaturalScale_helper(size);
10688 }
10689
10690 printf("[");
10691
10692 if (strictArmAsm)
10693 {
10694 emitDispReg(reg1, EA_8BYTE, true);
10695 emitDispExtendReg(reg2, opt, scale);
10696 }
10697 else // !strictArmAsm
10698 {
10699 emitDispReg(reg1, EA_8BYTE, false);
10700 printf("+");
10701 emitDispExtendReg(reg2, opt, scale);
10702 }
10703
10704 printf("]");
10705}
10706
10707/*****************************************************************************
10708 *
10709 * Display (optionally) the instruction encoding in hex
10710 */
10711
10712void emitter::emitDispInsHex(BYTE* code, size_t sz)
10713{
10714 // We do not display the instruction hex if we want diff-able disassembly
10715 if (!emitComp->opts.disDiffable)
10716 {
10717 if (sz == 4)
10718 {
10719 printf(" %08X ", (*((code_t*)code)));
10720 }
10721 else
10722 {
10723 printf(" ");
10724 }
10725 }
10726}
10727
10728/****************************************************************************
10729 *
10730 * Display the given instruction.
10731 */
10732
10733void emitter::emitDispIns(
10734 instrDesc* id, bool isNew, bool doffs, bool asmfm, unsigned offset, BYTE* pCode, size_t sz, insGroup* ig)
10735{
10736 if (EMITVERBOSE)
10737 {
10738 unsigned idNum =
10739 id->idDebugOnlyInfo()->idNum; // Do not remove this! It is needed for VisualStudio conditional breakpoints
10740
10741 printf("IN%04x: ", idNum);
10742 }
10743
10744 if (pCode == NULL)
10745 sz = 0;
10746
10747 if (!emitComp->opts.dspEmit && !isNew && !asmfm && sz)
10748 doffs = true;
10749
10750 /* Display the instruction offset */
10751
10752 emitDispInsOffs(offset, doffs);
10753
10754 /* Display the instruction hex code */
10755
10756 emitDispInsHex(pCode, sz);
10757
10758 printf(" ");
10759
10760 /* Get the instruction and format */
10761
10762 instruction ins = id->idIns();
10763 insFormat fmt = id->idInsFmt();
10764
10765 emitDispInst(ins);
10766
10767 /* If this instruction has just been added, check its size */
10768
10769 assert(isNew == false || (int)emitSizeOfInsDsc(id) == emitCurIGfreeNext - (BYTE*)id);
10770
10771 /* Figure out the operand size */
10772 emitAttr size = id->idOpSize();
10773 emitAttr attr = size;
10774 if (id->idGCref() == GCT_GCREF)
10775 attr = EA_GCREF;
10776 else if (id->idGCref() == GCT_BYREF)
10777 attr = EA_BYREF;
10778
10779 switch (fmt)
10780 {
10781 code_t code;
10782 ssize_t imm;
10783 int doffs;
10784 bool isExtendAlias;
10785 bitMaskImm bmi;
10786 halfwordImm hwi;
10787 condFlagsImm cfi;
10788 unsigned scale;
10789 unsigned immShift;
10790 bool hasShift;
10791 ssize_t offs;
10792 const char* methodName;
10793 emitAttr elemsize;
10794 emitAttr datasize;
10795 emitAttr srcsize;
10796 emitAttr dstsize;
10797 ssize_t index;
10798 ssize_t index2;
10799
10800 case IF_BI_0A: // BI_0A ......iiiiiiiiii iiiiiiiiiiiiiiii simm26:00
10801 case IF_BI_0B: // BI_0B ......iiiiiiiiii iiiiiiiiiii..... simm19:00
10802 case IF_LARGEJMP:
10803 {
10804 if (fmt == IF_LARGEJMP)
10805 {
10806 printf("(LARGEJMP)");
10807 }
10808 if (id->idAddr()->iiaHasInstrCount())
10809 {
10810 int instrCount = id->idAddr()->iiaGetInstrCount();
10811
10812 if (ig == nullptr)
10813 {
10814 printf("pc%s%d instructions", (instrCount >= 0) ? "+" : "", instrCount);
10815 }
10816 else
10817 {
10818 unsigned insNum = emitFindInsNum(ig, id);
10819 UNATIVE_OFFSET srcOffs = ig->igOffs + emitFindOffset(ig, insNum + 1);
10820 UNATIVE_OFFSET dstOffs = ig->igOffs + emitFindOffset(ig, insNum + 1 + instrCount);
10821 ssize_t relOffs = (ssize_t)(emitOffsetToPtr(dstOffs) - emitOffsetToPtr(srcOffs));
10822 printf("pc%s%d (%d instructions)", (relOffs >= 0) ? "+" : "", relOffs, instrCount);
10823 }
10824 }
10825 else if (id->idIsBound())
10826 {
10827 printf("G_M%03u_IG%02u", Compiler::s_compMethodsCount, id->idAddr()->iiaIGlabel->igNum);
10828 }
10829 else
10830 {
10831 printf("L_M%03u_" FMT_BB, Compiler::s_compMethodsCount, id->idAddr()->iiaBBlabel->bbNum);
10832 }
10833 }
10834 break;
10835
10836 case IF_BI_0C: // BI_0C ......iiiiiiiiii iiiiiiiiiiiiiiii simm26:00
10837 if (id->idIsCallAddr())
10838 {
10839 offs = (ssize_t)id->idAddr()->iiaAddr;
10840 methodName = "";
10841 }
10842 else
10843 {
10844 offs = 0;
10845 methodName = emitComp->eeGetMethodFullName((CORINFO_METHOD_HANDLE)id->idDebugOnlyInfo()->idMemCookie);
10846 }
10847
10848 if (offs)
10849 {
10850 if (id->idIsDspReloc())
10851 printf("reloc ");
10852 printf("%08X", offs);
10853 }
10854 else
10855 {
10856 printf("%s", methodName);
10857 }
10858 break;
10859
10860 case IF_BI_1A: // BI_1A ......iiiiiiiiii iiiiiiiiiiittttt Rt simm19:00
10861 assert(insOptsNone(id->idInsOpt()));
10862 emitDispReg(id->idReg1(), size, true);
10863 if (id->idIsBound())
10864 {
10865 printf("G_M%03u_IG%02u", Compiler::s_compMethodsCount, id->idAddr()->iiaIGlabel->igNum);
10866 }
10867 else
10868 {
10869 printf("L_M%03u_" FMT_BB, Compiler::s_compMethodsCount, id->idAddr()->iiaBBlabel->bbNum);
10870 }
10871 break;
10872
10873 case IF_BI_1B: // BI_1B B.......bbbbbiii iiiiiiiiiiittttt Rt imm6, simm14:00
10874 assert(insOptsNone(id->idInsOpt()));
10875 emitDispReg(id->idReg1(), size, true);
10876 emitDispImm(emitGetInsSC(id), true);
10877 if (id->idIsBound())
10878 {
10879 printf("G_M%03u_IG%02u", Compiler::s_compMethodsCount, id->idAddr()->iiaIGlabel->igNum);
10880 }
10881 else
10882 {
10883 printf("L_M%03u_" FMT_BB, Compiler::s_compMethodsCount, id->idAddr()->iiaBBlabel->bbNum);
10884 }
10885 break;
10886
10887 case IF_BR_1A: // BR_1A ................ ......nnnnn..... Rn
10888 assert(insOptsNone(id->idInsOpt()));
10889 emitDispReg(id->idReg1(), size, false);
10890 break;
10891
10892 case IF_BR_1B: // BR_1B ................ ......nnnnn..... Rn
10893 assert(insOptsNone(id->idInsOpt()));
10894 emitDispReg(id->idReg3(), size, false);
10895 break;
10896
10897 case IF_LS_1A: // LS_1A XX...V..iiiiiiii iiiiiiiiiiittttt Rt PC imm(1MB)
10898 case IF_DI_1E: // DI_1E .ii.....iiiiiiii iiiiiiiiiiiddddd Rd simm21
10899 case IF_LARGELDC:
10900 case IF_LARGEADR:
10901 assert(insOptsNone(id->idInsOpt()));
10902 emitDispReg(id->idReg1(), size, true);
10903 imm = emitGetInsSC(id);
10904
10905 /* Is this actually a reference to a data section? */
10906 if (fmt == IF_LARGEADR)
10907 {
10908 printf("(LARGEADR)");
10909 }
10910 else if (fmt == IF_LARGELDC)
10911 {
10912 printf("(LARGELDC)");
10913 }
10914
10915 printf("[");
10916 if (id->idAddr()->iiaIsJitDataOffset())
10917 {
10918 doffs = Compiler::eeGetJitDataOffs(id->idAddr()->iiaFieldHnd);
10919 /* Display a data section reference */
10920
10921 if (doffs & 1)
10922 printf("@CNS%02u", doffs - 1);
10923 else
10924 printf("@RWD%02u", doffs);
10925
10926 if (imm != 0)
10927 printf("%+Id", imm);
10928 }
10929 else
10930 {
10931 assert(imm == 0);
10932 if (id->idIsReloc())
10933 {
10934 printf("RELOC ");
10935 emitDispImm((ssize_t)id->idAddr()->iiaAddr, false);
10936 }
10937 else if (id->idIsBound())
10938 {
10939 printf("G_M%03u_IG%02u", Compiler::s_compMethodsCount, id->idAddr()->iiaIGlabel->igNum);
10940 }
10941 else
10942 {
10943 printf("L_M%03u_" FMT_BB, Compiler::s_compMethodsCount, id->idAddr()->iiaBBlabel->bbNum);
10944 }
10945 }
10946 printf("]");
10947 break;
10948
10949 case IF_LS_2A: // LS_2A .X.......X...... ......nnnnnttttt Rt Rn
10950 assert(insOptsNone(id->idInsOpt()));
10951 assert(emitGetInsSC(id) == 0);
10952 emitDispReg(id->idReg1(), emitInsTargetRegSize(id), true);
10953 emitDispAddrRI(id->idReg2(), id->idInsOpt(), 0);
10954 break;
10955
10956 case IF_LS_2B: // LS_2B .X.......Xiiiiii iiiiiinnnnnttttt Rt Rn imm(0-4095)
10957 assert(insOptsNone(id->idInsOpt()));
10958 imm = emitGetInsSC(id);
10959 scale = NaturalScale_helper(emitInsLoadStoreSize(id));
10960 imm <<= scale; // The immediate is scaled by the size of the ld/st
10961 emitDispReg(id->idReg1(), emitInsTargetRegSize(id), true);
10962 emitDispAddrRI(id->idReg2(), id->idInsOpt(), imm);
10963 break;
10964
10965 case IF_LS_2C: // LS_2C .X.......X.iiiii iiiiPPnnnnnttttt Rt Rn imm(-256..+255) no/pre/post inc
10966 assert(insOptsNone(id->idInsOpt()) || insOptsIndexed(id->idInsOpt()));
10967 imm = emitGetInsSC(id);
10968 emitDispReg(id->idReg1(), emitInsTargetRegSize(id), true);
10969 emitDispAddrRI(id->idReg2(), id->idInsOpt(), imm);
10970 break;
10971
10972 case IF_LS_3A: // LS_3A .X.......X.mmmmm oooS..nnnnnttttt Rt Rn Rm ext(Rm) LSL {}
10973 assert(insOptsLSExtend(id->idInsOpt()));
10974 emitDispReg(id->idReg1(), emitInsTargetRegSize(id), true);
10975 if (id->idIsLclVar())
10976 {
10977 emitDispAddrRRExt(id->idReg2(), codeGen->rsGetRsvdReg(), id->idInsOpt(), false, size);
10978 }
10979 else
10980 {
10981 emitDispAddrRRExt(id->idReg2(), id->idReg3(), id->idInsOpt(), id->idReg3Scaled(), size);
10982 }
10983 break;
10984
10985 case IF_LS_3B: // LS_3B X............... .aaaaannnnnddddd Rt Ra Rn
10986 assert(insOptsNone(id->idInsOpt()));
10987 assert(emitGetInsSC(id) == 0);
10988 emitDispReg(id->idReg1(), emitInsTargetRegSize(id), true);
10989 emitDispReg(id->idReg2(), emitInsTargetRegSize(id), true);
10990 emitDispAddrRI(id->idReg3(), id->idInsOpt(), 0);
10991 break;
10992
10993 case IF_LS_3C: // LS_3C X.........iiiiii iaaaaannnnnddddd Rt Ra Rn imm(im7,sh)
10994 assert(insOptsNone(id->idInsOpt()) || insOptsIndexed(id->idInsOpt()));
10995 imm = emitGetInsSC(id);
10996 scale = NaturalScale_helper(emitInsLoadStoreSize(id));
10997 imm <<= scale;
10998 emitDispReg(id->idReg1(), emitInsTargetRegSize(id), true);
10999 emitDispReg(id->idReg2(), emitInsTargetRegSize(id), true);
11000 emitDispAddrRI(id->idReg3(), id->idInsOpt(), imm);
11001 break;
11002
11003 case IF_LS_3D: // LS_3D .X.......X.mmmmm ......nnnnnttttt Wm Rt Rn
11004 assert(insOptsNone(id->idInsOpt()));
11005 emitDispReg(id->idReg1(), EA_4BYTE, true);
11006 emitDispReg(id->idReg2(), emitInsTargetRegSize(id), true);
11007 emitDispAddrRI(id->idReg3(), id->idInsOpt(), 0);
11008 break;
11009
11010 case IF_LS_3E: // LS_3E .X.........mmmmm ......nnnnnttttt Rm Rt Rn ARMv8.1 LSE Atomics
11011 assert(insOptsNone(id->idInsOpt()));
11012 emitDispReg(id->idReg1(), emitInsTargetRegSize(id), true);
11013 emitDispReg(id->idReg2(), emitInsTargetRegSize(id), true);
11014 emitDispAddrRI(id->idReg3(), id->idInsOpt(), 0);
11015 break;
11016
11017 case IF_DI_1A: // DI_1A X.......shiiiiii iiiiiinnnnn..... Rn imm(i12,sh)
11018 emitDispReg(id->idReg1(), size, true);
11019 emitDispImmOptsLSL12(emitGetInsSC(id), id->idInsOpt());
11020 break;
11021
11022 case IF_DI_1B: // DI_1B X........hwiiiii iiiiiiiiiiiddddd Rd imm(i16,hw)
11023 emitDispReg(id->idReg1(), size, true);
11024 hwi.immHWVal = (unsigned)emitGetInsSC(id);
11025 if (ins == INS_mov)
11026 {
11027 emitDispImm(emitDecodeHalfwordImm(hwi, size), false);
11028 }
11029 else // movz, movn, movk
11030 {
11031 emitDispImm(hwi.immVal, false);
11032 if (hwi.immHW != 0)
11033 {
11034 emitDispShiftOpts(INS_OPTS_LSL);
11035 emitDispImm(hwi.immHW * 16, false);
11036 }
11037 }
11038 break;
11039
11040 case IF_DI_1C: // DI_1C X........Nrrrrrr ssssssnnnnn..... Rn imm(N,r,s)
11041 emitDispReg(id->idReg1(), size, true);
11042 bmi.immNRS = (unsigned)emitGetInsSC(id);
11043 emitDispImm(emitDecodeBitMaskImm(bmi, size), false);
11044 break;
11045
11046 case IF_DI_1D: // DI_1D X........Nrrrrrr ssssss.....ddddd Rd imm(N,r,s)
11047 emitDispReg(encodingZRtoSP(id->idReg1()), size, true);
11048 bmi.immNRS = (unsigned)emitGetInsSC(id);
11049 emitDispImm(emitDecodeBitMaskImm(bmi, size), false);
11050 break;
11051
11052 case IF_DI_2A: // DI_2A X.......shiiiiii iiiiiinnnnnddddd Rd Rn imm(i12,sh)
11053 if ((ins == INS_add) || (ins == INS_sub))
11054 {
11055 emitDispReg(encodingZRtoSP(id->idReg1()), size, true);
11056 emitDispReg(encodingZRtoSP(id->idReg2()), size, true);
11057 }
11058 else
11059 {
11060 emitDispReg(id->idReg1(), size, true);
11061 emitDispReg(id->idReg2(), size, true);
11062 }
11063 emitDispImmOptsLSL12(emitGetInsSC(id), id->idInsOpt());
11064 break;
11065
11066 case IF_DI_2B: // DI_2B X........X.nnnnn ssssssnnnnnddddd Rd Rn imm(0-63)
11067 emitDispReg(id->idReg1(), size, true);
11068 emitDispReg(id->idReg2(), size, true);
11069 emitDispImm(emitGetInsSC(id), false);
11070 break;
11071
11072 case IF_DI_2C: // DI_2C X........Nrrrrrr ssssssnnnnnddddd Rd Rn imm(N,r,s)
11073 if (ins == INS_ands)
11074 {
11075 emitDispReg(id->idReg1(), size, true);
11076 }
11077 else
11078 {
11079 emitDispReg(encodingZRtoSP(id->idReg1()), size, true);
11080 }
11081 emitDispReg(id->idReg2(), size, true);
11082 bmi.immNRS = (unsigned)emitGetInsSC(id);
11083 emitDispImm(emitDecodeBitMaskImm(bmi, size), false);
11084 break;
11085
11086 case IF_DI_2D: // DI_2D X........Nrrrrrr ssssssnnnnnddddd Rd Rn imr, ims (N,r,s)
11087 emitDispReg(id->idReg1(), size, true);
11088 emitDispReg(id->idReg2(), size, true);
11089
11090 imm = emitGetInsSC(id);
11091 bmi.immNRS = (unsigned)imm;
11092
11093 switch (ins)
11094 {
11095 case INS_bfm:
11096 case INS_sbfm:
11097 case INS_ubfm:
11098 emitDispImm(bmi.immR, true);
11099 emitDispImm(bmi.immS, false);
11100 break;
11101
11102 case INS_bfi:
11103 case INS_sbfiz:
11104 case INS_ubfiz:
11105 emitDispImm(getBitWidth(size) - bmi.immR, true);
11106 emitDispImm(bmi.immS + 1, false);
11107 break;
11108
11109 case INS_bfxil:
11110 case INS_sbfx:
11111 case INS_ubfx:
11112 emitDispImm(bmi.immR, true);
11113 emitDispImm(bmi.immS - bmi.immR + 1, false);
11114 break;
11115
11116 case INS_asr:
11117 case INS_lsr:
11118 case INS_lsl:
11119 emitDispImm(imm, false);
11120 break;
11121
11122 default:
11123 assert(!"Unexpected instruction in IF_DI_2D");
11124 }
11125
11126 break;
11127
11128 case IF_DI_1F: // DI_1F X..........iiiii cccc..nnnnn.nzcv Rn imm5 nzcv cond
11129 emitDispReg(id->idReg1(), size, true);
11130 cfi.immCFVal = (unsigned)emitGetInsSC(id);
11131 emitDispImm(cfi.imm5, true);
11132 emitDispFlags(cfi.flags);
11133 printf(",");
11134 emitDispCond(cfi.cond);
11135 break;
11136
11137 case IF_DR_1D: // DR_1D X............... cccc.......mmmmm Rd cond
11138 emitDispReg(id->idReg1(), size, true);
11139 cfi.immCFVal = (unsigned)emitGetInsSC(id);
11140 emitDispCond(cfi.cond);
11141 break;
11142
11143 case IF_DR_2A: // DR_2A X..........mmmmm ......nnnnn..... Rn Rm
11144 emitDispReg(id->idReg1(), size, true);
11145 emitDispReg(id->idReg2(), size, false);
11146 break;
11147
11148 case IF_DR_2B: // DR_2B X.......sh.mmmmm ssssssnnnnn..... Rn Rm {LSL,LSR,ASR,ROR} imm(0-63)
11149 emitDispReg(id->idReg1(), size, true);
11150 emitDispShiftedReg(id->idReg2(), id->idInsOpt(), emitGetInsSC(id), size);
11151 break;
11152
11153 case IF_DR_2C: // DR_2C X..........mmmmm ooosssnnnnn..... Rn Rm ext(Rm) LSL imm(0-4)
11154 emitDispReg(encodingZRtoSP(id->idReg1()), size, true);
11155 imm = emitGetInsSC(id);
11156 emitDispExtendReg(id->idReg2(), id->idInsOpt(), imm);
11157 break;
11158
11159 case IF_DR_2D: // DR_2D X..........nnnnn cccc..nnnnnddddd Rd Rn cond
11160 emitDispReg(id->idReg1(), size, true);
11161 emitDispReg(id->idReg2(), size, true);
11162 cfi.immCFVal = (unsigned)emitGetInsSC(id);
11163 emitDispCond(cfi.cond);
11164 break;
11165
11166 case IF_DR_2E: // DR_2E X..........mmmmm ...........ddddd Rd Rm
11167 case IF_DR_2J: // DR_2J ................ ......nnnnnddddd Sd Sn
11168 emitDispReg(id->idReg1(), size, true);
11169 emitDispReg(id->idReg2(), size, false);
11170 break;
11171
11172 case IF_DR_2F: // DR_2F X.......sh.mmmmm ssssss.....ddddd Rd Rm {LSL,LSR,ASR} imm(0-63)
11173 emitDispReg(id->idReg1(), size, true);
11174 emitDispShiftedReg(id->idReg2(), id->idInsOpt(), emitGetInsSC(id), size);
11175 break;
11176
11177 case IF_DR_2G: // DR_2G X............... ......nnnnnddddd Rd Rn
11178 emitDispReg(encodingZRtoSP(id->idReg1()), size, true);
11179 emitDispReg(encodingZRtoSP(id->idReg2()), size, false);
11180 break;
11181
11182 case IF_DR_2H: // DR_2H X........X...... ......nnnnnddddd Rd Rn
11183 emitDispReg(id->idReg1(), size, true);
11184 emitDispReg(id->idReg2(), size, false);
11185 break;
11186
11187 case IF_DR_2I: // DR_2I X..........mmmmm cccc..nnnnn.nzcv Rn Rm nzcv cond
11188 emitDispReg(id->idReg1(), size, true);
11189 emitDispReg(id->idReg2(), size, true);
11190 cfi.immCFVal = (unsigned)emitGetInsSC(id);
11191 emitDispFlags(cfi.flags);
11192 printf(",");
11193 emitDispCond(cfi.cond);
11194 break;
11195
11196 case IF_DR_3A: // DR_3A X..........mmmmm ......nnnnnmmmmm Rd Rn Rm
11197 if ((ins == INS_add) || (ins == INS_sub))
11198 {
11199 emitDispReg(encodingZRtoSP(id->idReg1()), size, true);
11200 emitDispReg(encodingZRtoSP(id->idReg2()), size, true);
11201 }
11202 else if ((ins == INS_smull) || (ins == INS_smulh))
11203 {
11204 // Rd is always 8 bytes
11205 emitDispReg(id->idReg1(), EA_8BYTE, true);
11206
11207 // Rn, Rm effective size depends on instruction type
11208 size = (ins == INS_smulh) ? EA_8BYTE : EA_4BYTE;
11209 emitDispReg(id->idReg2(), size, true);
11210 }
11211 else
11212 {
11213 emitDispReg(id->idReg1(), size, true);
11214 emitDispReg(id->idReg2(), size, true);
11215 }
11216 if (id->idIsLclVar())
11217 {
11218 emitDispReg(codeGen->rsGetRsvdReg(), size, false);
11219 }
11220 else
11221 {
11222 emitDispReg(id->idReg3(), size, false);
11223 }
11224
11225 break;
11226
11227 case IF_DR_3B: // DR_3B X.......sh.mmmmm ssssssnnnnnddddd Rd Rn Rm {LSL,LSR,ASR} imm(0-63)
11228 emitDispReg(id->idReg1(), size, true);
11229 emitDispReg(id->idReg2(), size, true);
11230 emitDispShiftedReg(id->idReg3(), id->idInsOpt(), emitGetInsSC(id), size);
11231 break;
11232
11233 case IF_DR_3C: // DR_3C X..........mmmmm ooosssnnnnnddddd Rd Rn Rm ext(Rm) LSL imm(0-4)
11234 emitDispReg(encodingZRtoSP(id->idReg1()), size, true);
11235 emitDispReg(encodingZRtoSP(id->idReg2()), size, true);
11236 imm = emitGetInsSC(id);
11237 emitDispExtendReg(id->idReg3(), id->idInsOpt(), imm);
11238 break;
11239
11240 case IF_DR_3D: // DR_3D X..........mmmmm cccc..nnnnnmmmmm Rd Rn Rm cond
11241 emitDispReg(id->idReg1(), size, true);
11242 emitDispReg(id->idReg2(), size, true);
11243 emitDispReg(id->idReg3(), size, true);
11244 cfi.immCFVal = (unsigned)emitGetInsSC(id);
11245 emitDispCond(cfi.cond);
11246 break;
11247
11248 case IF_DR_3E: // DR_3E X........X.mmmmm ssssssnnnnnddddd Rd Rn Rm imm(0-63)
11249 emitDispReg(id->idReg1(), size, true);
11250 emitDispReg(id->idReg2(), size, true);
11251 emitDispReg(id->idReg3(), size, true);
11252 emitDispImm(emitGetInsSC(id), false);
11253 break;
11254
11255 case IF_DR_4A: // DR_4A X..........mmmmm .aaaaannnnnmmmmm Rd Rn Rm Ra
11256 emitDispReg(id->idReg1(), size, true);
11257 emitDispReg(id->idReg2(), size, true);
11258 emitDispReg(id->idReg3(), size, true);
11259 emitDispReg(id->idReg4(), size, false);
11260 break;
11261
11262 case IF_DV_1A: // DV_1A .........X.iiiii iii........ddddd Vd imm8 (fmov - immediate scalar)
11263 elemsize = id->idOpSize();
11264 emitDispReg(id->idReg1(), elemsize, true);
11265 emitDispFloatImm(emitGetInsSC(id));
11266 break;
11267
11268 case IF_DV_1B: // DV_1B .QX..........iii cmod..iiiiiddddd Vd imm8 (immediate vector)
11269 imm = emitGetInsSC(id) & 0x0ff;
11270 immShift = (emitGetInsSC(id) & 0x700) >> 8;
11271 hasShift = (immShift != 0);
11272 elemsize = optGetElemsize(id->idInsOpt());
11273 if (id->idInsOpt() == INS_OPTS_1D)
11274 {
11275 assert(elemsize == size);
11276 emitDispReg(id->idReg1(), size, true);
11277 }
11278 else
11279 {
11280 emitDispVectorReg(id->idReg1(), id->idInsOpt(), true);
11281 }
11282 if (ins == INS_fmov)
11283 {
11284 emitDispFloatImm(imm);
11285 assert(hasShift == false);
11286 }
11287 else
11288 {
11289 if (elemsize == EA_8BYTE)
11290 {
11291 assert(ins == INS_movi);
11292 ssize_t imm64 = 0;
11293 const ssize_t mask8 = 0xFF;
11294 for (unsigned b = 0; b < 8; b++)
11295 {
11296 if (imm & (ssize_t{1} << b))
11297 {
11298 imm64 |= (mask8 << (b * 8));
11299 }
11300 }
11301 emitDispImm(imm64, hasShift, true);
11302 }
11303 else
11304 {
11305 emitDispImm(imm, hasShift, true);
11306 }
11307 if (hasShift)
11308 {
11309 insOpts opt = (immShift & 0x4) ? INS_OPTS_MSL : INS_OPTS_LSL;
11310 unsigned shift = (immShift & 0x3) * 8;
11311 emitDispShiftOpts(opt);
11312 emitDispImm(shift, false);
11313 }
11314 }
11315 break;
11316
11317 case IF_DV_1C: // DV_1C .........X...... ......nnnnn..... Vn #0.0 (fcmp - with zero)
11318 elemsize = id->idOpSize();
11319 emitDispReg(id->idReg1(), elemsize, true);
11320 emitDispFloatZero();
11321 break;
11322
11323 case IF_DV_2A: // DV_2A .Q.......X...... ......nnnnnddddd Vd Vn (fabs, fcvt - vector)
11324 case IF_DV_2M: // DV_2M .Q......XX...... ......nnnnnddddd Vd Vn (abs, neg - vector)
11325 case IF_DV_2P: // DV_2P ................ ......nnnnnddddd Vd Vn (aes*, sha1su1)
11326 emitDispVectorReg(id->idReg1(), id->idInsOpt(), true);
11327 emitDispVectorReg(id->idReg2(), id->idInsOpt(), false);
11328 break;
11329
11330 case IF_DV_2N: // DV_2N .........iiiiiii ......nnnnnddddd Vd Vn imm (shift - scalar)
11331 elemsize = id->idOpSize();
11332 emitDispReg(id->idReg1(), elemsize, true);
11333 emitDispReg(id->idReg2(), elemsize, true);
11334 emitDispImm(emitGetInsSC(id), false);
11335 break;
11336
11337 case IF_DV_2O: // DV_2O .Q.......iiiiiii ......nnnnnddddd Vd Vn imm (shift - vector)
11338 imm = emitGetInsSC(id);
11339 // Do we have a sxtl or uxtl instruction?
11340 isExtendAlias = ((ins == INS_sxtl) || (ins == INS_sxtl2) || (ins == INS_uxtl) || (ins == INS_uxtl2));
11341 code = emitInsCode(ins, fmt);
11342 if (code & 0x00008000) // widen/narrow opcodes
11343 {
11344 if (code & 0x00002000) // SHL opcodes
11345 {
11346 emitDispVectorReg(id->idReg1(), optWidenElemsize(id->idInsOpt()), true);
11347 emitDispVectorReg(id->idReg2(), id->idInsOpt(), !isExtendAlias);
11348 }
11349 else // SHR opcodes
11350 {
11351 emitDispVectorReg(id->idReg1(), id->idInsOpt(), true);
11352 emitDispVectorReg(id->idReg2(), optWidenElemsize(id->idInsOpt()), !isExtendAlias);
11353 }
11354 }
11355 else
11356 {
11357 emitDispVectorReg(id->idReg1(), id->idInsOpt(), true);
11358 emitDispVectorReg(id->idReg2(), id->idInsOpt(), !isExtendAlias);
11359 }
11360 // Print the immediate unless we have a sxtl or uxtl instruction
11361 if (!isExtendAlias)
11362 {
11363 emitDispImm(imm, false);
11364 }
11365 break;
11366
11367 case IF_DV_2B: // DV_2B .Q.........iiiii ......nnnnnddddd Rd Vn[] (umov/smov - to general)
11368 srcsize = id->idOpSize();
11369 index = emitGetInsSC(id);
11370 if (ins == INS_smov)
11371 {
11372 dstsize = EA_8BYTE;
11373 }
11374 else // INS_umov or INS_mov
11375 {
11376 dstsize = (srcsize == EA_8BYTE) ? EA_8BYTE : EA_4BYTE;
11377 }
11378 emitDispReg(id->idReg1(), dstsize, true);
11379 emitDispVectorRegIndex(id->idReg2(), srcsize, index, false);
11380 break;
11381
11382 case IF_DV_2C: // DV_2C .Q.........iiiii ......nnnnnddddd Vd Rn (dup/ins - vector from general)
11383 if (ins == INS_dup)
11384 {
11385 datasize = id->idOpSize();
11386 assert(isValidVectorDatasize(datasize));
11387 assert(isValidArrangement(datasize, id->idInsOpt()));
11388 elemsize = optGetElemsize(id->idInsOpt());
11389 emitDispVectorReg(id->idReg1(), id->idInsOpt(), true);
11390 }
11391 else // INS_ins
11392 {
11393 elemsize = id->idOpSize();
11394 index = emitGetInsSC(id);
11395 assert(isValidVectorElemsize(elemsize));
11396 emitDispVectorRegIndex(id->idReg1(), elemsize, index, true);
11397 }
11398 emitDispReg(id->idReg2(), (elemsize == EA_8BYTE) ? EA_8BYTE : EA_4BYTE, false);
11399 break;
11400
11401 case IF_DV_2D: // DV_2D .Q.........iiiii ......nnnnnddddd Vd Vn[] (dup - vector)
11402 datasize = id->idOpSize();
11403 assert(isValidVectorDatasize(datasize));
11404 assert(isValidArrangement(datasize, id->idInsOpt()));
11405 elemsize = optGetElemsize(id->idInsOpt());
11406 index = emitGetInsSC(id);
11407 emitDispVectorReg(id->idReg1(), id->idInsOpt(), true);
11408 emitDispVectorRegIndex(id->idReg2(), elemsize, index, false);
11409 break;
11410
11411 case IF_DV_2E: // DV_2E ...........iiiii ......nnnnnddddd Vd Vn[] (dup - scalar)
11412 elemsize = id->idOpSize();
11413 index = emitGetInsSC(id);
11414 emitDispReg(id->idReg1(), elemsize, true);
11415 emitDispVectorRegIndex(id->idReg2(), elemsize, index, false);
11416 break;
11417
11418 case IF_DV_2F: // DV_2F ...........iiiii .jjjj.nnnnnddddd Vd[] Vn[] (ins - element)
11419 imm = emitGetInsSC(id);
11420 index = (imm >> 4) & 0xf;
11421 index2 = imm & 0xf;
11422 elemsize = id->idOpSize();
11423 emitDispVectorRegIndex(id->idReg1(), elemsize, index, true);
11424 emitDispVectorRegIndex(id->idReg2(), elemsize, index2, false);
11425 break;
11426
11427 case IF_DV_2G: // DV_2G .........X...... ......nnnnnddddd Vd Vn (fmov, fcvtXX - register)
11428 case IF_DV_2K: // DV_2K .........X.mmmmm ......nnnnn..... Vn Vm (fcmp)
11429 case IF_DV_2L: // DV_2L ........XX...... ......nnnnnddddd Vd Vn (abs, neg - scalar)
11430 elemsize = id->idOpSize();
11431 emitDispReg(id->idReg1(), elemsize, true);
11432 emitDispReg(id->idReg2(), elemsize, false);
11433 break;
11434
11435 case IF_DV_2H: // DV_2H X........X...... ......nnnnnddddd Rd Vn (fmov, fcvtXX - to general)
11436 case IF_DV_2I: // DV_2I X........X...... ......nnnnnddddd Vd Rn (fmov, Xcvtf - from general)
11437 case IF_DV_2J: // DV_2J ........SS.....D D.....nnnnnddddd Vd Vn (fcvt)
11438 dstsize = optGetDstsize(id->idInsOpt());
11439 srcsize = optGetSrcsize(id->idInsOpt());
11440
11441 emitDispReg(id->idReg1(), dstsize, true);
11442 emitDispReg(id->idReg2(), srcsize, false);
11443 break;
11444
11445 case IF_DV_3A: // DV_3A .Q......XX.mmmmm ......nnnnnddddd Vd Vn Vm (vector)
11446 case IF_DV_3B: // DV_3B .Q.........mmmmm ......nnnnnddddd Vd Vn Vm (vector)
11447 emitDispVectorReg(id->idReg1(), id->idInsOpt(), true);
11448 emitDispVectorReg(id->idReg2(), id->idInsOpt(), true);
11449 emitDispVectorReg(id->idReg3(), id->idInsOpt(), false);
11450 break;
11451
11452 case IF_DV_3C: // DV_3C .Q.........mmmmm ......nnnnnddddd Vd Vn Vm (vector)
11453 emitDispVectorReg(id->idReg1(), id->idInsOpt(), true);
11454 if (ins != INS_mov)
11455 {
11456 emitDispVectorReg(id->idReg2(), id->idInsOpt(), true);
11457 }
11458 emitDispVectorReg(id->idReg3(), id->idInsOpt(), false);
11459 break;
11460
11461 case IF_DV_3AI: // DV_3AI .Q......XXLMmmmm ....H.nnnnnddddd Vd Vn Vm[] (vector by elem)
11462 case IF_DV_3BI: // DV_3BI .Q........Lmmmmm ....H.nnnnnddddd Vd Vn Vm[] (vector by elem)
11463 emitDispVectorReg(id->idReg1(), id->idInsOpt(), true);
11464 emitDispVectorReg(id->idReg2(), id->idInsOpt(), true);
11465 elemsize = optGetElemsize(id->idInsOpt());
11466 emitDispVectorRegIndex(id->idReg3(), elemsize, emitGetInsSC(id), false);
11467 break;
11468
11469 case IF_DV_3D: // DV_3D .........X.mmmmm ......nnnnnddddd Vd Vn Vm (scalar)
11470 case IF_DV_3E: // DV_3E ...........mmmmm ......nnnnnddddd Vd Vn Vm (scalar)
11471 emitDispReg(id->idReg1(), size, true);
11472 emitDispReg(id->idReg2(), size, true);
11473 emitDispReg(id->idReg3(), size, false);
11474 break;
11475
11476 case IF_DV_3F: // DV_3F ..........mmmmm ......nnnnnddddd Vd Vn Vm (vector)
11477 if ((ins == INS_sha1c) || (ins == INS_sha1m) || (ins == INS_sha1p))
11478 {
11479 // Qd, Sn, Vm (vector)
11480 emitDispReg(id->idReg1(), size, true);
11481 emitDispReg(id->idReg2(), EA_4BYTE, true);
11482 emitDispVectorReg(id->idReg3(), id->idInsOpt(), false);
11483 }
11484 else if ((ins == INS_sha256h) || (ins == INS_sha256h2))
11485 {
11486 // Qd Qn Vm (vector)
11487 emitDispReg(id->idReg1(), size, true);
11488 emitDispReg(id->idReg2(), size, true);
11489 emitDispVectorReg(id->idReg3(), id->idInsOpt(), false);
11490 }
11491 else // INS_sha1su0, INS_sha256su1
11492 {
11493 // Vd, Vn, Vm (vector)
11494 emitDispVectorReg(id->idReg1(), id->idInsOpt(), true);
11495 emitDispVectorReg(id->idReg2(), id->idInsOpt(), true);
11496 emitDispVectorReg(id->idReg3(), id->idInsOpt(), false);
11497 }
11498 break;
11499
11500 case IF_DV_3DI: // DV_3DI .........XLmmmmm ....H.nnnnnddddd Vd Vn Vm[] (scalar by elem)
11501 emitDispReg(id->idReg1(), size, true);
11502 emitDispReg(id->idReg2(), size, true);
11503 elemsize = size;
11504 emitDispVectorRegIndex(id->idReg3(), elemsize, emitGetInsSC(id), false);
11505 break;
11506
11507 case IF_DV_4A: // DV_4A .........X.mmmmm .aaaaannnnnddddd Vd Va Vn Vm (scalar)
11508 emitDispReg(id->idReg1(), size, true);
11509 emitDispReg(id->idReg2(), size, true);
11510 emitDispReg(id->idReg3(), size, true);
11511 emitDispReg(id->idReg4(), size, false);
11512 break;
11513
11514 case IF_SN_0A: // SN_0A ................ ................
11515 break;
11516
11517 case IF_SI_0A: // SI_0A ...........iiiii iiiiiiiiiii..... imm16
11518 emitDispImm(emitGetInsSC(id), false);
11519 break;
11520
11521 case IF_SI_0B: // SI_0B ................ ....bbbb........ imm4 - barrier
11522 emitDispBarrier((insBarrier)emitGetInsSC(id));
11523 break;
11524
11525 default:
11526 printf("unexpected format %s", emitIfName(id->idInsFmt()));
11527 assert(!"unexpectedFormat");
11528 break;
11529 }
11530
11531 if (id->idDebugOnlyInfo()->idVarRefOffs)
11532 {
11533 printf("\t// ");
11534 emitDispFrameRef(id->idAddr()->iiaLclVar.lvaVarNum(), id->idAddr()->iiaLclVar.lvaOffset(),
11535 id->idDebugOnlyInfo()->idVarRefOffs, asmfm);
11536 }
11537
11538 printf("\n");
11539}
11540
11541/*****************************************************************************
11542 *
11543 * Display a stack frame reference.
11544 */
11545
11546void emitter::emitDispFrameRef(int varx, int disp, int offs, bool asmfm)
11547{
11548 printf("[");
11549
11550 if (varx < 0)
11551 printf("TEMP_%02u", -varx);
11552 else
11553 emitComp->gtDispLclVar(+varx, false);
11554
11555 if (disp < 0)
11556 printf("-0x%02x", -disp);
11557 else if (disp > 0)
11558 printf("+0x%02x", +disp);
11559
11560 printf("]");
11561
11562 if (varx >= 0 && emitComp->opts.varNames)
11563 {
11564 LclVarDsc* varDsc;
11565 const char* varName;
11566
11567 assert((unsigned)varx < emitComp->lvaCount);
11568 varDsc = emitComp->lvaTable + varx;
11569 varName = emitComp->compLocalVarName(varx, offs);
11570
11571 if (varName)
11572 {
11573 printf("'%s", varName);
11574
11575 if (disp < 0)
11576 printf("-%d", -disp);
11577 else if (disp > 0)
11578 printf("+%d", +disp);
11579
11580 printf("'");
11581 }
11582 }
11583}
11584
11585#endif // DEBUG
11586
11587// Generate code for a load or store operation with a potentially complex addressing mode
11588// This method handles the case of a GT_IND with contained GT_LEA op1 of the x86 form [base + index*sccale + offset]
11589// Since Arm64 does not directly support this complex of an addressing mode
11590// we may generates up to three instructions for this for Arm64
11591//
11592void emitter::emitInsLoadStoreOp(instruction ins, emitAttr attr, regNumber dataReg, GenTreeIndir* indir)
11593{
11594 emitAttr ldstAttr = isVectorRegister(dataReg) ? attr : emitInsAdjustLoadStoreAttr(ins, attr);
11595
11596 GenTree* addr = indir->Addr();
11597
11598 if (addr->isContained())
11599 {
11600 assert(addr->OperGet() == GT_LCL_VAR_ADDR || addr->OperGet() == GT_LEA);
11601
11602 int offset = 0;
11603 DWORD lsl = 0;
11604
11605 if (addr->OperGet() == GT_LEA)
11606 {
11607 offset = addr->AsAddrMode()->Offset();
11608 if (addr->AsAddrMode()->gtScale > 0)
11609 {
11610 assert(isPow2(addr->AsAddrMode()->gtScale));
11611 BitScanForward(&lsl, addr->AsAddrMode()->gtScale);
11612 }
11613 }
11614
11615 GenTree* memBase = indir->Base();
11616
11617 if (indir->HasIndex())
11618 {
11619 GenTree* index = indir->Index();
11620
11621 if (offset != 0)
11622 {
11623 regNumber tmpReg = indir->GetSingleTempReg();
11624
11625 emitAttr addType = varTypeIsGC(memBase) ? EA_BYREF : EA_PTRSIZE;
11626
11627 if (emitIns_valid_imm_for_add(offset, EA_8BYTE))
11628 {
11629 if (lsl > 0)
11630 {
11631 // Generate code to set tmpReg = base + index*scale
11632 emitIns_R_R_R_I(INS_add, addType, tmpReg, memBase->gtRegNum, index->gtRegNum, lsl,
11633 INS_OPTS_LSL);
11634 }
11635 else // no scale
11636 {
11637 // Generate code to set tmpReg = base + index
11638 emitIns_R_R_R(INS_add, addType, tmpReg, memBase->gtRegNum, index->gtRegNum);
11639 }
11640
11641 noway_assert(emitInsIsLoad(ins) || (tmpReg != dataReg));
11642
11643 // Then load/store dataReg from/to [tmpReg + offset]
11644 emitIns_R_R_I(ins, ldstAttr, dataReg, tmpReg, offset);
11645 }
11646 else // large offset
11647 {
11648 // First load/store tmpReg with the large offset constant
11649 codeGen->instGen_Set_Reg_To_Imm(EA_PTRSIZE, tmpReg, offset);
11650 // Then add the base register
11651 // rd = rd + base
11652 emitIns_R_R_R(INS_add, addType, tmpReg, tmpReg, memBase->gtRegNum);
11653
11654 noway_assert(emitInsIsLoad(ins) || (tmpReg != dataReg));
11655 noway_assert(tmpReg != index->gtRegNum);
11656
11657 // Then load/store dataReg from/to [tmpReg + index*scale]
11658 emitIns_R_R_R_I(ins, ldstAttr, dataReg, tmpReg, index->gtRegNum, lsl, INS_OPTS_LSL);
11659 }
11660 }
11661 else // (offset == 0)
11662 {
11663 if (lsl > 0)
11664 {
11665 // Then load/store dataReg from/to [memBase + index*scale]
11666 emitIns_R_R_R_I(ins, ldstAttr, dataReg, memBase->gtRegNum, index->gtRegNum, lsl, INS_OPTS_LSL);
11667 }
11668 else // no scale
11669 {
11670 // Then load/store dataReg from/to [memBase + index]
11671 emitIns_R_R_R(ins, ldstAttr, dataReg, memBase->gtRegNum, index->gtRegNum);
11672 }
11673 }
11674 }
11675 else // no Index register
11676 {
11677 if (emitIns_valid_imm_for_ldst_offset(offset, EA_SIZE(attr)))
11678 {
11679 // Then load/store dataReg from/to [memBase + offset]
11680 emitIns_R_R_I(ins, ldstAttr, dataReg, memBase->gtRegNum, offset);
11681 }
11682 else
11683 {
11684 // We require a tmpReg to hold the offset
11685 regNumber tmpReg = indir->GetSingleTempReg();
11686
11687 // First load/store tmpReg with the large offset constant
11688 codeGen->instGen_Set_Reg_To_Imm(EA_PTRSIZE, tmpReg, offset);
11689
11690 // Then load/store dataReg from/to [memBase + tmpReg]
11691 emitIns_R_R_R(ins, ldstAttr, dataReg, memBase->gtRegNum, tmpReg);
11692 }
11693 }
11694 }
11695 else // addr is not contained, so we evaluate it into a register
11696 {
11697 // Then load/store dataReg from/to [addrReg]
11698 emitIns_R_R(ins, ldstAttr, dataReg, addr->gtRegNum);
11699 }
11700}
11701
11702// The callee must call genConsumeReg() for any non-contained srcs
11703// and genProduceReg() for any non-contained dsts.
11704
11705regNumber emitter::emitInsBinary(instruction ins, emitAttr attr, GenTree* dst, GenTree* src)
11706{
11707 regNumber result = REG_NA;
11708
11709 // dst can only be a reg
11710 assert(!dst->isContained());
11711
11712 // src can be immed or reg
11713 assert(!src->isContained() || src->isContainedIntOrIImmed());
11714
11715 // find immed (if any) - it cannot be a dst
11716 GenTreeIntConCommon* intConst = nullptr;
11717 if (src->isContainedIntOrIImmed())
11718 {
11719 intConst = src->AsIntConCommon();
11720 }
11721
11722 if (intConst)
11723 {
11724 emitIns_R_I(ins, attr, dst->gtRegNum, intConst->IconValue());
11725 return dst->gtRegNum;
11726 }
11727 else
11728 {
11729 emitIns_R_R(ins, attr, dst->gtRegNum, src->gtRegNum);
11730 return dst->gtRegNum;
11731 }
11732}
11733
11734// The callee must call genConsumeReg() for any non-contained srcs
11735// and genProduceReg() for any non-contained dsts.
11736
11737regNumber emitter::emitInsTernary(instruction ins, emitAttr attr, GenTree* dst, GenTree* src1, GenTree* src2)
11738{
11739 regNumber result = REG_NA;
11740
11741 // dst can only be a reg
11742 assert(!dst->isContained());
11743
11744 // find immed (if any) - it cannot be a dst
11745 // Only one src can be an int.
11746 GenTreeIntConCommon* intConst = nullptr;
11747 GenTree* nonIntReg = nullptr;
11748
11749 if (varTypeIsFloating(dst))
11750 {
11751 // src1 can only be a reg
11752 assert(!src1->isContained());
11753 // src2 can only be a reg
11754 assert(!src2->isContained());
11755 }
11756 else // not floating point
11757 {
11758 // src2 can be immed or reg
11759 assert(!src2->isContained() || src2->isContainedIntOrIImmed());
11760
11761 // Check src2 first as we can always allow it to be a contained immediate
11762 if (src2->isContainedIntOrIImmed())
11763 {
11764 intConst = src2->AsIntConCommon();
11765 nonIntReg = src1;
11766 }
11767 // Only for commutative operations do we check src1 and allow it to be a contained immediate
11768 else if (dst->OperIsCommutative())
11769 {
11770 // src1 can be immed or reg
11771 assert(!src1->isContained() || src1->isContainedIntOrIImmed());
11772
11773 // Check src1 and allow it to be a contained immediate
11774 if (src1->isContainedIntOrIImmed())
11775 {
11776 assert(!src2->isContainedIntOrIImmed());
11777 intConst = src1->AsIntConCommon();
11778 nonIntReg = src2;
11779 }
11780 }
11781 else
11782 {
11783 // src1 can only be a reg
11784 assert(!src1->isContained());
11785 }
11786 }
11787
11788 bool isMulOverflow = false;
11789 if (dst->gtOverflowEx())
11790 {
11791 if ((ins == INS_add) || (ins == INS_adds))
11792 {
11793 ins = INS_adds;
11794 }
11795 else if ((ins == INS_sub) || (ins == INS_subs))
11796 {
11797 ins = INS_subs;
11798 }
11799 else if (ins == INS_mul)
11800 {
11801 isMulOverflow = true;
11802 assert(intConst == nullptr); // overflow format doesn't support an int constant operand
11803 }
11804 else
11805 {
11806 assert(!"Invalid ins for overflow check");
11807 }
11808 }
11809 if (intConst != nullptr)
11810 {
11811 emitIns_R_R_I(ins, attr, dst->gtRegNum, nonIntReg->gtRegNum, intConst->IconValue());
11812 }
11813 else
11814 {
11815 if (isMulOverflow)
11816 {
11817 regNumber extraReg = dst->GetSingleTempReg();
11818 assert(extraReg != dst->gtRegNum);
11819
11820 if ((dst->gtFlags & GTF_UNSIGNED) != 0)
11821 {
11822 if (attr == EA_4BYTE)
11823 {
11824 // Compute 8 byte results from 4 byte by 4 byte multiplication.
11825 emitIns_R_R_R(INS_umull, EA_8BYTE, dst->gtRegNum, src1->gtRegNum, src2->gtRegNum);
11826
11827 // Get the high result by shifting dst.
11828 emitIns_R_R_I(INS_lsr, EA_8BYTE, extraReg, dst->gtRegNum, 32);
11829 }
11830 else
11831 {
11832 assert(attr == EA_8BYTE);
11833 // Compute the high result.
11834 emitIns_R_R_R(INS_umulh, attr, extraReg, src1->gtRegNum, src2->gtRegNum);
11835
11836 // Now multiply without skewing the high result.
11837 emitIns_R_R_R(ins, attr, dst->gtRegNum, src1->gtRegNum, src2->gtRegNum);
11838 }
11839
11840 // zero-sign bit comparison to detect overflow.
11841 emitIns_R_I(INS_cmp, attr, extraReg, 0);
11842 }
11843 else
11844 {
11845 int bitShift = 0;
11846 if (attr == EA_4BYTE)
11847 {
11848 // Compute 8 byte results from 4 byte by 4 byte multiplication.
11849 emitIns_R_R_R(INS_smull, EA_8BYTE, dst->gtRegNum, src1->gtRegNum, src2->gtRegNum);
11850
11851 // Get the high result by shifting dst.
11852 emitIns_R_R_I(INS_lsr, EA_8BYTE, extraReg, dst->gtRegNum, 32);
11853
11854 bitShift = 31;
11855 }
11856 else
11857 {
11858 assert(attr == EA_8BYTE);
11859 // Save the high result in a temporary register.
11860 emitIns_R_R_R(INS_smulh, attr, extraReg, src1->gtRegNum, src2->gtRegNum);
11861
11862 // Now multiply without skewing the high result.
11863 emitIns_R_R_R(ins, attr, dst->gtRegNum, src1->gtRegNum, src2->gtRegNum);
11864
11865 bitShift = 63;
11866 }
11867
11868 // Sign bit comparison to detect overflow.
11869 emitIns_R_R_I(INS_cmp, attr, extraReg, dst->gtRegNum, bitShift, INS_OPTS_ASR);
11870 }
11871 }
11872 else
11873 {
11874 // We can just multiply.
11875 emitIns_R_R_R(ins, attr, dst->gtRegNum, src1->gtRegNum, src2->gtRegNum);
11876 }
11877 }
11878
11879 if (dst->gtOverflowEx())
11880 {
11881 assert(!varTypeIsFloating(dst));
11882 codeGen->genCheckOverflow(dst);
11883 }
11884
11885 return dst->gtRegNum;
11886}
11887
11888#endif // defined(_TARGET_ARM64_)
11889