5463e2a5f46409a6198454f96a15326f5d0d3207
[platform/upstream/coreclr.git] / src / jit / codegenarm64.cpp
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
6 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7 XX                                                                           XX
8 XX                        Arm64 Code Generator                               XX
9 XX                                                                           XX
10 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
11 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
12 */
13 #include "jitpch.h"
14 #ifdef _MSC_VER
15 #pragma hdrstop
16 #endif
17
18 #ifndef LEGACY_BACKEND // This file is ONLY used for the RyuJIT backend that uses the linear scan register allocator
19
20 #ifdef _TARGET_ARM64_
21 #include "emit.h"
22 #include "codegen.h"
23 #include "lower.h"
24 #include "gcinfo.h"
25 #include "gcinfoencoder.h"
26
27 /*
28 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
29 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
30 XX                                                                           XX
31 XX                           Prolog / Epilog                                 XX
32 XX                                                                           XX
33 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
34 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
35 */
36
37 //------------------------------------------------------------------------
38 // genInstrWithConstant:   we will typically generate one instruction
39 //
40 //    ins  reg1, reg2, imm
41 //
42 // However the imm might not fit as a directly encodable immediate,
43 // when it doesn't fit we generate extra instruction(s) that sets up
44 // the 'regTmp' with the proper immediate value.
45 //
46 //     mov  regTmp, imm
47 //     ins  reg1, reg2, regTmp
48 //
49 // Arguments:
50 //    ins                 - instruction
51 //    attr                - operation size and GC attribute
52 //    reg1, reg2          - first and second register operands
53 //    imm                 - immediate value (third operand when it fits)
54 //    tmpReg              - temp register to use when the 'imm' doesn't fit
55 //    inUnwindRegion      - true if we are in a prolog/epilog region with unwind codes
56 //
57 // Return Value:
58 //    returns true if the immediate was too large and tmpReg was used and modified.
59 //
60 bool CodeGen::genInstrWithConstant(instruction ins,
61                                    emitAttr    attr,
62                                    regNumber   reg1,
63                                    regNumber   reg2,
64                                    ssize_t     imm,
65                                    regNumber   tmpReg,
66                                    bool        inUnwindRegion /* = false */)
67 {
68     bool     immFitsInIns = false;
69     emitAttr size         = EA_SIZE(attr);
70
71     // reg1 is usually a dest register
72     // reg2 is always source register
73     assert(tmpReg != reg2); // regTmp can not match any source register
74
75     switch (ins)
76     {
77         case INS_add:
78         case INS_sub:
79             if (imm < 0)
80             {
81                 imm = -imm;
82                 ins = (ins == INS_add) ? INS_sub : INS_add;
83             }
84             immFitsInIns = emitter::emitIns_valid_imm_for_add(imm, size);
85             break;
86
87         case INS_strb:
88         case INS_strh:
89         case INS_str:
90             // reg1 is a source register for store instructions
91             assert(tmpReg != reg1); // regTmp can not match any source register
92             immFitsInIns = emitter::emitIns_valid_imm_for_ldst_offset(imm, size);
93             break;
94
95         case INS_ldrsb:
96         case INS_ldrsh:
97         case INS_ldrsw:
98         case INS_ldrb:
99         case INS_ldrh:
100         case INS_ldr:
101             immFitsInIns = emitter::emitIns_valid_imm_for_ldst_offset(imm, size);
102             break;
103
104         default:
105             assert(!"Unexpected instruction in genInstrWithConstant");
106             break;
107     }
108
109     if (immFitsInIns)
110     {
111         // generate a single instruction that encodes the immediate directly
112         getEmitter()->emitIns_R_R_I(ins, attr, reg1, reg2, imm);
113     }
114     else
115     {
116         // caller can specify REG_NA  for tmpReg, when it "knows" that the immediate will always fit
117         assert(tmpReg != REG_NA);
118
119         // generate two or more instructions
120
121         // first we load the immediate into tmpReg
122         instGen_Set_Reg_To_Imm(size, tmpReg, imm);
123         regTracker.rsTrackRegTrash(tmpReg);
124
125         // when we are in an unwind code region
126         // we record the extra instructions using unwindPadding()
127         if (inUnwindRegion)
128         {
129             compiler->unwindPadding();
130         }
131
132         // generate the instruction using a three register encoding with the immediate in tmpReg
133         getEmitter()->emitIns_R_R_R(ins, attr, reg1, reg2, tmpReg);
134     }
135     return immFitsInIns;
136 }
137
138 //------------------------------------------------------------------------
139 // genStackPointerAdjustment: add a specified constant value to the stack pointer in either the prolog
140 // or the epilog. The unwind codes for the generated instructions are produced. An available temporary
141 // register is required to be specified, in case the constant is too large to encode in an "add"
142 // instruction (or "sub" instruction if we choose to use one), such that we need to load the constant
143 // into a register first, before using it.
144 //
145 // Arguments:
146 //    spDelta                 - the value to add to SP (can be negative)
147 //    tmpReg                  - an available temporary register
148 //    pTmpRegIsZero           - If we use tmpReg, and pTmpRegIsZero is non-null, we set *pTmpRegIsZero to 'false'.
149 //                              Otherwise, we don't touch it.
150 //
151 // Return Value:
152 //    None.
153
154 void CodeGen::genStackPointerAdjustment(ssize_t spDelta, regNumber tmpReg, bool* pTmpRegIsZero)
155 {
156     // Even though INS_add is specified here, the encoder will choose either
157     // an INS_add or an INS_sub and encode the immediate as a positive value
158     //
159     if (genInstrWithConstant(INS_add, EA_PTRSIZE, REG_SPBASE, REG_SPBASE, spDelta, tmpReg, true))
160     {
161         if (pTmpRegIsZero != nullptr)
162         {
163             *pTmpRegIsZero = false;
164         }
165     }
166
167     // spDelta is negative in the prolog, positive in the epilog, but we always tell the unwind codes the positive
168     // value.
169     ssize_t  spDeltaAbs    = abs(spDelta);
170     unsigned unwindSpDelta = (unsigned)spDeltaAbs;
171     assert((ssize_t)unwindSpDelta == spDeltaAbs); // make sure that it fits in a unsigned
172
173     compiler->unwindAllocStack(unwindSpDelta);
174 }
175
176 //------------------------------------------------------------------------
177 // genPrologSaveRegPair: Save a pair of general-purpose or floating-point/SIMD registers in a function or funclet
178 // prolog. If possible, we use pre-indexed addressing to adjust SP and store the registers with a single instruction.
179 // The caller must ensure that we can use the STP instruction, and that spOffset will be in the legal range for that
180 // instruction.
181 //
182 // Arguments:
183 //    reg1                     - First register of pair to save.
184 //    reg2                     - Second register of pair to save.
185 //    spOffset                 - The offset from SP to store reg1 (must be positive or zero).
186 //    spDelta                  - If non-zero, the amount to add to SP before the register saves (must be negative or
187 //                               zero).
188 //    lastSavedWasPreviousPair - True if the last prolog instruction was to save the previous register pair. This
189 //                               allows us to emit the "save_next" unwind code.
190 //    tmpReg                   - An available temporary register. Needed for the case of large frames.
191 //    pTmpRegIsZero            - If we use tmpReg, and pTmpRegIsZero is non-null, we set *pTmpRegIsZero to 'false'.
192 //                               Otherwise, we don't touch it.
193 //
194 // Return Value:
195 //    None.
196
197 void CodeGen::genPrologSaveRegPair(regNumber reg1,
198                                    regNumber reg2,
199                                    int       spOffset,
200                                    int       spDelta,
201                                    bool      lastSavedWasPreviousPair,
202                                    regNumber tmpReg,
203                                    bool*     pTmpRegIsZero)
204 {
205     assert(spOffset >= 0);
206     assert(spDelta <= 0);
207     assert((spDelta % 16) == 0);                                  // SP changes must be 16-byte aligned
208     assert(genIsValidFloatReg(reg1) == genIsValidFloatReg(reg2)); // registers must be both general-purpose, or both
209                                                                   // FP/SIMD
210
211     bool needToSaveRegs = true;
212     if (spDelta != 0)
213     {
214         if ((spOffset == 0) && (spDelta >= -512))
215         {
216             // We can use pre-indexed addressing.
217             // stp REG, REG + 1, [SP, #spDelta]!
218             // 64-bit STP offset range: -512 to 504, multiple of 8.
219             getEmitter()->emitIns_R_R_R_I(INS_stp, EA_PTRSIZE, reg1, reg2, REG_SPBASE, spDelta, INS_OPTS_PRE_INDEX);
220             compiler->unwindSaveRegPairPreindexed(reg1, reg2, spDelta);
221
222             needToSaveRegs = false;
223         }
224         else // (spDelta < -512))
225         {
226             // We need to do SP adjustment separately from the store; we can't fold in a pre-indexed addressing and the
227             // non-zero offset.
228
229             // generate sub SP,SP,imm
230             genStackPointerAdjustment(spDelta, tmpReg, pTmpRegIsZero);
231         }
232     }
233
234     if (needToSaveRegs)
235     {
236         // stp REG, REG + 1, [SP, #offset]
237         // 64-bit STP offset range: -512 to 504, multiple of 8.
238         assert(spOffset <= 504);
239         getEmitter()->emitIns_R_R_R_I(INS_stp, EA_PTRSIZE, reg1, reg2, REG_SPBASE, spOffset);
240
241         if (lastSavedWasPreviousPair)
242         {
243             // This works as long as we've only been saving pairs, in order, and we've saved the previous one just
244             // before this one.
245             compiler->unwindSaveNext();
246         }
247         else
248         {
249             compiler->unwindSaveRegPair(reg1, reg2, spOffset);
250         }
251     }
252 }
253
254 //------------------------------------------------------------------------
255 // genPrologSaveReg: Like genPrologSaveRegPair, but for a single register. Save a single general-purpose or
256 // floating-point/SIMD register in a function or funclet prolog. Note that if we wish to change SP (i.e., spDelta != 0),
257 // then spOffset must be 8. This is because otherwise we would create an alignment hole above the saved register, not
258 // below it, which we currently don't support. This restriction could be loosened if the callers change to handle it
259 // (and this function changes to support using pre-indexed STR addressing). The caller must ensure that we can use the
260 // STR instruction, and that spOffset will be in the legal range for that instruction.
261 //
262 // Arguments:
263 //    reg1                     - Register to save.
264 //    spOffset                 - The offset from SP to store reg1 (must be positive or zero).
265 //    spDelta                  - If non-zero, the amount to add to SP before the register saves (must be negative or
266 //                               zero).
267 //    tmpReg                   - An available temporary register. Needed for the case of large frames.
268 //    pTmpRegIsZero            - If we use tmpReg, and pTmpRegIsZero is non-null, we set *pTmpRegIsZero to 'false'.
269 //                               Otherwise, we don't touch it.
270 //
271 // Return Value:
272 //    None.
273
274 void CodeGen::genPrologSaveReg(regNumber reg1, int spOffset, int spDelta, regNumber tmpReg, bool* pTmpRegIsZero)
275 {
276     assert(spOffset >= 0);
277     assert(spDelta <= 0);
278     assert((spDelta % 16) == 0); // SP changes must be 16-byte aligned
279
280     if (spDelta != 0)
281     {
282         // generate sub SP,SP,imm
283         genStackPointerAdjustment(spDelta, tmpReg, pTmpRegIsZero);
284     }
285
286     // str REG, [SP, #offset]
287     // 64-bit STR offset range: 0 to 32760, multiple of 8.
288     getEmitter()->emitIns_R_R_I(INS_str, EA_PTRSIZE, reg1, REG_SPBASE, spOffset);
289     compiler->unwindSaveReg(reg1, spOffset);
290 }
291
292 //------------------------------------------------------------------------
293 // genEpilogRestoreRegPair: This is the opposite of genPrologSaveRegPair(), run in the epilog instead of the prolog.
294 // The stack pointer adjustment, if requested, is done after the register restore, using post-index addressing.
295 // The caller must ensure that we can use the LDP instruction, and that spOffset will be in the legal range for that
296 // instruction.
297 //
298 // Arguments:
299 //    reg1                     - First register of pair to restore.
300 //    reg2                     - Second register of pair to restore.
301 //    spOffset                 - The offset from SP to load reg1 (must be positive or zero).
302 //    spDelta                  - If non-zero, the amount to add to SP after the register restores (must be positive or
303 //                               zero).
304 //    tmpReg                   - An available temporary register. Needed for the case of large frames.
305 //    pTmpRegIsZero            - If we use tmpReg, and pTmpRegIsZero is non-null, we set *pTmpRegIsZero to 'false'.
306 //                               Otherwise, we don't touch it.
307 //
308 // Return Value:
309 //    None.
310
311 void CodeGen::genEpilogRestoreRegPair(
312     regNumber reg1, regNumber reg2, int spOffset, int spDelta, regNumber tmpReg, bool* pTmpRegIsZero)
313 {
314     assert(spOffset >= 0);
315     assert(spDelta >= 0);
316     assert((spDelta % 16) == 0); // SP changes must be 16-byte aligned
317
318     if (spDelta != 0)
319     {
320         if ((spOffset == 0) && (spDelta <= 504))
321         {
322             // Fold the SP change into this instruction.
323             // ldp reg1, reg2, [SP], #spDelta
324             getEmitter()->emitIns_R_R_R_I(INS_ldp, EA_PTRSIZE, reg1, reg2, REG_SPBASE, spDelta, INS_OPTS_POST_INDEX);
325             compiler->unwindSaveRegPairPreindexed(reg1, reg2, -spDelta);
326         }
327         else // (spDelta > 504))
328         {
329             // Can't fold in the SP change; need to use a separate ADD instruction.
330
331             // ldp reg1, reg2, [SP, #offset]
332             getEmitter()->emitIns_R_R_R_I(INS_ldp, EA_PTRSIZE, reg1, reg2, REG_SPBASE, spOffset);
333             compiler->unwindSaveRegPair(reg1, reg2, spOffset);
334
335             // generate add SP,SP,imm
336             genStackPointerAdjustment(spDelta, tmpReg, pTmpRegIsZero);
337         }
338     }
339     else
340     {
341         // ldp reg1, reg2, [SP, #offset]
342         getEmitter()->emitIns_R_R_R_I(INS_ldp, EA_PTRSIZE, reg1, reg2, REG_SPBASE, spOffset);
343         compiler->unwindSaveRegPair(reg1, reg2, spOffset);
344     }
345 }
346
347 //------------------------------------------------------------------------
348 // genEpilogRestoreReg: The opposite of genPrologSaveReg(), run in the epilog instead of the prolog.
349 //
350 // Arguments:
351 //    reg1                     - Register to restore.
352 //    spOffset                 - The offset from SP to restore reg1 (must be positive or zero).
353 //    spDelta                  - If non-zero, the amount to add to SP after the register restores (must be positive or
354 //                               zero).
355 //    tmpReg                   - An available temporary register. Needed for the case of large frames.
356 //    pTmpRegIsZero            - If we use tmpReg, and pTmpRegIsZero is non-null, we set *pTmpRegIsZero to 'false'.
357 //                               Otherwise, we don't touch it.
358 //
359 // Return Value:
360 //    None.
361
362 void CodeGen::genEpilogRestoreReg(regNumber reg1, int spOffset, int spDelta, regNumber tmpReg, bool* pTmpRegIsZero)
363 {
364     assert(spOffset >= 0);
365     assert(spDelta >= 0);
366     assert((spDelta % 16) == 0); // SP changes must be 16-byte aligned
367
368     // ldr reg1, [SP, #offset]
369     getEmitter()->emitIns_R_R_I(INS_ldr, EA_PTRSIZE, reg1, REG_SPBASE, spOffset);
370     compiler->unwindSaveReg(reg1, spOffset);
371
372     if (spDelta != 0)
373     {
374         // generate add SP,SP,imm
375         genStackPointerAdjustment(spDelta, tmpReg, pTmpRegIsZero);
376     }
377 }
378
379 //------------------------------------------------------------------------
380 // genSaveCalleeSavedRegistersHelp: Save the callee-saved registers in 'regsToSaveMask' to the stack frame
381 // in the function or funclet prolog. The save set does not contain FP, since that is
382 // guaranteed to be saved separately, so we can set up chaining. We can only use the instructions
383 // that are allowed by the unwind codes. Integer registers are stored at lower addresses,
384 // FP/SIMD registers are stored at higher addresses. There are no gaps. The caller ensures that
385 // there is enough space on the frame to store these registers, and that the store instructions
386 // we need to use (STR or STP) are encodable with the stack-pointer immediate offsets we need to
387 // use. Note that the save set can contain LR if this is a frame without a frame pointer, in
388 // which case LR is saved along with the other callee-saved registers. The caller can tell us
389 // to fold in a stack pointer adjustment, which we will do with the first instruction. Note that
390 // the stack pointer adjustment must be by a multiple of 16 to preserve the invariant that the
391 // stack pointer is always 16 byte aligned. If we are saving an odd number of callee-saved
392 // registers, though, we will have an empty aligment slot somewhere. It turns out we will put
393 // it below (at a lower address) the callee-saved registers, as that is currently how we
394 // do frame layout. This means that the first stack offset will be 8 and the stack pointer
395 // adjustment must be done by a SUB, and not folded in to a pre-indexed store.
396 //
397 // Arguments:
398 //    regsToSaveMask          - The mask of callee-saved registers to save. If empty, this function does nothing.
399 //    lowestCalleeSavedOffset - The offset from SP that is the beginning of the callee-saved register area. Note that
400 //                              if non-zero spDelta, then this is the offset of the first save *after* that
401 //                              SP adjustment.
402 //    spDelta                 - If non-zero, the amount to add to SP before the register saves (must be negative or
403 //                              zero).
404 //
405 // Return Value:
406 //    None.
407
408 void CodeGen::genSaveCalleeSavedRegistersHelp(regMaskTP regsToSaveMask, int lowestCalleeSavedOffset, int spDelta)
409 {
410     assert(spDelta <= 0);
411     unsigned regsToSaveCount = genCountBits(regsToSaveMask);
412     if (regsToSaveCount == 0)
413     {
414         if (spDelta != 0)
415         {
416             // Currently this is the case for varargs only
417             // whose size is MAX_REG_ARG * REGSIZE_BYTES = 64 bytes.
418             genStackPointerAdjustment(spDelta, REG_NA, nullptr);
419         }
420         return;
421     }
422
423     assert((spDelta % 16) == 0);
424     assert((regsToSaveMask & RBM_FP) == 0);                             // we never save FP here
425     assert(regsToSaveCount <= genCountBits(RBM_CALLEE_SAVED | RBM_LR)); // We also save LR, even though it is not in
426                                                                         // RBM_CALLEE_SAVED.
427
428     regMaskTP maskSaveRegsFloat = regsToSaveMask & RBM_ALLFLOAT;
429     regMaskTP maskSaveRegsInt   = regsToSaveMask & ~maskSaveRegsFloat;
430
431     int spOffset = lowestCalleeSavedOffset; // this is the offset *after* we change SP.
432
433     unsigned intRegsToSaveCount   = genCountBits(maskSaveRegsInt);
434     unsigned floatRegsToSaveCount = genCountBits(maskSaveRegsFloat);
435     bool     isPairSave           = false;
436 #ifdef DEBUG
437     bool isRegsToSaveCountOdd = ((intRegsToSaveCount + floatRegsToSaveCount) % 2 != 0);
438 #endif
439
440     // Save the integer registers
441
442     bool lastSavedWasPair = false;
443
444     while (maskSaveRegsInt != RBM_NONE)
445     {
446         // If this is the first store that needs to change SP (spDelta != 0),
447         // then the offset must be 8 to account for alignment for the odd count
448         // or it must be 0 for the even count.
449         assert((spDelta == 0) || (isRegsToSaveCountOdd && spOffset == REGSIZE_BYTES) ||
450                (!isRegsToSaveCountOdd && spOffset == 0));
451
452         isPairSave         = (intRegsToSaveCount >= 2);
453         regMaskTP reg1Mask = genFindLowestBit(maskSaveRegsInt);
454         regNumber reg1     = genRegNumFromMask(reg1Mask);
455         maskSaveRegsInt &= ~reg1Mask;
456         intRegsToSaveCount -= 1;
457
458         if (isPairSave)
459         {
460             // We can use a STP instruction.
461
462             regMaskTP reg2Mask = genFindLowestBit(maskSaveRegsInt);
463             regNumber reg2     = genRegNumFromMask(reg2Mask);
464             assert((reg2 == REG_NEXT(reg1)) || (reg2 == REG_LR));
465             maskSaveRegsInt &= ~reg2Mask;
466             intRegsToSaveCount -= 1;
467
468             genPrologSaveRegPair(reg1, reg2, spOffset, spDelta, lastSavedWasPair, REG_IP0, nullptr);
469
470             // TODO-ARM64-CQ: this code works in the prolog, but it's a bit weird to think about "next" when generating
471             // this epilog, to get the codes to match. Turn this off until that is better understood.
472             // lastSavedWasPair = true;
473
474             spOffset += 2 * REGSIZE_BYTES;
475         }
476         else
477         {
478             // No register pair; we use a STR instruction.
479
480             genPrologSaveReg(reg1, spOffset, spDelta, REG_IP0, nullptr);
481
482             lastSavedWasPair = false;
483             spOffset += REGSIZE_BYTES;
484         }
485
486         spDelta = 0; // We've now changed SP already, if necessary; don't do it again.
487     }
488
489     assert(intRegsToSaveCount == 0);
490
491     // Save the floating-point/SIMD registers
492
493     lastSavedWasPair = false;
494
495     while (maskSaveRegsFloat != RBM_NONE)
496     {
497         // If this is the first store that needs to change SP (spDelta != 0),
498         // then the offset must be 8 to account for alignment for the odd count
499         // or it must be 0 for the even count.
500         assert((spDelta == 0) || (isRegsToSaveCountOdd && spOffset == REGSIZE_BYTES) ||
501                (!isRegsToSaveCountOdd && spOffset == 0));
502
503         isPairSave         = (floatRegsToSaveCount >= 2);
504         regMaskTP reg1Mask = genFindLowestBit(maskSaveRegsFloat);
505         regNumber reg1     = genRegNumFromMask(reg1Mask);
506         maskSaveRegsFloat &= ~reg1Mask;
507         floatRegsToSaveCount -= 1;
508
509         if (isPairSave)
510         {
511             // We can use a STP instruction.
512
513             regMaskTP reg2Mask = genFindLowestBit(maskSaveRegsFloat);
514             regNumber reg2     = genRegNumFromMask(reg2Mask);
515             assert(reg2 == REG_NEXT(reg1));
516             maskSaveRegsFloat &= ~reg2Mask;
517             floatRegsToSaveCount -= 1;
518
519             genPrologSaveRegPair(reg1, reg2, spOffset, spDelta, lastSavedWasPair, REG_IP0, nullptr);
520
521             // TODO-ARM64-CQ: this code works in the prolog, but it's a bit weird to think about "next" when generating
522             // this epilog, to get the codes to match. Turn this off until that is better understood.
523             // lastSavedWasPair = true;
524
525             spOffset += 2 * FPSAVE_REGSIZE_BYTES;
526         }
527         else
528         {
529             // No register pair; we use a STR instruction.
530
531             genPrologSaveReg(reg1, spOffset, spDelta, REG_IP0, nullptr);
532
533             lastSavedWasPair = false;
534             spOffset += FPSAVE_REGSIZE_BYTES;
535         }
536
537         spDelta = 0; // We've now changed SP already, if necessary; don't do it again.
538     }
539
540     assert(floatRegsToSaveCount == 0);
541 }
542
543 //------------------------------------------------------------------------
544 // genRestoreCalleeSavedRegistersHelp: Restore the callee-saved registers in 'regsToRestoreMask' from the stack frame
545 // in the function or funclet epilog. This exactly reverses the actions of genSaveCalleeSavedRegistersHelp().
546 //
547 // Arguments:
548 //    regsToRestoreMask       - The mask of callee-saved registers to restore. If empty, this function does nothing.
549 //    lowestCalleeSavedOffset - The offset from SP that is the beginning of the callee-saved register area.
550 //    spDelta                 - If non-zero, the amount to add to SP after the register restores (must be positive or
551 //                              zero).
552 //
553 // Here's an example restore sequence:
554 //      ldp     x27, x28, [sp,#96]
555 //      ldp     x25, x26, [sp,#80]
556 //      ldp     x23, x24, [sp,#64]
557 //      ldp     x21, x22, [sp,#48]
558 //      ldp     x19, x20, [sp,#32]
559 //
560 // For the case of non-zero spDelta, we assume the base of the callee-save registers to restore is at SP, and
561 // the last restore adjusts SP by the specified amount. For example:
562 //      ldp     x27, x28, [sp,#64]
563 //      ldp     x25, x26, [sp,#48]
564 //      ldp     x23, x24, [sp,#32]
565 //      ldp     x21, x22, [sp,#16]
566 //      ldp     x19, x20, [sp], #80
567 //
568 // Note you call the unwind functions specifying the prolog operation that is being un-done. So, for example, when
569 // generating a post-indexed load, you call the unwind function for specifying the corresponding preindexed store.
570 //
571 // Return Value:
572 //    None.
573
574 void CodeGen::genRestoreCalleeSavedRegistersHelp(regMaskTP regsToRestoreMask, int lowestCalleeSavedOffset, int spDelta)
575 {
576     assert(spDelta >= 0);
577     unsigned regsToRestoreCount = genCountBits(regsToRestoreMask);
578     if (regsToRestoreCount == 0)
579     {
580         if (spDelta != 0)
581         {
582             // Currently this is the case for varargs only
583             // whose size is MAX_REG_ARG * REGSIZE_BYTES = 64 bytes.
584             genStackPointerAdjustment(spDelta, REG_NA, nullptr);
585         }
586         return;
587     }
588
589     assert((spDelta % 16) == 0);
590     assert((regsToRestoreMask & RBM_FP) == 0); // we never restore FP here
591     assert(regsToRestoreCount <=
592            genCountBits(RBM_CALLEE_SAVED | RBM_LR)); // We also save LR, even though it is not in RBM_CALLEE_SAVED.
593
594     regMaskTP maskRestoreRegsFloat = regsToRestoreMask & RBM_ALLFLOAT;
595     regMaskTP maskRestoreRegsInt   = regsToRestoreMask & ~maskRestoreRegsFloat;
596
597     assert(REGSIZE_BYTES == FPSAVE_REGSIZE_BYTES);
598     int spOffset = lowestCalleeSavedOffset + regsToRestoreCount * REGSIZE_BYTES; // Point past the end, to start. We
599                                                                                  // predecrement to find the offset to
600                                                                                  // load from.
601
602     unsigned floatRegsToRestoreCount         = genCountBits(maskRestoreRegsFloat);
603     unsigned intRegsToRestoreCount           = genCountBits(maskRestoreRegsInt);
604     int      stackDelta                      = 0;
605     bool     isPairRestore                   = false;
606     bool     thisIsTheLastRestoreInstruction = false;
607 #ifdef DEBUG
608     bool isRegsToRestoreCountOdd = ((floatRegsToRestoreCount + intRegsToRestoreCount) % 2 != 0);
609 #endif
610
611     // We want to restore in the opposite order we saved, so the unwind codes match. Be careful to handle odd numbers of
612     // callee-saved registers properly.
613
614     // Restore the floating-point/SIMD registers
615
616     while (maskRestoreRegsFloat != RBM_NONE)
617     {
618         thisIsTheLastRestoreInstruction = (floatRegsToRestoreCount <= 2) && (maskRestoreRegsInt == RBM_NONE);
619         isPairRestore                   = (floatRegsToRestoreCount % 2) == 0;
620
621         // Update stack delta only if it is the last restore (the first save).
622         if (thisIsTheLastRestoreInstruction)
623         {
624             assert(stackDelta == 0);
625             stackDelta = spDelta;
626         }
627
628         // Update stack offset.
629         if (isPairRestore)
630         {
631             spOffset -= 2 * FPSAVE_REGSIZE_BYTES;
632         }
633         else
634         {
635             spOffset -= FPSAVE_REGSIZE_BYTES;
636         }
637
638         // If this is the last restore (the first save) that needs to change SP (stackDelta != 0),
639         // then the offset must be 8 to account for alignment for the odd count
640         // or it must be 0 for the even count.
641         assert((stackDelta == 0) || (isRegsToRestoreCountOdd && spOffset == FPSAVE_REGSIZE_BYTES) ||
642                (!isRegsToRestoreCountOdd && spOffset == 0));
643
644         regMaskTP reg2Mask = genFindHighestBit(maskRestoreRegsFloat);
645         regNumber reg2     = genRegNumFromMask(reg2Mask);
646         maskRestoreRegsFloat &= ~reg2Mask;
647         floatRegsToRestoreCount -= 1;
648
649         if (isPairRestore)
650         {
651             regMaskTP reg1Mask = genFindHighestBit(maskRestoreRegsFloat);
652             regNumber reg1     = genRegNumFromMask(reg1Mask);
653             maskRestoreRegsFloat &= ~reg1Mask;
654             floatRegsToRestoreCount -= 1;
655
656             genEpilogRestoreRegPair(reg1, reg2, spOffset, stackDelta, REG_IP1, nullptr);
657         }
658         else
659         {
660             genEpilogRestoreReg(reg2, spOffset, stackDelta, REG_IP1, nullptr);
661         }
662     }
663
664     assert(floatRegsToRestoreCount == 0);
665
666     // Restore the integer registers
667
668     while (maskRestoreRegsInt != RBM_NONE)
669     {
670         thisIsTheLastRestoreInstruction = (intRegsToRestoreCount <= 2);
671         isPairRestore                   = (intRegsToRestoreCount % 2) == 0;
672
673         // Update stack delta only if it is the last restore (the first save).
674         if (thisIsTheLastRestoreInstruction)
675         {
676             assert(stackDelta == 0);
677             stackDelta = spDelta;
678         }
679
680         // Update stack offset.
681         spOffset -= REGSIZE_BYTES;
682         if (isPairRestore)
683         {
684             spOffset -= REGSIZE_BYTES;
685         }
686
687         // If this is the last restore (the first save) that needs to change SP (stackDelta != 0),
688         // then the offset must be 8 to account for alignment for the odd count
689         // or it must be 0 for the even count.
690         assert((stackDelta == 0) || (isRegsToRestoreCountOdd && spOffset == REGSIZE_BYTES) ||
691                (!isRegsToRestoreCountOdd && spOffset == 0));
692
693         regMaskTP reg2Mask = genFindHighestBit(maskRestoreRegsInt);
694         regNumber reg2     = genRegNumFromMask(reg2Mask);
695         maskRestoreRegsInt &= ~reg2Mask;
696         intRegsToRestoreCount -= 1;
697
698         if (isPairRestore)
699         {
700             regMaskTP reg1Mask = genFindHighestBit(maskRestoreRegsInt);
701             regNumber reg1     = genRegNumFromMask(reg1Mask);
702             maskRestoreRegsInt &= ~reg1Mask;
703             intRegsToRestoreCount -= 1;
704
705             genEpilogRestoreRegPair(reg1, reg2, spOffset, stackDelta, REG_IP1, nullptr);
706         }
707         else
708         {
709             genEpilogRestoreReg(reg2, spOffset, stackDelta, REG_IP1, nullptr);
710         }
711     }
712
713     assert(intRegsToRestoreCount == 0);
714 }
715
716 // clang-format off
717 /*****************************************************************************
718  *
719  *  Generates code for an EH funclet prolog.
720  *
721  *  Funclets have the following incoming arguments:
722  *
723  *      catch:          x0 = the exception object that was caught (see GT_CATCH_ARG)
724  *      filter:         x0 = the exception object to filter (see GT_CATCH_ARG), x1 = CallerSP of the containing function
725  *      finally/fault:  none
726  *
727  *  Funclets set the following registers on exit:
728  *
729  *      catch:          x0 = the address at which execution should resume (see BBJ_EHCATCHRET)
730  *      filter:         x0 = non-zero if the handler should handle the exception, zero otherwise (see GT_RETFILT)
731  *      finally/fault:  none
732  *
733  *  The ARM64 funclet prolog sequence is one of the following (Note: #framesz is total funclet frame size,
734  *  including everything; #outsz is outgoing argument space. #framesz must be a multiple of 16):
735  *
736  *  Frame type 1:
737  *     For #outsz == 0 and #framesz <= 512:
738  *     stp fp,lr,[sp,-#framesz]!    ; establish the frame, save FP/LR
739  *     stp x19,x20,[sp,#xxx]        ; save callee-saved registers, as necessary
740  *
741  *  The funclet frame is thus:
742  *
743  *      |                       |
744  *      |-----------------------|
745  *      |       incoming        |
746  *      |       arguments       |
747  *      +=======================+ <---- Caller's SP
748  *      |Callee saved registers | // multiple of 8 bytes
749  *      |-----------------------|
750  *      |        PSP slot       | // 8 bytes (omitted in CoreRT ABI)
751  *      |-----------------------|
752  *      ~  alignment padding    ~ // To make the whole frame 16 byte aligned.
753  *      |-----------------------|
754  *      |      Saved FP, LR     | // 16 bytes
755  *      |-----------------------| <---- Ambient SP
756  *      |       |               |         
757  *      ~       | Stack grows   ~         
758  *      |       | downward      |         
759  *              V
760  *
761  *  Frame type 2:
762  *     For #outsz != 0 and #framesz <= 512:
763  *     sub sp,sp,#framesz           ; establish the frame
764  *     stp fp,lr,[sp,#outsz]        ; save FP/LR.
765  *     stp x19,x20,[sp,#xxx]        ; save callee-saved registers, as necessary
766  *
767  *  The funclet frame is thus:
768  *
769  *      |                       |
770  *      |-----------------------|
771  *      |       incoming        |
772  *      |       arguments       |
773  *      +=======================+ <---- Caller's SP
774  *      |Callee saved registers | // multiple of 8 bytes
775  *      |-----------------------|
776  *      |        PSP slot       | // 8 bytes (omitted in CoreRT ABI)
777  *      |-----------------------|
778  *      ~  alignment padding    ~ // To make the whole frame 16 byte aligned.
779  *      |-----------------------|
780  *      |      Saved FP, LR     | // 16 bytes
781  *      |-----------------------|
782  *      |   Outgoing arg space  | // multiple of 8 bytes
783  *      |-----------------------| <---- Ambient SP
784  *      |       |               |         
785  *      ~       | Stack grows   ~         
786  *      |       | downward      |         
787  *              V
788  *
789  *  Frame type 3:
790  *     For #framesz > 512:
791  *     stp fp,lr,[sp,- (#framesz - #outsz)]!    ; establish the frame, save FP/LR: note that it is guaranteed here that (#framesz - #outsz) <= 168
792  *     stp x19,x20,[sp,#xxx]                    ; save callee-saved registers, as necessary
793  *     sub sp,sp,#outsz                         ; create space for outgoing argument space
794  *
795  *  The funclet frame is thus:
796  *
797  *      |                       |
798  *      |-----------------------|
799  *      |       incoming        |
800  *      |       arguments       |
801  *      +=======================+ <---- Caller's SP
802  *      |Callee saved registers | // multiple of 8 bytes
803  *      |-----------------------|
804  *      |        PSP slot       | // 8 bytes (omitted in CoreRT ABI)
805  *      |-----------------------|
806  *      ~  alignment padding    ~ // To make the first SP subtraction 16 byte aligned
807  *      |-----------------------|
808  *      |      Saved FP, LR     | // 16 bytes
809  *      |-----------------------|
810  *      ~  alignment padding    ~ // To make the whole frame 16 byte aligned (specifically, to 16-byte align the outgoing argument space).
811  *      |-----------------------|
812  *      |   Outgoing arg space  | // multiple of 8 bytes
813  *      |-----------------------| <---- Ambient SP
814  *      |       |               |         
815  *      ~       | Stack grows   ~         
816  *      |       | downward      |         
817  *              V
818  *
819  * Both #1 and #2 only change SP once. That means that there will be a maximum of one alignment slot needed. For the general case, #3,
820  * it is possible that we will need to add alignment to both changes to SP, leading to 16 bytes of alignment. Remember that the stack
821  * pointer needs to be 16 byte aligned at all times. The size of the PSP slot plus callee-saved registers space is a maximum of 168 bytes:
822  * (1 PSP slot + 12 integer registers + 8 FP/SIMD registers) * 8 bytes. The outgoing argument size, however, can be very large, if we call a
823  * function that takes a large number of arguments (note that we currently use the same outgoing argument space size in the funclet as for the main
824  * function, even if the funclet doesn't have any calls, or has a much smaller, or larger, maximum number of outgoing arguments for any call).
825  * In that case, we need to 16-byte align the initial change to SP, before saving off the callee-saved registers and establishing the PSPsym,
826  * so we can use the limited immediate offset encodings we have available, before doing another 16-byte aligned SP adjustment to create the
827  * outgoing argument space. Both changes to SP might need to add alignment padding.
828  *
829  * Note that in all cases, the PSPSym is in exactly the same position with respect to Caller-SP, and that location is the same relative to Caller-SP
830  * as in the main function.
831  *
832  *     ; After this header, fill the PSP slot, for use by the VM (it gets reported with the GC info), or by code generation of nested filters.
833  *     ; This is not part of the "OS prolog"; it has no associated unwind data, and is not reversed in the funclet epilog.
834  *
835  *     if (this is a filter funclet)
836  *     {
837  *          // x1 on entry to a filter funclet is CallerSP of the containing function:
838  *          // either the main function, or the funclet for a handler that this filter is dynamically nested within.
839  *          // Note that a filter can be dynamically nested within a funclet even if it is not statically within
840  *          // a funclet. Consider:
841  *          //
842  *          //    try {
843  *          //        try {
844  *          //            throw new Exception();
845  *          //        } catch(Exception) {
846  *          //            throw new Exception();     // The exception thrown here ...
847  *          //        }
848  *          //    } filter {                         // ... will be processed here, while the "catch" funclet frame is still on the stack
849  *          //    } filter-handler {
850  *          //    }
851  *          //
852  *          // Because of this, we need a PSP in the main function anytime a filter funclet doesn't know whether the enclosing frame will
853  *          // be a funclet or main function. We won't know any time there is a filter protecting nested EH. To simplify, we just always
854  *          // create a main function PSP for any function with a filter.
855  *
856  *          ldr x1, [x1, #CallerSP_to_PSP_slot_delta]  ; Load the CallerSP of the main function (stored in the PSP of the dynamically containing funclet or function)
857  *          str x1, [sp, #SP_to_PSP_slot_delta]        ; store the PSP
858  *          add fp, x1, #Function_CallerSP_to_FP_delta ; re-establish the frame pointer
859  *     }
860  *     else
861  *     {
862  *          // This is NOT a filter funclet. The VM re-establishes the frame pointer on entry.
863  *          // TODO-ARM64-CQ: if VM set x1 to CallerSP on entry, like for filters, we could save an instruction.
864  *
865  *          add x3, fp, #Function_FP_to_CallerSP_delta  ; compute the CallerSP, given the frame pointer. x3 is scratch.
866  *          str x3, [sp, #SP_to_PSP_slot_delta]         ; store the PSP
867  *     }
868  *
869  *  An example epilog sequence is then:
870  *
871  *     add sp,sp,#outsz             ; if any outgoing argument space
872  *     ...                          ; restore callee-saved registers
873  *     ldp x19,x20,[sp,#xxx]
874  *     ldp fp,lr,[sp],#framesz
875  *     ret lr
876  *
877  *  The funclet frame is thus:
878  *
879  *      |                       |
880  *      |-----------------------|
881  *      |       incoming        |
882  *      |       arguments       |
883  *      +=======================+ <---- Caller's SP
884  *      |Callee saved registers | // multiple of 8 bytes
885  *      |-----------------------|
886  *      |        PSP slot       | // 8 bytes (omitted in CoreRT ABI)
887  *      |-----------------------|
888  *      |      Saved FP, LR     | // 16 bytes
889  *      |-----------------------|
890  *      ~  alignment padding    ~ // To make the whole frame 16 byte aligned.
891  *      |-----------------------|
892  *      |   Outgoing arg space  | // multiple of 8 bytes
893  *      |-----------------------| <---- Ambient SP
894  *      |       |               |         
895  *      ~       | Stack grows   ~         
896  *      |       | downward      |         
897  *              V
898  */
899 // clang-format on
900
901 void CodeGen::genFuncletProlog(BasicBlock* block)
902 {
903 #ifdef DEBUG
904     if (verbose)
905         printf("*************** In genFuncletProlog()\n");
906 #endif
907
908     assert(block != NULL);
909     assert(block->bbFlags & BBF_FUNCLET_BEG);
910
911     ScopedSetVariable<bool> _setGeneratingProlog(&compiler->compGeneratingProlog, true);
912
913     gcInfo.gcResetForBB();
914
915     compiler->unwindBegProlog();
916
917     regMaskTP maskSaveRegsFloat = genFuncletInfo.fiSaveRegs & RBM_ALLFLOAT;
918     regMaskTP maskSaveRegsInt   = genFuncletInfo.fiSaveRegs & ~maskSaveRegsFloat;
919
920     // Funclets must always save LR and FP, since when we have funclets we must have an FP frame.
921     assert((maskSaveRegsInt & RBM_LR) != 0);
922     assert((maskSaveRegsInt & RBM_FP) != 0);
923
924     bool isFilter = (block->bbCatchTyp == BBCT_FILTER);
925
926     regMaskTP maskArgRegsLiveIn;
927     if (isFilter)
928     {
929         maskArgRegsLiveIn = RBM_R0 | RBM_R1;
930     }
931     else if ((block->bbCatchTyp == BBCT_FINALLY) || (block->bbCatchTyp == BBCT_FAULT))
932     {
933         maskArgRegsLiveIn = RBM_NONE;
934     }
935     else
936     {
937         maskArgRegsLiveIn = RBM_R0;
938     }
939
940     int lowestCalleeSavedOffset = genFuncletInfo.fiSP_to_CalleeSave_delta;
941
942     if (genFuncletInfo.fiFrameType == 1)
943     {
944         getEmitter()->emitIns_R_R_R_I(INS_stp, EA_PTRSIZE, REG_FP, REG_LR, REG_SPBASE, genFuncletInfo.fiSpDelta1,
945                                       INS_OPTS_PRE_INDEX);
946         compiler->unwindSaveRegPairPreindexed(REG_FP, REG_LR, genFuncletInfo.fiSpDelta1);
947
948         assert(genFuncletInfo.fiSpDelta2 == 0);
949         assert(genFuncletInfo.fiSP_to_FPLR_save_delta == 0);
950     }
951     else if (genFuncletInfo.fiFrameType == 2)
952     {
953         // fiFrameType==2 constraints:
954         assert(genFuncletInfo.fiSpDelta1 < 0);
955         assert(genFuncletInfo.fiSpDelta1 >= -512);
956
957         // generate sub SP,SP,imm
958         genStackPointerAdjustment(genFuncletInfo.fiSpDelta1, REG_NA, nullptr);
959
960         assert(genFuncletInfo.fiSpDelta2 == 0);
961
962         getEmitter()->emitIns_R_R_R_I(INS_stp, EA_PTRSIZE, REG_FP, REG_LR, REG_SPBASE,
963                                       genFuncletInfo.fiSP_to_FPLR_save_delta);
964         compiler->unwindSaveRegPair(REG_FP, REG_LR, genFuncletInfo.fiSP_to_FPLR_save_delta);
965     }
966     else
967     {
968         assert(genFuncletInfo.fiFrameType == 3);
969         getEmitter()->emitIns_R_R_R_I(INS_stp, EA_PTRSIZE, REG_FP, REG_LR, REG_SPBASE, genFuncletInfo.fiSpDelta1,
970                                       INS_OPTS_PRE_INDEX);
971         compiler->unwindSaveRegPairPreindexed(REG_FP, REG_LR, genFuncletInfo.fiSpDelta1);
972
973         lowestCalleeSavedOffset += genFuncletInfo.fiSpDelta2; // We haven't done the second adjustment of SP yet.
974     }
975     maskSaveRegsInt &= ~(RBM_LR | RBM_FP); // We've saved these now
976
977     genSaveCalleeSavedRegistersHelp(maskSaveRegsInt | maskSaveRegsFloat, lowestCalleeSavedOffset, 0);
978
979     if (genFuncletInfo.fiFrameType == 3)
980     {
981         // Note that genFuncletInfo.fiSpDelta2 is always a negative value
982         assert(genFuncletInfo.fiSpDelta2 < 0);
983
984         // generate sub SP,SP,imm
985         genStackPointerAdjustment(genFuncletInfo.fiSpDelta2, REG_R2, nullptr);
986     }
987
988     // This is the end of the OS-reported prolog for purposes of unwinding
989     compiler->unwindEndProlog();
990
991     // If there is no PSPSym (CoreRT ABI), we are done.
992     if (compiler->lvaPSPSym == BAD_VAR_NUM)
993     {
994         return;
995     }
996
997     if (isFilter)
998     {
999         // This is the first block of a filter
1000         // Note that register x1 = CallerSP of the containing function
1001         // X1 is overwritten by the first Load (new callerSP)
1002         // X2 is scratch when we have a large constant offset
1003
1004         // Load the CallerSP of the main function (stored in the PSP of the dynamically containing funclet or function)
1005         genInstrWithConstant(ins_Load(TYP_I_IMPL), EA_PTRSIZE, REG_R1, REG_R1,
1006                              genFuncletInfo.fiCallerSP_to_PSP_slot_delta, REG_R2, false);
1007         regTracker.rsTrackRegTrash(REG_R1);
1008
1009         // Store the PSP value (aka CallerSP)
1010         genInstrWithConstant(ins_Store(TYP_I_IMPL), EA_PTRSIZE, REG_R1, REG_SPBASE,
1011                              genFuncletInfo.fiSP_to_PSP_slot_delta, REG_R2, false);
1012
1013         // re-establish the frame pointer
1014         genInstrWithConstant(INS_add, EA_PTRSIZE, REG_FPBASE, REG_R1, genFuncletInfo.fiFunction_CallerSP_to_FP_delta,
1015                              REG_R2, false);
1016     }
1017     else // This is a non-filter funclet
1018     {
1019         // X3 is scratch, X2 can also become scratch
1020
1021         // compute the CallerSP, given the frame pointer. x3 is scratch.
1022         genInstrWithConstant(INS_add, EA_PTRSIZE, REG_R3, REG_FPBASE, -genFuncletInfo.fiFunction_CallerSP_to_FP_delta,
1023                              REG_R2, false);
1024         regTracker.rsTrackRegTrash(REG_R3);
1025
1026         genInstrWithConstant(ins_Store(TYP_I_IMPL), EA_PTRSIZE, REG_R3, REG_SPBASE,
1027                              genFuncletInfo.fiSP_to_PSP_slot_delta, REG_R2, false);
1028     }
1029 }
1030
1031 /*****************************************************************************
1032  *
1033  *  Generates code for an EH funclet epilog.
1034  */
1035
1036 void CodeGen::genFuncletEpilog()
1037 {
1038 #ifdef DEBUG
1039     if (verbose)
1040         printf("*************** In genFuncletEpilog()\n");
1041 #endif
1042
1043     ScopedSetVariable<bool> _setGeneratingEpilog(&compiler->compGeneratingEpilog, true);
1044
1045     bool unwindStarted = false;
1046
1047     if (!unwindStarted)
1048     {
1049         // We can delay this until we know we'll generate an unwindable instruction, if necessary.
1050         compiler->unwindBegEpilog();
1051         unwindStarted = true;
1052     }
1053
1054     regMaskTP maskRestoreRegsFloat = genFuncletInfo.fiSaveRegs & RBM_ALLFLOAT;
1055     regMaskTP maskRestoreRegsInt   = genFuncletInfo.fiSaveRegs & ~maskRestoreRegsFloat;
1056
1057     // Funclets must always save LR and FP, since when we have funclets we must have an FP frame.
1058     assert((maskRestoreRegsInt & RBM_LR) != 0);
1059     assert((maskRestoreRegsInt & RBM_FP) != 0);
1060
1061     maskRestoreRegsInt &= ~(RBM_LR | RBM_FP); // We restore FP/LR at the end
1062
1063     int lowestCalleeSavedOffset = genFuncletInfo.fiSP_to_CalleeSave_delta;
1064
1065     if (genFuncletInfo.fiFrameType == 3)
1066     {
1067         // Note that genFuncletInfo.fiSpDelta2 is always a negative value
1068         assert(genFuncletInfo.fiSpDelta2 < 0);
1069
1070         // generate add SP,SP,imm
1071         genStackPointerAdjustment(-genFuncletInfo.fiSpDelta2, REG_R2, nullptr);
1072
1073         lowestCalleeSavedOffset += genFuncletInfo.fiSpDelta2;
1074     }
1075
1076     regMaskTP regsToRestoreMask = maskRestoreRegsInt | maskRestoreRegsFloat;
1077     genRestoreCalleeSavedRegistersHelp(regsToRestoreMask, lowestCalleeSavedOffset, 0);
1078
1079     if (genFuncletInfo.fiFrameType == 1)
1080     {
1081         getEmitter()->emitIns_R_R_R_I(INS_ldp, EA_PTRSIZE, REG_FP, REG_LR, REG_SPBASE, -genFuncletInfo.fiSpDelta1,
1082                                       INS_OPTS_POST_INDEX);
1083         compiler->unwindSaveRegPairPreindexed(REG_FP, REG_LR, genFuncletInfo.fiSpDelta1);
1084
1085         assert(genFuncletInfo.fiSpDelta2 == 0);
1086         assert(genFuncletInfo.fiSP_to_FPLR_save_delta == 0);
1087     }
1088     else if (genFuncletInfo.fiFrameType == 2)
1089     {
1090         getEmitter()->emitIns_R_R_R_I(INS_ldp, EA_PTRSIZE, REG_FP, REG_LR, REG_SPBASE,
1091                                       genFuncletInfo.fiSP_to_FPLR_save_delta);
1092         compiler->unwindSaveRegPair(REG_FP, REG_LR, genFuncletInfo.fiSP_to_FPLR_save_delta);
1093
1094         // fiFrameType==2 constraints:
1095         assert(genFuncletInfo.fiSpDelta1 < 0);
1096         assert(genFuncletInfo.fiSpDelta1 >= -512);
1097
1098         // generate add SP,SP,imm
1099         genStackPointerAdjustment(-genFuncletInfo.fiSpDelta1, REG_NA, nullptr);
1100
1101         assert(genFuncletInfo.fiSpDelta2 == 0);
1102     }
1103     else
1104     {
1105         assert(genFuncletInfo.fiFrameType == 3);
1106
1107         getEmitter()->emitIns_R_R_R_I(INS_ldp, EA_PTRSIZE, REG_FP, REG_LR, REG_SPBASE, -genFuncletInfo.fiSpDelta1,
1108                                       INS_OPTS_POST_INDEX);
1109         compiler->unwindSaveRegPairPreindexed(REG_FP, REG_LR, genFuncletInfo.fiSpDelta1);
1110     }
1111
1112     inst_RV(INS_ret, REG_LR, TYP_I_IMPL);
1113     compiler->unwindReturn(REG_LR);
1114
1115     compiler->unwindEndEpilog();
1116 }
1117
1118 /*****************************************************************************
1119  *
1120  *  Capture the information used to generate the funclet prologs and epilogs.
1121  *  Note that all funclet prologs are identical, and all funclet epilogs are
1122  *  identical (per type: filters are identical, and non-filters are identical).
1123  *  Thus, we compute the data used for these just once.
1124  *
1125  *  See genFuncletProlog() for more information about the prolog/epilog sequences.
1126  */
1127
1128 void CodeGen::genCaptureFuncletPrologEpilogInfo()
1129 {
1130     if (!compiler->ehAnyFunclets())
1131         return;
1132
1133     assert(isFramePointerUsed());
1134     assert(compiler->lvaDoneFrameLayout == Compiler::FINAL_FRAME_LAYOUT); // The frame size and offsets must be
1135                                                                           // finalized
1136
1137     genFuncletInfo.fiFunction_CallerSP_to_FP_delta = genCallerSPtoFPdelta();
1138
1139     regMaskTP rsMaskSaveRegs = regSet.rsMaskCalleeSaved;
1140     assert((rsMaskSaveRegs & RBM_LR) != 0);
1141     assert((rsMaskSaveRegs & RBM_FP) != 0);
1142
1143     unsigned PSPSize = (compiler->lvaPSPSym != BAD_VAR_NUM) ? REGSIZE_BYTES : 0;
1144
1145     unsigned saveRegsCount       = genCountBits(rsMaskSaveRegs);
1146     unsigned saveRegsPlusPSPSize = saveRegsCount * REGSIZE_BYTES + PSPSize;
1147     if (compiler->info.compIsVarArgs)
1148     {
1149         // For varargs we always save all of the integer register arguments
1150         // so that they are contiguous with the incoming stack arguments.
1151         saveRegsPlusPSPSize += MAX_REG_ARG * REGSIZE_BYTES;
1152     }
1153     unsigned saveRegsPlusPSPSizeAligned = (unsigned)roundUp(saveRegsPlusPSPSize, STACK_ALIGN);
1154
1155     assert(compiler->lvaOutgoingArgSpaceSize % REGSIZE_BYTES == 0);
1156     unsigned outgoingArgSpaceAligned = (unsigned)roundUp(compiler->lvaOutgoingArgSpaceSize, STACK_ALIGN);
1157
1158     unsigned maxFuncletFrameSizeAligned = saveRegsPlusPSPSizeAligned + outgoingArgSpaceAligned;
1159     assert((maxFuncletFrameSizeAligned % STACK_ALIGN) == 0);
1160
1161     int SP_to_FPLR_save_delta;
1162     int SP_to_PSP_slot_delta;
1163     int CallerSP_to_PSP_slot_delta;
1164
1165     if (maxFuncletFrameSizeAligned <= 512)
1166     {
1167         unsigned funcletFrameSize        = saveRegsPlusPSPSize + compiler->lvaOutgoingArgSpaceSize;
1168         unsigned funcletFrameSizeAligned = (unsigned)roundUp(funcletFrameSize, STACK_ALIGN);
1169         assert(funcletFrameSizeAligned <= maxFuncletFrameSizeAligned);
1170
1171         unsigned funcletFrameAlignmentPad = funcletFrameSizeAligned - funcletFrameSize;
1172         assert((funcletFrameAlignmentPad == 0) || (funcletFrameAlignmentPad == REGSIZE_BYTES));
1173
1174         SP_to_FPLR_save_delta      = compiler->lvaOutgoingArgSpaceSize;
1175         SP_to_PSP_slot_delta       = SP_to_FPLR_save_delta + 2 /* FP, LR */ * REGSIZE_BYTES + funcletFrameAlignmentPad;
1176         CallerSP_to_PSP_slot_delta = -(int)(saveRegsPlusPSPSize - 2 /* FP, LR */ * REGSIZE_BYTES);
1177
1178         if (compiler->lvaOutgoingArgSpaceSize == 0)
1179         {
1180             genFuncletInfo.fiFrameType = 1;
1181         }
1182         else
1183         {
1184             genFuncletInfo.fiFrameType = 2;
1185         }
1186         genFuncletInfo.fiSpDelta1 = -(int)funcletFrameSizeAligned;
1187         genFuncletInfo.fiSpDelta2 = 0;
1188
1189         assert(genFuncletInfo.fiSpDelta1 + genFuncletInfo.fiSpDelta2 == -(int)funcletFrameSizeAligned);
1190     }
1191     else
1192     {
1193         unsigned saveRegsPlusPSPAlignmentPad = saveRegsPlusPSPSizeAligned - saveRegsPlusPSPSize;
1194         assert((saveRegsPlusPSPAlignmentPad == 0) || (saveRegsPlusPSPAlignmentPad == REGSIZE_BYTES));
1195
1196         SP_to_FPLR_save_delta = outgoingArgSpaceAligned;
1197         SP_to_PSP_slot_delta  = SP_to_FPLR_save_delta + 2 /* FP, LR */ * REGSIZE_BYTES + saveRegsPlusPSPAlignmentPad;
1198         CallerSP_to_PSP_slot_delta =
1199             -(int)(saveRegsPlusPSPSizeAligned - 2 /* FP, LR */ * REGSIZE_BYTES - saveRegsPlusPSPAlignmentPad);
1200
1201         genFuncletInfo.fiFrameType = 3;
1202         genFuncletInfo.fiSpDelta1  = -(int)saveRegsPlusPSPSizeAligned;
1203         genFuncletInfo.fiSpDelta2  = -(int)outgoingArgSpaceAligned;
1204
1205         assert(genFuncletInfo.fiSpDelta1 + genFuncletInfo.fiSpDelta2 == -(int)maxFuncletFrameSizeAligned);
1206     }
1207
1208     /* Now save it for future use */
1209
1210     genFuncletInfo.fiSaveRegs                   = rsMaskSaveRegs;
1211     genFuncletInfo.fiSP_to_FPLR_save_delta      = SP_to_FPLR_save_delta;
1212     genFuncletInfo.fiSP_to_PSP_slot_delta       = SP_to_PSP_slot_delta;
1213     genFuncletInfo.fiSP_to_CalleeSave_delta     = SP_to_PSP_slot_delta + REGSIZE_BYTES;
1214     genFuncletInfo.fiCallerSP_to_PSP_slot_delta = CallerSP_to_PSP_slot_delta;
1215
1216 #ifdef DEBUG
1217     if (verbose)
1218     {
1219         printf("\n");
1220         printf("Funclet prolog / epilog info\n");
1221         printf("                        Save regs: ");
1222         dspRegMask(genFuncletInfo.fiSaveRegs);
1223         printf("\n");
1224         printf("    Function CallerSP-to-FP delta: %d\n", genFuncletInfo.fiFunction_CallerSP_to_FP_delta);
1225         printf("  SP to FP/LR save location delta: %d\n", genFuncletInfo.fiSP_to_FPLR_save_delta);
1226         printf("             SP to PSP slot delta: %d\n", genFuncletInfo.fiSP_to_PSP_slot_delta);
1227         printf("    SP to callee-saved area delta: %d\n", genFuncletInfo.fiSP_to_CalleeSave_delta);
1228         printf("      Caller SP to PSP slot delta: %d\n", genFuncletInfo.fiCallerSP_to_PSP_slot_delta);
1229         printf("                       Frame type: %d\n", genFuncletInfo.fiFrameType);
1230         printf("                       SP delta 1: %d\n", genFuncletInfo.fiSpDelta1);
1231         printf("                       SP delta 2: %d\n", genFuncletInfo.fiSpDelta2);
1232
1233         if (compiler->lvaPSPSym != BAD_VAR_NUM)
1234         {
1235             if (CallerSP_to_PSP_slot_delta !=
1236                 compiler->lvaGetCallerSPRelativeOffset(compiler->lvaPSPSym)) // for debugging
1237             {
1238                 printf("lvaGetCallerSPRelativeOffset(lvaPSPSym): %d\n",
1239                        compiler->lvaGetCallerSPRelativeOffset(compiler->lvaPSPSym));
1240             }
1241         }
1242     }
1243
1244     assert(genFuncletInfo.fiSP_to_FPLR_save_delta >= 0);
1245     assert(genFuncletInfo.fiSP_to_PSP_slot_delta >= 0);
1246     assert(genFuncletInfo.fiSP_to_CalleeSave_delta >= 0);
1247     assert(genFuncletInfo.fiCallerSP_to_PSP_slot_delta <= 0);
1248
1249     if (compiler->lvaPSPSym != BAD_VAR_NUM)
1250     {
1251         assert(genFuncletInfo.fiCallerSP_to_PSP_slot_delta ==
1252                compiler->lvaGetCallerSPRelativeOffset(compiler->lvaPSPSym)); // same offset used in main function and
1253                                                                              // funclet!
1254     }
1255 #endif // DEBUG
1256 }
1257
1258 /*
1259 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1260 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1261 XX                                                                           XX
1262 XX                           End Prolog / Epilog                             XX
1263 XX                                                                           XX
1264 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1265 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1266 */
1267
1268 BasicBlock* CodeGen::genCallFinally(BasicBlock* block)
1269 {
1270     // Generate a call to the finally, like this:
1271     //      mov         x0,qword ptr [fp + 10H] / sp    // Load x0 with PSPSym, or sp if PSPSym is not used
1272     //      bl          finally-funclet
1273     //      b           finally-return                  // Only for non-retless finally calls
1274     // The 'b' can be a NOP if we're going to the next block.
1275
1276     if (compiler->lvaPSPSym != BAD_VAR_NUM)
1277     {
1278         getEmitter()->emitIns_R_S(ins_Load(TYP_I_IMPL), EA_PTRSIZE, REG_R0, compiler->lvaPSPSym, 0);
1279     }
1280     else
1281     {
1282         getEmitter()->emitIns_R_R(INS_mov, EA_PTRSIZE, REG_R0, REG_SPBASE);
1283     }
1284     getEmitter()->emitIns_J(INS_bl_local, block->bbJumpDest);
1285
1286     if (block->bbFlags & BBF_RETLESS_CALL)
1287     {
1288         // We have a retless call, and the last instruction generated was a call.
1289         // If the next block is in a different EH region (or is the end of the code
1290         // block), then we need to generate a breakpoint here (since it will never
1291         // get executed) to get proper unwind behavior.
1292
1293         if ((block->bbNext == nullptr) || !BasicBlock::sameEHRegion(block, block->bbNext))
1294         {
1295             instGen(INS_bkpt); // This should never get executed
1296         }
1297     }
1298     else
1299     {
1300         // Because of the way the flowgraph is connected, the liveness info for this one instruction
1301         // after the call is not (can not be) correct in cases where a variable has a last use in the
1302         // handler.  So turn off GC reporting for this single instruction.
1303         getEmitter()->emitDisableGC();
1304
1305         // Now go to where the finally funclet needs to return to.
1306         if (block->bbNext->bbJumpDest == block->bbNext->bbNext)
1307         {
1308             // Fall-through.
1309             // TODO-ARM64-CQ: Can we get rid of this instruction, and just have the call return directly
1310             // to the next instruction? This would depend on stack walking from within the finally
1311             // handler working without this instruction being in this special EH region.
1312             instGen(INS_nop);
1313         }
1314         else
1315         {
1316             inst_JMP(EJ_jmp, block->bbNext->bbJumpDest);
1317         }
1318
1319         getEmitter()->emitEnableGC();
1320     }
1321
1322     // The BBJ_ALWAYS is used because the BBJ_CALLFINALLY can't point to the
1323     // jump target using bbJumpDest - that is already used to point
1324     // to the finally block. So just skip past the BBJ_ALWAYS unless the
1325     // block is RETLESS.
1326     if (!(block->bbFlags & BBF_RETLESS_CALL))
1327     {
1328         assert(block->isBBCallAlwaysPair());
1329         block = block->bbNext;
1330     }
1331     return block;
1332 }
1333
1334 void CodeGen::genEHCatchRet(BasicBlock* block)
1335 {
1336     // For long address (default): `adrp + add` will be emitted.
1337     // For short address (proven later): `adr` will be emitted.
1338     getEmitter()->emitIns_R_L(INS_adr, EA_PTRSIZE, block->bbJumpDest, REG_INTRET);
1339 }
1340
1341 //  move an immediate value into an integer register
1342
1343 void CodeGen::instGen_Set_Reg_To_Imm(emitAttr size, regNumber reg, ssize_t imm, insFlags flags)
1344 {
1345     // reg cannot be a FP register
1346     assert(!genIsValidFloatReg(reg));
1347     if (!compiler->opts.compReloc)
1348     {
1349         size = EA_SIZE(size); // Strip any Reloc flags from size if we aren't doing relocs
1350     }
1351
1352     if (EA_IS_RELOC(size))
1353     {
1354         // This emits a pair of adrp/add (two instructions) with fix-ups.
1355         getEmitter()->emitIns_R_AI(INS_adrp, size, reg, imm);
1356     }
1357     else if (imm == 0)
1358     {
1359         instGen_Set_Reg_To_Zero(size, reg, flags);
1360     }
1361     else
1362     {
1363         if (emitter::emitIns_valid_imm_for_mov(imm, size))
1364         {
1365             getEmitter()->emitIns_R_I(INS_mov, size, reg, imm);
1366         }
1367         else
1368         {
1369             // Arm64 allows any arbitrary 16-bit constant to be loaded into a register halfword
1370             // There are three forms
1371             //    movk which loads into any halfword preserving the remaining halfwords
1372             //    movz which loads into any halfword zeroing the remaining halfwords
1373             //    movn which loads into any halfword zeroing the remaining halfwords then bitwise inverting the register
1374             // In some cases it is preferable to use movn, because it has the side effect of filling the other halfwords
1375             // with ones
1376
1377             // Determine whether movn or movz will require the fewest instructions to populate the immediate
1378             int preferMovn = 0;
1379
1380             for (int i = (size == EA_8BYTE) ? 48 : 16; i >= 0; i -= 16)
1381             {
1382                 if (uint16_t(imm >> i) == 0xffff)
1383                     ++preferMovn; // a single movk 0xffff could be skipped if movn was used
1384                 else if (uint16_t(imm >> i) == 0x0000)
1385                     --preferMovn; // a single movk 0 could be skipped if movz was used
1386             }
1387
1388             // Select the first instruction.  Any additional instruction will use movk
1389             instruction ins = (preferMovn > 0) ? INS_movn : INS_movz;
1390
1391             // Initial movz or movn will fill the remaining bytes with the skipVal
1392             // This can allow skipping filling a halfword
1393             uint16_t skipVal = (preferMovn > 0) ? 0xffff : 0;
1394
1395             unsigned bits = (size == EA_8BYTE) ? 64 : 32;
1396
1397             // Iterate over imm examining 16 bits at a time
1398             for (unsigned i = 0; i < bits; i += 16)
1399             {
1400                 uint16_t imm16 = uint16_t(imm >> i);
1401
1402                 if (imm16 != skipVal)
1403                 {
1404                     if (ins == INS_movn)
1405                     {
1406                         // For the movn case, we need to bitwise invert the immediate.  This is because
1407                         //   (movn x0, ~imm16) === (movz x0, imm16; or x0, x0, #0xffff`ffff`ffff`0000)
1408                         imm16 = ~imm16;
1409                     }
1410
1411                     getEmitter()->emitIns_R_I_I(ins, size, reg, imm16, i, INS_OPTS_LSL);
1412
1413                     // Once the initial movz/movn is emitted the remaining instructions will all use movk
1414                     ins = INS_movk;
1415                 }
1416             }
1417
1418             // We must emit a movn or movz or we have not done anything
1419             // The cases which hit this assert should be (emitIns_valid_imm_for_mov() == true) and
1420             // should not be in this else condition
1421             assert(ins == INS_movk);
1422         }
1423         // The caller may have requested that the flags be set on this mov (rarely/never)
1424         if (flags == INS_FLAGS_SET)
1425         {
1426             getEmitter()->emitIns_R_I(INS_tst, size, reg, 0);
1427         }
1428     }
1429
1430     regTracker.rsTrackRegIntCns(reg, imm);
1431 }
1432
1433 /***********************************************************************************
1434  *
1435  * Generate code to set a register 'targetReg' of type 'targetType' to the constant
1436  * specified by the constant (GT_CNS_INT or GT_CNS_DBL) in 'tree'. This does not call
1437  * genProduceReg() on the target register.
1438  */
1439 void CodeGen::genSetRegToConst(regNumber targetReg, var_types targetType, GenTree* tree)
1440 {
1441     switch (tree->gtOper)
1442     {
1443         case GT_CNS_INT:
1444         {
1445             // relocatable values tend to come down as a CNS_INT of native int type
1446             // so the line between these two opcodes is kind of blurry
1447             GenTreeIntConCommon* con    = tree->AsIntConCommon();
1448             ssize_t              cnsVal = con->IconValue();
1449
1450             if (con->ImmedValNeedsReloc(compiler))
1451             {
1452                 instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, targetReg, cnsVal);
1453                 regTracker.rsTrackRegTrash(targetReg);
1454             }
1455             else
1456             {
1457                 genSetRegToIcon(targetReg, cnsVal, targetType);
1458             }
1459         }
1460         break;
1461
1462         case GT_CNS_DBL:
1463         {
1464             emitter* emit       = getEmitter();
1465             emitAttr size       = emitActualTypeSize(tree);
1466             double   constValue = tree->AsDblCon()->gtDconVal;
1467
1468             // Make sure we use "movi reg, 0x00"  only for positive zero (0.0) and not for negative zero (-0.0)
1469             if (*(__int64*)&constValue == 0)
1470             {
1471                 // A faster/smaller way to generate 0.0
1472                 // We will just zero out the entire vector register for both float and double
1473                 emit->emitIns_R_I(INS_movi, EA_16BYTE, targetReg, 0x00, INS_OPTS_16B);
1474             }
1475             else if (emitter::emitIns_valid_imm_for_fmov(constValue))
1476             {
1477                 // We can load the FP constant using the fmov FP-immediate for this constValue
1478                 emit->emitIns_R_F(INS_fmov, size, targetReg, constValue);
1479             }
1480             else
1481             {
1482                 // Get a temp integer register to compute long address.
1483                 regNumber addrReg = tree->GetSingleTempReg();
1484
1485                 // We must load the FP constant from the constant pool
1486                 // Emit a data section constant for the float or double constant.
1487                 CORINFO_FIELD_HANDLE hnd = emit->emitFltOrDblConst(constValue, size);
1488                 // For long address (default): `adrp + ldr + fmov` will be emitted.
1489                 // For short address (proven later), `ldr` will be emitted.
1490                 emit->emitIns_R_C(INS_ldr, size, targetReg, addrReg, hnd, 0);
1491             }
1492         }
1493         break;
1494
1495         default:
1496             unreached();
1497     }
1498 }
1499
1500 // Generate code to get the high N bits of a N*N=2N bit multiplication result
1501 void CodeGen::genCodeForMulHi(GenTreeOp* treeNode)
1502 {
1503     assert(!treeNode->gtOverflowEx());
1504
1505     genConsumeOperands(treeNode);
1506
1507     regNumber targetReg  = treeNode->gtRegNum;
1508     var_types targetType = treeNode->TypeGet();
1509     emitter*  emit       = getEmitter();
1510     emitAttr  attr       = emitActualTypeSize(treeNode);
1511     unsigned  isUnsigned = (treeNode->gtFlags & GTF_UNSIGNED);
1512
1513     GenTree* op1 = treeNode->gtGetOp1();
1514     GenTree* op2 = treeNode->gtGetOp2();
1515
1516     assert(!varTypeIsFloating(targetType));
1517
1518     // The arithmetic node must be sitting in a register (since it's not contained)
1519     assert(targetReg != REG_NA);
1520
1521     if (EA_SIZE(attr) == EA_8BYTE)
1522     {
1523         instruction ins = isUnsigned ? INS_umulh : INS_smulh;
1524
1525         regNumber r = emit->emitInsTernary(ins, attr, treeNode, op1, op2);
1526
1527         assert(r == targetReg);
1528     }
1529     else
1530     {
1531         assert(EA_SIZE(attr) == EA_4BYTE);
1532
1533         instruction ins = isUnsigned ? INS_umull : INS_smull;
1534
1535         regNumber r = emit->emitInsTernary(ins, EA_4BYTE, treeNode, op1, op2);
1536
1537         emit->emitIns_R_R_I(isUnsigned ? INS_lsr : INS_asr, EA_8BYTE, targetReg, targetReg, 32);
1538     }
1539
1540     genProduceReg(treeNode);
1541 }
1542
1543 // Generate code for ADD, SUB, MUL, DIV, UDIV, AND, OR and XOR
1544 // This method is expected to have called genConsumeOperands() before calling it.
1545 void CodeGen::genCodeForBinary(GenTree* treeNode)
1546 {
1547     const genTreeOps oper       = treeNode->OperGet();
1548     regNumber        targetReg  = treeNode->gtRegNum;
1549     var_types        targetType = treeNode->TypeGet();
1550     emitter*         emit       = getEmitter();
1551
1552     assert(oper == GT_ADD || oper == GT_SUB || oper == GT_MUL || oper == GT_DIV || oper == GT_UDIV || oper == GT_AND ||
1553            oper == GT_OR || oper == GT_XOR);
1554
1555     GenTree*    op1 = treeNode->gtGetOp1();
1556     GenTree*    op2 = treeNode->gtGetOp2();
1557     instruction ins = genGetInsForOper(treeNode->OperGet(), targetType);
1558
1559     if ((treeNode->gtFlags & GTF_SET_FLAGS) != 0)
1560     {
1561         switch (oper)
1562         {
1563             case GT_ADD:
1564                 ins = INS_adds;
1565                 break;
1566             case GT_SUB:
1567                 ins = INS_subs;
1568                 break;
1569             case GT_AND:
1570                 ins = INS_ands;
1571                 break;
1572             default:
1573                 noway_assert(!"Unexpected BinaryOp with GTF_SET_FLAGS set");
1574         }
1575     }
1576
1577     // The arithmetic node must be sitting in a register (since it's not contained)
1578     assert(targetReg != REG_NA);
1579
1580     regNumber r = emit->emitInsTernary(ins, emitActualTypeSize(treeNode), treeNode, op1, op2);
1581     assert(r == targetReg);
1582
1583     genProduceReg(treeNode);
1584 }
1585
1586 //------------------------------------------------------------------------
1587 // genCodeForLclVar: Produce code for a GT_LCL_VAR node.
1588 //
1589 // Arguments:
1590 //    tree - the GT_LCL_VAR node
1591 //
1592 void CodeGen::genCodeForLclVar(GenTreeLclVar* tree)
1593 {
1594     var_types targetType = tree->TypeGet();
1595     emitter*  emit       = getEmitter();
1596
1597     unsigned varNum = tree->gtLclNum;
1598     assert(varNum < compiler->lvaCount);
1599     LclVarDsc* varDsc         = &(compiler->lvaTable[varNum]);
1600     bool       isRegCandidate = varDsc->lvIsRegCandidate();
1601
1602     // lcl_vars are not defs
1603     assert((tree->gtFlags & GTF_VAR_DEF) == 0);
1604
1605     // If this is a register candidate that has been spilled, genConsumeReg() will
1606     // reload it at the point of use.  Otherwise, if it's not in a register, we load it here.
1607
1608     if (!isRegCandidate && !(tree->gtFlags & GTF_SPILLED))
1609     {
1610         // targetType must be a normal scalar type and not a TYP_STRUCT
1611         assert(targetType != TYP_STRUCT);
1612
1613         instruction ins  = ins_Load(targetType);
1614         emitAttr    attr = emitTypeSize(targetType);
1615
1616         attr = varTypeIsFloating(targetType) ? attr : emit->emitInsAdjustLoadStoreAttr(ins, attr);
1617
1618         emit->emitIns_R_S(ins, attr, tree->gtRegNum, varNum, 0);
1619         genProduceReg(tree);
1620     }
1621 }
1622
1623 //------------------------------------------------------------------------
1624 // genCodeForStoreLclFld: Produce code for a GT_STORE_LCL_FLD node.
1625 //
1626 // Arguments:
1627 //    tree - the GT_STORE_LCL_FLD node
1628 //
1629 void CodeGen::genCodeForStoreLclFld(GenTreeLclFld* tree)
1630 {
1631     var_types targetType = tree->TypeGet();
1632     regNumber targetReg  = tree->gtRegNum;
1633     emitter*  emit       = getEmitter();
1634     noway_assert(targetType != TYP_STRUCT);
1635
1636 #ifdef FEATURE_SIMD
1637     // storing of TYP_SIMD12 (i.e. Vector3) field
1638     if (tree->TypeGet() == TYP_SIMD12)
1639     {
1640         genStoreLclTypeSIMD12(tree);
1641         return;
1642     }
1643 #endif // FEATURE_SIMD
1644
1645     // record the offset
1646     unsigned offset = tree->gtLclOffs;
1647
1648     // We must have a stack store with GT_STORE_LCL_FLD
1649     noway_assert(targetReg == REG_NA);
1650
1651     unsigned varNum = tree->gtLclNum;
1652     assert(varNum < compiler->lvaCount);
1653     LclVarDsc* varDsc = &(compiler->lvaTable[varNum]);
1654
1655     // Ensure that lclVar nodes are typed correctly.
1656     assert(!varDsc->lvNormalizeOnStore() || targetType == genActualType(varDsc->TypeGet()));
1657
1658     GenTree* data = tree->gtOp1;
1659     genConsumeRegs(data);
1660
1661     regNumber dataReg = REG_NA;
1662     if (data->isContainedIntOrIImmed())
1663     {
1664         assert(data->IsIntegralConst(0));
1665         dataReg = REG_ZR;
1666     }
1667     else
1668     {
1669         assert(!data->isContained());
1670         dataReg = data->gtRegNum;
1671     }
1672     assert(dataReg != REG_NA);
1673
1674     instruction ins = ins_Store(targetType);
1675
1676     emitAttr attr = emitTypeSize(targetType);
1677
1678     attr = varTypeIsFloating(targetType) ? attr : emit->emitInsAdjustLoadStoreAttr(ins, attr);
1679
1680     emit->emitIns_S_R(ins, attr, dataReg, varNum, offset);
1681
1682     genUpdateLife(tree);
1683
1684     varDsc->lvRegNum = REG_STK;
1685 }
1686
1687 //------------------------------------------------------------------------
1688 // genCodeForStoreLclVar: Produce code for a GT_STORE_LCL_VAR node.
1689 //
1690 // Arguments:
1691 //    tree - the GT_STORE_LCL_VAR node
1692 //
1693 void CodeGen::genCodeForStoreLclVar(GenTreeLclVar* tree)
1694 {
1695     var_types targetType = tree->TypeGet();
1696     regNumber targetReg  = tree->gtRegNum;
1697     emitter*  emit       = getEmitter();
1698
1699     unsigned varNum = tree->gtLclNum;
1700     assert(varNum < compiler->lvaCount);
1701     LclVarDsc* varDsc = &(compiler->lvaTable[varNum]);
1702
1703     // Ensure that lclVar nodes are typed correctly.
1704     assert(!varDsc->lvNormalizeOnStore() || targetType == genActualType(varDsc->TypeGet()));
1705
1706     GenTree* data = tree->gtOp1;
1707
1708     // var = call, where call returns a multi-reg return value
1709     // case is handled separately.
1710     if (data->gtSkipReloadOrCopy()->IsMultiRegCall())
1711     {
1712         genMultiRegCallStoreToLocal(tree);
1713     }
1714     else
1715     {
1716 #ifdef FEATURE_SIMD
1717         // storing of TYP_SIMD12 (i.e. Vector3) field
1718         if (tree->TypeGet() == TYP_SIMD12)
1719         {
1720             genStoreLclTypeSIMD12(tree);
1721             return;
1722         }
1723 #endif // FEATURE_SIMD
1724
1725         genConsumeRegs(data);
1726
1727         regNumber dataReg = REG_NA;
1728         if (data->isContainedIntOrIImmed())
1729         {
1730             // This is only possible for a zero-init.
1731             assert(data->IsIntegralConst(0));
1732
1733             if (varTypeIsSIMD(targetType))
1734             {
1735                 assert(targetReg != REG_NA);
1736                 getEmitter()->emitIns_R_I(INS_movi, EA_16BYTE, targetReg, 0x00, INS_OPTS_16B);
1737                 genProduceReg(tree);
1738                 return;
1739             }
1740
1741             dataReg = REG_ZR;
1742         }
1743         else
1744         {
1745             assert(!data->isContained());
1746             dataReg = data->gtRegNum;
1747         }
1748         assert(dataReg != REG_NA);
1749
1750         if (targetReg == REG_NA) // store into stack based LclVar
1751         {
1752             inst_set_SV_var(tree);
1753
1754             instruction ins  = ins_Store(targetType);
1755             emitAttr    attr = emitTypeSize(targetType);
1756
1757             attr = varTypeIsFloating(targetType) ? attr : emit->emitInsAdjustLoadStoreAttr(ins, attr);
1758
1759             emit->emitIns_S_R(ins, attr, dataReg, varNum, /* offset */ 0);
1760
1761             genUpdateLife(tree);
1762
1763             varDsc->lvRegNum = REG_STK;
1764         }
1765         else // store into register (i.e move into register)
1766         {
1767             if (dataReg != targetReg)
1768             {
1769                 // Assign into targetReg when dataReg (from op1) is not the same register
1770                 inst_RV_RV(ins_Copy(targetType), targetReg, dataReg, targetType);
1771             }
1772             genProduceReg(tree);
1773         }
1774     }
1775 }
1776
1777 //------------------------------------------------------------------------
1778 // genReturn: Generates code for return statement.
1779 //            In case of struct return, delegates to the genStructReturn method.
1780 //
1781 // Arguments:
1782 //    treeNode - The GT_RETURN or GT_RETFILT tree node.
1783 //
1784 // Return Value:
1785 //    None
1786 //
1787 void CodeGen::genReturn(GenTree* treeNode)
1788 {
1789     assert(treeNode->OperGet() == GT_RETURN || treeNode->OperGet() == GT_RETFILT);
1790     GenTree*  op1        = treeNode->gtGetOp1();
1791     var_types targetType = treeNode->TypeGet();
1792
1793     // A void GT_RETFILT is the end of a finally. For non-void filter returns we need to load the result in the return
1794     // register, if it's not already there. The processing is the same as GT_RETURN. For filters, the IL spec says the
1795     // result is type int32. Further, the only legal values are 0 or 1; the use of other values is "undefined".
1796     assert(!treeNode->OperIs(GT_RETFILT) || (targetType == TYP_VOID) || (targetType == TYP_INT));
1797
1798 #ifdef DEBUG
1799     if (targetType == TYP_VOID)
1800     {
1801         assert(op1 == nullptr);
1802     }
1803 #endif
1804
1805     if (isStructReturn(treeNode))
1806     {
1807         genStructReturn(treeNode);
1808     }
1809     else if (targetType != TYP_VOID)
1810     {
1811         assert(op1 != nullptr);
1812         noway_assert(op1->gtRegNum != REG_NA);
1813
1814         genConsumeReg(op1);
1815
1816         regNumber retReg = varTypeIsFloating(treeNode) ? REG_FLOATRET : REG_INTRET;
1817
1818         bool movRequired = (op1->gtRegNum != retReg);
1819
1820         if (!movRequired)
1821         {
1822             if (op1->OperGet() == GT_LCL_VAR)
1823             {
1824                 GenTreeLclVarCommon* lcl            = op1->AsLclVarCommon();
1825                 bool                 isRegCandidate = compiler->lvaTable[lcl->gtLclNum].lvIsRegCandidate();
1826                 if (isRegCandidate && ((op1->gtFlags & GTF_SPILLED) == 0))
1827                 {
1828                     // We may need to generate a zero-extending mov instruction to load the value from this GT_LCL_VAR
1829
1830                     unsigned   lclNum  = lcl->gtLclNum;
1831                     LclVarDsc* varDsc  = &(compiler->lvaTable[lclNum]);
1832                     var_types  op1Type = genActualType(op1->TypeGet());
1833                     var_types  lclType = genActualType(varDsc->TypeGet());
1834
1835                     if (genTypeSize(op1Type) < genTypeSize(lclType))
1836                     {
1837                         movRequired = true;
1838                     }
1839                 }
1840             }
1841         }
1842
1843         if (movRequired)
1844         {
1845             emitAttr attr = emitActualTypeSize(targetType);
1846             getEmitter()->emitIns_R_R(INS_mov, attr, retReg, op1->gtRegNum);
1847         }
1848     }
1849
1850 #ifdef PROFILING_SUPPORTED
1851     // There will be a single return block while generating profiler ELT callbacks.
1852     //
1853     // Reason for not materializing Leave callback as a GT_PROF_HOOK node after GT_RETURN:
1854     // In flowgraph and other places assert that the last node of a block marked as
1855     // GT_RETURN is either a GT_RETURN or GT_JMP or a tail call.  It would be nice to
1856     // maintain such an invariant irrespective of whether profiler hook needed or not.
1857     // Also, there is not much to be gained by materializing it as an explicit node.
1858     if (compiler->compCurBB == compiler->genReturnBB)
1859     {
1860         genProfilingLeaveCallback();
1861     }
1862 #endif
1863 }
1864
1865 /***********************************************************************************************
1866  *  Generate code for localloc
1867  */
1868 void CodeGen::genLclHeap(GenTree* tree)
1869 {
1870     assert(tree->OperGet() == GT_LCLHEAP);
1871
1872     GenTree* size = tree->gtOp.gtOp1;
1873     noway_assert((genActualType(size->gtType) == TYP_INT) || (genActualType(size->gtType) == TYP_I_IMPL));
1874
1875     regNumber   targetReg       = tree->gtRegNum;
1876     regNumber   regCnt          = REG_NA;
1877     regNumber   pspSymReg       = REG_NA;
1878     var_types   type            = genActualType(size->gtType);
1879     emitAttr    easz            = emitTypeSize(type);
1880     BasicBlock* endLabel        = nullptr;
1881     BasicBlock* loop            = nullptr;
1882     unsigned    stackAdjustment = 0;
1883
1884 #ifdef DEBUG
1885     // Verify ESP
1886     if (compiler->opts.compStackCheckOnRet)
1887     {
1888         noway_assert(compiler->lvaReturnEspCheck != 0xCCCCCCCC &&
1889                      compiler->lvaTable[compiler->lvaReturnEspCheck].lvDoNotEnregister &&
1890                      compiler->lvaTable[compiler->lvaReturnEspCheck].lvOnFrame);
1891         getEmitter()->emitIns_S_R(INS_cmp, EA_PTRSIZE, REG_SPBASE, compiler->lvaReturnEspCheck, 0);
1892
1893         BasicBlock*  esp_check = genCreateTempLabel();
1894         emitJumpKind jmpEqual  = genJumpKindForOper(GT_EQ, CK_SIGNED);
1895         inst_JMP(jmpEqual, esp_check);
1896         getEmitter()->emitIns(INS_bkpt);
1897         genDefineTempLabel(esp_check);
1898     }
1899 #endif
1900
1901     noway_assert(isFramePointerUsed()); // localloc requires Frame Pointer to be established since SP changes
1902     noway_assert(genStackLevel == 0);   // Can't have anything on the stack
1903
1904     // Whether method has PSPSym.
1905     bool hasPspSym;
1906 #if FEATURE_EH_FUNCLETS
1907     hasPspSym = (compiler->lvaPSPSym != BAD_VAR_NUM);
1908 #else
1909     hasPspSym = false;
1910 #endif
1911
1912     // compute the amount of memory to allocate to properly STACK_ALIGN.
1913     size_t amount = 0;
1914     if (size->IsCnsIntOrI())
1915     {
1916         // If size is a constant, then it must be contained.
1917         assert(size->isContained());
1918
1919         // If amount is zero then return null in targetReg
1920         amount = size->gtIntCon.gtIconVal;
1921         if (amount == 0)
1922         {
1923             instGen_Set_Reg_To_Zero(EA_PTRSIZE, targetReg);
1924             goto BAILOUT;
1925         }
1926
1927         // 'amount' is the total numbe of bytes to localloc to properly STACK_ALIGN
1928         amount = AlignUp(amount, STACK_ALIGN);
1929     }
1930     else
1931     {
1932         // If 0 bail out by returning null in targetReg
1933         genConsumeRegAndCopy(size, targetReg);
1934         endLabel = genCreateTempLabel();
1935         getEmitter()->emitIns_R_R(INS_tst, easz, targetReg, targetReg);
1936         emitJumpKind jmpEqual = genJumpKindForOper(GT_EQ, CK_SIGNED);
1937         inst_JMP(jmpEqual, endLabel);
1938
1939         // Compute the size of the block to allocate and perform alignment.
1940         // If the method has no PSPSym and compInitMem=true, we can reuse targetReg as regcnt,
1941         // since we don't need any internal registers.
1942         if (!hasPspSym && compiler->info.compInitMem)
1943         {
1944             assert(tree->AvailableTempRegCount() == 0);
1945             regCnt = targetReg;
1946         }
1947         else
1948         {
1949             regCnt = tree->ExtractTempReg();
1950             if (regCnt != targetReg)
1951             {
1952                 inst_RV_RV(INS_mov, regCnt, targetReg, size->TypeGet());
1953             }
1954         }
1955
1956         // Align to STACK_ALIGN
1957         // regCnt will be the total number of bytes to localloc
1958         inst_RV_IV(INS_add, regCnt, (STACK_ALIGN - 1), emitActualTypeSize(type));
1959         inst_RV_IV(INS_and, regCnt, ~(STACK_ALIGN - 1), emitActualTypeSize(type));
1960     }
1961
1962     stackAdjustment = 0;
1963 #if FEATURE_EH_FUNCLETS
1964     // If we have PSPsym, then need to re-locate it after localloc.
1965     if (hasPspSym)
1966     {
1967         stackAdjustment += STACK_ALIGN;
1968
1969         // Save a copy of PSPSym
1970         pspSymReg = tree->ExtractTempReg();
1971         getEmitter()->emitIns_R_S(ins_Load(TYP_I_IMPL), EA_PTRSIZE, pspSymReg, compiler->lvaPSPSym, 0);
1972     }
1973 #endif
1974
1975 #if FEATURE_FIXED_OUT_ARGS
1976     // If we have an outgoing arg area then we must adjust the SP by popping off the
1977     // outgoing arg area. We will restore it right before we return from this method.
1978     //
1979     // Localloc is supposed to return stack space that is STACK_ALIGN'ed.  The following
1980     // are the cases that needs to be handled:
1981     //   i) Method has PSPSym + out-going arg area.
1982     //      It is guaranteed that size of out-going arg area is STACK_ALIGNED (see fgMorphArgs).
1983     //      Therefore, we will pop-off RSP upto out-going arg area before locallocating.
1984     //      We need to add padding to ensure RSP is STACK_ALIGN'ed while re-locating PSPSym + arg area.
1985     //  ii) Method has no PSPSym but out-going arg area.
1986     //      Almost same case as above without the requirement to pad for the final RSP to be STACK_ALIGN'ed.
1987     // iii) Method has PSPSym but no out-going arg area.
1988     //      Nothing to pop-off from the stack but needs to relocate PSPSym with SP padded.
1989     //  iv) Method has neither PSPSym nor out-going arg area.
1990     //      Nothing needs to popped off from stack nor relocated.
1991     if (compiler->lvaOutgoingArgSpaceSize > 0)
1992     {
1993         assert((compiler->lvaOutgoingArgSpaceSize % STACK_ALIGN) == 0); // This must be true for the stack to remain
1994                                                                         // aligned
1995         inst_RV_IV(INS_add, REG_SPBASE, compiler->lvaOutgoingArgSpaceSize, EA_PTRSIZE);
1996         stackAdjustment += compiler->lvaOutgoingArgSpaceSize;
1997     }
1998 #endif
1999
2000     if (size->IsCnsIntOrI())
2001     {
2002         // We should reach here only for non-zero, constant size allocations.
2003         assert(amount > 0);
2004
2005         // For small allocations we will generate up to four stp instructions
2006         size_t cntStackAlignedWidthItems = (amount >> STACK_ALIGN_SHIFT);
2007         if (cntStackAlignedWidthItems <= 4)
2008         {
2009             while (cntStackAlignedWidthItems != 0)
2010             {
2011                 // We can use pre-indexed addressing.
2012                 // stp ZR, ZR, [SP, #-16]!
2013                 getEmitter()->emitIns_R_R_R_I(INS_stp, EA_PTRSIZE, REG_ZR, REG_ZR, REG_SPBASE, -16, INS_OPTS_PRE_INDEX);
2014                 cntStackAlignedWidthItems -= 1;
2015             }
2016
2017             goto ALLOC_DONE;
2018         }
2019         else if (!compiler->info.compInitMem && (amount < compiler->eeGetPageSize())) // must be < not <=
2020         {
2021             // Since the size is a page or less, simply adjust the SP value
2022             // The SP might already be in the guard page, must touch it BEFORE
2023             // the alloc, not after.
2024             // ldr wz, [SP, #0]
2025             getEmitter()->emitIns_R_R_I(INS_ldr, EA_4BYTE, REG_ZR, REG_SP, 0);
2026
2027             inst_RV_IV(INS_sub, REG_SP, amount, EA_PTRSIZE);
2028
2029             goto ALLOC_DONE;
2030         }
2031
2032         // else, "mov regCnt, amount"
2033         // If the method has no PSPSym and compInitMem=true, we can reuse targetReg as regcnt.
2034         // Since size is a constant, regCnt is not yet initialized.
2035         assert(regCnt == REG_NA);
2036         if (!hasPspSym && compiler->info.compInitMem)
2037         {
2038             assert(tree->AvailableTempRegCount() == 0);
2039             regCnt = targetReg;
2040         }
2041         else
2042         {
2043             regCnt = tree->ExtractTempReg();
2044         }
2045         genSetRegToIcon(regCnt, amount, ((int)amount == amount) ? TYP_INT : TYP_LONG);
2046     }
2047
2048     if (compiler->info.compInitMem)
2049     {
2050         BasicBlock* loop = genCreateTempLabel();
2051
2052         // At this point 'regCnt' is set to the total number of bytes to locAlloc.
2053         // Since we have to zero out the allocated memory AND ensure that RSP is always valid
2054         // by tickling the pages, we will just push 0's on the stack.
2055         //
2056         // Note: regCnt is guaranteed to be even on Amd64 since STACK_ALIGN/TARGET_POINTER_SIZE = 2
2057         // and localloc size is a multiple of STACK_ALIGN.
2058
2059         // Loop:
2060         genDefineTempLabel(loop);
2061
2062         // We can use pre-indexed addressing.
2063         // stp ZR, ZR, [SP, #-16]!
2064         getEmitter()->emitIns_R_R_R_I(INS_stp, EA_PTRSIZE, REG_ZR, REG_ZR, REG_SPBASE, -16, INS_OPTS_PRE_INDEX);
2065
2066         // If not done, loop
2067         // Note that regCnt is the number of bytes to stack allocate.
2068         // Therefore we need to subtract 16 from regcnt here.
2069         assert(genIsValidIntReg(regCnt));
2070         inst_RV_IV(INS_subs, regCnt, 16, emitActualTypeSize(type));
2071         emitJumpKind jmpNotEqual = genJumpKindForOper(GT_NE, CK_SIGNED);
2072         inst_JMP(jmpNotEqual, loop);
2073     }
2074     else
2075     {
2076         // At this point 'regCnt' is set to the total number of bytes to locAlloc.
2077         //
2078         // We don't need to zero out the allocated memory. However, we do have
2079         // to tickle the pages to ensure that SP is always valid and is
2080         // in sync with the "stack guard page".  Note that in the worst
2081         // case SP is on the last byte of the guard page.  Thus you must
2082         // touch SP-0 first not SP-0x1000.
2083         //
2084         // Another subtlety is that you don't want SP to be exactly on the
2085         // boundary of the guard page because PUSH is predecrement, thus
2086         // call setup would not touch the guard page but just beyond it
2087         //
2088         // Note that we go through a few hoops so that SP never points to
2089         // illegal pages at any time during the tickling process
2090         //
2091         //       subs  regCnt, SP, regCnt      // regCnt now holds ultimate SP
2092         //       bvc   Loop                    // result is smaller than orignial SP (no wrap around)
2093         //       mov   regCnt, #0              // Overflow, pick lowest possible value
2094         //
2095         //  Loop:
2096         //       ldr   wzr, [SP + 0]           // tickle the page - read from the page
2097         //       sub   regTmp, SP, PAGE_SIZE   // decrement SP by eeGetPageSize()
2098         //       cmp   regTmp, regCnt
2099         //       jb    Done
2100         //       mov   SP, regTmp
2101         //       j     Loop
2102         //
2103         //  Done:
2104         //       mov   SP, regCnt
2105         //
2106
2107         // Setup the regTmp
2108         regNumber regTmp = tree->GetSingleTempReg();
2109
2110         BasicBlock* loop = genCreateTempLabel();
2111         BasicBlock* done = genCreateTempLabel();
2112
2113         //       subs  regCnt, SP, regCnt      // regCnt now holds ultimate SP
2114         getEmitter()->emitIns_R_R_R(INS_subs, EA_PTRSIZE, regCnt, REG_SPBASE, regCnt);
2115
2116         inst_JMP(EJ_vc, loop); // branch if the V flag is not set
2117
2118         // Overflow, set regCnt to lowest possible value
2119         instGen_Set_Reg_To_Zero(EA_PTRSIZE, regCnt);
2120
2121         genDefineTempLabel(loop);
2122
2123         // tickle the page - Read from the updated SP - this triggers a page fault when on the guard page
2124         getEmitter()->emitIns_R_R_I(INS_ldr, EA_4BYTE, REG_ZR, REG_SPBASE, 0);
2125
2126         // decrement SP by eeGetPageSize()
2127         getEmitter()->emitIns_R_R_I(INS_sub, EA_PTRSIZE, regTmp, REG_SPBASE, compiler->eeGetPageSize());
2128
2129         getEmitter()->emitIns_R_R(INS_cmp, EA_PTRSIZE, regTmp, regCnt);
2130         emitJumpKind jmpLTU = genJumpKindForOper(GT_LT, CK_UNSIGNED);
2131         inst_JMP(jmpLTU, done);
2132
2133         // Update SP to be at the next page of stack that we will tickle
2134         getEmitter()->emitIns_R_R(INS_mov, EA_PTRSIZE, REG_SPBASE, regTmp);
2135
2136         // Jump to loop and tickle new stack address
2137         inst_JMP(EJ_jmp, loop);
2138
2139         // Done with stack tickle loop
2140         genDefineTempLabel(done);
2141
2142         // Now just move the final value to SP
2143         getEmitter()->emitIns_R_R(INS_mov, EA_PTRSIZE, REG_SPBASE, regCnt);
2144     }
2145
2146 ALLOC_DONE:
2147     // Re-adjust SP to allocate PSPSym and out-going arg area
2148     if (stackAdjustment != 0)
2149     {
2150         assert((stackAdjustment % STACK_ALIGN) == 0); // This must be true for the stack to remain aligned
2151         assert(stackAdjustment > 0);
2152         getEmitter()->emitIns_R_R_I(INS_sub, EA_PTRSIZE, REG_SPBASE, REG_SPBASE, (int)stackAdjustment);
2153
2154 #if FEATURE_EH_FUNCLETS
2155         // Write PSPSym to its new location.
2156         if (hasPspSym)
2157         {
2158             assert(genIsValidIntReg(pspSymReg));
2159             getEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), EA_PTRSIZE, pspSymReg, compiler->lvaPSPSym, 0);
2160         }
2161 #endif
2162         // Return the stackalloc'ed address in result register.
2163         // TargetReg = RSP + stackAdjustment.
2164         //
2165         getEmitter()->emitIns_R_R_I(INS_add, EA_PTRSIZE, targetReg, REG_SPBASE, (int)stackAdjustment);
2166     }
2167     else // stackAdjustment == 0
2168     {
2169         // Move the final value of SP to targetReg
2170         inst_RV_RV(INS_mov, targetReg, REG_SPBASE);
2171     }
2172
2173 BAILOUT:
2174     if (endLabel != nullptr)
2175         genDefineTempLabel(endLabel);
2176
2177     // Write the lvaLocAllocSPvar stack frame slot
2178     if (compiler->lvaLocAllocSPvar != BAD_VAR_NUM)
2179     {
2180         getEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), EA_PTRSIZE, targetReg, compiler->lvaLocAllocSPvar, 0);
2181     }
2182
2183 #if STACK_PROBES
2184     if (compiler->opts.compNeedStackProbes)
2185     {
2186         genGenerateStackProbe();
2187     }
2188 #endif
2189
2190 #ifdef DEBUG
2191     // Update new ESP
2192     if (compiler->opts.compStackCheckOnRet)
2193     {
2194         noway_assert(compiler->lvaReturnEspCheck != 0xCCCCCCCC &&
2195                      compiler->lvaTable[compiler->lvaReturnEspCheck].lvDoNotEnregister &&
2196                      compiler->lvaTable[compiler->lvaReturnEspCheck].lvOnFrame);
2197         getEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), EA_PTRSIZE, targetReg, compiler->lvaReturnEspCheck, 0);
2198     }
2199 #endif
2200
2201     genProduceReg(tree);
2202 }
2203
2204 //------------------------------------------------------------------------
2205 // genCodeForNegNot: Produce code for a GT_NEG/GT_NOT node.
2206 //
2207 // Arguments:
2208 //    tree - the node
2209 //
2210 void CodeGen::genCodeForNegNot(GenTree* tree)
2211 {
2212     assert(tree->OperIs(GT_NEG, GT_NOT));
2213
2214     var_types targetType = tree->TypeGet();
2215
2216     assert(!tree->OperIs(GT_NOT) || !varTypeIsFloating(targetType));
2217
2218     regNumber   targetReg = tree->gtRegNum;
2219     instruction ins       = genGetInsForOper(tree->OperGet(), targetType);
2220
2221     // The arithmetic node must be sitting in a register (since it's not contained)
2222     assert(!tree->isContained());
2223     // The dst can only be a register.
2224     assert(targetReg != REG_NA);
2225
2226     GenTree* operand = tree->gtGetOp1();
2227     assert(!operand->isContained());
2228     // The src must be a register.
2229     regNumber operandReg = genConsumeReg(operand);
2230
2231     getEmitter()->emitIns_R_R(ins, emitActualTypeSize(tree), targetReg, operandReg);
2232
2233     genProduceReg(tree);
2234 }
2235
2236 //------------------------------------------------------------------------
2237 // genCodeForDivMod: Produce code for a GT_DIV/GT_UDIV node. We don't see MOD:
2238 // (1) integer MOD is morphed into a sequence of sub, mul, div in fgMorph;
2239 // (2) float/double MOD is morphed into a helper call by front-end.
2240 //
2241 // Arguments:
2242 //    tree - the node
2243 //
2244 void CodeGen::genCodeForDivMod(GenTreeOp* tree)
2245 {
2246     assert(tree->OperIs(GT_DIV, GT_UDIV));
2247
2248     var_types targetType = tree->TypeGet();
2249     emitter*  emit       = getEmitter();
2250
2251     genConsumeOperands(tree);
2252
2253     if (varTypeIsFloating(targetType))
2254     {
2255         // Floating point divide never raises an exception
2256         genCodeForBinary(tree);
2257     }
2258     else // an integer divide operation
2259     {
2260         GenTree* divisorOp = tree->gtGetOp2();
2261         emitAttr size      = EA_ATTR(genTypeSize(genActualType(tree->TypeGet())));
2262
2263         if (divisorOp->IsIntegralConst(0))
2264         {
2265             // We unconditionally throw a divide by zero exception
2266             genJumpToThrowHlpBlk(EJ_jmp, SCK_DIV_BY_ZERO);
2267
2268             // We still need to call genProduceReg
2269             genProduceReg(tree);
2270         }
2271         else // the divisor is not the constant zero
2272         {
2273             regNumber divisorReg = divisorOp->gtRegNum;
2274
2275             // Generate the require runtime checks for GT_DIV or GT_UDIV
2276             if (tree->gtOper == GT_DIV)
2277             {
2278                 BasicBlock* sdivLabel = genCreateTempLabel();
2279
2280                 // Two possible exceptions:
2281                 //     (AnyVal /  0) => DivideByZeroException
2282                 //     (MinInt / -1) => ArithmeticException
2283                 //
2284                 bool checkDividend = true;
2285
2286                 // Do we have an immediate for the 'divisorOp'?
2287                 //
2288                 if (divisorOp->IsCnsIntOrI())
2289                 {
2290                     GenTreeIntConCommon* intConstTree  = divisorOp->AsIntConCommon();
2291                     ssize_t              intConstValue = intConstTree->IconValue();
2292                     assert(intConstValue != 0); // already checked above by IsIntegralConst(0))
2293                     if (intConstValue != -1)
2294                     {
2295                         checkDividend = false; // We statically know that the dividend is not -1
2296                     }
2297                 }
2298                 else // insert check for divison by zero
2299                 {
2300                     // Check if the divisor is zero throw a DivideByZeroException
2301                     emit->emitIns_R_I(INS_cmp, size, divisorReg, 0);
2302                     emitJumpKind jmpEqual = genJumpKindForOper(GT_EQ, CK_SIGNED);
2303                     genJumpToThrowHlpBlk(jmpEqual, SCK_DIV_BY_ZERO);
2304                 }
2305
2306                 if (checkDividend)
2307                 {
2308                     // Check if the divisor is not -1 branch to 'sdivLabel'
2309                     emit->emitIns_R_I(INS_cmp, size, divisorReg, -1);
2310
2311                     emitJumpKind jmpNotEqual = genJumpKindForOper(GT_NE, CK_SIGNED);
2312                     inst_JMP(jmpNotEqual, sdivLabel);
2313                     // If control flow continues past here the 'divisorReg' is known to be -1
2314
2315                     regNumber dividendReg = tree->gtGetOp1()->gtRegNum;
2316                     // At this point the divisor is known to be -1
2317                     //
2318                     // Issue the 'adds  zr, dividendReg, dividendReg' instruction
2319                     // this will set both the Z and V flags only when dividendReg is MinInt
2320                     //
2321                     emit->emitIns_R_R_R(INS_adds, size, REG_ZR, dividendReg, dividendReg);
2322                     inst_JMP(jmpNotEqual, sdivLabel);             // goto sdiv if the Z flag is clear
2323                     genJumpToThrowHlpBlk(EJ_vs, SCK_ARITH_EXCPN); // if the V flags is set throw
2324                                                                   // ArithmeticException
2325
2326                     genDefineTempLabel(sdivLabel);
2327                 }
2328                 genCodeForBinary(tree); // Generate the sdiv instruction
2329             }
2330             else // (tree->gtOper == GT_UDIV)
2331             {
2332                 // Only one possible exception
2333                 //     (AnyVal /  0) => DivideByZeroException
2334                 //
2335                 // Note that division by the constant 0 was already checked for above by the
2336                 // op2->IsIntegralConst(0) check
2337                 //
2338                 if (!divisorOp->IsCnsIntOrI())
2339                 {
2340                     // divisorOp is not a constant, so it could be zero
2341                     //
2342                     emit->emitIns_R_I(INS_cmp, size, divisorReg, 0);
2343                     emitJumpKind jmpEqual = genJumpKindForOper(GT_EQ, CK_SIGNED);
2344                     genJumpToThrowHlpBlk(jmpEqual, SCK_DIV_BY_ZERO);
2345                 }
2346                 genCodeForBinary(tree);
2347             }
2348         }
2349     }
2350 }
2351
2352 // Generate code for InitBlk by performing a loop unroll
2353 // Preconditions:
2354 //   a) Both the size and fill byte value are integer constants.
2355 //   b) The size of the struct to initialize is smaller than INITBLK_UNROLL_LIMIT bytes.
2356 void CodeGen::genCodeForInitBlkUnroll(GenTreeBlk* initBlkNode)
2357 {
2358     // Make sure we got the arguments of the initblk/initobj operation in the right registers
2359     unsigned size    = initBlkNode->Size();
2360     GenTree* dstAddr = initBlkNode->Addr();
2361     GenTree* initVal = initBlkNode->Data();
2362     if (initVal->OperIsInitVal())
2363     {
2364         initVal = initVal->gtGetOp1();
2365     }
2366
2367     assert(dstAddr->isUsedFromReg());
2368     assert(initVal->isUsedFromReg() && !initVal->IsIntegralConst(0) || initVal->IsIntegralConst(0));
2369     assert(size != 0);
2370     assert(size <= INITBLK_UNROLL_LIMIT);
2371
2372     emitter* emit = getEmitter();
2373
2374     genConsumeOperands(initBlkNode);
2375
2376     if (initBlkNode->gtFlags & GTF_BLK_VOLATILE)
2377     {
2378         // issue a full memory barrier before a volatile initBlockUnroll operation
2379         instGen_MemoryBarrier();
2380     }
2381
2382     regNumber valReg = initVal->IsIntegralConst(0) ? REG_ZR : initVal->gtRegNum;
2383
2384     assert(!initVal->IsIntegralConst(0) || (valReg == REG_ZR));
2385
2386     unsigned offset = 0;
2387
2388     // Perform an unroll using stp.
2389     if (size >= 2 * REGSIZE_BYTES)
2390     {
2391         // Determine how many 16 byte slots
2392         size_t slots = size / (2 * REGSIZE_BYTES);
2393
2394         while (slots-- > 0)
2395         {
2396             emit->emitIns_R_R_R_I(INS_stp, EA_8BYTE, valReg, valReg, dstAddr->gtRegNum, offset);
2397             offset += (2 * REGSIZE_BYTES);
2398         }
2399     }
2400
2401     // Fill the remainder (15 bytes or less) if there's any.
2402     if ((size & 0xf) != 0)
2403     {
2404         if ((size & 8) != 0)
2405         {
2406             emit->emitIns_R_R_I(INS_str, EA_8BYTE, valReg, dstAddr->gtRegNum, offset);
2407             offset += 8;
2408         }
2409         if ((size & 4) != 0)
2410         {
2411             emit->emitIns_R_R_I(INS_str, EA_4BYTE, valReg, dstAddr->gtRegNum, offset);
2412             offset += 4;
2413         }
2414         if ((size & 2) != 0)
2415         {
2416             emit->emitIns_R_R_I(INS_strh, EA_2BYTE, valReg, dstAddr->gtRegNum, offset);
2417             offset += 2;
2418         }
2419         if ((size & 1) != 0)
2420         {
2421             emit->emitIns_R_R_I(INS_strb, EA_1BYTE, valReg, dstAddr->gtRegNum, offset);
2422         }
2423     }
2424 }
2425
2426 // Generate code for a load pair from some address + offset
2427 //   base: tree node which can be either a local address or arbitrary node
2428 //   offset: distance from the base from which to load
2429 void CodeGen::genCodeForLoadPairOffset(regNumber dst, regNumber dst2, GenTree* base, unsigned offset)
2430 {
2431     emitter* emit = getEmitter();
2432
2433     if (base->OperIsLocalAddr())
2434     {
2435         if (base->gtOper == GT_LCL_FLD_ADDR)
2436             offset += base->gtLclFld.gtLclOffs;
2437
2438         emit->emitIns_R_R_S_S(INS_ldp, EA_8BYTE, EA_8BYTE, dst, dst2, base->gtLclVarCommon.gtLclNum, offset);
2439     }
2440     else
2441     {
2442         emit->emitIns_R_R_R_I(INS_ldp, EA_8BYTE, dst, dst2, base->gtRegNum, offset);
2443     }
2444 }
2445
2446 // Generate code for a store pair to some address + offset
2447 //   base: tree node which can be either a local address or arbitrary node
2448 //   offset: distance from the base from which to load
2449 void CodeGen::genCodeForStorePairOffset(regNumber src, regNumber src2, GenTree* base, unsigned offset)
2450 {
2451     emitter* emit = getEmitter();
2452
2453     if (base->OperIsLocalAddr())
2454     {
2455         if (base->gtOper == GT_LCL_FLD_ADDR)
2456             offset += base->gtLclFld.gtLclOffs;
2457
2458         emit->emitIns_S_S_R_R(INS_stp, EA_8BYTE, EA_8BYTE, src, src2, base->gtLclVarCommon.gtLclNum, offset);
2459     }
2460     else
2461     {
2462         emit->emitIns_R_R_R_I(INS_stp, EA_8BYTE, src, src2, base->gtRegNum, offset);
2463     }
2464 }
2465
2466 // Generate code for CpObj nodes wich copy structs that have interleaved
2467 // GC pointers.
2468 // For this case we'll generate a sequence of loads/stores in the case of struct
2469 // slots that don't contain GC pointers.  The generated code will look like:
2470 // ldr tempReg, [R13, #8]
2471 // str tempReg, [R14, #8]
2472 //
2473 // In the case of a GC-Pointer we'll call the ByRef write barrier helper
2474 // who happens to use the same registers as the previous call to maintain
2475 // the same register requirements and register killsets:
2476 // bl CORINFO_HELP_ASSIGN_BYREF
2477 //
2478 // So finally an example would look like this:
2479 // ldr tempReg, [R13, #8]
2480 // str tempReg, [R14, #8]
2481 // bl CORINFO_HELP_ASSIGN_BYREF
2482 // ldr tempReg, [R13, #8]
2483 // str tempReg, [R14, #8]
2484 // bl CORINFO_HELP_ASSIGN_BYREF
2485 // ldr tempReg, [R13, #8]
2486 // str tempReg, [R14, #8]
2487 void CodeGen::genCodeForCpObj(GenTreeObj* cpObjNode)
2488 {
2489     GenTree*  dstAddr       = cpObjNode->Addr();
2490     GenTree*  source        = cpObjNode->Data();
2491     var_types srcAddrType   = TYP_BYREF;
2492     bool      sourceIsLocal = false;
2493
2494     assert(source->isContained());
2495     if (source->gtOper == GT_IND)
2496     {
2497         GenTree* srcAddr = source->gtGetOp1();
2498         assert(!srcAddr->isContained());
2499         srcAddrType = srcAddr->TypeGet();
2500     }
2501     else
2502     {
2503         noway_assert(source->IsLocal());
2504         sourceIsLocal = true;
2505     }
2506
2507     bool dstOnStack = dstAddr->OperIsLocalAddr();
2508
2509 #ifdef DEBUG
2510     assert(!dstAddr->isContained());
2511
2512     // This GenTree node has data about GC pointers, this means we're dealing
2513     // with CpObj.
2514     assert(cpObjNode->gtGcPtrCount > 0);
2515 #endif // DEBUG
2516
2517     // Consume the operands and get them into the right registers.
2518     // They may now contain gc pointers (depending on their type; gcMarkRegPtrVal will "do the right thing").
2519     genConsumeBlockOp(cpObjNode, REG_WRITE_BARRIER_DST_BYREF, REG_WRITE_BARRIER_SRC_BYREF, REG_NA);
2520     gcInfo.gcMarkRegPtrVal(REG_WRITE_BARRIER_SRC_BYREF, srcAddrType);
2521     gcInfo.gcMarkRegPtrVal(REG_WRITE_BARRIER_DST_BYREF, dstAddr->TypeGet());
2522
2523     unsigned slots = cpObjNode->gtSlots;
2524
2525     // Temp register(s) used to perform the sequence of loads and stores.
2526     regNumber tmpReg  = cpObjNode->ExtractTempReg();
2527     regNumber tmpReg2 = REG_NA;
2528
2529     assert(genIsValidIntReg(tmpReg));
2530     assert(tmpReg != REG_WRITE_BARRIER_SRC_BYREF);
2531     assert(tmpReg != REG_WRITE_BARRIER_DST_BYREF);
2532
2533     if (slots > 1)
2534     {
2535         tmpReg2 = cpObjNode->GetSingleTempReg();
2536         assert(tmpReg2 != tmpReg);
2537         assert(genIsValidIntReg(tmpReg2));
2538         assert(tmpReg2 != REG_WRITE_BARRIER_DST_BYREF);
2539         assert(tmpReg2 != REG_WRITE_BARRIER_SRC_BYREF);
2540     }
2541
2542     if (cpObjNode->gtFlags & GTF_BLK_VOLATILE)
2543     {
2544         // issue a full memory barrier before a volatile CpObj operation
2545         instGen_MemoryBarrier();
2546     }
2547
2548     emitter* emit = getEmitter();
2549
2550     BYTE* gcPtrs = cpObjNode->gtGcPtrs;
2551
2552     // If we can prove it's on the stack we don't need to use the write barrier.
2553     if (dstOnStack)
2554     {
2555         unsigned i = 0;
2556         // Check if two or more remaining slots and use a ldp/stp sequence
2557         while (i < slots - 1)
2558         {
2559             emitAttr attr0 = emitTypeSize(compiler->getJitGCType(gcPtrs[i + 0]));
2560             emitAttr attr1 = emitTypeSize(compiler->getJitGCType(gcPtrs[i + 1]));
2561
2562             emit->emitIns_R_R_R_I(INS_ldp, attr0, tmpReg, tmpReg2, REG_WRITE_BARRIER_SRC_BYREF, 2 * TARGET_POINTER_SIZE,
2563                                   INS_OPTS_POST_INDEX, attr1);
2564             emit->emitIns_R_R_R_I(INS_stp, attr0, tmpReg, tmpReg2, REG_WRITE_BARRIER_DST_BYREF, 2 * TARGET_POINTER_SIZE,
2565                                   INS_OPTS_POST_INDEX, attr1);
2566             i += 2;
2567         }
2568
2569         // Use a ldr/str sequence for the last remainder
2570         if (i < slots)
2571         {
2572             emitAttr attr0 = emitTypeSize(compiler->getJitGCType(gcPtrs[i + 0]));
2573
2574             emit->emitIns_R_R_I(INS_ldr, attr0, tmpReg, REG_WRITE_BARRIER_SRC_BYREF, TARGET_POINTER_SIZE,
2575                                 INS_OPTS_POST_INDEX);
2576             emit->emitIns_R_R_I(INS_str, attr0, tmpReg, REG_WRITE_BARRIER_DST_BYREF, TARGET_POINTER_SIZE,
2577                                 INS_OPTS_POST_INDEX);
2578         }
2579     }
2580     else
2581     {
2582         unsigned gcPtrCount = cpObjNode->gtGcPtrCount;
2583
2584         unsigned i = 0;
2585         while (i < slots)
2586         {
2587             switch (gcPtrs[i])
2588             {
2589                 case TYPE_GC_NONE:
2590                     // Check if the next slot's type is also TYP_GC_NONE and use ldp/stp
2591                     if ((i + 1 < slots) && (gcPtrs[i + 1] == TYPE_GC_NONE))
2592                     {
2593                         emit->emitIns_R_R_R_I(INS_ldp, EA_8BYTE, tmpReg, tmpReg2, REG_WRITE_BARRIER_SRC_BYREF,
2594                                               2 * TARGET_POINTER_SIZE, INS_OPTS_POST_INDEX);
2595                         emit->emitIns_R_R_R_I(INS_stp, EA_8BYTE, tmpReg, tmpReg2, REG_WRITE_BARRIER_DST_BYREF,
2596                                               2 * TARGET_POINTER_SIZE, INS_OPTS_POST_INDEX);
2597                         ++i; // extra increment of i, since we are copying two items
2598                     }
2599                     else
2600                     {
2601                         emit->emitIns_R_R_I(INS_ldr, EA_8BYTE, tmpReg, REG_WRITE_BARRIER_SRC_BYREF, TARGET_POINTER_SIZE,
2602                                             INS_OPTS_POST_INDEX);
2603                         emit->emitIns_R_R_I(INS_str, EA_8BYTE, tmpReg, REG_WRITE_BARRIER_DST_BYREF, TARGET_POINTER_SIZE,
2604                                             INS_OPTS_POST_INDEX);
2605                     }
2606                     break;
2607
2608                 default:
2609                     // In the case of a GC-Pointer we'll call the ByRef write barrier helper
2610                     genEmitHelperCall(CORINFO_HELP_ASSIGN_BYREF, 0, EA_PTRSIZE);
2611
2612                     gcPtrCount--;
2613                     break;
2614             }
2615             ++i;
2616         }
2617         assert(gcPtrCount == 0);
2618     }
2619
2620     if (cpObjNode->gtFlags & GTF_BLK_VOLATILE)
2621     {
2622         // issue a INS_BARRIER_ISHLD after a volatile CpObj operation
2623         instGen_MemoryBarrier(INS_BARRIER_ISHLD);
2624     }
2625
2626     // Clear the gcInfo for REG_WRITE_BARRIER_SRC_BYREF and REG_WRITE_BARRIER_DST_BYREF.
2627     // While we normally update GC info prior to the last instruction that uses them,
2628     // these actually live into the helper call.
2629     gcInfo.gcMarkRegSetNpt(RBM_WRITE_BARRIER_SRC_BYREF | RBM_WRITE_BARRIER_DST_BYREF);
2630 }
2631
2632 // generate code do a switch statement based on a table of ip-relative offsets
2633 void CodeGen::genTableBasedSwitch(GenTree* treeNode)
2634 {
2635     genConsumeOperands(treeNode->AsOp());
2636     regNumber idxReg  = treeNode->gtOp.gtOp1->gtRegNum;
2637     regNumber baseReg = treeNode->gtOp.gtOp2->gtRegNum;
2638
2639     regNumber tmpReg = treeNode->GetSingleTempReg();
2640
2641     // load the ip-relative offset (which is relative to start of fgFirstBB)
2642     getEmitter()->emitIns_R_R_R(INS_ldr, EA_4BYTE, baseReg, baseReg, idxReg, INS_OPTS_LSL);
2643
2644     // add it to the absolute address of fgFirstBB
2645     compiler->fgFirstBB->bbFlags |= BBF_JMP_TARGET;
2646     getEmitter()->emitIns_R_L(INS_adr, EA_PTRSIZE, compiler->fgFirstBB, tmpReg);
2647     getEmitter()->emitIns_R_R_R(INS_add, EA_PTRSIZE, baseReg, baseReg, tmpReg);
2648
2649     // br baseReg
2650     getEmitter()->emitIns_R(INS_br, emitActualTypeSize(TYP_I_IMPL), baseReg);
2651 }
2652
2653 // emits the table and an instruction to get the address of the first element
2654 void CodeGen::genJumpTable(GenTree* treeNode)
2655 {
2656     noway_assert(compiler->compCurBB->bbJumpKind == BBJ_SWITCH);
2657     assert(treeNode->OperGet() == GT_JMPTABLE);
2658
2659     unsigned     jumpCount = compiler->compCurBB->bbJumpSwt->bbsCount;
2660     BasicBlock** jumpTable = compiler->compCurBB->bbJumpSwt->bbsDstTab;
2661     unsigned     jmpTabOffs;
2662     unsigned     jmpTabBase;
2663
2664     jmpTabBase = getEmitter()->emitBBTableDataGenBeg(jumpCount, true);
2665
2666     jmpTabOffs = 0;
2667
2668     JITDUMP("\n      J_M%03u_DS%02u LABEL   DWORD\n", Compiler::s_compMethodsCount, jmpTabBase);
2669
2670     for (unsigned i = 0; i < jumpCount; i++)
2671     {
2672         BasicBlock* target = *jumpTable++;
2673         noway_assert(target->bbFlags & BBF_JMP_TARGET);
2674
2675         JITDUMP("            DD      L_M%03u_BB%02u\n", Compiler::s_compMethodsCount, target->bbNum);
2676
2677         getEmitter()->emitDataGenData(i, target);
2678     };
2679
2680     getEmitter()->emitDataGenEnd();
2681
2682     // Access to inline data is 'abstracted' by a special type of static member
2683     // (produced by eeFindJitDataOffs) which the emitter recognizes as being a reference
2684     // to constant data, not a real static field.
2685     getEmitter()->emitIns_R_C(INS_adr, emitActualTypeSize(TYP_I_IMPL), treeNode->gtRegNum, REG_NA,
2686                               compiler->eeFindJitDataOffs(jmpTabBase), 0);
2687     genProduceReg(treeNode);
2688 }
2689
2690 // generate code for the locked operations:
2691 // GT_LOCKADD, GT_XCHG, GT_XADD
2692 void CodeGen::genLockedInstructions(GenTreeOp* treeNode)
2693 {
2694     GenTree*  data      = treeNode->gtOp.gtOp2;
2695     GenTree*  addr      = treeNode->gtOp.gtOp1;
2696     regNumber targetReg = treeNode->gtRegNum;
2697     regNumber dataReg   = data->gtRegNum;
2698     regNumber addrReg   = addr->gtRegNum;
2699
2700     regNumber exResultReg  = treeNode->ExtractTempReg(RBM_ALLINT);
2701     regNumber storeDataReg = (treeNode->OperGet() == GT_XCHG) ? dataReg : treeNode->ExtractTempReg(RBM_ALLINT);
2702     regNumber loadReg      = (targetReg != REG_NA) ? targetReg : storeDataReg;
2703
2704     // Check allocator assumptions
2705     //
2706     // The register allocator should have extended the lifetimes of all input and internal registers so that
2707     // none interfere with the target.
2708     noway_assert(addrReg != targetReg);
2709
2710     noway_assert(addrReg != loadReg);
2711     noway_assert(dataReg != loadReg);
2712
2713     noway_assert(addrReg != storeDataReg);
2714     noway_assert((treeNode->OperGet() == GT_XCHG) || (addrReg != dataReg));
2715
2716     assert(addr->isUsedFromReg());
2717     noway_assert(exResultReg != REG_NA);
2718     noway_assert(exResultReg != targetReg);
2719     noway_assert((targetReg != REG_NA) || (treeNode->OperGet() != GT_XCHG));
2720
2721     // Store exclusive unpredictable cases must be avoided
2722     noway_assert(exResultReg != storeDataReg);
2723     noway_assert(exResultReg != addrReg);
2724
2725     genConsumeAddress(addr);
2726     genConsumeRegs(data);
2727
2728     // NOTE: `genConsumeAddress` marks the consumed register as not a GC pointer, as it assumes that the input registers
2729     // die at the first instruction generated by the node. This is not the case for these atomics as the  input
2730     // registers are multiply-used. As such, we need to mark the addr register as containing a GC pointer until
2731     // we are finished generating the code for this node.
2732
2733     gcInfo.gcMarkRegPtrVal(addrReg, addr->TypeGet());
2734
2735     // TODO-ARM64-CQ Use ARMv8.1 atomics if available
2736     // https://github.com/dotnet/coreclr/issues/11881
2737
2738     // Emit code like this:
2739     //   retry:
2740     //     ldxr loadReg, [addrReg]
2741     //     add storeDataReg, loadReg, dataReg         # Only for GT_XADD & GT_LOCKADD
2742     //                                                # GT_XCHG storeDataReg === dataReg
2743     //     stxr exResult, storeDataReg, [addrReg]
2744     //     cbnz exResult, retry
2745
2746     BasicBlock* labelRetry = genCreateTempLabel();
2747     genDefineTempLabel(labelRetry);
2748
2749     emitAttr dataSize = emitActualTypeSize(data);
2750     // The following instruction includes a acquire half barrier
2751     // TODO-ARM64-CQ Evaluate whether this is necessary
2752     // https://github.com/dotnet/coreclr/issues/14346
2753     getEmitter()->emitIns_R_R(INS_ldaxr, dataSize, loadReg, addrReg);
2754
2755     switch (treeNode->OperGet())
2756     {
2757         case GT_XADD:
2758         case GT_LOCKADD:
2759             if (data->isContainedIntOrIImmed())
2760             {
2761                 // Even though INS_add is specified here, the encoder will choose either
2762                 // an INS_add or an INS_sub and encode the immediate as a positive value
2763                 genInstrWithConstant(INS_add, dataSize, storeDataReg, loadReg, data->AsIntConCommon()->IconValue(),
2764                                      REG_NA);
2765             }
2766             else
2767             {
2768                 getEmitter()->emitIns_R_R_R(INS_add, dataSize, storeDataReg, loadReg, dataReg);
2769             }
2770             break;
2771         case GT_XCHG:
2772             assert(!data->isContained());
2773             storeDataReg = dataReg;
2774             break;
2775         default:
2776             unreached();
2777     }
2778
2779     // The following instruction includes a release half barrier
2780     // TODO-ARM64-CQ Evaluate whether this is necessary
2781     // https://github.com/dotnet/coreclr/issues/14346
2782     getEmitter()->emitIns_R_R_R(INS_stlxr, dataSize, exResultReg, storeDataReg, addrReg);
2783
2784     getEmitter()->emitIns_J_R(INS_cbnz, EA_4BYTE, labelRetry, exResultReg);
2785
2786     gcInfo.gcMarkRegSetNpt(addr->gtGetRegMask());
2787
2788     if (treeNode->gtRegNum != REG_NA)
2789     {
2790         genProduceReg(treeNode);
2791     }
2792 }
2793
2794 //------------------------------------------------------------------------
2795 // genCodeForSwap: Produce code for a GT_CMPXCHG node.
2796 //
2797 // Arguments:
2798 //    tree - the GT_CMPXCHG node
2799 //
2800 void CodeGen::genCodeForCmpXchg(GenTreeCmpXchg* treeNode)
2801 {
2802     assert(treeNode->OperIs(GT_CMPXCHG));
2803
2804     GenTree* addr      = treeNode->gtOpLocation;  // arg1
2805     GenTree* data      = treeNode->gtOpValue;     // arg2
2806     GenTree* comparand = treeNode->gtOpComparand; // arg3
2807
2808     regNumber targetReg    = treeNode->gtRegNum;
2809     regNumber dataReg      = data->gtRegNum;
2810     regNumber addrReg      = addr->gtRegNum;
2811     regNumber comparandReg = comparand->gtRegNum;
2812     regNumber exResultReg  = treeNode->ExtractTempReg(RBM_ALLINT);
2813
2814     // Check allocator assumptions
2815     //
2816     // The register allocator should have extended the lifetimes of all input and internal registers so that
2817     // none interfere with the target.
2818     noway_assert(addrReg != targetReg);
2819     noway_assert(dataReg != targetReg);
2820     noway_assert(comparandReg != targetReg);
2821     noway_assert(addrReg != dataReg);
2822     noway_assert(targetReg != REG_NA);
2823     noway_assert(exResultReg != REG_NA);
2824     noway_assert(exResultReg != targetReg);
2825
2826     assert(addr->isUsedFromReg());
2827     assert(data->isUsedFromReg());
2828     assert(!comparand->isUsedFromMemory());
2829
2830     // Store exclusive unpredictable cases must be avoided
2831     noway_assert(exResultReg != dataReg);
2832     noway_assert(exResultReg != addrReg);
2833
2834     genConsumeAddress(addr);
2835     genConsumeRegs(data);
2836     genConsumeRegs(comparand);
2837
2838     // NOTE: `genConsumeAddress` marks the consumed register as not a GC pointer, as it assumes that the input registers
2839     // die at the first instruction generated by the node. This is not the case for these atomics as the  input
2840     // registers are multiply-used. As such, we need to mark the addr register as containing a GC pointer until
2841     // we are finished generating the code for this node.
2842
2843     gcInfo.gcMarkRegPtrVal(addrReg, addr->TypeGet());
2844
2845     // TODO-ARM64-CQ Use ARMv8.1 atomics if available
2846     // https://github.com/dotnet/coreclr/issues/11881
2847
2848     // Emit code like this:
2849     //   retry:
2850     //     ldxr targetReg, [addrReg]
2851     //     cmp targetReg, comparandReg
2852     //     bne compareFail
2853     //     stxr exResult, dataReg, [addrReg]
2854     //     cbnz exResult, retry
2855     //   compareFail:
2856
2857     BasicBlock* labelRetry       = genCreateTempLabel();
2858     BasicBlock* labelCompareFail = genCreateTempLabel();
2859     genDefineTempLabel(labelRetry);
2860
2861     // The following instruction includes a acquire half barrier
2862     // TODO-ARM64-CQ Evaluate whether this is necessary
2863     // https://github.com/dotnet/coreclr/issues/14346
2864     getEmitter()->emitIns_R_R(INS_ldaxr, emitTypeSize(treeNode), targetReg, addrReg);
2865
2866     if (comparand->isContainedIntOrIImmed())
2867     {
2868         if (comparand->IsIntegralConst(0))
2869         {
2870             getEmitter()->emitIns_J_R(INS_cbnz, emitActualTypeSize(treeNode), labelCompareFail, targetReg);
2871         }
2872         else
2873         {
2874             getEmitter()->emitIns_R_I(INS_cmp, emitActualTypeSize(treeNode), targetReg,
2875                                       comparand->AsIntConCommon()->IconValue());
2876             getEmitter()->emitIns_J(INS_bne, labelCompareFail);
2877         }
2878     }
2879     else
2880     {
2881         getEmitter()->emitIns_R_R(INS_cmp, emitActualTypeSize(treeNode), targetReg, comparandReg);
2882         getEmitter()->emitIns_J(INS_bne, labelCompareFail);
2883     }
2884
2885     // The following instruction includes a release half barrier
2886     // TODO-ARM64-CQ Evaluate whether this is necessary
2887     // https://github.com/dotnet/coreclr/issues/14346
2888     getEmitter()->emitIns_R_R_R(INS_stlxr, emitTypeSize(treeNode), exResultReg, dataReg, addrReg);
2889
2890     getEmitter()->emitIns_J_R(INS_cbnz, EA_4BYTE, labelRetry, exResultReg);
2891
2892     genDefineTempLabel(labelCompareFail);
2893
2894     gcInfo.gcMarkRegSetNpt(addr->gtGetRegMask());
2895
2896     genProduceReg(treeNode);
2897 }
2898
2899 instruction CodeGen::genGetInsForOper(genTreeOps oper, var_types type)
2900 {
2901     instruction ins = INS_brk;
2902
2903     if (varTypeIsFloating(type))
2904     {
2905         switch (oper)
2906         {
2907             case GT_ADD:
2908                 ins = INS_fadd;
2909                 break;
2910             case GT_SUB:
2911                 ins = INS_fsub;
2912                 break;
2913             case GT_MUL:
2914                 ins = INS_fmul;
2915                 break;
2916             case GT_DIV:
2917                 ins = INS_fdiv;
2918                 break;
2919             case GT_NEG:
2920                 ins = INS_fneg;
2921                 break;
2922
2923             default:
2924                 NYI("Unhandled oper in genGetInsForOper() - float");
2925                 unreached();
2926                 break;
2927         }
2928     }
2929     else
2930     {
2931         switch (oper)
2932         {
2933             case GT_ADD:
2934                 ins = INS_add;
2935                 break;
2936             case GT_AND:
2937                 ins = INS_and;
2938                 break;
2939             case GT_DIV:
2940                 ins = INS_sdiv;
2941                 break;
2942             case GT_UDIV:
2943                 ins = INS_udiv;
2944                 break;
2945             case GT_MUL:
2946                 ins = INS_mul;
2947                 break;
2948             case GT_LSH:
2949                 ins = INS_lsl;
2950                 break;
2951             case GT_NEG:
2952                 ins = INS_neg;
2953                 break;
2954             case GT_NOT:
2955                 ins = INS_mvn;
2956                 break;
2957             case GT_OR:
2958                 ins = INS_orr;
2959                 break;
2960             case GT_ROR:
2961                 ins = INS_ror;
2962                 break;
2963             case GT_RSH:
2964                 ins = INS_asr;
2965                 break;
2966             case GT_RSZ:
2967                 ins = INS_lsr;
2968                 break;
2969             case GT_SUB:
2970                 ins = INS_sub;
2971                 break;
2972             case GT_XOR:
2973                 ins = INS_eor;
2974                 break;
2975
2976             default:
2977                 NYI("Unhandled oper in genGetInsForOper() - integer");
2978                 unreached();
2979                 break;
2980         }
2981     }
2982     return ins;
2983 }
2984
2985 //------------------------------------------------------------------------
2986 // genCodeForReturnTrap: Produce code for a GT_RETURNTRAP node.
2987 //
2988 // Arguments:
2989 //    tree - the GT_RETURNTRAP node
2990 //
2991 void CodeGen::genCodeForReturnTrap(GenTreeOp* tree)
2992 {
2993     assert(tree->OperGet() == GT_RETURNTRAP);
2994
2995     // this is nothing but a conditional call to CORINFO_HELP_STOP_FOR_GC
2996     // based on the contents of 'data'
2997
2998     GenTree* data = tree->gtOp1;
2999     genConsumeRegs(data);
3000     getEmitter()->emitIns_R_I(INS_cmp, EA_4BYTE, data->gtRegNum, 0);
3001
3002     BasicBlock* skipLabel = genCreateTempLabel();
3003
3004     emitJumpKind jmpEqual = genJumpKindForOper(GT_EQ, CK_SIGNED);
3005     inst_JMP(jmpEqual, skipLabel);
3006     // emit the call to the EE-helper that stops for GC (or other reasons)
3007
3008     genEmitHelperCall(CORINFO_HELP_STOP_FOR_GC, 0, EA_UNKNOWN);
3009     genDefineTempLabel(skipLabel);
3010 }
3011
3012 //------------------------------------------------------------------------
3013 // genCodeForStoreInd: Produce code for a GT_STOREIND node.
3014 //
3015 // Arguments:
3016 //    tree - the GT_STOREIND node
3017 //
3018 void CodeGen::genCodeForStoreInd(GenTreeStoreInd* tree)
3019 {
3020     GenTree*    data       = tree->Data();
3021     GenTree*    addr       = tree->Addr();
3022     var_types   targetType = tree->TypeGet();
3023     emitter*    emit       = getEmitter();
3024     emitAttr    attr       = emitTypeSize(tree);
3025     instruction ins        = ins_Store(targetType);
3026
3027 #ifdef FEATURE_SIMD
3028     // Storing Vector3 of size 12 bytes through indirection
3029     if (tree->TypeGet() == TYP_SIMD12)
3030     {
3031         genStoreIndTypeSIMD12(tree);
3032         return;
3033     }
3034 #endif // FEATURE_SIMD
3035
3036     GCInfo::WriteBarrierForm writeBarrierForm = gcInfo.gcIsWriteBarrierCandidate(tree, data);
3037     if (writeBarrierForm != GCInfo::WBF_NoBarrier)
3038     {
3039         // data and addr must be in registers.
3040         // Consume both registers so that any copies of interfering
3041         // registers are taken care of.
3042         genConsumeOperands(tree);
3043
3044 #if NOGC_WRITE_BARRIERS
3045         // At this point, we should not have any interference.
3046         // That is, 'data' must not be in REG_WRITE_BARRIER_DST_BYREF,
3047         //  as that is where 'addr' must go.
3048         noway_assert(data->gtRegNum != REG_WRITE_BARRIER_DST_BYREF);
3049
3050         // 'addr' goes into x14 (REG_WRITE_BARRIER_DST_BYREF)
3051         if (addr->gtRegNum != REG_WRITE_BARRIER_DST_BYREF)
3052         {
3053             inst_RV_RV(INS_mov, REG_WRITE_BARRIER_DST_BYREF, addr->gtRegNum, addr->TypeGet());
3054         }
3055
3056         // 'data'  goes into x15 (REG_WRITE_BARRIER)
3057         if (data->gtRegNum != REG_WRITE_BARRIER)
3058         {
3059             inst_RV_RV(INS_mov, REG_WRITE_BARRIER, data->gtRegNum, data->TypeGet());
3060         }
3061 #else
3062         // At this point, we should not have any interference.
3063         // That is, 'data' must not be in REG_ARG_0,
3064         //  as that is where 'addr' must go.
3065         noway_assert(data->gtRegNum != REG_ARG_0);
3066
3067         // addr goes in REG_ARG_0
3068         if (addr->gtRegNum != REG_ARG_0)
3069         {
3070             inst_RV_RV(INS_mov, REG_ARG_0, addr->gtRegNum, addr->TypeGet());
3071         }
3072
3073         // data goes in REG_ARG_1
3074         if (data->gtRegNum != REG_ARG_1)
3075         {
3076             inst_RV_RV(INS_mov, REG_ARG_1, data->gtRegNum, data->TypeGet());
3077         }
3078 #endif // NOGC_WRITE_BARRIERS
3079
3080         genGCWriteBarrier(tree, writeBarrierForm);
3081     }
3082     else // A normal store, not a WriteBarrier store
3083     {
3084         bool     dataIsUnary = false;
3085         GenTree* nonRMWsrc   = nullptr;
3086         // We must consume the operands in the proper execution order,
3087         // so that liveness is updated appropriately.
3088         genConsumeAddress(addr);
3089
3090         if (!data->isContained())
3091         {
3092             genConsumeRegs(data);
3093         }
3094
3095         regNumber dataReg = REG_NA;
3096         if (data->isContainedIntOrIImmed())
3097         {
3098             assert(data->IsIntegralConst(0));
3099             dataReg = REG_ZR;
3100         }
3101         else // data is not contained, so evaluate it into a register
3102         {
3103             assert(!data->isContained());
3104             dataReg = data->gtRegNum;
3105         }
3106
3107         assert((attr != EA_1BYTE) || !(tree->gtFlags & GTF_IND_UNALIGNED));
3108
3109         if (tree->gtFlags & GTF_IND_VOLATILE)
3110         {
3111             bool useStoreRelease =
3112                 genIsValidIntReg(dataReg) && !addr->isContained() && !(tree->gtFlags & GTF_IND_UNALIGNED);
3113
3114             if (useStoreRelease)
3115             {
3116                 switch (EA_SIZE(attr))
3117                 {
3118                     case EA_1BYTE:
3119                         assert(ins == INS_strb);
3120                         ins = INS_stlrb;
3121                         break;
3122                     case EA_2BYTE:
3123                         assert(ins == INS_strh);
3124                         ins = INS_stlrh;
3125                         break;
3126                     case EA_4BYTE:
3127                     case EA_8BYTE:
3128                         assert(ins == INS_str);
3129                         ins = INS_stlr;
3130                         break;
3131                     default:
3132                         assert(false); // We should not get here
3133                 }
3134             }
3135             else
3136             {
3137                 // issue a full memory barrier before a volatile StInd
3138                 instGen_MemoryBarrier();
3139             }
3140         }
3141
3142         emit->emitInsLoadStoreOp(ins, attr, dataReg, tree);
3143     }
3144 }
3145
3146 //------------------------------------------------------------------------
3147 // genCodeForSwap: Produce code for a GT_SWAP node.
3148 //
3149 // Arguments:
3150 //    tree - the GT_SWAP node
3151 //
3152 void CodeGen::genCodeForSwap(GenTreeOp* tree)
3153 {
3154     // Swap is only supported for lclVar operands that are enregistered
3155     // We do not consume or produce any registers.  Both operands remain enregistered.
3156     // However, the gc-ness may change.
3157     assert(genIsRegCandidateLocal(tree->gtOp1) && genIsRegCandidateLocal(tree->gtOp2));
3158
3159     GenTreeLclVarCommon* lcl1    = tree->gtOp1->AsLclVarCommon();
3160     LclVarDsc*           varDsc1 = &(compiler->lvaTable[lcl1->gtLclNum]);
3161     var_types            type1   = varDsc1->TypeGet();
3162     GenTreeLclVarCommon* lcl2    = tree->gtOp2->AsLclVarCommon();
3163     LclVarDsc*           varDsc2 = &(compiler->lvaTable[lcl2->gtLclNum]);
3164     var_types            type2   = varDsc2->TypeGet();
3165
3166     // We must have both int or both fp regs
3167     assert(!varTypeIsFloating(type1) || varTypeIsFloating(type2));
3168
3169     // FP swap is not yet implemented (and should have NYI'd in LSRA)
3170     assert(!varTypeIsFloating(type1));
3171
3172     regNumber oldOp1Reg     = lcl1->gtRegNum;
3173     regMaskTP oldOp1RegMask = genRegMask(oldOp1Reg);
3174     regNumber oldOp2Reg     = lcl2->gtRegNum;
3175     regMaskTP oldOp2RegMask = genRegMask(oldOp2Reg);
3176
3177     // We don't call genUpdateVarReg because we don't have a tree node with the new register.
3178     varDsc1->lvRegNum = oldOp2Reg;
3179     varDsc2->lvRegNum = oldOp1Reg;
3180
3181     // Do the xchg
3182     emitAttr size = EA_PTRSIZE;
3183     if (varTypeGCtype(type1) != varTypeGCtype(type2))
3184     {
3185         // If the type specified to the emitter is a GC type, it will swap the GC-ness of the registers.
3186         // Otherwise it will leave them alone, which is correct if they have the same GC-ness.
3187         size = EA_GCREF;
3188     }
3189
3190     NYI("register swap");
3191     // inst_RV_RV(INS_xchg, oldOp1Reg, oldOp2Reg, TYP_I_IMPL, size);
3192
3193     // Update the gcInfo.
3194     // Manually remove these regs for the gc sets (mostly to avoid confusing duplicative dump output)
3195     gcInfo.gcRegByrefSetCur &= ~(oldOp1RegMask | oldOp2RegMask);
3196     gcInfo.gcRegGCrefSetCur &= ~(oldOp1RegMask | oldOp2RegMask);
3197
3198     // gcMarkRegPtrVal will do the appropriate thing for non-gc types.
3199     // It will also dump the updates.
3200     gcInfo.gcMarkRegPtrVal(oldOp2Reg, type1);
3201     gcInfo.gcMarkRegPtrVal(oldOp1Reg, type2);
3202 }
3203
3204 //-------------------------------------------------------------------------------------------
3205 // genSetRegToCond:  Set a register 'dstReg' to the appropriate one or zero value
3206 //                   corresponding to a binary Relational operator result.
3207 //
3208 // Arguments:
3209 //   dstReg          - The target register to set to 1 or 0
3210 //   tree            - The GenTree Relop node that was used to set the Condition codes
3211 //
3212 // Return Value:     none
3213 //
3214 // Notes:
3215 //    A full 64-bit value of either 1 or 0 is setup in the 'dstReg'
3216 //-------------------------------------------------------------------------------------------
3217
3218 void CodeGen::genSetRegToCond(regNumber dstReg, GenTree* tree)
3219 {
3220     emitJumpKind jumpKind[2];
3221     bool         branchToTrueLabel[2];
3222     genJumpKindsForTree(tree, jumpKind, branchToTrueLabel);
3223     assert(jumpKind[0] != EJ_NONE);
3224
3225     // Set the reg according to the flags
3226     inst_SET(jumpKind[0], dstReg);
3227
3228     // Do we need to use two operation to set the flags?
3229     //
3230     if (jumpKind[1] != EJ_NONE)
3231     {
3232         emitter* emit    = getEmitter();
3233         bool     ordered = ((tree->gtFlags & GTF_RELOP_NAN_UN) == 0);
3234         insCond  secondCond;
3235
3236         // The only ones that require two operations are the
3237         // floating point compare operations of BEQ or BNE.UN
3238         //
3239         if (tree->gtOper == GT_EQ)
3240         {
3241             // This must be an ordered comparison.
3242             assert(ordered);
3243             assert(jumpKind[1] == EJ_vs); // We complement this value
3244             secondCond = INS_COND_VC;     // for the secondCond
3245         }
3246         else // gtOper == GT_NE
3247         {
3248             // This must be BNE.UN (unordered comparison)
3249             assert((tree->gtOper == GT_NE) && !ordered);
3250             assert(jumpKind[1] == EJ_lo); // We complement this value
3251             secondCond = INS_COND_HS;     // for the secondCond
3252         }
3253
3254         // The second instruction is a 'csinc' instruction that either selects the previous dstReg
3255         // or increments the ZR register, which produces a 1 result.
3256
3257         emit->emitIns_R_R_R_COND(INS_csinc, EA_8BYTE, dstReg, dstReg, REG_ZR, secondCond);
3258     }
3259 }
3260
3261 //------------------------------------------------------------------------
3262 // genIntToFloatCast: Generate code to cast an int/long to float/double
3263 //
3264 // Arguments:
3265 //    treeNode - The GT_CAST node
3266 //
3267 // Return Value:
3268 //    None.
3269 //
3270 // Assumptions:
3271 //    Cast is a non-overflow conversion.
3272 //    The treeNode must have an assigned register.
3273 //    SrcType= int32/uint32/int64/uint64 and DstType=float/double.
3274 //
3275 void CodeGen::genIntToFloatCast(GenTree* treeNode)
3276 {
3277     // int type --> float/double conversions are always non-overflow ones
3278     assert(treeNode->OperGet() == GT_CAST);
3279     assert(!treeNode->gtOverflow());
3280
3281     regNumber targetReg = treeNode->gtRegNum;
3282     assert(genIsValidFloatReg(targetReg));
3283
3284     GenTree* op1 = treeNode->gtOp.gtOp1;
3285     assert(!op1->isContained());             // Cannot be contained
3286     assert(genIsValidIntReg(op1->gtRegNum)); // Must be a valid int reg.
3287
3288     var_types dstType = treeNode->CastToType();
3289     var_types srcType = genActualType(op1->TypeGet());
3290     assert(!varTypeIsFloating(srcType) && varTypeIsFloating(dstType));
3291
3292     // force the srcType to unsigned if GT_UNSIGNED flag is set
3293     if (treeNode->gtFlags & GTF_UNSIGNED)
3294     {
3295         srcType = genUnsignedType(srcType);
3296     }
3297
3298     // We should never see a srcType whose size is neither EA_4BYTE or EA_8BYTE
3299     emitAttr srcSize = EA_ATTR(genTypeSize(srcType));
3300     noway_assert((srcSize == EA_4BYTE) || (srcSize == EA_8BYTE));
3301
3302     instruction ins       = varTypeIsUnsigned(srcType) ? INS_ucvtf : INS_scvtf;
3303     insOpts     cvtOption = INS_OPTS_NONE; // invalid value
3304
3305     if (dstType == TYP_DOUBLE)
3306     {
3307         if (srcSize == EA_4BYTE)
3308         {
3309             cvtOption = INS_OPTS_4BYTE_TO_D;
3310         }
3311         else
3312         {
3313             assert(srcSize == EA_8BYTE);
3314             cvtOption = INS_OPTS_8BYTE_TO_D;
3315         }
3316     }
3317     else
3318     {
3319         assert(dstType == TYP_FLOAT);
3320         if (srcSize == EA_4BYTE)
3321         {
3322             cvtOption = INS_OPTS_4BYTE_TO_S;
3323         }
3324         else
3325         {
3326             assert(srcSize == EA_8BYTE);
3327             cvtOption = INS_OPTS_8BYTE_TO_S;
3328         }
3329     }
3330
3331     genConsumeOperands(treeNode->AsOp());
3332
3333     getEmitter()->emitIns_R_R(ins, emitActualTypeSize(dstType), treeNode->gtRegNum, op1->gtRegNum, cvtOption);
3334
3335     genProduceReg(treeNode);
3336 }
3337
3338 //------------------------------------------------------------------------
3339 // genFloatToIntCast: Generate code to cast float/double to int/long
3340 //
3341 // Arguments:
3342 //    treeNode - The GT_CAST node
3343 //
3344 // Return Value:
3345 //    None.
3346 //
3347 // Assumptions:
3348 //    Cast is a non-overflow conversion.
3349 //    The treeNode must have an assigned register.
3350 //    SrcType=float/double and DstType= int32/uint32/int64/uint64
3351 //
3352 void CodeGen::genFloatToIntCast(GenTree* treeNode)
3353 {
3354     // we don't expect to see overflow detecting float/double --> int type conversions here
3355     // as they should have been converted into helper calls by front-end.
3356     assert(treeNode->OperGet() == GT_CAST);
3357     assert(!treeNode->gtOverflow());
3358
3359     regNumber targetReg = treeNode->gtRegNum;
3360     assert(genIsValidIntReg(targetReg)); // Must be a valid int reg.
3361
3362     GenTree* op1 = treeNode->gtOp.gtOp1;
3363     assert(!op1->isContained());               // Cannot be contained
3364     assert(genIsValidFloatReg(op1->gtRegNum)); // Must be a valid float reg.
3365
3366     var_types dstType = treeNode->CastToType();
3367     var_types srcType = op1->TypeGet();
3368     assert(varTypeIsFloating(srcType) && !varTypeIsFloating(dstType));
3369
3370     // We should never see a dstType whose size is neither EA_4BYTE or EA_8BYTE
3371     // For conversions to small types (byte/sbyte/int16/uint16) from float/double,
3372     // we expect the front-end or lowering phase to have generated two levels of cast.
3373     //
3374     emitAttr dstSize = EA_ATTR(genTypeSize(dstType));
3375     noway_assert((dstSize == EA_4BYTE) || (dstSize == EA_8BYTE));
3376
3377     instruction ins       = INS_fcvtzs;    // default to sign converts
3378     insOpts     cvtOption = INS_OPTS_NONE; // invalid value
3379
3380     if (varTypeIsUnsigned(dstType))
3381     {
3382         ins = INS_fcvtzu; // use unsigned converts
3383     }
3384
3385     if (srcType == TYP_DOUBLE)
3386     {
3387         if (dstSize == EA_4BYTE)
3388         {
3389             cvtOption = INS_OPTS_D_TO_4BYTE;
3390         }
3391         else
3392         {
3393             assert(dstSize == EA_8BYTE);
3394             cvtOption = INS_OPTS_D_TO_8BYTE;
3395         }
3396     }
3397     else
3398     {
3399         assert(srcType == TYP_FLOAT);
3400         if (dstSize == EA_4BYTE)
3401         {
3402             cvtOption = INS_OPTS_S_TO_4BYTE;
3403         }
3404         else
3405         {
3406             assert(dstSize == EA_8BYTE);
3407             cvtOption = INS_OPTS_S_TO_8BYTE;
3408         }
3409     }
3410
3411     genConsumeOperands(treeNode->AsOp());
3412
3413     getEmitter()->emitIns_R_R(ins, dstSize, treeNode->gtRegNum, op1->gtRegNum, cvtOption);
3414
3415     genProduceReg(treeNode);
3416 }
3417
3418 //------------------------------------------------------------------------
3419 // genCkfinite: Generate code for ckfinite opcode.
3420 //
3421 // Arguments:
3422 //    treeNode - The GT_CKFINITE node
3423 //
3424 // Return Value:
3425 //    None.
3426 //
3427 // Assumptions:
3428 //    GT_CKFINITE node has reserved an internal register.
3429 //
3430 void CodeGen::genCkfinite(GenTree* treeNode)
3431 {
3432     assert(treeNode->OperGet() == GT_CKFINITE);
3433
3434     GenTree*  op1         = treeNode->gtOp.gtOp1;
3435     var_types targetType  = treeNode->TypeGet();
3436     int       expMask     = (targetType == TYP_FLOAT) ? 0x7F8 : 0x7FF; // Bit mask to extract exponent.
3437     int       shiftAmount = targetType == TYP_FLOAT ? 20 : 52;
3438
3439     emitter* emit = getEmitter();
3440
3441     // Extract exponent into a register.
3442     regNumber intReg = treeNode->GetSingleTempReg();
3443     regNumber fpReg  = genConsumeReg(op1);
3444
3445     emit->emitIns_R_R(ins_Copy(targetType), emitActualTypeSize(treeNode), intReg, fpReg);
3446     emit->emitIns_R_R_I(INS_lsr, emitActualTypeSize(targetType), intReg, intReg, shiftAmount);
3447
3448     // Mask of exponent with all 1's and check if the exponent is all 1's
3449     emit->emitIns_R_R_I(INS_and, EA_4BYTE, intReg, intReg, expMask);
3450     emit->emitIns_R_I(INS_cmp, EA_4BYTE, intReg, expMask);
3451
3452     // If exponent is all 1's, throw ArithmeticException
3453     emitJumpKind jmpEqual = genJumpKindForOper(GT_EQ, CK_SIGNED);
3454     genJumpToThrowHlpBlk(jmpEqual, SCK_ARITH_EXCPN);
3455
3456     // if it is a finite value copy it to targetReg
3457     if (treeNode->gtRegNum != fpReg)
3458     {
3459         emit->emitIns_R_R(ins_Copy(targetType), emitActualTypeSize(treeNode), treeNode->gtRegNum, fpReg);
3460     }
3461     genProduceReg(treeNode);
3462 }
3463
3464 //------------------------------------------------------------------------
3465 // genCodeForCompare: Produce code for a GT_EQ/GT_NE/GT_LT/GT_LE/GT_GE/GT_GT/GT_TEST_EQ/GT_TEST_NE node.
3466 //
3467 // Arguments:
3468 //    tree - the node
3469 //
3470 void CodeGen::genCodeForCompare(GenTreeOp* tree)
3471 {
3472     regNumber targetReg = tree->gtRegNum;
3473     emitter*  emit      = getEmitter();
3474
3475     GenTree*  op1     = tree->gtOp1;
3476     GenTree*  op2     = tree->gtOp2;
3477     var_types op1Type = genActualType(op1->TypeGet());
3478     var_types op2Type = genActualType(op2->TypeGet());
3479
3480     assert(!op1->isUsedFromMemory());
3481     assert(!op2->isUsedFromMemory());
3482
3483     genConsumeOperands(tree);
3484
3485     emitAttr cmpSize = EA_ATTR(genTypeSize(op1Type));
3486
3487     assert(genTypeSize(op1Type) == genTypeSize(op2Type));
3488
3489     if (varTypeIsFloating(op1Type))
3490     {
3491         assert(varTypeIsFloating(op2Type));
3492         assert(!op1->isContained());
3493         assert(op1Type == op2Type);
3494
3495         if (op2->IsIntegralConst(0))
3496         {
3497             assert(op2->isContained());
3498             emit->emitIns_R_F(INS_fcmp, cmpSize, op1->gtRegNum, 0.0);
3499         }
3500         else
3501         {
3502             assert(!op2->isContained());
3503             emit->emitIns_R_R(INS_fcmp, cmpSize, op1->gtRegNum, op2->gtRegNum);
3504         }
3505     }
3506     else
3507     {
3508         assert(!varTypeIsFloating(op2Type));
3509         // We don't support swapping op1 and op2 to generate cmp reg, imm
3510         assert(!op1->isContainedIntOrIImmed());
3511
3512         instruction ins = tree->OperIs(GT_TEST_EQ, GT_TEST_NE) ? INS_tst : INS_cmp;
3513
3514         if (op2->isContainedIntOrIImmed())
3515         {
3516             GenTreeIntConCommon* intConst = op2->AsIntConCommon();
3517             emit->emitIns_R_I(ins, cmpSize, op1->gtRegNum, intConst->IconValue());
3518         }
3519         else
3520         {
3521             emit->emitIns_R_R(ins, cmpSize, op1->gtRegNum, op2->gtRegNum);
3522         }
3523     }
3524
3525     // Are we evaluating this into a register?
3526     if (targetReg != REG_NA)
3527     {
3528         genSetRegToCond(targetReg, tree);
3529         genProduceReg(tree);
3530     }
3531 }
3532
3533 //------------------------------------------------------------------------
3534 // genCodeForJumpCompare: Generates code for jmpCompare statement.
3535 //
3536 // A GT_JCMP node is created when a comparison and conditional branch
3537 // can be executed in a single instruction.
3538 //
3539 // Arm64 has a few instructions with this behavior.
3540 //   - cbz/cbnz -- Compare and branch register zero/not zero
3541 //   - tbz/tbnz -- Test and branch register bit zero/not zero
3542 //
3543 // The cbz/cbnz supports the normal +/- 1MB branch range for conditional branches
3544 // The tbz/tbnz supports a  smaller +/- 32KB branch range
3545 //
3546 // A GT_JCMP cbz/cbnz node is created when there is a GT_EQ or GT_NE
3547 // integer/unsigned comparison against #0 which is used by a GT_JTRUE
3548 // condition jump node.
3549 //
3550 // A GT_JCMP tbz/tbnz node is created when there is a GT_TEST_EQ or GT_TEST_NE
3551 // integer/unsigned comparison against against a mask with a single bit set
3552 // which is used by a GT_JTRUE condition jump node.
3553 //
3554 // This node is repsonsible for consuming the register, and emitting the
3555 // appropriate fused compare/test and branch instruction
3556 //
3557 // Two flags guide code generation
3558 //    GTF_JCMP_TST -- Set if this is a tbz/tbnz rather than cbz/cbnz
3559 //    GTF_JCMP_EQ  -- Set if this is cbz/tbz rather than cbnz/tbnz
3560 //
3561 // Arguments:
3562 //    tree - The GT_JCMP tree node.
3563 //
3564 // Return Value:
3565 //    None
3566 //
3567 void CodeGen::genCodeForJumpCompare(GenTreeOp* tree)
3568 {
3569     assert(compiler->compCurBB->bbJumpKind == BBJ_COND);
3570
3571     GenTree* op1 = tree->gtGetOp1();
3572     GenTree* op2 = tree->gtGetOp2();
3573
3574     assert(tree->OperIs(GT_JCMP));
3575     assert(!varTypeIsFloating(tree));
3576     assert(!op1->isUsedFromMemory());
3577     assert(!op2->isUsedFromMemory());
3578     assert(op2->IsCnsIntOrI());
3579     assert(op2->isContained());
3580
3581     genConsumeOperands(tree);
3582
3583     regNumber reg  = op1->gtRegNum;
3584     emitAttr  attr = emitActualTypeSize(op1->TypeGet());
3585
3586     if (tree->gtFlags & GTF_JCMP_TST)
3587     {
3588         ssize_t compareImm = op2->gtIntCon.IconValue();
3589
3590         assert(isPow2(compareImm));
3591
3592         instruction ins = (tree->gtFlags & GTF_JCMP_EQ) ? INS_tbz : INS_tbnz;
3593         int         imm = genLog2((size_t)compareImm);
3594
3595         getEmitter()->emitIns_J_R_I(ins, attr, compiler->compCurBB->bbJumpDest, reg, imm);
3596     }
3597     else
3598     {
3599         assert(op2->IsIntegralConst(0));
3600
3601         instruction ins = (tree->gtFlags & GTF_JCMP_EQ) ? INS_cbz : INS_cbnz;
3602
3603         getEmitter()->emitIns_J_R(ins, attr, compiler->compCurBB->bbJumpDest, reg);
3604     }
3605 }
3606
3607 int CodeGenInterface::genSPtoFPdelta()
3608 {
3609     int delta;
3610
3611     // We place the saved frame pointer immediately above the outgoing argument space.
3612     delta = (int)compiler->lvaOutgoingArgSpaceSize;
3613
3614     assert(delta >= 0);
3615     return delta;
3616 }
3617
3618 //---------------------------------------------------------------------
3619 // genTotalFrameSize - return the total size of the stack frame, including local size,
3620 // callee-saved register size, etc.
3621 //
3622 // Return value:
3623 //    Total frame size
3624 //
3625
3626 int CodeGenInterface::genTotalFrameSize()
3627 {
3628     // For varargs functions, we home all the incoming register arguments. They are not
3629     // included in the compCalleeRegsPushed count. This is like prespill on ARM32, but
3630     // since we don't use "push" instructions to save them, we don't have to do the
3631     // save of these varargs register arguments as the first thing in the prolog.
3632
3633     assert(!IsUninitialized(compiler->compCalleeRegsPushed));
3634
3635     int totalFrameSize = (compiler->info.compIsVarArgs ? MAX_REG_ARG * REGSIZE_BYTES : 0) +
3636                          compiler->compCalleeRegsPushed * REGSIZE_BYTES + compiler->compLclFrameSize;
3637
3638     assert(totalFrameSize >= 0);
3639     return totalFrameSize;
3640 }
3641
3642 //---------------------------------------------------------------------
3643 // genCallerSPtoFPdelta - return the offset from Caller-SP to the frame pointer.
3644 // This number is going to be negative, since the Caller-SP is at a higher
3645 // address than the frame pointer.
3646 //
3647 // There must be a frame pointer to call this function!
3648
3649 int CodeGenInterface::genCallerSPtoFPdelta()
3650 {
3651     assert(isFramePointerUsed());
3652     int callerSPtoFPdelta;
3653
3654     callerSPtoFPdelta = genCallerSPtoInitialSPdelta() + genSPtoFPdelta();
3655
3656     assert(callerSPtoFPdelta <= 0);
3657     return callerSPtoFPdelta;
3658 }
3659
3660 //---------------------------------------------------------------------
3661 // genCallerSPtoInitialSPdelta - return the offset from Caller-SP to Initial SP.
3662 //
3663 // This number will be negative.
3664
3665 int CodeGenInterface::genCallerSPtoInitialSPdelta()
3666 {
3667     int callerSPtoSPdelta = 0;
3668
3669     callerSPtoSPdelta -= genTotalFrameSize();
3670
3671     assert(callerSPtoSPdelta <= 0);
3672     return callerSPtoSPdelta;
3673 }
3674
3675 /*****************************************************************************
3676  *  Emit a call to a helper function.
3677  *
3678  */
3679
3680 void CodeGen::genEmitHelperCall(unsigned helper, int argSize, emitAttr retSize, regNumber callTargetReg /*= REG_NA */)
3681 {
3682     void* addr  = nullptr;
3683     void* pAddr = nullptr;
3684
3685     emitter::EmitCallType callType = emitter::EC_FUNC_TOKEN;
3686     addr                           = compiler->compGetHelperFtn((CorInfoHelpFunc)helper, &pAddr);
3687     regNumber callTarget           = REG_NA;
3688
3689     if (addr == nullptr)
3690     {
3691         // This is call to a runtime helper.
3692         // adrp x, [reloc:rel page addr]
3693         // add x, x, [reloc:page offset]
3694         // ldr x, [x]
3695         // br x
3696
3697         if (callTargetReg == REG_NA)
3698         {
3699             // If a callTargetReg has not been explicitly provided, we will use REG_DEFAULT_HELPER_CALL_TARGET, but
3700             // this is only a valid assumption if the helper call is known to kill REG_DEFAULT_HELPER_CALL_TARGET.
3701             callTargetReg = REG_DEFAULT_HELPER_CALL_TARGET;
3702         }
3703
3704         regMaskTP callTargetMask = genRegMask(callTargetReg);
3705         regMaskTP callKillSet    = compiler->compHelperCallKillSet((CorInfoHelpFunc)helper);
3706
3707         // assert that all registers in callTargetMask are in the callKillSet
3708         noway_assert((callTargetMask & callKillSet) == callTargetMask);
3709
3710         callTarget = callTargetReg;
3711
3712         // adrp + add with relocations will be emitted
3713         getEmitter()->emitIns_R_AI(INS_adrp, EA_PTR_DSP_RELOC, callTarget, (ssize_t)pAddr);
3714         getEmitter()->emitIns_R_R(INS_ldr, EA_PTRSIZE, callTarget, callTarget);
3715         callType = emitter::EC_INDIR_R;
3716     }
3717
3718     getEmitter()->emitIns_Call(callType, compiler->eeFindHelper(helper), INDEBUG_LDISASM_COMMA(nullptr) addr, argSize,
3719                                retSize, EA_UNKNOWN, gcInfo.gcVarPtrSetCur, gcInfo.gcRegGCrefSetCur,
3720                                gcInfo.gcRegByrefSetCur, BAD_IL_OFFSET, /* IL offset */
3721                                callTarget,                             /* ireg */
3722                                REG_NA, 0, 0,                           /* xreg, xmul, disp */
3723                                false,                                  /* isJump */
3724                                emitter::emitNoGChelper(helper));
3725
3726     regMaskTP killMask = compiler->compHelperCallKillSet((CorInfoHelpFunc)helper);
3727     regTracker.rsTrashRegSet(killMask);
3728 }
3729
3730 #ifdef FEATURE_SIMD
3731
3732 //------------------------------------------------------------------------
3733 // genSIMDIntrinsic: Generate code for a SIMD Intrinsic.  This is the main
3734 // routine which in turn calls apropriate genSIMDIntrinsicXXX() routine.
3735 //
3736 // Arguments:
3737 //    simdNode - The GT_SIMD node
3738 //
3739 // Return Value:
3740 //    None.
3741 //
3742 // Notes:
3743 //    Currently, we only recognize SIMDVector<float> and SIMDVector<int>, and
3744 //    a limited set of methods.
3745 //
3746 // TODO-CLEANUP Merge all versions of this function and move to new file simdcodegencommon.cpp.
3747 void CodeGen::genSIMDIntrinsic(GenTreeSIMD* simdNode)
3748 {
3749     // NYI for unsupported base types
3750     if (simdNode->gtSIMDBaseType != TYP_INT && simdNode->gtSIMDBaseType != TYP_LONG &&
3751         simdNode->gtSIMDBaseType != TYP_FLOAT && simdNode->gtSIMDBaseType != TYP_DOUBLE &&
3752         simdNode->gtSIMDBaseType != TYP_USHORT && simdNode->gtSIMDBaseType != TYP_UBYTE &&
3753         simdNode->gtSIMDBaseType != TYP_SHORT && simdNode->gtSIMDBaseType != TYP_BYTE &&
3754         simdNode->gtSIMDBaseType != TYP_UINT && simdNode->gtSIMDBaseType != TYP_ULONG)
3755     {
3756         noway_assert(!"SIMD intrinsic with unsupported base type.");
3757     }
3758
3759     switch (simdNode->gtSIMDIntrinsicID)
3760     {
3761         case SIMDIntrinsicInit:
3762             genSIMDIntrinsicInit(simdNode);
3763             break;
3764
3765         case SIMDIntrinsicInitN:
3766             genSIMDIntrinsicInitN(simdNode);
3767             break;
3768
3769         case SIMDIntrinsicSqrt:
3770         case SIMDIntrinsicAbs:
3771         case SIMDIntrinsicCast:
3772         case SIMDIntrinsicConvertToSingle:
3773         case SIMDIntrinsicConvertToInt32:
3774         case SIMDIntrinsicConvertToDouble:
3775         case SIMDIntrinsicConvertToInt64:
3776             genSIMDIntrinsicUnOp(simdNode);
3777             break;
3778
3779         case SIMDIntrinsicWidenLo:
3780         case SIMDIntrinsicWidenHi:
3781             genSIMDIntrinsicWiden(simdNode);
3782             break;
3783
3784         case SIMDIntrinsicNarrow:
3785             genSIMDIntrinsicNarrow(simdNode);
3786             break;
3787
3788         case SIMDIntrinsicAdd:
3789         case SIMDIntrinsicSub:
3790         case SIMDIntrinsicMul:
3791         case SIMDIntrinsicDiv:
3792         case SIMDIntrinsicBitwiseAnd:
3793         case SIMDIntrinsicBitwiseAndNot:
3794         case SIMDIntrinsicBitwiseOr:
3795         case SIMDIntrinsicBitwiseXor:
3796         case SIMDIntrinsicMin:
3797         case SIMDIntrinsicMax:
3798         case SIMDIntrinsicEqual:
3799         case SIMDIntrinsicLessThan:
3800         case SIMDIntrinsicGreaterThan:
3801         case SIMDIntrinsicLessThanOrEqual:
3802         case SIMDIntrinsicGreaterThanOrEqual:
3803             genSIMDIntrinsicBinOp(simdNode);
3804             break;
3805
3806         case SIMDIntrinsicOpEquality:
3807         case SIMDIntrinsicOpInEquality:
3808             genSIMDIntrinsicRelOp(simdNode);
3809             break;
3810
3811         case SIMDIntrinsicDotProduct:
3812             genSIMDIntrinsicDotProduct(simdNode);
3813             break;
3814
3815         case SIMDIntrinsicGetItem:
3816             genSIMDIntrinsicGetItem(simdNode);
3817             break;
3818
3819         case SIMDIntrinsicSetX:
3820         case SIMDIntrinsicSetY:
3821         case SIMDIntrinsicSetZ:
3822         case SIMDIntrinsicSetW:
3823             genSIMDIntrinsicSetItem(simdNode);
3824             break;
3825
3826         case SIMDIntrinsicUpperSave:
3827             genSIMDIntrinsicUpperSave(simdNode);
3828             break;
3829
3830         case SIMDIntrinsicUpperRestore:
3831             genSIMDIntrinsicUpperRestore(simdNode);
3832             break;
3833
3834         case SIMDIntrinsicSelect:
3835             NYI("SIMDIntrinsicSelect lowered during import to (a & sel) | (b & ~sel)");
3836             break;
3837
3838         default:
3839             noway_assert(!"Unimplemented SIMD intrinsic.");
3840             unreached();
3841     }
3842 }
3843
3844 insOpts CodeGen::genGetSimdInsOpt(bool is16Byte, var_types elementType)
3845 {
3846     insOpts result = INS_OPTS_NONE;
3847
3848     switch (elementType)
3849     {
3850         case TYP_DOUBLE:
3851         case TYP_ULONG:
3852         case TYP_LONG:
3853             result = is16Byte ? INS_OPTS_2D : INS_OPTS_1D;
3854             break;
3855         case TYP_FLOAT:
3856         case TYP_UINT:
3857         case TYP_INT:
3858             result = is16Byte ? INS_OPTS_4S : INS_OPTS_2S;
3859             break;
3860         case TYP_USHORT:
3861         case TYP_SHORT:
3862             result = is16Byte ? INS_OPTS_8H : INS_OPTS_4H;
3863             break;
3864         case TYP_UBYTE:
3865         case TYP_BYTE:
3866             result = is16Byte ? INS_OPTS_16B : INS_OPTS_8B;
3867             break;
3868         default:
3869             assert(!"Unsupported element type");
3870             unreached();
3871     }
3872
3873     return result;
3874 }
3875
3876 // getOpForSIMDIntrinsic: return the opcode for the given SIMD Intrinsic
3877 //
3878 // Arguments:
3879 //   intrinsicId    -   SIMD intrinsic Id
3880 //   baseType       -   Base type of the SIMD vector
3881 //   immed          -   Out param. Any immediate byte operand that needs to be passed to SSE2 opcode
3882 //
3883 //
3884 // Return Value:
3885 //   Instruction (op) to be used, and immed is set if instruction requires an immediate operand.
3886 //
3887 instruction CodeGen::getOpForSIMDIntrinsic(SIMDIntrinsicID intrinsicId, var_types baseType, unsigned* ival /*=nullptr*/)
3888 {
3889     instruction result = INS_invalid;
3890     if (varTypeIsFloating(baseType))
3891     {
3892         switch (intrinsicId)
3893         {
3894             case SIMDIntrinsicAbs:
3895                 result = INS_fabs;
3896                 break;
3897             case SIMDIntrinsicAdd:
3898                 result = INS_fadd;
3899                 break;
3900             case SIMDIntrinsicBitwiseAnd:
3901                 result = INS_and;
3902                 break;
3903             case SIMDIntrinsicBitwiseAndNot:
3904                 result = INS_bic;
3905                 break;
3906             case SIMDIntrinsicBitwiseOr:
3907                 result = INS_orr;
3908                 break;
3909             case SIMDIntrinsicBitwiseXor:
3910                 result = INS_eor;
3911                 break;
3912             case SIMDIntrinsicCast:
3913                 result = INS_mov;
3914                 break;
3915             case SIMDIntrinsicConvertToInt32:
3916             case SIMDIntrinsicConvertToInt64:
3917                 result = INS_fcvtns;
3918                 break;
3919             case SIMDIntrinsicDiv:
3920                 result = INS_fdiv;
3921                 break;
3922             case SIMDIntrinsicEqual:
3923                 result = INS_fcmeq;
3924                 break;
3925             case SIMDIntrinsicGreaterThan:
3926                 result = INS_fcmgt;
3927                 break;
3928             case SIMDIntrinsicGreaterThanOrEqual:
3929                 result = INS_fcmge;
3930                 break;
3931             case SIMDIntrinsicLessThan:
3932                 result = INS_fcmlt;
3933                 break;
3934             case SIMDIntrinsicLessThanOrEqual:
3935                 result = INS_fcmle;
3936                 break;
3937             case SIMDIntrinsicMax:
3938                 result = INS_fmax;
3939                 break;
3940             case SIMDIntrinsicMin:
3941                 result = INS_fmin;
3942                 break;
3943             case SIMDIntrinsicMul:
3944                 result = INS_fmul;
3945                 break;
3946             case SIMDIntrinsicNarrow:
3947                 // Use INS_fcvtn lower bytes of result followed by INS_fcvtn2 for upper bytes
3948                 // Return lower bytes instruction here
3949                 result = INS_fcvtn;
3950                 break;
3951             case SIMDIntrinsicSelect:
3952                 result = INS_bsl;
3953                 break;
3954             case SIMDIntrinsicSqrt:
3955                 result = INS_fsqrt;
3956                 break;
3957             case SIMDIntrinsicSub:
3958                 result = INS_fsub;
3959                 break;
3960             case SIMDIntrinsicWidenLo:
3961                 result = INS_fcvtl;
3962                 break;
3963             case SIMDIntrinsicWidenHi:
3964                 result = INS_fcvtl2;
3965                 break;
3966             default:
3967                 assert(!"Unsupported SIMD intrinsic");
3968                 unreached();
3969         }
3970     }
3971     else
3972     {
3973         bool isUnsigned = varTypeIsUnsigned(baseType);
3974
3975         switch (intrinsicId)
3976         {
3977             case SIMDIntrinsicAbs:
3978                 assert(!isUnsigned);
3979                 result = INS_abs;
3980                 break;
3981             case SIMDIntrinsicAdd:
3982                 result = INS_add;
3983                 break;
3984             case SIMDIntrinsicBitwiseAnd:
3985                 result = INS_and;
3986                 break;
3987             case SIMDIntrinsicBitwiseAndNot:
3988                 result = INS_bic;
3989                 break;
3990             case SIMDIntrinsicBitwiseOr:
3991                 result = INS_orr;
3992                 break;
3993             case SIMDIntrinsicBitwiseXor:
3994                 result = INS_eor;
3995                 break;
3996             case SIMDIntrinsicCast:
3997                 result = INS_mov;
3998                 break;
3999             case SIMDIntrinsicConvertToDouble:
4000             case SIMDIntrinsicConvertToSingle:
4001                 result = isUnsigned ? INS_ucvtf : INS_scvtf;
4002                 break;
4003             case SIMDIntrinsicEqual:
4004                 result = INS_cmeq;
4005                 break;
4006             case SIMDIntrinsicGreaterThan:
4007                 result = isUnsigned ? INS_cmhi : INS_cmgt;
4008                 break;
4009             case SIMDIntrinsicGreaterThanOrEqual:
4010                 result = isUnsigned ? INS_cmhs : INS_cmge;
4011                 break;
4012             case SIMDIntrinsicLessThan:
4013                 assert(!isUnsigned);
4014                 result = INS_cmlt;
4015                 break;
4016             case SIMDIntrinsicLessThanOrEqual:
4017                 assert(!isUnsigned);
4018                 result = INS_cmle;
4019                 break;
4020             case SIMDIntrinsicMax:
4021                 result = isUnsigned ? INS_umax : INS_smax;
4022                 break;
4023             case SIMDIntrinsicMin:
4024                 result = isUnsigned ? INS_umin : INS_smin;
4025                 break;
4026             case SIMDIntrinsicMul:
4027                 result = INS_mul;
4028                 break;
4029             case SIMDIntrinsicNarrow:
4030                 // Use INS_xtn lower bytes of result followed by INS_xtn2 for upper bytes
4031                 // Return lower bytes instruction here
4032                 result = INS_xtn;
4033                 break;
4034             case SIMDIntrinsicSelect:
4035                 result = INS_bsl;
4036                 break;
4037             case SIMDIntrinsicSub:
4038                 result = INS_sub;
4039                 break;
4040             case SIMDIntrinsicWidenLo:
4041                 result = isUnsigned ? INS_uxtl : INS_sxtl;
4042                 break;
4043             case SIMDIntrinsicWidenHi:
4044                 result = isUnsigned ? INS_uxtl2 : INS_sxtl2;
4045                 break;
4046             default:
4047                 assert(!"Unsupported SIMD intrinsic");
4048                 unreached();
4049         }
4050     }
4051
4052     noway_assert(result != INS_invalid);
4053     return result;
4054 }
4055
4056 //------------------------------------------------------------------------
4057 // genSIMDIntrinsicInit: Generate code for SIMD Intrinsic Initialize.
4058 //
4059 // Arguments:
4060 //    simdNode - The GT_SIMD node
4061 //
4062 // Return Value:
4063 //    None.
4064 //
4065 void CodeGen::genSIMDIntrinsicInit(GenTreeSIMD* simdNode)
4066 {
4067     assert(simdNode->gtSIMDIntrinsicID == SIMDIntrinsicInit);
4068
4069     GenTree*  op1       = simdNode->gtGetOp1();
4070     var_types baseType  = simdNode->gtSIMDBaseType;
4071     regNumber targetReg = simdNode->gtRegNum;
4072     assert(targetReg != REG_NA);
4073     var_types targetType = simdNode->TypeGet();
4074
4075     genConsumeOperands(simdNode);
4076     regNumber op1Reg = op1->IsIntegralConst(0) ? REG_ZR : op1->gtRegNum;
4077
4078     // TODO-ARM64-CQ Add LD1R to allow SIMDIntrinsicInit from contained memory
4079     // TODO-ARM64-CQ Add MOVI to allow SIMDIntrinsicInit from contained immediate small constants
4080
4081     assert(op1->isContained() == op1->IsIntegralConst(0));
4082     assert(!op1->isUsedFromMemory());
4083
4084     assert(genIsValidFloatReg(targetReg));
4085     assert(genIsValidIntReg(op1Reg) || genIsValidFloatReg(op1Reg));
4086
4087     bool     is16Byte = (simdNode->gtSIMDSize > 8);
4088     emitAttr attr     = is16Byte ? EA_16BYTE : EA_8BYTE;
4089     insOpts  opt      = genGetSimdInsOpt(is16Byte, baseType);
4090
4091     if (genIsValidIntReg(op1Reg))
4092     {
4093         getEmitter()->emitIns_R_R(INS_dup, attr, targetReg, op1Reg, opt);
4094     }
4095     else
4096     {
4097         getEmitter()->emitIns_R_R_I(INS_dup, attr, targetReg, op1Reg, 0, opt);
4098     }
4099
4100     genProduceReg(simdNode);
4101 }
4102
4103 //-------------------------------------------------------------------------------------------
4104 // genSIMDIntrinsicInitN: Generate code for SIMD Intrinsic Initialize for the form that takes
4105 //                        a number of arguments equal to the length of the Vector.
4106 //
4107 // Arguments:
4108 //    simdNode - The GT_SIMD node
4109 //
4110 // Return Value:
4111 //    None.
4112 //
4113 void CodeGen::genSIMDIntrinsicInitN(GenTreeSIMD* simdNode)
4114 {
4115     assert(simdNode->gtSIMDIntrinsicID == SIMDIntrinsicInitN);
4116
4117     regNumber targetReg = simdNode->gtRegNum;
4118     assert(targetReg != REG_NA);
4119
4120     var_types targetType = simdNode->TypeGet();
4121
4122     var_types baseType = simdNode->gtSIMDBaseType;
4123
4124     regNumber vectorReg = targetReg;
4125
4126     if (varTypeIsFloating(baseType))
4127     {
4128         // Note that we cannot use targetReg before consuming all float source operands.
4129         // Therefore use an internal temp register
4130         vectorReg = simdNode->GetSingleTempReg(RBM_ALLFLOAT);
4131     }
4132
4133     emitAttr baseTypeSize = emitTypeSize(baseType);
4134
4135     // We will first consume the list items in execution (left to right) order,
4136     // and record the registers.
4137     regNumber operandRegs[FP_REGSIZE_BYTES];
4138     unsigned  initCount = 0;
4139     for (GenTree* list = simdNode->gtGetOp1(); list != nullptr; list = list->gtGetOp2())
4140     {
4141         assert(list->OperGet() == GT_LIST);
4142         GenTree* listItem = list->gtGetOp1();
4143         assert(listItem->TypeGet() == baseType);
4144         assert(!listItem->isContained());
4145         regNumber operandReg   = genConsumeReg(listItem);
4146         operandRegs[initCount] = operandReg;
4147         initCount++;
4148     }
4149
4150     assert((initCount * baseTypeSize) <= simdNode->gtSIMDSize);
4151
4152     if (initCount * baseTypeSize < EA_16BYTE)
4153     {
4154         getEmitter()->emitIns_R_I(INS_movi, EA_16BYTE, vectorReg, 0x00, INS_OPTS_16B);
4155     }
4156
4157     if (varTypeIsIntegral(baseType))
4158     {
4159         for (unsigned i = 0; i < initCount; i++)
4160         {
4161             getEmitter()->emitIns_R_R_I(INS_ins, baseTypeSize, vectorReg, operandRegs[i], i);
4162         }
4163     }
4164     else
4165     {
4166         for (unsigned i = 0; i < initCount; i++)
4167         {
4168             getEmitter()->emitIns_R_R_I_I(INS_ins, baseTypeSize, vectorReg, operandRegs[i], i, 0);
4169         }
4170     }
4171
4172     // Load the initialized value.
4173     if (targetReg != vectorReg)
4174     {
4175         getEmitter()->emitIns_R_R(INS_mov, EA_16BYTE, targetReg, vectorReg);
4176     }
4177
4178     genProduceReg(simdNode);
4179 }
4180
4181 //----------------------------------------------------------------------------------
4182 // genSIMDIntrinsicUnOp: Generate code for SIMD Intrinsic unary operations like sqrt.
4183 //
4184 // Arguments:
4185 //    simdNode - The GT_SIMD node
4186 //
4187 // Return Value:
4188 //    None.
4189 //
4190 void CodeGen::genSIMDIntrinsicUnOp(GenTreeSIMD* simdNode)
4191 {
4192     assert(simdNode->gtSIMDIntrinsicID == SIMDIntrinsicSqrt || simdNode->gtSIMDIntrinsicID == SIMDIntrinsicCast ||
4193            simdNode->gtSIMDIntrinsicID == SIMDIntrinsicAbs ||
4194            simdNode->gtSIMDIntrinsicID == SIMDIntrinsicConvertToSingle ||
4195            simdNode->gtSIMDIntrinsicID == SIMDIntrinsicConvertToInt32 ||
4196            simdNode->gtSIMDIntrinsicID == SIMDIntrinsicConvertToDouble ||
4197            simdNode->gtSIMDIntrinsicID == SIMDIntrinsicConvertToInt64);
4198
4199     GenTree*  op1       = simdNode->gtGetOp1();
4200     var_types baseType  = simdNode->gtSIMDBaseType;
4201     regNumber targetReg = simdNode->gtRegNum;
4202     assert(targetReg != REG_NA);
4203     var_types targetType = simdNode->TypeGet();
4204
4205     genConsumeOperands(simdNode);
4206     regNumber op1Reg = op1->gtRegNum;
4207
4208     assert(genIsValidFloatReg(op1Reg));
4209     assert(genIsValidFloatReg(targetReg));
4210
4211     instruction ins = getOpForSIMDIntrinsic(simdNode->gtSIMDIntrinsicID, baseType);
4212
4213     bool     is16Byte = (simdNode->gtSIMDSize > 8);
4214     emitAttr attr     = is16Byte ? EA_16BYTE : EA_8BYTE;
4215     insOpts  opt      = (ins == INS_mov) ? INS_OPTS_NONE : genGetSimdInsOpt(is16Byte, baseType);
4216
4217     getEmitter()->emitIns_R_R(ins, attr, targetReg, op1Reg, opt);
4218
4219     genProduceReg(simdNode);
4220 }
4221
4222 //--------------------------------------------------------------------------------
4223 // genSIMDIntrinsicWiden: Generate code for SIMD Intrinsic Widen operations
4224 //
4225 // Arguments:
4226 //    simdNode - The GT_SIMD node
4227 //
4228 // Notes:
4229 //    The Widen intrinsics are broken into separate intrinsics for the two results.
4230 //
4231 void CodeGen::genSIMDIntrinsicWiden(GenTreeSIMD* simdNode)
4232 {
4233     assert((simdNode->gtSIMDIntrinsicID == SIMDIntrinsicWidenLo) ||
4234            (simdNode->gtSIMDIntrinsicID == SIMDIntrinsicWidenHi));
4235
4236     GenTree*  op1       = simdNode->gtGetOp1();
4237     var_types baseType  = simdNode->gtSIMDBaseType;
4238     regNumber targetReg = simdNode->gtRegNum;
4239     assert(targetReg != REG_NA);
4240     var_types simdType = simdNode->TypeGet();
4241
4242     genConsumeOperands(simdNode);
4243     regNumber op1Reg   = op1->gtRegNum;
4244     regNumber srcReg   = op1Reg;
4245     emitAttr  emitSize = emitActualTypeSize(simdType);
4246
4247     instruction ins = getOpForSIMDIntrinsic(simdNode->gtSIMDIntrinsicID, baseType);
4248
4249     if (varTypeIsFloating(baseType))
4250     {
4251         getEmitter()->emitIns_R_R(ins, EA_8BYTE, targetReg, op1Reg);
4252     }
4253     else
4254     {
4255         bool    is16Byte = (simdNode->gtSIMDIntrinsicID == SIMDIntrinsicWidenHi);
4256         insOpts opt      = genGetSimdInsOpt(is16Byte, baseType);
4257
4258         getEmitter()->emitIns_R_R(ins, is16Byte ? EA_16BYTE : EA_8BYTE, targetReg, op1Reg, opt);
4259     }
4260
4261     genProduceReg(simdNode);
4262 }
4263
4264 //--------------------------------------------------------------------------------
4265 // genSIMDIntrinsicNarrow: Generate code for SIMD Intrinsic Narrow operations
4266 //
4267 // Arguments:
4268 //    simdNode - The GT_SIMD node
4269 //
4270 // Notes:
4271 //    This intrinsic takes two arguments. The first operand is narrowed to produce the
4272 //    lower elements of the results, and the second operand produces the high elements.
4273 //
4274 void CodeGen::genSIMDIntrinsicNarrow(GenTreeSIMD* simdNode)
4275 {
4276     assert(simdNode->gtSIMDIntrinsicID == SIMDIntrinsicNarrow);
4277
4278     GenTree*  op1       = simdNode->gtGetOp1();
4279     GenTree*  op2       = simdNode->gtGetOp2();
4280     var_types baseType  = simdNode->gtSIMDBaseType;
4281     regNumber targetReg = simdNode->gtRegNum;
4282     assert(targetReg != REG_NA);
4283     var_types simdType = simdNode->TypeGet();
4284     emitAttr  emitSize = emitTypeSize(simdType);
4285
4286     genConsumeOperands(simdNode);
4287     regNumber op1Reg = op1->gtRegNum;
4288     regNumber op2Reg = op2->gtRegNum;
4289
4290     assert(genIsValidFloatReg(op1Reg));
4291     assert(genIsValidFloatReg(op2Reg));
4292     assert(genIsValidFloatReg(targetReg));
4293     assert(op2Reg != targetReg);
4294     assert(simdNode->gtSIMDSize == 16);
4295
4296     instruction ins = getOpForSIMDIntrinsic(simdNode->gtSIMDIntrinsicID, baseType);
4297     assert((ins == INS_fcvtn) || (ins == INS_xtn));
4298
4299     if (ins == INS_fcvtn)
4300     {
4301         getEmitter()->emitIns_R_R(INS_fcvtn, EA_8BYTE, targetReg, op1Reg);
4302         getEmitter()->emitIns_R_R(INS_fcvtn2, EA_8BYTE, targetReg, op2Reg);
4303     }
4304     else
4305     {
4306         insOpts opt  = INS_OPTS_NONE;
4307         insOpts opt2 = INS_OPTS_NONE;
4308
4309         // This is not the same as genGetSimdInsOpt()
4310         // Basetype is the soure operand type
4311         // However encoding is based on the destination operand type which is 1/2 the basetype.
4312         switch (baseType)
4313         {
4314             case TYP_ULONG:
4315             case TYP_LONG:
4316                 opt  = INS_OPTS_2S;
4317                 opt2 = INS_OPTS_4S;
4318                 break;
4319             case TYP_UINT:
4320             case TYP_INT:
4321                 opt  = INS_OPTS_4H;
4322                 opt2 = INS_OPTS_8H;
4323                 break;
4324             case TYP_USHORT:
4325             case TYP_SHORT:
4326                 opt  = INS_OPTS_8B;
4327                 opt2 = INS_OPTS_16B;
4328                 break;
4329             default:
4330                 assert(!"Unsupported narrowing element type");
4331                 unreached();
4332         }
4333         getEmitter()->emitIns_R_R(INS_xtn, EA_8BYTE, targetReg, op1Reg, opt);
4334         getEmitter()->emitIns_R_R(INS_xtn2, EA_16BYTE, targetReg, op2Reg, opt2);
4335     }
4336
4337     genProduceReg(simdNode);
4338 }
4339
4340 //--------------------------------------------------------------------------------
4341 // genSIMDIntrinsicBinOp: Generate code for SIMD Intrinsic binary operations
4342 // add, sub, mul, bit-wise And, AndNot and Or.
4343 //
4344 // Arguments:
4345 //    simdNode - The GT_SIMD node
4346 //
4347 // Return Value:
4348 //    None.
4349 //
4350 void CodeGen::genSIMDIntrinsicBinOp(GenTreeSIMD* simdNode)
4351 {
4352     assert(simdNode->gtSIMDIntrinsicID == SIMDIntrinsicAdd || simdNode->gtSIMDIntrinsicID == SIMDIntrinsicSub ||
4353            simdNode->gtSIMDIntrinsicID == SIMDIntrinsicMul || simdNode->gtSIMDIntrinsicID == SIMDIntrinsicDiv ||
4354            simdNode->gtSIMDIntrinsicID == SIMDIntrinsicBitwiseAnd ||
4355            simdNode->gtSIMDIntrinsicID == SIMDIntrinsicBitwiseAndNot ||
4356            simdNode->gtSIMDIntrinsicID == SIMDIntrinsicBitwiseOr ||
4357            simdNode->gtSIMDIntrinsicID == SIMDIntrinsicBitwiseXor || simdNode->gtSIMDIntrinsicID == SIMDIntrinsicMin ||
4358            simdNode->gtSIMDIntrinsicID == SIMDIntrinsicMax || simdNode->gtSIMDIntrinsicID == SIMDIntrinsicEqual ||
4359            simdNode->gtSIMDIntrinsicID == SIMDIntrinsicLessThan ||
4360            simdNode->gtSIMDIntrinsicID == SIMDIntrinsicGreaterThan ||
4361            simdNode->gtSIMDIntrinsicID == SIMDIntrinsicLessThanOrEqual ||
4362            simdNode->gtSIMDIntrinsicID == SIMDIntrinsicGreaterThanOrEqual);
4363
4364     GenTree*  op1       = simdNode->gtGetOp1();
4365     GenTree*  op2       = simdNode->gtGetOp2();
4366     var_types baseType  = simdNode->gtSIMDBaseType;
4367     regNumber targetReg = simdNode->gtRegNum;
4368     assert(targetReg != REG_NA);
4369     var_types targetType = simdNode->TypeGet();
4370
4371     genConsumeOperands(simdNode);
4372     regNumber op1Reg = op1->gtRegNum;
4373     regNumber op2Reg = op2->gtRegNum;
4374
4375     assert(genIsValidFloatReg(op1Reg));
4376     assert(genIsValidFloatReg(op2Reg));
4377     assert(genIsValidFloatReg(targetReg));
4378
4379     // TODO-ARM64-CQ Contain integer constants where posible
4380
4381     instruction ins = getOpForSIMDIntrinsic(simdNode->gtSIMDIntrinsicID, baseType);
4382
4383     bool     is16Byte = (simdNode->gtSIMDSize > 8);
4384     emitAttr attr     = is16Byte ? EA_16BYTE : EA_8BYTE;
4385     insOpts  opt      = genGetSimdInsOpt(is16Byte, baseType);
4386
4387     getEmitter()->emitIns_R_R_R(ins, attr, targetReg, op1Reg, op2Reg, opt);
4388
4389     genProduceReg(simdNode);
4390 }
4391
4392 //--------------------------------------------------------------------------------
4393 // genSIMDIntrinsicRelOp: Generate code for a SIMD Intrinsic relational operater
4394 // == and !=
4395 //
4396 // Arguments:
4397 //    simdNode - The GT_SIMD node
4398 //
4399 // Return Value:
4400 //    None.
4401 //
4402 void CodeGen::genSIMDIntrinsicRelOp(GenTreeSIMD* simdNode)
4403 {
4404     assert(simdNode->gtSIMDIntrinsicID == SIMDIntrinsicOpEquality ||
4405            simdNode->gtSIMDIntrinsicID == SIMDIntrinsicOpInEquality);
4406
4407     GenTree*  op1        = simdNode->gtGetOp1();
4408     GenTree*  op2        = simdNode->gtGetOp2();
4409     var_types baseType   = simdNode->gtSIMDBaseType;
4410     regNumber targetReg  = simdNode->gtRegNum;
4411     var_types targetType = simdNode->TypeGet();
4412
4413     genConsumeOperands(simdNode);
4414     regNumber op1Reg   = op1->gtRegNum;
4415     regNumber op2Reg   = op2->gtRegNum;
4416     regNumber otherReg = op2Reg;
4417
4418     instruction ins = getOpForSIMDIntrinsic(SIMDIntrinsicEqual, baseType);
4419
4420     bool     is16Byte = (simdNode->gtSIMDSize > 8);
4421     emitAttr attr     = is16Byte ? EA_16BYTE : EA_8BYTE;
4422     insOpts  opt      = genGetSimdInsOpt(is16Byte, baseType);
4423
4424     // TODO-ARM64-CQ Contain integer constants where posible
4425
4426     regNumber tmpFloatReg = simdNode->GetSingleTempReg(RBM_ALLFLOAT);
4427
4428     getEmitter()->emitIns_R_R_R(ins, attr, tmpFloatReg, op1Reg, op2Reg, opt);
4429
4430     if ((simdNode->gtFlags & GTF_SIMD12_OP) != 0)
4431     {
4432         // For 12Byte vectors we must set upper bits to get correct comparison
4433         // We do not assume upper bits are zero.
4434         instGen_Set_Reg_To_Imm(EA_4BYTE, targetReg, -1);
4435         getEmitter()->emitIns_R_R_I(INS_ins, EA_4BYTE, tmpFloatReg, targetReg, 3);
4436     }
4437
4438     getEmitter()->emitIns_R_R(INS_uminv, attr, tmpFloatReg, tmpFloatReg,
4439                               (simdNode->gtSIMDSize > 8) ? INS_OPTS_16B : INS_OPTS_8B);
4440
4441     getEmitter()->emitIns_R_R_I(INS_mov, EA_1BYTE, targetReg, tmpFloatReg, 0);
4442
4443     if (simdNode->gtSIMDIntrinsicID == SIMDIntrinsicOpInEquality)
4444     {
4445         getEmitter()->emitIns_R_R_I(INS_eor, EA_4BYTE, targetReg, targetReg, 0x1);
4446     }
4447
4448     getEmitter()->emitIns_R_R_I(INS_and, EA_4BYTE, targetReg, targetReg, 0x1);
4449
4450     genProduceReg(simdNode);
4451 }
4452
4453 //--------------------------------------------------------------------------------
4454 // genSIMDIntrinsicDotProduct: Generate code for SIMD Intrinsic Dot Product.
4455 //
4456 // Arguments:
4457 //    simdNode - The GT_SIMD node
4458 //
4459 // Return Value:
4460 //    None.
4461 //
4462 void CodeGen::genSIMDIntrinsicDotProduct(GenTreeSIMD* simdNode)
4463 {
4464     assert(simdNode->gtSIMDIntrinsicID == SIMDIntrinsicDotProduct);
4465
4466     GenTree*  op1      = simdNode->gtGetOp1();
4467     GenTree*  op2      = simdNode->gtGetOp2();
4468     var_types baseType = simdNode->gtSIMDBaseType;
4469     var_types simdType = op1->TypeGet();
4470
4471     regNumber targetReg = simdNode->gtRegNum;
4472     assert(targetReg != REG_NA);
4473
4474     var_types targetType = simdNode->TypeGet();
4475     assert(targetType == baseType);
4476
4477     genConsumeOperands(simdNode);
4478     regNumber op1Reg = op1->gtRegNum;
4479     regNumber op2Reg = op2->gtRegNum;
4480     regNumber tmpReg = targetReg;
4481
4482     if (!varTypeIsFloating(baseType))
4483     {
4484         tmpReg = simdNode->GetSingleTempReg(RBM_ALLFLOAT);
4485     }
4486
4487     instruction ins = getOpForSIMDIntrinsic(SIMDIntrinsicMul, baseType);
4488
4489     bool     is16Byte = (simdNode->gtSIMDSize > 8);
4490     emitAttr attr     = is16Byte ? EA_16BYTE : EA_8BYTE;
4491     insOpts  opt      = genGetSimdInsOpt(is16Byte, baseType);
4492
4493     // Vector multiply
4494     getEmitter()->emitIns_R_R_R(ins, attr, tmpReg, op1Reg, op2Reg, opt);
4495
4496     if ((simdNode->gtFlags & GTF_SIMD12_OP) != 0)
4497     {
4498         // For 12Byte vectors we must zero upper bits to get correct dot product
4499         // We do not assume upper bits are zero.
4500         getEmitter()->emitIns_R_R_I(INS_ins, EA_4BYTE, tmpReg, REG_ZR, 3);
4501     }
4502
4503     // Vector add horizontal
4504     if (varTypeIsFloating(baseType))
4505     {
4506         if (baseType == TYP_FLOAT)
4507         {
4508             if (opt == INS_OPTS_4S)
4509             {
4510                 getEmitter()->emitIns_R_R_R(INS_faddp, attr, tmpReg, tmpReg, tmpReg, INS_OPTS_4S);
4511             }
4512             getEmitter()->emitIns_R_R(INS_faddp, EA_4BYTE, targetReg, tmpReg);
4513         }
4514         else
4515         {
4516             getEmitter()->emitIns_R_R(INS_faddp, EA_8BYTE, targetReg, tmpReg);
4517         }
4518     }
4519     else
4520     {
4521         ins = varTypeIsUnsigned(baseType) ? INS_uaddlv : INS_saddlv;
4522
4523         getEmitter()->emitIns_R_R(ins, attr, tmpReg, tmpReg, opt);
4524
4525         // Mov to integer register
4526         if (varTypeIsUnsigned(baseType) || (genTypeSize(baseType) < 4))
4527         {
4528             getEmitter()->emitIns_R_R_I(INS_mov, emitTypeSize(baseType), targetReg, tmpReg, 0);
4529         }
4530         else
4531         {
4532             getEmitter()->emitIns_R_R_I(INS_smov, emitActualTypeSize(baseType), targetReg, tmpReg, 0);
4533         }
4534     }
4535
4536     genProduceReg(simdNode);
4537 }
4538
4539 //------------------------------------------------------------------------------------
4540 // genSIMDIntrinsicGetItem: Generate code for SIMD Intrinsic get element at index i.
4541 //
4542 // Arguments:
4543 //    simdNode - The GT_SIMD node
4544 //
4545 // Return Value:
4546 //    None.
4547 //
4548 void CodeGen::genSIMDIntrinsicGetItem(GenTreeSIMD* simdNode)
4549 {
4550     assert(simdNode->gtSIMDIntrinsicID == SIMDIntrinsicGetItem);
4551
4552     GenTree*  op1      = simdNode->gtGetOp1();
4553     GenTree*  op2      = simdNode->gtGetOp2();
4554     var_types simdType = op1->TypeGet();
4555     assert(varTypeIsSIMD(simdType));
4556
4557     // op1 of TYP_SIMD12 should be considered as TYP_SIMD16
4558     if (simdType == TYP_SIMD12)
4559     {
4560         simdType = TYP_SIMD16;
4561     }
4562
4563     var_types baseType  = simdNode->gtSIMDBaseType;
4564     regNumber targetReg = simdNode->gtRegNum;
4565     assert(targetReg != REG_NA);
4566     var_types targetType = simdNode->TypeGet();
4567     assert(targetType == genActualType(baseType));
4568
4569     // GetItem has 2 operands:
4570     // - the source of SIMD type (op1)
4571     // - the index of the value to be returned.
4572     genConsumeOperands(simdNode);
4573
4574     emitAttr baseTypeSize  = emitTypeSize(baseType);
4575     unsigned baseTypeScale = genLog2(EA_SIZE_IN_BYTES(baseTypeSize));
4576
4577     if (op2->IsCnsIntOrI())
4578     {
4579         assert(op2->isContained());
4580
4581         ssize_t index = op2->gtIntCon.gtIconVal;
4582
4583         // We only need to generate code for the get if the index is valid
4584         // If the index is invalid, previously generated for the range check will throw
4585         if (getEmitter()->isValidVectorIndex(emitTypeSize(simdType), baseTypeSize, index))
4586         {
4587             if (op1->isContained())
4588             {
4589                 int         offset = (int)index * genTypeSize(baseType);
4590                 instruction ins    = ins_Load(baseType);
4591                 baseTypeSize       = varTypeIsFloating(baseType)
4592                                    ? baseTypeSize
4593                                    : getEmitter()->emitInsAdjustLoadStoreAttr(ins, baseTypeSize);
4594
4595                 assert(!op1->isUsedFromReg());
4596
4597                 if (op1->OperIsLocal())
4598                 {
4599                     unsigned varNum = op1->gtLclVarCommon.gtLclNum;
4600
4601                     getEmitter()->emitIns_R_S(ins, baseTypeSize, targetReg, varNum, offset);
4602                 }
4603                 else
4604                 {
4605                     assert(op1->OperGet() == GT_IND);
4606
4607                     GenTree* addr = op1->AsIndir()->Addr();
4608                     assert(!addr->isContained());
4609                     regNumber baseReg = addr->gtRegNum;
4610
4611                     // ldr targetReg, [baseReg, #offset]
4612                     getEmitter()->emitIns_R_R_I(ins, baseTypeSize, targetReg, baseReg, offset);
4613                 }
4614             }
4615             else
4616             {
4617                 assert(op1->isUsedFromReg());
4618                 regNumber srcReg = op1->gtRegNum;
4619
4620                 // mov targetReg, srcReg[#index]
4621                 getEmitter()->emitIns_R_R_I(INS_mov, baseTypeSize, targetReg, srcReg, index);
4622             }
4623         }
4624     }
4625     else
4626     {
4627         assert(!op2->isContained());
4628
4629         regNumber baseReg  = REG_NA;
4630         regNumber indexReg = op2->gtRegNum;
4631
4632         if (op1->isContained())
4633         {
4634             // Optimize the case of op1 is in memory and trying to access ith element.
4635             assert(!op1->isUsedFromReg());
4636             if (op1->OperIsLocal())
4637             {
4638                 unsigned varNum = op1->gtLclVarCommon.gtLclNum;
4639
4640                 baseReg = simdNode->ExtractTempReg();
4641
4642                 // Load the address of varNum
4643                 getEmitter()->emitIns_R_S(INS_lea, EA_PTRSIZE, baseReg, varNum, 0);
4644             }
4645             else
4646             {
4647                 // Require GT_IND addr to be not contained.
4648                 assert(op1->OperGet() == GT_IND);
4649
4650                 GenTree* addr = op1->AsIndir()->Addr();
4651                 assert(!addr->isContained());
4652
4653                 baseReg = addr->gtRegNum;
4654             }
4655         }
4656         else
4657         {
4658             assert(op1->isUsedFromReg());
4659             regNumber srcReg = op1->gtRegNum;
4660
4661             unsigned simdInitTempVarNum = compiler->lvaSIMDInitTempVarNum;
4662             noway_assert(compiler->lvaSIMDInitTempVarNum != BAD_VAR_NUM);
4663
4664             baseReg = simdNode->ExtractTempReg();
4665
4666             // Load the address of simdInitTempVarNum
4667             getEmitter()->emitIns_R_S(INS_lea, EA_PTRSIZE, baseReg, simdInitTempVarNum, 0);
4668
4669             // Store the vector to simdInitTempVarNum
4670             getEmitter()->emitIns_R_R(INS_str, emitTypeSize(simdType), srcReg, baseReg);
4671         }
4672
4673         assert(genIsValidIntReg(indexReg));
4674         assert(genIsValidIntReg(baseReg));
4675         assert(baseReg != indexReg);
4676
4677         // Load item at baseReg[index]
4678         getEmitter()->emitIns_R_R_R_Ext(ins_Load(baseType), baseTypeSize, targetReg, baseReg, indexReg, INS_OPTS_LSL,
4679                                         baseTypeScale);
4680     }
4681
4682     genProduceReg(simdNode);
4683 }
4684
4685 //------------------------------------------------------------------------------------
4686 // genSIMDIntrinsicSetItem: Generate code for SIMD Intrinsic set element at index i.
4687 //
4688 // Arguments:
4689 //    simdNode - The GT_SIMD node
4690 //
4691 // Return Value:
4692 //    None.
4693 //
4694 void CodeGen::genSIMDIntrinsicSetItem(GenTreeSIMD* simdNode)
4695 {
4696     // Determine index based on intrinsic ID
4697     int index = -1;
4698     switch (simdNode->gtSIMDIntrinsicID)
4699     {
4700         case SIMDIntrinsicSetX:
4701             index = 0;
4702             break;
4703         case SIMDIntrinsicSetY:
4704             index = 1;
4705             break;
4706         case SIMDIntrinsicSetZ:
4707             index = 2;
4708             break;
4709         case SIMDIntrinsicSetW:
4710             index = 3;
4711             break;
4712
4713         default:
4714             unreached();
4715     }
4716     assert(index != -1);
4717
4718     // op1 is the SIMD vector
4719     // op2 is the value to be set
4720     GenTree* op1 = simdNode->gtGetOp1();
4721     GenTree* op2 = simdNode->gtGetOp2();
4722
4723     var_types baseType  = simdNode->gtSIMDBaseType;
4724     regNumber targetReg = simdNode->gtRegNum;
4725     assert(targetReg != REG_NA);
4726     var_types targetType = simdNode->TypeGet();
4727     assert(varTypeIsSIMD(targetType));
4728
4729     assert(op2->TypeGet() == baseType);
4730     assert(simdNode->gtSIMDSize >= ((index + 1) * genTypeSize(baseType)));
4731
4732     genConsumeOperands(simdNode);
4733     regNumber op1Reg = op1->gtRegNum;
4734     regNumber op2Reg = op2->gtRegNum;
4735
4736     assert(genIsValidFloatReg(targetReg));
4737     assert(genIsValidFloatReg(op1Reg));
4738     assert(genIsValidIntReg(op2Reg) || genIsValidFloatReg(op2Reg));
4739     assert(targetReg != op2Reg);
4740
4741     emitAttr attr = emitTypeSize(baseType);
4742
4743     // Insert mov if register assignment requires it
4744     getEmitter()->emitIns_R_R(INS_mov, EA_16BYTE, targetReg, op1Reg);
4745
4746     if (genIsValidIntReg(op2Reg))
4747     {
4748         getEmitter()->emitIns_R_R_I(INS_ins, attr, targetReg, op2Reg, index);
4749     }
4750     else
4751     {
4752         getEmitter()->emitIns_R_R_I_I(INS_ins, attr, targetReg, op2Reg, index, 0);
4753     }
4754
4755     genProduceReg(simdNode);
4756 }
4757
4758 //-----------------------------------------------------------------------------
4759 // genSIMDIntrinsicUpperSave: save the upper half of a TYP_SIMD16 vector to
4760 //                            the given register, if any, or to memory.
4761 //
4762 // Arguments:
4763 //    simdNode - The GT_SIMD node
4764 //
4765 // Return Value:
4766 //    None.
4767 //
4768 // Notes:
4769 //    The upper half of all SIMD registers are volatile, even the callee-save registers.
4770 //    When a 16-byte SIMD value is live across a call, the register allocator will use this intrinsic
4771 //    to cause the upper half to be saved.  It will first attempt to find another, unused, callee-save
4772 //    register.  If such a register cannot be found, it will save it to an available caller-save register.
4773 //    In that case, this node will be marked GTF_SPILL, which will cause genProduceReg to save the 8 byte
4774 //    value to the stack.  (Note that if there are no caller-save registers available, the entire 16 byte
4775 //    value will be spilled to the stack.)
4776 //
4777 void CodeGen::genSIMDIntrinsicUpperSave(GenTreeSIMD* simdNode)
4778 {
4779     assert(simdNode->gtSIMDIntrinsicID == SIMDIntrinsicUpperSave);
4780
4781     GenTree* op1 = simdNode->gtGetOp1();
4782     assert(op1->IsLocal());
4783     assert(emitTypeSize(op1->TypeGet()) == 16);
4784     regNumber targetReg = simdNode->gtRegNum;
4785     regNumber op1Reg    = genConsumeReg(op1);
4786     assert(op1Reg != REG_NA);
4787     assert(targetReg != REG_NA);
4788     getEmitter()->emitIns_R_R_I_I(INS_mov, EA_8BYTE, targetReg, op1Reg, 0, 1);
4789
4790     genProduceReg(simdNode);
4791 }
4792
4793 //-----------------------------------------------------------------------------
4794 // genSIMDIntrinsicUpperRestore: Restore the upper half of a TYP_SIMD16 vector to
4795 //                               the given register, if any, or to memory.
4796 //
4797 // Arguments:
4798 //    simdNode - The GT_SIMD node
4799 //
4800 // Return Value:
4801 //    None.
4802 //
4803 // Notes:
4804 //    For consistency with genSIMDIntrinsicUpperSave, and to ensure that lclVar nodes always
4805 //    have their home register, this node has its targetReg on the lclVar child, and its source
4806 //    on the simdNode.
4807 //    Regarding spill, please see the note above on genSIMDIntrinsicUpperSave.  If we have spilled
4808 //    an upper-half to a caller save register, this node will be marked GTF_SPILLED.  However, unlike
4809 //    most spill scenarios, the saved tree will be different from the restored tree, but the spill
4810 //    restore logic, which is triggered by the call to genConsumeReg, requires us to provide the
4811 //    spilled tree (saveNode) in order to perform the reload.  We can easily find that tree,
4812 //    as it is in the spill descriptor for the register from which it was saved.
4813 //
4814 void CodeGen::genSIMDIntrinsicUpperRestore(GenTreeSIMD* simdNode)
4815 {
4816     assert(simdNode->gtSIMDIntrinsicID == SIMDIntrinsicUpperRestore);
4817
4818     GenTree* op1 = simdNode->gtGetOp1();
4819     assert(op1->IsLocal());
4820     assert(emitTypeSize(op1->TypeGet()) == 16);
4821     regNumber srcReg    = simdNode->gtRegNum;
4822     regNumber lclVarReg = genConsumeReg(op1);
4823     unsigned  varNum    = op1->AsLclVarCommon()->gtLclNum;
4824     assert(lclVarReg != REG_NA);
4825     assert(srcReg != REG_NA);
4826     if (simdNode->gtFlags & GTF_SPILLED)
4827     {
4828         GenTree* saveNode = regSet.rsSpillDesc[srcReg]->spillTree;
4829         noway_assert(saveNode != nullptr && (saveNode->gtRegNum == srcReg));
4830         genConsumeReg(saveNode);
4831     }
4832     getEmitter()->emitIns_R_R_I_I(INS_mov, EA_8BYTE, lclVarReg, srcReg, 1, 0);
4833 }
4834
4835 //-----------------------------------------------------------------------------
4836 // genStoreIndTypeSIMD12: store indirect a TYP_SIMD12 (i.e. Vector3) to memory.
4837 // Since Vector3 is not a hardware supported write size, it is performed
4838 // as two writes: 8 byte followed by 4-byte.
4839 //
4840 // Arguments:
4841 //    treeNode - tree node that is attempting to store indirect
4842 //
4843 //
4844 // Return Value:
4845 //    None.
4846 //
4847 void CodeGen::genStoreIndTypeSIMD12(GenTree* treeNode)
4848 {
4849     assert(treeNode->OperGet() == GT_STOREIND);
4850
4851     GenTree* addr = treeNode->gtOp.gtOp1;
4852     GenTree* data = treeNode->gtOp.gtOp2;
4853
4854     // addr and data should not be contained.
4855     assert(!data->isContained());
4856     assert(!addr->isContained());
4857
4858 #ifdef DEBUG
4859     // Should not require a write barrier
4860     GCInfo::WriteBarrierForm writeBarrierForm = gcInfo.gcIsWriteBarrierCandidate(treeNode, data);
4861     assert(writeBarrierForm == GCInfo::WBF_NoBarrier);
4862 #endif
4863
4864     genConsumeOperands(treeNode->AsOp());
4865
4866     // Need an addtional integer register to extract upper 4 bytes from data.
4867     regNumber tmpReg = treeNode->GetSingleTempReg();
4868     assert(tmpReg != addr->gtRegNum);
4869
4870     // 8-byte write
4871     getEmitter()->emitIns_R_R(ins_Store(TYP_DOUBLE), EA_8BYTE, data->gtRegNum, addr->gtRegNum);
4872
4873     // Extract upper 4-bytes from data
4874     getEmitter()->emitIns_R_R_I(INS_mov, EA_4BYTE, tmpReg, data->gtRegNum, 2);
4875
4876     // 4-byte write
4877     getEmitter()->emitIns_R_R_I(INS_str, EA_4BYTE, tmpReg, addr->gtRegNum, 8);
4878 }
4879
4880 //-----------------------------------------------------------------------------
4881 // genLoadIndTypeSIMD12: load indirect a TYP_SIMD12 (i.e. Vector3) value.
4882 // Since Vector3 is not a hardware supported write size, it is performed
4883 // as two loads: 8 byte followed by 4-byte.
4884 //
4885 // Arguments:
4886 //    treeNode - tree node of GT_IND
4887 //
4888 //
4889 // Return Value:
4890 //    None.
4891 //
4892 void CodeGen::genLoadIndTypeSIMD12(GenTree* treeNode)
4893 {
4894     assert(treeNode->OperGet() == GT_IND);
4895
4896     GenTree*  addr      = treeNode->gtOp.gtOp1;
4897     regNumber targetReg = treeNode->gtRegNum;
4898
4899     assert(!addr->isContained());
4900
4901     regNumber operandReg = genConsumeReg(addr);
4902
4903     // Need an addtional int register to read upper 4 bytes, which is different from targetReg
4904     regNumber tmpReg = treeNode->GetSingleTempReg();
4905
4906     // 8-byte read
4907     getEmitter()->emitIns_R_R(ins_Load(TYP_DOUBLE), EA_8BYTE, targetReg, addr->gtRegNum);
4908
4909     // 4-byte read
4910     getEmitter()->emitIns_R_R_I(INS_ldr, EA_4BYTE, tmpReg, addr->gtRegNum, 8);
4911
4912     // Insert upper 4-bytes into data
4913     getEmitter()->emitIns_R_R_I(INS_mov, EA_4BYTE, targetReg, tmpReg, 2);
4914
4915     genProduceReg(treeNode);
4916 }
4917
4918 //-----------------------------------------------------------------------------
4919 // genStoreLclTypeSIMD12: store a TYP_SIMD12 (i.e. Vector3) type field.
4920 // Since Vector3 is not a hardware supported write size, it is performed
4921 // as two stores: 8 byte followed by 4-byte.
4922 //
4923 // Arguments:
4924 //    treeNode - tree node that is attempting to store TYP_SIMD12 field
4925 //
4926 // Return Value:
4927 //    None.
4928 //
4929 void CodeGen::genStoreLclTypeSIMD12(GenTree* treeNode)
4930 {
4931     assert((treeNode->OperGet() == GT_STORE_LCL_FLD) || (treeNode->OperGet() == GT_STORE_LCL_VAR));
4932
4933     unsigned offs   = 0;
4934     unsigned varNum = treeNode->gtLclVarCommon.gtLclNum;
4935     assert(varNum < compiler->lvaCount);
4936
4937     if (treeNode->OperGet() == GT_LCL_FLD)
4938     {
4939         offs = treeNode->gtLclFld.gtLclOffs;
4940     }
4941
4942     GenTree* op1 = treeNode->gtOp.gtOp1;
4943     assert(!op1->isContained());
4944     regNumber operandReg = genConsumeReg(op1);
4945
4946     // Need an addtional integer register to extract upper 4 bytes from data.
4947     regNumber tmpReg = treeNode->GetSingleTempReg();
4948
4949     // store lower 8 bytes
4950     getEmitter()->emitIns_S_R(ins_Store(TYP_DOUBLE), EA_8BYTE, operandReg, varNum, offs);
4951
4952     // Extract upper 4-bytes from data
4953     getEmitter()->emitIns_R_R_I(INS_mov, EA_4BYTE, tmpReg, operandReg, 2);
4954
4955     // 4-byte write
4956     getEmitter()->emitIns_S_R(INS_str, EA_4BYTE, tmpReg, varNum, offs + 8);
4957 }
4958
4959 #endif // FEATURE_SIMD
4960
4961 #ifdef FEATURE_HW_INTRINSICS
4962 #include "hwintrinsicArm64.h"
4963
4964 instruction CodeGen::getOpForHWIntrinsic(GenTreeHWIntrinsic* node, var_types instrType)
4965 {
4966     NamedIntrinsic intrinsicID = node->gtHWIntrinsicId;
4967
4968     unsigned int instrTypeIndex = varTypeIsFloating(instrType) ? 0 : varTypeIsUnsigned(instrType) ? 2 : 1;
4969
4970     return compiler->getHWIntrinsicInfo(intrinsicID).instrs[instrTypeIndex];
4971 }
4972
4973 //------------------------------------------------------------------------
4974 // genHWIntrinsic: Produce code for a GT_HWIntrinsic node.
4975 //
4976 // This is the main routine which in turn calls the genHWIntrinsicXXX() routines.
4977 //
4978 // Arguments:
4979 //    node - the GT_HWIntrinsic node
4980 //
4981 // Return Value:
4982 //    None.
4983 //
4984 void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node)
4985 {
4986     NamedIntrinsic intrinsicID = node->gtHWIntrinsicId;
4987
4988     switch (compiler->getHWIntrinsicInfo(intrinsicID).form)
4989     {
4990         case HWIntrinsicInfo::UnaryOp:
4991             genHWIntrinsicUnaryOp(node);
4992             break;
4993         case HWIntrinsicInfo::CrcOp:
4994             genHWIntrinsicCrcOp(node);
4995             break;
4996         case HWIntrinsicInfo::SimdBinaryOp:
4997             genHWIntrinsicSimdBinaryOp(node);
4998             break;
4999         case HWIntrinsicInfo::SimdExtractOp:
5000             genHWIntrinsicSimdExtractOp(node);
5001             break;
5002         case HWIntrinsicInfo::SimdInsertOp:
5003             genHWIntrinsicSimdInsertOp(node);
5004             break;
5005         case HWIntrinsicInfo::SimdSelectOp:
5006             genHWIntrinsicSimdSelectOp(node);
5007             break;
5008         case HWIntrinsicInfo::SimdSetAllOp:
5009             genHWIntrinsicSimdSetAllOp(node);
5010             break;
5011         case HWIntrinsicInfo::SimdUnaryOp:
5012             genHWIntrinsicSimdUnaryOp(node);
5013             break;
5014         default:
5015             NYI("HWIntrinsic form not implemented");
5016     }
5017 }
5018
5019 //------------------------------------------------------------------------
5020 // genHWIntrinsicUnaryOp:
5021 //
5022 // Produce code for a GT_HWIntrinsic node with form UnaryOp.
5023 //
5024 // Consumes one scalar operand produces a scalar
5025 //
5026 // Arguments:
5027 //    node - the GT_HWIntrinsic node
5028 //
5029 // Return Value:
5030 //    None.
5031 //
5032 void CodeGen::genHWIntrinsicUnaryOp(GenTreeHWIntrinsic* node)
5033 {
5034     GenTree*  op1       = node->gtGetOp1();
5035     regNumber targetReg = node->gtRegNum;
5036     emitAttr  attr      = emitActualTypeSize(node);
5037
5038     assert(targetReg != REG_NA);
5039     var_types targetType = node->TypeGet();
5040
5041     genConsumeOperands(node);
5042
5043     regNumber op1Reg = op1->gtRegNum;
5044
5045     instruction ins = getOpForHWIntrinsic(node, node->TypeGet());
5046     assert(ins != INS_invalid);
5047
5048     getEmitter()->emitIns_R_R(ins, attr, targetReg, op1Reg);
5049
5050     genProduceReg(node);
5051 }
5052
5053 //------------------------------------------------------------------------
5054 // genHWIntrinsicCrcOp:
5055 //
5056 // Produce code for a GT_HWIntrinsic node with form CrcOp.
5057 //
5058 // Consumes two scalar operands and produces a scalar result
5059 //
5060 // This form differs from BinaryOp because the attr depends on the size of op2
5061 //
5062 // Arguments:
5063 //    node - the GT_HWIntrinsic node
5064 //
5065 // Return Value:
5066 //    None.
5067 //
5068 void CodeGen::genHWIntrinsicCrcOp(GenTreeHWIntrinsic* node)
5069 {
5070     NYI("genHWIntrinsicCrcOp not implemented");
5071 }
5072
5073 //------------------------------------------------------------------------
5074 // genHWIntrinsicSimdBinaryOp:
5075 //
5076 // Produce code for a GT_HWIntrinsic node with form SimdBinaryOp.
5077 //
5078 // Consumes two SIMD operands and produces a SIMD result
5079 //
5080 // Arguments:
5081 //    node - the GT_HWIntrinsic node
5082 //
5083 // Return Value:
5084 //    None.
5085 //
5086 void CodeGen::genHWIntrinsicSimdBinaryOp(GenTreeHWIntrinsic* node)
5087 {
5088     GenTree*  op1       = node->gtGetOp1();
5089     GenTree*  op2       = node->gtGetOp2();
5090     var_types baseType  = node->gtSIMDBaseType;
5091     regNumber targetReg = node->gtRegNum;
5092
5093     assert(targetReg != REG_NA);
5094     var_types targetType = node->TypeGet();
5095
5096     genConsumeOperands(node);
5097
5098     regNumber op1Reg = op1->gtRegNum;
5099     regNumber op2Reg = op2->gtRegNum;
5100
5101     assert(genIsValidFloatReg(op1Reg));
5102     assert(genIsValidFloatReg(op2Reg));
5103     assert(genIsValidFloatReg(targetReg));
5104
5105     instruction ins = getOpForHWIntrinsic(node, baseType);
5106     assert(ins != INS_invalid);
5107
5108     bool     is16Byte = (node->gtSIMDSize > 8);
5109     emitAttr attr     = is16Byte ? EA_16BYTE : EA_8BYTE;
5110     insOpts  opt      = genGetSimdInsOpt(is16Byte, baseType);
5111
5112     getEmitter()->emitIns_R_R_R(ins, attr, targetReg, op1Reg, op2Reg, opt);
5113
5114     genProduceReg(node);
5115 }
5116
5117 //------------------------------------------------------------------------
5118 // genHWIntrinsicSwitchTable:
5119 //
5120 // Generate code for an immediate switch table
5121 //
5122 // In cases where an instruction only supports const immediate operands, we
5123 // need to generate functionally correct code when the operand is not constant
5124 //
5125 // This is required by the HW Intrinsic design to handle indirect calls, such as:
5126 //   debugger calls
5127 //   reflection
5128 //   call backs
5129 //
5130 // Generated code implements a switch of this form
5131 //
5132 // switch (swReg)
5133 // {
5134 // case 0:
5135 //    ins0; // emitSwCase(0)
5136 //    break;
5137 // case 1:
5138 //    ins1; // emitSwCase(1)
5139 //    break;
5140 // ...
5141 // ...
5142 // ...
5143 // case swMax - 1:
5144 //    insLast; // emitSwCase(swMax - 1)
5145 //    break;
5146 // default:
5147 //    throw ArgumentOutOfRangeException
5148 // }
5149 //
5150 // Generated code looks like:
5151 //
5152 //     cmp swReg, #swMax
5153 //     b.hs ThrowArgumentOutOfRangeExceptionHelper
5154 //     adr tmpReg, labelFirst
5155 //     add tmpReg, tmpReg, swReg, LSL #3
5156 //     b   [tmpReg]
5157 // labelFirst:
5158 //     ins0
5159 //     b labelBreakTarget
5160 //     ins1
5161 //     b labelBreakTarget
5162 //     ...
5163 //     ...
5164 //     ...
5165 //     insLast
5166 //     b labelBreakTarget
5167 // labelBreakTarget:
5168 //
5169 //
5170 // Arguments:
5171 //    swReg      - register containing the switch case to execute
5172 //    tmpReg     - temporary integer register for calculating the switch indirect branch target
5173 //    swMax      - the number of switch cases.  If swReg >= swMax throw SCK_ARG_RNG_EXCPN
5174 //    emitSwCase - function like argument taking an immediate value and emitting one instruction
5175 //
5176 // Return Value:
5177 //    None.
5178 //
5179 template <typename HWIntrinsicSwitchCaseBody>
5180 void CodeGen::genHWIntrinsicSwitchTable(regNumber                 swReg,
5181                                         regNumber                 tmpReg,
5182                                         int                       swMax,
5183                                         HWIntrinsicSwitchCaseBody emitSwCase)
5184 {
5185     assert(swMax > 0);
5186     assert(swMax <= 256);
5187
5188     assert(genIsValidIntReg(tmpReg));
5189     assert(genIsValidIntReg(swReg));
5190
5191     BasicBlock* labelFirst       = genCreateTempLabel();
5192     BasicBlock* labelBreakTarget = genCreateTempLabel();
5193
5194     // Detect and throw out of range exception
5195     getEmitter()->emitIns_R_I(INS_cmp, EA_4BYTE, swReg, swMax);
5196
5197     emitJumpKind jmpGEU = genJumpKindForOper(GT_GE, CK_UNSIGNED);
5198     genJumpToThrowHlpBlk(jmpGEU, SCK_ARG_RNG_EXCPN);
5199
5200     // Calculate switch target
5201     labelFirst->bbFlags |= BBF_JMP_TARGET;
5202
5203     // tmpReg = labelFirst
5204     getEmitter()->emitIns_R_L(INS_adr, EA_PTRSIZE, labelFirst, tmpReg);
5205
5206     // tmpReg = labelFirst + swReg * 8
5207     getEmitter()->emitIns_R_R_R_I(INS_add, EA_PTRSIZE, tmpReg, tmpReg, swReg, 3, INS_OPTS_LSL);
5208
5209     // br tmpReg
5210     getEmitter()->emitIns_R(INS_br, EA_PTRSIZE, tmpReg);
5211
5212     genDefineTempLabel(labelFirst);
5213     for (int i = 0; i < swMax; ++i)
5214     {
5215         unsigned prevInsCount = getEmitter()->emitInsCount;
5216
5217         emitSwCase(i);
5218
5219         assert(getEmitter()->emitInsCount == prevInsCount + 1);
5220
5221         inst_JMP(EJ_jmp, labelBreakTarget);
5222
5223         assert(getEmitter()->emitInsCount == prevInsCount + 2);
5224     }
5225     genDefineTempLabel(labelBreakTarget);
5226 }
5227
5228 //------------------------------------------------------------------------
5229 // genHWIntrinsicSimdExtractOp:
5230 //
5231 // Produce code for a GT_HWIntrinsic node with form SimdExtractOp.
5232 //
5233 // Consumes one SIMD operand and one scalar
5234 //
5235 // The element index operand is typically a const immediate
5236 // When it is not, a switch table is generated
5237 //
5238 // See genHWIntrinsicSwitchTable comments
5239 //
5240 // Arguments:
5241 //    node - the GT_HWIntrinsic node
5242 //
5243 // Return Value:
5244 //    None.
5245 //
5246 void CodeGen::genHWIntrinsicSimdExtractOp(GenTreeHWIntrinsic* node)
5247 {
5248     GenTree*  op1        = node->gtGetOp1();
5249     GenTree*  op2        = node->gtGetOp2();
5250     var_types simdType   = op1->TypeGet();
5251     var_types targetType = node->TypeGet();
5252     regNumber targetReg  = node->gtRegNum;
5253
5254     assert(targetReg != REG_NA);
5255
5256     genConsumeOperands(node);
5257
5258     regNumber op1Reg = op1->gtRegNum;
5259
5260     assert(genIsValidFloatReg(op1Reg));
5261
5262     emitAttr baseTypeSize = emitTypeSize(targetType);
5263
5264     int elements = emitTypeSize(simdType) / baseTypeSize;
5265
5266     auto emitSwCase = [&](int element) {
5267         assert(element >= 0);
5268         assert(element < elements);
5269
5270         if (varTypeIsFloating(targetType))
5271         {
5272             assert(genIsValidFloatReg(targetReg));
5273             getEmitter()->emitIns_R_R_I_I(INS_mov, baseTypeSize, targetReg, op1Reg, 0, element);
5274         }
5275         else if (varTypeIsUnsigned(targetType) || (baseTypeSize == EA_8BYTE))
5276         {
5277             assert(genIsValidIntReg(targetReg));
5278             getEmitter()->emitIns_R_R_I(INS_umov, baseTypeSize, targetReg, op1Reg, element);
5279         }
5280         else
5281         {
5282             assert(genIsValidIntReg(targetReg));
5283             getEmitter()->emitIns_R_R_I(INS_smov, baseTypeSize, targetReg, op1Reg, element);
5284         }
5285     };
5286
5287     if (op2->isContainedIntOrIImmed())
5288     {
5289         int element = (int)op2->AsIntConCommon()->IconValue();
5290
5291         emitSwCase(element);
5292     }
5293     else
5294     {
5295         regNumber elementReg = op2->gtRegNum;
5296         regNumber tmpReg     = node->GetSingleTempReg();
5297
5298         genHWIntrinsicSwitchTable(elementReg, tmpReg, elements, emitSwCase);
5299     }
5300
5301     genProduceReg(node);
5302 }
5303
5304 //------------------------------------------------------------------------
5305 // genHWIntrinsicSimdInsertOp:
5306 //
5307 // Produce code for a GT_HWIntrinsic node with form SimdInsertOp.
5308 //
5309 // Consumes one SIMD operand and two scalars
5310 //
5311 // The element index operand is typically a const immediate
5312 // When it is not, a switch table is generated
5313 //
5314 // See genHWIntrinsicSwitchTable comments
5315 //
5316 // Arguments:
5317 //    node - the GT_HWIntrinsic node
5318 //
5319 // Return Value:
5320 //    None.
5321 //
5322 void CodeGen::genHWIntrinsicSimdInsertOp(GenTreeHWIntrinsic* node)
5323 {
5324     GenTreeArgList* argList   = node->gtGetOp1()->AsArgList();
5325     GenTree*        op1       = argList->Current();
5326     GenTree*        op2       = argList->Rest()->Current();
5327     GenTree*        op3       = argList->Rest()->Rest()->Current();
5328     var_types       simdType  = op1->TypeGet();
5329     var_types       baseType  = node->gtSIMDBaseType;
5330     regNumber       targetReg = node->gtRegNum;
5331
5332     assert(targetReg != REG_NA);
5333
5334     genConsumeRegs(op1);
5335     genConsumeRegs(op2);
5336     genConsumeRegs(op3);
5337
5338     regNumber op1Reg = op1->gtRegNum;
5339
5340     assert(genIsValidFloatReg(targetReg));
5341     assert(genIsValidFloatReg(op1Reg));
5342
5343     emitAttr baseTypeSize = emitTypeSize(baseType);
5344
5345     int elements = emitTypeSize(simdType) / baseTypeSize;
5346
5347     if (targetReg != op1Reg)
5348     {
5349         bool     is16Byte = (node->gtSIMDSize > 8);
5350         emitAttr attr     = is16Byte ? EA_16BYTE : EA_8BYTE;
5351         getEmitter()->emitIns_R_R(INS_mov, baseTypeSize, targetReg, op1Reg);
5352     }
5353
5354     if (op3->isContained())
5355     {
5356         // Handle vector element to vector element case
5357         //
5358         // If op3 is contained this is because lowering found an opportunity to contain a Simd.Extract in a Simd.Insert
5359         //
5360         regNumber op3Reg = op3->gtGetOp1()->gtRegNum;
5361
5362         assert(genIsValidFloatReg(op3Reg));
5363
5364         // op3 containment currently only occurs when
5365         //   + op3 is a Simd.Extract() (gtHWIntrinsicId == NI_ARM64_SIMD_GetItem)
5366         //   + element & srcLane are immediate constants
5367         assert(op2->isContainedIntOrIImmed());
5368         assert(op3->OperIs(GT_HWIntrinsic));
5369         assert(op3->AsHWIntrinsic()->gtHWIntrinsicId == NI_ARM64_SIMD_GetItem);
5370         assert(op3->gtGetOp2()->isContainedIntOrIImmed());
5371
5372         int element = (int)op2->AsIntConCommon()->IconValue();
5373         int srcLane = (int)op3->gtGetOp2()->AsIntConCommon()->IconValue();
5374
5375         // Emit mov targetReg[element], op3Reg[srcLane]
5376         getEmitter()->emitIns_R_R_I_I(INS_mov, baseTypeSize, targetReg, op3Reg, element, srcLane);
5377     }
5378     else
5379     {
5380         // Handle scalar to vector element case
5381         // TODO-ARM64-CQ handle containing op3 scalar const where possible
5382         regNumber op3Reg = op3->gtRegNum;
5383
5384         auto emitSwCase = [&](int element) {
5385             assert(element >= 0);
5386             assert(element < elements);
5387
5388             if (varTypeIsFloating(baseType))
5389             {
5390                 assert(genIsValidFloatReg(op3Reg));
5391                 getEmitter()->emitIns_R_R_I_I(INS_mov, baseTypeSize, targetReg, op3Reg, element, 0);
5392             }
5393             else
5394             {
5395                 assert(genIsValidIntReg(op3Reg));
5396                 getEmitter()->emitIns_R_R_I(INS_mov, baseTypeSize, targetReg, op3Reg, element);
5397             }
5398         };
5399
5400         if (op2->isContainedIntOrIImmed())
5401         {
5402             int element = (int)op2->AsIntConCommon()->IconValue();
5403
5404             emitSwCase(element);
5405         }
5406         else
5407         {
5408             regNumber elementReg = op2->gtRegNum;
5409             regNumber tmpReg     = node->GetSingleTempReg();
5410
5411             genHWIntrinsicSwitchTable(elementReg, tmpReg, elements, emitSwCase);
5412         }
5413     }
5414
5415     genProduceReg(node);
5416 }
5417
5418 //------------------------------------------------------------------------
5419 // genHWIntrinsicSimdSelectOp:
5420 //
5421 // Produce code for a GT_HWIntrinsic node with form SimdSelectOp.
5422 //
5423 // Consumes three SIMD operands and produces a SIMD result
5424 //
5425 // This intrinsic form requires one of the source registers to be the
5426 // destination register.  Inserts a INS_mov if this requirement is not met.
5427 //
5428 // Arguments:
5429 //    node - the GT_HWIntrinsic node
5430 //
5431 // Return Value:
5432 //    None.
5433 //
5434 void CodeGen::genHWIntrinsicSimdSelectOp(GenTreeHWIntrinsic* node)
5435 {
5436     GenTreeArgList* argList   = node->gtGetOp1()->AsArgList();
5437     GenTree*        op1       = argList->Current();
5438     GenTree*        op2       = argList->Rest()->Current();
5439     GenTree*        op3       = argList->Rest()->Rest()->Current();
5440     var_types       baseType  = node->gtSIMDBaseType;
5441     regNumber       targetReg = node->gtRegNum;
5442
5443     assert(targetReg != REG_NA);
5444     var_types targetType = node->TypeGet();
5445
5446     genConsumeRegs(op1);
5447     genConsumeRegs(op2);
5448     genConsumeRegs(op3);
5449
5450     regNumber op1Reg = op1->gtRegNum;
5451     regNumber op2Reg = op2->gtRegNum;
5452     regNumber op3Reg = op3->gtRegNum;
5453
5454     assert(genIsValidFloatReg(op1Reg));
5455     assert(genIsValidFloatReg(op2Reg));
5456     assert(genIsValidFloatReg(op3Reg));
5457     assert(genIsValidFloatReg(targetReg));
5458
5459     bool     is16Byte = (node->gtSIMDSize > 8);
5460     emitAttr attr     = is16Byte ? EA_16BYTE : EA_8BYTE;
5461
5462     // Arm64 has three bit select forms; each uses three source registers
5463     // One of the sources is also the destination
5464     if (targetReg == op3Reg)
5465     {
5466         // op3 is target use bit insert if true
5467         // op3 = op3 ^ (op1 & (op2 ^ op3))
5468         getEmitter()->emitIns_R_R_R(INS_bit, attr, op3Reg, op2Reg, op1Reg);
5469     }
5470     else if (targetReg == op2Reg)
5471     {
5472         // op2 is target use bit insert if false
5473         // op2 = op2 ^ (~op1 & (op2 ^ op3))
5474         getEmitter()->emitIns_R_R_R(INS_bif, attr, op2Reg, op3Reg, op1Reg);
5475     }
5476     else
5477     {
5478         if (targetReg != op1Reg)
5479         {
5480             // target is not one of the sources, copy op1 to use bit select form
5481             getEmitter()->emitIns_R_R(INS_mov, attr, targetReg, op1Reg);
5482         }
5483         // use bit select
5484         // targetReg = op3 ^ (targetReg & (op2 ^ op3))
5485         getEmitter()->emitIns_R_R_R(INS_bsl, attr, targetReg, op2Reg, op3Reg);
5486     }
5487
5488     genProduceReg(node);
5489 }
5490
5491 //------------------------------------------------------------------------
5492 // genHWIntrinsicSimdSetAllOp:
5493 //
5494 // Produce code for a GT_HWIntrinsic node with form SimdSetAllOp.
5495 //
5496 // Consumes single scalar operand and produces a SIMD result
5497 //
5498 // Arguments:
5499 //    node - the GT_HWIntrinsic node
5500 //
5501 // Return Value:
5502 //    None.
5503 //
5504 void CodeGen::genHWIntrinsicSimdSetAllOp(GenTreeHWIntrinsic* node)
5505 {
5506     GenTree*  op1       = node->gtGetOp1();
5507     var_types baseType  = node->gtSIMDBaseType;
5508     regNumber targetReg = node->gtRegNum;
5509
5510     assert(targetReg != REG_NA);
5511     var_types targetType = node->TypeGet();
5512
5513     genConsumeOperands(node);
5514
5515     regNumber op1Reg = op1->gtRegNum;
5516
5517     assert(genIsValidFloatReg(targetReg));
5518     assert(genIsValidIntReg(op1Reg) || genIsValidFloatReg(op1Reg));
5519
5520     instruction ins = getOpForHWIntrinsic(node, baseType);
5521     assert(ins != INS_invalid);
5522
5523     bool     is16Byte = (node->gtSIMDSize > 8);
5524     emitAttr attr     = is16Byte ? EA_16BYTE : EA_8BYTE;
5525     insOpts  opt      = genGetSimdInsOpt(is16Byte, baseType);
5526
5527     // TODO-ARM64-CQ Support contained immediate cases
5528
5529     if (genIsValidIntReg(op1Reg))
5530     {
5531         getEmitter()->emitIns_R_R(ins, attr, targetReg, op1Reg, opt);
5532     }
5533     else
5534     {
5535         getEmitter()->emitIns_R_R_I(ins, attr, targetReg, op1Reg, 0, opt);
5536     }
5537
5538     genProduceReg(node);
5539 }
5540
5541 //------------------------------------------------------------------------
5542 // genHWIntrinsicSimdUnaryOp:
5543 //
5544 // Produce code for a GT_HWIntrinsic node with form SimdUnaryOp.
5545 //
5546 // Consumes single SIMD operand and produces a SIMD result
5547 //
5548 // Arguments:
5549 //    node - the GT_HWIntrinsic node
5550 //
5551 // Return Value:
5552 //    None.
5553 //
5554 void CodeGen::genHWIntrinsicSimdUnaryOp(GenTreeHWIntrinsic* node)
5555 {
5556     GenTree*  op1       = node->gtGetOp1();
5557     var_types baseType  = node->gtSIMDBaseType;
5558     regNumber targetReg = node->gtRegNum;
5559
5560     assert(targetReg != REG_NA);
5561     var_types targetType = node->TypeGet();
5562
5563     genConsumeOperands(node);
5564
5565     regNumber op1Reg = op1->gtRegNum;
5566
5567     assert(genIsValidFloatReg(op1Reg));
5568     assert(genIsValidFloatReg(targetReg));
5569
5570     instruction ins = getOpForHWIntrinsic(node, baseType);
5571     assert(ins != INS_invalid);
5572
5573     bool     is16Byte = (node->gtSIMDSize > 8);
5574     emitAttr attr     = is16Byte ? EA_16BYTE : EA_8BYTE;
5575     insOpts  opt      = genGetSimdInsOpt(is16Byte, baseType);
5576
5577     getEmitter()->emitIns_R_R(ins, attr, targetReg, op1Reg, opt);
5578
5579     genProduceReg(node);
5580 }
5581
5582 #endif // FEATURE_HW_INTRINSICS
5583
5584 /*****************************************************************************
5585  * Unit testing of the ARM64 emitter: generate a bunch of instructions into the prolog
5586  * (it's as good a place as any), then use COMPlus_JitLateDisasm=* to see if the late
5587  * disassembler thinks the instructions as the same as we do.
5588  */
5589
5590 // Uncomment "#define ALL_ARM64_EMITTER_UNIT_TESTS" to run all the unit tests here.
5591 // After adding a unit test, and verifying it works, put it under this #ifdef, so we don't see it run every time.
5592 //#define ALL_ARM64_EMITTER_UNIT_TESTS
5593
5594 #if defined(DEBUG)
5595 void CodeGen::genArm64EmitterUnitTests()
5596 {
5597     if (!verbose)
5598     {
5599         return;
5600     }
5601
5602     if (!compiler->opts.altJit)
5603     {
5604         // No point doing this in a "real" JIT.
5605         return;
5606     }
5607
5608     // Mark the "fake" instructions in the output.
5609     printf("*************** In genArm64EmitterUnitTests()\n");
5610
5611     emitter* theEmitter = getEmitter();
5612
5613 #ifdef ALL_ARM64_EMITTER_UNIT_TESTS
5614     // We use this:
5615     //      genDefineTempLabel(genCreateTempLabel());
5616     // to create artificial labels to help separate groups of tests.
5617
5618     //
5619     // Loads/Stores basic general register
5620     //
5621
5622     genDefineTempLabel(genCreateTempLabel());
5623
5624     // ldr/str Xt, [reg]
5625     theEmitter->emitIns_R_R(INS_ldr, EA_8BYTE, REG_R8, REG_R9);
5626     theEmitter->emitIns_R_R(INS_ldrb, EA_1BYTE, REG_R8, REG_R9);
5627     theEmitter->emitIns_R_R(INS_ldrh, EA_2BYTE, REG_R8, REG_R9);
5628     theEmitter->emitIns_R_R(INS_str, EA_8BYTE, REG_R8, REG_R9);
5629     theEmitter->emitIns_R_R(INS_strb, EA_1BYTE, REG_R8, REG_R9);
5630     theEmitter->emitIns_R_R(INS_strh, EA_2BYTE, REG_R8, REG_R9);
5631
5632     // ldr/str Wt, [reg]
5633     theEmitter->emitIns_R_R(INS_ldr, EA_4BYTE, REG_R8, REG_R9);
5634     theEmitter->emitIns_R_R(INS_ldrb, EA_1BYTE, REG_R8, REG_R9);
5635     theEmitter->emitIns_R_R(INS_ldrh, EA_2BYTE, REG_R8, REG_R9);
5636     theEmitter->emitIns_R_R(INS_str, EA_4BYTE, REG_R8, REG_R9);
5637     theEmitter->emitIns_R_R(INS_strb, EA_1BYTE, REG_R8, REG_R9);
5638     theEmitter->emitIns_R_R(INS_strh, EA_2BYTE, REG_R8, REG_R9);
5639
5640     theEmitter->emitIns_R_R(INS_ldrsb, EA_4BYTE, REG_R8, REG_R9); // target Wt
5641     theEmitter->emitIns_R_R(INS_ldrsh, EA_4BYTE, REG_R8, REG_R9); // target Wt
5642     theEmitter->emitIns_R_R(INS_ldrsb, EA_8BYTE, REG_R8, REG_R9); // target Xt
5643     theEmitter->emitIns_R_R(INS_ldrsh, EA_8BYTE, REG_R8, REG_R9); // target Xt
5644     theEmitter->emitIns_R_R(INS_ldrsw, EA_8BYTE, REG_R8, REG_R9); // target Xt
5645
5646     theEmitter->emitIns_R_R_I(INS_ldurb, EA_4BYTE, REG_R8, REG_R9, 1);
5647     theEmitter->emitIns_R_R_I(INS_ldurh, EA_4BYTE, REG_R8, REG_R9, 1);
5648     theEmitter->emitIns_R_R_I(INS_sturb, EA_4BYTE, REG_R8, REG_R9, 1);
5649     theEmitter->emitIns_R_R_I(INS_sturh, EA_4BYTE, REG_R8, REG_R9, 1);
5650     theEmitter->emitIns_R_R_I(INS_ldursb, EA_4BYTE, REG_R8, REG_R9, 1);
5651     theEmitter->emitIns_R_R_I(INS_ldursb, EA_8BYTE, REG_R8, REG_R9, 1);
5652     theEmitter->emitIns_R_R_I(INS_ldursh, EA_4BYTE, REG_R8, REG_R9, 1);
5653     theEmitter->emitIns_R_R_I(INS_ldursh, EA_8BYTE, REG_R8, REG_R9, 1);
5654     theEmitter->emitIns_R_R_I(INS_ldur, EA_8BYTE, REG_R8, REG_R9, 1);
5655     theEmitter->emitIns_R_R_I(INS_ldur, EA_4BYTE, REG_R8, REG_R9, 1);
5656     theEmitter->emitIns_R_R_I(INS_stur, EA_4BYTE, REG_R8, REG_R9, 1);
5657     theEmitter->emitIns_R_R_I(INS_stur, EA_8BYTE, REG_R8, REG_R9, 1);
5658     theEmitter->emitIns_R_R_I(INS_ldursw, EA_8BYTE, REG_R8, REG_R9, 1);
5659
5660     // SP and ZR tests
5661     theEmitter->emitIns_R_R_I(INS_ldur, EA_8BYTE, REG_R8, REG_SP, 1);
5662     theEmitter->emitIns_R_R_I(INS_ldurb, EA_8BYTE, REG_ZR, REG_R9, 1);
5663     theEmitter->emitIns_R_R_I(INS_ldurh, EA_8BYTE, REG_ZR, REG_SP, 1);
5664
5665     // scaled
5666     theEmitter->emitIns_R_R_I(INS_ldrb, EA_1BYTE, REG_R8, REG_R9, 1);
5667     theEmitter->emitIns_R_R_I(INS_ldrh, EA_2BYTE, REG_R8, REG_R9, 2);
5668     theEmitter->emitIns_R_R_I(INS_ldr, EA_4BYTE, REG_R8, REG_R9, 4);
5669     theEmitter->emitIns_R_R_I(INS_ldr, EA_8BYTE, REG_R8, REG_R9, 8);
5670
5671     // pre-/post-indexed (unscaled)
5672     theEmitter->emitIns_R_R_I(INS_ldr, EA_4BYTE, REG_R8, REG_R9, 1, INS_OPTS_POST_INDEX);
5673     theEmitter->emitIns_R_R_I(INS_ldr, EA_4BYTE, REG_R8, REG_R9, 1, INS_OPTS_PRE_INDEX);
5674     theEmitter->emitIns_R_R_I(INS_ldr, EA_8BYTE, REG_R8, REG_R9, 1, INS_OPTS_POST_INDEX);
5675     theEmitter->emitIns_R_R_I(INS_ldr, EA_8BYTE, REG_R8, REG_R9, 1, INS_OPTS_PRE_INDEX);
5676
5677     // ldar/stlr Rt, [reg]
5678     theEmitter->emitIns_R_R(INS_ldar, EA_8BYTE, REG_R9, REG_R8);
5679     theEmitter->emitIns_R_R(INS_ldar, EA_4BYTE, REG_R7, REG_R10);
5680     theEmitter->emitIns_R_R(INS_ldarb, EA_4BYTE, REG_R5, REG_R11);
5681     theEmitter->emitIns_R_R(INS_ldarh, EA_4BYTE, REG_R5, REG_R12);
5682
5683     theEmitter->emitIns_R_R(INS_stlr, EA_8BYTE, REG_R9, REG_R8);
5684     theEmitter->emitIns_R_R(INS_stlr, EA_4BYTE, REG_R7, REG_R13);
5685     theEmitter->emitIns_R_R(INS_stlrb, EA_4BYTE, REG_R5, REG_R14);
5686     theEmitter->emitIns_R_R(INS_stlrh, EA_4BYTE, REG_R3, REG_R15);
5687
5688     // ldaxr Rt, [reg]
5689     theEmitter->emitIns_R_R(INS_ldaxr, EA_8BYTE, REG_R9, REG_R8);
5690     theEmitter->emitIns_R_R(INS_ldaxr, EA_4BYTE, REG_R7, REG_R10);
5691     theEmitter->emitIns_R_R(INS_ldaxrb, EA_4BYTE, REG_R5, REG_R11);
5692     theEmitter->emitIns_R_R(INS_ldaxrh, EA_4BYTE, REG_R5, REG_R12);
5693
5694     // ldxr Rt, [reg]
5695     theEmitter->emitIns_R_R(INS_ldxr, EA_8BYTE, REG_R9, REG_R8);
5696     theEmitter->emitIns_R_R(INS_ldxr, EA_4BYTE, REG_R7, REG_R10);
5697     theEmitter->emitIns_R_R(INS_ldxrb, EA_4BYTE, REG_R5, REG_R11);
5698     theEmitter->emitIns_R_R(INS_ldxrh, EA_4BYTE, REG_R5, REG_R12);
5699
5700     // stxr Ws, Rt, [reg]
5701     theEmitter->emitIns_R_R_R(INS_stxr, EA_8BYTE, REG_R1, REG_R9, REG_R8);
5702     theEmitter->emitIns_R_R_R(INS_stxr, EA_4BYTE, REG_R3, REG_R7, REG_R13);
5703     theEmitter->emitIns_R_R_R(INS_stxrb, EA_4BYTE, REG_R8, REG_R5, REG_R14);
5704     theEmitter->emitIns_R_R_R(INS_stxrh, EA_4BYTE, REG_R12, REG_R3, REG_R15);
5705
5706     // stlxr Ws, Rt, [reg]
5707     theEmitter->emitIns_R_R_R(INS_stlxr, EA_8BYTE, REG_R1, REG_R9, REG_R8);
5708     theEmitter->emitIns_R_R_R(INS_stlxr, EA_4BYTE, REG_R3, REG_R7, REG_R13);
5709     theEmitter->emitIns_R_R_R(INS_stlxrb, EA_4BYTE, REG_R8, REG_R5, REG_R14);
5710     theEmitter->emitIns_R_R_R(INS_stlxrh, EA_4BYTE, REG_R12, REG_R3, REG_R15);
5711
5712 #endif // ALL_ARM64_EMITTER_UNIT_TESTS
5713
5714 #ifdef ALL_ARM64_EMITTER_UNIT_TESTS
5715     //
5716     // Compares
5717     //
5718
5719     genDefineTempLabel(genCreateTempLabel());
5720
5721     // cmp reg, reg
5722     theEmitter->emitIns_R_R(INS_cmp, EA_8BYTE, REG_R8, REG_R9);
5723     theEmitter->emitIns_R_R(INS_cmn, EA_8BYTE, REG_R8, REG_R9);
5724
5725     // cmp reg, imm
5726     theEmitter->emitIns_R_I(INS_cmp, EA_8BYTE, REG_R8, 0);
5727     theEmitter->emitIns_R_I(INS_cmp, EA_8BYTE, REG_R8, 4095);
5728     theEmitter->emitIns_R_I(INS_cmp, EA_8BYTE, REG_R8, 1 << 12);
5729     theEmitter->emitIns_R_I(INS_cmp, EA_8BYTE, REG_R8, 4095 << 12);
5730
5731     theEmitter->emitIns_R_I(INS_cmn, EA_8BYTE, REG_R8, 0);
5732     theEmitter->emitIns_R_I(INS_cmn, EA_8BYTE, REG_R8, 4095);
5733     theEmitter->emitIns_R_I(INS_cmn, EA_8BYTE, REG_R8, 1 << 12);
5734     theEmitter->emitIns_R_I(INS_cmn, EA_8BYTE, REG_R8, 4095 << 12);
5735
5736     theEmitter->emitIns_R_I(INS_cmp, EA_8BYTE, REG_R8, -1);
5737     theEmitter->emitIns_R_I(INS_cmp, EA_8BYTE, REG_R8, -0xfff);
5738     theEmitter->emitIns_R_I(INS_cmp, EA_8BYTE, REG_R8, 0xfffffffffffff000LL);
5739     theEmitter->emitIns_R_I(INS_cmp, EA_8BYTE, REG_R8, 0xffffffffff800000LL);
5740
5741     theEmitter->emitIns_R_I(INS_cmn, EA_8BYTE, REG_R8, -1);
5742     theEmitter->emitIns_R_I(INS_cmn, EA_8BYTE, REG_R8, -0xfff);
5743     theEmitter->emitIns_R_I(INS_cmn, EA_8BYTE, REG_R8, 0xfffffffffffff000LL);
5744     theEmitter->emitIns_R_I(INS_cmn, EA_8BYTE, REG_R8, 0xffffffffff800000LL);
5745
5746 #endif // ALL_ARM64_EMITTER_UNIT_TESTS
5747
5748 #ifdef ALL_ARM64_EMITTER_UNIT_TESTS
5749     // R_R
5750     //
5751
5752     genDefineTempLabel(genCreateTempLabel());
5753
5754     theEmitter->emitIns_R_R(INS_cls, EA_8BYTE, REG_R1, REG_R12);
5755     theEmitter->emitIns_R_R(INS_clz, EA_8BYTE, REG_R2, REG_R13);
5756     theEmitter->emitIns_R_R(INS_rbit, EA_8BYTE, REG_R3, REG_R14);
5757     theEmitter->emitIns_R_R(INS_rev, EA_8BYTE, REG_R4, REG_R15);
5758     theEmitter->emitIns_R_R(INS_rev16, EA_8BYTE, REG_R5, REG_R0);
5759     theEmitter->emitIns_R_R(INS_rev32, EA_8BYTE, REG_R6, REG_R1);
5760
5761     theEmitter->emitIns_R_R(INS_cls, EA_4BYTE, REG_R7, REG_R2);
5762     theEmitter->emitIns_R_R(INS_clz, EA_4BYTE, REG_R8, REG_R3);
5763     theEmitter->emitIns_R_R(INS_rbit, EA_4BYTE, REG_R9, REG_R4);
5764     theEmitter->emitIns_R_R(INS_rev, EA_4BYTE, REG_R10, REG_R5);
5765     theEmitter->emitIns_R_R(INS_rev16, EA_4BYTE, REG_R11, REG_R6);
5766
5767 #endif // ALL_ARM64_EMITTER_UNIT_TESTS
5768
5769 #ifdef ALL_ARM64_EMITTER_UNIT_TESTS
5770     //
5771     // R_I
5772     //
5773
5774     genDefineTempLabel(genCreateTempLabel());
5775
5776     // mov reg, imm(i16,hw)
5777     theEmitter->emitIns_R_I(INS_mov, EA_8BYTE, REG_R8, 0x0000000000001234);
5778     theEmitter->emitIns_R_I(INS_mov, EA_8BYTE, REG_R8, 0x0000000043210000);
5779     theEmitter->emitIns_R_I(INS_mov, EA_8BYTE, REG_R8, 0x0000567800000000);
5780     theEmitter->emitIns_R_I(INS_mov, EA_8BYTE, REG_R8, 0x8765000000000000);
5781     theEmitter->emitIns_R_I(INS_mov, EA_8BYTE, REG_R8, 0xFFFFFFFFFFFF1234);
5782     theEmitter->emitIns_R_I(INS_mov, EA_8BYTE, REG_R8, 0xFFFFFFFF4321FFFF);
5783     theEmitter->emitIns_R_I(INS_mov, EA_8BYTE, REG_R8, 0xFFFF5678FFFFFFFF);
5784     theEmitter->emitIns_R_I(INS_mov, EA_8BYTE, REG_R8, 0x8765FFFFFFFFFFFF);
5785
5786     theEmitter->emitIns_R_I(INS_mov, EA_4BYTE, REG_R8, 0x00001234);
5787     theEmitter->emitIns_R_I(INS_mov, EA_4BYTE, REG_R8, 0x87650000);
5788     theEmitter->emitIns_R_I(INS_mov, EA_4BYTE, REG_R8, 0xFFFF1234);
5789     theEmitter->emitIns_R_I(INS_mov, EA_4BYTE, REG_R8, 0x4567FFFF);
5790
5791     // mov reg, imm(N,r,s)
5792     theEmitter->emitIns_R_I(INS_mov, EA_8BYTE, REG_R8, 0x00FFFFF000000000);
5793     theEmitter->emitIns_R_I(INS_mov, EA_8BYTE, REG_R8, 0x6666666666666666);
5794     theEmitter->emitIns_R_I(INS_mov, EA_8BYTE, REG_SP, 0x7FFF00007FFF0000);
5795     theEmitter->emitIns_R_I(INS_mov, EA_8BYTE, REG_R8, 0x5555555555555555);
5796     theEmitter->emitIns_R_I(INS_mov, EA_8BYTE, REG_R8, 0xE003E003E003E003);
5797     theEmitter->emitIns_R_I(INS_mov, EA_8BYTE, REG_R8, 0x0707070707070707);
5798
5799     theEmitter->emitIns_R_I(INS_mov, EA_4BYTE, REG_R8, 0x00FFFFF0);
5800     theEmitter->emitIns_R_I(INS_mov, EA_4BYTE, REG_R8, 0x66666666);
5801     theEmitter->emitIns_R_I(INS_mov, EA_4BYTE, REG_R8, 0x03FFC000);
5802     theEmitter->emitIns_R_I(INS_mov, EA_4BYTE, REG_R8, 0x55555555);
5803     theEmitter->emitIns_R_I(INS_mov, EA_4BYTE, REG_R8, 0xE003E003);
5804     theEmitter->emitIns_R_I(INS_mov, EA_4BYTE, REG_R8, 0x07070707);
5805
5806     theEmitter->emitIns_R_I(INS_tst, EA_8BYTE, REG_R8, 0xE003E003E003E003);
5807     theEmitter->emitIns_R_I(INS_tst, EA_8BYTE, REG_R8, 0x00FFFFF000000000);
5808     theEmitter->emitIns_R_I(INS_tst, EA_8BYTE, REG_R8, 0x6666666666666666);
5809     theEmitter->emitIns_R_I(INS_tst, EA_8BYTE, REG_R8, 0x0707070707070707);
5810     theEmitter->emitIns_R_I(INS_tst, EA_8BYTE, REG_R8, 0x7FFF00007FFF0000);
5811     theEmitter->emitIns_R_I(INS_tst, EA_8BYTE, REG_R8, 0x5555555555555555);
5812
5813     theEmitter->emitIns_R_I(INS_tst, EA_4BYTE, REG_R8, 0xE003E003);
5814     theEmitter->emitIns_R_I(INS_tst, EA_4BYTE, REG_R8, 0x00FFFFF0);
5815     theEmitter->emitIns_R_I(INS_tst, EA_4BYTE, REG_R8, 0x66666666);
5816     theEmitter->emitIns_R_I(INS_tst, EA_4BYTE, REG_R8, 0x07070707);
5817     theEmitter->emitIns_R_I(INS_tst, EA_4BYTE, REG_R8, 0xFFF00000);
5818     theEmitter->emitIns_R_I(INS_tst, EA_4BYTE, REG_R8, 0x55555555);
5819
5820 #endif // ALL_ARM64_EMITTER_UNIT_TESTS
5821
5822 #ifdef ALL_ARM64_EMITTER_UNIT_TESTS
5823     //
5824     // R_R
5825     //
5826
5827     genDefineTempLabel(genCreateTempLabel());
5828
5829     // tst reg, reg
5830     theEmitter->emitIns_R_R(INS_tst, EA_8BYTE, REG_R7, REG_R10);
5831
5832     // mov reg, reg
5833     theEmitter->emitIns_R_R(INS_mov, EA_8BYTE, REG_R7, REG_R10);
5834     theEmitter->emitIns_R_R(INS_mov, EA_8BYTE, REG_R8, REG_SP);
5835     theEmitter->emitIns_R_R(INS_mov, EA_8BYTE, REG_SP, REG_R9);
5836
5837     theEmitter->emitIns_R_R(INS_mvn, EA_8BYTE, REG_R5, REG_R11);
5838     theEmitter->emitIns_R_R(INS_neg, EA_8BYTE, REG_R4, REG_R12);
5839     theEmitter->emitIns_R_R(INS_negs, EA_8BYTE, REG_R3, REG_R13);
5840
5841     theEmitter->emitIns_R_R(INS_mov, EA_4BYTE, REG_R7, REG_R10);
5842     theEmitter->emitIns_R_R(INS_mvn, EA_4BYTE, REG_R5, REG_R11);
5843     theEmitter->emitIns_R_R(INS_neg, EA_4BYTE, REG_R4, REG_R12);
5844     theEmitter->emitIns_R_R(INS_negs, EA_4BYTE, REG_R3, REG_R13);
5845
5846     theEmitter->emitIns_R_R(INS_sxtb, EA_8BYTE, REG_R7, REG_R10);
5847     theEmitter->emitIns_R_R(INS_sxth, EA_8BYTE, REG_R5, REG_R11);
5848     theEmitter->emitIns_R_R(INS_sxtw, EA_8BYTE, REG_R4, REG_R12);
5849     theEmitter->emitIns_R_R(INS_uxtb, EA_8BYTE, REG_R3, REG_R13); // map to Wt
5850     theEmitter->emitIns_R_R(INS_uxth, EA_8BYTE, REG_R2, REG_R14); // map to Wt
5851
5852     theEmitter->emitIns_R_R(INS_sxtb, EA_4BYTE, REG_R7, REG_R10);
5853     theEmitter->emitIns_R_R(INS_sxth, EA_4BYTE, REG_R5, REG_R11);
5854     theEmitter->emitIns_R_R(INS_uxtb, EA_4BYTE, REG_R3, REG_R13);
5855     theEmitter->emitIns_R_R(INS_uxth, EA_4BYTE, REG_R2, REG_R14);
5856
5857 #endif // ALL_ARM64_EMITTER_UNIT_TESTS
5858
5859 #ifdef ALL_ARM64_EMITTER_UNIT_TESTS
5860     //
5861     // R_I_I
5862     //
5863
5864     genDefineTempLabel(genCreateTempLabel());
5865
5866     // mov reg, imm(i16,hw)
5867     theEmitter->emitIns_R_I_I(INS_mov, EA_8BYTE, REG_R8, 0x1234, 0, INS_OPTS_LSL);
5868     theEmitter->emitIns_R_I_I(INS_mov, EA_8BYTE, REG_R8, 0x4321, 16, INS_OPTS_LSL);
5869
5870     theEmitter->emitIns_R_I_I(INS_movk, EA_8BYTE, REG_R8, 0x4321, 16, INS_OPTS_LSL);
5871     theEmitter->emitIns_R_I_I(INS_movn, EA_8BYTE, REG_R8, 0x5678, 32, INS_OPTS_LSL);
5872     theEmitter->emitIns_R_I_I(INS_movz, EA_8BYTE, REG_R8, 0x8765, 48, INS_OPTS_LSL);
5873
5874     theEmitter->emitIns_R_I_I(INS_movk, EA_4BYTE, REG_R8, 0x4321, 16, INS_OPTS_LSL);
5875     theEmitter->emitIns_R_I_I(INS_movn, EA_4BYTE, REG_R8, 0x5678, 16, INS_OPTS_LSL);
5876     theEmitter->emitIns_R_I_I(INS_movz, EA_4BYTE, REG_R8, 0x8765, 16, INS_OPTS_LSL);
5877
5878 #endif // ALL_ARM64_EMITTER_UNIT_TESTS
5879
5880 #ifdef ALL_ARM64_EMITTER_UNIT_TESTS
5881     //
5882     // R_R_I
5883     //
5884
5885     genDefineTempLabel(genCreateTempLabel());
5886
5887     theEmitter->emitIns_R_R_I(INS_lsl, EA_8BYTE, REG_R0, REG_R0, 1);
5888     theEmitter->emitIns_R_R_I(INS_lsl, EA_4BYTE, REG_R9, REG_R3, 18);
5889     theEmitter->emitIns_R_R_I(INS_lsr, EA_8BYTE, REG_R7, REG_R0, 37);
5890     theEmitter->emitIns_R_R_I(INS_lsr, EA_4BYTE, REG_R0, REG_R1, 2);
5891     theEmitter->emitIns_R_R_I(INS_asr, EA_8BYTE, REG_R2, REG_R3, 53);
5892     theEmitter->emitIns_R_R_I(INS_asr, EA_4BYTE, REG_R9, REG_R3, 18);
5893
5894     theEmitter->emitIns_R_R_I(INS_and, EA_8BYTE, REG_R2, REG_R3, 0x5555555555555555);
5895     theEmitter->emitIns_R_R_I(INS_ands, EA_8BYTE, REG_R1, REG_R5, 0x6666666666666666);
5896     theEmitter->emitIns_R_R_I(INS_eor, EA_8BYTE, REG_R8, REG_R9, 0x0707070707070707);
5897     theEmitter->emitIns_R_R_I(INS_orr, EA_8BYTE, REG_SP, REG_R3, 0xFFFC000000000000);
5898     theEmitter->emitIns_R_R_I(INS_ands, EA_4BYTE, REG_R8, REG_R9, 0xE003E003);
5899
5900     theEmitter->emitIns_R_R_I(INS_ror, EA_8BYTE, REG_R8, REG_R9, 1);
5901     theEmitter->emitIns_R_R_I(INS_ror, EA_8BYTE, REG_R8, REG_R9, 31);
5902     theEmitter->emitIns_R_R_I(INS_ror, EA_8BYTE, REG_R8, REG_R9, 32);
5903     theEmitter->emitIns_R_R_I(INS_ror, EA_8BYTE, REG_R8, REG_R9, 63);
5904
5905     theEmitter->emitIns_R_R_I(INS_ror, EA_4BYTE, REG_R8, REG_R9, 1);
5906     theEmitter->emitIns_R_R_I(INS_ror, EA_4BYTE, REG_R8, REG_R9, 31);
5907
5908     theEmitter->emitIns_R_R_I(INS_add, EA_8BYTE, REG_R8, REG_R9, 0); // == mov
5909     theEmitter->emitIns_R_R_I(INS_add, EA_8BYTE, REG_R8, REG_R9, 1);
5910     theEmitter->emitIns_R_R_I(INS_add, EA_8BYTE, REG_R8, REG_R9, -1);
5911     theEmitter->emitIns_R_R_I(INS_add, EA_8BYTE, REG_R8, REG_R9, 0xfff);
5912     theEmitter->emitIns_R_R_I(INS_add, EA_8BYTE, REG_R8, REG_R9, -0xfff);
5913     theEmitter->emitIns_R_R_I(INS_add, EA_8BYTE, REG_R8, REG_R9, 0x1000);
5914     theEmitter->emitIns_R_R_I(INS_add, EA_8BYTE, REG_R8, REG_R9, 0xfff000);
5915     theEmitter->emitIns_R_R_I(INS_add, EA_8BYTE, REG_R8, REG_R9, 0xfffffffffffff000LL);
5916     theEmitter->emitIns_R_R_I(INS_add, EA_8BYTE, REG_R8, REG_R9, 0xffffffffff800000LL);
5917
5918     theEmitter->emitIns_R_R_I(INS_add, EA_4BYTE, REG_R8, REG_R9, 0); // == mov
5919     theEmitter->emitIns_R_R_I(INS_add, EA_4BYTE, REG_R8, REG_R9, 1);
5920     theEmitter->emitIns_R_R_I(INS_add, EA_4BYTE, REG_R8, REG_R9, -1);
5921     theEmitter->emitIns_R_R_I(INS_add, EA_4BYTE, REG_R8, REG_R9, 0xfff);
5922     theEmitter->emitIns_R_R_I(INS_add, EA_4BYTE, REG_R8, REG_R9, -0xfff);
5923     theEmitter->emitIns_R_R_I(INS_add, EA_4BYTE, REG_R8, REG_R9, 0x1000);
5924     theEmitter->emitIns_R_R_I(INS_add, EA_4BYTE, REG_R8, REG_R9, 0xfff000);
5925     theEmitter->emitIns_R_R_I(INS_add, EA_4BYTE, REG_R8, REG_R9, 0xfffffffffffff000LL);
5926     theEmitter->emitIns_R_R_I(INS_add, EA_4BYTE, REG_R8, REG_R9, 0xffffffffff800000LL);
5927
5928     theEmitter->emitIns_R_R_I(INS_sub, EA_8BYTE, REG_R8, REG_R9, 0); // == mov
5929     theEmitter->emitIns_R_R_I(INS_sub, EA_8BYTE, REG_R8, REG_R9, 1);
5930     theEmitter->emitIns_R_R_I(INS_sub, EA_8BYTE, REG_R8, REG_R9, -1);
5931     theEmitter->emitIns_R_R_I(INS_sub, EA_8BYTE, REG_R8, REG_R9, 0xfff);
5932     theEmitter->emitIns_R_R_I(INS_sub, EA_8BYTE, REG_R8, REG_R9, -0xfff);
5933     theEmitter->emitIns_R_R_I(INS_sub, EA_8BYTE, REG_R8, REG_R9, 0x1000);
5934     theEmitter->emitIns_R_R_I(INS_sub, EA_8BYTE, REG_R8, REG_R9, 0xfff000);
5935     theEmitter->emitIns_R_R_I(INS_sub, EA_8BYTE, REG_R8, REG_R9, 0xfffffffffffff000LL);
5936     theEmitter->emitIns_R_R_I(INS_sub, EA_8BYTE, REG_R8, REG_R9, 0xffffffffff800000LL);
5937
5938     theEmitter->emitIns_R_R_I(INS_sub, EA_4BYTE, REG_R8, REG_R9, 0); // == mov
5939     theEmitter->emitIns_R_R_I(INS_sub, EA_4BYTE, REG_R8, REG_R9, 1);
5940     theEmitter->emitIns_R_R_I(INS_sub, EA_4BYTE, REG_R8, REG_R9, -1);
5941     theEmitter->emitIns_R_R_I(INS_sub, EA_4BYTE, REG_R8, REG_R9, 0xfff);
5942     theEmitter->emitIns_R_R_I(INS_sub, EA_4BYTE, REG_R8, REG_R9, -0xfff);
5943     theEmitter->emitIns_R_R_I(INS_sub, EA_4BYTE, REG_R8, REG_R9, 0x1000);
5944     theEmitter->emitIns_R_R_I(INS_sub, EA_4BYTE, REG_R8, REG_R9, 0xfff000);
5945     theEmitter->emitIns_R_R_I(INS_sub, EA_4BYTE, REG_R8, REG_R9, 0xfffffffffffff000LL);
5946     theEmitter->emitIns_R_R_I(INS_sub, EA_4BYTE, REG_R8, REG_R9, 0xffffffffff800000LL);
5947
5948     theEmitter->emitIns_R_R_I(INS_adds, EA_8BYTE, REG_R8, REG_R9, 0); // == mov
5949     theEmitter->emitIns_R_R_I(INS_adds, EA_8BYTE, REG_R8, REG_R9, 1);
5950     theEmitter->emitIns_R_R_I(INS_adds, EA_8BYTE, REG_R8, REG_R9, -1);
5951     theEmitter->emitIns_R_R_I(INS_adds, EA_8BYTE, REG_R8, REG_R9, 0xfff);
5952     theEmitter->emitIns_R_R_I(INS_adds, EA_8BYTE, REG_R8, REG_R9, -0xfff);
5953     theEmitter->emitIns_R_R_I(INS_adds, EA_8BYTE, REG_R8, REG_R9, 0x1000);
5954     theEmitter->emitIns_R_R_I(INS_adds, EA_8BYTE, REG_R8, REG_R9, 0xfff000);
5955     theEmitter->emitIns_R_R_I(INS_adds, EA_8BYTE, REG_R8, REG_R9, 0xfffffffffffff000LL);
5956     theEmitter->emitIns_R_R_I(INS_adds, EA_8BYTE, REG_R8, REG_R9, 0xffffffffff800000LL);
5957
5958     theEmitter->emitIns_R_R_I(INS_adds, EA_4BYTE, REG_R8, REG_R9, 0); // == mov
5959     theEmitter->emitIns_R_R_I(INS_adds, EA_4BYTE, REG_R8, REG_R9, 1);
5960     theEmitter->emitIns_R_R_I(INS_adds, EA_4BYTE, REG_R8, REG_R9, -1);
5961     theEmitter->emitIns_R_R_I(INS_adds, EA_4BYTE, REG_R8, REG_R9, 0xfff);
5962     theEmitter->emitIns_R_R_I(INS_adds, EA_4BYTE, REG_R8, REG_R9, -0xfff);
5963     theEmitter->emitIns_R_R_I(INS_adds, EA_4BYTE, REG_R8, REG_R9, 0x1000);
5964     theEmitter->emitIns_R_R_I(INS_adds, EA_4BYTE, REG_R8, REG_R9, 0xfff000);
5965     theEmitter->emitIns_R_R_I(INS_adds, EA_4BYTE, REG_R8, REG_R9, 0xfffffffffffff000LL);
5966     theEmitter->emitIns_R_R_I(INS_adds, EA_4BYTE, REG_R8, REG_R9, 0xffffffffff800000LL);
5967
5968     theEmitter->emitIns_R_R_I(INS_subs, EA_8BYTE, REG_R8, REG_R9, 0); // == mov
5969     theEmitter->emitIns_R_R_I(INS_subs, EA_8BYTE, REG_R8, REG_R9, 1);
5970     theEmitter->emitIns_R_R_I(INS_subs, EA_8BYTE, REG_R8, REG_R9, -1);
5971     theEmitter->emitIns_R_R_I(INS_subs, EA_8BYTE, REG_R8, REG_R9, 0xfff);
5972     theEmitter->emitIns_R_R_I(INS_subs, EA_8BYTE, REG_R8, REG_R9, -0xfff);
5973     theEmitter->emitIns_R_R_I(INS_subs, EA_8BYTE, REG_R8, REG_R9, 0x1000);
5974     theEmitter->emitIns_R_R_I(INS_subs, EA_8BYTE, REG_R8, REG_R9, 0xfff000);
5975     theEmitter->emitIns_R_R_I(INS_subs, EA_8BYTE, REG_R8, REG_R9, 0xfffffffffffff000LL);
5976     theEmitter->emitIns_R_R_I(INS_subs, EA_8BYTE, REG_R8, REG_R9, 0xffffffffff800000LL);
5977
5978     theEmitter->emitIns_R_R_I(INS_subs, EA_4BYTE, REG_R8, REG_R9, 0); // == mov
5979     theEmitter->emitIns_R_R_I(INS_subs, EA_4BYTE, REG_R8, REG_R9, 1);
5980     theEmitter->emitIns_R_R_I(INS_subs, EA_4BYTE, REG_R8, REG_R9, -1);
5981     theEmitter->emitIns_R_R_I(INS_subs, EA_4BYTE, REG_R8, REG_R9, 0xfff);
5982     theEmitter->emitIns_R_R_I(INS_subs, EA_4BYTE, REG_R8, REG_R9, -0xfff);
5983     theEmitter->emitIns_R_R_I(INS_subs, EA_4BYTE, REG_R8, REG_R9, 0x1000);
5984     theEmitter->emitIns_R_R_I(INS_subs, EA_4BYTE, REG_R8, REG_R9, 0xfff000);
5985     theEmitter->emitIns_R_R_I(INS_subs, EA_4BYTE, REG_R8, REG_R9, 0xfffffffffffff000LL);
5986     theEmitter->emitIns_R_R_I(INS_subs, EA_4BYTE, REG_R8, REG_R9, 0xffffffffff800000LL);
5987
5988 #endif // ALL_ARM64_EMITTER_UNIT_TESTS
5989
5990 #ifdef ALL_ARM64_EMITTER_UNIT_TESTS
5991     //
5992     // R_R_I cmp/txt
5993     //
5994
5995     // cmp
5996     theEmitter->emitIns_R_R_I(INS_cmp, EA_8BYTE, REG_R8, REG_R9, 0);
5997     theEmitter->emitIns_R_R_I(INS_cmp, EA_4BYTE, REG_R8, REG_R9, 0);
5998
5999     // CMP (shifted register)
6000     theEmitter->emitIns_R_R_I(INS_cmp, EA_8BYTE, REG_R8, REG_R9, 31, INS_OPTS_LSL);
6001     theEmitter->emitIns_R_R_I(INS_cmp, EA_8BYTE, REG_R8, REG_R9, 32, INS_OPTS_LSR);
6002     theEmitter->emitIns_R_R_I(INS_cmp, EA_8BYTE, REG_R8, REG_R9, 33, INS_OPTS_ASR);
6003
6004     theEmitter->emitIns_R_R_I(INS_cmp, EA_4BYTE, REG_R8, REG_R9, 21, INS_OPTS_LSL);
6005     theEmitter->emitIns_R_R_I(INS_cmp, EA_4BYTE, REG_R8, REG_R9, 22, INS_OPTS_LSR);
6006     theEmitter->emitIns_R_R_I(INS_cmp, EA_4BYTE, REG_R8, REG_R9, 23, INS_OPTS_ASR);
6007
6008     // TST (shifted register)
6009     theEmitter->emitIns_R_R_I(INS_tst, EA_8BYTE, REG_R8, REG_R9, 31, INS_OPTS_LSL);
6010     theEmitter->emitIns_R_R_I(INS_tst, EA_8BYTE, REG_R8, REG_R9, 32, INS_OPTS_LSR);
6011     theEmitter->emitIns_R_R_I(INS_tst, EA_8BYTE, REG_R8, REG_R9, 33, INS_OPTS_ASR);
6012     theEmitter->emitIns_R_R_I(INS_tst, EA_8BYTE, REG_R8, REG_R9, 34, INS_OPTS_ROR);
6013
6014     theEmitter->emitIns_R_R_I(INS_tst, EA_4BYTE, REG_R8, REG_R9, 21, INS_OPTS_LSL);
6015     theEmitter->emitIns_R_R_I(INS_tst, EA_4BYTE, REG_R8, REG_R9, 22, INS_OPTS_LSR);
6016     theEmitter->emitIns_R_R_I(INS_tst, EA_4BYTE, REG_R8, REG_R9, 23, INS_OPTS_ASR);
6017     theEmitter->emitIns_R_R_I(INS_tst, EA_4BYTE, REG_R8, REG_R9, 24, INS_OPTS_ROR);
6018
6019     // CMP (extended register)
6020     theEmitter->emitIns_R_R_I(INS_cmp, EA_8BYTE, REG_R8, REG_R9, 0, INS_OPTS_UXTB);
6021     theEmitter->emitIns_R_R_I(INS_cmp, EA_8BYTE, REG_R8, REG_R9, 0, INS_OPTS_UXTH);
6022     theEmitter->emitIns_R_R_I(INS_cmp, EA_8BYTE, REG_R8, REG_R9, 0, INS_OPTS_UXTW); // "cmp x8, x9, UXTW"; msdis
6023                                                                                     // disassembles this "cmp x8,x9",
6024                                                                                     // which looks like an msdis issue.
6025     theEmitter->emitIns_R_R_I(INS_cmp, EA_8BYTE, REG_R8, REG_R9, 0, INS_OPTS_UXTX);
6026
6027     theEmitter->emitIns_R_R_I(INS_cmp, EA_8BYTE, REG_R8, REG_R9, 0, INS_OPTS_SXTB);
6028     theEmitter->emitIns_R_R_I(INS_cmp, EA_8BYTE, REG_R8, REG_R9, 0, INS_OPTS_SXTH);
6029     theEmitter->emitIns_R_R_I(INS_cmp, EA_8BYTE, REG_R8, REG_R9, 0, INS_OPTS_SXTW);
6030     theEmitter->emitIns_R_R_I(INS_cmp, EA_8BYTE, REG_R8, REG_R9, 0, INS_OPTS_SXTX);
6031
6032     // CMP 64-bit (extended register) and left shift
6033     theEmitter->emitIns_R_R_I(INS_cmp, EA_8BYTE, REG_R8, REG_R9, 1, INS_OPTS_UXTB);
6034     theEmitter->emitIns_R_R_I(INS_cmp, EA_8BYTE, REG_R8, REG_R9, 2, INS_OPTS_UXTH);
6035     theEmitter->emitIns_R_R_I(INS_cmp, EA_8BYTE, REG_R8, REG_R9, 3, INS_OPTS_UXTW);
6036     theEmitter->emitIns_R_R_I(INS_cmp, EA_8BYTE, REG_R8, REG_R9, 4, INS_OPTS_UXTX);
6037
6038     theEmitter->emitIns_R_R_I(INS_cmp, EA_8BYTE, REG_R8, REG_R9, 1, INS_OPTS_SXTB);
6039     theEmitter->emitIns_R_R_I(INS_cmp, EA_8BYTE, REG_R8, REG_R9, 2, INS_OPTS_SXTH);
6040     theEmitter->emitIns_R_R_I(INS_cmp, EA_8BYTE, REG_R8, REG_R9, 3, INS_OPTS_SXTW);
6041     theEmitter->emitIns_R_R_I(INS_cmp, EA_8BYTE, REG_R8, REG_R9, 4, INS_OPTS_SXTX);
6042
6043     // CMP 32-bit (extended register) and left shift
6044     theEmitter->emitIns_R_R_I(INS_cmp, EA_4BYTE, REG_R8, REG_R9, 0, INS_OPTS_UXTB);
6045     theEmitter->emitIns_R_R_I(INS_cmp, EA_4BYTE, REG_R8, REG_R9, 2, INS_OPTS_UXTH);
6046     theEmitter->emitIns_R_R_I(INS_cmp, EA_4BYTE, REG_R8, REG_R9, 4, INS_OPTS_UXTW);
6047
6048     theEmitter->emitIns_R_R_I(INS_cmp, EA_4BYTE, REG_R8, REG_R9, 0, INS_OPTS_SXTB);
6049     theEmitter->emitIns_R_R_I(INS_cmp, EA_4BYTE, REG_R8, REG_R9, 2, INS_OPTS_SXTH);
6050     theEmitter->emitIns_R_R_I(INS_cmp, EA_4BYTE, REG_R8, REG_R9, 4, INS_OPTS_SXTW);
6051
6052 #endif // ALL_ARM64_EMITTER_UNIT_TESTS
6053
6054 #ifdef ALL_ARM64_EMITTER_UNIT_TESTS
6055     //
6056     // R_R_R
6057     //
6058
6059     genDefineTempLabel(genCreateTempLabel());
6060
6061     theEmitter->emitIns_R_R_R(INS_lsl, EA_8BYTE, REG_R8, REG_R9, REG_R10);
6062     theEmitter->emitIns_R_R_R(INS_lsr, EA_8BYTE, REG_R8, REG_R9, REG_R10);
6063     theEmitter->emitIns_R_R_R(INS_asr, EA_8BYTE, REG_R8, REG_R9, REG_R10);
6064     theEmitter->emitIns_R_R_R(INS_ror, EA_8BYTE, REG_R8, REG_R9, REG_R10);
6065     theEmitter->emitIns_R_R_R(INS_adc, EA_8BYTE, REG_R8, REG_R9, REG_R10);
6066     theEmitter->emitIns_R_R_R(INS_adcs, EA_8BYTE, REG_R8, REG_R9, REG_R10);
6067     theEmitter->emitIns_R_R_R(INS_sbc, EA_8BYTE, REG_R8, REG_R9, REG_R10);
6068     theEmitter->emitIns_R_R_R(INS_sbcs, EA_8BYTE, REG_R8, REG_R9, REG_R10);
6069     theEmitter->emitIns_R_R_R(INS_udiv, EA_8BYTE, REG_R8, REG_R9, REG_R10);
6070     theEmitter->emitIns_R_R_R(INS_sdiv, EA_8BYTE, REG_R8, REG_R9, REG_R10);
6071     theEmitter->emitIns_R_R_R(INS_mul, EA_8BYTE, REG_R8, REG_R9, REG_R10);
6072     theEmitter->emitIns_R_R_R(INS_mneg, EA_8BYTE, REG_R8, REG_R9, REG_R10);
6073     theEmitter->emitIns_R_R_R(INS_smull, EA_8BYTE, REG_R8, REG_R9, REG_R10);
6074     theEmitter->emitIns_R_R_R(INS_smnegl, EA_8BYTE, REG_R8, REG_R9, REG_R10);
6075     theEmitter->emitIns_R_R_R(INS_smulh, EA_8BYTE, REG_R8, REG_R9, REG_R10);
6076     theEmitter->emitIns_R_R_R(INS_umull, EA_8BYTE, REG_R8, REG_R9, REG_R10);
6077     theEmitter->emitIns_R_R_R(INS_umnegl, EA_8BYTE, REG_R8, REG_R9, REG_R10);
6078     theEmitter->emitIns_R_R_R(INS_umulh, EA_8BYTE, REG_R8, REG_R9, REG_R10);
6079     theEmitter->emitIns_R_R_R(INS_lslv, EA_8BYTE, REG_R8, REG_R9, REG_R10);
6080     theEmitter->emitIns_R_R_R(INS_lsrv, EA_8BYTE, REG_R8, REG_R9, REG_R10);
6081     theEmitter->emitIns_R_R_R(INS_asrv, EA_8BYTE, REG_R8, REG_R9, REG_R10);
6082     theEmitter->emitIns_R_R_R(INS_rorv, EA_8BYTE, REG_R8, REG_R9, REG_R10);
6083
6084     theEmitter->emitIns_R_R_R(INS_lsl, EA_4BYTE, REG_R8, REG_R9, REG_R10);
6085     theEmitter->emitIns_R_R_R(INS_lsr, EA_4BYTE, REG_R8, REG_R9, REG_R10);
6086     theEmitter->emitIns_R_R_R(INS_asr, EA_4BYTE, REG_R8, REG_R9, REG_R10);
6087     theEmitter->emitIns_R_R_R(INS_ror, EA_4BYTE, REG_R8, REG_R9, REG_R10);
6088     theEmitter->emitIns_R_R_R(INS_adc, EA_4BYTE, REG_R8, REG_R9, REG_R10);
6089     theEmitter->emitIns_R_R_R(INS_adcs, EA_4BYTE, REG_R8, REG_R9, REG_R10);
6090     theEmitter->emitIns_R_R_R(INS_sbc, EA_4BYTE, REG_R8, REG_R9, REG_R10);
6091     theEmitter->emitIns_R_R_R(INS_sbcs, EA_4BYTE, REG_R8, REG_R9, REG_R10);
6092     theEmitter->emitIns_R_R_R(INS_udiv, EA_4BYTE, REG_R8, REG_R9, REG_R10);
6093     theEmitter->emitIns_R_R_R(INS_sdiv, EA_4BYTE, REG_R8, REG_R9, REG_R10);
6094     theEmitter->emitIns_R_R_R(INS_mul, EA_4BYTE, REG_R8, REG_R9, REG_R10);
6095     theEmitter->emitIns_R_R_R(INS_mneg, EA_4BYTE, REG_R8, REG_R9, REG_R10);
6096     theEmitter->emitIns_R_R_R(INS_smull, EA_4BYTE, REG_R8, REG_R9, REG_R10);
6097     theEmitter->emitIns_R_R_R(INS_smnegl, EA_4BYTE, REG_R8, REG_R9, REG_R10);
6098     theEmitter->emitIns_R_R_R(INS_smulh, EA_4BYTE, REG_R8, REG_R9, REG_R10);
6099     theEmitter->emitIns_R_R_R(INS_umull, EA_4BYTE, REG_R8, REG_R9, REG_R10);
6100     theEmitter->emitIns_R_R_R(INS_umnegl, EA_4BYTE, REG_R8, REG_R9, REG_R10);
6101     theEmitter->emitIns_R_R_R(INS_umulh, EA_4BYTE, REG_R8, REG_R9, REG_R10);
6102     theEmitter->emitIns_R_R_R(INS_lslv, EA_4BYTE, REG_R8, REG_R9, REG_R10);
6103     theEmitter->emitIns_R_R_R(INS_lsrv, EA_4BYTE, REG_R8, REG_R9, REG_R10);
6104     theEmitter->emitIns_R_R_R(INS_asrv, EA_4BYTE, REG_R8, REG_R9, REG_R10);
6105     theEmitter->emitIns_R_R_R(INS_rorv, EA_4BYTE, REG_R8, REG_R9, REG_R10);
6106
6107 #endif // ALL_ARM64_EMITTER_UNIT_TESTS
6108
6109 #ifdef ALL_ARM64_EMITTER_UNIT_TESTS
6110     //
6111     // R_R_I_I
6112     //
6113
6114     genDefineTempLabel(genCreateTempLabel());
6115
6116     theEmitter->emitIns_R_R_I_I(INS_sbfm, EA_8BYTE, REG_R2, REG_R3, 4, 39);
6117     theEmitter->emitIns_R_R_I_I(INS_bfm, EA_8BYTE, REG_R1, REG_R5, 20, 23);
6118     theEmitter->emitIns_R_R_I_I(INS_ubfm, EA_8BYTE, REG_R8, REG_R9, 36, 7);
6119
6120     theEmitter->emitIns_R_R_I_I(INS_sbfiz, EA_8BYTE, REG_R2, REG_R3, 7, 37);
6121     theEmitter->emitIns_R_R_I_I(INS_bfi, EA_8BYTE, REG_R1, REG_R5, 23, 21);
6122     theEmitter->emitIns_R_R_I_I(INS_ubfiz, EA_8BYTE, REG_R8, REG_R9, 39, 5);
6123
6124     theEmitter->emitIns_R_R_I_I(INS_sbfx, EA_8BYTE, REG_R2, REG_R3, 10, 24);
6125     theEmitter->emitIns_R_R_I_I(INS_bfxil, EA_8BYTE, REG_R1, REG_R5, 26, 16);
6126     theEmitter->emitIns_R_R_I_I(INS_ubfx, EA_8BYTE, REG_R8, REG_R9, 42, 8);
6127
6128     theEmitter->emitIns_R_R_I_I(INS_sbfm, EA_4BYTE, REG_R2, REG_R3, 4, 19);
6129     theEmitter->emitIns_R_R_I_I(INS_bfm, EA_4BYTE, REG_R1, REG_R5, 10, 13);
6130     theEmitter->emitIns_R_R_I_I(INS_ubfm, EA_4BYTE, REG_R8, REG_R9, 16, 7);
6131
6132     theEmitter->emitIns_R_R_I_I(INS_sbfiz, EA_4BYTE, REG_R2, REG_R3, 5, 17);
6133     theEmitter->emitIns_R_R_I_I(INS_bfi, EA_4BYTE, REG_R1, REG_R5, 13, 11);
6134     theEmitter->emitIns_R_R_I_I(INS_ubfiz, EA_4BYTE, REG_R8, REG_R9, 19, 5);
6135
6136     theEmitter->emitIns_R_R_I_I(INS_sbfx, EA_4BYTE, REG_R2, REG_R3, 3, 14);
6137     theEmitter->emitIns_R_R_I_I(INS_bfxil, EA_4BYTE, REG_R1, REG_R5, 11, 9);
6138     theEmitter->emitIns_R_R_I_I(INS_ubfx, EA_4BYTE, REG_R8, REG_R9, 22, 8);
6139
6140 #endif // ALL_ARM64_EMITTER_UNIT_TESTS
6141
6142 #ifdef ALL_ARM64_EMITTER_UNIT_TESTS
6143     //
6144     // R_R_R_I
6145     //
6146
6147     genDefineTempLabel(genCreateTempLabel());
6148
6149     // ADD (extended register)
6150     theEmitter->emitIns_R_R_R_I(INS_add, EA_8BYTE, REG_R8, REG_R9, REG_R10, 0, INS_OPTS_UXTB);
6151     theEmitter->emitIns_R_R_R_I(INS_add, EA_8BYTE, REG_R8, REG_R9, REG_R10, 0, INS_OPTS_UXTH);
6152     theEmitter->emitIns_R_R_R_I(INS_add, EA_8BYTE, REG_R8, REG_R9, REG_R10, 0, INS_OPTS_UXTW);
6153     theEmitter->emitIns_R_R_R_I(INS_add, EA_8BYTE, REG_R8, REG_R9, REG_R10, 0, INS_OPTS_UXTX);
6154     theEmitter->emitIns_R_R_R_I(INS_add, EA_8BYTE, REG_R8, REG_R9, REG_R10, 0, INS_OPTS_SXTB);
6155     theEmitter->emitIns_R_R_R_I(INS_add, EA_8BYTE, REG_R8, REG_R9, REG_R10, 0, INS_OPTS_SXTH);
6156     theEmitter->emitIns_R_R_R_I(INS_add, EA_8BYTE, REG_R8, REG_R9, REG_R10, 0, INS_OPTS_SXTW);
6157     theEmitter->emitIns_R_R_R_I(INS_add, EA_8BYTE, REG_R8, REG_R9, REG_R10, 0, INS_OPTS_SXTX);
6158
6159     // ADD (extended register) and left shift
6160     theEmitter->emitIns_R_R_R_I(INS_add, EA_8BYTE, REG_R8, REG_R9, REG_R10, 4, INS_OPTS_UXTB);
6161     theEmitter->emitIns_R_R_R_I(INS_add, EA_8BYTE, REG_R8, REG_R9, REG_R10, 4, INS_OPTS_UXTH);
6162     theEmitter->emitIns_R_R_R_I(INS_add, EA_8BYTE, REG_R8, REG_R9, REG_R10, 4, INS_OPTS_UXTW);
6163     theEmitter->emitIns_R_R_R_I(INS_add, EA_8BYTE, REG_R8, REG_R9, REG_R10, 4, INS_OPTS_UXTX);
6164     theEmitter->emitIns_R_R_R_I(INS_add, EA_8BYTE, REG_R8, REG_R9, REG_R10, 4, INS_OPTS_SXTB);
6165     theEmitter->emitIns_R_R_R_I(INS_add, EA_8BYTE, REG_R8, REG_R9, REG_R10, 4, INS_OPTS_SXTH);
6166     theEmitter->emitIns_R_R_R_I(INS_add, EA_8BYTE, REG_R8, REG_R9, REG_R10, 4, INS_OPTS_SXTW);
6167     theEmitter->emitIns_R_R_R_I(INS_add, EA_8BYTE, REG_R8, REG_R9, REG_R10, 4, INS_OPTS_SXTX);
6168
6169     // ADD (shifted register)
6170     theEmitter->emitIns_R_R_R_I(INS_add, EA_8BYTE, REG_R8, REG_R9, REG_R10, 0);
6171     theEmitter->emitIns_R_R_R_I(INS_add, EA_8BYTE, REG_R8, REG_R9, REG_R10, 31, INS_OPTS_LSL);
6172     theEmitter->emitIns_R_R_R_I(INS_add, EA_8BYTE, REG_R8, REG_R9, REG_R10, 32, INS_OPTS_LSR);
6173     theEmitter->emitIns_R_R_R_I(INS_add, EA_8BYTE, REG_R8, REG_R9, REG_R10, 33, INS_OPTS_ASR);
6174
6175     // EXTR (extract field from register pair)
6176     theEmitter->emitIns_R_R_R_I(INS_extr, EA_8BYTE, REG_R8, REG_R9, REG_R10, 1);
6177     theEmitter->emitIns_R_R_R_I(INS_extr, EA_8BYTE, REG_R8, REG_R9, REG_R10, 31);
6178     theEmitter->emitIns_R_R_R_I(INS_extr, EA_8BYTE, REG_R8, REG_R9, REG_R10, 32);
6179     theEmitter->emitIns_R_R_R_I(INS_extr, EA_8BYTE, REG_R8, REG_R9, REG_R10, 63);
6180
6181     theEmitter->emitIns_R_R_R_I(INS_extr, EA_4BYTE, REG_R8, REG_R9, REG_R10, 1);
6182     theEmitter->emitIns_R_R_R_I(INS_extr, EA_4BYTE, REG_R8, REG_R9, REG_R10, 31);
6183
6184     // SUB (extended register)
6185     theEmitter->emitIns_R_R_R_I(INS_sub, EA_4BYTE, REG_R8, REG_R9, REG_R10, 0, INS_OPTS_UXTB);
6186     theEmitter->emitIns_R_R_R_I(INS_sub, EA_4BYTE, REG_R8, REG_R9, REG_R10, 0, INS_OPTS_UXTH);
6187     theEmitter->emitIns_R_R_R_I(INS_sub, EA_4BYTE, REG_R8, REG_R9, REG_R10, 0, INS_OPTS_UXTW);
6188     theEmitter->emitIns_R_R_R_I(INS_sub, EA_4BYTE, REG_R8, REG_R9, REG_R10, 0, INS_OPTS_UXTX);
6189     theEmitter->emitIns_R_R_R_I(INS_sub, EA_4BYTE, REG_R8, REG_R9, REG_R10, 0, INS_OPTS_SXTB);
6190     theEmitter->emitIns_R_R_R_I(INS_sub, EA_4BYTE, REG_R8, REG_R9, REG_R10, 0, INS_OPTS_SXTH);
6191     theEmitter->emitIns_R_R_R_I(INS_sub, EA_4BYTE, REG_R8, REG_R9, REG_R10, 0, INS_OPTS_SXTW);
6192     theEmitter->emitIns_R_R_R_I(INS_sub, EA_4BYTE, REG_R8, REG_R9, REG_R10, 0, INS_OPTS_SXTX);
6193
6194     // SUB (extended register) and left shift
6195     theEmitter->emitIns_R_R_R_I(INS_sub, EA_4BYTE, REG_R8, REG_R9, REG_R10, 4, INS_OPTS_UXTB);
6196     theEmitter->emitIns_R_R_R_I(INS_sub, EA_4BYTE, REG_R8, REG_R9, REG_R10, 4, INS_OPTS_UXTH);
6197     theEmitter->emitIns_R_R_R_I(INS_sub, EA_4BYTE, REG_R8, REG_R9, REG_R10, 4, INS_OPTS_UXTW);
6198     theEmitter->emitIns_R_R_R_I(INS_sub, EA_4BYTE, REG_R8, REG_R9, REG_R10, 4, INS_OPTS_UXTX);
6199     theEmitter->emitIns_R_R_R_I(INS_sub, EA_4BYTE, REG_R8, REG_R9, REG_R10, 4, INS_OPTS_SXTB);
6200     theEmitter->emitIns_R_R_R_I(INS_sub, EA_4BYTE, REG_R8, REG_R9, REG_R10, 4, INS_OPTS_SXTH);
6201     theEmitter->emitIns_R_R_R_I(INS_sub, EA_4BYTE, REG_R8, REG_R9, REG_R10, 4, INS_OPTS_SXTW);
6202     theEmitter->emitIns_R_R_R_I(INS_sub, EA_4BYTE, REG_R8, REG_R9, REG_R10, 4, INS_OPTS_SXTX);
6203
6204     // SUB (shifted register)
6205     theEmitter->emitIns_R_R_R_I(INS_sub, EA_4BYTE, REG_R8, REG_R9, REG_R10, 0);
6206     theEmitter->emitIns_R_R_R_I(INS_sub, EA_4BYTE, REG_R8, REG_R9, REG_R10, 27, INS_OPTS_LSL);
6207     theEmitter->emitIns_R_R_R_I(INS_sub, EA_4BYTE, REG_R8, REG_R9, REG_R10, 28, INS_OPTS_LSR);
6208     theEmitter->emitIns_R_R_R_I(INS_sub, EA_4BYTE, REG_R8, REG_R9, REG_R10, 29, INS_OPTS_ASR);
6209
6210     // bit operations
6211     theEmitter->emitIns_R_R_R_I(INS_and, EA_8BYTE, REG_R8, REG_R9, REG_R10, 0);
6212     theEmitter->emitIns_R_R_R_I(INS_ands, EA_8BYTE, REG_R8, REG_R9, REG_R10, 0);
6213     theEmitter->emitIns_R_R_R_I(INS_eor, EA_8BYTE, REG_R8, REG_R9, REG_R10, 0);
6214     theEmitter->emitIns_R_R_R_I(INS_orr, EA_8BYTE, REG_R8, REG_R9, REG_R10, 0);
6215     theEmitter->emitIns_R_R_R_I(INS_bic, EA_8BYTE, REG_R8, REG_R9, REG_R10, 0);
6216     theEmitter->emitIns_R_R_R_I(INS_bics, EA_8BYTE, REG_R8, REG_R9, REG_R10, 0);
6217     theEmitter->emitIns_R_R_R_I(INS_eon, EA_8BYTE, REG_R8, REG_R9, REG_R10, 0);
6218     theEmitter->emitIns_R_R_R_I(INS_orn, EA_8BYTE, REG_R8, REG_R9, REG_R10, 0);
6219
6220     theEmitter->emitIns_R_R_R_I(INS_and, EA_8BYTE, REG_R8, REG_R9, REG_R10, 1, INS_OPTS_LSL);
6221     theEmitter->emitIns_R_R_R_I(INS_ands, EA_8BYTE, REG_R8, REG_R9, REG_R10, 2, INS_OPTS_LSR);
6222     theEmitter->emitIns_R_R_R_I(INS_eor, EA_8BYTE, REG_R8, REG_R9, REG_R10, 3, INS_OPTS_ASR);
6223     theEmitter->emitIns_R_R_R_I(INS_orr, EA_8BYTE, REG_R8, REG_R9, REG_R10, 4, INS_OPTS_ROR);
6224     theEmitter->emitIns_R_R_R_I(INS_bic, EA_8BYTE, REG_R8, REG_R9, REG_R10, 5, INS_OPTS_LSL);
6225     theEmitter->emitIns_R_R_R_I(INS_bics, EA_8BYTE, REG_R8, REG_R9, REG_R10, 6, INS_OPTS_LSR);
6226     theEmitter->emitIns_R_R_R_I(INS_eon, EA_8BYTE, REG_R8, REG_R9, REG_R10, 7, INS_OPTS_ASR);
6227     theEmitter->emitIns_R_R_R_I(INS_orn, EA_8BYTE, REG_R8, REG_R9, REG_R10, 8, INS_OPTS_ROR);
6228
6229     theEmitter->emitIns_R_R_R_I(INS_and, EA_4BYTE, REG_R8, REG_R9, REG_R10, 0);
6230     theEmitter->emitIns_R_R_R_I(INS_ands, EA_4BYTE, REG_R8, REG_R9, REG_R10, 0);
6231     theEmitter->emitIns_R_R_R_I(INS_eor, EA_4BYTE, REG_R8, REG_R9, REG_R10, 0);
6232     theEmitter->emitIns_R_R_R_I(INS_orr, EA_4BYTE, REG_R8, REG_R9, REG_R10, 0);
6233     theEmitter->emitIns_R_R_R_I(INS_bic, EA_4BYTE, REG_R8, REG_R9, REG_R10, 0);
6234     theEmitter->emitIns_R_R_R_I(INS_bics, EA_4BYTE, REG_R8, REG_R9, REG_R10, 0);
6235     theEmitter->emitIns_R_R_R_I(INS_eon, EA_4BYTE, REG_R8, REG_R9, REG_R10, 0);
6236     theEmitter->emitIns_R_R_R_I(INS_orn, EA_4BYTE, REG_R8, REG_R9, REG_R10, 0);
6237
6238     theEmitter->emitIns_R_R_R_I(INS_and, EA_4BYTE, REG_R8, REG_R9, REG_R10, 1, INS_OPTS_LSL);
6239     theEmitter->emitIns_R_R_R_I(INS_ands, EA_4BYTE, REG_R8, REG_R9, REG_R10, 2, INS_OPTS_LSR);
6240     theEmitter->emitIns_R_R_R_I(INS_eor, EA_4BYTE, REG_R8, REG_R9, REG_R10, 3, INS_OPTS_ASR);
6241     theEmitter->emitIns_R_R_R_I(INS_orr, EA_4BYTE, REG_R8, REG_R9, REG_R10, 4, INS_OPTS_ROR);
6242     theEmitter->emitIns_R_R_R_I(INS_bic, EA_4BYTE, REG_R8, REG_R9, REG_R10, 5, INS_OPTS_LSL);
6243     theEmitter->emitIns_R_R_R_I(INS_bics, EA_4BYTE, REG_R8, REG_R9, REG_R10, 6, INS_OPTS_LSR);
6244     theEmitter->emitIns_R_R_R_I(INS_eon, EA_4BYTE, REG_R8, REG_R9, REG_R10, 7, INS_OPTS_ASR);
6245     theEmitter->emitIns_R_R_R_I(INS_orn, EA_4BYTE, REG_R8, REG_R9, REG_R10, 8, INS_OPTS_ROR);
6246
6247 #endif // ALL_ARM64_EMITTER_UNIT_TESTS
6248
6249 #ifdef ALL_ARM64_EMITTER_UNIT_TESTS
6250     //
6251     // R_R_R_I  -- load/store pair
6252     //
6253
6254     theEmitter->emitIns_R_R_R_I(INS_ldnp, EA_8BYTE, REG_R8, REG_R9, REG_R10, 0);
6255     theEmitter->emitIns_R_R_R_I(INS_stnp, EA_8BYTE, REG_R8, REG_R9, REG_R10, 0);
6256     theEmitter->emitIns_R_R_R_I(INS_ldnp, EA_8BYTE, REG_R8, REG_R9, REG_R10, 8);
6257     theEmitter->emitIns_R_R_R_I(INS_stnp, EA_8BYTE, REG_R8, REG_R9, REG_R10, 8);
6258
6259     theEmitter->emitIns_R_R_R_I(INS_ldnp, EA_4BYTE, REG_R8, REG_R9, REG_SP, 0);
6260     theEmitter->emitIns_R_R_R_I(INS_stnp, EA_4BYTE, REG_R8, REG_R9, REG_SP, 0);
6261     theEmitter->emitIns_R_R_R_I(INS_ldnp, EA_4BYTE, REG_R8, REG_R9, REG_SP, 8);
6262     theEmitter->emitIns_R_R_R_I(INS_stnp, EA_4BYTE, REG_R8, REG_R9, REG_SP, 8);
6263
6264     theEmitter->emitIns_R_R_R_I(INS_ldp, EA_8BYTE, REG_R8, REG_R9, REG_R10, 0);
6265     theEmitter->emitIns_R_R_R_I(INS_stp, EA_8BYTE, REG_R8, REG_R9, REG_R10, 0);
6266     theEmitter->emitIns_R_R_R_I(INS_ldp, EA_8BYTE, REG_R8, REG_R9, REG_R10, 16);
6267     theEmitter->emitIns_R_R_R_I(INS_stp, EA_8BYTE, REG_R8, REG_R9, REG_R10, 16);
6268     theEmitter->emitIns_R_R_R_I(INS_ldp, EA_8BYTE, REG_R8, REG_R9, REG_R10, 16, INS_OPTS_POST_INDEX);
6269     theEmitter->emitIns_R_R_R_I(INS_stp, EA_8BYTE, REG_R8, REG_R9, REG_R10, 16, INS_OPTS_POST_INDEX);
6270     theEmitter->emitIns_R_R_R_I(INS_ldp, EA_8BYTE, REG_R8, REG_R9, REG_R10, 16, INS_OPTS_PRE_INDEX);
6271     theEmitter->emitIns_R_R_R_I(INS_stp, EA_8BYTE, REG_R8, REG_R9, REG_R10, 16, INS_OPTS_PRE_INDEX);
6272
6273     theEmitter->emitIns_R_R_R_I(INS_ldp, EA_4BYTE, REG_R8, REG_R9, REG_SP, 0);
6274     theEmitter->emitIns_R_R_R_I(INS_stp, EA_4BYTE, REG_R8, REG_R9, REG_SP, 0);
6275     theEmitter->emitIns_R_R_R_I(INS_ldp, EA_4BYTE, REG_R8, REG_R9, REG_SP, 16);
6276     theEmitter->emitIns_R_R_R_I(INS_stp, EA_4BYTE, REG_R8, REG_R9, REG_SP, 16);
6277     theEmitter->emitIns_R_R_R_I(INS_ldp, EA_4BYTE, REG_R8, REG_R9, REG_R10, 16, INS_OPTS_POST_INDEX);
6278     theEmitter->emitIns_R_R_R_I(INS_stp, EA_4BYTE, REG_R8, REG_R9, REG_R10, 16, INS_OPTS_POST_INDEX);
6279     theEmitter->emitIns_R_R_R_I(INS_ldp, EA_4BYTE, REG_R8, REG_R9, REG_R10, 16, INS_OPTS_PRE_INDEX);
6280     theEmitter->emitIns_R_R_R_I(INS_stp, EA_4BYTE, REG_R8, REG_R9, REG_R10, 16, INS_OPTS_PRE_INDEX);
6281
6282     theEmitter->emitIns_R_R_R_I(INS_ldpsw, EA_4BYTE, REG_R8, REG_R9, REG_R10, 0);
6283     theEmitter->emitIns_R_R_R_I(INS_ldpsw, EA_4BYTE, REG_R8, REG_R9, REG_R10, 16);
6284     theEmitter->emitIns_R_R_R_I(INS_ldpsw, EA_4BYTE, REG_R8, REG_R9, REG_R10, 16, INS_OPTS_POST_INDEX);
6285     theEmitter->emitIns_R_R_R_I(INS_ldpsw, EA_4BYTE, REG_R8, REG_R9, REG_R10, 16, INS_OPTS_PRE_INDEX);
6286
6287     // SP and ZR tests
6288     theEmitter->emitIns_R_R_R_I(INS_ldp, EA_8BYTE, REG_ZR, REG_R1, REG_SP, 0);
6289     theEmitter->emitIns_R_R_R_I(INS_ldp, EA_8BYTE, REG_R0, REG_ZR, REG_SP, 16);
6290     theEmitter->emitIns_R_R_R_I(INS_stp, EA_8BYTE, REG_ZR, REG_R1, REG_SP, 0);
6291     theEmitter->emitIns_R_R_R_I(INS_stp, EA_8BYTE, REG_R0, REG_ZR, REG_SP, 16);
6292     theEmitter->emitIns_R_R_R_I(INS_stp, EA_8BYTE, REG_ZR, REG_ZR, REG_SP, 16, INS_OPTS_POST_INDEX);
6293     theEmitter->emitIns_R_R_R_I(INS_stp, EA_8BYTE, REG_ZR, REG_ZR, REG_R8, 16, INS_OPTS_PRE_INDEX);
6294
6295 #endif // ALL_ARM64_EMITTER_UNIT_TESTS
6296
6297 #ifdef ALL_ARM64_EMITTER_UNIT_TESTS
6298     //
6299     // R_R_R_Ext    -- load/store shifted/extend
6300     //
6301
6302     genDefineTempLabel(genCreateTempLabel());
6303
6304     // LDR (register)
6305     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_8BYTE, REG_R8, REG_SP, REG_R9);
6306     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_8BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_LSL);
6307     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_8BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_LSL, 3);
6308     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_8BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_SXTW);
6309     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_8BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_SXTW, 3);
6310     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_8BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_UXTW);
6311     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_8BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_UXTW, 3);
6312     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_8BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_SXTX);
6313     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_8BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_SXTX, 3);
6314     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_8BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_UXTX);
6315     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_8BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_UXTX, 3);
6316
6317     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_4BYTE, REG_R8, REG_SP, REG_R9);
6318     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_4BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_LSL);
6319     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_4BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_LSL, 2);
6320     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_4BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_SXTW);
6321     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_4BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_SXTW, 2);
6322     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_4BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_UXTW);
6323     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_4BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_UXTW, 2);
6324     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_4BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_SXTX);
6325     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_4BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_SXTX, 2);
6326     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_4BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_UXTX);
6327     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_4BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_UXTX, 2);
6328
6329     theEmitter->emitIns_R_R_R_Ext(INS_ldrh, EA_2BYTE, REG_R8, REG_SP, REG_R9);
6330     theEmitter->emitIns_R_R_R_Ext(INS_ldrh, EA_2BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_LSL);
6331     theEmitter->emitIns_R_R_R_Ext(INS_ldrh, EA_2BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_LSL, 1);
6332     theEmitter->emitIns_R_R_R_Ext(INS_ldrh, EA_2BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_SXTW);
6333     theEmitter->emitIns_R_R_R_Ext(INS_ldrh, EA_2BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_SXTW, 1);
6334     theEmitter->emitIns_R_R_R_Ext(INS_ldrh, EA_2BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_UXTW);
6335     theEmitter->emitIns_R_R_R_Ext(INS_ldrh, EA_2BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_UXTW, 1);
6336     theEmitter->emitIns_R_R_R_Ext(INS_ldrh, EA_2BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_SXTX);
6337     theEmitter->emitIns_R_R_R_Ext(INS_ldrh, EA_2BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_SXTX, 1);
6338     theEmitter->emitIns_R_R_R_Ext(INS_ldrh, EA_2BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_UXTX);
6339     theEmitter->emitIns_R_R_R_Ext(INS_ldrh, EA_2BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_UXTX, 1);
6340
6341     theEmitter->emitIns_R_R_R_Ext(INS_ldrb, EA_1BYTE, REG_R8, REG_SP, REG_R9);
6342     theEmitter->emitIns_R_R_R_Ext(INS_ldrb, EA_1BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_SXTW);
6343     theEmitter->emitIns_R_R_R_Ext(INS_ldrb, EA_1BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_UXTW);
6344     theEmitter->emitIns_R_R_R_Ext(INS_ldrb, EA_1BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_SXTX);
6345     theEmitter->emitIns_R_R_R_Ext(INS_ldrb, EA_1BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_UXTX);
6346
6347     theEmitter->emitIns_R_R_R_Ext(INS_ldrsw, EA_4BYTE, REG_R8, REG_SP, REG_R9);
6348     theEmitter->emitIns_R_R_R_Ext(INS_ldrsw, EA_4BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_LSL);
6349     theEmitter->emitIns_R_R_R_Ext(INS_ldrsw, EA_4BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_LSL, 2);
6350     theEmitter->emitIns_R_R_R_Ext(INS_ldrsw, EA_4BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_SXTW);
6351     theEmitter->emitIns_R_R_R_Ext(INS_ldrsw, EA_4BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_SXTW, 2);
6352     theEmitter->emitIns_R_R_R_Ext(INS_ldrsw, EA_4BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_UXTW);
6353     theEmitter->emitIns_R_R_R_Ext(INS_ldrsw, EA_4BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_UXTW, 2);
6354     theEmitter->emitIns_R_R_R_Ext(INS_ldrsw, EA_4BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_SXTX);
6355     theEmitter->emitIns_R_R_R_Ext(INS_ldrsw, EA_4BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_SXTX, 2);
6356     theEmitter->emitIns_R_R_R_Ext(INS_ldrsw, EA_4BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_UXTX);
6357     theEmitter->emitIns_R_R_R_Ext(INS_ldrsw, EA_4BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_UXTX, 2);
6358
6359     theEmitter->emitIns_R_R_R_Ext(INS_ldrsh, EA_4BYTE, REG_R8, REG_SP, REG_R9);
6360     theEmitter->emitIns_R_R_R_Ext(INS_ldrsh, EA_8BYTE, REG_R8, REG_SP, REG_R9);
6361     theEmitter->emitIns_R_R_R_Ext(INS_ldrsh, EA_8BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_LSL);
6362     theEmitter->emitIns_R_R_R_Ext(INS_ldrsh, EA_4BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_LSL, 1);
6363     theEmitter->emitIns_R_R_R_Ext(INS_ldrsh, EA_4BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_SXTW);
6364     theEmitter->emitIns_R_R_R_Ext(INS_ldrsh, EA_8BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_SXTW, 1);
6365     theEmitter->emitIns_R_R_R_Ext(INS_ldrsh, EA_8BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_UXTW);
6366     theEmitter->emitIns_R_R_R_Ext(INS_ldrsh, EA_4BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_UXTW, 1);
6367     theEmitter->emitIns_R_R_R_Ext(INS_ldrsh, EA_4BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_SXTX);
6368     theEmitter->emitIns_R_R_R_Ext(INS_ldrsh, EA_8BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_SXTX, 1);
6369     theEmitter->emitIns_R_R_R_Ext(INS_ldrsh, EA_8BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_UXTX);
6370     theEmitter->emitIns_R_R_R_Ext(INS_ldrsh, EA_4BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_UXTX, 1);
6371
6372     theEmitter->emitIns_R_R_R_Ext(INS_ldrsb, EA_4BYTE, REG_R8, REG_SP, REG_R9);
6373     theEmitter->emitIns_R_R_R_Ext(INS_ldrsb, EA_8BYTE, REG_R8, REG_SP, REG_R9);
6374     theEmitter->emitIns_R_R_R_Ext(INS_ldrsb, EA_8BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_SXTW);
6375     theEmitter->emitIns_R_R_R_Ext(INS_ldrsb, EA_4BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_UXTW);
6376     theEmitter->emitIns_R_R_R_Ext(INS_ldrsb, EA_4BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_SXTX);
6377     theEmitter->emitIns_R_R_R_Ext(INS_ldrsb, EA_8BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_UXTX);
6378
6379     // STR (register)
6380     theEmitter->emitIns_R_R_R_Ext(INS_str, EA_8BYTE, REG_R8, REG_SP, REG_R9);
6381     theEmitter->emitIns_R_R_R_Ext(INS_str, EA_8BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_LSL);
6382     theEmitter->emitIns_R_R_R_Ext(INS_str, EA_8BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_LSL, 3);
6383     theEmitter->emitIns_R_R_R_Ext(INS_str, EA_8BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_SXTW);
6384     theEmitter->emitIns_R_R_R_Ext(INS_str, EA_8BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_SXTW, 3);
6385     theEmitter->emitIns_R_R_R_Ext(INS_str, EA_8BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_UXTW);
6386     theEmitter->emitIns_R_R_R_Ext(INS_str, EA_8BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_UXTW, 3);
6387     theEmitter->emitIns_R_R_R_Ext(INS_str, EA_8BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_SXTX);
6388     theEmitter->emitIns_R_R_R_Ext(INS_str, EA_8BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_SXTX, 3);
6389     theEmitter->emitIns_R_R_R_Ext(INS_str, EA_8BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_UXTX);
6390     theEmitter->emitIns_R_R_R_Ext(INS_str, EA_8BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_UXTX, 3);
6391
6392     theEmitter->emitIns_R_R_R_Ext(INS_str, EA_4BYTE, REG_R8, REG_SP, REG_R9);
6393     theEmitter->emitIns_R_R_R_Ext(INS_str, EA_4BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_LSL);
6394     theEmitter->emitIns_R_R_R_Ext(INS_str, EA_4BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_LSL, 2);
6395     theEmitter->emitIns_R_R_R_Ext(INS_str, EA_4BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_SXTW);
6396     theEmitter->emitIns_R_R_R_Ext(INS_str, EA_4BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_SXTW, 2);
6397     theEmitter->emitIns_R_R_R_Ext(INS_str, EA_4BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_UXTW);
6398     theEmitter->emitIns_R_R_R_Ext(INS_str, EA_4BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_UXTW, 2);
6399     theEmitter->emitIns_R_R_R_Ext(INS_str, EA_4BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_SXTX);
6400     theEmitter->emitIns_R_R_R_Ext(INS_str, EA_4BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_SXTX, 2);
6401     theEmitter->emitIns_R_R_R_Ext(INS_str, EA_4BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_UXTX);
6402     theEmitter->emitIns_R_R_R_Ext(INS_str, EA_4BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_UXTX, 2);
6403
6404     theEmitter->emitIns_R_R_R_Ext(INS_strh, EA_2BYTE, REG_R8, REG_SP, REG_R9);
6405     theEmitter->emitIns_R_R_R_Ext(INS_strh, EA_2BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_LSL);
6406     theEmitter->emitIns_R_R_R_Ext(INS_strh, EA_2BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_LSL, 1);
6407     theEmitter->emitIns_R_R_R_Ext(INS_strh, EA_2BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_SXTW);
6408     theEmitter->emitIns_R_R_R_Ext(INS_strh, EA_2BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_SXTW, 1);
6409     theEmitter->emitIns_R_R_R_Ext(INS_strh, EA_2BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_UXTW);
6410     theEmitter->emitIns_R_R_R_Ext(INS_strh, EA_2BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_UXTW, 1);
6411     theEmitter->emitIns_R_R_R_Ext(INS_strh, EA_2BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_SXTX);
6412     theEmitter->emitIns_R_R_R_Ext(INS_strh, EA_2BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_SXTX, 1);
6413     theEmitter->emitIns_R_R_R_Ext(INS_strh, EA_2BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_UXTX);
6414     theEmitter->emitIns_R_R_R_Ext(INS_strh, EA_2BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_UXTX, 1);
6415
6416     theEmitter->emitIns_R_R_R_Ext(INS_strb, EA_1BYTE, REG_R8, REG_SP, REG_R9);
6417     theEmitter->emitIns_R_R_R_Ext(INS_strb, EA_1BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_SXTW);
6418     theEmitter->emitIns_R_R_R_Ext(INS_strb, EA_1BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_UXTW);
6419     theEmitter->emitIns_R_R_R_Ext(INS_strb, EA_1BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_SXTX);
6420     theEmitter->emitIns_R_R_R_Ext(INS_strb, EA_1BYTE, REG_R8, REG_SP, REG_R9, INS_OPTS_UXTX);
6421
6422 #endif // ALL_ARM64_EMITTER_UNIT_TESTS
6423
6424 #ifdef ALL_ARM64_EMITTER_UNIT_TESTS
6425     //
6426     // R_R_R_R
6427     //
6428
6429     genDefineTempLabel(genCreateTempLabel());
6430
6431     theEmitter->emitIns_R_R_R_R(INS_madd, EA_4BYTE, REG_R0, REG_R12, REG_R27, REG_R10);
6432     theEmitter->emitIns_R_R_R_R(INS_msub, EA_4BYTE, REG_R1, REG_R13, REG_R28, REG_R11);
6433     theEmitter->emitIns_R_R_R_R(INS_smaddl, EA_4BYTE, REG_R2, REG_R14, REG_R0, REG_R12);
6434     theEmitter->emitIns_R_R_R_R(INS_smsubl, EA_4BYTE, REG_R3, REG_R15, REG_R1, REG_R13);
6435     theEmitter->emitIns_R_R_R_R(INS_umaddl, EA_4BYTE, REG_R4, REG_R19, REG_R2, REG_R14);
6436     theEmitter->emitIns_R_R_R_R(INS_umsubl, EA_4BYTE, REG_R5, REG_R20, REG_R3, REG_R15);
6437
6438     theEmitter->emitIns_R_R_R_R(INS_madd, EA_8BYTE, REG_R6, REG_R21, REG_R4, REG_R19);
6439     theEmitter->emitIns_R_R_R_R(INS_msub, EA_8BYTE, REG_R7, REG_R22, REG_R5, REG_R20);
6440     theEmitter->emitIns_R_R_R_R(INS_smaddl, EA_8BYTE, REG_R8, REG_R23, REG_R6, REG_R21);
6441     theEmitter->emitIns_R_R_R_R(INS_smsubl, EA_8BYTE, REG_R9, REG_R24, REG_R7, REG_R22);
6442     theEmitter->emitIns_R_R_R_R(INS_umaddl, EA_8BYTE, REG_R10, REG_R25, REG_R8, REG_R23);
6443     theEmitter->emitIns_R_R_R_R(INS_umsubl, EA_8BYTE, REG_R11, REG_R26, REG_R9, REG_R24);
6444
6445 #endif // ALL_ARM64_EMITTER_UNIT_TESTS
6446
6447 #ifdef ALL_ARM64_EMITTER_UNIT_TESTS
6448     // R_COND
6449     //
6450
6451     // cset reg, cond
6452     theEmitter->emitIns_R_COND(INS_cset, EA_8BYTE, REG_R9, INS_COND_EQ); // eq
6453     theEmitter->emitIns_R_COND(INS_cset, EA_4BYTE, REG_R8, INS_COND_NE); // ne
6454     theEmitter->emitIns_R_COND(INS_cset, EA_4BYTE, REG_R7, INS_COND_HS); // hs
6455     theEmitter->emitIns_R_COND(INS_cset, EA_8BYTE, REG_R6, INS_COND_LO); // lo
6456     theEmitter->emitIns_R_COND(INS_cset, EA_8BYTE, REG_R5, INS_COND_MI); // mi
6457     theEmitter->emitIns_R_COND(INS_cset, EA_4BYTE, REG_R4, INS_COND_PL); // pl
6458     theEmitter->emitIns_R_COND(INS_cset, EA_4BYTE, REG_R3, INS_COND_VS); // vs
6459     theEmitter->emitIns_R_COND(INS_cset, EA_8BYTE, REG_R2, INS_COND_VC); // vc
6460     theEmitter->emitIns_R_COND(INS_cset, EA_8BYTE, REG_R1, INS_COND_HI); // hi
6461     theEmitter->emitIns_R_COND(INS_cset, EA_4BYTE, REG_R0, INS_COND_LS); // ls
6462     theEmitter->emitIns_R_COND(INS_cset, EA_4BYTE, REG_R9, INS_COND_GE); // ge
6463     theEmitter->emitIns_R_COND(INS_cset, EA_8BYTE, REG_R8, INS_COND_LT); // lt
6464     theEmitter->emitIns_R_COND(INS_cset, EA_8BYTE, REG_R7, INS_COND_GT); // gt
6465     theEmitter->emitIns_R_COND(INS_cset, EA_4BYTE, REG_R6, INS_COND_LE); // le
6466
6467     // csetm reg, cond
6468     theEmitter->emitIns_R_COND(INS_csetm, EA_4BYTE, REG_R9, INS_COND_EQ); // eq
6469     theEmitter->emitIns_R_COND(INS_csetm, EA_8BYTE, REG_R8, INS_COND_NE); // ne
6470     theEmitter->emitIns_R_COND(INS_csetm, EA_8BYTE, REG_R7, INS_COND_HS); // hs
6471     theEmitter->emitIns_R_COND(INS_csetm, EA_4BYTE, REG_R6, INS_COND_LO); // lo
6472     theEmitter->emitIns_R_COND(INS_csetm, EA_4BYTE, REG_R5, INS_COND_MI); // mi
6473     theEmitter->emitIns_R_COND(INS_csetm, EA_8BYTE, REG_R4, INS_COND_PL); // pl
6474     theEmitter->emitIns_R_COND(INS_csetm, EA_8BYTE, REG_R3, INS_COND_VS); // vs
6475     theEmitter->emitIns_R_COND(INS_csetm, EA_4BYTE, REG_R2, INS_COND_VC); // vc
6476     theEmitter->emitIns_R_COND(INS_csetm, EA_4BYTE, REG_R1, INS_COND_HI); // hi
6477     theEmitter->emitIns_R_COND(INS_csetm, EA_8BYTE, REG_R0, INS_COND_LS); // ls
6478     theEmitter->emitIns_R_COND(INS_csetm, EA_8BYTE, REG_R9, INS_COND_GE); // ge
6479     theEmitter->emitIns_R_COND(INS_csetm, EA_4BYTE, REG_R8, INS_COND_LT); // lt
6480     theEmitter->emitIns_R_COND(INS_csetm, EA_4BYTE, REG_R7, INS_COND_GT); // gt
6481     theEmitter->emitIns_R_COND(INS_csetm, EA_8BYTE, REG_R6, INS_COND_LE); // le
6482
6483 #endif // ALL_ARM64_EMITTER_UNIT_TESTS
6484
6485 #ifdef ALL_ARM64_EMITTER_UNIT_TESTS
6486     // R_R_COND
6487     //
6488
6489     // cinc reg, reg, cond
6490     // cinv reg, reg, cond
6491     // cneg reg, reg, cond
6492     theEmitter->emitIns_R_R_COND(INS_cinc, EA_8BYTE, REG_R0, REG_R4, INS_COND_EQ); // eq
6493     theEmitter->emitIns_R_R_COND(INS_cinv, EA_4BYTE, REG_R1, REG_R5, INS_COND_NE); // ne
6494     theEmitter->emitIns_R_R_COND(INS_cneg, EA_4BYTE, REG_R2, REG_R6, INS_COND_HS); // hs
6495     theEmitter->emitIns_R_R_COND(INS_cinc, EA_8BYTE, REG_R3, REG_R7, INS_COND_LO); // lo
6496     theEmitter->emitIns_R_R_COND(INS_cinv, EA_4BYTE, REG_R4, REG_R8, INS_COND_MI); // mi
6497     theEmitter->emitIns_R_R_COND(INS_cneg, EA_8BYTE, REG_R5, REG_R9, INS_COND_PL); // pl
6498     theEmitter->emitIns_R_R_COND(INS_cinc, EA_8BYTE, REG_R6, REG_R0, INS_COND_VS); // vs
6499     theEmitter->emitIns_R_R_COND(INS_cinv, EA_4BYTE, REG_R7, REG_R1, INS_COND_VC); // vc
6500     theEmitter->emitIns_R_R_COND(INS_cneg, EA_8BYTE, REG_R8, REG_R2, INS_COND_HI); // hi
6501     theEmitter->emitIns_R_R_COND(INS_cinc, EA_4BYTE, REG_R9, REG_R3, INS_COND_LS); // ls
6502     theEmitter->emitIns_R_R_COND(INS_cinv, EA_4BYTE, REG_R0, REG_R4, INS_COND_GE); // ge
6503     theEmitter->emitIns_R_R_COND(INS_cneg, EA_8BYTE, REG_R2, REG_R5, INS_COND_LT); // lt
6504     theEmitter->emitIns_R_R_COND(INS_cinc, EA_4BYTE, REG_R2, REG_R6, INS_COND_GT); // gt
6505     theEmitter->emitIns_R_R_COND(INS_cinv, EA_8BYTE, REG_R3, REG_R7, INS_COND_LE); // le
6506
6507 #endif // ALL_ARM64_EMITTER_UNIT_TESTS
6508
6509 #ifdef ALL_ARM64_EMITTER_UNIT_TESTS
6510     // R_R_R_COND
6511     //
6512
6513     // csel  reg, reg, reg, cond
6514     // csinc reg, reg, reg, cond
6515     // csinv reg, reg, reg, cond
6516     // csneg reg, reg, reg, cond
6517     theEmitter->emitIns_R_R_R_COND(INS_csel, EA_8BYTE, REG_R0, REG_R4, REG_R8, INS_COND_EQ);  // eq
6518     theEmitter->emitIns_R_R_R_COND(INS_csinc, EA_4BYTE, REG_R1, REG_R5, REG_R9, INS_COND_NE); // ne
6519     theEmitter->emitIns_R_R_R_COND(INS_csinv, EA_4BYTE, REG_R2, REG_R6, REG_R0, INS_COND_HS); // hs
6520     theEmitter->emitIns_R_R_R_COND(INS_csneg, EA_8BYTE, REG_R3, REG_R7, REG_R1, INS_COND_LO); // lo
6521     theEmitter->emitIns_R_R_R_COND(INS_csel, EA_4BYTE, REG_R4, REG_R8, REG_R2, INS_COND_MI);  // mi
6522     theEmitter->emitIns_R_R_R_COND(INS_csinc, EA_8BYTE, REG_R5, REG_R9, REG_R3, INS_COND_PL); // pl
6523     theEmitter->emitIns_R_R_R_COND(INS_csinv, EA_8BYTE, REG_R6, REG_R0, REG_R4, INS_COND_VS); // vs
6524     theEmitter->emitIns_R_R_R_COND(INS_csneg, EA_4BYTE, REG_R7, REG_R1, REG_R5, INS_COND_VC); // vc
6525     theEmitter->emitIns_R_R_R_COND(INS_csel, EA_8BYTE, REG_R8, REG_R2, REG_R6, INS_COND_HI);  // hi
6526     theEmitter->emitIns_R_R_R_COND(INS_csinc, EA_4BYTE, REG_R9, REG_R3, REG_R7, INS_COND_LS); // ls
6527     theEmitter->emitIns_R_R_R_COND(INS_csinv, EA_4BYTE, REG_R0, REG_R4, REG_R8, INS_COND_GE); // ge
6528     theEmitter->emitIns_R_R_R_COND(INS_csneg, EA_8BYTE, REG_R2, REG_R5, REG_R9, INS_COND_LT); // lt
6529     theEmitter->emitIns_R_R_R_COND(INS_csel, EA_4BYTE, REG_R2, REG_R6, REG_R0, INS_COND_GT);  // gt
6530     theEmitter->emitIns_R_R_R_COND(INS_csinc, EA_8BYTE, REG_R3, REG_R7, REG_R1, INS_COND_LE); // le
6531
6532 #endif // ALL_ARM64_EMITTER_UNIT_TESTS
6533
6534 #ifdef ALL_ARM64_EMITTER_UNIT_TESTS
6535     // R_R_FLAGS_COND
6536     //
6537
6538     // ccmp reg1, reg2, nzcv, cond
6539     theEmitter->emitIns_R_R_FLAGS_COND(INS_ccmp, EA_8BYTE, REG_R9, REG_R3, INS_FLAGS_V, INS_COND_EQ);    // eq
6540     theEmitter->emitIns_R_R_FLAGS_COND(INS_ccmp, EA_4BYTE, REG_R8, REG_R2, INS_FLAGS_C, INS_COND_NE);    // ne
6541     theEmitter->emitIns_R_R_FLAGS_COND(INS_ccmp, EA_4BYTE, REG_R7, REG_R1, INS_FLAGS_Z, INS_COND_HS);    // hs
6542     theEmitter->emitIns_R_R_FLAGS_COND(INS_ccmp, EA_8BYTE, REG_R6, REG_R0, INS_FLAGS_N, INS_COND_LO);    // lo
6543     theEmitter->emitIns_R_R_FLAGS_COND(INS_ccmp, EA_8BYTE, REG_R5, REG_R3, INS_FLAGS_CV, INS_COND_MI);   // mi
6544     theEmitter->emitIns_R_R_FLAGS_COND(INS_ccmp, EA_4BYTE, REG_R4, REG_R2, INS_FLAGS_ZV, INS_COND_PL);   // pl
6545     theEmitter->emitIns_R_R_FLAGS_COND(INS_ccmp, EA_4BYTE, REG_R3, REG_R1, INS_FLAGS_ZC, INS_COND_VS);   // vs
6546     theEmitter->emitIns_R_R_FLAGS_COND(INS_ccmp, EA_8BYTE, REG_R2, REG_R0, INS_FLAGS_NV, INS_COND_VC);   // vc
6547     theEmitter->emitIns_R_R_FLAGS_COND(INS_ccmp, EA_8BYTE, REG_R1, REG_R3, INS_FLAGS_NC, INS_COND_HI);   // hi
6548     theEmitter->emitIns_R_R_FLAGS_COND(INS_ccmp, EA_4BYTE, REG_R0, REG_R2, INS_FLAGS_NZ, INS_COND_LS);   // ls
6549     theEmitter->emitIns_R_R_FLAGS_COND(INS_ccmp, EA_4BYTE, REG_R9, REG_R1, INS_FLAGS_NONE, INS_COND_GE); // ge
6550     theEmitter->emitIns_R_R_FLAGS_COND(INS_ccmp, EA_8BYTE, REG_R8, REG_R0, INS_FLAGS_NZV, INS_COND_LT);  // lt
6551     theEmitter->emitIns_R_R_FLAGS_COND(INS_ccmp, EA_8BYTE, REG_R7, REG_R3, INS_FLAGS_NZC, INS_COND_GT);  // gt
6552     theEmitter->emitIns_R_R_FLAGS_COND(INS_ccmp, EA_4BYTE, REG_R6, REG_R2, INS_FLAGS_NZCV, INS_COND_LE); // le
6553
6554     // ccmp reg1, imm, nzcv, cond
6555     theEmitter->emitIns_R_I_FLAGS_COND(INS_ccmp, EA_8BYTE, REG_R9, 3, INS_FLAGS_V, INS_COND_EQ);     // eq
6556     theEmitter->emitIns_R_I_FLAGS_COND(INS_ccmp, EA_4BYTE, REG_R8, 2, INS_FLAGS_C, INS_COND_NE);     // ne
6557     theEmitter->emitIns_R_I_FLAGS_COND(INS_ccmp, EA_4BYTE, REG_R7, 1, INS_FLAGS_Z, INS_COND_HS);     // hs
6558     theEmitter->emitIns_R_I_FLAGS_COND(INS_ccmp, EA_8BYTE, REG_R6, 0, INS_FLAGS_N, INS_COND_LO);     // lo
6559     theEmitter->emitIns_R_I_FLAGS_COND(INS_ccmp, EA_8BYTE, REG_R5, 31, INS_FLAGS_CV, INS_COND_MI);   // mi
6560     theEmitter->emitIns_R_I_FLAGS_COND(INS_ccmp, EA_4BYTE, REG_R4, 28, INS_FLAGS_ZV, INS_COND_PL);   // pl
6561     theEmitter->emitIns_R_I_FLAGS_COND(INS_ccmp, EA_4BYTE, REG_R3, 25, INS_FLAGS_ZC, INS_COND_VS);   // vs
6562     theEmitter->emitIns_R_I_FLAGS_COND(INS_ccmp, EA_8BYTE, REG_R2, 22, INS_FLAGS_NV, INS_COND_VC);   // vc
6563     theEmitter->emitIns_R_I_FLAGS_COND(INS_ccmp, EA_8BYTE, REG_R1, 19, INS_FLAGS_NC, INS_COND_HI);   // hi
6564     theEmitter->emitIns_R_I_FLAGS_COND(INS_ccmp, EA_4BYTE, REG_R0, 16, INS_FLAGS_NZ, INS_COND_LS);   // ls
6565     theEmitter->emitIns_R_I_FLAGS_COND(INS_ccmp, EA_4BYTE, REG_R9, 13, INS_FLAGS_NONE, INS_COND_GE); // ge
6566     theEmitter->emitIns_R_I_FLAGS_COND(INS_ccmp, EA_8BYTE, REG_R8, 10, INS_FLAGS_NZV, INS_COND_LT);  // lt
6567     theEmitter->emitIns_R_I_FLAGS_COND(INS_ccmp, EA_8BYTE, REG_R7, 7, INS_FLAGS_NZC, INS_COND_GT);   // gt
6568     theEmitter->emitIns_R_I_FLAGS_COND(INS_ccmp, EA_4BYTE, REG_R6, 4, INS_FLAGS_NZCV, INS_COND_LE);  // le
6569
6570     // ccmp reg1, imm, nzcv, cond  -- encoded as ccmn
6571     theEmitter->emitIns_R_I_FLAGS_COND(INS_ccmp, EA_8BYTE, REG_R9, -3, INS_FLAGS_V, INS_COND_EQ);     // eq
6572     theEmitter->emitIns_R_I_FLAGS_COND(INS_ccmp, EA_4BYTE, REG_R8, -2, INS_FLAGS_C, INS_COND_NE);     // ne
6573     theEmitter->emitIns_R_I_FLAGS_COND(INS_ccmp, EA_4BYTE, REG_R7, -1, INS_FLAGS_Z, INS_COND_HS);     // hs
6574     theEmitter->emitIns_R_I_FLAGS_COND(INS_ccmp, EA_8BYTE, REG_R6, -5, INS_FLAGS_N, INS_COND_LO);     // lo
6575     theEmitter->emitIns_R_I_FLAGS_COND(INS_ccmp, EA_8BYTE, REG_R5, -31, INS_FLAGS_CV, INS_COND_MI);   // mi
6576     theEmitter->emitIns_R_I_FLAGS_COND(INS_ccmp, EA_4BYTE, REG_R4, -28, INS_FLAGS_ZV, INS_COND_PL);   // pl
6577     theEmitter->emitIns_R_I_FLAGS_COND(INS_ccmp, EA_4BYTE, REG_R3, -25, INS_FLAGS_ZC, INS_COND_VS);   // vs
6578     theEmitter->emitIns_R_I_FLAGS_COND(INS_ccmp, EA_8BYTE, REG_R2, -22, INS_FLAGS_NV, INS_COND_VC);   // vc
6579     theEmitter->emitIns_R_I_FLAGS_COND(INS_ccmp, EA_8BYTE, REG_R1, -19, INS_FLAGS_NC, INS_COND_HI);   // hi
6580     theEmitter->emitIns_R_I_FLAGS_COND(INS_ccmp, EA_4BYTE, REG_R0, -16, INS_FLAGS_NZ, INS_COND_LS);   // ls
6581     theEmitter->emitIns_R_I_FLAGS_COND(INS_ccmp, EA_4BYTE, REG_R9, -13, INS_FLAGS_NONE, INS_COND_GE); // ge
6582     theEmitter->emitIns_R_I_FLAGS_COND(INS_ccmp, EA_8BYTE, REG_R8, -10, INS_FLAGS_NZV, INS_COND_LT);  // lt
6583     theEmitter->emitIns_R_I_FLAGS_COND(INS_ccmp, EA_8BYTE, REG_R7, -7, INS_FLAGS_NZC, INS_COND_GT);   // gt
6584     theEmitter->emitIns_R_I_FLAGS_COND(INS_ccmp, EA_4BYTE, REG_R6, -4, INS_FLAGS_NZCV, INS_COND_LE);  // le
6585
6586     // ccmn reg1, reg2, nzcv, cond
6587     theEmitter->emitIns_R_R_FLAGS_COND(INS_ccmn, EA_8BYTE, REG_R9, REG_R3, INS_FLAGS_V, INS_COND_EQ);    // eq
6588     theEmitter->emitIns_R_R_FLAGS_COND(INS_ccmn, EA_4BYTE, REG_R8, REG_R2, INS_FLAGS_C, INS_COND_NE);    // ne
6589     theEmitter->emitIns_R_R_FLAGS_COND(INS_ccmn, EA_4BYTE, REG_R7, REG_R1, INS_FLAGS_Z, INS_COND_HS);    // hs
6590     theEmitter->emitIns_R_R_FLAGS_COND(INS_ccmn, EA_8BYTE, REG_R6, REG_R0, INS_FLAGS_N, INS_COND_LO);    // lo
6591     theEmitter->emitIns_R_R_FLAGS_COND(INS_ccmn, EA_8BYTE, REG_R5, REG_R3, INS_FLAGS_CV, INS_COND_MI);   // mi
6592     theEmitter->emitIns_R_R_FLAGS_COND(INS_ccmn, EA_4BYTE, REG_R4, REG_R2, INS_FLAGS_ZV, INS_COND_PL);   // pl
6593     theEmitter->emitIns_R_R_FLAGS_COND(INS_ccmn, EA_4BYTE, REG_R3, REG_R1, INS_FLAGS_ZC, INS_COND_VS);   // vs
6594     theEmitter->emitIns_R_R_FLAGS_COND(INS_ccmn, EA_8BYTE, REG_R2, REG_R0, INS_FLAGS_NV, INS_COND_VC);   // vc
6595     theEmitter->emitIns_R_R_FLAGS_COND(INS_ccmn, EA_8BYTE, REG_R1, REG_R3, INS_FLAGS_NC, INS_COND_HI);   // hi
6596     theEmitter->emitIns_R_R_FLAGS_COND(INS_ccmn, EA_4BYTE, REG_R0, REG_R2, INS_FLAGS_NZ, INS_COND_LS);   // ls
6597     theEmitter->emitIns_R_R_FLAGS_COND(INS_ccmn, EA_4BYTE, REG_R9, REG_R1, INS_FLAGS_NONE, INS_COND_GE); // ge
6598     theEmitter->emitIns_R_R_FLAGS_COND(INS_ccmn, EA_8BYTE, REG_R8, REG_R0, INS_FLAGS_NZV, INS_COND_LT);  // lt
6599     theEmitter->emitIns_R_R_FLAGS_COND(INS_ccmn, EA_8BYTE, REG_R7, REG_R3, INS_FLAGS_NZC, INS_COND_GT);  // gt
6600     theEmitter->emitIns_R_R_FLAGS_COND(INS_ccmn, EA_4BYTE, REG_R6, REG_R2, INS_FLAGS_NZCV, INS_COND_LE); // le
6601
6602     // ccmn reg1, imm, nzcv, cond
6603     theEmitter->emitIns_R_I_FLAGS_COND(INS_ccmn, EA_8BYTE, REG_R9, 3, INS_FLAGS_V, INS_COND_EQ);     // eq
6604     theEmitter->emitIns_R_I_FLAGS_COND(INS_ccmn, EA_4BYTE, REG_R8, 2, INS_FLAGS_C, INS_COND_NE);     // ne
6605     theEmitter->emitIns_R_I_FLAGS_COND(INS_ccmn, EA_4BYTE, REG_R7, 1, INS_FLAGS_Z, INS_COND_HS);     // hs
6606     theEmitter->emitIns_R_I_FLAGS_COND(INS_ccmn, EA_8BYTE, REG_R6, 0, INS_FLAGS_N, INS_COND_LO);     // lo
6607     theEmitter->emitIns_R_I_FLAGS_COND(INS_ccmn, EA_8BYTE, REG_R5, 31, INS_FLAGS_CV, INS_COND_MI);   // mi
6608     theEmitter->emitIns_R_I_FLAGS_COND(INS_ccmn, EA_4BYTE, REG_R4, 28, INS_FLAGS_ZV, INS_COND_PL);   // pl
6609     theEmitter->emitIns_R_I_FLAGS_COND(INS_ccmn, EA_4BYTE, REG_R3, 25, INS_FLAGS_ZC, INS_COND_VS);   // vs
6610     theEmitter->emitIns_R_I_FLAGS_COND(INS_ccmn, EA_8BYTE, REG_R2, 22, INS_FLAGS_NV, INS_COND_VC);   // vc
6611     theEmitter->emitIns_R_I_FLAGS_COND(INS_ccmn, EA_8BYTE, REG_R1, 19, INS_FLAGS_NC, INS_COND_HI);   // hi
6612     theEmitter->emitIns_R_I_FLAGS_COND(INS_ccmn, EA_4BYTE, REG_R0, 16, INS_FLAGS_NZ, INS_COND_LS);   // ls
6613     theEmitter->emitIns_R_I_FLAGS_COND(INS_ccmn, EA_4BYTE, REG_R9, 13, INS_FLAGS_NONE, INS_COND_GE); // ge
6614     theEmitter->emitIns_R_I_FLAGS_COND(INS_ccmn, EA_8BYTE, REG_R8, 10, INS_FLAGS_NZV, INS_COND_LT);  // lt
6615     theEmitter->emitIns_R_I_FLAGS_COND(INS_ccmn, EA_8BYTE, REG_R7, 7, INS_FLAGS_NZC, INS_COND_GT);   // gt
6616     theEmitter->emitIns_R_I_FLAGS_COND(INS_ccmn, EA_4BYTE, REG_R6, 4, INS_FLAGS_NZCV, INS_COND_LE);  // le
6617
6618 #endif // ALL_ARM64_EMITTER_UNIT_TESTS
6619
6620 #ifdef ALL_ARM64_EMITTER_UNIT_TESTS
6621     //
6622     // Branch to register
6623     //
6624
6625     genDefineTempLabel(genCreateTempLabel());
6626
6627     theEmitter->emitIns_R(INS_br, EA_PTRSIZE, REG_R8);
6628     theEmitter->emitIns_R(INS_blr, EA_PTRSIZE, REG_R9);
6629     theEmitter->emitIns_R(INS_ret, EA_PTRSIZE, REG_R8);
6630     theEmitter->emitIns_R(INS_ret, EA_PTRSIZE, REG_LR);
6631
6632 #endif // ALL_ARM64_EMITTER_UNIT_TESTS
6633
6634 #ifdef ALL_ARM64_EMITTER_UNIT_TESTS
6635     //
6636     // Misc
6637     //
6638
6639     genDefineTempLabel(genCreateTempLabel());
6640
6641     theEmitter->emitIns_I(INS_brk, EA_PTRSIZE, 0);
6642     theEmitter->emitIns_I(INS_brk, EA_PTRSIZE, 65535);
6643
6644     theEmitter->emitIns_BARR(INS_dsb, INS_BARRIER_OSHLD);
6645     theEmitter->emitIns_BARR(INS_dmb, INS_BARRIER_OSHST);
6646     theEmitter->emitIns_BARR(INS_isb, INS_BARRIER_OSH);
6647
6648     theEmitter->emitIns_BARR(INS_dmb, INS_BARRIER_NSHLD);
6649     theEmitter->emitIns_BARR(INS_isb, INS_BARRIER_NSHST);
6650     theEmitter->emitIns_BARR(INS_dsb, INS_BARRIER_NSH);
6651
6652     theEmitter->emitIns_BARR(INS_isb, INS_BARRIER_ISHLD);
6653     theEmitter->emitIns_BARR(INS_dsb, INS_BARRIER_ISHST);
6654     theEmitter->emitIns_BARR(INS_dmb, INS_BARRIER_ISH);
6655
6656     theEmitter->emitIns_BARR(INS_dsb, INS_BARRIER_LD);
6657     theEmitter->emitIns_BARR(INS_dmb, INS_BARRIER_ST);
6658     theEmitter->emitIns_BARR(INS_isb, INS_BARRIER_SY);
6659
6660 #endif // ALL_ARM64_EMITTER_UNIT_TESTS
6661
6662 #ifdef ALL_ARM64_EMITTER_UNIT_TESTS
6663     ////////////////////////////////////////////////////////////////////////////////
6664     //
6665     // SIMD and Floating point
6666     //
6667     ////////////////////////////////////////////////////////////////////////////////
6668
6669     //
6670     // Load/Stores vector register
6671     //
6672
6673     genDefineTempLabel(genCreateTempLabel());
6674
6675     // ldr/str Vt, [reg]
6676     theEmitter->emitIns_R_R(INS_ldr, EA_8BYTE, REG_V1, REG_R9);
6677     theEmitter->emitIns_R_R(INS_str, EA_8BYTE, REG_V2, REG_R8);
6678     theEmitter->emitIns_R_R(INS_ldr, EA_4BYTE, REG_V3, REG_R7);
6679     theEmitter->emitIns_R_R(INS_str, EA_4BYTE, REG_V4, REG_R6);
6680     theEmitter->emitIns_R_R(INS_ldr, EA_2BYTE, REG_V5, REG_R5);
6681     theEmitter->emitIns_R_R(INS_str, EA_2BYTE, REG_V6, REG_R4);
6682     theEmitter->emitIns_R_R(INS_ldr, EA_1BYTE, REG_V7, REG_R3);
6683     theEmitter->emitIns_R_R(INS_str, EA_1BYTE, REG_V8, REG_R2);
6684     theEmitter->emitIns_R_R(INS_ldr, EA_16BYTE, REG_V9, REG_R1);
6685     theEmitter->emitIns_R_R(INS_str, EA_16BYTE, REG_V10, REG_R0);
6686
6687     // ldr/str Vt, [reg+cns]        -- scaled
6688     theEmitter->emitIns_R_R_I(INS_ldr, EA_1BYTE, REG_V8, REG_R9, 1);
6689     theEmitter->emitIns_R_R_I(INS_ldr, EA_2BYTE, REG_V8, REG_R9, 2);
6690     theEmitter->emitIns_R_R_I(INS_ldr, EA_4BYTE, REG_V8, REG_R9, 4);
6691     theEmitter->emitIns_R_R_I(INS_ldr, EA_8BYTE, REG_V8, REG_R9, 8);
6692     theEmitter->emitIns_R_R_I(INS_ldr, EA_16BYTE, REG_V8, REG_R9, 16);
6693
6694     theEmitter->emitIns_R_R_I(INS_ldr, EA_1BYTE, REG_V7, REG_R10, 1);
6695     theEmitter->emitIns_R_R_I(INS_ldr, EA_2BYTE, REG_V7, REG_R10, 2);
6696     theEmitter->emitIns_R_R_I(INS_ldr, EA_4BYTE, REG_V7, REG_R10, 4);
6697     theEmitter->emitIns_R_R_I(INS_ldr, EA_8BYTE, REG_V7, REG_R10, 8);
6698     theEmitter->emitIns_R_R_I(INS_ldr, EA_16BYTE, REG_V7, REG_R10, 16);
6699
6700     // ldr/str Vt, [reg],cns        -- post-indexed (unscaled)
6701     // ldr/str Vt, [reg+cns]!       -- post-indexed (unscaled)
6702     theEmitter->emitIns_R_R_I(INS_ldr, EA_1BYTE, REG_V8, REG_R9, 1, INS_OPTS_POST_INDEX);
6703     theEmitter->emitIns_R_R_I(INS_ldr, EA_2BYTE, REG_V8, REG_R9, 1, INS_OPTS_POST_INDEX);
6704     theEmitter->emitIns_R_R_I(INS_ldr, EA_4BYTE, REG_V8, REG_R9, 1, INS_OPTS_POST_INDEX);
6705     theEmitter->emitIns_R_R_I(INS_ldr, EA_8BYTE, REG_V8, REG_R9, 1, INS_OPTS_POST_INDEX);
6706     theEmitter->emitIns_R_R_I(INS_ldr, EA_16BYTE, REG_V8, REG_R9, 1, INS_OPTS_POST_INDEX);
6707
6708     theEmitter->emitIns_R_R_I(INS_ldr, EA_1BYTE, REG_V8, REG_R9, 1, INS_OPTS_PRE_INDEX);
6709     theEmitter->emitIns_R_R_I(INS_ldr, EA_2BYTE, REG_V8, REG_R9, 1, INS_OPTS_PRE_INDEX);
6710     theEmitter->emitIns_R_R_I(INS_ldr, EA_4BYTE, REG_V8, REG_R9, 1, INS_OPTS_PRE_INDEX);
6711     theEmitter->emitIns_R_R_I(INS_ldr, EA_8BYTE, REG_V8, REG_R9, 1, INS_OPTS_PRE_INDEX);
6712     theEmitter->emitIns_R_R_I(INS_ldr, EA_16BYTE, REG_V8, REG_R9, 1, INS_OPTS_PRE_INDEX);
6713
6714     theEmitter->emitIns_R_R_I(INS_str, EA_1BYTE, REG_V8, REG_R9, 1, INS_OPTS_POST_INDEX);
6715     theEmitter->emitIns_R_R_I(INS_str, EA_2BYTE, REG_V8, REG_R9, 1, INS_OPTS_POST_INDEX);
6716     theEmitter->emitIns_R_R_I(INS_str, EA_4BYTE, REG_V8, REG_R9, 1, INS_OPTS_POST_INDEX);
6717     theEmitter->emitIns_R_R_I(INS_str, EA_8BYTE, REG_V8, REG_R9, 1, INS_OPTS_POST_INDEX);
6718     theEmitter->emitIns_R_R_I(INS_str, EA_16BYTE, REG_V8, REG_R9, 1, INS_OPTS_POST_INDEX);
6719
6720     theEmitter->emitIns_R_R_I(INS_str, EA_1BYTE, REG_V8, REG_R9, 1, INS_OPTS_PRE_INDEX);
6721     theEmitter->emitIns_R_R_I(INS_str, EA_2BYTE, REG_V8, REG_R9, 1, INS_OPTS_PRE_INDEX);
6722     theEmitter->emitIns_R_R_I(INS_str, EA_4BYTE, REG_V8, REG_R9, 1, INS_OPTS_PRE_INDEX);
6723     theEmitter->emitIns_R_R_I(INS_str, EA_8BYTE, REG_V8, REG_R9, 1, INS_OPTS_PRE_INDEX);
6724     theEmitter->emitIns_R_R_I(INS_str, EA_16BYTE, REG_V8, REG_R9, 1, INS_OPTS_PRE_INDEX);
6725
6726     theEmitter->emitIns_R_R_I(INS_ldur, EA_1BYTE, REG_V8, REG_R9, 2);
6727     theEmitter->emitIns_R_R_I(INS_ldur, EA_2BYTE, REG_V8, REG_R9, 3);
6728     theEmitter->emitIns_R_R_I(INS_ldur, EA_4BYTE, REG_V8, REG_R9, 5);
6729     theEmitter->emitIns_R_R_I(INS_ldur, EA_8BYTE, REG_V8, REG_R9, 9);
6730     theEmitter->emitIns_R_R_I(INS_ldur, EA_16BYTE, REG_V8, REG_R9, 17);
6731
6732     theEmitter->emitIns_R_R_I(INS_stur, EA_1BYTE, REG_V7, REG_R10, 2);
6733     theEmitter->emitIns_R_R_I(INS_stur, EA_2BYTE, REG_V7, REG_R10, 3);
6734     theEmitter->emitIns_R_R_I(INS_stur, EA_4BYTE, REG_V7, REG_R10, 5);
6735     theEmitter->emitIns_R_R_I(INS_stur, EA_8BYTE, REG_V7, REG_R10, 9);
6736     theEmitter->emitIns_R_R_I(INS_stur, EA_16BYTE, REG_V7, REG_R10, 17);
6737
6738     // load/store pair
6739     theEmitter->emitIns_R_R_R(INS_ldnp, EA_8BYTE, REG_V0, REG_V1, REG_R10);
6740     theEmitter->emitIns_R_R_R_I(INS_stnp, EA_8BYTE, REG_V1, REG_V2, REG_R10, 0);
6741     theEmitter->emitIns_R_R_R_I(INS_ldnp, EA_8BYTE, REG_V2, REG_V3, REG_R10, 8);
6742     theEmitter->emitIns_R_R_R_I(INS_stnp, EA_8BYTE, REG_V3, REG_V4, REG_R10, 24);
6743
6744     theEmitter->emitIns_R_R_R(INS_ldnp, EA_4BYTE, REG_V4, REG_V5, REG_SP);
6745     theEmitter->emitIns_R_R_R_I(INS_stnp, EA_4BYTE, REG_V5, REG_V6, REG_SP, 0);
6746     theEmitter->emitIns_R_R_R_I(INS_ldnp, EA_4BYTE, REG_V6, REG_V7, REG_SP, 4);
6747     theEmitter->emitIns_R_R_R_I(INS_stnp, EA_4BYTE, REG_V7, REG_V8, REG_SP, 12);
6748
6749     theEmitter->emitIns_R_R_R(INS_ldnp, EA_16BYTE, REG_V8, REG_V9, REG_R10);
6750     theEmitter->emitIns_R_R_R_I(INS_stnp, EA_16BYTE, REG_V9, REG_V10, REG_R10, 0);
6751     theEmitter->emitIns_R_R_R_I(INS_ldnp, EA_16BYTE, REG_V10, REG_V11, REG_R10, 16);
6752     theEmitter->emitIns_R_R_R_I(INS_stnp, EA_16BYTE, REG_V11, REG_V12, REG_R10, 48);
6753
6754     theEmitter->emitIns_R_R_R(INS_ldp, EA_8BYTE, REG_V0, REG_V1, REG_R10);
6755     theEmitter->emitIns_R_R_R_I(INS_stp, EA_8BYTE, REG_V1, REG_V2, REG_SP, 0);
6756     theEmitter->emitIns_R_R_R_I(INS_ldp, EA_8BYTE, REG_V2, REG_V3, REG_SP, 8);
6757     theEmitter->emitIns_R_R_R_I(INS_stp, EA_8BYTE, REG_V3, REG_V4, REG_R10, 16);
6758     theEmitter->emitIns_R_R_R_I(INS_ldp, EA_8BYTE, REG_V4, REG_V5, REG_R10, 24, INS_OPTS_POST_INDEX);
6759     theEmitter->emitIns_R_R_R_I(INS_stp, EA_8BYTE, REG_V5, REG_V6, REG_SP, 32, INS_OPTS_POST_INDEX);
6760     theEmitter->emitIns_R_R_R_I(INS_ldp, EA_8BYTE, REG_V6, REG_V7, REG_SP, 40, INS_OPTS_PRE_INDEX);
6761     theEmitter->emitIns_R_R_R_I(INS_stp, EA_8BYTE, REG_V7, REG_V8, REG_R10, 48, INS_OPTS_PRE_INDEX);
6762
6763     theEmitter->emitIns_R_R_R(INS_ldp, EA_4BYTE, REG_V0, REG_V1, REG_R10);
6764     theEmitter->emitIns_R_R_R_I(INS_stp, EA_4BYTE, REG_V1, REG_V2, REG_SP, 0);
6765     theEmitter->emitIns_R_R_R_I(INS_ldp, EA_4BYTE, REG_V2, REG_V3, REG_SP, 4);
6766     theEmitter->emitIns_R_R_R_I(INS_stp, EA_4BYTE, REG_V3, REG_V4, REG_R10, 8);
6767     theEmitter->emitIns_R_R_R_I(INS_ldp, EA_4BYTE, REG_V4, REG_V5, REG_R10, 12, INS_OPTS_POST_INDEX);
6768     theEmitter->emitIns_R_R_R_I(INS_stp, EA_4BYTE, REG_V5, REG_V6, REG_SP, 16, INS_OPTS_POST_INDEX);
6769     theEmitter->emitIns_R_R_R_I(INS_ldp, EA_4BYTE, REG_V6, REG_V7, REG_SP, 20, INS_OPTS_PRE_INDEX);
6770     theEmitter->emitIns_R_R_R_I(INS_stp, EA_4BYTE, REG_V7, REG_V8, REG_R10, 24, INS_OPTS_PRE_INDEX);
6771
6772     theEmitter->emitIns_R_R_R(INS_ldp, EA_16BYTE, REG_V0, REG_V1, REG_R10);
6773     theEmitter->emitIns_R_R_R_I(INS_stp, EA_16BYTE, REG_V1, REG_V2, REG_SP, 0);
6774     theEmitter->emitIns_R_R_R_I(INS_ldp, EA_16BYTE, REG_V2, REG_V3, REG_SP, 16);
6775     theEmitter->emitIns_R_R_R_I(INS_stp, EA_16BYTE, REG_V3, REG_V4, REG_R10, 32);
6776     theEmitter->emitIns_R_R_R_I(INS_ldp, EA_16BYTE, REG_V4, REG_V5, REG_R10, 48, INS_OPTS_POST_INDEX);
6777     theEmitter->emitIns_R_R_R_I(INS_stp, EA_16BYTE, REG_V5, REG_V6, REG_SP, 64, INS_OPTS_POST_INDEX);
6778     theEmitter->emitIns_R_R_R_I(INS_ldp, EA_16BYTE, REG_V6, REG_V7, REG_SP, 80, INS_OPTS_PRE_INDEX);
6779     theEmitter->emitIns_R_R_R_I(INS_stp, EA_16BYTE, REG_V7, REG_V8, REG_R10, 96, INS_OPTS_PRE_INDEX);
6780
6781     // LDR (register)
6782     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_8BYTE, REG_V1, REG_SP, REG_R9);
6783     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_8BYTE, REG_V2, REG_R7, REG_R9, INS_OPTS_LSL);
6784     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_8BYTE, REG_V3, REG_R7, REG_R9, INS_OPTS_LSL, 3);
6785     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_8BYTE, REG_V4, REG_R7, REG_R9, INS_OPTS_SXTW);
6786     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_8BYTE, REG_V5, REG_R7, REG_R9, INS_OPTS_SXTW, 3);
6787     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_8BYTE, REG_V6, REG_SP, REG_R9, INS_OPTS_UXTW);
6788     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_8BYTE, REG_V7, REG_R7, REG_R9, INS_OPTS_UXTW, 3);
6789     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_8BYTE, REG_V8, REG_R7, REG_R9, INS_OPTS_SXTX);
6790     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_8BYTE, REG_V9, REG_R7, REG_R9, INS_OPTS_SXTX, 3);
6791     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_8BYTE, REG_V10, REG_R7, REG_R9, INS_OPTS_UXTX);
6792     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_8BYTE, REG_V11, REG_SP, REG_R9, INS_OPTS_UXTX, 3);
6793
6794     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_4BYTE, REG_V1, REG_SP, REG_R9);
6795     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_4BYTE, REG_V2, REG_R7, REG_R9, INS_OPTS_LSL);
6796     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_4BYTE, REG_V3, REG_R7, REG_R9, INS_OPTS_LSL, 2);
6797     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_4BYTE, REG_V4, REG_R7, REG_R9, INS_OPTS_SXTW);
6798     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_4BYTE, REG_V5, REG_R7, REG_R9, INS_OPTS_SXTW, 2);
6799     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_4BYTE, REG_V6, REG_SP, REG_R9, INS_OPTS_UXTW);
6800     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_4BYTE, REG_V7, REG_R7, REG_R9, INS_OPTS_UXTW, 2);
6801     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_4BYTE, REG_V8, REG_R7, REG_R9, INS_OPTS_SXTX);
6802     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_4BYTE, REG_V9, REG_R7, REG_R9, INS_OPTS_SXTX, 2);
6803     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_4BYTE, REG_V10, REG_R7, REG_R9, INS_OPTS_UXTX);
6804     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_4BYTE, REG_V11, REG_SP, REG_R9, INS_OPTS_UXTX, 2);
6805
6806     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_16BYTE, REG_V1, REG_SP, REG_R9);
6807     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_16BYTE, REG_V2, REG_R7, REG_R9, INS_OPTS_LSL);
6808     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_16BYTE, REG_V3, REG_R7, REG_R9, INS_OPTS_LSL, 4);
6809     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_16BYTE, REG_V4, REG_R7, REG_R9, INS_OPTS_SXTW);
6810     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_16BYTE, REG_V5, REG_R7, REG_R9, INS_OPTS_SXTW, 4);
6811     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_16BYTE, REG_V6, REG_SP, REG_R9, INS_OPTS_UXTW);
6812     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_16BYTE, REG_V7, REG_R7, REG_R9, INS_OPTS_UXTW, 4);
6813     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_16BYTE, REG_V8, REG_R7, REG_R9, INS_OPTS_SXTX);
6814     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_16BYTE, REG_V9, REG_R7, REG_R9, INS_OPTS_SXTX, 4);
6815     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_16BYTE, REG_V10, REG_R7, REG_R9, INS_OPTS_UXTX);
6816     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_16BYTE, REG_V11, REG_SP, REG_R9, INS_OPTS_UXTX, 4);
6817
6818     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_2BYTE, REG_V1, REG_SP, REG_R9);
6819     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_2BYTE, REG_V2, REG_R7, REG_R9, INS_OPTS_LSL);
6820     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_2BYTE, REG_V3, REG_R7, REG_R9, INS_OPTS_LSL, 1);
6821     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_2BYTE, REG_V4, REG_R7, REG_R9, INS_OPTS_SXTW);
6822     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_2BYTE, REG_V5, REG_R7, REG_R9, INS_OPTS_SXTW, 1);
6823     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_2BYTE, REG_V6, REG_SP, REG_R9, INS_OPTS_UXTW);
6824     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_2BYTE, REG_V7, REG_R7, REG_R9, INS_OPTS_UXTW, 1);
6825     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_2BYTE, REG_V8, REG_R7, REG_R9, INS_OPTS_SXTX);
6826     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_2BYTE, REG_V9, REG_R7, REG_R9, INS_OPTS_SXTX, 1);
6827     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_2BYTE, REG_V10, REG_R7, REG_R9, INS_OPTS_UXTX);
6828     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_2BYTE, REG_V11, REG_SP, REG_R9, INS_OPTS_UXTX, 1);
6829
6830     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_1BYTE, REG_V1, REG_R7, REG_R9);
6831     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_1BYTE, REG_V2, REG_SP, REG_R9, INS_OPTS_SXTW);
6832     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_1BYTE, REG_V3, REG_R7, REG_R9, INS_OPTS_UXTW);
6833     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_1BYTE, REG_V4, REG_SP, REG_R9, INS_OPTS_SXTX);
6834     theEmitter->emitIns_R_R_R_Ext(INS_ldr, EA_1BYTE, REG_V5, REG_R7, REG_R9, INS_OPTS_UXTX);
6835
6836 #endif // ALL_ARM64_EMITTER_UNIT_TESTS
6837
6838 #ifdef ALL_ARM64_EMITTER_UNIT_TESTS
6839     //
6840     // R_R   mov and aliases for mov
6841     //
6842
6843     // mov vector to vector
6844     theEmitter->emitIns_R_R(INS_mov, EA_8BYTE, REG_V0, REG_V1);
6845     theEmitter->emitIns_R_R(INS_mov, EA_16BYTE, REG_V2, REG_V3);
6846
6847     theEmitter->emitIns_R_R(INS_mov, EA_4BYTE, REG_V12, REG_V13);
6848     theEmitter->emitIns_R_R(INS_mov, EA_2BYTE, REG_V14, REG_V15);
6849     theEmitter->emitIns_R_R(INS_mov, EA_1BYTE, REG_V16, REG_V17);
6850
6851     // mov vector to general
6852     theEmitter->emitIns_R_R(INS_mov, EA_8BYTE, REG_R0, REG_V4);
6853     theEmitter->emitIns_R_R(INS_mov, EA_4BYTE, REG_R1, REG_V5);
6854     theEmitter->emitIns_R_R(INS_mov, EA_2BYTE, REG_R2, REG_V6);
6855     theEmitter->emitIns_R_R(INS_mov, EA_1BYTE, REG_R3, REG_V7);
6856
6857     // mov general to vector
6858     theEmitter->emitIns_R_R(INS_mov, EA_8BYTE, REG_V8, REG_R4);
6859     theEmitter->emitIns_R_R(INS_mov, EA_4BYTE, REG_V9, REG_R5);
6860     theEmitter->emitIns_R_R(INS_mov, EA_2BYTE, REG_V10, REG_R6);
6861     theEmitter->emitIns_R_R(INS_mov, EA_1BYTE, REG_V11, REG_R7);
6862
6863     // mov vector[index] to vector
6864     theEmitter->emitIns_R_R_I(INS_mov, EA_8BYTE, REG_V0, REG_V1, 1);
6865     theEmitter->emitIns_R_R_I(INS_mov, EA_4BYTE, REG_V2, REG_V3, 3);
6866     theEmitter->emitIns_R_R_I(INS_mov, EA_2BYTE, REG_V4, REG_V5, 7);
6867     theEmitter->emitIns_R_R_I(INS_mov, EA_1BYTE, REG_V6, REG_V7, 15);
6868
6869     // mov to general from vector[index]
6870     theEmitter->emitIns_R_R_I(INS_mov, EA_8BYTE, REG_R8, REG_V16, 1);
6871     theEmitter->emitIns_R_R_I(INS_mov, EA_4BYTE, REG_R9, REG_V17, 2);
6872     theEmitter->emitIns_R_R_I(INS_mov, EA_2BYTE, REG_R10, REG_V18, 3);
6873     theEmitter->emitIns_R_R_I(INS_mov, EA_1BYTE, REG_R11, REG_V19, 4);
6874
6875     // mov to vector[index] from general
6876     theEmitter->emitIns_R_R_I(INS_mov, EA_8BYTE, REG_V20, REG_R12, 1);
6877     theEmitter->emitIns_R_R_I(INS_mov, EA_4BYTE, REG_V21, REG_R13, 2);
6878     theEmitter->emitIns_R_R_I(INS_mov, EA_2BYTE, REG_V22, REG_R14, 6);
6879     theEmitter->emitIns_R_R_I(INS_mov, EA_1BYTE, REG_V23, REG_R15, 8);
6880
6881     // mov vector[index] to vector[index2]
6882     theEmitter->emitIns_R_R_I_I(INS_mov, EA_8BYTE, REG_V8, REG_V9, 1, 0);
6883     theEmitter->emitIns_R_R_I_I(INS_mov, EA_4BYTE, REG_V10, REG_V11, 2, 1);
6884     theEmitter->emitIns_R_R_I_I(INS_mov, EA_2BYTE, REG_V12, REG_V13, 5, 2);
6885     theEmitter->emitIns_R_R_I_I(INS_mov, EA_1BYTE, REG_V14, REG_V15, 12, 3);
6886
6887     //////////////////////////////////////////////////////////////////////////////////
6888
6889     // mov/dup scalar
6890     theEmitter->emitIns_R_R_I(INS_dup, EA_8BYTE, REG_V24, REG_V25, 1);
6891     theEmitter->emitIns_R_R_I(INS_dup, EA_4BYTE, REG_V26, REG_V27, 3);
6892     theEmitter->emitIns_R_R_I(INS_dup, EA_2BYTE, REG_V28, REG_V29, 7);
6893     theEmitter->emitIns_R_R_I(INS_dup, EA_1BYTE, REG_V30, REG_V31, 15);
6894
6895     // mov/ins vector element
6896     theEmitter->emitIns_R_R_I_I(INS_ins, EA_8BYTE, REG_V0, REG_V1, 0, 1);
6897     theEmitter->emitIns_R_R_I_I(INS_ins, EA_4BYTE, REG_V2, REG_V3, 2, 2);
6898     theEmitter->emitIns_R_R_I_I(INS_ins, EA_2BYTE, REG_V4, REG_V5, 4, 3);
6899     theEmitter->emitIns_R_R_I_I(INS_ins, EA_1BYTE, REG_V6, REG_V7, 8, 4);
6900
6901     // umov to general from vector element
6902     theEmitter->emitIns_R_R_I(INS_umov, EA_8BYTE, REG_R0, REG_V8, 1);
6903     theEmitter->emitIns_R_R_I(INS_umov, EA_4BYTE, REG_R1, REG_V9, 2);
6904     theEmitter->emitIns_R_R_I(INS_umov, EA_2BYTE, REG_R2, REG_V10, 4);
6905     theEmitter->emitIns_R_R_I(INS_umov, EA_1BYTE, REG_R3, REG_V11, 8);
6906
6907     // ins to vector element from general
6908     theEmitter->emitIns_R_R_I(INS_ins, EA_8BYTE, REG_V12, REG_R4, 1);
6909     theEmitter->emitIns_R_R_I(INS_ins, EA_4BYTE, REG_V13, REG_R5, 3);
6910     theEmitter->emitIns_R_R_I(INS_ins, EA_2BYTE, REG_V14, REG_R6, 7);
6911     theEmitter->emitIns_R_R_I(INS_ins, EA_1BYTE, REG_V15, REG_R7, 15);
6912
6913     // smov to general from vector element
6914     theEmitter->emitIns_R_R_I(INS_smov, EA_4BYTE, REG_R5, REG_V17, 2);
6915     theEmitter->emitIns_R_R_I(INS_smov, EA_2BYTE, REG_R6, REG_V18, 4);
6916     theEmitter->emitIns_R_R_I(INS_smov, EA_1BYTE, REG_R7, REG_V19, 8);
6917
6918 #endif // ALL_ARM64_EMITTER_UNIT_TESTS
6919
6920 #ifdef ALL_ARM64_EMITTER_UNIT_TESTS
6921     //
6922     // R_I   movi and mvni
6923     //
6924
6925     // movi  imm8  (vector)
6926     theEmitter->emitIns_R_I(INS_movi, EA_8BYTE, REG_V0, 0x00, INS_OPTS_8B);
6927     theEmitter->emitIns_R_I(INS_movi, EA_8BYTE, REG_V1, 0xFF, INS_OPTS_8B);
6928     theEmitter->emitIns_R_I(INS_movi, EA_16BYTE, REG_V2, 0x00, INS_OPTS_16B);
6929     theEmitter->emitIns_R_I(INS_movi, EA_16BYTE, REG_V3, 0xFF, INS_OPTS_16B);
6930
6931     theEmitter->emitIns_R_I(INS_movi, EA_8BYTE, REG_V4, 0x007F, INS_OPTS_4H);
6932     theEmitter->emitIns_R_I(INS_movi, EA_8BYTE, REG_V5, 0x7F00, INS_OPTS_4H); // LSL  8
6933     theEmitter->emitIns_R_I(INS_movi, EA_16BYTE, REG_V6, 0x003F, INS_OPTS_8H);
6934     theEmitter->emitIns_R_I(INS_movi, EA_16BYTE, REG_V7, 0x3F00, INS_OPTS_8H); // LSL  8
6935
6936     theEmitter->emitIns_R_I(INS_movi, EA_8BYTE, REG_V8, 0x1F, INS_OPTS_2S);
6937     theEmitter->emitIns_R_I(INS_movi, EA_8BYTE, REG_V9, 0x1F00, INS_OPTS_2S);      // LSL  8
6938     theEmitter->emitIns_R_I(INS_movi, EA_8BYTE, REG_V10, 0x1F0000, INS_OPTS_2S);   // LSL 16
6939     theEmitter->emitIns_R_I(INS_movi, EA_8BYTE, REG_V11, 0x1F000000, INS_OPTS_2S); // LSL 24
6940
6941     theEmitter->emitIns_R_I(INS_movi, EA_8BYTE, REG_V12, 0x1FFF, INS_OPTS_2S);   // MSL  8
6942     theEmitter->emitIns_R_I(INS_movi, EA_8BYTE, REG_V13, 0x1FFFFF, INS_OPTS_2S); // MSL 16
6943
6944     theEmitter->emitIns_R_I(INS_movi, EA_16BYTE, REG_V14, 0x37, INS_OPTS_4S);
6945     theEmitter->emitIns_R_I(INS_movi, EA_16BYTE, REG_V15, 0x3700, INS_OPTS_4S);     // LSL  8
6946     theEmitter->emitIns_R_I(INS_movi, EA_16BYTE, REG_V16, 0x370000, INS_OPTS_4S);   // LSL 16
6947     theEmitter->emitIns_R_I(INS_movi, EA_16BYTE, REG_V17, 0x37000000, INS_OPTS_4S); // LSL 24
6948
6949     theEmitter->emitIns_R_I(INS_movi, EA_16BYTE, REG_V18, 0x37FF, INS_OPTS_4S);   // MSL  8
6950     theEmitter->emitIns_R_I(INS_movi, EA_16BYTE, REG_V19, 0x37FFFF, INS_OPTS_4S); // MSL 16
6951
6952     theEmitter->emitIns_R_I(INS_movi, EA_8BYTE, REG_V20, 0xFF80, INS_OPTS_4H);  // mvni
6953     theEmitter->emitIns_R_I(INS_movi, EA_16BYTE, REG_V21, 0xFFC0, INS_OPTS_8H); // mvni
6954
6955     theEmitter->emitIns_R_I(INS_movi, EA_8BYTE, REG_V22, 0xFFFFFFE0, INS_OPTS_2S);  // mvni
6956     theEmitter->emitIns_R_I(INS_movi, EA_16BYTE, REG_V23, 0xFFFFF0FF, INS_OPTS_4S); // mvni LSL  8
6957     theEmitter->emitIns_R_I(INS_movi, EA_8BYTE, REG_V24, 0xFFF8FFFF, INS_OPTS_2S);  // mvni LSL 16
6958     theEmitter->emitIns_R_I(INS_movi, EA_16BYTE, REG_V25, 0xFCFFFFFF, INS_OPTS_4S); // mvni LSL 24
6959
6960     theEmitter->emitIns_R_I(INS_movi, EA_8BYTE, REG_V26, 0xFFFFFE00, INS_OPTS_2S);  // mvni MSL  8
6961     theEmitter->emitIns_R_I(INS_movi, EA_16BYTE, REG_V27, 0xFFFC0000, INS_OPTS_4S); // mvni MSL 16
6962
6963     theEmitter->emitIns_R_I(INS_movi, EA_8BYTE, REG_V28, 0x00FF00FF00FF00FF, INS_OPTS_1D);
6964     theEmitter->emitIns_R_I(INS_movi, EA_16BYTE, REG_V29, 0x00FFFF0000FFFF00, INS_OPTS_2D);
6965     theEmitter->emitIns_R_I(INS_movi, EA_8BYTE, REG_V30, 0xFF000000FF000000);
6966     theEmitter->emitIns_R_I(INS_movi, EA_16BYTE, REG_V31, 0x0, INS_OPTS_2D);
6967
6968     theEmitter->emitIns_R_I(INS_mvni, EA_8BYTE, REG_V0, 0x0022, INS_OPTS_4H);
6969     theEmitter->emitIns_R_I(INS_mvni, EA_8BYTE, REG_V1, 0x2200, INS_OPTS_4H); // LSL  8
6970     theEmitter->emitIns_R_I(INS_mvni, EA_16BYTE, REG_V2, 0x0033, INS_OPTS_8H);
6971     theEmitter->emitIns_R_I(INS_mvni, EA_16BYTE, REG_V3, 0x3300, INS_OPTS_8H); // LSL  8
6972
6973     theEmitter->emitIns_R_I(INS_mvni, EA_8BYTE, REG_V4, 0x42, INS_OPTS_2S);
6974     theEmitter->emitIns_R_I(INS_mvni, EA_8BYTE, REG_V5, 0x4200, INS_OPTS_2S);     // LSL  8
6975     theEmitter->emitIns_R_I(INS_mvni, EA_8BYTE, REG_V6, 0x420000, INS_OPTS_2S);   // LSL 16
6976     theEmitter->emitIns_R_I(INS_mvni, EA_8BYTE, REG_V7, 0x42000000, INS_OPTS_2S); // LSL 24
6977
6978     theEmitter->emitIns_R_I(INS_mvni, EA_8BYTE, REG_V8, 0x42FF, INS_OPTS_2S);   // MSL  8
6979     theEmitter->emitIns_R_I(INS_mvni, EA_8BYTE, REG_V9, 0x42FFFF, INS_OPTS_2S); // MSL 16
6980
6981     theEmitter->emitIns_R_I(INS_mvni, EA_16BYTE, REG_V10, 0x5D, INS_OPTS_4S);
6982     theEmitter->emitIns_R_I(INS_mvni, EA_16BYTE, REG_V11, 0x5D00, INS_OPTS_4S);     // LSL  8
6983     theEmitter->emitIns_R_I(INS_mvni, EA_16BYTE, REG_V12, 0x5D0000, INS_OPTS_4S);   // LSL 16
6984     theEmitter->emitIns_R_I(INS_mvni, EA_16BYTE, REG_V13, 0x5D000000, INS_OPTS_4S); // LSL 24
6985
6986     theEmitter->emitIns_R_I(INS_mvni, EA_16BYTE, REG_V14, 0x5DFF, INS_OPTS_4S);   // MSL  8
6987     theEmitter->emitIns_R_I(INS_mvni, EA_16BYTE, REG_V15, 0x5DFFFF, INS_OPTS_4S); // MSL 16
6988
6989 #endif // ALL_ARM64_EMITTER_UNIT_TESTS
6990
6991 #ifdef ALL_ARM64_EMITTER_UNIT_TESTS
6992     //
6993     // R_I   orr/bic vector immediate
6994     //
6995
6996     theEmitter->emitIns_R_I(INS_orr, EA_8BYTE, REG_V0, 0x0022, INS_OPTS_4H);
6997     theEmitter->emitIns_R_I(INS_orr, EA_8BYTE, REG_V1, 0x2200, INS_OPTS_4H); // LSL  8
6998     theEmitter->emitIns_R_I(INS_orr, EA_16BYTE, REG_V2, 0x0033, INS_OPTS_8H);
6999     theEmitter->emitIns_R_I(INS_orr, EA_16BYTE, REG_V3, 0x3300, INS_OPTS_8H); // LSL  8
7000
7001     theEmitter->emitIns_R_I(INS_orr, EA_8BYTE, REG_V4, 0x42, INS_OPTS_2S);
7002     theEmitter->emitIns_R_I(INS_orr, EA_8BYTE, REG_V5, 0x4200, INS_OPTS_2S);     // LSL  8
7003     theEmitter->emitIns_R_I(INS_orr, EA_8BYTE, REG_V6, 0x420000, INS_OPTS_2S);   // LSL 16
7004     theEmitter->emitIns_R_I(INS_orr, EA_8BYTE, REG_V7, 0x42000000, INS_OPTS_2S); // LSL 24
7005
7006     theEmitter->emitIns_R_I(INS_orr, EA_16BYTE, REG_V10, 0x5D, INS_OPTS_4S);
7007     theEmitter->emitIns_R_I(INS_orr, EA_16BYTE, REG_V11, 0x5D00, INS_OPTS_4S);     // LSL  8
7008     theEmitter->emitIns_R_I(INS_orr, EA_16BYTE, REG_V12, 0x5D0000, INS_OPTS_4S);   // LSL 16
7009     theEmitter->emitIns_R_I(INS_orr, EA_16BYTE, REG_V13, 0x5D000000, INS_OPTS_4S); // LSL 24
7010
7011     theEmitter->emitIns_R_I(INS_bic, EA_8BYTE, REG_V0, 0x0022, INS_OPTS_4H);
7012     theEmitter->emitIns_R_I(INS_bic, EA_8BYTE, REG_V1, 0x2200, INS_OPTS_4H); // LSL  8
7013     theEmitter->emitIns_R_I(INS_bic, EA_16BYTE, REG_V2, 0x0033, INS_OPTS_8H);
7014     theEmitter->emitIns_R_I(INS_bic, EA_16BYTE, REG_V3, 0x3300, INS_OPTS_8H); // LSL  8
7015
7016     theEmitter->emitIns_R_I(INS_bic, EA_8BYTE, REG_V4, 0x42, INS_OPTS_2S);
7017     theEmitter->emitIns_R_I(INS_bic, EA_8BYTE, REG_V5, 0x4200, INS_OPTS_2S);     // LSL  8
7018     theEmitter->emitIns_R_I(INS_bic, EA_8BYTE, REG_V6, 0x420000, INS_OPTS_2S);   // LSL 16
7019     theEmitter->emitIns_R_I(INS_bic, EA_8BYTE, REG_V7, 0x42000000, INS_OPTS_2S); // LSL 24
7020
7021     theEmitter->emitIns_R_I(INS_bic, EA_16BYTE, REG_V10, 0x5D, INS_OPTS_4S);
7022     theEmitter->emitIns_R_I(INS_bic, EA_16BYTE, REG_V11, 0x5D00, INS_OPTS_4S);     // LSL  8
7023     theEmitter->emitIns_R_I(INS_bic, EA_16BYTE, REG_V12, 0x5D0000, INS_OPTS_4S);   // LSL 16
7024     theEmitter->emitIns_R_I(INS_bic, EA_16BYTE, REG_V13, 0x5D000000, INS_OPTS_4S); // LSL 24
7025
7026 #endif // ALL_ARM64_EMITTER_UNIT_TESTS
7027
7028 #ifdef ALL_ARM64_EMITTER_UNIT_TESTS
7029     //
7030     // R_F   cmp/fmov immediate
7031     //
7032
7033     // fmov  imm8  (scalar)
7034     theEmitter->emitIns_R_F(INS_fmov, EA_8BYTE, REG_V14, 1.0);
7035     theEmitter->emitIns_R_F(INS_fmov, EA_4BYTE, REG_V15, -1.0);
7036     theEmitter->emitIns_R_F(INS_fmov, EA_4BYTE, REG_V0, 2.0); // encodes imm8 == 0
7037     theEmitter->emitIns_R_F(INS_fmov, EA_4BYTE, REG_V16, 10.0);
7038     theEmitter->emitIns_R_F(INS_fmov, EA_8BYTE, REG_V17, -10.0);
7039     theEmitter->emitIns_R_F(INS_fmov, EA_8BYTE, REG_V18, 31); // Largest encodable value
7040     theEmitter->emitIns_R_F(INS_fmov, EA_4BYTE, REG_V19, -31);
7041     theEmitter->emitIns_R_F(INS_fmov, EA_4BYTE, REG_V20, 1.25);
7042     theEmitter->emitIns_R_F(INS_fmov, EA_8BYTE, REG_V21, -1.25);
7043     theEmitter->emitIns_R_F(INS_fmov, EA_8BYTE, REG_V22, 0.125); // Smallest encodable value
7044     theEmitter->emitIns_R_F(INS_fmov, EA_4BYTE, REG_V23, -0.125);
7045
7046     // fmov  imm8  (vector)
7047     theEmitter->emitIns_R_F(INS_fmov, EA_8BYTE, REG_V0, 2.0, INS_OPTS_2S);
7048     theEmitter->emitIns_R_F(INS_fmov, EA_8BYTE, REG_V24, 1.0, INS_OPTS_2S);
7049     theEmitter->emitIns_R_F(INS_fmov, EA_16BYTE, REG_V25, 1.0, INS_OPTS_4S);
7050     theEmitter->emitIns_R_F(INS_fmov, EA_16BYTE, REG_V26, 1.0, INS_OPTS_2D);
7051     theEmitter->emitIns_R_F(INS_fmov, EA_8BYTE, REG_V27, -10.0, INS_OPTS_2S);
7052     theEmitter->emitIns_R_F(INS_fmov, EA_16BYTE, REG_V28, -10.0, INS_OPTS_4S);
7053     theEmitter->emitIns_R_F(INS_fmov, EA_16BYTE, REG_V29, -10.0, INS_OPTS_2D);
7054     theEmitter->emitIns_R_F(INS_fmov, EA_8BYTE, REG_V30, 31.0, INS_OPTS_2S);
7055     theEmitter->emitIns_R_F(INS_fmov, EA_16BYTE, REG_V31, 31.0, INS_OPTS_4S);
7056     theEmitter->emitIns_R_F(INS_fmov, EA_16BYTE, REG_V0, 31.0, INS_OPTS_2D);
7057     theEmitter->emitIns_R_F(INS_fmov, EA_8BYTE, REG_V1, -0.125, INS_OPTS_2S);
7058     theEmitter->emitIns_R_F(INS_fmov, EA_16BYTE, REG_V2, -0.125, INS_OPTS_4S);
7059     theEmitter->emitIns_R_F(INS_fmov, EA_16BYTE, REG_V3, -0.125, INS_OPTS_2D);
7060
7061     // fcmp with 0.0
7062     theEmitter->emitIns_R_F(INS_fcmp, EA_8BYTE, REG_V12, 0.0);
7063     theEmitter->emitIns_R_F(INS_fcmp, EA_4BYTE, REG_V13, 0.0);
7064     theEmitter->emitIns_R_F(INS_fcmpe, EA_8BYTE, REG_V14, 0.0);
7065     theEmitter->emitIns_R_F(INS_fcmpe, EA_4BYTE, REG_V15, 0.0);
7066
7067 #endif // ALL_ARM64_EMITTER_UNIT_TESTS
7068
7069 #ifdef ALL_ARM64_EMITTER_UNIT_TESTS
7070     //
7071     // R_R   fmov/fcmp/fcvt
7072     //
7073
7074     // fmov to vector to vector
7075     theEmitter->emitIns_R_R(INS_fmov, EA_8BYTE, REG_V0, REG_V2);
7076     theEmitter->emitIns_R_R(INS_fmov, EA_4BYTE, REG_V1, REG_V3);
7077
7078     // fmov to vector to general
7079     theEmitter->emitIns_R_R(INS_fmov, EA_8BYTE, REG_R0, REG_V4);
7080     theEmitter->emitIns_R_R(INS_fmov, EA_4BYTE, REG_R1, REG_V5);
7081     //    using the optional conversion specifier
7082     theEmitter->emitIns_R_R(INS_fmov, EA_8BYTE, REG_R2, REG_V6, INS_OPTS_D_TO_8BYTE);
7083     theEmitter->emitIns_R_R(INS_fmov, EA_4BYTE, REG_R3, REG_V7, INS_OPTS_S_TO_4BYTE);
7084
7085     // fmov to general to vector
7086     theEmitter->emitIns_R_R(INS_fmov, EA_8BYTE, REG_V8, REG_R4);
7087     theEmitter->emitIns_R_R(INS_fmov, EA_4BYTE, REG_V9, REG_R5);
7088     //   using the optional conversion specifier
7089     theEmitter->emitIns_R_R(INS_fmov, EA_8BYTE, REG_V10, REG_R6, INS_OPTS_8BYTE_TO_D);
7090     theEmitter->emitIns_R_R(INS_fmov, EA_4BYTE, REG_V11, REG_R7, INS_OPTS_4BYTE_TO_S);
7091
7092     // fcmp/fcmpe
7093     theEmitter->emitIns_R_R(INS_fcmp, EA_8BYTE, REG_V8, REG_V16);
7094     theEmitter->emitIns_R_R(INS_fcmp, EA_4BYTE, REG_V9, REG_V17);
7095     theEmitter->emitIns_R_R(INS_fcmpe, EA_8BYTE, REG_V10, REG_V18);
7096     theEmitter->emitIns_R_R(INS_fcmpe, EA_4BYTE, REG_V11, REG_V19);
7097
7098     // fcvt
7099     theEmitter->emitIns_R_R(INS_fcvt, EA_8BYTE, REG_V24, REG_V25, INS_OPTS_S_TO_D); // Single to Double
7100     theEmitter->emitIns_R_R(INS_fcvt, EA_4BYTE, REG_V26, REG_V27, INS_OPTS_D_TO_S); // Double to Single
7101
7102     theEmitter->emitIns_R_R(INS_fcvt, EA_4BYTE, REG_V1, REG_V2, INS_OPTS_H_TO_S);
7103     theEmitter->emitIns_R_R(INS_fcvt, EA_8BYTE, REG_V3, REG_V4, INS_OPTS_H_TO_D);
7104
7105     theEmitter->emitIns_R_R(INS_fcvt, EA_2BYTE, REG_V5, REG_V6, INS_OPTS_S_TO_H);
7106     theEmitter->emitIns_R_R(INS_fcvt, EA_2BYTE, REG_V7, REG_V8, INS_OPTS_D_TO_H);
7107
7108 #endif // ALL_ARM64_EMITTER_UNIT_TESTS
7109
7110 #ifdef ALL_ARM64_EMITTER_UNIT_TESTS
7111     //
7112     // R_R   floating point conversions
7113     //
7114
7115     // fcvtas scalar
7116     theEmitter->emitIns_R_R(INS_fcvtas, EA_4BYTE, REG_V0, REG_V1);
7117     theEmitter->emitIns_R_R(INS_fcvtas, EA_8BYTE, REG_V2, REG_V3);
7118
7119     // fcvtas scalar to general
7120     theEmitter->emitIns_R_R(INS_fcvtas, EA_4BYTE, REG_R0, REG_V4, INS_OPTS_S_TO_4BYTE);
7121     theEmitter->emitIns_R_R(INS_fcvtas, EA_4BYTE, REG_R1, REG_V5, INS_OPTS_D_TO_4BYTE);
7122     theEmitter->emitIns_R_R(INS_fcvtas, EA_8BYTE, REG_R2, REG_V6, INS_OPTS_S_TO_8BYTE);
7123     theEmitter->emitIns_R_R(INS_fcvtas, EA_8BYTE, REG_R3, REG_V7, INS_OPTS_D_TO_8BYTE);
7124
7125     // fcvtas vector
7126     theEmitter->emitIns_R_R(INS_fcvtas, EA_8BYTE, REG_V8, REG_V9, INS_OPTS_2S);
7127     theEmitter->emitIns_R_R(INS_fcvtas, EA_16BYTE, REG_V10, REG_V11, INS_OPTS_4S);
7128     theEmitter->emitIns_R_R(INS_fcvtas, EA_16BYTE, REG_V12, REG_V13, INS_OPTS_2D);
7129
7130     // fcvtau scalar
7131     theEmitter->emitIns_R_R(INS_fcvtau, EA_4BYTE, REG_V0, REG_V1);
7132     theEmitter->emitIns_R_R(INS_fcvtau, EA_8BYTE, REG_V2, REG_V3);
7133
7134     // fcvtau scalar to general
7135     theEmitter->emitIns_R_R(INS_fcvtau, EA_4BYTE, REG_R0, REG_V4, INS_OPTS_S_TO_4BYTE);
7136     theEmitter->emitIns_R_R(INS_fcvtau, EA_4BYTE, REG_R1, REG_V5, INS_OPTS_D_TO_4BYTE);
7137     theEmitter->emitIns_R_R(INS_fcvtau, EA_8BYTE, REG_R2, REG_V6, INS_OPTS_S_TO_8BYTE);
7138     theEmitter->emitIns_R_R(INS_fcvtau, EA_8BYTE, REG_R3, REG_V7, INS_OPTS_D_TO_8BYTE);
7139
7140     // fcvtau vector
7141     theEmitter->emitIns_R_R(INS_fcvtau, EA_8BYTE, REG_V8, REG_V9, INS_OPTS_2S);
7142     theEmitter->emitIns_R_R(INS_fcvtau, EA_16BYTE, REG_V10, REG_V11, INS_OPTS_4S);
7143     theEmitter->emitIns_R_R(INS_fcvtau, EA_16BYTE, REG_V12, REG_V13, INS_OPTS_2D);
7144
7145     ////////////////////////////////////////////////////////////////////////////////
7146
7147     // fcvtms scalar
7148     theEmitter->emitIns_R_R(INS_fcvtms, EA_4BYTE, REG_V0, REG_V1);
7149     theEmitter->emitIns_R_R(INS_fcvtms, EA_8BYTE, REG_V2, REG_V3);
7150
7151     // fcvtms scalar to general
7152     theEmitter->emitIns_R_R(INS_fcvtms, EA_4BYTE, REG_R0, REG_V4, INS_OPTS_S_TO_4BYTE);
7153     theEmitter->emitIns_R_R(INS_fcvtms, EA_4BYTE, REG_R1, REG_V5, INS_OPTS_D_TO_4BYTE);
7154     theEmitter->emitIns_R_R(INS_fcvtms, EA_8BYTE, REG_R2, REG_V6, INS_OPTS_S_TO_8BYTE);
7155     theEmitter->emitIns_R_R(INS_fcvtms, EA_8BYTE, REG_R3, REG_V7, INS_OPTS_D_TO_8BYTE);
7156
7157     // fcvtms vector
7158     theEmitter->emitIns_R_R(INS_fcvtms, EA_8BYTE, REG_V8, REG_V9, INS_OPTS_2S);
7159     theEmitter->emitIns_R_R(INS_fcvtms, EA_16BYTE, REG_V10, REG_V11, INS_OPTS_4S);
7160     theEmitter->emitIns_R_R(INS_fcvtms, EA_16BYTE, REG_V12, REG_V13, INS_OPTS_2D);
7161
7162     // fcvtmu scalar
7163     theEmitter->emitIns_R_R(INS_fcvtmu, EA_4BYTE, REG_V0, REG_V1);
7164     theEmitter->emitIns_R_R(INS_fcvtmu, EA_8BYTE, REG_V2, REG_V3);
7165
7166     // fcvtmu scalar to general
7167     theEmitter->emitIns_R_R(INS_fcvtmu, EA_4BYTE, REG_R0, REG_V4, INS_OPTS_S_TO_4BYTE);
7168     theEmitter->emitIns_R_R(INS_fcvtmu, EA_4BYTE, REG_R1, REG_V5, INS_OPTS_D_TO_4BYTE);
7169     theEmitter->emitIns_R_R(INS_fcvtmu, EA_8BYTE, REG_R2, REG_V6, INS_OPTS_S_TO_8BYTE);
7170     theEmitter->emitIns_R_R(INS_fcvtmu, EA_8BYTE, REG_R3, REG_V7, INS_OPTS_D_TO_8BYTE);
7171
7172     // fcvtmu vector
7173     theEmitter->emitIns_R_R(INS_fcvtmu, EA_8BYTE, REG_V8, REG_V9, INS_OPTS_2S);
7174     theEmitter->emitIns_R_R(INS_fcvtmu, EA_16BYTE, REG_V10, REG_V11, INS_OPTS_4S);
7175     theEmitter->emitIns_R_R(INS_fcvtmu, EA_16BYTE, REG_V12, REG_V13, INS_OPTS_2D);
7176
7177     ////////////////////////////////////////////////////////////////////////////////
7178
7179     // fcvtns scalar
7180     theEmitter->emitIns_R_R(INS_fcvtns, EA_4BYTE, REG_V0, REG_V1);
7181     theEmitter->emitIns_R_R(INS_fcvtns, EA_8BYTE, REG_V2, REG_V3);
7182
7183     // fcvtns scalar to general
7184     theEmitter->emitIns_R_R(INS_fcvtns, EA_4BYTE, REG_R0, REG_V4, INS_OPTS_S_TO_4BYTE);
7185     theEmitter->emitIns_R_R(INS_fcvtns, EA_4BYTE, REG_R1, REG_V5, INS_OPTS_D_TO_4BYTE);
7186     theEmitter->emitIns_R_R(INS_fcvtns, EA_8BYTE, REG_R2, REG_V6, INS_OPTS_S_TO_8BYTE);
7187     theEmitter->emitIns_R_R(INS_fcvtns, EA_8BYTE, REG_R3, REG_V7, INS_OPTS_D_TO_8BYTE);
7188
7189     // fcvtns vector
7190     theEmitter->emitIns_R_R(INS_fcvtns, EA_8BYTE, REG_V8, REG_V9, INS_OPTS_2S);
7191     theEmitter->emitIns_R_R(INS_fcvtns, EA_16BYTE, REG_V10, REG_V11, INS_OPTS_4S);
7192     theEmitter->emitIns_R_R(INS_fcvtns, EA_16BYTE, REG_V12, REG_V13, INS_OPTS_2D);
7193
7194     // fcvtnu scalar
7195     theEmitter->emitIns_R_R(INS_fcvtnu, EA_4BYTE, REG_V0, REG_V1);
7196     theEmitter->emitIns_R_R(INS_fcvtnu, EA_8BYTE, REG_V2, REG_V3);
7197
7198     // fcvtnu scalar to general
7199     theEmitter->emitIns_R_R(INS_fcvtnu, EA_4BYTE, REG_R0, REG_V4, INS_OPTS_S_TO_4BYTE);
7200     theEmitter->emitIns_R_R(INS_fcvtnu, EA_4BYTE, REG_R1, REG_V5, INS_OPTS_D_TO_4BYTE);
7201     theEmitter->emitIns_R_R(INS_fcvtnu, EA_8BYTE, REG_R2, REG_V6, INS_OPTS_S_TO_8BYTE);
7202     theEmitter->emitIns_R_R(INS_fcvtnu, EA_8BYTE, REG_R3, REG_V7, INS_OPTS_D_TO_8BYTE);
7203
7204     // fcvtnu vector
7205     theEmitter->emitIns_R_R(INS_fcvtnu, EA_8BYTE, REG_V8, REG_V9, INS_OPTS_2S);
7206     theEmitter->emitIns_R_R(INS_fcvtnu, EA_16BYTE, REG_V10, REG_V11, INS_OPTS_4S);
7207     theEmitter->emitIns_R_R(INS_fcvtnu, EA_16BYTE, REG_V12, REG_V13, INS_OPTS_2D);
7208
7209     ////////////////////////////////////////////////////////////////////////////////
7210
7211     // fcvtps scalar
7212     theEmitter->emitIns_R_R(INS_fcvtps, EA_4BYTE, REG_V0, REG_V1);
7213     theEmitter->emitIns_R_R(INS_fcvtps, EA_8BYTE, REG_V2, REG_V3);
7214
7215     // fcvtps scalar to general
7216     theEmitter->emitIns_R_R(INS_fcvtps, EA_4BYTE, REG_R0, REG_V4, INS_OPTS_S_TO_4BYTE);
7217     theEmitter->emitIns_R_R(INS_fcvtps, EA_4BYTE, REG_R1, REG_V5, INS_OPTS_D_TO_4BYTE);
7218     theEmitter->emitIns_R_R(INS_fcvtps, EA_8BYTE, REG_R2, REG_V6, INS_OPTS_S_TO_8BYTE);
7219     theEmitter->emitIns_R_R(INS_fcvtps, EA_8BYTE, REG_R3, REG_V7, INS_OPTS_D_TO_8BYTE);
7220
7221     // fcvtps vector
7222     theEmitter->emitIns_R_R(INS_fcvtps, EA_8BYTE, REG_V8, REG_V9, INS_OPTS_2S);
7223     theEmitter->emitIns_R_R(INS_fcvtps, EA_16BYTE, REG_V10, REG_V11, INS_OPTS_4S);
7224     theEmitter->emitIns_R_R(INS_fcvtps, EA_16BYTE, REG_V12, REG_V13, INS_OPTS_2D);
7225
7226     // fcvtpu scalar
7227     theEmitter->emitIns_R_R(INS_fcvtpu, EA_4BYTE, REG_V0, REG_V1);
7228     theEmitter->emitIns_R_R(INS_fcvtpu, EA_8BYTE, REG_V2, REG_V3);
7229
7230     // fcvtpu scalar to general
7231     theEmitter->emitIns_R_R(INS_fcvtpu, EA_4BYTE, REG_R0, REG_V4, INS_OPTS_S_TO_4BYTE);
7232     theEmitter->emitIns_R_R(INS_fcvtpu, EA_4BYTE, REG_R1, REG_V5, INS_OPTS_D_TO_4BYTE);
7233     theEmitter->emitIns_R_R(INS_fcvtpu, EA_8BYTE, REG_R2, REG_V6, INS_OPTS_S_TO_8BYTE);
7234     theEmitter->emitIns_R_R(INS_fcvtpu, EA_8BYTE, REG_R3, REG_V7, INS_OPTS_D_TO_8BYTE);
7235
7236     // fcvtpu vector
7237     theEmitter->emitIns_R_R(INS_fcvtpu, EA_8BYTE, REG_V8, REG_V9, INS_OPTS_2S);
7238     theEmitter->emitIns_R_R(INS_fcvtpu, EA_16BYTE, REG_V10, REG_V11, INS_OPTS_4S);
7239     theEmitter->emitIns_R_R(INS_fcvtpu, EA_16BYTE, REG_V12, REG_V13, INS_OPTS_2D);
7240
7241     ////////////////////////////////////////////////////////////////////////////////
7242
7243     // fcvtzs scalar
7244     theEmitter->emitIns_R_R(INS_fcvtzs, EA_4BYTE, REG_V0, REG_V1);
7245     theEmitter->emitIns_R_R(INS_fcvtzs, EA_8BYTE, REG_V2, REG_V3);
7246
7247     // fcvtzs scalar to general
7248     theEmitter->emitIns_R_R(INS_fcvtzs, EA_4BYTE, REG_R0, REG_V4, INS_OPTS_S_TO_4BYTE);
7249     theEmitter->emitIns_R_R(INS_fcvtzs, EA_4BYTE, REG_R1, REG_V5, INS_OPTS_D_TO_4BYTE);
7250     theEmitter->emitIns_R_R(INS_fcvtzs, EA_8BYTE, REG_R2, REG_V6, INS_OPTS_S_TO_8BYTE);
7251     theEmitter->emitIns_R_R(INS_fcvtzs, EA_8BYTE, REG_R3, REG_V7, INS_OPTS_D_TO_8BYTE);
7252
7253     // fcvtzs vector
7254     theEmitter->emitIns_R_R(INS_fcvtzs, EA_8BYTE, REG_V8, REG_V9, INS_OPTS_2S);
7255     theEmitter->emitIns_R_R(INS_fcvtzs, EA_16BYTE, REG_V10, REG_V11, INS_OPTS_4S);
7256     theEmitter->emitIns_R_R(INS_fcvtzs, EA_16BYTE, REG_V12, REG_V13, INS_OPTS_2D);
7257
7258     // fcvtzu scalar
7259     theEmitter->emitIns_R_R(INS_fcvtzu, EA_4BYTE, REG_V0, REG_V1);
7260     theEmitter->emitIns_R_R(INS_fcvtzu, EA_8BYTE, REG_V2, REG_V3);
7261
7262     // fcvtzu scalar to general
7263     theEmitter->emitIns_R_R(INS_fcvtzu, EA_4BYTE, REG_R0, REG_V4, INS_OPTS_S_TO_4BYTE);
7264     theEmitter->emitIns_R_R(INS_fcvtzu, EA_4BYTE, REG_R1, REG_V5, INS_OPTS_D_TO_4BYTE);
7265     theEmitter->emitIns_R_R(INS_fcvtzu, EA_8BYTE, REG_R2, REG_V6, INS_OPTS_S_TO_8BYTE);
7266     theEmitter->emitIns_R_R(INS_fcvtzu, EA_8BYTE, REG_R3, REG_V7, INS_OPTS_D_TO_8BYTE);
7267
7268     // fcvtzu vector
7269     theEmitter->emitIns_R_R(INS_fcvtzu, EA_8BYTE, REG_V8, REG_V9, INS_OPTS_2S);
7270     theEmitter->emitIns_R_R(INS_fcvtzu, EA_16BYTE, REG_V10, REG_V11, INS_OPTS_4S);
7271     theEmitter->emitIns_R_R(INS_fcvtzu, EA_16BYTE, REG_V12, REG_V13, INS_OPTS_2D);
7272
7273     ////////////////////////////////////////////////////////////////////////////////
7274
7275     // scvtf scalar
7276     theEmitter->emitIns_R_R(INS_scvtf, EA_4BYTE, REG_V0, REG_V1);
7277     theEmitter->emitIns_R_R(INS_scvtf, EA_8BYTE, REG_V2, REG_V3);
7278
7279     // scvtf scalar from general
7280     theEmitter->emitIns_R_R(INS_scvtf, EA_4BYTE, REG_V4, REG_R0, INS_OPTS_4BYTE_TO_S);
7281     theEmitter->emitIns_R_R(INS_scvtf, EA_4BYTE, REG_V5, REG_R1, INS_OPTS_8BYTE_TO_S);
7282     theEmitter->emitIns_R_R(INS_scvtf, EA_8BYTE, REG_V6, REG_R2, INS_OPTS_4BYTE_TO_D);
7283     theEmitter->emitIns_R_R(INS_scvtf, EA_8BYTE, REG_V7, REG_R3, INS_OPTS_8BYTE_TO_D);
7284
7285     // scvtf vector
7286     theEmitter->emitIns_R_R(INS_scvtf, EA_8BYTE, REG_V8, REG_V9, INS_OPTS_2S);
7287     theEmitter->emitIns_R_R(INS_scvtf, EA_16BYTE, REG_V10, REG_V11, INS_OPTS_4S);
7288     theEmitter->emitIns_R_R(INS_scvtf, EA_16BYTE, REG_V12, REG_V13, INS_OPTS_2D);
7289
7290     // ucvtf scalar
7291     theEmitter->emitIns_R_R(INS_ucvtf, EA_4BYTE, REG_V0, REG_V1);
7292     theEmitter->emitIns_R_R(INS_ucvtf, EA_8BYTE, REG_V2, REG_V3);
7293
7294     // ucvtf scalar from general
7295     theEmitter->emitIns_R_R(INS_ucvtf, EA_4BYTE, REG_V4, REG_R0, INS_OPTS_4BYTE_TO_S);
7296     theEmitter->emitIns_R_R(INS_ucvtf, EA_4BYTE, REG_V5, REG_R1, INS_OPTS_8BYTE_TO_S);
7297     theEmitter->emitIns_R_R(INS_ucvtf, EA_8BYTE, REG_V6, REG_R2, INS_OPTS_4BYTE_TO_D);
7298     theEmitter->emitIns_R_R(INS_ucvtf, EA_8BYTE, REG_V7, REG_R3, INS_OPTS_8BYTE_TO_D);
7299
7300     // ucvtf vector
7301     theEmitter->emitIns_R_R(INS_ucvtf, EA_8BYTE, REG_V8, REG_V9, INS_OPTS_2S);
7302     theEmitter->emitIns_R_R(INS_ucvtf, EA_16BYTE, REG_V10, REG_V11, INS_OPTS_4S);
7303     theEmitter->emitIns_R_R(INS_ucvtf, EA_16BYTE, REG_V12, REG_V13, INS_OPTS_2D);
7304
7305 #endif // ALL_ARM64_EMITTER_UNIT_TESTS
7306
7307 #ifdef ALL_ARM64_EMITTER_UNIT_TESTS
7308     //
7309     // R_R   floating point operations, one dest, one source
7310     //
7311
7312     // fabs scalar
7313     theEmitter->emitIns_R_R(INS_fabs, EA_4BYTE, REG_V0, REG_V1);
7314     theEmitter->emitIns_R_R(INS_fabs, EA_8BYTE, REG_V2, REG_V3);
7315
7316     // fabs vector
7317     theEmitter->emitIns_R_R(INS_fabs, EA_8BYTE, REG_V4, REG_V5, INS_OPTS_2S);
7318     theEmitter->emitIns_R_R(INS_fabs, EA_16BYTE, REG_V6, REG_V7, INS_OPTS_4S);
7319     theEmitter->emitIns_R_R(INS_fabs, EA_16BYTE, REG_V8, REG_V9, INS_OPTS_2D);
7320
7321     // fneg scalar
7322     theEmitter->emitIns_R_R(INS_fneg, EA_4BYTE, REG_V0, REG_V1);
7323     theEmitter->emitIns_R_R(INS_fneg, EA_8BYTE, REG_V2, REG_V3);
7324
7325     // fneg vector
7326     theEmitter->emitIns_R_R(INS_fneg, EA_8BYTE, REG_V4, REG_V5, INS_OPTS_2S);
7327     theEmitter->emitIns_R_R(INS_fneg, EA_16BYTE, REG_V6, REG_V7, INS_OPTS_4S);
7328     theEmitter->emitIns_R_R(INS_fneg, EA_16BYTE, REG_V8, REG_V9, INS_OPTS_2D);
7329
7330     // fsqrt scalar
7331     theEmitter->emitIns_R_R(INS_fsqrt, EA_4BYTE, REG_V0, REG_V1);
7332     theEmitter->emitIns_R_R(INS_fsqrt, EA_8BYTE, REG_V2, REG_V3);
7333
7334     // fsqrt vector
7335     theEmitter->emitIns_R_R(INS_fsqrt, EA_8BYTE, REG_V4, REG_V5, INS_OPTS_2S);
7336     theEmitter->emitIns_R_R(INS_fsqrt, EA_16BYTE, REG_V6, REG_V7, INS_OPTS_4S);
7337     theEmitter->emitIns_R_R(INS_fsqrt, EA_16BYTE, REG_V8, REG_V9, INS_OPTS_2D);
7338
7339     genDefineTempLabel(genCreateTempLabel());
7340
7341     // abs scalar
7342     theEmitter->emitIns_R_R(INS_abs, EA_8BYTE, REG_V2, REG_V3);
7343
7344     // abs vector
7345     theEmitter->emitIns_R_R(INS_abs, EA_8BYTE, REG_V4, REG_V5, INS_OPTS_8B);
7346     theEmitter->emitIns_R_R(INS_abs, EA_16BYTE, REG_V6, REG_V7, INS_OPTS_16B);
7347     theEmitter->emitIns_R_R(INS_abs, EA_8BYTE, REG_V8, REG_V9, INS_OPTS_4H);
7348     theEmitter->emitIns_R_R(INS_abs, EA_16BYTE, REG_V10, REG_V11, INS_OPTS_8H);
7349     theEmitter->emitIns_R_R(INS_abs, EA_8BYTE, REG_V12, REG_V13, INS_OPTS_2S);
7350     theEmitter->emitIns_R_R(INS_abs, EA_16BYTE, REG_V14, REG_V15, INS_OPTS_4S);
7351     theEmitter->emitIns_R_R(INS_abs, EA_16BYTE, REG_V16, REG_V17, INS_OPTS_2D);
7352
7353     // neg scalar
7354     theEmitter->emitIns_R_R(INS_neg, EA_8BYTE, REG_V2, REG_V3);
7355
7356     // neg vector
7357     theEmitter->emitIns_R_R(INS_neg, EA_8BYTE, REG_V4, REG_V5, INS_OPTS_8B);
7358     theEmitter->emitIns_R_R(INS_neg, EA_16BYTE, REG_V6, REG_V7, INS_OPTS_16B);
7359     theEmitter->emitIns_R_R(INS_neg, EA_8BYTE, REG_V8, REG_V9, INS_OPTS_4H);
7360     theEmitter->emitIns_R_R(INS_neg, EA_16BYTE, REG_V10, REG_V11, INS_OPTS_8H);
7361     theEmitter->emitIns_R_R(INS_neg, EA_8BYTE, REG_V12, REG_V13, INS_OPTS_2S);
7362     theEmitter->emitIns_R_R(INS_neg, EA_16BYTE, REG_V14, REG_V15, INS_OPTS_4S);
7363     theEmitter->emitIns_R_R(INS_neg, EA_16BYTE, REG_V16, REG_V17, INS_OPTS_2D);
7364
7365     // mvn vector
7366     theEmitter->emitIns_R_R(INS_mvn, EA_8BYTE, REG_V4, REG_V5);
7367     theEmitter->emitIns_R_R(INS_mvn, EA_8BYTE, REG_V6, REG_V7, INS_OPTS_8B);
7368     theEmitter->emitIns_R_R(INS_mvn, EA_16BYTE, REG_V8, REG_V9);
7369     theEmitter->emitIns_R_R(INS_mvn, EA_16BYTE, REG_V10, REG_V11, INS_OPTS_16B);
7370
7371     // cnt vector
7372     theEmitter->emitIns_R_R(INS_cnt, EA_8BYTE, REG_V22, REG_V23, INS_OPTS_8B);
7373     theEmitter->emitIns_R_R(INS_cnt, EA_16BYTE, REG_V24, REG_V25, INS_OPTS_16B);
7374
7375     // not vector (the same encoding as mvn)
7376     theEmitter->emitIns_R_R(INS_not, EA_8BYTE, REG_V12, REG_V13);
7377     theEmitter->emitIns_R_R(INS_not, EA_8BYTE, REG_V14, REG_V15, INS_OPTS_8B);
7378     theEmitter->emitIns_R_R(INS_not, EA_16BYTE, REG_V16, REG_V17);
7379     theEmitter->emitIns_R_R(INS_not, EA_16BYTE, REG_V18, REG_V19, INS_OPTS_16B);
7380
7381     // cls vector
7382     theEmitter->emitIns_R_R(INS_cls, EA_8BYTE, REG_V4, REG_V5, INS_OPTS_8B);
7383     theEmitter->emitIns_R_R(INS_cls, EA_16BYTE, REG_V6, REG_V7, INS_OPTS_16B);
7384     theEmitter->emitIns_R_R(INS_cls, EA_8BYTE, REG_V8, REG_V9, INS_OPTS_4H);
7385     theEmitter->emitIns_R_R(INS_cls, EA_16BYTE, REG_V10, REG_V11, INS_OPTS_8H);
7386     theEmitter->emitIns_R_R(INS_cls, EA_8BYTE, REG_V12, REG_V13, INS_OPTS_2S);
7387     theEmitter->emitIns_R_R(INS_cls, EA_16BYTE, REG_V14, REG_V15, INS_OPTS_4S);
7388
7389     // clz vector
7390     theEmitter->emitIns_R_R(INS_clz, EA_8BYTE, REG_V4, REG_V5, INS_OPTS_8B);
7391     theEmitter->emitIns_R_R(INS_clz, EA_16BYTE, REG_V6, REG_V7, INS_OPTS_16B);
7392     theEmitter->emitIns_R_R(INS_clz, EA_8BYTE, REG_V8, REG_V9, INS_OPTS_4H);
7393     theEmitter->emitIns_R_R(INS_clz, EA_16BYTE, REG_V10, REG_V11, INS_OPTS_8H);
7394     theEmitter->emitIns_R_R(INS_clz, EA_8BYTE, REG_V12, REG_V13, INS_OPTS_2S);
7395     theEmitter->emitIns_R_R(INS_clz, EA_16BYTE, REG_V14, REG_V15, INS_OPTS_4S);
7396
7397     // rbit vector
7398     theEmitter->emitIns_R_R(INS_rbit, EA_8BYTE, REG_V0, REG_V1, INS_OPTS_8B);
7399     theEmitter->emitIns_R_R(INS_rbit, EA_16BYTE, REG_V2, REG_V3, INS_OPTS_16B);
7400
7401     // rev16 vector
7402     theEmitter->emitIns_R_R(INS_rev16, EA_8BYTE, REG_V0, REG_V1, INS_OPTS_8B);
7403     theEmitter->emitIns_R_R(INS_rev16, EA_16BYTE, REG_V2, REG_V3, INS_OPTS_16B);
7404
7405     // rev32 vector
7406     theEmitter->emitIns_R_R(INS_rev32, EA_8BYTE, REG_V4, REG_V5, INS_OPTS_8B);
7407     theEmitter->emitIns_R_R(INS_rev32, EA_16BYTE, REG_V6, REG_V7, INS_OPTS_16B);
7408     theEmitter->emitIns_R_R(INS_rev32, EA_8BYTE, REG_V8, REG_V9, INS_OPTS_4H);
7409     theEmitter->emitIns_R_R(INS_rev32, EA_16BYTE, REG_V10, REG_V11, INS_OPTS_8H);
7410
7411     // rev64 vector
7412     theEmitter->emitIns_R_R(INS_rev64, EA_8BYTE, REG_V4, REG_V5, INS_OPTS_8B);
7413     theEmitter->emitIns_R_R(INS_rev64, EA_16BYTE, REG_V6, REG_V7, INS_OPTS_16B);
7414     theEmitter->emitIns_R_R(INS_rev64, EA_8BYTE, REG_V8, REG_V9, INS_OPTS_4H);
7415     theEmitter->emitIns_R_R(INS_rev64, EA_16BYTE, REG_V10, REG_V11, INS_OPTS_8H);
7416     theEmitter->emitIns_R_R(INS_rev64, EA_8BYTE, REG_V12, REG_V13, INS_OPTS_2S);
7417     theEmitter->emitIns_R_R(INS_rev64, EA_16BYTE, REG_V14, REG_V15, INS_OPTS_4S);
7418
7419     // addv vector
7420     theEmitter->emitIns_R_R(INS_addv, EA_8BYTE, REG_V4, REG_V5, INS_OPTS_8B);
7421     theEmitter->emitIns_R_R(INS_addv, EA_16BYTE, REG_V6, REG_V7, INS_OPTS_16B);
7422     theEmitter->emitIns_R_R(INS_addv, EA_8BYTE, REG_V8, REG_V9, INS_OPTS_4H);
7423     theEmitter->emitIns_R_R(INS_addv, EA_16BYTE, REG_V10, REG_V11, INS_OPTS_8H);
7424     theEmitter->emitIns_R_R(INS_addv, EA_8BYTE, REG_V12, REG_V13, INS_OPTS_2S);
7425     theEmitter->emitIns_R_R(INS_addv, EA_16BYTE, REG_V14, REG_V15, INS_OPTS_4S);
7426
7427     // saddlv vector
7428     theEmitter->emitIns_R_R(INS_saddlv, EA_8BYTE, REG_V4, REG_V5, INS_OPTS_8B);
7429     theEmitter->emitIns_R_R(INS_saddlv, EA_16BYTE, REG_V6, REG_V7, INS_OPTS_16B);
7430     theEmitter->emitIns_R_R(INS_saddlv, EA_8BYTE, REG_V8, REG_V9, INS_OPTS_4H);
7431     theEmitter->emitIns_R_R(INS_saddlv, EA_16BYTE, REG_V10, REG_V11, INS_OPTS_8H);
7432     theEmitter->emitIns_R_R(INS_saddlv, EA_8BYTE, REG_V12, REG_V13, INS_OPTS_2S);
7433     theEmitter->emitIns_R_R(INS_saddlv, EA_16BYTE, REG_V14, REG_V15, INS_OPTS_4S);
7434
7435     // smaxlv vector
7436     theEmitter->emitIns_R_R(INS_smaxlv, EA_8BYTE, REG_V4, REG_V5, INS_OPTS_8B);
7437     theEmitter->emitIns_R_R(INS_smaxlv, EA_16BYTE, REG_V6, REG_V7, INS_OPTS_16B);
7438     theEmitter->emitIns_R_R(INS_smaxlv, EA_8BYTE, REG_V8, REG_V9, INS_OPTS_4H);
7439     theEmitter->emitIns_R_R(INS_smaxlv, EA_16BYTE, REG_V10, REG_V11, INS_OPTS_8H);
7440     theEmitter->emitIns_R_R(INS_smaxlv, EA_8BYTE, REG_V12, REG_V13, INS_OPTS_2S);
7441     theEmitter->emitIns_R_R(INS_smaxlv, EA_16BYTE, REG_V14, REG_V15, INS_OPTS_4S);
7442
7443     // sminlv vector
7444     theEmitter->emitIns_R_R(INS_sminlv, EA_8BYTE, REG_V4, REG_V5, INS_OPTS_8B);
7445     theEmitter->emitIns_R_R(INS_sminlv, EA_16BYTE, REG_V6, REG_V7, INS_OPTS_16B);
7446     theEmitter->emitIns_R_R(INS_sminlv, EA_8BYTE, REG_V8, REG_V9, INS_OPTS_4H);
7447     theEmitter->emitIns_R_R(INS_sminlv, EA_16BYTE, REG_V10, REG_V11, INS_OPTS_8H);
7448     theEmitter->emitIns_R_R(INS_sminlv, EA_8BYTE, REG_V12, REG_V13, INS_OPTS_2S);
7449     theEmitter->emitIns_R_R(INS_sminlv, EA_16BYTE, REG_V14, REG_V15, INS_OPTS_4S);
7450
7451     // uaddlv vector
7452     theEmitter->emitIns_R_R(INS_uaddlv, EA_8BYTE, REG_V4, REG_V5, INS_OPTS_8B);
7453     theEmitter->emitIns_R_R(INS_uaddlv, EA_16BYTE, REG_V6, REG_V7, INS_OPTS_16B);
7454     theEmitter->emitIns_R_R(INS_uaddlv, EA_8BYTE, REG_V8, REG_V9, INS_OPTS_4H);
7455     theEmitter->emitIns_R_R(INS_uaddlv, EA_16BYTE, REG_V10, REG_V11, INS_OPTS_8H);
7456     theEmitter->emitIns_R_R(INS_uaddlv, EA_8BYTE, REG_V12, REG_V13, INS_OPTS_2S);
7457     theEmitter->emitIns_R_R(INS_uaddlv, EA_16BYTE, REG_V14, REG_V15, INS_OPTS_4S);
7458
7459     // umaxlv vector
7460     theEmitter->emitIns_R_R(INS_umaxlv, EA_8BYTE, REG_V4, REG_V5, INS_OPTS_8B);
7461     theEmitter->emitIns_R_R(INS_umaxlv, EA_16BYTE, REG_V6, REG_V7, INS_OPTS_16B);
7462     theEmitter->emitIns_R_R(INS_umaxlv, EA_8BYTE, REG_V8, REG_V9, INS_OPTS_4H);
7463     theEmitter->emitIns_R_R(INS_umaxlv, EA_16BYTE, REG_V10, REG_V11, INS_OPTS_8H);
7464     theEmitter->emitIns_R_R(INS_umaxlv, EA_8BYTE, REG_V12, REG_V13, INS_OPTS_2S);
7465     theEmitter->emitIns_R_R(INS_umaxlv, EA_16BYTE, REG_V14, REG_V15, INS_OPTS_4S);
7466
7467     // uminlv vector
7468     theEmitter->emitIns_R_R(INS_uminlv, EA_8BYTE, REG_V4, REG_V5, INS_OPTS_8B);
7469     theEmitter->emitIns_R_R(INS_uminlv, EA_16BYTE, REG_V6, REG_V7, INS_OPTS_16B);
7470     theEmitter->emitIns_R_R(INS_uminlv, EA_8BYTE, REG_V8, REG_V9, INS_OPTS_4H);
7471     theEmitter->emitIns_R_R(INS_uminlv, EA_16BYTE, REG_V10, REG_V11, INS_OPTS_8H);
7472     theEmitter->emitIns_R_R(INS_uminlv, EA_8BYTE, REG_V12, REG_V13, INS_OPTS_2S);
7473     theEmitter->emitIns_R_R(INS_uminlv, EA_16BYTE, REG_V14, REG_V15, INS_OPTS_4S);
7474
7475     // faddp scalar
7476     theEmitter->emitIns_R_R(INS_faddp, EA_4BYTE, REG_V0, REG_V1);
7477     theEmitter->emitIns_R_R(INS_faddp, EA_8BYTE, REG_V2, REG_V3);
7478
7479     // INS_fcvtl
7480     theEmitter->emitIns_R_R(INS_fcvtl, EA_4BYTE, REG_V0, REG_V1);
7481
7482     // INS_fcvtl2
7483     theEmitter->emitIns_R_R(INS_fcvtl2, EA_4BYTE, REG_V0, REG_V1);
7484
7485     // INS_fcvtn
7486     theEmitter->emitIns_R_R(INS_fcvtn, EA_8BYTE, REG_V0, REG_V1);
7487
7488     // INS_fcvtn2
7489     theEmitter->emitIns_R_R(INS_fcvtn2, EA_8BYTE, REG_V0, REG_V1);
7490 #endif
7491
7492 #ifdef ALL_ARM64_EMITTER_UNIT_TESTS
7493     //
7494     // R_R   floating point round to int, one dest, one source
7495     //
7496
7497     // frinta scalar
7498     theEmitter->emitIns_R_R(INS_frinta, EA_4BYTE, REG_V0, REG_V1);
7499     theEmitter->emitIns_R_R(INS_frinta, EA_8BYTE, REG_V2, REG_V3);
7500
7501     // frinta vector
7502     theEmitter->emitIns_R_R(INS_frinta, EA_8BYTE, REG_V4, REG_V5, INS_OPTS_2S);
7503     theEmitter->emitIns_R_R(INS_frinta, EA_16BYTE, REG_V6, REG_V7, INS_OPTS_4S);
7504     theEmitter->emitIns_R_R(INS_frinta, EA_16BYTE, REG_V8, REG_V9, INS_OPTS_2D);
7505
7506     // frinti scalar
7507     theEmitter->emitIns_R_R(INS_frinti, EA_4BYTE, REG_V0, REG_V1);
7508     theEmitter->emitIns_R_R(INS_frinti, EA_8BYTE, REG_V2, REG_V3);
7509
7510     // frinti vector
7511     theEmitter->emitIns_R_R(INS_frinti, EA_8BYTE, REG_V4, REG_V5, INS_OPTS_2S);
7512     theEmitter->emitIns_R_R(INS_frinti, EA_16BYTE, REG_V6, REG_V7, INS_OPTS_4S);
7513     theEmitter->emitIns_R_R(INS_frinti, EA_16BYTE, REG_V8, REG_V9, INS_OPTS_2D);
7514
7515     // frintm scalar
7516     theEmitter->emitIns_R_R(INS_frintm, EA_4BYTE, REG_V0, REG_V1);
7517     theEmitter->emitIns_R_R(INS_frintm, EA_8BYTE, REG_V2, REG_V3);
7518
7519     // frintm vector
7520     theEmitter->emitIns_R_R(INS_frintm, EA_8BYTE, REG_V4, REG_V5, INS_OPTS_2S);
7521     theEmitter->emitIns_R_R(INS_frintm, EA_16BYTE, REG_V6, REG_V7, INS_OPTS_4S);
7522     theEmitter->emitIns_R_R(INS_frintm, EA_16BYTE, REG_V8, REG_V9, INS_OPTS_2D);
7523
7524     // frintn scalar
7525     theEmitter->emitIns_R_R(INS_frintn, EA_4BYTE, REG_V0, REG_V1);
7526     theEmitter->emitIns_R_R(INS_frintn, EA_8BYTE, REG_V2, REG_V3);
7527
7528     // frintn vector
7529     theEmitter->emitIns_R_R(INS_frintn, EA_8BYTE, REG_V4, REG_V5, INS_OPTS_2S);
7530     theEmitter->emitIns_R_R(INS_frintn, EA_16BYTE, REG_V6, REG_V7, INS_OPTS_4S);
7531     theEmitter->emitIns_R_R(INS_frintn, EA_16BYTE, REG_V8, REG_V9, INS_OPTS_2D);
7532
7533     // frintp scalar
7534     theEmitter->emitIns_R_R(INS_frintp, EA_4BYTE, REG_V0, REG_V1);
7535     theEmitter->emitIns_R_R(INS_frintp, EA_8BYTE, REG_V2, REG_V3);
7536
7537     // frintp vector
7538     theEmitter->emitIns_R_R(INS_frintp, EA_8BYTE, REG_V4, REG_V5, INS_OPTS_2S);
7539     theEmitter->emitIns_R_R(INS_frintp, EA_16BYTE, REG_V6, REG_V7, INS_OPTS_4S);
7540     theEmitter->emitIns_R_R(INS_frintp, EA_16BYTE, REG_V8, REG_V9, INS_OPTS_2D);
7541
7542     // frintx scalar
7543     theEmitter->emitIns_R_R(INS_frintx, EA_4BYTE, REG_V0, REG_V1);
7544     theEmitter->emitIns_R_R(INS_frintx, EA_8BYTE, REG_V2, REG_V3);
7545
7546     // frintx vector
7547     theEmitter->emitIns_R_R(INS_frintx, EA_8BYTE, REG_V4, REG_V5, INS_OPTS_2S);
7548     theEmitter->emitIns_R_R(INS_frintx, EA_16BYTE, REG_V6, REG_V7, INS_OPTS_4S);
7549     theEmitter->emitIns_R_R(INS_frintx, EA_16BYTE, REG_V8, REG_V9, INS_OPTS_2D);
7550
7551     // frintz scalar
7552     theEmitter->emitIns_R_R(INS_frintz, EA_4BYTE, REG_V0, REG_V1);
7553     theEmitter->emitIns_R_R(INS_frintz, EA_8BYTE, REG_V2, REG_V3);
7554
7555     // frintz vector
7556     theEmitter->emitIns_R_R(INS_frintz, EA_8BYTE, REG_V4, REG_V5, INS_OPTS_2S);
7557     theEmitter->emitIns_R_R(INS_frintz, EA_16BYTE, REG_V6, REG_V7, INS_OPTS_4S);
7558     theEmitter->emitIns_R_R(INS_frintz, EA_16BYTE, REG_V8, REG_V9, INS_OPTS_2D);
7559
7560 #endif // ALL_ARM64_EMITTER_UNIT_TESTS
7561
7562 #ifdef ALL_ARM64_EMITTER_UNIT_TESTS
7563     //
7564     // R_R_R   floating point operations, one dest, two source
7565     //
7566
7567     genDefineTempLabel(genCreateTempLabel());
7568
7569     theEmitter->emitIns_R_R_R(INS_fadd, EA_4BYTE, REG_V0, REG_V1, REG_V2); // scalar 4BYTE
7570     theEmitter->emitIns_R_R_R(INS_fadd, EA_8BYTE, REG_V3, REG_V4, REG_V5); // scalar 8BYTE
7571     theEmitter->emitIns_R_R_R(INS_fadd, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_2S);
7572     theEmitter->emitIns_R_R_R(INS_fadd, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_4S);
7573     theEmitter->emitIns_R_R_R(INS_fadd, EA_16BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_2D);
7574
7575     theEmitter->emitIns_R_R_R(INS_fsub, EA_4BYTE, REG_V0, REG_V1, REG_V2); // scalar 4BYTE
7576     theEmitter->emitIns_R_R_R(INS_fsub, EA_8BYTE, REG_V3, REG_V4, REG_V5); // scalar 8BYTE
7577     theEmitter->emitIns_R_R_R(INS_fsub, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_2S);
7578     theEmitter->emitIns_R_R_R(INS_fsub, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_4S);
7579     theEmitter->emitIns_R_R_R(INS_fsub, EA_16BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_2D);
7580
7581     theEmitter->emitIns_R_R_R(INS_fdiv, EA_4BYTE, REG_V0, REG_V1, REG_V2); // scalar 4BYTE
7582     theEmitter->emitIns_R_R_R(INS_fdiv, EA_8BYTE, REG_V3, REG_V4, REG_V5); // scalar 8BYTE
7583     theEmitter->emitIns_R_R_R(INS_fdiv, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_2S);
7584     theEmitter->emitIns_R_R_R(INS_fdiv, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_4S);
7585     theEmitter->emitIns_R_R_R(INS_fdiv, EA_16BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_2D);
7586
7587     theEmitter->emitIns_R_R_R(INS_fmax, EA_4BYTE, REG_V0, REG_V1, REG_V2); // scalar 4BYTE
7588     theEmitter->emitIns_R_R_R(INS_fmax, EA_8BYTE, REG_V3, REG_V4, REG_V5); // scalar 8BYTE
7589     theEmitter->emitIns_R_R_R(INS_fmax, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_2S);
7590     theEmitter->emitIns_R_R_R(INS_fmax, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_4S);
7591     theEmitter->emitIns_R_R_R(INS_fmax, EA_16BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_2D);
7592
7593     theEmitter->emitIns_R_R_R(INS_fmin, EA_4BYTE, REG_V0, REG_V1, REG_V2); // scalar 4BYTE
7594     theEmitter->emitIns_R_R_R(INS_fmin, EA_8BYTE, REG_V3, REG_V4, REG_V5); // scalar 8BYTE
7595     theEmitter->emitIns_R_R_R(INS_fmin, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_2S);
7596     theEmitter->emitIns_R_R_R(INS_fmin, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_4S);
7597     theEmitter->emitIns_R_R_R(INS_fmin, EA_16BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_2D);
7598
7599     // fabd
7600     theEmitter->emitIns_R_R_R(INS_fabd, EA_4BYTE, REG_V0, REG_V1, REG_V2); // scalar 4BYTE
7601     theEmitter->emitIns_R_R_R(INS_fabd, EA_8BYTE, REG_V3, REG_V4, REG_V5); // scalar 8BYTE
7602     theEmitter->emitIns_R_R_R(INS_fabd, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_2S);
7603     theEmitter->emitIns_R_R_R(INS_fabd, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_4S);
7604     theEmitter->emitIns_R_R_R(INS_fabd, EA_16BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_2D);
7605
7606     genDefineTempLabel(genCreateTempLabel());
7607
7608     theEmitter->emitIns_R_R_R(INS_fmul, EA_4BYTE, REG_V0, REG_V1, REG_V2); // scalar 4BYTE
7609     theEmitter->emitIns_R_R_R(INS_fmul, EA_8BYTE, REG_V3, REG_V4, REG_V5); // scalar 8BYTE
7610     theEmitter->emitIns_R_R_R(INS_fmul, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_2S);
7611     theEmitter->emitIns_R_R_R(INS_fmul, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_4S);
7612     theEmitter->emitIns_R_R_R(INS_fmul, EA_16BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_2D);
7613
7614     theEmitter->emitIns_R_R_R_I(INS_fmul, EA_4BYTE, REG_V15, REG_V16, REG_V17, 3); // scalar by elem 4BYTE
7615     theEmitter->emitIns_R_R_R_I(INS_fmul, EA_8BYTE, REG_V18, REG_V19, REG_V20, 1); // scalar by elem 8BYTE
7616     theEmitter->emitIns_R_R_R_I(INS_fmul, EA_8BYTE, REG_V21, REG_V22, REG_V23, 0, INS_OPTS_2S);
7617     theEmitter->emitIns_R_R_R_I(INS_fmul, EA_16BYTE, REG_V24, REG_V25, REG_V26, 2, INS_OPTS_4S);
7618     theEmitter->emitIns_R_R_R_I(INS_fmul, EA_16BYTE, REG_V27, REG_V28, REG_V29, 0, INS_OPTS_2D);
7619
7620     theEmitter->emitIns_R_R_R(INS_fmulx, EA_4BYTE, REG_V0, REG_V1, REG_V2); // scalar 4BYTE
7621     theEmitter->emitIns_R_R_R(INS_fmulx, EA_8BYTE, REG_V3, REG_V4, REG_V5); // scalar 8BYTE
7622     theEmitter->emitIns_R_R_R(INS_fmulx, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_2S);
7623     theEmitter->emitIns_R_R_R(INS_fmulx, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_4S);
7624     theEmitter->emitIns_R_R_R(INS_fmulx, EA_16BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_2D);
7625
7626     theEmitter->emitIns_R_R_R_I(INS_fmulx, EA_4BYTE, REG_V15, REG_V16, REG_V17, 3); // scalar by elem 4BYTE
7627     theEmitter->emitIns_R_R_R_I(INS_fmulx, EA_8BYTE, REG_V18, REG_V19, REG_V20, 1); // scalar by elem 8BYTE
7628     theEmitter->emitIns_R_R_R_I(INS_fmulx, EA_8BYTE, REG_V21, REG_V22, REG_V23, 0, INS_OPTS_2S);
7629     theEmitter->emitIns_R_R_R_I(INS_fmulx, EA_16BYTE, REG_V24, REG_V25, REG_V26, 2, INS_OPTS_4S);
7630     theEmitter->emitIns_R_R_R_I(INS_fmulx, EA_16BYTE, REG_V27, REG_V28, REG_V29, 0, INS_OPTS_2D);
7631
7632     theEmitter->emitIns_R_R_R(INS_fnmul, EA_4BYTE, REG_V0, REG_V1, REG_V2); // scalar 4BYTE
7633     theEmitter->emitIns_R_R_R(INS_fnmul, EA_8BYTE, REG_V3, REG_V4, REG_V5); // scalar 8BYTE
7634
7635 #endif // ALL_ARM64_EMITTER_UNIT_TESTS
7636
7637 #ifdef ALL_ARM64_EMITTER_UNIT_TESTS
7638     //
7639     // R_R_I  vector operations, one dest, one source reg, one immed
7640     //
7641
7642     genDefineTempLabel(genCreateTempLabel());
7643
7644     // 'sshr' scalar
7645     theEmitter->emitIns_R_R_I(INS_sshr, EA_8BYTE, REG_V0, REG_V1, 1);
7646     theEmitter->emitIns_R_R_I(INS_sshr, EA_8BYTE, REG_V2, REG_V3, 14);
7647     theEmitter->emitIns_R_R_I(INS_sshr, EA_8BYTE, REG_V4, REG_V5, 27);
7648     theEmitter->emitIns_R_R_I(INS_sshr, EA_8BYTE, REG_V6, REG_V7, 40);
7649     theEmitter->emitIns_R_R_I(INS_sshr, EA_8BYTE, REG_V8, REG_V9, 63);
7650
7651     // 'sshr' vector
7652     theEmitter->emitIns_R_R_I(INS_sshr, EA_8BYTE, REG_V0, REG_V1, 1, INS_OPTS_8B);
7653     theEmitter->emitIns_R_R_I(INS_sshr, EA_16BYTE, REG_V2, REG_V3, 7, INS_OPTS_16B);
7654     theEmitter->emitIns_R_R_I(INS_sshr, EA_8BYTE, REG_V4, REG_V5, 9, INS_OPTS_4H);
7655     theEmitter->emitIns_R_R_I(INS_sshr, EA_16BYTE, REG_V6, REG_V7, 15, INS_OPTS_8H);
7656     theEmitter->emitIns_R_R_I(INS_sshr, EA_8BYTE, REG_V8, REG_V9, 17, INS_OPTS_2S);
7657     theEmitter->emitIns_R_R_I(INS_sshr, EA_16BYTE, REG_V10, REG_V11, 31, INS_OPTS_4S);
7658     theEmitter->emitIns_R_R_I(INS_sshr, EA_16BYTE, REG_V12, REG_V13, 33, INS_OPTS_2D);
7659     theEmitter->emitIns_R_R_I(INS_sshr, EA_16BYTE, REG_V14, REG_V15, 63, INS_OPTS_2D);
7660
7661     // 'ssra' scalar
7662     theEmitter->emitIns_R_R_I(INS_ssra, EA_8BYTE, REG_V0, REG_V1, 1);
7663     theEmitter->emitIns_R_R_I(INS_ssra, EA_8BYTE, REG_V2, REG_V3, 14);
7664     theEmitter->emitIns_R_R_I(INS_ssra, EA_8BYTE, REG_V4, REG_V5, 27);
7665     theEmitter->emitIns_R_R_I(INS_ssra, EA_8BYTE, REG_V6, REG_V7, 40);
7666     theEmitter->emitIns_R_R_I(INS_ssra, EA_8BYTE, REG_V8, REG_V9, 63);
7667
7668     // 'ssra' vector
7669     theEmitter->emitIns_R_R_I(INS_ssra, EA_8BYTE, REG_V0, REG_V1, 1, INS_OPTS_8B);
7670     theEmitter->emitIns_R_R_I(INS_ssra, EA_16BYTE, REG_V2, REG_V3, 7, INS_OPTS_16B);
7671     theEmitter->emitIns_R_R_I(INS_ssra, EA_8BYTE, REG_V4, REG_V5, 9, INS_OPTS_4H);
7672     theEmitter->emitIns_R_R_I(INS_ssra, EA_16BYTE, REG_V6, REG_V7, 15, INS_OPTS_8H);
7673     theEmitter->emitIns_R_R_I(INS_ssra, EA_8BYTE, REG_V8, REG_V9, 17, INS_OPTS_2S);
7674     theEmitter->emitIns_R_R_I(INS_ssra, EA_16BYTE, REG_V10, REG_V11, 31, INS_OPTS_4S);
7675     theEmitter->emitIns_R_R_I(INS_ssra, EA_16BYTE, REG_V12, REG_V13, 33, INS_OPTS_2D);
7676     theEmitter->emitIns_R_R_I(INS_ssra, EA_16BYTE, REG_V14, REG_V15, 63, INS_OPTS_2D);
7677
7678     // 'srshr' scalar
7679     theEmitter->emitIns_R_R_I(INS_srshr, EA_8BYTE, REG_V0, REG_V1, 1);
7680     theEmitter->emitIns_R_R_I(INS_srshr, EA_8BYTE, REG_V2, REG_V3, 14);
7681     theEmitter->emitIns_R_R_I(INS_srshr, EA_8BYTE, REG_V4, REG_V5, 27);
7682     theEmitter->emitIns_R_R_I(INS_srshr, EA_8BYTE, REG_V6, REG_V7, 40);
7683     theEmitter->emitIns_R_R_I(INS_srshr, EA_8BYTE, REG_V8, REG_V9, 63);
7684
7685     // 'srshr' vector
7686     theEmitter->emitIns_R_R_I(INS_srshr, EA_8BYTE, REG_V0, REG_V1, 1, INS_OPTS_8B);
7687     theEmitter->emitIns_R_R_I(INS_srshr, EA_16BYTE, REG_V2, REG_V3, 7, INS_OPTS_16B);
7688     theEmitter->emitIns_R_R_I(INS_srshr, EA_8BYTE, REG_V4, REG_V5, 9, INS_OPTS_4H);
7689     theEmitter->emitIns_R_R_I(INS_srshr, EA_16BYTE, REG_V6, REG_V7, 15, INS_OPTS_8H);
7690     theEmitter->emitIns_R_R_I(INS_srshr, EA_8BYTE, REG_V8, REG_V9, 17, INS_OPTS_2S);
7691     theEmitter->emitIns_R_R_I(INS_srshr, EA_16BYTE, REG_V10, REG_V11, 31, INS_OPTS_4S);
7692     theEmitter->emitIns_R_R_I(INS_srshr, EA_16BYTE, REG_V12, REG_V13, 33, INS_OPTS_2D);
7693     theEmitter->emitIns_R_R_I(INS_srshr, EA_16BYTE, REG_V14, REG_V15, 63, INS_OPTS_2D);
7694
7695     // 'srsra' scalar
7696     theEmitter->emitIns_R_R_I(INS_srsra, EA_8BYTE, REG_V0, REG_V1, 1);
7697     theEmitter->emitIns_R_R_I(INS_srsra, EA_8BYTE, REG_V2, REG_V3, 14);
7698     theEmitter->emitIns_R_R_I(INS_srsra, EA_8BYTE, REG_V4, REG_V5, 27);
7699     theEmitter->emitIns_R_R_I(INS_srsra, EA_8BYTE, REG_V6, REG_V7, 40);
7700     theEmitter->emitIns_R_R_I(INS_srsra, EA_8BYTE, REG_V8, REG_V9, 63);
7701
7702     // 'srsra' vector
7703     theEmitter->emitIns_R_R_I(INS_srsra, EA_8BYTE, REG_V0, REG_V1, 1, INS_OPTS_8B);
7704     theEmitter->emitIns_R_R_I(INS_srsra, EA_16BYTE, REG_V2, REG_V3, 7, INS_OPTS_16B);
7705     theEmitter->emitIns_R_R_I(INS_srsra, EA_8BYTE, REG_V4, REG_V5, 9, INS_OPTS_4H);
7706     theEmitter->emitIns_R_R_I(INS_srsra, EA_16BYTE, REG_V6, REG_V7, 15, INS_OPTS_8H);
7707     theEmitter->emitIns_R_R_I(INS_srsra, EA_8BYTE, REG_V8, REG_V9, 17, INS_OPTS_2S);
7708     theEmitter->emitIns_R_R_I(INS_srsra, EA_16BYTE, REG_V10, REG_V11, 31, INS_OPTS_4S);
7709     theEmitter->emitIns_R_R_I(INS_srsra, EA_16BYTE, REG_V12, REG_V13, 33, INS_OPTS_2D);
7710     theEmitter->emitIns_R_R_I(INS_srsra, EA_16BYTE, REG_V14, REG_V15, 63, INS_OPTS_2D);
7711
7712     // 'shl' scalar
7713     theEmitter->emitIns_R_R_I(INS_shl, EA_8BYTE, REG_V0, REG_V1, 1);
7714     theEmitter->emitIns_R_R_I(INS_shl, EA_8BYTE, REG_V2, REG_V3, 14);
7715     theEmitter->emitIns_R_R_I(INS_shl, EA_8BYTE, REG_V4, REG_V5, 27);
7716     theEmitter->emitIns_R_R_I(INS_shl, EA_8BYTE, REG_V6, REG_V7, 40);
7717     theEmitter->emitIns_R_R_I(INS_shl, EA_8BYTE, REG_V8, REG_V9, 63);
7718
7719     // 'shl' vector
7720     theEmitter->emitIns_R_R_I(INS_shl, EA_8BYTE, REG_V0, REG_V1, 1, INS_OPTS_8B);
7721     theEmitter->emitIns_R_R_I(INS_shl, EA_16BYTE, REG_V2, REG_V3, 7, INS_OPTS_16B);
7722     theEmitter->emitIns_R_R_I(INS_shl, EA_8BYTE, REG_V4, REG_V5, 9, INS_OPTS_4H);
7723     theEmitter->emitIns_R_R_I(INS_shl, EA_16BYTE, REG_V6, REG_V7, 15, INS_OPTS_8H);
7724     theEmitter->emitIns_R_R_I(INS_shl, EA_8BYTE, REG_V8, REG_V9, 17, INS_OPTS_2S);
7725     theEmitter->emitIns_R_R_I(INS_shl, EA_16BYTE, REG_V10, REG_V11, 31, INS_OPTS_4S);
7726     theEmitter->emitIns_R_R_I(INS_shl, EA_16BYTE, REG_V12, REG_V13, 33, INS_OPTS_2D);
7727     theEmitter->emitIns_R_R_I(INS_shl, EA_16BYTE, REG_V14, REG_V15, 63, INS_OPTS_2D);
7728
7729     // 'ushr' scalar
7730     theEmitter->emitIns_R_R_I(INS_ushr, EA_8BYTE, REG_V0, REG_V1, 1);
7731     theEmitter->emitIns_R_R_I(INS_ushr, EA_8BYTE, REG_V2, REG_V3, 14);
7732     theEmitter->emitIns_R_R_I(INS_ushr, EA_8BYTE, REG_V4, REG_V5, 27);
7733     theEmitter->emitIns_R_R_I(INS_ushr, EA_8BYTE, REG_V6, REG_V7, 40);
7734     theEmitter->emitIns_R_R_I(INS_ushr, EA_8BYTE, REG_V8, REG_V9, 63);
7735
7736     // 'ushr' vector
7737     theEmitter->emitIns_R_R_I(INS_ushr, EA_8BYTE, REG_V0, REG_V1, 1, INS_OPTS_8B);
7738     theEmitter->emitIns_R_R_I(INS_ushr, EA_16BYTE, REG_V2, REG_V3, 7, INS_OPTS_16B);
7739     theEmitter->emitIns_R_R_I(INS_ushr, EA_8BYTE, REG_V4, REG_V5, 9, INS_OPTS_4H);
7740     theEmitter->emitIns_R_R_I(INS_ushr, EA_16BYTE, REG_V6, REG_V7, 15, INS_OPTS_8H);
7741     theEmitter->emitIns_R_R_I(INS_ushr, EA_8BYTE, REG_V8, REG_V9, 17, INS_OPTS_2S);
7742     theEmitter->emitIns_R_R_I(INS_ushr, EA_16BYTE, REG_V10, REG_V11, 31, INS_OPTS_4S);
7743     theEmitter->emitIns_R_R_I(INS_ushr, EA_16BYTE, REG_V12, REG_V13, 33, INS_OPTS_2D);
7744     theEmitter->emitIns_R_R_I(INS_ushr, EA_16BYTE, REG_V14, REG_V15, 63, INS_OPTS_2D);
7745
7746     // 'usra' scalar
7747     theEmitter->emitIns_R_R_I(INS_usra, EA_8BYTE, REG_V0, REG_V1, 1);
7748     theEmitter->emitIns_R_R_I(INS_usra, EA_8BYTE, REG_V2, REG_V3, 14);
7749     theEmitter->emitIns_R_R_I(INS_usra, EA_8BYTE, REG_V4, REG_V5, 27);
7750     theEmitter->emitIns_R_R_I(INS_usra, EA_8BYTE, REG_V6, REG_V7, 40);
7751     theEmitter->emitIns_R_R_I(INS_usra, EA_8BYTE, REG_V8, REG_V9, 63);
7752
7753     // 'usra' vector
7754     theEmitter->emitIns_R_R_I(INS_usra, EA_8BYTE, REG_V0, REG_V1, 1, INS_OPTS_8B);
7755     theEmitter->emitIns_R_R_I(INS_usra, EA_16BYTE, REG_V2, REG_V3, 7, INS_OPTS_16B);
7756     theEmitter->emitIns_R_R_I(INS_usra, EA_8BYTE, REG_V4, REG_V5, 9, INS_OPTS_4H);
7757     theEmitter->emitIns_R_R_I(INS_usra, EA_16BYTE, REG_V6, REG_V7, 15, INS_OPTS_8H);
7758     theEmitter->emitIns_R_R_I(INS_usra, EA_8BYTE, REG_V8, REG_V9, 17, INS_OPTS_2S);
7759     theEmitter->emitIns_R_R_I(INS_usra, EA_16BYTE, REG_V10, REG_V11, 31, INS_OPTS_4S);
7760     theEmitter->emitIns_R_R_I(INS_usra, EA_16BYTE, REG_V12, REG_V13, 33, INS_OPTS_2D);
7761     theEmitter->emitIns_R_R_I(INS_usra, EA_16BYTE, REG_V14, REG_V15, 63, INS_OPTS_2D);
7762
7763     // 'urshr' scalar
7764     theEmitter->emitIns_R_R_I(INS_urshr, EA_8BYTE, REG_V0, REG_V1, 1);
7765     theEmitter->emitIns_R_R_I(INS_urshr, EA_8BYTE, REG_V2, REG_V3, 14);
7766     theEmitter->emitIns_R_R_I(INS_urshr, EA_8BYTE, REG_V4, REG_V5, 27);
7767     theEmitter->emitIns_R_R_I(INS_urshr, EA_8BYTE, REG_V6, REG_V7, 40);
7768     theEmitter->emitIns_R_R_I(INS_urshr, EA_8BYTE, REG_V8, REG_V9, 63);
7769
7770     // 'urshr' vector
7771     theEmitter->emitIns_R_R_I(INS_urshr, EA_8BYTE, REG_V0, REG_V1, 1, INS_OPTS_8B);
7772     theEmitter->emitIns_R_R_I(INS_urshr, EA_16BYTE, REG_V2, REG_V3, 7, INS_OPTS_16B);
7773     theEmitter->emitIns_R_R_I(INS_urshr, EA_8BYTE, REG_V4, REG_V5, 9, INS_OPTS_4H);
7774     theEmitter->emitIns_R_R_I(INS_urshr, EA_16BYTE, REG_V6, REG_V7, 15, INS_OPTS_8H);
7775     theEmitter->emitIns_R_R_I(INS_urshr, EA_8BYTE, REG_V8, REG_V9, 17, INS_OPTS_2S);
7776     theEmitter->emitIns_R_R_I(INS_urshr, EA_16BYTE, REG_V10, REG_V11, 31, INS_OPTS_4S);
7777     theEmitter->emitIns_R_R_I(INS_urshr, EA_16BYTE, REG_V12, REG_V13, 33, INS_OPTS_2D);
7778     theEmitter->emitIns_R_R_I(INS_urshr, EA_16BYTE, REG_V14, REG_V15, 63, INS_OPTS_2D);
7779
7780     // 'ursra' scalar
7781     theEmitter->emitIns_R_R_I(INS_ursra, EA_8BYTE, REG_V0, REG_V1, 1);
7782     theEmitter->emitIns_R_R_I(INS_ursra, EA_8BYTE, REG_V2, REG_V3, 14);
7783     theEmitter->emitIns_R_R_I(INS_ursra, EA_8BYTE, REG_V4, REG_V5, 27);
7784     theEmitter->emitIns_R_R_I(INS_ursra, EA_8BYTE, REG_V6, REG_V7, 40);
7785     theEmitter->emitIns_R_R_I(INS_ursra, EA_8BYTE, REG_V8, REG_V9, 63);
7786
7787     // 'srsra' vector
7788     theEmitter->emitIns_R_R_I(INS_ursra, EA_8BYTE, REG_V0, REG_V1, 1, INS_OPTS_8B);
7789     theEmitter->emitIns_R_R_I(INS_ursra, EA_16BYTE, REG_V2, REG_V3, 7, INS_OPTS_16B);
7790     theEmitter->emitIns_R_R_I(INS_ursra, EA_8BYTE, REG_V4, REG_V5, 9, INS_OPTS_4H);
7791     theEmitter->emitIns_R_R_I(INS_ursra, EA_16BYTE, REG_V6, REG_V7, 15, INS_OPTS_8H);
7792     theEmitter->emitIns_R_R_I(INS_ursra, EA_8BYTE, REG_V8, REG_V9, 17, INS_OPTS_2S);
7793     theEmitter->emitIns_R_R_I(INS_ursra, EA_16BYTE, REG_V10, REG_V11, 31, INS_OPTS_4S);
7794     theEmitter->emitIns_R_R_I(INS_ursra, EA_16BYTE, REG_V12, REG_V13, 33, INS_OPTS_2D);
7795     theEmitter->emitIns_R_R_I(INS_ursra, EA_16BYTE, REG_V14, REG_V15, 63, INS_OPTS_2D);
7796
7797     // 'sri' scalar
7798     theEmitter->emitIns_R_R_I(INS_sri, EA_8BYTE, REG_V0, REG_V1, 1);
7799     theEmitter->emitIns_R_R_I(INS_sri, EA_8BYTE, REG_V2, REG_V3, 14);
7800     theEmitter->emitIns_R_R_I(INS_sri, EA_8BYTE, REG_V4, REG_V5, 27);
7801     theEmitter->emitIns_R_R_I(INS_sri, EA_8BYTE, REG_V6, REG_V7, 40);
7802     theEmitter->emitIns_R_R_I(INS_sri, EA_8BYTE, REG_V8, REG_V9, 63);
7803
7804     // 'sri' vector
7805     theEmitter->emitIns_R_R_I(INS_sri, EA_8BYTE, REG_V0, REG_V1, 1, INS_OPTS_8B);
7806     theEmitter->emitIns_R_R_I(INS_sri, EA_16BYTE, REG_V2, REG_V3, 7, INS_OPTS_16B);
7807     theEmitter->emitIns_R_R_I(INS_sri, EA_8BYTE, REG_V4, REG_V5, 9, INS_OPTS_4H);
7808     theEmitter->emitIns_R_R_I(INS_sri, EA_16BYTE, REG_V6, REG_V7, 15, INS_OPTS_8H);
7809     theEmitter->emitIns_R_R_I(INS_sri, EA_8BYTE, REG_V8, REG_V9, 17, INS_OPTS_2S);
7810     theEmitter->emitIns_R_R_I(INS_sri, EA_16BYTE, REG_V10, REG_V11, 31, INS_OPTS_4S);
7811     theEmitter->emitIns_R_R_I(INS_sri, EA_16BYTE, REG_V12, REG_V13, 33, INS_OPTS_2D);
7812     theEmitter->emitIns_R_R_I(INS_sri, EA_16BYTE, REG_V14, REG_V15, 63, INS_OPTS_2D);
7813
7814     // 'sli' scalar
7815     theEmitter->emitIns_R_R_I(INS_sli, EA_8BYTE, REG_V0, REG_V1, 1);
7816     theEmitter->emitIns_R_R_I(INS_sli, EA_8BYTE, REG_V2, REG_V3, 14);
7817     theEmitter->emitIns_R_R_I(INS_sli, EA_8BYTE, REG_V4, REG_V5, 27);
7818     theEmitter->emitIns_R_R_I(INS_sli, EA_8BYTE, REG_V6, REG_V7, 40);
7819     theEmitter->emitIns_R_R_I(INS_sli, EA_8BYTE, REG_V8, REG_V9, 63);
7820
7821     // 'sli' vector
7822     theEmitter->emitIns_R_R_I(INS_sli, EA_8BYTE, REG_V0, REG_V1, 1, INS_OPTS_8B);
7823     theEmitter->emitIns_R_R_I(INS_sli, EA_16BYTE, REG_V2, REG_V3, 7, INS_OPTS_16B);
7824     theEmitter->emitIns_R_R_I(INS_sli, EA_8BYTE, REG_V4, REG_V5, 9, INS_OPTS_4H);
7825     theEmitter->emitIns_R_R_I(INS_sli, EA_16BYTE, REG_V6, REG_V7, 15, INS_OPTS_8H);
7826     theEmitter->emitIns_R_R_I(INS_sli, EA_8BYTE, REG_V8, REG_V9, 17, INS_OPTS_2S);
7827     theEmitter->emitIns_R_R_I(INS_sli, EA_16BYTE, REG_V10, REG_V11, 31, INS_OPTS_4S);
7828     theEmitter->emitIns_R_R_I(INS_sli, EA_16BYTE, REG_V12, REG_V13, 33, INS_OPTS_2D);
7829     theEmitter->emitIns_R_R_I(INS_sli, EA_16BYTE, REG_V14, REG_V15, 63, INS_OPTS_2D);
7830
7831     // 'sshll' vector
7832     theEmitter->emitIns_R_R_I(INS_sshll, EA_8BYTE, REG_V0, REG_V1, 1, INS_OPTS_8B);
7833     theEmitter->emitIns_R_R_I(INS_sshll2, EA_16BYTE, REG_V2, REG_V3, 7, INS_OPTS_16B);
7834     theEmitter->emitIns_R_R_I(INS_sshll, EA_8BYTE, REG_V4, REG_V5, 9, INS_OPTS_4H);
7835     theEmitter->emitIns_R_R_I(INS_sshll2, EA_16BYTE, REG_V6, REG_V7, 15, INS_OPTS_8H);
7836     theEmitter->emitIns_R_R_I(INS_sshll, EA_8BYTE, REG_V8, REG_V9, 17, INS_OPTS_2S);
7837     theEmitter->emitIns_R_R_I(INS_sshll2, EA_16BYTE, REG_V10, REG_V11, 31, INS_OPTS_4S);
7838
7839     // 'ushll' vector
7840     theEmitter->emitIns_R_R_I(INS_ushll, EA_8BYTE, REG_V0, REG_V1, 1, INS_OPTS_8B);
7841     theEmitter->emitIns_R_R_I(INS_ushll2, EA_16BYTE, REG_V2, REG_V3, 7, INS_OPTS_16B);
7842     theEmitter->emitIns_R_R_I(INS_ushll, EA_8BYTE, REG_V4, REG_V5, 9, INS_OPTS_4H);
7843     theEmitter->emitIns_R_R_I(INS_ushll2, EA_16BYTE, REG_V6, REG_V7, 15, INS_OPTS_8H);
7844     theEmitter->emitIns_R_R_I(INS_ushll, EA_8BYTE, REG_V8, REG_V9, 17, INS_OPTS_2S);
7845     theEmitter->emitIns_R_R_I(INS_ushll2, EA_16BYTE, REG_V10, REG_V11, 31, INS_OPTS_4S);
7846
7847     // 'shrn' vector
7848     theEmitter->emitIns_R_R_I(INS_shrn, EA_8BYTE, REG_V0, REG_V1, 1, INS_OPTS_8B);
7849     theEmitter->emitIns_R_R_I(INS_shrn2, EA_16BYTE, REG_V2, REG_V3, 7, INS_OPTS_16B);
7850     theEmitter->emitIns_R_R_I(INS_shrn, EA_8BYTE, REG_V4, REG_V5, 9, INS_OPTS_4H);
7851     theEmitter->emitIns_R_R_I(INS_shrn2, EA_16BYTE, REG_V6, REG_V7, 15, INS_OPTS_8H);
7852     theEmitter->emitIns_R_R_I(INS_shrn, EA_8BYTE, REG_V8, REG_V9, 17, INS_OPTS_2S);
7853     theEmitter->emitIns_R_R_I(INS_shrn2, EA_16BYTE, REG_V10, REG_V11, 31, INS_OPTS_4S);
7854
7855     // 'rshrn' vector
7856     theEmitter->emitIns_R_R_I(INS_rshrn, EA_8BYTE, REG_V0, REG_V1, 1, INS_OPTS_8B);
7857     theEmitter->emitIns_R_R_I(INS_rshrn2, EA_16BYTE, REG_V2, REG_V3, 7, INS_OPTS_16B);
7858     theEmitter->emitIns_R_R_I(INS_rshrn, EA_8BYTE, REG_V4, REG_V5, 9, INS_OPTS_4H);
7859     theEmitter->emitIns_R_R_I(INS_rshrn2, EA_16BYTE, REG_V6, REG_V7, 15, INS_OPTS_8H);
7860     theEmitter->emitIns_R_R_I(INS_rshrn, EA_8BYTE, REG_V8, REG_V9, 17, INS_OPTS_2S);
7861     theEmitter->emitIns_R_R_I(INS_rshrn2, EA_16BYTE, REG_V10, REG_V11, 31, INS_OPTS_4S);
7862
7863     // 'sxtl' vector
7864     theEmitter->emitIns_R_R(INS_sxtl, EA_8BYTE, REG_V0, REG_V1, INS_OPTS_8B);
7865     theEmitter->emitIns_R_R(INS_sxtl2, EA_16BYTE, REG_V2, REG_V3, INS_OPTS_16B);
7866     theEmitter->emitIns_R_R(INS_sxtl, EA_8BYTE, REG_V4, REG_V5, INS_OPTS_4H);
7867     theEmitter->emitIns_R_R(INS_sxtl2, EA_16BYTE, REG_V6, REG_V7, INS_OPTS_8H);
7868     theEmitter->emitIns_R_R(INS_sxtl, EA_8BYTE, REG_V8, REG_V9, INS_OPTS_2S);
7869     theEmitter->emitIns_R_R(INS_sxtl2, EA_16BYTE, REG_V10, REG_V11, INS_OPTS_4S);
7870
7871     // 'uxtl' vector
7872     theEmitter->emitIns_R_R(INS_uxtl, EA_8BYTE, REG_V0, REG_V1, INS_OPTS_8B);
7873     theEmitter->emitIns_R_R(INS_uxtl2, EA_16BYTE, REG_V2, REG_V3, INS_OPTS_16B);
7874     theEmitter->emitIns_R_R(INS_uxtl, EA_8BYTE, REG_V4, REG_V5, INS_OPTS_4H);
7875     theEmitter->emitIns_R_R(INS_uxtl2, EA_16BYTE, REG_V6, REG_V7, INS_OPTS_8H);
7876     theEmitter->emitIns_R_R(INS_uxtl, EA_8BYTE, REG_V8, REG_V9, INS_OPTS_2S);
7877     theEmitter->emitIns_R_R(INS_uxtl2, EA_16BYTE, REG_V10, REG_V11, INS_OPTS_4S);
7878
7879 #endif // ALL_ARM64_EMITTER_UNIT_TESTS
7880
7881 #ifdef ALL_ARM64_EMITTER_UNIT_TESTS
7882     //
7883     // R_R_R   vector operations, one dest, two source
7884     //
7885
7886     genDefineTempLabel(genCreateTempLabel());
7887
7888     // Specifying an Arrangement is optional
7889     //
7890     theEmitter->emitIns_R_R_R(INS_and, EA_8BYTE, REG_V6, REG_V7, REG_V8);
7891     theEmitter->emitIns_R_R_R(INS_bic, EA_8BYTE, REG_V9, REG_V10, REG_V11);
7892     theEmitter->emitIns_R_R_R(INS_eor, EA_8BYTE, REG_V12, REG_V13, REG_V14);
7893     theEmitter->emitIns_R_R_R(INS_orr, EA_8BYTE, REG_V15, REG_V16, REG_V17);
7894     theEmitter->emitIns_R_R_R(INS_orn, EA_8BYTE, REG_V18, REG_V19, REG_V20);
7895     theEmitter->emitIns_R_R_R(INS_and, EA_16BYTE, REG_V21, REG_V22, REG_V23);
7896     theEmitter->emitIns_R_R_R(INS_bic, EA_16BYTE, REG_V24, REG_V25, REG_V26);
7897     theEmitter->emitIns_R_R_R(INS_eor, EA_16BYTE, REG_V27, REG_V28, REG_V29);
7898     theEmitter->emitIns_R_R_R(INS_orr, EA_16BYTE, REG_V30, REG_V31, REG_V0);
7899     theEmitter->emitIns_R_R_R(INS_orn, EA_16BYTE, REG_V1, REG_V2, REG_V3);
7900
7901     theEmitter->emitIns_R_R_R(INS_bsl, EA_8BYTE, REG_V4, REG_V5, REG_V6);
7902     theEmitter->emitIns_R_R_R(INS_bit, EA_8BYTE, REG_V7, REG_V8, REG_V9);
7903     theEmitter->emitIns_R_R_R(INS_bif, EA_8BYTE, REG_V10, REG_V11, REG_V12);
7904     theEmitter->emitIns_R_R_R(INS_bsl, EA_16BYTE, REG_V13, REG_V14, REG_V15);
7905     theEmitter->emitIns_R_R_R(INS_bit, EA_16BYTE, REG_V16, REG_V17, REG_V18);
7906     theEmitter->emitIns_R_R_R(INS_bif, EA_16BYTE, REG_V19, REG_V20, REG_V21);
7907
7908     // Default Arrangement as per the ARM64 manual
7909     //
7910     theEmitter->emitIns_R_R_R(INS_and, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_8B);
7911     theEmitter->emitIns_R_R_R(INS_bic, EA_8BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_8B);
7912     theEmitter->emitIns_R_R_R(INS_eor, EA_8BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_8B);
7913     theEmitter->emitIns_R_R_R(INS_orr, EA_8BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_8B);
7914     theEmitter->emitIns_R_R_R(INS_orn, EA_8BYTE, REG_V18, REG_V19, REG_V20, INS_OPTS_8B);
7915     theEmitter->emitIns_R_R_R(INS_and, EA_16BYTE, REG_V21, REG_V22, REG_V23, INS_OPTS_16B);
7916     theEmitter->emitIns_R_R_R(INS_bic, EA_16BYTE, REG_V24, REG_V25, REG_V26, INS_OPTS_16B);
7917     theEmitter->emitIns_R_R_R(INS_eor, EA_16BYTE, REG_V27, REG_V28, REG_V29, INS_OPTS_16B);
7918     theEmitter->emitIns_R_R_R(INS_orr, EA_16BYTE, REG_V30, REG_V31, REG_V0, INS_OPTS_16B);
7919     theEmitter->emitIns_R_R_R(INS_orn, EA_16BYTE, REG_V1, REG_V2, REG_V3, INS_OPTS_16B);
7920
7921     theEmitter->emitIns_R_R_R(INS_bsl, EA_8BYTE, REG_V4, REG_V5, REG_V6, INS_OPTS_8B);
7922     theEmitter->emitIns_R_R_R(INS_bit, EA_8BYTE, REG_V7, REG_V8, REG_V9, INS_OPTS_8B);
7923     theEmitter->emitIns_R_R_R(INS_bif, EA_8BYTE, REG_V10, REG_V11, REG_V12, INS_OPTS_8B);
7924     theEmitter->emitIns_R_R_R(INS_bsl, EA_16BYTE, REG_V13, REG_V14, REG_V15, INS_OPTS_16B);
7925     theEmitter->emitIns_R_R_R(INS_bit, EA_16BYTE, REG_V16, REG_V17, REG_V18, INS_OPTS_16B);
7926     theEmitter->emitIns_R_R_R(INS_bif, EA_16BYTE, REG_V19, REG_V20, REG_V21, INS_OPTS_16B);
7927
7928     genDefineTempLabel(genCreateTempLabel());
7929
7930     theEmitter->emitIns_R_R_R(INS_add, EA_8BYTE, REG_V0, REG_V1, REG_V2); // scalar 8BYTE
7931     theEmitter->emitIns_R_R_R(INS_add, EA_8BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_8B);
7932     theEmitter->emitIns_R_R_R(INS_add, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_4H);
7933     theEmitter->emitIns_R_R_R(INS_add, EA_8BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_2S);
7934     theEmitter->emitIns_R_R_R(INS_add, EA_16BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_16B);
7935     theEmitter->emitIns_R_R_R(INS_add, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_8H);
7936     theEmitter->emitIns_R_R_R(INS_add, EA_16BYTE, REG_V18, REG_V19, REG_V20, INS_OPTS_4S);
7937     theEmitter->emitIns_R_R_R(INS_add, EA_16BYTE, REG_V21, REG_V22, REG_V23, INS_OPTS_2D);
7938
7939     theEmitter->emitIns_R_R_R(INS_sub, EA_8BYTE, REG_V1, REG_V2, REG_V3); // scalar 8BYTE
7940     theEmitter->emitIns_R_R_R(INS_sub, EA_8BYTE, REG_V4, REG_V5, REG_V6, INS_OPTS_8B);
7941     theEmitter->emitIns_R_R_R(INS_sub, EA_8BYTE, REG_V7, REG_V8, REG_V9, INS_OPTS_4H);
7942     theEmitter->emitIns_R_R_R(INS_sub, EA_8BYTE, REG_V10, REG_V11, REG_V12, INS_OPTS_2S);
7943     theEmitter->emitIns_R_R_R(INS_sub, EA_16BYTE, REG_V13, REG_V14, REG_V15, INS_OPTS_16B);
7944     theEmitter->emitIns_R_R_R(INS_sub, EA_16BYTE, REG_V16, REG_V17, REG_V18, INS_OPTS_8H);
7945     theEmitter->emitIns_R_R_R(INS_sub, EA_16BYTE, REG_V19, REG_V20, REG_V21, INS_OPTS_4S);
7946     theEmitter->emitIns_R_R_R(INS_sub, EA_16BYTE, REG_V22, REG_V23, REG_V24, INS_OPTS_2D);
7947
7948     genDefineTempLabel(genCreateTempLabel());
7949
7950     // saba vector
7951     theEmitter->emitIns_R_R_R(INS_saba, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B);
7952     theEmitter->emitIns_R_R_R(INS_saba, EA_16BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_16B);
7953     theEmitter->emitIns_R_R_R(INS_saba, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_4H);
7954     theEmitter->emitIns_R_R_R(INS_saba, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_8H);
7955     theEmitter->emitIns_R_R_R(INS_saba, EA_8BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_2S);
7956     theEmitter->emitIns_R_R_R(INS_saba, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S);
7957
7958     // sabd vector
7959     theEmitter->emitIns_R_R_R(INS_sabd, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B);
7960     theEmitter->emitIns_R_R_R(INS_sabd, EA_16BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_16B);
7961     theEmitter->emitIns_R_R_R(INS_sabd, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_4H);
7962     theEmitter->emitIns_R_R_R(INS_sabd, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_8H);
7963     theEmitter->emitIns_R_R_R(INS_sabd, EA_8BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_2S);
7964     theEmitter->emitIns_R_R_R(INS_sabd, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S);
7965
7966     // uaba vector
7967     theEmitter->emitIns_R_R_R(INS_uaba, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B);
7968     theEmitter->emitIns_R_R_R(INS_uaba, EA_16BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_16B);
7969     theEmitter->emitIns_R_R_R(INS_uaba, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_4H);
7970     theEmitter->emitIns_R_R_R(INS_uaba, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_8H);
7971     theEmitter->emitIns_R_R_R(INS_uaba, EA_8BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_2S);
7972     theEmitter->emitIns_R_R_R(INS_uaba, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S);
7973
7974     // uabd vector
7975     theEmitter->emitIns_R_R_R(INS_uabd, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B);
7976     theEmitter->emitIns_R_R_R(INS_uabd, EA_16BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_16B);
7977     theEmitter->emitIns_R_R_R(INS_uabd, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_4H);
7978     theEmitter->emitIns_R_R_R(INS_uabd, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_8H);
7979     theEmitter->emitIns_R_R_R(INS_uabd, EA_8BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_2S);
7980     theEmitter->emitIns_R_R_R(INS_uabd, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S);
7981 #endif // ALL_ARM64_EMITTER_UNIT_TESTS
7982
7983 #ifdef ALL_ARM64_EMITTER_UNIT_TESTS
7984     // smax vector
7985     theEmitter->emitIns_R_R_R(INS_smax, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B);
7986     theEmitter->emitIns_R_R_R(INS_smax, EA_16BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_16B);
7987     theEmitter->emitIns_R_R_R(INS_smax, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_4H);
7988     theEmitter->emitIns_R_R_R(INS_smax, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_8H);
7989     theEmitter->emitIns_R_R_R(INS_smax, EA_8BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_2S);
7990     theEmitter->emitIns_R_R_R(INS_smax, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S);
7991
7992     // smin vector
7993     theEmitter->emitIns_R_R_R(INS_smin, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B);
7994     theEmitter->emitIns_R_R_R(INS_smin, EA_16BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_16B);
7995     theEmitter->emitIns_R_R_R(INS_smin, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_4H);
7996     theEmitter->emitIns_R_R_R(INS_smin, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_8H);
7997     theEmitter->emitIns_R_R_R(INS_smin, EA_8BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_2S);
7998     theEmitter->emitIns_R_R_R(INS_smin, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S);
7999
8000     // umax vector
8001     theEmitter->emitIns_R_R_R(INS_umax, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B);
8002     theEmitter->emitIns_R_R_R(INS_umax, EA_16BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_16B);
8003     theEmitter->emitIns_R_R_R(INS_umax, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_4H);
8004     theEmitter->emitIns_R_R_R(INS_umax, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_8H);
8005     theEmitter->emitIns_R_R_R(INS_umax, EA_8BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_2S);
8006     theEmitter->emitIns_R_R_R(INS_umax, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S);
8007
8008     // umin vector
8009     theEmitter->emitIns_R_R_R(INS_umin, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B);
8010     theEmitter->emitIns_R_R_R(INS_umin, EA_16BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_16B);
8011     theEmitter->emitIns_R_R_R(INS_umin, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_4H);
8012     theEmitter->emitIns_R_R_R(INS_umin, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_8H);
8013     theEmitter->emitIns_R_R_R(INS_umin, EA_8BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_2S);
8014     theEmitter->emitIns_R_R_R(INS_umin, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S);
8015
8016     // cmeq vector
8017     theEmitter->emitIns_R_R_R(INS_cmeq, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B);
8018     theEmitter->emitIns_R_R_R(INS_cmeq, EA_16BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_16B);
8019     theEmitter->emitIns_R_R_R(INS_cmeq, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_4H);
8020     theEmitter->emitIns_R_R_R(INS_cmeq, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_8H);
8021     theEmitter->emitIns_R_R_R(INS_cmeq, EA_8BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_2S);
8022     theEmitter->emitIns_R_R_R(INS_cmeq, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S);
8023     theEmitter->emitIns_R_R_R(INS_cmeq, EA_8BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_1D);
8024     theEmitter->emitIns_R_R_R(INS_cmeq, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_2D);
8025
8026     // cmge vector
8027     theEmitter->emitIns_R_R_R(INS_cmge, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B);
8028     theEmitter->emitIns_R_R_R(INS_cmge, EA_16BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_16B);
8029     theEmitter->emitIns_R_R_R(INS_cmge, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_4H);
8030     theEmitter->emitIns_R_R_R(INS_cmge, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_8H);
8031     theEmitter->emitIns_R_R_R(INS_cmge, EA_8BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_2S);
8032     theEmitter->emitIns_R_R_R(INS_cmge, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S);
8033     theEmitter->emitIns_R_R_R(INS_cmge, EA_8BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_1D);
8034     theEmitter->emitIns_R_R_R(INS_cmge, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_2D);
8035
8036     // cmgt vector
8037     theEmitter->emitIns_R_R_R(INS_cmgt, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B);
8038     theEmitter->emitIns_R_R_R(INS_cmgt, EA_16BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_16B);
8039     theEmitter->emitIns_R_R_R(INS_cmgt, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_4H);
8040     theEmitter->emitIns_R_R_R(INS_cmgt, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_8H);
8041     theEmitter->emitIns_R_R_R(INS_cmgt, EA_8BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_2S);
8042     theEmitter->emitIns_R_R_R(INS_cmgt, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S);
8043     theEmitter->emitIns_R_R_R(INS_cmgt, EA_8BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_1D);
8044     theEmitter->emitIns_R_R_R(INS_cmgt, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_2D);
8045
8046     // cmhi vector
8047     theEmitter->emitIns_R_R_R(INS_cmhi, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B);
8048     theEmitter->emitIns_R_R_R(INS_cmhi, EA_16BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_16B);
8049     theEmitter->emitIns_R_R_R(INS_cmhi, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_4H);
8050     theEmitter->emitIns_R_R_R(INS_cmhi, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_8H);
8051     theEmitter->emitIns_R_R_R(INS_cmhi, EA_8BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_2S);
8052     theEmitter->emitIns_R_R_R(INS_cmhi, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S);
8053     theEmitter->emitIns_R_R_R(INS_cmhi, EA_8BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_1D);
8054     theEmitter->emitIns_R_R_R(INS_cmhi, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_2D);
8055
8056     // cmhs vector
8057     theEmitter->emitIns_R_R_R(INS_cmhs, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B);
8058     theEmitter->emitIns_R_R_R(INS_cmhs, EA_16BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_16B);
8059     theEmitter->emitIns_R_R_R(INS_cmhs, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_4H);
8060     theEmitter->emitIns_R_R_R(INS_cmhs, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_8H);
8061     theEmitter->emitIns_R_R_R(INS_cmhs, EA_8BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_2S);
8062     theEmitter->emitIns_R_R_R(INS_cmhs, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S);
8063     theEmitter->emitIns_R_R_R(INS_cmhs, EA_8BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_1D);
8064     theEmitter->emitIns_R_R_R(INS_cmhs, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_2D);
8065
8066     // ctst vector
8067     theEmitter->emitIns_R_R_R(INS_ctst, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B);
8068     theEmitter->emitIns_R_R_R(INS_ctst, EA_16BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_16B);
8069     theEmitter->emitIns_R_R_R(INS_ctst, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_4H);
8070     theEmitter->emitIns_R_R_R(INS_ctst, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_8H);
8071     theEmitter->emitIns_R_R_R(INS_ctst, EA_8BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_2S);
8072     theEmitter->emitIns_R_R_R(INS_ctst, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S);
8073     theEmitter->emitIns_R_R_R(INS_ctst, EA_8BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_1D);
8074     theEmitter->emitIns_R_R_R(INS_ctst, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_2D);
8075
8076     // faddp vector
8077     theEmitter->emitIns_R_R_R(INS_faddp, EA_8BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_2S);
8078     theEmitter->emitIns_R_R_R(INS_faddp, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S);
8079     theEmitter->emitIns_R_R_R(INS_faddp, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_2D);
8080
8081     // fcmeq vector
8082     theEmitter->emitIns_R_R_R(INS_fcmeq, EA_8BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_2S);
8083     theEmitter->emitIns_R_R_R(INS_fcmeq, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S);
8084     theEmitter->emitIns_R_R_R(INS_fcmeq, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_2D);
8085
8086     // fcmge vector
8087     theEmitter->emitIns_R_R_R(INS_fcmge, EA_8BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_2S);
8088     theEmitter->emitIns_R_R_R(INS_fcmge, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S);
8089     theEmitter->emitIns_R_R_R(INS_fcmge, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_2D);
8090
8091     // fcmgt vector
8092     theEmitter->emitIns_R_R_R(INS_fcmgt, EA_8BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_2S);
8093     theEmitter->emitIns_R_R_R(INS_fcmgt, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S);
8094     theEmitter->emitIns_R_R_R(INS_fcmgt, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_2D);
8095 #endif // ALL_ARM64_EMITTER_UNIT_TESTS
8096
8097 #ifdef ALL_ARM64_EMITTER_UNIT_TESTS
8098     //
8099     // R_R_R  vector multiply
8100     //
8101
8102     genDefineTempLabel(genCreateTempLabel());
8103
8104     theEmitter->emitIns_R_R_R(INS_mul, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B);
8105     theEmitter->emitIns_R_R_R(INS_mul, EA_8BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_4H);
8106     theEmitter->emitIns_R_R_R(INS_mul, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_2S);
8107     theEmitter->emitIns_R_R_R(INS_mul, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_16B);
8108     theEmitter->emitIns_R_R_R(INS_mul, EA_16BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_8H);
8109     theEmitter->emitIns_R_R_R(INS_mul, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S);
8110
8111     theEmitter->emitIns_R_R_R(INS_pmul, EA_8BYTE, REG_V18, REG_V19, REG_V20, INS_OPTS_8B);
8112     theEmitter->emitIns_R_R_R(INS_pmul, EA_16BYTE, REG_V21, REG_V22, REG_V23, INS_OPTS_16B);
8113
8114     // 'mul' vector by elem
8115     theEmitter->emitIns_R_R_R_I(INS_mul, EA_8BYTE, REG_V0, REG_V1, REG_V16, 0, INS_OPTS_2S);
8116     theEmitter->emitIns_R_R_R_I(INS_mul, EA_8BYTE, REG_V2, REG_V3, REG_V15, 1, INS_OPTS_2S);
8117     theEmitter->emitIns_R_R_R_I(INS_mul, EA_8BYTE, REG_V4, REG_V5, REG_V17, 3, INS_OPTS_2S);
8118     theEmitter->emitIns_R_R_R_I(INS_mul, EA_8BYTE, REG_V6, REG_V7, REG_V0, 0, INS_OPTS_4H);
8119     theEmitter->emitIns_R_R_R_I(INS_mul, EA_8BYTE, REG_V8, REG_V9, REG_V1, 3, INS_OPTS_4H);
8120     theEmitter->emitIns_R_R_R_I(INS_mul, EA_8BYTE, REG_V10, REG_V11, REG_V2, 7, INS_OPTS_4H);
8121     theEmitter->emitIns_R_R_R_I(INS_mul, EA_16BYTE, REG_V12, REG_V13, REG_V14, 0, INS_OPTS_4S);
8122     theEmitter->emitIns_R_R_R_I(INS_mul, EA_16BYTE, REG_V14, REG_V15, REG_V18, 1, INS_OPTS_4S);
8123     theEmitter->emitIns_R_R_R_I(INS_mul, EA_16BYTE, REG_V16, REG_V17, REG_V13, 3, INS_OPTS_4S);
8124     theEmitter->emitIns_R_R_R_I(INS_mul, EA_16BYTE, REG_V18, REG_V19, REG_V3, 0, INS_OPTS_8H);
8125     theEmitter->emitIns_R_R_R_I(INS_mul, EA_16BYTE, REG_V20, REG_V21, REG_V4, 3, INS_OPTS_8H);
8126     theEmitter->emitIns_R_R_R_I(INS_mul, EA_16BYTE, REG_V22, REG_V23, REG_V5, 7, INS_OPTS_8H);
8127
8128     // 'mla' vector by elem
8129     theEmitter->emitIns_R_R_R_I(INS_mla, EA_8BYTE, REG_V0, REG_V1, REG_V16, 0, INS_OPTS_2S);
8130     theEmitter->emitIns_R_R_R_I(INS_mla, EA_8BYTE, REG_V2, REG_V3, REG_V15, 1, INS_OPTS_2S);
8131     theEmitter->emitIns_R_R_R_I(INS_mla, EA_8BYTE, REG_V4, REG_V5, REG_V17, 3, INS_OPTS_2S);
8132     theEmitter->emitIns_R_R_R_I(INS_mla, EA_8BYTE, REG_V6, REG_V7, REG_V0, 0, INS_OPTS_4H);
8133     theEmitter->emitIns_R_R_R_I(INS_mla, EA_8BYTE, REG_V8, REG_V9, REG_V1, 3, INS_OPTS_4H);
8134     theEmitter->emitIns_R_R_R_I(INS_mla, EA_8BYTE, REG_V10, REG_V11, REG_V2, 7, INS_OPTS_4H);
8135     theEmitter->emitIns_R_R_R_I(INS_mla, EA_16BYTE, REG_V12, REG_V13, REG_V14, 0, INS_OPTS_4S);
8136     theEmitter->emitIns_R_R_R_I(INS_mla, EA_16BYTE, REG_V14, REG_V15, REG_V18, 1, INS_OPTS_4S);
8137     theEmitter->emitIns_R_R_R_I(INS_mla, EA_16BYTE, REG_V16, REG_V17, REG_V13, 3, INS_OPTS_4S);
8138     theEmitter->emitIns_R_R_R_I(INS_mla, EA_16BYTE, REG_V18, REG_V19, REG_V3, 0, INS_OPTS_8H);
8139     theEmitter->emitIns_R_R_R_I(INS_mla, EA_16BYTE, REG_V20, REG_V21, REG_V4, 3, INS_OPTS_8H);
8140     theEmitter->emitIns_R_R_R_I(INS_mla, EA_16BYTE, REG_V22, REG_V23, REG_V5, 7, INS_OPTS_8H);
8141
8142     // 'mls' vector by elem
8143     theEmitter->emitIns_R_R_R_I(INS_mls, EA_8BYTE, REG_V0, REG_V1, REG_V16, 0, INS_OPTS_2S);
8144     theEmitter->emitIns_R_R_R_I(INS_mls, EA_8BYTE, REG_V2, REG_V3, REG_V15, 1, INS_OPTS_2S);
8145     theEmitter->emitIns_R_R_R_I(INS_mls, EA_8BYTE, REG_V4, REG_V5, REG_V17, 3, INS_OPTS_2S);
8146     theEmitter->emitIns_R_R_R_I(INS_mls, EA_8BYTE, REG_V6, REG_V7, REG_V0, 0, INS_OPTS_4H);
8147     theEmitter->emitIns_R_R_R_I(INS_mls, EA_8BYTE, REG_V8, REG_V9, REG_V1, 3, INS_OPTS_4H);
8148     theEmitter->emitIns_R_R_R_I(INS_mls, EA_8BYTE, REG_V10, REG_V11, REG_V2, 7, INS_OPTS_4H);
8149     theEmitter->emitIns_R_R_R_I(INS_mls, EA_16BYTE, REG_V12, REG_V13, REG_V14, 0, INS_OPTS_4S);
8150     theEmitter->emitIns_R_R_R_I(INS_mls, EA_16BYTE, REG_V14, REG_V15, REG_V18, 1, INS_OPTS_4S);
8151     theEmitter->emitIns_R_R_R_I(INS_mls, EA_16BYTE, REG_V16, REG_V17, REG_V13, 3, INS_OPTS_4S);
8152     theEmitter->emitIns_R_R_R_I(INS_mls, EA_16BYTE, REG_V18, REG_V19, REG_V3, 0, INS_OPTS_8H);
8153     theEmitter->emitIns_R_R_R_I(INS_mls, EA_16BYTE, REG_V20, REG_V21, REG_V4, 3, INS_OPTS_8H);
8154     theEmitter->emitIns_R_R_R_I(INS_mls, EA_16BYTE, REG_V22, REG_V23, REG_V5, 7, INS_OPTS_8H);
8155
8156 #endif // ALL_ARM64_EMITTER_UNIT_TESTS
8157
8158 #ifdef ALL_ARM64_EMITTER_UNIT_TESTS
8159     //
8160     // R_R_R   floating point operations, one source/dest, and two source
8161     //
8162
8163     genDefineTempLabel(genCreateTempLabel());
8164
8165     theEmitter->emitIns_R_R_R(INS_fmla, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_2S);
8166     theEmitter->emitIns_R_R_R(INS_fmla, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_4S);
8167     theEmitter->emitIns_R_R_R(INS_fmla, EA_16BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_2D);
8168
8169     theEmitter->emitIns_R_R_R_I(INS_fmla, EA_4BYTE, REG_V15, REG_V16, REG_V17, 3); // scalar by elem 4BYTE
8170     theEmitter->emitIns_R_R_R_I(INS_fmla, EA_8BYTE, REG_V18, REG_V19, REG_V20, 1); // scalar by elem 8BYTE
8171     theEmitter->emitIns_R_R_R_I(INS_fmla, EA_8BYTE, REG_V21, REG_V22, REG_V23, 0, INS_OPTS_2S);
8172     theEmitter->emitIns_R_R_R_I(INS_fmla, EA_16BYTE, REG_V24, REG_V25, REG_V26, 2, INS_OPTS_4S);
8173     theEmitter->emitIns_R_R_R_I(INS_fmla, EA_16BYTE, REG_V27, REG_V28, REG_V29, 0, INS_OPTS_2D);
8174
8175     theEmitter->emitIns_R_R_R(INS_fmls, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_2S);
8176     theEmitter->emitIns_R_R_R(INS_fmls, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_4S);
8177     theEmitter->emitIns_R_R_R(INS_fmls, EA_16BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_2D);
8178
8179     theEmitter->emitIns_R_R_R_I(INS_fmls, EA_4BYTE, REG_V15, REG_V16, REG_V17, 3); // scalar by elem 4BYTE
8180     theEmitter->emitIns_R_R_R_I(INS_fmls, EA_8BYTE, REG_V18, REG_V19, REG_V20, 1); // scalar by elem 8BYTE
8181     theEmitter->emitIns_R_R_R_I(INS_fmls, EA_8BYTE, REG_V21, REG_V22, REG_V23, 0, INS_OPTS_2S);
8182     theEmitter->emitIns_R_R_R_I(INS_fmls, EA_16BYTE, REG_V24, REG_V25, REG_V26, 2, INS_OPTS_4S);
8183     theEmitter->emitIns_R_R_R_I(INS_fmls, EA_16BYTE, REG_V27, REG_V28, REG_V29, 0, INS_OPTS_2D);
8184
8185 #endif // ALL_ARM64_EMITTER_UNIT_TESTS
8186
8187 #ifdef ALL_ARM64_EMITTER_UNIT_TESTS
8188     //
8189     // R_R_R_R   floating point operations, one dest, and three source
8190     //
8191
8192     theEmitter->emitIns_R_R_R_R(INS_fmadd, EA_4BYTE, REG_V0, REG_V8, REG_V16, REG_V24);
8193     theEmitter->emitIns_R_R_R_R(INS_fmsub, EA_4BYTE, REG_V1, REG_V9, REG_V17, REG_V25);
8194     theEmitter->emitIns_R_R_R_R(INS_fnmadd, EA_4BYTE, REG_V2, REG_V10, REG_V18, REG_V26);
8195     theEmitter->emitIns_R_R_R_R(INS_fnmsub, EA_4BYTE, REG_V3, REG_V11, REG_V19, REG_V27);
8196
8197     theEmitter->emitIns_R_R_R_R(INS_fmadd, EA_8BYTE, REG_V4, REG_V12, REG_V20, REG_V28);
8198     theEmitter->emitIns_R_R_R_R(INS_fmsub, EA_8BYTE, REG_V5, REG_V13, REG_V21, REG_V29);
8199     theEmitter->emitIns_R_R_R_R(INS_fnmadd, EA_8BYTE, REG_V6, REG_V14, REG_V22, REG_V30);
8200     theEmitter->emitIns_R_R_R_R(INS_fnmsub, EA_8BYTE, REG_V7, REG_V15, REG_V23, REG_V31);
8201
8202 #endif
8203
8204 #ifdef ALL_ARM64_EMITTER_UNIT_TESTS
8205
8206     BasicBlock* label = genCreateTempLabel();
8207     genDefineTempLabel(label);
8208     instGen(INS_nop);
8209     instGen(INS_nop);
8210     instGen(INS_nop);
8211     instGen(INS_nop);
8212     theEmitter->emitIns_R_L(INS_adr, EA_4BYTE_DSP_RELOC, label, REG_R0);
8213
8214 #endif // ALL_ARM64_EMITTER_UNIT_TESTS
8215
8216     printf("*************** End of genArm64EmitterUnitTests()\n");
8217 }
8218 #endif // defined(DEBUG)
8219
8220 #endif // _TARGET_ARM64_
8221
8222 #endif // !LEGACY_BACKEND