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.
5 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10 XX The interface to generate a machine-instruction. XX
12 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
13 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
25 /*****************************************************************************/
28 /*****************************************************************************
30 * Returns the string representation of the given CPU instruction.
33 const char* CodeGen::genInsName(instruction ins)
37 const char * const insNames[] =
39 #if defined(_TARGET_XARCH_)
40 #define INST0(id, nm, fp, um, rf, wf, mr ) nm,
41 #define INST1(id, nm, fp, um, rf, wf, mr ) nm,
42 #define INST2(id, nm, fp, um, rf, wf, mr, mi ) nm,
43 #define INST3(id, nm, fp, um, rf, wf, mr, mi, rm ) nm,
44 #define INST4(id, nm, fp, um, rf, wf, mr, mi, rm, a4 ) nm,
45 #define INST5(id, nm, fp, um, rf, wf, mr, mi, rm, a4, rr ) nm,
48 #elif defined(_TARGET_ARM_)
49 #define INST1(id, nm, fp, ldst, fmt, e1 ) nm,
50 #define INST2(id, nm, fp, ldst, fmt, e1, e2 ) nm,
51 #define INST3(id, nm, fp, ldst, fmt, e1, e2, e3 ) nm,
52 #define INST4(id, nm, fp, ldst, fmt, e1, e2, e3, e4 ) nm,
53 #define INST5(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5 ) nm,
54 #define INST6(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6 ) nm,
55 #define INST8(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6, e7, e8 ) nm,
56 #define INST9(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6, e7, e8, e9 ) nm,
59 #elif defined(_TARGET_ARM64_)
60 #define INST1(id, nm, fp, ldst, fmt, e1 ) nm,
61 #define INST2(id, nm, fp, ldst, fmt, e1, e2 ) nm,
62 #define INST3(id, nm, fp, ldst, fmt, e1, e2, e3 ) nm,
63 #define INST4(id, nm, fp, ldst, fmt, e1, e2, e3, e4 ) nm,
64 #define INST5(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5 ) nm,
65 #define INST6(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6 ) nm,
66 #define INST9(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6, e7, e8, e9 ) nm,
70 #error "Unknown _TARGET_"
75 assert((unsigned)ins < sizeof(insNames) / sizeof(insNames[0]));
76 assert(insNames[ins] != nullptr);
81 void __cdecl CodeGen::instDisp(instruction ins, bool noNL, const char* fmt, ...)
83 if (compiler->opts.dspCode)
85 /* Display the instruction offset within the emit block */
87 // printf("[%08X:%04X]", getEmitter().emitCodeCurBlock(), getEmitter().emitCodeOffsInBlock());
89 /* Display the FP stack depth (before the instruction is executed) */
91 // printf("[FP=%02u] ", genGetFPstkLevel());
93 /* Display the instruction mnemonic */
96 printf(" %-8s", genInsName(ins));
113 /*****************************************************************************/
115 /*****************************************************************************/
117 void CodeGen::instInit()
121 /*****************************************************************************
123 * Return the size string (e.g. "word ptr") appropriate for the given size.
128 const char* CodeGen::genSizeStr(emitAttr attr)
132 const char * const sizes[] =
151 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
152 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
157 unsigned size = EA_SIZE(attr);
159 assert(size == 0 || size == 1 || size == 2 || size == 4 || size == 8 || size == 16 || size == 32);
161 if (EA_ATTR(size) == attr)
165 else if (attr == EA_GCREF)
169 else if (attr == EA_BYREF)
173 else if (EA_IS_DSP_RELOC(attr))
179 assert(!"Unexpected");
186 /*****************************************************************************
188 * Generate an instruction.
191 void CodeGen::instGen(instruction ins)
194 getEmitter()->emitIns(ins);
196 #ifdef _TARGET_XARCH_
197 // A workaround necessitated by limitations of emitter
198 // if we are scheduled to insert a nop here, we have to delay it
199 // hopefully we have not missed any other prefix instructions or places
200 // they could be inserted
201 if (ins == INS_lock && getEmitter()->emitNextNop == 0)
203 getEmitter()->emitNextNop = 1;
208 /*****************************************************************************
210 * Returns non-zero if the given CPU instruction is a floating-point ins.
214 bool CodeGenInterface::instIsFP(instruction ins)
216 assert((unsigned)ins < sizeof(instInfo) / sizeof(instInfo[0]));
218 return (instInfo[ins] & INST_FP) != 0;
221 #ifdef _TARGET_XARCH_
222 /*****************************************************************************
224 * Generate a multi-byte NOP instruction.
227 void CodeGen::instNop(unsigned size)
230 getEmitter()->emitIns_Nop(size);
234 /*****************************************************************************
236 * Generate a jump instruction.
239 void CodeGen::inst_JMP(emitJumpKind jmp, BasicBlock* tgtBlock)
241 #if !FEATURE_FIXED_OUT_ARGS
242 // On the x86 we are pushing (and changing the stack level), but on x64 and other archs we have
243 // a fixed outgoing args area that we store into and we never change the stack level when calling methods.
245 // Thus only on x86 do we need to assert that the stack level at the target block matches the current stack level.
247 CLANG_FORMAT_COMMENT_ANCHOR;
250 // bbTgtStkDepth is a (pure) argument count (stack alignment padding should be excluded).
251 assert((tgtBlock->bbTgtStkDepth * sizeof(int) == (genStackLevel - curNestedAlignment)) || isFramePointerUsed());
253 assert((tgtBlock->bbTgtStkDepth * sizeof(int) == genStackLevel) || isFramePointerUsed());
255 #endif // !FEATURE_FIXED_OUT_ARGS
257 getEmitter()->emitIns_J(emitter::emitJumpKindToIns(jmp), tgtBlock);
260 /*****************************************************************************
262 * Generate a set instruction.
265 void CodeGen::inst_SET(emitJumpKind condition, regNumber reg)
267 #ifdef _TARGET_XARCH_
270 /* Convert the condition to an instruction opcode */
321 NO_WAY("unexpected condition type");
325 assert(genRegMask(reg) & RBM_BYTE_REGS);
327 // These instructions only write the low byte of 'reg'
328 getEmitter()->emitIns_R(ins, EA_1BYTE, reg);
329 #elif defined(_TARGET_ARM64_)
331 /* Convert the condition to an insCond value */
381 NO_WAY("unexpected condition type");
384 getEmitter()->emitIns_R_COND(INS_cset, EA_8BYTE, reg, cond);
390 /*****************************************************************************
392 * Generate a "op reg" instruction.
395 void CodeGen::inst_RV(instruction ins, regNumber reg, var_types type, emitAttr size)
397 if (size == EA_UNKNOWN)
399 size = emitActualTypeSize(type);
402 getEmitter()->emitIns_R(ins, size, reg);
405 /*****************************************************************************
407 * Generate a "op reg1, reg2" instruction.
410 void CodeGen::inst_RV_RV(instruction ins,
415 insFlags flags /* = INS_FLAGS_DONT_CARE */)
417 if (size == EA_UNKNOWN)
419 size = emitActualTypeSize(type);
423 getEmitter()->emitIns_R_R(ins, size, reg1, reg2, flags);
425 getEmitter()->emitIns_R_R(ins, size, reg1, reg2);
429 /*****************************************************************************
431 * Generate a "op reg1, reg2, reg3" instruction.
434 void CodeGen::inst_RV_RV_RV(instruction ins,
439 insFlags flags /* = INS_FLAGS_DONT_CARE */)
442 getEmitter()->emitIns_R_R_R(ins, size, reg1, reg2, reg3, flags);
443 #elif defined(_TARGET_XARCH_)
444 getEmitter()->emitIns_R_R_R(ins, size, reg1, reg2, reg3);
446 NYI("inst_RV_RV_RV");
449 /*****************************************************************************
451 * Generate a "op icon" instruction.
454 void CodeGen::inst_IV(instruction ins, int val)
456 getEmitter()->emitIns_I(ins, EA_PTRSIZE, val);
459 /*****************************************************************************
461 * Generate a "op icon" instruction where icon is a handle of type specified
465 void CodeGen::inst_IV_handle(instruction ins, int val)
467 getEmitter()->emitIns_I(ins, EA_HANDLE_CNS_RELOC, val);
470 #if FEATURE_STACK_FP_X87
471 /*****************************************************************************
473 * Generate a "op ST(n), ST(0)" instruction.
476 void CodeGen::inst_FS(instruction ins, unsigned stk)
486 break; // Implicit operand of compp is ST(1)
489 assert(!"don't do this. Do you want to use inst_FN() instead?");
497 getEmitter()->emitIns_F_F0(ins, stk);
500 /*****************************************************************************
502 * Generate a "op ST(0), ST(n)" instruction
505 void CodeGenInterface::inst_FN(instruction ins, unsigned stk)
522 assert(!"don't do this. Do you want to use inst_FS() instead?");
530 getEmitter()->emitIns_F0_F(ins, stk);
532 #endif // FEATURE_STACK_FP_X87
534 /*****************************************************************************
536 * Display a stack frame reference.
539 void CodeGen::inst_set_SV_var(GenTreePtr tree)
542 assert(tree && (tree->gtOper == GT_LCL_VAR || tree->gtOper == GT_LCL_VAR_ADDR || tree->gtOper == GT_STORE_LCL_VAR));
543 assert(tree->gtLclVarCommon.gtLclNum < compiler->lvaCount);
545 getEmitter()->emitVarRefOffs = tree->gtLclVar.gtLclILoffs;
550 /*****************************************************************************
552 * Generate a "op reg, icon" instruction.
555 void CodeGen::inst_RV_IV(
556 instruction ins, regNumber reg, ssize_t val, emitAttr size, insFlags flags /* = INS_FLAGS_DONT_CARE */)
558 #if !defined(_TARGET_64BIT_)
559 assert(size != EA_8BYTE);
563 if (arm_Valid_Imm_For_Instr(ins, val, flags))
565 getEmitter()->emitIns_R_I(ins, size, reg, val, flags);
567 else if (ins == INS_mov)
569 instGen_Set_Reg_To_Imm(size, reg, val);
573 #ifndef LEGACY_BACKEND
574 // TODO-Cleanup: Add a comment about why this is unreached() for RyuJIT backend.
576 #else // LEGACY_BACKEND
577 regNumber tmpReg = regSet.rsGrabReg(RBM_ALLINT & ~genRegMask(reg));
578 instGen_Set_Reg_To_Imm(size, tmpReg, val);
579 getEmitter()->emitIns_R_R(ins, size, reg, tmpReg, flags);
580 #endif // LEGACY_BACKEND
582 #elif defined(_TARGET_ARM64_)
583 // TODO-Arm64-Bug: handle large constants!
584 // Probably need something like the ARM case above: if (arm_Valid_Imm_For_Instr(ins, val)) ...
585 assert(ins != INS_cmp);
586 assert(ins != INS_tst);
587 assert(ins != INS_mov);
588 getEmitter()->emitIns_R_R_I(ins, size, reg, reg, val);
589 #else // !_TARGET_ARM_
590 #ifdef _TARGET_AMD64_
591 // Instead of an 8-byte immediate load, a 4-byte immediate will do fine
592 // as the high 4 bytes will be zero anyway.
593 if (size == EA_8BYTE && ins == INS_mov && ((val & 0xFFFFFFFF00000000LL) == 0))
596 getEmitter()->emitIns_R_I(ins, size, reg, val);
598 else if (EA_SIZE(size) == EA_8BYTE && ins != INS_mov && (((int)val != val) || EA_IS_CNS_RELOC(size)))
600 #ifndef LEGACY_BACKEND
601 assert(!"Invalid immediate for inst_RV_IV");
602 #else // LEGACY_BACKEND
603 // We can't fit the immediate into this instruction, so move it into
605 regNumber tmpReg = regSet.rsGrabReg(RBM_ALLINT & ~genRegMask(reg));
606 instGen_Set_Reg_To_Imm(size, tmpReg, val);
608 // We might have to switch back from 3-operand imul to two operand form
609 if (instrIs3opImul(ins))
611 assert(getEmitter()->inst3opImulReg(ins) == reg);
614 getEmitter()->emitIns_R_R(ins, EA_TYPE(size), reg, tmpReg);
615 #endif // LEGACY_BACKEND
618 #endif // _TARGET_AMD64_
620 getEmitter()->emitIns_R_I(ins, size, reg, val);
622 #endif // !_TARGET_ARM_
625 #if defined(LEGACY_BACKEND)
626 /*****************************************************************************
627 * Figure out the operands to address the tree.
628 * 'addr' can be one of (1) a pointer to be indirected
629 * (2) a calculation to be done with LEA_AVAILABLE
632 * On return, *baseReg, *indScale, *indReg, and *cns are set.
635 void CodeGen::instGetAddrMode(GenTreePtr addr, regNumber* baseReg, unsigned* indScale, regNumber* indReg, unsigned* cns)
637 if (addr->gtOper == GT_ARR_ELEM)
639 /* For GT_ARR_ELEM, the addressibility registers are marked on
640 gtArrObj and gtArrInds[0] */
642 assert(addr->gtArrElem.gtArrObj->InReg());
643 *baseReg = addr->gtArrElem.gtArrObj->gtRegNum;
645 assert(addr->gtArrElem.gtArrInds[0]->InReg());
646 *indReg = addr->gtArrElem.gtArrInds[0]->gtRegNum;
648 if (jitIsScaleIndexMul(addr->gtArrElem.gtArrElemSize))
649 *indScale = addr->gtArrElem.gtArrElemSize;
653 *cns = compiler->eeGetMDArrayDataOffset(addr->gtArrElem.gtArrElemType, addr->gtArrElem.gtArrRank);
655 else if (addr->gtOper == GT_LEA)
657 GenTreeAddrMode* lea = addr->AsAddrMode();
658 GenTreePtr base = lea->Base();
659 assert(!base || (base->InReg()));
660 GenTreePtr index = lea->Index();
661 assert(!index || (index->InReg()));
663 *baseReg = base ? base->gtRegNum : REG_NA;
664 *indReg = index ? index->gtRegNum : REG_NA;
665 *indScale = lea->gtScale;
666 *cns = lea->gtOffset;
671 /* Figure out what complex address mode to use */
673 GenTreePtr rv1 = NULL;
674 GenTreePtr rv2 = NULL;
678 genCreateAddrMode(addr, -1, true, RBM_NONE, &rev, &rv1, &rv2,
679 #if SCALED_ADDR_MODES
684 assert(yes); // // since we have called genMakeAddressable() on addr
685 // Ensure that the base and index, if used, are in registers.
686 if (rv1 && ((rv1->gtFlags & GTF_REG_VAL) == 0))
688 if (rv1->gtFlags & GTF_SPILLED)
690 genRecoverReg(rv1, RBM_ALLINT, RegSet::KEEP_REG);
694 genCodeForTree(rv1, RBM_NONE);
695 regSet.rsMarkRegUsed(rv1, addr);
697 assert(rv1->gtFlags & GTF_REG_VAL);
699 if (rv2 && !rv2->InReg())
701 if (rv2->gtFlags & GTF_SPILLED)
703 genRecoverReg(rv2, ~genRegMask(rv1->gtRegNum), RegSet::KEEP_REG);
707 genCodeForTree(rv2, RBM_NONE);
708 regSet.rsMarkRegUsed(rv2, addr);
710 assert(rv2->InReg());
712 // If we did both, we might have spilled rv1.
713 if (rv1 && ((rv1->gtFlags & GTF_SPILLED) != 0))
715 regSet.rsLockUsedReg(genRegMask(rv2->gtRegNum));
716 genRecoverReg(rv1, ~genRegMask(rv2->gtRegNum), RegSet::KEEP_REG);
717 regSet.rsUnlockReg(genRegMask(rv2->gtRegNum));
720 *baseReg = rv1 ? rv1->gtRegNum : REG_NA;
721 *indReg = rv2 ? rv2->gtRegNum : REG_NA;
725 #if CPU_LOAD_STORE_ARCH
726 /*****************************************************************************
728 * Originally this was somewhat specific to the x86 instrution format.
729 * For a Load/Store arch we generate the 1-8 instructions necessary to
730 * implement the single addressing mode instruction used on x86.
731 * We currently don't have an instruction scheduler enabled on any target.
733 * [Schedule] an "ins reg, [r/m]" (rdst=true), or "ins [r/m], reg" (rdst=false)
734 * instruction (the r/m operand given by a tree). We also allow instructions
735 * of the form "ins [r/m], icon", these are signaled by setting 'cons' to
738 * The longest instruction sequence emitted on the ARM is as follows:
740 * - the "addr" represents an array addressing mode,
741 * with a baseReg, indReg with a shift and a large offset
742 * (Note that typically array addressing modes do NOT have a large offset)
743 * - "ins" is an ALU instruction,
744 * - cons=true, and imm is a large constant that can not be directly encoded with "ins"
745 * - We may need to grab upto four additional registers: regT, rtegVal, regOffs and regImm
747 * add regT, baseReg, indReg<<shift
748 * movw regOffs, offsLo
749 * movt regOffs, offsHi
750 * ldr regVal, [regT + regOffs]
751 * movw regImm, consLo
752 * movt regImm, consHi
753 * "ins" regVal, regImm
754 * str regVal, [regT + regOffs]
758 void CodeGen::sched_AM(instruction ins,
769 assert(size != EA_UNKNOWN);
778 INS_TYPE insType = eIT_Other;
785 else if (getEmitter()->emitInsIsLoad(ins))
789 else if (getEmitter()->emitInsIsStore(ins))
794 regNumber baseReg = REG_NA;
795 regNumber indReg = REG_NA;
796 unsigned indScale = 0;
798 regMaskTP avoidMask = RBM_NONE;
802 /* The address is "[reg+offs]" */
803 baseReg = addr->gtRegNum;
805 else if (addr->IsCnsIntOrI())
807 // Do we need relocations?
808 if (compiler->opts.compReloc && addr->IsIconHandle())
810 size = EA_SET_FLG(size, EA_DSP_RELOC_FLG);
811 // offs should be smaller than ZapperModule::FixupPlaceHolder
812 // so that we can uniquely identify the handle
815 ssize_t disp = addr->gtIntCon.gtIconVal + offs;
816 if ((insType == eIT_Store) && (ireg != REG_NA))
818 // Can't use the ireg as the baseReg when we have a store instruction
819 avoidMask |= genRegMask(ireg);
821 baseReg = regSet.rsPickFreeReg(RBM_ALLINT & ~avoidMask);
823 avoidMask |= genRegMask(baseReg);
824 instGen_Set_Reg_To_Imm(size, baseReg, disp);
831 instGetAddrMode(addr, &baseReg, &indScale, &indReg, &cns);
833 /* Add the constant offset value, if present */
837 #if SCALED_ADDR_MODES
838 noway_assert((baseReg != REG_NA) || (indReg != REG_NA));
839 if (baseReg != REG_NA)
842 avoidMask |= genRegMask(baseReg);
845 // I don't think this is necessary even in the non-proto-jit case, but better to be
846 // conservative here. It is only necessary to avoid using ireg if it is used as regT,
847 // in which case it will be added to avoidMask below.
851 avoidMask |= genRegMask(ireg);
854 if (indReg != REG_NA)
856 avoidMask |= genRegMask(indReg);
860 unsigned shift = (indScale > 0) ? genLog2((unsigned)indScale) : 0;
862 regNumber regT = REG_NA; // the register where the address is computed into
863 regNumber regOffs = REG_NA; // a temporary register to use for the offs when it can't be directly encoded
864 regNumber regImm = REG_NA; // a temporary register to use for the imm when it can't be directly encoded
865 regNumber regVal = REG_NA; // a temporary register to use when we have to do a load/modify/store operation
868 if (indReg == REG_NA)
870 regT = baseReg; // We can use the baseReg, regT is read-only
872 else // We have an index register (indReg != REG_NA)
874 // Check for special case that we can encode using one instruction
875 if ((offs == 0) && (insType != eIT_Other) && !instIsFP(ins) && baseReg != REG_NA)
877 // ins ireg, [baseReg + indReg << shift]
878 getEmitter()->emitIns_R_R_R_I(ins, size, ireg, baseReg, indReg, shift, flags, INS_OPTS_LSL);
882 // Otherwise setup regT, regT is written once here
884 if (insType == eIT_Lea || (insType == eIT_Load && !instIsFP(ins)))
886 assert(ireg != REG_NA);
887 // ireg will be written, so we can take it as our temporary register
892 // need a new temporary reg
893 regT = regSet.rsPickFreeReg(RBM_ALLINT & ~avoidMask);
894 regTracker.rsTrackRegTrash(regT);
897 #if SCALED_ADDR_MODES
898 if (baseReg == REG_NA)
901 // LSL regT, indReg, shift.
902 getEmitter()->emitIns_R_R_I(INS_lsl, EA_PTRSIZE, regT, indReg, shift & ((TARGET_POINTER_SIZE * 8) - 1));
905 #endif // SCALED_ADDR_MODES
907 assert(baseReg != REG_NA);
909 // add regT, baseReg, indReg<<shift.
910 getEmitter()->emitIns_R_R_R_I(INS_add,
911 // The "add" operation will yield either a pointer or byref, depending on the
913 varTypeIsGC(addr->TypeGet()) ? EA_BYREF : EA_PTRSIZE, regT, baseReg, indReg,
914 shift, INS_FLAGS_NOT_SET, INS_OPTS_LSL);
918 // regT is the base register for a load/store or an operand for add when insType is eIT_Lea
920 assert(regT != REG_NA);
921 avoidMask |= genRegMask(regT);
923 if (insType != eIT_Other)
925 assert((flags != INS_FLAGS_SET) || (insType == eIT_Lea));
926 if ((insType == eIT_Lea) && (offs == 0))
928 // If we have the same register as src and dst and we do not need to set the flags
929 // then we can skip emitting the instruction
930 if ((ireg != regT) || (flags == INS_FLAGS_SET))
933 getEmitter()->emitIns_R_R(INS_mov, size, ireg, regT, flags);
936 else if (arm_Valid_Imm_For_Instr(ins, offs, flags))
938 // ins ireg, [regT + offs]
939 getEmitter()->emitIns_R_R_I(ins, size, ireg, regT, offs, flags);
943 regOffs = regSet.rsPickFreeReg(RBM_ALLINT & ~avoidMask);
945 // We cannot use [regT + regOffs] to load/store a floating register
946 if (emitter::isFloatReg(ireg))
948 if (arm_Valid_Imm_For_Instr(INS_add, offs, flags))
950 // add regOffs, regT, offs
951 getEmitter()->emitIns_R_R_I(INS_add, EA_4BYTE, regOffs, regT, offs, flags);
955 // movw regOffs, offs_lo16
956 // movt regOffs, offs_hi16
957 // add regOffs, regOffs, regT
958 instGen_Set_Reg_To_Imm(EA_4BYTE, regOffs, offs);
959 getEmitter()->emitIns_R_R_R(INS_add, EA_4BYTE, regOffs, regOffs, regT, flags);
961 // ins ireg, [regOffs]
962 getEmitter()->emitIns_R_R_I(ins, size, ireg, regOffs, 0, flags);
964 regTracker.rsTrackRegTrash(regOffs);
969 // ins ireg, [regT + regOffs]
970 instGen_Set_Reg_To_Imm(EA_4BYTE, regOffs, offs);
971 getEmitter()->emitIns_R_R_R(ins, size, ireg, regT, regOffs, flags);
975 else // (insType == eIT_Other);
980 regVal = regSet.rsPickFreeReg(RBM_ALLINT & ~avoidMask);
981 regTracker.rsTrackRegTrash(regVal);
982 avoidMask |= genRegMask(regVal);
983 var_types load_store_type;
987 load_store_type = TYP_INT;
991 load_store_type = TYP_SHORT;
995 load_store_type = TYP_BYTE;
999 assert(!"Unexpected size in sched_AM, eIT_Other");
1000 load_store_type = TYP_INT;
1004 // Load the content at addr into regVal using regT + offs
1005 if (arm_Valid_Disp_For_LdSt(offs, load_store_type))
1007 // ldrX regVal, [regT + offs]
1008 getEmitter()->emitIns_R_R_I(ins_Load(load_store_type), size, regVal, regT, offs);
1012 // mov regOffs, offs
1013 // ldrX regVal, [regT + regOffs]
1014 regOffs = regSet.rsPickFreeReg(RBM_ALLINT & ~avoidMask);
1015 avoidMask |= genRegMask(regOffs);
1016 instGen_Set_Reg_To_Imm(EA_4BYTE, regOffs, offs);
1017 getEmitter()->emitIns_R_R_R(ins_Load(load_store_type), size, regVal, regT, regOffs);
1022 if (arm_Valid_Imm_For_Instr(ins, imm, flags))
1024 getEmitter()->emitIns_R_I(ins, size, regVal, imm, flags);
1028 assert(regOffs == REG_NA);
1029 regImm = regSet.rsPickFreeReg(RBM_ALLINT & ~avoidMask);
1030 avoidMask |= genRegMask(regImm);
1031 instGen_Set_Reg_To_Imm(size, regImm, imm);
1032 getEmitter()->emitIns_R_R(ins, size, regVal, regImm, flags);
1037 getEmitter()->emitIns_R_R(ins, size, ireg, regVal, flags);
1041 getEmitter()->emitIns_R_R(ins, size, regVal, ireg, flags);
1044 // If we do not have a register destination we must perform the write-back store instruction
1045 // (unless we have an instruction like INS_cmp that does not write a destination)
1047 if (!rdst && ins_Writes_Dest(ins))
1049 // Store regVal into [addr]
1050 if (regOffs == REG_NA)
1052 // strX regVal, [regT + offs]
1053 getEmitter()->emitIns_R_R_I(ins_Store(load_store_type), size, regVal, regT, offs);
1057 // strX regVal, [regT + regOffs]
1058 getEmitter()->emitIns_R_R_R(ins_Store(load_store_type), size, regVal, regT, regOffs);
1064 #else // !CPU_LOAD_STORE_ARCH
1066 /*****************************************************************************
1068 * This is somewhat specific to the x86 instrution format.
1069 * We currently don't have an instruction scheduler enabled on any target.
1071 * [Schedule] an "ins reg, [r/m]" (rdst=true), or "ins [r/m], reg" (rdst=false)
1072 * instruction (the r/m operand given by a tree). We also allow instructions
1073 * of the form "ins [r/m], icon", these are signalled by setting 'cons' to
1077 void CodeGen::sched_AM(instruction ins,
1087 #ifdef _TARGET_XARCH_
1088 /* Don't use this method for issuing calls. Use instEmit_xxxCall() */
1089 assert(ins != INS_call);
1093 assert(size != EA_UNKNOWN);
1097 /* Has the address been conveniently loaded into a register,
1098 or is it an absolute value ? */
1100 if ((addr->InReg()) || (addr->IsCnsIntOrI()))
1104 /* The address is "[reg+offs]" */
1106 reg = addr->gtRegNum;
1109 getEmitter()->emitIns_I_AR(ins, size, imm, reg, offs);
1111 getEmitter()->emitIns_R_AR(ins, size, ireg, reg, offs);
1113 getEmitter()->emitIns_AR_R(ins, size, ireg, reg, offs);
1117 /* The address is an absolute value */
1119 assert(addr->IsCnsIntOrI());
1121 // Do we need relocations?
1122 if (compiler->opts.compReloc && addr->IsIconHandle())
1124 size = EA_SET_FLG(size, EA_DSP_RELOC_FLG);
1125 // offs should be smaller than ZapperModule::FixupPlaceHolder
1126 // so that we can uniquely identify the handle
1131 ssize_t disp = addr->gtIntCon.gtIconVal + offs;
1133 // Cross our fingers and hope the codegenerator did the right
1134 // thing and the constant address can be RIP-relative
1137 getEmitter()->emitIns_I_AI(ins, size, imm, disp);
1139 getEmitter()->emitIns_R_AI(ins, size, ireg, disp);
1141 getEmitter()->emitIns_AI_R(ins, size, ireg, disp);
1147 /* Figure out what complex address mode to use */
1149 regNumber baseReg, indReg;
1150 unsigned indScale = 0, cns = 0;
1152 instGetAddrMode(addr, &baseReg, &indScale, &indReg, &cns);
1154 /* Add the constant offset value, if present */
1158 /* Is there an index reg operand? */
1160 if (indReg != REG_NA)
1162 /* Is the index reg operand scaled? */
1166 /* Is there a base address operand? */
1168 if (baseReg != REG_NA)
1172 /* The address is "[reg + {2/4/8} * indReg + offs]" */
1175 getEmitter()->emitIns_I_ARX(ins, size, imm, reg, indReg, indScale, offs);
1177 getEmitter()->emitIns_R_ARX(ins, size, ireg, reg, indReg, indScale, offs);
1179 getEmitter()->emitIns_ARX_R(ins, size, ireg, reg, indReg, indScale, offs);
1183 /* The address is "[{2/4/8} * indReg + offs]" */
1186 getEmitter()->emitIns_I_AX(ins, size, imm, indReg, indScale, offs);
1188 getEmitter()->emitIns_R_AX(ins, size, ireg, indReg, indScale, offs);
1190 getEmitter()->emitIns_AX_R(ins, size, ireg, indReg, indScale, offs);
1195 assert(baseReg != REG_NA);
1198 /* The address is "[reg + indReg + offs]" */
1200 getEmitter()->emitIns_I_ARR(ins, size, imm, reg, indReg, offs);
1202 getEmitter()->emitIns_R_ARR(ins, size, ireg, reg, indReg, offs);
1204 getEmitter()->emitIns_ARR_R(ins, size, ireg, reg, indReg, offs);
1210 CORINFO_CLASS_HANDLE cls = 0;
1212 /* No second operand: the address is "[reg + icon]" */
1214 assert(baseReg != REG_NA);
1219 getEmitter()->emitIns_I_AR(ins, size, imm, reg, offs);
1223 getEmitter()->emitIns_R_AR(ins, size, ireg, reg, offs);
1227 getEmitter()->emitIns_AR_R(ins, size, ireg, reg, offs);
1232 #endif // !CPU_LOAD_STORE_ARCH
1234 /*****************************************************************************
1236 * Emit a "call [r/m]" instruction (the r/m operand given by a tree).
1240 void CodeGen::instEmit_indCall(GenTreeCall* call,
1243 MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize))
1248 emitter::EmitCallType emitCallType;
1250 regNumber brg = REG_NA;
1251 regNumber xrg = REG_NA;
1255 CORINFO_SIG_INFO* sigInfo = nullptr;
1257 /* Get hold of the function address */
1259 assert(call->gtCallType == CT_INDIRECT);
1260 addr = call->gtCallAddr;
1264 // Pass the call signature information from the GenTree node so the emitter can associate
1265 // native call sites with the signatures they were generated from.
1266 sigInfo = call->callSig;
1269 #if CPU_LOAD_STORE_ARCH
1271 emitCallType = emitter::EC_INDIR_R;
1273 if (!addr->OperIsIndir())
1275 if (!(addr->InReg()) && (addr->OperGet() == GT_CNS_INT))
1277 ssize_t funcPtr = addr->gtIntCon.gtIconVal;
1280 getEmitter()->emitIns_Call(emitter::EC_FUNC_ADDR,
1282 INDEBUG_LDISASM_COMMA(sigInfo)
1286 MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(secondRetSize),
1287 gcInfo.gcVarPtrSetCur,
1288 gcInfo.gcRegGCrefSetCur,
1289 gcInfo.gcRegByrefSetCur);
1297 /* Get hold of the address of the function pointer */
1299 addr = addr->gtOp.gtOp1;
1304 /* The address is "reg" */
1306 brg = addr->gtRegNum;
1310 // Force the address into a register
1311 CLANG_FORMAT_COMMENT_ANCHOR;
1313 #ifdef LEGACY_BACKEND
1314 genCodeForTree(addr, RBM_NONE);
1315 #endif // LEGACY_BACKEND
1316 assert(addr->InReg());
1317 brg = addr->gtRegNum;
1320 #else // CPU_LOAD_STORE_ARCH
1322 /* Is there an indirection? */
1324 if (!addr->OperIsIndir())
1328 emitCallType = emitter::EC_INDIR_R;
1329 brg = addr->gtRegNum;
1333 if (addr->OperGet() != GT_CNS_INT)
1335 assert(addr->OperGet() == GT_LCL_VAR);
1337 emitCallType = emitter::EC_INDIR_SR;
1338 cns = addr->gtLclVarCommon.gtLclNum;
1342 ssize_t funcPtr = addr->gtIntCon.gtIconVal;
1345 getEmitter()->emitIns_Call(emitter::EC_FUNC_ADDR,
1347 INDEBUG_LDISASM_COMMA(sigInfo)
1351 MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(secondRetSize),
1352 gcInfo.gcVarPtrSetCur,
1353 gcInfo.gcRegGCrefSetCur,
1354 gcInfo.gcRegByrefSetCur);
1363 /* This is an indirect call */
1365 emitCallType = emitter::EC_INDIR_ARD;
1367 /* Get hold of the address of the function pointer */
1369 addr = addr->gtOp.gtOp1;
1371 /* Has the address been conveniently loaded into a register? */
1375 /* The address is "reg" */
1377 brg = addr->gtRegNum;
1383 GenTreePtr rv1 = nullptr;
1384 GenTreePtr rv2 = nullptr;
1386 /* Figure out what complex address mode to use */
1389 genCreateAddrMode(addr, -1, true, RBM_NONE, &rev, &rv1, &rv2, &mul, &cns);
1391 INDEBUG(PREFIX_ASSUME(yes)); // since we have called genMakeAddressable() on call->gtCallAddr
1393 /* Get the additional operands if any */
1397 assert(rv1->InReg());
1398 brg = rv1->gtRegNum;
1403 assert(rv2->InReg());
1404 xrg = rv2->gtRegNum;
1409 assert(emitCallType == emitter::EC_INDIR_R || emitCallType == emitter::EC_INDIR_SR ||
1410 emitCallType == emitter::EC_INDIR_C || emitCallType == emitter::EC_INDIR_ARD);
1412 #endif // CPU_LOAD_STORE_ARCH
1415 getEmitter()->emitIns_Call(emitCallType,
1417 INDEBUG_LDISASM_COMMA(sigInfo)
1421 MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(secondRetSize),
1422 gcInfo.gcVarPtrSetCur,
1423 gcInfo.gcRegGCrefSetCur,
1424 gcInfo.gcRegByrefSetCur,
1425 BAD_IL_OFFSET, // ilOffset
1429 cns); // addressing mode values
1433 /*****************************************************************************
1435 * Emit an "op [r/m]" instruction (the r/m operand given by a tree).
1438 void CodeGen::instEmit_RM(instruction ins, GenTreePtr tree, GenTreePtr addr, unsigned offs)
1443 size = emitTypeSize(tree->TypeGet());
1445 size = EA_ATTR(genTypeSize(tree->TypeGet()));
1447 sched_AM(ins, size, REG_NA, false, addr, offs);
1450 /*****************************************************************************
1452 * Emit an "op [r/m], reg" instruction (the r/m operand given by a tree).
1455 void CodeGen::instEmit_RM_RV(instruction ins, emitAttr size, GenTreePtr tree, regNumber reg, unsigned offs)
1457 #ifdef _TARGET_XARCH_
1458 assert(instIsFP(ins) == 0);
1460 sched_AM(ins, size, reg, false, tree, offs);
1462 #endif // LEGACY_BACKEND
1464 /*****************************************************************************
1466 * Generate an instruction that has one operand given by a tree (which has
1467 * been made addressable).
1470 void CodeGen::inst_TT(instruction ins, GenTreePtr tree, unsigned offs, int shfv, emitAttr size)
1472 bool sizeInferred = false;
1474 if (size == EA_UNKNOWN)
1476 sizeInferred = true;
1479 size = EA_ATTR(genTypeSize(tree->TypeGet()));
1483 size = emitTypeSize(tree->TypeGet());
1489 #ifdef LEGACY_BACKEND
1490 /* Is the value sitting in a register? */
1496 #ifndef _TARGET_64BIT_
1500 #if FEATURE_STACK_FP_X87
1502 /* Is this a floating-point instruction? */
1504 if (isFloatRegType(tree->gtType))
1506 reg = tree->gtRegNum;
1508 assert(instIsFP(ins) && ins != INS_fst && ins != INS_fstp);
1511 inst_FS(ins, reg + genGetFPstkLevel());
1514 #endif // FEATURE_STACK_FP_X87
1516 assert(!instIsFP(ins));
1518 #if CPU_LONG_USES_REGPAIR
1519 if (tree->gtType == TYP_LONG)
1523 assert(offs == sizeof(int));
1524 reg = genRegPairHi(tree->gtRegPair);
1528 reg = genRegPairLo(tree->gtRegPair);
1532 #endif // CPU_LONG_USES_REGPAIR
1534 reg = tree->gtRegNum;
1537 /* Make sure it is not the "stack-half" of an enregistered long */
1541 // For short types, indicate that the value is promoted to 4 bytes.
1542 // For longs, we are only emitting half of it so again set it to 4 bytes.
1543 // but leave the GC tracking information alone
1544 if (sizeInferred && EA_SIZE(size) < EA_4BYTE)
1546 size = EA_SET_SIZE(size, 4);
1551 getEmitter()->emitIns_R_I(ins, size, reg, shfv);
1555 inst_RV(ins, reg, tree->TypeGet(), size);
1561 #endif // LEGACY_BACKEND
1563 /* Is this a spilled value? */
1565 if (tree->gtFlags & GTF_SPILLED)
1567 assert(!"ISSUE: If this can happen, we need to generate 'ins [ebp+spill]'");
1570 switch (tree->gtOper)
1576 #ifdef LEGACY_BACKEND
1577 /* Is this an enregistered long ? */
1579 if (tree->gtType == TYP_LONG && !(tree->InReg()))
1581 /* Avoid infinite loop */
1583 if (genMarkLclVar(tree))
1586 #endif // LEGACY_BACKEND
1588 inst_set_SV_var(tree);
1593 offs += tree->gtLclFld.gtLclOffs;
1597 varNum = tree->gtLclVarCommon.gtLclNum;
1598 assert(varNum < compiler->lvaCount);
1602 getEmitter()->emitIns_S_I(ins, size, varNum, offs, shfv);
1606 getEmitter()->emitIns_S(ins, size, varNum, offs);
1612 // Make sure FP instruction size matches the operand size
1613 // (We optimized constant doubles to floats when we can, just want to
1614 // make sure that we don't mistakenly use 8 bytes when the
1616 assert(!isFloatRegType(tree->gtType) || genTypeSize(tree->gtType) == EA_SIZE_IN_BYTES(size));
1620 getEmitter()->emitIns_C_I(ins, size, tree->gtClsVar.gtClsVarHnd, offs, shfv);
1624 getEmitter()->emitIns_C(ins, size, tree->gtClsVar.gtClsVarHnd, offs);
1632 #ifndef LEGACY_BACKEND
1633 assert(!"inst_TT not supported for GT_IND, GT_NULLCHECK or GT_ARR_ELEM in !LEGACY_BACKEND");
1634 #else // LEGACY_BACKEND
1635 GenTreePtr addr = tree->OperIsIndir() ? tree->gtOp.gtOp1 : tree;
1637 sched_AM(ins, size, REG_NA, false, addr, offs, true, shfv);
1639 instEmit_RM(ins, tree, addr, offs);
1640 #endif // LEGACY_BACKEND
1646 // We will get here for GT_MKREFANY from CodeGen::genPushArgList
1649 if (tree->IsIconHandle())
1650 inst_IV_handle(ins, tree->gtIntCon.gtIconVal);
1652 inst_IV(ins, tree->gtIntCon.gtIconVal);
1657 // tree->gtOp.gtOp1 - already processed by genCreateAddrMode()
1658 tree = tree->gtOp.gtOp2;
1662 assert(!"invalid address");
1666 /*****************************************************************************
1668 * Generate an instruction that has one operand given by a tree (which has
1669 * been made addressable) and another that is a register.
1672 void CodeGen::inst_TT_RV(instruction ins, GenTreePtr tree, regNumber reg, unsigned offs, emitAttr size, insFlags flags)
1674 assert(reg != REG_STK);
1678 #ifdef LEGACY_BACKEND
1679 /* Is the value sitting in a register? */
1685 #ifdef _TARGET_64BIT_
1686 assert(!instIsFP(ins));
1688 rg2 = tree->gtRegNum;
1691 assert(rg2 != REG_STK);
1693 if (ins != INS_mov || rg2 != reg)
1695 inst_RV_RV(ins, rg2, reg, tree->TypeGet());
1699 #else // !_TARGET_64BIT_
1701 #ifdef LEGACY_BACKEND
1703 #endif // LEGACY_BACKEND
1705 #ifdef _TARGET_XARCH_
1706 assert(!instIsFP(ins));
1709 #if CPU_LONG_USES_REGPAIR
1710 if (tree->gtType == TYP_LONG)
1714 assert(offs == sizeof(int));
1715 rg2 = genRegPairHi(tree->gtRegPair);
1719 rg2 = genRegPairLo(tree->gtRegPair);
1723 #endif // CPU_LONG_USES_REGPAIR
1725 rg2 = tree->gtRegNum;
1730 if (ins != INS_mov || rg2 != reg)
1731 inst_RV_RV(ins, rg2, reg, tree->TypeGet(), size, flags);
1735 #endif // _TARGET_64BIT_
1737 #endif // LEGACY_BACKEND
1739 /* Is this a spilled value? */
1741 if (tree->gtFlags & GTF_SPILLED)
1743 assert(!"ISSUE: If this can happen, we need to generate 'ins [ebp+spill]'");
1746 if (size == EA_UNKNOWN)
1750 size = EA_ATTR(genTypeSize(tree->TypeGet()));
1754 size = emitTypeSize(tree->TypeGet());
1758 switch (tree->gtOper)
1764 #ifdef LEGACY_BACKEND
1765 if (tree->gtType == TYP_LONG && !(tree->InReg()))
1767 /* Avoid infinite loop */
1769 if (genMarkLclVar(tree))
1772 #endif // LEGACY_BACKEND
1774 inst_set_SV_var(tree);
1778 case GT_STORE_LCL_FLD:
1779 offs += tree->gtLclFld.gtLclOffs;
1784 varNum = tree->gtLclVarCommon.gtLclNum;
1785 assert(varNum < compiler->lvaCount);
1787 #if CPU_LOAD_STORE_ARCH
1788 if (!getEmitter()->emitInsIsStore(ins))
1790 #ifndef LEGACY_BACKEND
1791 // TODO-LdStArch-Bug: Should regTmp be a dst on the node or an internal reg?
1792 // Either way, it is not currently being handled by Lowering.
1793 regNumber regTmp = tree->gtRegNum;
1794 assert(regTmp != REG_NA);
1795 #else // LEGACY_BACKEND
1796 regNumber regTmp = regSet.rsPickFreeReg(RBM_ALLINT & ~genRegMask(reg));
1797 #endif // LEGACY_BACKEND
1798 getEmitter()->emitIns_R_S(ins_Load(tree->TypeGet()), size, regTmp, varNum, offs);
1799 getEmitter()->emitIns_R_R(ins, size, regTmp, reg, flags);
1800 getEmitter()->emitIns_S_R(ins_Store(tree->TypeGet()), size, regTmp, varNum, offs);
1802 regTracker.rsTrackRegTrash(regTmp);
1807 // ins is a Store instruction
1809 getEmitter()->emitIns_S_R(ins, size, reg, varNum, offs);
1811 // If we need to set the flags then add an extra movs reg,reg instruction
1812 if (flags == INS_FLAGS_SET)
1813 getEmitter()->emitIns_R_R(INS_mov, size, reg, reg, INS_FLAGS_SET);
1819 // Make sure FP instruction size matches the operand size
1820 // (We optimized constant doubles to floats when we can, just want to
1821 // make sure that we don't mistakenly use 8 bytes when the
1823 assert(!isFloatRegType(tree->gtType) || genTypeSize(tree->gtType) == EA_SIZE_IN_BYTES(size));
1825 #if CPU_LOAD_STORE_ARCH
1826 if (!getEmitter()->emitInsIsStore(ins))
1828 #ifndef LEGACY_BACKEND
1829 NYI("Store of GT_CLS_VAR not supported for ARM RyuJIT Backend");
1830 #else // LEGACY_BACKEND
1831 regNumber regTmpAddr = regSet.rsPickFreeReg(RBM_ALLINT & ~genRegMask(reg));
1832 regNumber regTmpArith = regSet.rsPickFreeReg(RBM_ALLINT & ~genRegMask(reg) & ~genRegMask(regTmpAddr));
1834 getEmitter()->emitIns_R_C(INS_lea, EA_PTRSIZE, regTmpAddr, tree->gtClsVar.gtClsVarHnd, offs);
1835 getEmitter()->emitIns_R_R(ins_Load(tree->TypeGet()), size, regTmpArith, regTmpAddr);
1836 getEmitter()->emitIns_R_R(ins, size, regTmpArith, reg, flags);
1837 getEmitter()->emitIns_R_R(ins_Store(tree->TypeGet()), size, regTmpArith, regTmpAddr);
1839 regTracker.rsTrackRegTrash(regTmpAddr);
1840 regTracker.rsTrackRegTrash(regTmpArith);
1841 #endif // LEGACY_BACKEND
1844 #endif // CPU_LOAD_STORE_ARCH
1846 getEmitter()->emitIns_C_R(ins, size, tree->gtClsVar.gtClsVarHnd, reg, offs);
1854 #ifndef LEGACY_BACKEND
1855 assert(!"inst_TT_RV not supported for GT_IND, GT_NULLCHECK or GT_ARR_ELEM in RyuJIT Backend");
1856 #else // LEGACY_BACKEND
1857 GenTreePtr addr = tree->OperIsIndir() ? tree->gtOp.gtOp1 : tree;
1858 sched_AM(ins, size, reg, false, addr, offs, false, 0, flags);
1859 #endif // LEGACY_BACKEND
1864 // tree->gtOp.gtOp1 - already processed by genCreateAddrMode()
1865 tree = tree->gtOp.gtOp2;
1869 assert(!"invalid address");
1873 #ifdef LEGACY_BACKEND
1874 regNumber CodeGen::genGetZeroRegister()
1876 // Is the constant already in some register?
1878 regNumber zeroReg = regTracker.rsIconIsInReg(0);
1880 if (zeroReg == REG_NA)
1882 regMaskTP freeMask = regSet.rsRegMaskFree();
1884 if ((freeMask != 0) && (compiler->compCodeOpt() != Compiler::FAST_CODE))
1886 // For SMALL_CODE and BLENDED_CODE,
1887 // we try to generate:
1892 // When selecting a register to xor we try to avoid REG_TMP_0
1893 // when we have another CALLEE_TRASH register available.
1894 // This will often let us reuse the zeroed register in
1895 // several back-to-back assignments
1897 if ((freeMask & RBM_CALLEE_TRASH) != RBM_TMP_0)
1898 freeMask &= ~RBM_TMP_0;
1899 zeroReg = regSet.rsGrabReg(freeMask); // PickReg in stress will pick 'random' registers
1900 // We want one in the freeMask set, so just use GrabReg
1901 genSetRegToIcon(zeroReg, 0, TYP_INT);
1908 /*****************************************************************************
1910 * Generate an instruction that has one operand given by a tree (which has
1911 * been made addressable) and another that is an integer constant.
1913 void CodeGen::inst_TT_IV(instruction ins, GenTreePtr tree, ssize_t val, unsigned offs, emitAttr size, insFlags flags)
1915 bool sizeInferred = false;
1917 if (size == EA_UNKNOWN)
1919 sizeInferred = true;
1921 size = EA_ATTR(genTypeSize(tree->TypeGet()));
1923 size = emitTypeSize(tree->TypeGet());
1928 /* Is the value sitting in a register? */
1932 #ifndef _TARGET_64BIT_
1937 assert(instIsFP(ins) == 0);
1939 #if CPU_LONG_USES_REGPAIR
1940 if (tree->gtType == TYP_LONG)
1944 reg = genRegPairLo(tree->gtRegPair);
1948 assert(offs == sizeof(int));
1949 reg = genRegPairHi(tree->gtRegPair);
1951 #if CPU_LOAD_STORE_ARCH
1952 if (reg == REG_STK && !getEmitter()->emitInsIsLoadOrStore(ins))
1954 reg = regSet.rsPickFreeReg();
1955 inst_RV_TT(INS_mov, reg, tree, offs, EA_4BYTE, flags);
1956 regTracker.rsTrackRegTrash(reg);
1961 #endif // CPU_LONG_USES_REGPAIR
1963 reg = tree->gtRegNum;
1968 // We always widen as part of enregistering,
1969 // so a smaller tree in a register can be
1970 // treated as 4 bytes
1971 if (sizeInferred && (size < EA_4BYTE))
1973 size = EA_SET_SIZE(size, EA_4BYTE);
1976 if ((ins == INS_mov) && !EA_IS_CNS_RELOC(size))
1978 genSetRegToIcon(reg, val, tree->TypeGet(), flags);
1982 #if defined(_TARGET_XARCH_)
1983 inst_RV_IV(ins, reg, val, size);
1984 #elif defined(_TARGET_ARM_)
1985 if (!EA_IS_CNS_RELOC(size) && arm_Valid_Imm_For_Instr(ins, val, flags))
1987 getEmitter()->emitIns_R_I(ins, size, reg, val, flags);
1989 else // We need a scratch register
1991 // Load imm into a register
1993 if (tree->gtType == TYP_LONG)
1995 usedMask = genRegPairMask(tree->gtRegPair);
1996 #if CPU_LOAD_STORE_ARCH
1997 // In gtRegPair, this part of the long may have been on the stack
1998 // in which case, the code above would have loaded it into 'reg'
1999 // and so we need to also include 'reg' in the set of registers
2000 // that are already in use.
2001 usedMask |= genRegMask(reg);
2002 #endif // CPU_LOAD_STORE_ARCH
2006 usedMask = genRegMask(tree->gtRegNum);
2008 regNumber immReg = regSet.rsGrabReg(RBM_ALLINT & ~usedMask);
2009 noway_assert(reg != immReg);
2010 instGen_Set_Reg_To_Imm(size, immReg, val);
2011 if (getEmitter()->emitInsIsStore(ins))
2013 getEmitter()->emitIns_R_R(ins, size, reg, immReg, flags);
2016 NYI("inst_TT_IV - unknown target");
2023 #ifdef _TARGET_XARCH_
2024 /* Are we storing a zero? */
2026 if ((ins == INS_mov) && (val == 0) &&
2027 ((genTypeSize(tree->gtType) == sizeof(int)) || (genTypeSize(tree->gtType) == REGSIZE_BYTES)))
2031 zeroReg = genGetZeroRegister();
2033 if (zeroReg != REG_NA)
2035 inst_TT_RV(INS_mov, tree, zeroReg, offs);
2041 #if CPU_LOAD_STORE_ARCH
2042 /* Are we storing/comparing with a constant? */
2044 if (getEmitter()->emitInsIsStore(ins) || getEmitter()->emitInsIsCompare(ins))
2046 // Load val into a register
2049 valReg = regSet.rsGrabReg(RBM_ALLINT);
2050 instGen_Set_Reg_To_Imm(EA_PTRSIZE, valReg, val);
2051 inst_TT_RV(ins, tree, valReg, offs, size, flags);
2054 else if (ins == INS_mov)
2056 assert(!"Please call ins_Store(type) to get the store instruction");
2058 assert(!getEmitter()->emitInsIsLoad(ins));
2059 #endif // CPU_LOAD_STORE_ARCH
2061 /* Is this a spilled value? */
2063 if (tree->gtFlags & GTF_SPILLED)
2065 assert(!"ISSUE: If this can happen, we need to generate 'ins [ebp+spill], icon'");
2068 #ifdef _TARGET_AMD64_
2069 if ((EA_SIZE(size) == EA_8BYTE) && (((int)val != (ssize_t)val) || EA_IS_CNS_RELOC(size)))
2071 // Load imm into a register
2072 regNumber immReg = regSet.rsGrabReg(RBM_ALLINT);
2073 instGen_Set_Reg_To_Imm(size, immReg, val);
2074 inst_TT_RV(ins, tree, immReg, offs);
2077 #endif // _TARGET_AMD64_
2079 int ival = (int)val;
2081 switch (tree->gtOper)
2088 varNum = tree->gtLclVarCommon.gtLclNum;
2089 assert(varNum < compiler->lvaCount);
2090 offs += tree->gtLclFld.gtLclOffs;
2096 #ifndef _TARGET_64BIT_
2097 /* Is this an enregistered long ? */
2098 CLANG_FORMAT_COMMENT_ANCHOR;
2099 #ifdef LEGACY_BACKEND
2100 if (tree->gtType == TYP_LONG && !(tree->InReg()))
2101 #else // !LEGACY_BACKEND
2102 if (tree->gtType == TYP_LONG)
2103 #endif // !LEGACY_BACKEND
2105 /* Avoid infinite loop */
2107 if (genMarkLclVar(tree))
2110 #endif // !_TARGET_64BIT_
2112 inst_set_SV_var(tree);
2114 varNum = tree->gtLclVarCommon.gtLclNum;
2115 assert(varNum < compiler->lvaCount);
2116 varDsc = &compiler->lvaTable[varNum];
2118 // Fix the immediate by sign extending if needed
2119 if (size < EA_4BYTE && !varTypeIsUnsigned(varDsc->TypeGet()))
2121 if (size == EA_1BYTE)
2123 if ((ival & 0x7f) != ival)
2124 ival = ival | 0xffffff00;
2128 assert(size == EA_2BYTE);
2129 if ((ival & 0x7fff) != ival)
2130 ival = ival | 0xffff0000;
2134 // A local stack slot is at least 4 bytes in size, regardles of
2135 // what the local var is typed as, so auto-promote it here
2136 // unless the codegenerator told us a size, or it is a field
2137 // of a promoted struct
2138 if (sizeInferred && (size < EA_4BYTE) && !varDsc->lvIsStructField)
2140 size = EA_SET_SIZE(size, EA_4BYTE);
2145 /* Integer instructions never operate on more than EA_PTRSIZE */
2147 assert(instIsFP(ins) == false);
2149 #if CPU_LOAD_STORE_ARCH
2150 if (!getEmitter()->emitInsIsStore(ins))
2152 regNumber regTmp = regSet.rsPickFreeReg(RBM_ALLINT);
2153 getEmitter()->emitIns_R_S(ins_Load(tree->TypeGet()), size, regTmp, varNum, offs);
2154 regTracker.rsTrackRegTrash(regTmp);
2156 if (arm_Valid_Imm_For_Instr(ins, val, flags))
2158 getEmitter()->emitIns_R_I(ins, size, regTmp, ival, flags);
2160 else // We need a scratch register
2162 // Load imm into a register
2163 regNumber regImm = regSet.rsGrabReg(RBM_ALLINT & ~genRegMask(regTmp));
2165 instGen_Set_Reg_To_Imm(size, regImm, val);
2166 getEmitter()->emitIns_R_R(ins, size, regTmp, regImm, flags);
2168 getEmitter()->emitIns_S_R(ins_Store(tree->TypeGet()), size, regTmp, varNum, offs);
2173 getEmitter()->emitIns_S_I(ins, size, varNum, offs, ival);
2178 // Make sure FP instruction size matches the operand size
2179 // (We optimize constant doubles to floats when we can)
2180 // We just want to make sure that we don't mistakenly
2181 // use 8 bytes when the constant is smaller.
2183 assert(!isFloatRegType(tree->gtType) || genTypeSize(tree->gtType) == EA_SIZE_IN_BYTES(size));
2185 #if CPU_LOAD_STORE_ARCH
2186 regNumber regTmpAddr;
2187 regTmpAddr = regSet.rsPickFreeReg(RBM_ALLINT);
2189 getEmitter()->emitIns_R_C(INS_lea, EA_PTRSIZE, regTmpAddr, tree->gtClsVar.gtClsVarHnd, offs);
2190 regTracker.rsTrackRegTrash(regTmpAddr);
2192 if (!getEmitter()->emitInsIsStore(ins))
2194 regNumber regTmpArith = regSet.rsPickFreeReg(RBM_ALLINT & ~genRegMask(regTmpAddr));
2196 getEmitter()->emitIns_R_R(ins_Load(tree->TypeGet()), size, regTmpArith, regTmpAddr);
2198 if (arm_Valid_Imm_For_Instr(ins, ival, flags))
2200 getEmitter()->emitIns_R_R_I(ins, size, regTmpArith, regTmpArith, ival, flags);
2204 regNumber regTmpImm =
2205 regSet.rsPickFreeReg(RBM_ALLINT & ~genRegMask(regTmpAddr) & ~genRegMask(regTmpArith));
2206 instGen_Set_Reg_To_Imm(EA_4BYTE, regTmpImm, (ssize_t)ival);
2207 getEmitter()->emitIns_R_R(ins, size, regTmpArith, regTmpImm, flags);
2209 regTracker.rsTrackRegTrash(regTmpArith);
2211 getEmitter()->emitIns_R_R(ins_Store(tree->TypeGet()), size, regTmpArith, regTmpAddr);
2215 regNumber regTmpImm = regSet.rsPickFreeReg(RBM_ALLINT & ~genRegMask(regTmpAddr));
2217 instGen_Set_Reg_To_Imm(EA_4BYTE, regTmpImm, (ssize_t)ival, flags);
2218 getEmitter()->emitIns_R_R(ins_Store(tree->TypeGet()), size, regTmpImm, regTmpAddr);
2220 #else // !CPU_LOAD_STORE_ARCH
2221 getEmitter()->emitIns_C_I(ins, size, tree->gtClsVar.gtClsVarHnd, offs, ival);
2229 GenTreePtr addr = tree->OperIsIndir() ? tree->gtOp.gtOp1 : tree;
2230 sched_AM(ins, size, REG_NA, false, addr, offs, true, ival, flags);
2235 // tree->gtOp.gtOp1 - already processed by genCreateAddrMode()
2236 tree = tree->gtOp.gtOp2;
2240 assert(!"invalid address");
2244 /*****************************************************************************
2246 * Generate an instruction that has one operand given by a register and the
2247 * other one by an indirection tree (which has been made addressable).
2250 void CodeGen::inst_RV_AT(
2251 instruction ins, emitAttr size, var_types type, regNumber reg, GenTreePtr tree, unsigned offs, insFlags flags)
2253 #ifdef _TARGET_XARCH_
2255 // If it is a GC type and the result is not, then either
2257 // 2) optOptimizeBools() optimized if (ref != 0 && ref != 0) to if (ref & ref)
2258 // 3) optOptimizeBools() optimized if (ref == 0 || ref == 0) to if (ref | ref)
2259 // 4) byref - byref = int
2260 if (type == TYP_REF && !EA_IS_GCREF(size))
2261 assert((EA_IS_BYREF(size) && ins == INS_add) || (ins == INS_lea || ins == INS_and || ins == INS_or));
2262 if (type == TYP_BYREF && !EA_IS_BYREF(size))
2263 assert(ins == INS_lea || ins == INS_and || ins == INS_or || ins == INS_sub);
2264 assert(!instIsFP(ins));
2268 // Integer instructions never operate on more than EA_PTRSIZE.
2269 if (EA_SIZE(size) > EA_PTRSIZE && !instIsFP(ins))
2270 EA_SET_SIZE(size, EA_PTRSIZE);
2272 GenTreePtr addr = tree;
2273 sched_AM(ins, size, reg, true, addr, offs, false, 0, flags);
2276 /*****************************************************************************
2278 * Generate an instruction that has one operand given by an indirection tree
2279 * (which has been made addressable) and an integer constant.
2282 void CodeGen::inst_AT_IV(instruction ins, emitAttr size, GenTreePtr baseTree, int icon, unsigned offs)
2284 sched_AM(ins, size, REG_NA, false, baseTree, offs, true, icon);
2286 #endif // LEGACY_BACKEND
2288 /*****************************************************************************
2290 * Generate an instruction that has one operand given by a register and the
2291 * other one by a tree (which has been made addressable).
2294 void CodeGen::inst_RV_TT(instruction ins,
2299 insFlags flags /* = INS_FLAGS_DONT_CARE */)
2301 assert(reg != REG_STK);
2303 if (size == EA_UNKNOWN)
2307 size = emitTypeSize(tree->TypeGet());
2311 size = EA_ATTR(genTypeSize(tree->TypeGet()));
2315 #ifdef _TARGET_XARCH_
2317 // If it is a GC type and the result is not, then either
2319 // 2) optOptimizeBools() optimized if (ref != 0 && ref != 0) to if (ref & ref)
2320 // 3) optOptimizeBools() optimized if (ref == 0 || ref == 0) to if (ref | ref)
2321 // 4) byref - byref = int
2322 if (tree->gtType == TYP_REF && !EA_IS_GCREF(size))
2324 assert((EA_IS_BYREF(size) && ins == INS_add) || (ins == INS_lea || ins == INS_and || ins == INS_or));
2326 if (tree->gtType == TYP_BYREF && !EA_IS_BYREF(size))
2328 assert(ins == INS_lea || ins == INS_and || ins == INS_or || ins == INS_sub);
2333 #if CPU_LOAD_STORE_ARCH
2336 #if defined(_TARGET_ARM_) && CPU_LONG_USES_REGPAIR
2337 if (tree->TypeGet() != TYP_LONG)
2339 ins = ins_Move_Extend(tree->TypeGet(), tree->InReg());
2343 ins = ins_Move_Extend(TYP_INT, tree->InReg() && genRegPairLo(tree->gtRegPair) != REG_STK);
2347 ins = ins_Move_Extend(TYP_INT, tree->InReg() && genRegPairHi(tree->gtRegPair) != REG_STK);
2349 #elif defined(_TARGET_ARM64_) || defined(_TARGET_ARM64_)
2350 ins = ins_Move_Extend(tree->TypeGet(), false);
2352 NYI("CodeGen::inst_RV_TT with INS_mov");
2355 #endif // CPU_LOAD_STORE_ARCH
2359 #ifdef LEGACY_BACKEND
2360 /* Is the value sitting in a register? */
2364 #ifdef _TARGET_64BIT_
2365 assert(instIsFP(ins) == 0);
2367 regNumber rg2 = tree->gtRegNum;
2370 assert(rg2 != REG_STK);
2372 if ((ins != INS_mov) || (rg2 != reg))
2374 inst_RV_RV(ins, reg, rg2, tree->TypeGet(), size);
2378 #else // !_TARGET_64BIT_
2380 #ifdef LEGACY_BACKEND
2382 #endif // LEGACY_BACKEND
2384 #ifdef _TARGET_XARCH_
2385 assert(instIsFP(ins) == 0);
2390 #if CPU_LONG_USES_REGPAIR
2391 if (tree->gtType == TYP_LONG)
2395 assert(offs == sizeof(int));
2397 rg2 = genRegPairHi(tree->gtRegPair);
2401 rg2 = genRegPairLo(tree->gtRegPair);
2405 #endif // LEGACY_BACKEND
2407 rg2 = tree->gtRegNum;
2413 if (getEmitter()->emitInsIsLoad(ins) || (ins == INS_lea))
2415 ins = ins_Copy(tree->TypeGet());
2419 bool isMoveIns = (ins == INS_mov);
2421 if (ins == INS_vmov)
2424 if (!isMoveIns || (rg2 != reg))
2426 inst_RV_RV(ins, reg, rg2, tree->TypeGet(), size, flags);
2431 #endif // _TARGET_64BIT_
2433 #endif // LEGACY_BACKEND
2435 /* Is this a spilled value? */
2437 if (tree->gtFlags & GTF_SPILLED)
2439 assert(!"ISSUE: If this can happen, we need to generate 'ins [ebp+spill]'");
2442 switch (tree->gtOper)
2447 case GT_LCL_VAR_ADDR:
2449 #ifdef LEGACY_BACKEND
2450 /* Is this an enregistered long ? */
2452 if (tree->gtType == TYP_LONG && !(tree->InReg()))
2455 /* Avoid infinite loop */
2457 if (genMarkLclVar(tree))
2460 #endif // LEGACY_BACKEND
2462 inst_set_SV_var(tree);
2465 case GT_LCL_FLD_ADDR:
2467 offs += tree->gtLclFld.gtLclOffs;
2471 varNum = tree->gtLclVarCommon.gtLclNum;
2472 assert(varNum < compiler->lvaCount);
2478 ins = ins_Load(tree->TypeGet());
2488 assert(flags != INS_FLAGS_SET);
2489 getEmitter()->emitIns_R_S(ins, size, reg, varNum, offs);
2494 #ifndef LEGACY_BACKEND
2495 #if CPU_LONG_USES_REGPAIR
2496 if (tree->TypeGet() == TYP_LONG)
2497 regTmp = (offs == 0) ? genRegPairLo(tree->gtRegPair) : genRegPairHi(tree->gtRegPair);
2499 #endif // CPU_LONG_USES_REGPAIR
2500 regTmp = tree->gtRegNum;
2501 #else // LEGACY_BACKEND
2502 if (varTypeIsFloating(tree))
2504 regTmp = regSet.PickRegFloat(tree->TypeGet());
2508 // Lock the destination register to ensure that rsPickReg does not choose it.
2509 const regMaskTP regMask = genRegMask(reg);
2510 if ((regMask & regSet.rsMaskUsed) == 0)
2512 regSet.rsLockReg(regMask);
2513 regTmp = regSet.rsPickReg(RBM_ALLINT);
2514 regSet.rsUnlockReg(regMask);
2516 else if ((regMask & regSet.rsMaskLock) == 0)
2518 regSet.rsLockUsedReg(regMask);
2519 regTmp = regSet.rsPickReg(RBM_ALLINT);
2520 regSet.rsUnlockUsedReg(regMask);
2524 regTmp = regSet.rsPickReg(RBM_ALLINT);
2527 #endif // LEGACY_BACKEND
2529 getEmitter()->emitIns_R_S(ins_Load(tree->TypeGet()), size, regTmp, varNum, offs);
2530 getEmitter()->emitIns_R_R(ins, size, reg, regTmp, flags);
2532 regTracker.rsTrackRegTrash(regTmp);
2535 #else // !_TARGET_ARM_
2536 getEmitter()->emitIns_R_S(ins, size, reg, varNum, offs);
2538 #endif // !_TARGET_ARM_
2541 // Make sure FP instruction size matches the operand size
2542 // (We optimized constant doubles to floats when we can, just want to
2543 // make sure that we don't mistakenly use 8 bytes when the
2545 assert(!isFloatRegType(tree->gtType) || genTypeSize(tree->gtType) == EA_SIZE_IN_BYTES(size));
2547 #if CPU_LOAD_STORE_ARCH
2548 #ifndef LEGACY_BACKEND
2549 assert(!"GT_CLS_VAR not supported in ARM RyuJIT backend");
2550 #else // LEGACY_BACKEND
2554 ins = ins_Load(tree->TypeGet());
2565 assert(flags != INS_FLAGS_SET);
2566 getEmitter()->emitIns_R_C(ins, size, reg, tree->gtClsVar.gtClsVarHnd, offs);
2570 regNumber regTmp = regSet.rsPickFreeReg(RBM_ALLINT & ~genRegMask(reg));
2571 getEmitter()->emitIns_R_C(ins_Load(tree->TypeGet()), size, regTmp, tree->gtClsVar.gtClsVarHnd,
2573 getEmitter()->emitIns_R_R(ins, size, reg, regTmp, flags);
2574 regTracker.rsTrackRegTrash(regTmp);
2577 #endif // LEGACY_BACKEND
2578 #else // CPU_LOAD_STORE_ARCH
2579 getEmitter()->emitIns_R_C(ins, size, reg, tree->gtClsVar.gtClsVarHnd, offs);
2580 #endif // CPU_LOAD_STORE_ARCH
2588 #ifndef LEGACY_BACKEND
2589 assert(!"inst_RV_TT not supported for GT_IND, GT_NULLCHECK, GT_ARR_ELEM or GT_LEA in !LEGACY_BACKEND");
2590 #else // LEGACY_BACKEND
2591 GenTreePtr addr = tree->OperIsIndir() ? tree->gtOp.gtOp1 : tree;
2592 inst_RV_AT(ins, size, tree->TypeGet(), reg, addr, offs, flags);
2593 #endif // LEGACY_BACKEND
2601 inst_RV_IV(ins, reg, tree->gtIntCon.gtIconVal, emitActualTypeSize(tree->TypeGet()), flags);
2606 assert(size == EA_4BYTE || size == EA_8BYTE);
2608 #ifdef _TARGET_AMD64_
2610 #endif // _TARGET_AMD64_
2616 constVal = (ssize_t)(tree->gtLngCon.gtLconVal);
2621 constVal = (ssize_t)(tree->gtLngCon.gtLconVal >> 32);
2625 inst_RV_IV(ins, reg, constVal, size, flags);
2629 tree = tree->gtOp.gtOp2;
2633 assert(!"invalid address");
2637 /*****************************************************************************
2639 * Generate the 3-operand imul instruction "imul reg, [tree], icon"
2640 * which is reg=[tree]*icon
2642 #ifdef LEGACY_BACKEND
2643 void CodeGen::inst_RV_TT_IV(instruction ins, regNumber reg, GenTreePtr tree, int val)
2645 assert(tree->gtType <= TYP_I_IMPL);
2647 #ifdef _TARGET_XARCH_
2648 /* Only 'imul' uses this instruction format. Since we don't represent
2649 three operands for an instruction, we encode the target register as
2650 an implicit operand */
2652 assert(ins == INS_imul);
2653 ins = getEmitter()->inst3opImulForReg(reg);
2655 genUpdateLife(tree);
2656 inst_TT_IV(ins, tree, val);
2658 NYI("inst_RV_TT_IV - unknown target");
2661 #endif // LEGACY_BACKEND
2663 /*****************************************************************************
2665 * Generate a "shift reg, icon" instruction.
2668 void CodeGen::inst_RV_SH(
2669 instruction ins, emitAttr size, regNumber reg, unsigned val, insFlags flags /* = INS_FLAGS_DONT_CARE */)
2671 #if defined(_TARGET_ARM_)
2676 getEmitter()->emitIns_R_I(ins, size, reg, val, flags);
2678 #elif defined(_TARGET_XARCH_)
2680 #ifdef _TARGET_AMD64_
2681 // X64 JB BE insures only encodable values make it here.
2682 // x86 can encode 8 bits, though it masks down to 5 or 6
2683 // depending on 32-bit or 64-bit registers are used.
2684 // Here we will allow anything that is encodable.
2688 ins = genMapShiftInsToShiftByConstantIns(ins, val);
2692 getEmitter()->emitIns_R(ins, size, reg);
2696 getEmitter()->emitIns_R_I(ins, size, reg, val);
2700 NYI("inst_RV_SH - unknown target");
2704 /*****************************************************************************
2706 * Generate a "shift [r/m], icon" instruction.
2709 void CodeGen::inst_TT_SH(instruction ins, GenTreePtr tree, unsigned val, unsigned offs)
2711 #ifdef _TARGET_XARCH_
2714 // Shift by 0 - why are you wasting our precious time????
2718 ins = genMapShiftInsToShiftByConstantIns(ins, val);
2721 inst_TT(ins, tree, offs, 0, emitTypeSize(tree->TypeGet()));
2725 inst_TT(ins, tree, offs, val, emitTypeSize(tree->TypeGet()));
2727 #endif // _TARGET_XARCH_
2730 inst_TT(ins, tree, offs, val, emitTypeSize(tree->TypeGet()));
2734 /*****************************************************************************
2736 * Generate a "shift [addr], cl" instruction.
2739 void CodeGen::inst_TT_CL(instruction ins, GenTreePtr tree, unsigned offs)
2741 inst_TT(ins, tree, offs, 0, emitTypeSize(tree->TypeGet()));
2744 /*****************************************************************************
2746 * Generate an instruction of the form "op reg1, reg2, icon".
2749 #if defined(_TARGET_XARCH_)
2750 void CodeGen::inst_RV_RV_IV(instruction ins, emitAttr size, regNumber reg1, regNumber reg2, unsigned ival)
2752 #if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
2753 assert(ins == INS_shld || ins == INS_shrd || ins == INS_shufps || ins == INS_shufpd || ins == INS_pshufd ||
2754 ins == INS_cmpps || ins == INS_cmppd || ins == INS_dppd || ins == INS_dpps || ins == INS_insertps);
2755 #else // !_TARGET_XARCH_
2756 assert(ins == INS_shld || ins == INS_shrd);
2757 #endif // !_TARGET_XARCH_
2759 getEmitter()->emitIns_R_R_I(ins, size, reg1, reg2, ival);
2763 /*****************************************************************************
2765 * Generate an instruction with two registers, the second one being a byte
2766 * or word register (i.e. this is something like "movzx eax, cl").
2769 void CodeGen::inst_RV_RR(instruction ins, emitAttr size, regNumber reg1, regNumber reg2)
2771 assert(size == EA_1BYTE || size == EA_2BYTE);
2772 #ifdef _TARGET_XARCH_
2773 assert(ins == INS_movsx || ins == INS_movzx);
2774 assert(size != EA_1BYTE || (genRegMask(reg2) & RBM_BYTE_REGS));
2777 getEmitter()->emitIns_R_R(ins, size, reg1, reg2);
2780 /*****************************************************************************
2782 * The following should all end up inline in compiler.hpp at some point.
2785 void CodeGen::inst_ST_RV(instruction ins, TempDsc* tmp, unsigned ofs, regNumber reg, var_types type)
2787 getEmitter()->emitIns_S_R(ins, emitActualTypeSize(type), reg, tmp->tdTempNum(), ofs);
2790 void CodeGen::inst_ST_IV(instruction ins, TempDsc* tmp, unsigned ofs, int val, var_types type)
2792 getEmitter()->emitIns_S_I(ins, emitActualTypeSize(type), tmp->tdTempNum(), ofs, val);
2795 #if FEATURE_FIXED_OUT_ARGS
2796 /*****************************************************************************
2798 * Generate an instruction that references the outgoing argument space
2799 * like "str r3, [sp+0x04]"
2802 void CodeGen::inst_SA_RV(instruction ins, unsigned ofs, regNumber reg, var_types type)
2804 assert(ofs < compiler->lvaOutgoingArgSpaceSize);
2806 getEmitter()->emitIns_S_R(ins, emitActualTypeSize(type), reg, compiler->lvaOutgoingArgSpaceVar, ofs);
2809 void CodeGen::inst_SA_IV(instruction ins, unsigned ofs, int val, var_types type)
2811 assert(ofs < compiler->lvaOutgoingArgSpaceSize);
2813 getEmitter()->emitIns_S_I(ins, emitActualTypeSize(type), compiler->lvaOutgoingArgSpaceVar, ofs, val);
2815 #endif // FEATURE_FIXED_OUT_ARGS
2817 /*****************************************************************************
2819 * Generate an instruction with one register and one operand that is byte
2820 * or short (e.g. something like "movzx eax, byte ptr [edx]").
2823 void CodeGen::inst_RV_ST(instruction ins, emitAttr size, regNumber reg, GenTreePtr tree)
2825 assert(size == EA_1BYTE || size == EA_2BYTE);
2827 #ifdef LEGACY_BACKEND
2830 /* "movsx erx, rl" must be handled as a special case */
2831 inst_RV_RR(ins, size, reg, tree->gtRegNum);
2834 #endif // LEGACY_BACKEND
2836 inst_RV_TT(ins, reg, tree, 0, size);
2840 void CodeGen::inst_RV_ST(instruction ins, regNumber reg, TempDsc* tmp, unsigned ofs, var_types type, emitAttr size)
2842 if (size == EA_UNKNOWN)
2844 size = emitActualTypeSize(type);
2851 assert(!"Please call ins_Load(type) to get the load instruction");
2862 getEmitter()->emitIns_R_S(ins, size, reg, tmp->tdTempNum(), ofs);
2866 #ifndef LEGACY_BACKEND
2867 assert(!"Default inst_RV_ST case not supported for Arm !LEGACY_BACKEND");
2868 #else // LEGACY_BACKEND
2870 if (varTypeIsFloating(type))
2872 regTmp = regSet.PickRegFloat(type);
2876 regTmp = regSet.rsPickFreeReg(RBM_ALLINT & ~genRegMask(reg));
2878 getEmitter()->emitIns_R_S(ins_Load(type), size, regTmp, tmp->tdTempNum(), ofs);
2879 regTracker.rsTrackRegTrash(regTmp);
2880 getEmitter()->emitIns_R_R(ins, size, reg, regTmp);
2881 #endif // LEGACY_BACKEND
2884 #else // !_TARGET_ARM_
2885 getEmitter()->emitIns_R_S(ins, size, reg, tmp->tdTempNum(), ofs);
2886 #endif // !_TARGET_ARM_
2889 void CodeGen::inst_mov_RV_ST(regNumber reg, GenTreePtr tree)
2891 /* Figure out the size of the value being loaded */
2893 emitAttr size = EA_ATTR(genTypeSize(tree->gtType));
2894 #ifdef LEGACY_BACKEND
2895 instruction loadIns = ins_Move_Extend(tree->TypeGet(), tree->InReg());
2896 #else // !LEGACY_BACKEND
2897 instruction loadIns = ins_Move_Extend(tree->TypeGet(), false);
2898 #endif // !LEGACY_BACKEND
2900 if (size < EA_4BYTE)
2902 #if CPU_HAS_BYTE_REGS && defined(LEGACY_BACKEND)
2903 if ((tree->gtFlags & GTF_SMALL_OK) && (size == EA_1BYTE) && (genRegMask(reg) & RBM_BYTE_REGS))
2905 /* We only need to load the actual size */
2907 inst_RV_TT(INS_mov, reg, tree, 0, EA_1BYTE);
2910 #endif // CPU_HAS_BYTE_REGS && defined(LEGACY_BACKEND)
2912 /* Generate the "movsx/movzx" opcode */
2914 inst_RV_ST(loadIns, size, reg, tree);
2919 /* Compute op1 into the target register */
2921 inst_RV_TT(loadIns, reg, tree);
2924 #ifdef _TARGET_XARCH_
2925 void CodeGen::inst_FS_ST(instruction ins, emitAttr size, TempDsc* tmp, unsigned ofs)
2927 getEmitter()->emitIns_S(ins, size, tmp->tdTempNum(), ofs);
2932 bool CodeGenInterface::validImmForInstr(instruction ins, ssize_t imm, insFlags flags)
2934 if (getEmitter()->emitInsIsLoadOrStore(ins) && !instIsFP(ins))
2936 return validDispForLdSt(imm, TYP_INT);
2939 bool result = false;
2944 if (validImmForAlu(imm) || validImmForAlu(-imm))
2953 if (validImmForAlu(imm) || validImmForAlu(~imm))
2958 if (validImmForMov(imm))
2964 if ((unsigned_abs(imm) <= 0x00000fff) && (flags != INS_FLAGS_SET)) // 12-bit immediate
2970 if (validImmForAdd(imm, flags))
2980 if (validImmForAlu(imm))
2988 if (imm > 0 && imm <= 32)
2994 if ((imm & 0x3FC) == imm)
3003 bool CodeGen::arm_Valid_Imm_For_Instr(instruction ins, ssize_t imm, insFlags flags)
3005 return validImmForInstr(ins, imm, flags);
3008 bool CodeGenInterface::validDispForLdSt(ssize_t disp, var_types type)
3010 if (varTypeIsFloating(type))
3012 if ((disp & 0x3FC) == disp)
3019 if ((disp >= -0x00ff) && (disp <= 0x0fff))
3025 bool CodeGen::arm_Valid_Disp_For_LdSt(ssize_t disp, var_types type)
3027 return validDispForLdSt(disp, type);
3030 bool CodeGenInterface::validImmForAlu(ssize_t imm)
3032 return emitter::emitIns_valid_imm_for_alu(imm);
3034 bool CodeGen::arm_Valid_Imm_For_Alu(ssize_t imm)
3036 return validImmForAlu(imm);
3039 bool CodeGenInterface::validImmForMov(ssize_t imm)
3041 return emitter::emitIns_valid_imm_for_mov(imm);
3043 bool CodeGen::arm_Valid_Imm_For_Mov(ssize_t imm)
3045 return validImmForMov(imm);
3048 bool CodeGen::arm_Valid_Imm_For_Small_Mov(regNumber reg, ssize_t imm, insFlags flags)
3050 return emitter::emitIns_valid_imm_for_small_mov(reg, imm, flags);
3053 bool CodeGenInterface::validImmForAdd(ssize_t imm, insFlags flags)
3055 return emitter::emitIns_valid_imm_for_add(imm, flags);
3057 bool CodeGen::arm_Valid_Imm_For_Add(ssize_t imm, insFlags flags)
3059 return emitter::emitIns_valid_imm_for_add(imm, flags);
3062 // Check "add Rd,SP,i10"
3063 bool CodeGen::arm_Valid_Imm_For_Add_SP(ssize_t imm)
3065 return emitter::emitIns_valid_imm_for_add_sp(imm);
3068 bool CodeGenInterface::validImmForBL(ssize_t addr)
3071 // If we are running the altjit for NGEN, then assume we can use the "BL" instruction.
3072 // This matches the usual behavior for NGEN, since we normally do generate "BL".
3073 (!compiler->info.compMatchedVM && compiler->opts.jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT)) ||
3074 (compiler->eeGetRelocTypeHint((void*)addr) == IMAGE_REL_BASED_THUMB_BRANCH24);
3076 bool CodeGen::arm_Valid_Imm_For_BL(ssize_t addr)
3078 return validImmForBL(addr);
3081 // Returns true if this instruction writes to a destination register
3083 bool CodeGen::ins_Writes_Dest(instruction ins)
3098 #endif // _TARGET_ARM_
3100 /*****************************************************************************
3102 * Get the machine dependent instruction for performing sign/zero extension.
3105 * srcType - source type
3106 * srcInReg - whether source is in a register
3108 instruction CodeGen::ins_Move_Extend(var_types srcType, bool srcInReg)
3110 instruction ins = INS_invalid;
3112 if (varTypeIsSIMD(srcType))
3114 #if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
3115 // SSE2/AVX requires destination to be a reg always.
3116 // If src is in reg means, it is a reg-reg move.
3118 // SSE2 Note: always prefer movaps/movups over movapd/movupd since the
3119 // former doesn't require 66h prefix and one byte smaller than the
3122 // TODO-CQ: based on whether src type is aligned use movaps instead
3124 return (srcInReg) ? INS_movaps : INS_movups;
3125 #elif defined(_TARGET_ARM64_)
3126 return (srcInReg) ? INS_mov : ins_Load(srcType);
3127 #else // !defined(_TARGET_ARM64_) && !(defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND))
3128 assert(!"unhandled SIMD type");
3129 #endif // !defined(_TARGET_ARM64_) && !(defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND))
3132 #if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
3133 if (varTypeIsFloating(srcType))
3135 if (srcType == TYP_DOUBLE)
3137 return (srcInReg) ? INS_movaps : INS_movsdsse2;
3139 else if (srcType == TYP_FLOAT)
3141 return (srcInReg) ? INS_movaps : INS_movss;
3145 assert(!"unhandled floating type");
3148 #elif defined(_TARGET_ARM_)
3149 if (varTypeIsFloating(srcType))
3152 assert(!varTypeIsFloating(srcType));
3155 #if defined(_TARGET_XARCH_)
3156 if (!varTypeIsSmall(srcType))
3160 else if (varTypeIsUnsigned(srcType))
3168 #elif defined(_TARGET_ARM_)
3170 // Register to Register zero/sign extend operation
3174 if (!varTypeIsSmall(srcType))
3178 else if (varTypeIsUnsigned(srcType))
3180 if (varTypeIsByte(srcType))
3187 if (varTypeIsByte(srcType))
3195 ins = ins_Load(srcType);
3197 #elif defined(_TARGET_ARM64_)
3199 // Register to Register zero/sign extend operation
3203 if (varTypeIsUnsigned(srcType))
3205 if (varTypeIsByte(srcType))
3209 else if (varTypeIsShort(srcType))
3215 // A mov Rd, Rm instruction performs the zero extend
3216 // for the upper 32 bits when the size is EA_4BYTE
3223 if (varTypeIsByte(srcType))
3227 else if (varTypeIsShort(srcType))
3233 if (srcType == TYP_INT)
3246 ins = ins_Load(srcType);
3249 NYI("ins_Move_Extend");
3251 assert(ins != INS_invalid);
3255 /*****************************************************************************
3257 * Get the machine dependent instruction for performing a load for srcType
3260 * srcType - source type
3261 * aligned - whether source is properly aligned if srcType is a SIMD type
3263 instruction CodeGenInterface::ins_Load(var_types srcType, bool aligned /*=false*/)
3265 instruction ins = INS_invalid;
3267 if (varTypeIsSIMD(srcType))
3269 #if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
3271 if (srcType == TYP_SIMD8)
3273 return INS_movsdsse2;
3276 #endif // FEATURE_SIMD
3277 if (compiler->canUseVexEncoding())
3279 return (aligned) ? INS_movapd : INS_movupd;
3283 // SSE2 Note: always prefer movaps/movups over movapd/movupd since the
3284 // former doesn't require 66h prefix and one byte smaller than the
3286 return (aligned) ? INS_movaps : INS_movups;
3288 #elif defined(_TARGET_ARM64_)
3291 assert(!"ins_Load with SIMD type");
3295 if (varTypeIsFloating(srcType))
3297 #if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
3298 if (srcType == TYP_DOUBLE)
3300 return INS_movsdsse2;
3302 else if (srcType == TYP_FLOAT)
3308 assert(!"unhandled floating type");
3310 #elif defined(_TARGET_ARM64_)
3312 #elif defined(_TARGET_ARM_)
3315 assert(!varTypeIsFloating(srcType));
3319 #if defined(_TARGET_XARCH_)
3320 if (!varTypeIsSmall(srcType))
3324 else if (varTypeIsUnsigned(srcType))
3333 #elif defined(_TARGET_ARMARCH_)
3334 if (!varTypeIsSmall(srcType))
3336 #if defined(_TARGET_ARM64_)
3337 if (!varTypeIsI(srcType) && !varTypeIsUnsigned(srcType))
3342 #endif // defined(_TARGET_ARM64_)
3347 else if (varTypeIsByte(srcType))
3349 if (varTypeIsUnsigned(srcType))
3354 else if (varTypeIsShort(srcType))
3356 if (varTypeIsUnsigned(srcType))
3365 assert(ins != INS_invalid);
3369 /*****************************************************************************
3371 * Get the machine dependent instruction for performing a reg-reg copy for dstType
3374 * dstType - destination type
3376 instruction CodeGen::ins_Copy(var_types dstType)
3378 #if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
3379 if (varTypeIsSIMD(dstType))
3383 else if (varTypeIsFloating(dstType))
3385 // Both float and double copy can use movaps
3392 #elif defined(_TARGET_ARM64_)
3393 if (varTypeIsFloating(dstType))
3401 #elif defined(_TARGET_ARM_)
3402 assert(!varTypeIsSIMD(dstType));
3403 if (varTypeIsFloating(dstType))
3411 #elif defined(_TARGET_X86_)
3412 assert(!varTypeIsSIMD(dstType));
3413 assert(!varTypeIsFloating(dstType));
3416 #error "Unknown _TARGET_"
3420 /*****************************************************************************
3422 * Get the machine dependent instruction for performing a store for dstType
3425 * dstType - destination type
3426 * aligned - whether destination is properly aligned if dstType is a SIMD type
3428 instruction CodeGenInterface::ins_Store(var_types dstType, bool aligned /*=false*/)
3430 instruction ins = INS_invalid;
3432 #if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
3433 if (varTypeIsSIMD(dstType))
3436 if (dstType == TYP_SIMD8)
3438 return INS_movsdsse2;
3441 #endif // FEATURE_SIMD
3442 if (compiler->canUseVexEncoding())
3444 return (aligned) ? INS_movapd : INS_movupd;
3448 // SSE2 Note: always prefer movaps/movups over movapd/movupd since the
3449 // former doesn't require 66h prefix and one byte smaller than the
3451 return (aligned) ? INS_movaps : INS_movups;
3454 else if (varTypeIsFloating(dstType))
3456 if (dstType == TYP_DOUBLE)
3458 return INS_movsdsse2;
3460 else if (dstType == TYP_FLOAT)
3466 assert(!"unhandled floating type");
3469 #elif defined(_TARGET_ARM64_)
3470 if (varTypeIsSIMD(dstType) || varTypeIsFloating(dstType))
3472 // All sizes of SIMD and FP instructions use INS_str
3475 #elif defined(_TARGET_ARM_)
3476 assert(!varTypeIsSIMD(dstType));
3477 if (varTypeIsFloating(dstType))
3482 assert(!varTypeIsSIMD(dstType));
3483 assert(!varTypeIsFloating(dstType));
3486 #if defined(_TARGET_XARCH_)
3488 #elif defined(_TARGET_ARMARCH_)
3489 if (!varTypeIsSmall(dstType))
3491 else if (varTypeIsByte(dstType))
3493 else if (varTypeIsShort(dstType))
3499 assert(ins != INS_invalid);
3503 #if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
3505 bool CodeGen::isMoveIns(instruction ins)
3507 return (ins == INS_mov);
3510 instruction CodeGenInterface::ins_FloatLoad(var_types type)
3512 // Do Not use this routine in RyuJIT backend. Instead use ins_Load()/ins_Store()
3516 // everything is just an addressing mode variation on x64
3517 instruction CodeGen::ins_FloatStore(var_types type)
3519 // Do Not use this routine in RyuJIT backend. Instead use ins_Store()
3523 instruction CodeGen::ins_FloatCopy(var_types type)
3525 // Do Not use this routine in RyuJIT backend. Instead use ins_Load().
3529 instruction CodeGen::ins_FloatCompare(var_types type)
3531 return (type == TYP_FLOAT) ? INS_ucomiss : INS_ucomisd;
3534 instruction CodeGen::ins_CopyIntToFloat(var_types srcType, var_types dstType)
3536 // On SSE2/AVX - the same instruction is used for moving double/quad word to XMM/YMM register.
3537 assert((srcType == TYP_INT) || (srcType == TYP_UINT) || (srcType == TYP_LONG) || (srcType == TYP_ULONG));
3539 #if !defined(_TARGET_64BIT_)
3540 // No 64-bit registers on x86.
3541 assert((srcType != TYP_LONG) && (srcType != TYP_ULONG));
3542 #endif // !defined(_TARGET_64BIT_)
3544 return INS_mov_i2xmm;
3547 instruction CodeGen::ins_CopyFloatToInt(var_types srcType, var_types dstType)
3549 // On SSE2/AVX - the same instruction is used for moving double/quad word of XMM/YMM to an integer register.
3550 assert((dstType == TYP_INT) || (dstType == TYP_UINT) || (dstType == TYP_LONG) || (dstType == TYP_ULONG));
3552 #if !defined(_TARGET_64BIT_)
3553 // No 64-bit registers on x86.
3554 assert((dstType != TYP_LONG) && (dstType != TYP_ULONG));
3555 #endif // !defined(_TARGET_64BIT_)
3557 return INS_mov_xmm2i;
3560 instruction CodeGen::ins_MathOp(genTreeOps oper, var_types type)
3565 #ifdef LEGACY_BACKEND
3568 return type == TYP_DOUBLE ? INS_addsd : INS_addss;
3570 #ifdef LEGACY_BACKEND
3573 return type == TYP_DOUBLE ? INS_subsd : INS_subss;
3575 #ifdef LEGACY_BACKEND
3578 return type == TYP_DOUBLE ? INS_mulsd : INS_mulss;
3580 #ifdef LEGACY_BACKEND
3583 return type == TYP_DOUBLE ? INS_divsd : INS_divss;
3585 return type == TYP_DOUBLE ? INS_andpd : INS_andps;
3587 return type == TYP_DOUBLE ? INS_orpd : INS_orps;
3589 return type == TYP_DOUBLE ? INS_xorpd : INS_xorps;
3595 instruction CodeGen::ins_FloatSqrt(var_types type)
3597 instruction ins = INS_invalid;
3599 if (type == TYP_DOUBLE)
3603 else if (type == TYP_FLOAT)
3609 assert(!"ins_FloatSqrt: Unsupported type");
3616 // Conversions to or from floating point values
3617 instruction CodeGen::ins_FloatConv(var_types to, var_types from)
3619 // AVX: For now we support only conversion from Int/Long -> float
3623 // int/long -> float/double use the same instruction but type size would be different.
3629 return INS_cvtsi2ss;
3631 return INS_cvtsi2sd;
3641 return INS_cvttss2si;
3643 return INS_cvttss2si;
3645 return ins_Move_Extend(TYP_FLOAT, false);
3647 return INS_cvtss2sd;
3657 return INS_cvttsd2si;
3659 return INS_cvttsd2si;
3661 return INS_cvtsd2ss;
3663 return ins_Move_Extend(TYP_DOUBLE, false);
3674 #elif defined(_TARGET_ARM_)
3676 bool CodeGen::isMoveIns(instruction ins)
3678 return (ins == INS_vmov) || (ins == INS_mov);
3681 instruction CodeGenInterface::ins_FloatLoad(var_types type)
3683 assert(type == TYP_DOUBLE || type == TYP_FLOAT);
3686 instruction CodeGen::ins_FloatStore(var_types type)
3688 assert(type == TYP_DOUBLE || type == TYP_FLOAT);
3691 instruction CodeGen::ins_FloatCopy(var_types type)
3693 assert(type == TYP_DOUBLE || type == TYP_FLOAT);
3697 instruction CodeGen::ins_CopyIntToFloat(var_types srcType, var_types dstType)
3699 assert((dstType == TYP_FLOAT) || (dstType == TYP_DOUBLE));
3700 assert((srcType == TYP_INT) || (srcType == TYP_UINT) || (srcType == TYP_LONG) || (srcType == TYP_ULONG));
3702 if ((srcType == TYP_LONG) || (srcType == TYP_ULONG))
3704 return INS_vmov_i2d;
3708 return INS_vmov_i2f;
3712 instruction CodeGen::ins_CopyFloatToInt(var_types srcType, var_types dstType)
3714 assert((srcType == TYP_FLOAT) || (srcType == TYP_DOUBLE));
3715 assert((dstType == TYP_INT) || (dstType == TYP_UINT) || (dstType == TYP_LONG) || (dstType == TYP_ULONG));
3717 if ((dstType == TYP_LONG) || (dstType == TYP_ULONG))
3719 return INS_vmov_d2i;
3723 return INS_vmov_f2i;
3727 instruction CodeGen::ins_FloatCompare(var_types type)
3729 // Not used and not implemented
3733 instruction CodeGen::ins_FloatSqrt(var_types type)
3735 // Not used and not implemented
3739 instruction CodeGen::ins_MathOp(genTreeOps oper, var_types type)
3744 #ifdef LEGACY_BACKEND
3749 #ifdef LEGACY_BACKEND
3754 #ifdef LEGACY_BACKEND
3760 #ifdef LEGACY_BACKEND
3771 instruction CodeGen::ins_FloatConv(var_types to, var_types from)
3779 return INS_vcvt_i2f;
3781 return INS_vcvt_i2d;
3790 return INS_vcvt_u2f;
3792 return INS_vcvt_u2d;
3801 NYI("long to float");
3803 NYI("long to double");
3812 return INS_vcvt_f2i;
3814 return INS_vcvt_f2u;
3816 NYI("float to long");
3818 return INS_vcvt_f2d;
3829 return INS_vcvt_d2i;
3831 return INS_vcvt_d2u;
3833 NYI("double to long");
3835 return INS_vcvt_d2f;
3847 #endif // #elif defined(_TARGET_ARM_)
3849 /*****************************************************************************
3851 * Machine independent way to return
3853 void CodeGen::instGen_Return(unsigned stkArgSize)
3855 #if defined(_TARGET_XARCH_)
3856 if (stkArgSize == 0)
3862 inst_IV(INS_ret, stkArgSize);
3864 #elif defined(_TARGET_ARM_)
3866 // The return on ARM is folded into the pop multiple instruction
3867 // and as we do not know the exact set of registers that we will
3868 // need to restore (pop) when we first call instGen_Return we will
3869 // instead just not emit anything for this method on the ARM
3870 // The return will be part of the pop multiple and that will be
3871 // part of the epilog that is generated by genFnEpilog()
3872 #elif defined(_TARGET_ARM64_)
3873 // This function shouldn't be used on ARM64.
3876 NYI("instGen_Return");
3880 /*****************************************************************************
3882 * Emit a MemoryBarrier instruction
3884 * Note: all MemoryBarriers instructions can be removed by
3885 * SET COMPlus_JitNoMemoryBarriers=1
3887 #ifdef _TARGET_ARM64_
3888 void CodeGen::instGen_MemoryBarrier(insBarrier barrierType)
3890 void CodeGen::instGen_MemoryBarrier()
3894 if (JitConfig.JitNoMemoryBarriers() == 1)
3900 #if defined(_TARGET_XARCH_)
3902 getEmitter()->emitIns_I_AR(INS_or, EA_4BYTE, 0, REG_SPBASE, 0);
3903 #elif defined(_TARGET_ARM_)
3904 getEmitter()->emitIns_I(INS_dmb, EA_4BYTE, 0xf);
3905 #elif defined(_TARGET_ARM64_)
3906 getEmitter()->emitIns_BARR(INS_dmb, barrierType);
3908 #error "Unknown _TARGET_"
3912 /*****************************************************************************
3914 * Machine independent way to move a Zero value into a register
3916 void CodeGen::instGen_Set_Reg_To_Zero(emitAttr size, regNumber reg, insFlags flags)
3918 #if defined(_TARGET_XARCH_)
3919 getEmitter()->emitIns_R_R(INS_xor, size, reg, reg);
3920 #elif defined(_TARGET_ARMARCH_)
3921 getEmitter()->emitIns_R_I(INS_mov, size, reg, 0 ARM_ARG(flags));
3923 #error "Unknown _TARGET_"
3925 regTracker.rsTrackRegIntCns(reg, 0);
3928 #ifdef LEGACY_BACKEND
3929 /*****************************************************************************
3931 * Machine independent way to move an immediate value into a register
3933 void CodeGen::instGen_Set_Reg_To_Imm(emitAttr size, regNumber reg, ssize_t imm, insFlags flags)
3935 if (!compiler->opts.compReloc)
3937 size = EA_SIZE(size); // Strip any Reloc flags from size if we aren't doing relocs
3940 if ((imm == 0) && !EA_IS_RELOC(size))
3942 instGen_Set_Reg_To_Zero(size, reg, flags);
3946 #if defined(_TARGET_XARCH_)
3947 getEmitter()->emitIns_R_I(INS_mov, size, reg, imm);
3948 #elif defined(_TARGET_ARM_)
3950 if (EA_IS_RELOC(size))
3952 genMov32RelocatableImmediate(size, imm, reg);
3954 else if (arm_Valid_Imm_For_Mov(imm))
3956 getEmitter()->emitIns_R_I(INS_mov, size, reg, imm, flags);
3958 else // We have to use a movw/movt pair of instructions
3960 ssize_t imm_lo16 = (imm & 0xffff);
3961 ssize_t imm_hi16 = (imm >> 16) & 0xffff;
3963 assert(arm_Valid_Imm_For_Mov(imm_lo16));
3964 assert(imm_hi16 != 0);
3966 getEmitter()->emitIns_R_I(INS_movw, size, reg, imm_lo16);
3968 // If we've got a low register, the high word is all bits set,
3969 // and the high bit of the low word is set, we can sign extend
3970 // halfword and save two bytes of encoding. This can happen for
3971 // small magnitude negative numbers 'n' for -32768 <= n <= -1.
3973 if (getEmitter()->isLowRegister(reg) && (imm_hi16 == 0xffff) && ((imm_lo16 & 0x8000) == 0x8000))
3975 getEmitter()->emitIns_R_R(INS_sxth, EA_2BYTE, reg, reg);
3979 getEmitter()->emitIns_R_I(INS_movt, size, reg, imm_hi16);
3982 if (flags == INS_FLAGS_SET)
3983 getEmitter()->emitIns_R_R(INS_mov, size, reg, reg, INS_FLAGS_SET);
3985 #elif defined(_TARGET_ARM64_)
3986 NYI_ARM64("instGen_Set_Reg_To_Imm");
3988 #error "Unknown _TARGET_"
3991 regTracker.rsTrackRegIntCns(reg, imm);
3993 #endif // LEGACY_BACKEND
3995 /*****************************************************************************
3997 * Machine independent way to set the flags based on
3998 * comparing a register with zero
4000 void CodeGen::instGen_Compare_Reg_To_Zero(emitAttr size, regNumber reg)
4002 #if defined(_TARGET_XARCH_)
4003 getEmitter()->emitIns_R_R(INS_test, size, reg, reg);
4004 #elif defined(_TARGET_ARMARCH_)
4005 getEmitter()->emitIns_R_I(INS_cmp, size, reg, 0);
4007 #error "Unknown _TARGET_"
4011 /*****************************************************************************
4013 * Machine independent way to set the flags based upon
4014 * comparing a register with another register
4016 void CodeGen::instGen_Compare_Reg_To_Reg(emitAttr size, regNumber reg1, regNumber reg2)
4018 #if defined(_TARGET_XARCH_) || defined(_TARGET_ARMARCH_)
4019 getEmitter()->emitIns_R_R(INS_cmp, size, reg1, reg2);
4021 #error "Unknown _TARGET_"
4025 /*****************************************************************************
4027 * Machine independent way to set the flags based upon
4028 * comparing a register with an immediate
4030 void CodeGen::instGen_Compare_Reg_To_Imm(emitAttr size, regNumber reg, ssize_t imm)
4034 instGen_Compare_Reg_To_Zero(size, reg);
4038 #if defined(_TARGET_XARCH_)
4039 #if defined(_TARGET_AMD64_)
4040 if ((EA_SIZE(size) == EA_8BYTE) && (((int)imm != (ssize_t)imm) || EA_IS_CNS_RELOC(size)))
4042 #ifndef LEGACY_BACKEND
4043 assert(!"Invalid immediate for instGen_Compare_Reg_To_Imm");
4044 #else // LEGACY_BACKEND
4045 // Load imm into a register
4046 regNumber immReg = regSet.rsGrabReg(RBM_ALLINT & ~genRegMask(reg));
4047 instGen_Set_Reg_To_Imm(size, immReg, (ssize_t)imm);
4048 getEmitter()->emitIns_R_R(INS_cmp, EA_TYPE(size), reg, immReg);
4049 #endif // LEGACY_BACKEND
4052 #endif // _TARGET_AMD64_
4054 getEmitter()->emitIns_R_I(INS_cmp, size, reg, imm);
4056 #elif defined(_TARGET_ARM_)
4057 if (arm_Valid_Imm_For_Alu(imm) || arm_Valid_Imm_For_Alu(-imm))
4059 getEmitter()->emitIns_R_I(INS_cmp, size, reg, imm);
4061 else // We need a scratch register
4063 #ifndef LEGACY_BACKEND
4064 assert(!"Invalid immediate for instGen_Compare_Reg_To_Imm");
4065 #else // LEGACY_BACKEND
4066 // Load imm into a register
4067 regNumber immReg = regSet.rsGrabReg(RBM_ALLINT & ~genRegMask(reg));
4068 instGen_Set_Reg_To_Imm(size, immReg, (ssize_t)imm);
4069 getEmitter()->emitIns_R_R(INS_cmp, size, reg, immReg);
4070 #endif // !LEGACY_BACKEND
4072 #elif defined(_TARGET_ARM64_)
4073 if (true) // TODO-ARM64-NYI: arm_Valid_Imm_For_Alu(imm) || arm_Valid_Imm_For_Alu(-imm))
4075 getEmitter()->emitIns_R_I(INS_cmp, size, reg, imm);
4077 else // We need a scratch register
4079 assert(!"Invalid immediate for instGen_Compare_Reg_To_Imm");
4082 #error "Unknown _TARGET_"
4087 /*****************************************************************************
4089 * Machine independent way to move a stack based local variable into a register
4091 void CodeGen::instGen_Load_Reg_From_Lcl(var_types srcType, regNumber dstReg, int varNum, int offs)
4093 emitAttr size = emitTypeSize(srcType);
4095 getEmitter()->emitIns_R_S(ins_Load(srcType), size, dstReg, varNum, offs);
4098 /*****************************************************************************
4100 * Machine independent way to move a register into a stack based local variable
4102 void CodeGen::instGen_Store_Reg_Into_Lcl(var_types dstType, regNumber srcReg, int varNum, int offs)
4104 emitAttr size = emitTypeSize(dstType);
4106 getEmitter()->emitIns_S_R(ins_Store(dstType), size, srcReg, varNum, offs);
4109 /*****************************************************************************
4111 * Machine independent way to move an immediate into a stack based local variable
4113 void CodeGen::instGen_Store_Imm_Into_Lcl(
4114 var_types dstType, emitAttr sizeAttr, ssize_t imm, int varNum, int offs, regNumber regToUse)
4116 #ifdef _TARGET_XARCH_
4117 #ifdef _TARGET_AMD64_
4118 if ((EA_SIZE(sizeAttr) == EA_8BYTE) && (((int)imm != (ssize_t)imm) || EA_IS_CNS_RELOC(sizeAttr)))
4120 assert(!"Invalid immediate for instGen_Store_Imm_Into_Lcl");
4123 #endif // _TARGET_AMD64_
4125 getEmitter()->emitIns_S_I(ins_Store(dstType), sizeAttr, varNum, offs, (int)imm);
4127 #elif defined(_TARGET_ARMARCH_)
4128 // Load imm into a register
4129 CLANG_FORMAT_COMMENT_ANCHOR;
4131 #ifndef LEGACY_BACKEND
4132 regNumber immReg = regToUse;
4133 assert(regToUse != REG_NA);
4134 #else // LEGACY_BACKEND
4135 regNumber immReg = (regToUse == REG_NA) ? regSet.rsGrabReg(RBM_ALLINT) : regToUse;
4136 #endif // LEGACY_BACKEND
4137 instGen_Set_Reg_To_Imm(sizeAttr, immReg, (ssize_t)imm);
4138 instGen_Store_Reg_Into_Lcl(dstType, immReg, varNum, offs);
4139 if (EA_IS_RELOC(sizeAttr))
4141 regTracker.rsTrackRegTrash(immReg);
4144 #error "Unknown _TARGET_"
4148 /*****************************************************************************/
4149 /*****************************************************************************/
4150 /*****************************************************************************/