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 < _countof(insNames));
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 < _countof(instInfo));
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(GenTree* 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(GenTree* 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 GenTree* base = lea->Base();
659 assert(!base || (base->InReg()));
660 GenTree* 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 */
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 GenTree* rv1 = nullptr;
1384 GenTree* 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, GenTree* tree, GenTree* 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, GenTree* 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, GenTree* 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 GenTree* 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, GenTree* 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 GenTree* 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, GenTree* 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 GenTree* 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, GenTree* 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 GenTree* 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, GenTree* 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 GenTree* 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, GenTree* 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, GenTree* 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, GenTree* 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 ins == INS_roundps || ins == INS_roundss || ins == INS_roundpd || ins == INS_roundsd);
2756 #else // !_TARGET_XARCH_
2757 assert(ins == INS_shld || ins == INS_shrd);
2758 #endif // !_TARGET_XARCH_
2760 getEmitter()->emitIns_R_R_I(ins, size, reg1, reg2, ival);
2764 /*****************************************************************************
2766 * Generate an instruction with two registers, the second one being a byte
2767 * or word register (i.e. this is something like "movzx eax, cl").
2770 void CodeGen::inst_RV_RR(instruction ins, emitAttr size, regNumber reg1, regNumber reg2)
2772 assert(size == EA_1BYTE || size == EA_2BYTE);
2773 #ifdef _TARGET_XARCH_
2774 assert(ins == INS_movsx || ins == INS_movzx);
2775 assert(size != EA_1BYTE || (genRegMask(reg2) & RBM_BYTE_REGS));
2778 getEmitter()->emitIns_R_R(ins, size, reg1, reg2);
2781 /*****************************************************************************
2783 * The following should all end up inline in compiler.hpp at some point.
2786 void CodeGen::inst_ST_RV(instruction ins, TempDsc* tmp, unsigned ofs, regNumber reg, var_types type)
2788 getEmitter()->emitIns_S_R(ins, emitActualTypeSize(type), reg, tmp->tdTempNum(), ofs);
2791 void CodeGen::inst_ST_IV(instruction ins, TempDsc* tmp, unsigned ofs, int val, var_types type)
2793 getEmitter()->emitIns_S_I(ins, emitActualTypeSize(type), tmp->tdTempNum(), ofs, val);
2796 #if FEATURE_FIXED_OUT_ARGS
2797 /*****************************************************************************
2799 * Generate an instruction that references the outgoing argument space
2800 * like "str r3, [sp+0x04]"
2803 void CodeGen::inst_SA_RV(instruction ins, unsigned ofs, regNumber reg, var_types type)
2805 assert(ofs < compiler->lvaOutgoingArgSpaceSize);
2807 getEmitter()->emitIns_S_R(ins, emitActualTypeSize(type), reg, compiler->lvaOutgoingArgSpaceVar, ofs);
2810 void CodeGen::inst_SA_IV(instruction ins, unsigned ofs, int val, var_types type)
2812 assert(ofs < compiler->lvaOutgoingArgSpaceSize);
2814 getEmitter()->emitIns_S_I(ins, emitActualTypeSize(type), compiler->lvaOutgoingArgSpaceVar, ofs, val);
2816 #endif // FEATURE_FIXED_OUT_ARGS
2818 /*****************************************************************************
2820 * Generate an instruction with one register and one operand that is byte
2821 * or short (e.g. something like "movzx eax, byte ptr [edx]").
2824 void CodeGen::inst_RV_ST(instruction ins, emitAttr size, regNumber reg, GenTree* tree)
2826 assert(size == EA_1BYTE || size == EA_2BYTE);
2828 #ifdef LEGACY_BACKEND
2831 /* "movsx erx, rl" must be handled as a special case */
2832 inst_RV_RR(ins, size, reg, tree->gtRegNum);
2835 #endif // LEGACY_BACKEND
2837 inst_RV_TT(ins, reg, tree, 0, size);
2841 void CodeGen::inst_RV_ST(instruction ins, regNumber reg, TempDsc* tmp, unsigned ofs, var_types type, emitAttr size)
2843 if (size == EA_UNKNOWN)
2845 size = emitActualTypeSize(type);
2852 assert(!"Please call ins_Load(type) to get the load instruction");
2863 getEmitter()->emitIns_R_S(ins, size, reg, tmp->tdTempNum(), ofs);
2867 #ifndef LEGACY_BACKEND
2868 assert(!"Default inst_RV_ST case not supported for Arm !LEGACY_BACKEND");
2869 #else // LEGACY_BACKEND
2871 if (varTypeIsFloating(type))
2873 regTmp = regSet.PickRegFloat(type);
2877 regTmp = regSet.rsPickFreeReg(RBM_ALLINT & ~genRegMask(reg));
2879 getEmitter()->emitIns_R_S(ins_Load(type), size, regTmp, tmp->tdTempNum(), ofs);
2880 regTracker.rsTrackRegTrash(regTmp);
2881 getEmitter()->emitIns_R_R(ins, size, reg, regTmp);
2882 #endif // LEGACY_BACKEND
2885 #else // !_TARGET_ARM_
2886 getEmitter()->emitIns_R_S(ins, size, reg, tmp->tdTempNum(), ofs);
2887 #endif // !_TARGET_ARM_
2890 void CodeGen::inst_mov_RV_ST(regNumber reg, GenTree* tree)
2892 /* Figure out the size of the value being loaded */
2894 emitAttr size = EA_ATTR(genTypeSize(tree->gtType));
2895 #ifdef LEGACY_BACKEND
2896 instruction loadIns = ins_Move_Extend(tree->TypeGet(), tree->InReg());
2897 #else // !LEGACY_BACKEND
2898 instruction loadIns = ins_Move_Extend(tree->TypeGet(), false);
2899 #endif // !LEGACY_BACKEND
2901 if (size < EA_4BYTE)
2903 #if CPU_HAS_BYTE_REGS && defined(LEGACY_BACKEND)
2904 if ((tree->gtFlags & GTF_SMALL_OK) && (size == EA_1BYTE) && (genRegMask(reg) & RBM_BYTE_REGS))
2906 /* We only need to load the actual size */
2908 inst_RV_TT(INS_mov, reg, tree, 0, EA_1BYTE);
2911 #endif // CPU_HAS_BYTE_REGS && defined(LEGACY_BACKEND)
2913 /* Generate the "movsx/movzx" opcode */
2915 inst_RV_ST(loadIns, size, reg, tree);
2920 /* Compute op1 into the target register */
2922 inst_RV_TT(loadIns, reg, tree);
2925 #ifdef _TARGET_XARCH_
2926 void CodeGen::inst_FS_ST(instruction ins, emitAttr size, TempDsc* tmp, unsigned ofs)
2928 getEmitter()->emitIns_S(ins, size, tmp->tdTempNum(), ofs);
2933 bool CodeGenInterface::validImmForInstr(instruction ins, ssize_t imm, insFlags flags)
2935 if (getEmitter()->emitInsIsLoadOrStore(ins) && !instIsFP(ins))
2937 return validDispForLdSt(imm, TYP_INT);
2940 bool result = false;
2945 if (validImmForAlu(imm) || validImmForAlu(-imm))
2954 if (validImmForAlu(imm) || validImmForAlu(~imm))
2959 if (validImmForMov(imm))
2965 if ((unsigned_abs(imm) <= 0x00000fff) && (flags != INS_FLAGS_SET)) // 12-bit immediate
2971 if (validImmForAdd(imm, flags))
2981 if (validImmForAlu(imm))
2989 if (imm > 0 && imm <= 32)
2995 if ((imm & 0x3FC) == imm)
3004 bool CodeGen::arm_Valid_Imm_For_Instr(instruction ins, ssize_t imm, insFlags flags)
3006 return validImmForInstr(ins, imm, flags);
3009 bool CodeGenInterface::validDispForLdSt(ssize_t disp, var_types type)
3011 if (varTypeIsFloating(type))
3013 if ((disp & 0x3FC) == disp)
3020 if ((disp >= -0x00ff) && (disp <= 0x0fff))
3026 bool CodeGen::arm_Valid_Disp_For_LdSt(ssize_t disp, var_types type)
3028 return validDispForLdSt(disp, type);
3031 bool CodeGenInterface::validImmForAlu(ssize_t imm)
3033 return emitter::emitIns_valid_imm_for_alu(imm);
3035 bool CodeGen::arm_Valid_Imm_For_Alu(ssize_t imm)
3037 return validImmForAlu(imm);
3040 bool CodeGenInterface::validImmForMov(ssize_t imm)
3042 return emitter::emitIns_valid_imm_for_mov(imm);
3044 bool CodeGen::arm_Valid_Imm_For_Mov(ssize_t imm)
3046 return validImmForMov(imm);
3049 bool CodeGen::arm_Valid_Imm_For_Small_Mov(regNumber reg, ssize_t imm, insFlags flags)
3051 return emitter::emitIns_valid_imm_for_small_mov(reg, imm, flags);
3054 bool CodeGenInterface::validImmForAdd(ssize_t imm, insFlags flags)
3056 return emitter::emitIns_valid_imm_for_add(imm, flags);
3058 bool CodeGen::arm_Valid_Imm_For_Add(ssize_t imm, insFlags flags)
3060 return emitter::emitIns_valid_imm_for_add(imm, flags);
3063 // Check "add Rd,SP,i10"
3064 bool CodeGen::arm_Valid_Imm_For_Add_SP(ssize_t imm)
3066 return emitter::emitIns_valid_imm_for_add_sp(imm);
3069 bool CodeGenInterface::validImmForBL(ssize_t addr)
3072 // If we are running the altjit for NGEN, then assume we can use the "BL" instruction.
3073 // This matches the usual behavior for NGEN, since we normally do generate "BL".
3074 (!compiler->info.compMatchedVM && compiler->opts.jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT)) ||
3075 (compiler->eeGetRelocTypeHint((void*)addr) == IMAGE_REL_BASED_THUMB_BRANCH24);
3077 bool CodeGen::arm_Valid_Imm_For_BL(ssize_t addr)
3079 return validImmForBL(addr);
3082 // Returns true if this instruction writes to a destination register
3084 bool CodeGen::ins_Writes_Dest(instruction ins)
3099 #endif // _TARGET_ARM_
3101 /*****************************************************************************
3103 * Get the machine dependent instruction for performing sign/zero extension.
3106 * srcType - source type
3107 * srcInReg - whether source is in a register
3109 instruction CodeGen::ins_Move_Extend(var_types srcType, bool srcInReg)
3111 instruction ins = INS_invalid;
3113 if (varTypeIsSIMD(srcType))
3115 #if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
3116 // SSE2/AVX requires destination to be a reg always.
3117 // If src is in reg means, it is a reg-reg move.
3119 // SSE2 Note: always prefer movaps/movups over movapd/movupd since the
3120 // former doesn't require 66h prefix and one byte smaller than the
3123 // TODO-CQ: based on whether src type is aligned use movaps instead
3125 return (srcInReg) ? INS_movaps : INS_movups;
3126 #elif defined(_TARGET_ARM64_)
3127 return (srcInReg) ? INS_mov : ins_Load(srcType);
3128 #else // !defined(_TARGET_ARM64_) && !(defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND))
3129 assert(!"unhandled SIMD type");
3130 #endif // !defined(_TARGET_ARM64_) && !(defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND))
3133 #if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
3134 if (varTypeIsFloating(srcType))
3136 if (srcType == TYP_DOUBLE)
3138 return (srcInReg) ? INS_movaps : INS_movsdsse2;
3140 else if (srcType == TYP_FLOAT)
3142 return (srcInReg) ? INS_movaps : INS_movss;
3146 assert(!"unhandled floating type");
3149 #elif defined(_TARGET_ARM_)
3150 if (varTypeIsFloating(srcType))
3153 assert(!varTypeIsFloating(srcType));
3156 #if defined(_TARGET_XARCH_)
3157 if (!varTypeIsSmall(srcType))
3161 else if (varTypeIsUnsigned(srcType))
3169 #elif defined(_TARGET_ARM_)
3171 // Register to Register zero/sign extend operation
3175 if (!varTypeIsSmall(srcType))
3179 else if (varTypeIsUnsigned(srcType))
3181 if (varTypeIsByte(srcType))
3188 if (varTypeIsByte(srcType))
3196 ins = ins_Load(srcType);
3198 #elif defined(_TARGET_ARM64_)
3200 // Register to Register zero/sign extend operation
3204 if (varTypeIsUnsigned(srcType))
3206 if (varTypeIsByte(srcType))
3210 else if (varTypeIsShort(srcType))
3216 // A mov Rd, Rm instruction performs the zero extend
3217 // for the upper 32 bits when the size is EA_4BYTE
3224 if (varTypeIsByte(srcType))
3228 else if (varTypeIsShort(srcType))
3234 if (srcType == TYP_INT)
3247 ins = ins_Load(srcType);
3250 NYI("ins_Move_Extend");
3252 assert(ins != INS_invalid);
3256 /*****************************************************************************
3258 * Get the machine dependent instruction for performing a load for srcType
3261 * srcType - source type
3262 * aligned - whether source is properly aligned if srcType is a SIMD type
3264 instruction CodeGenInterface::ins_Load(var_types srcType, bool aligned /*=false*/)
3266 instruction ins = INS_invalid;
3268 if (varTypeIsSIMD(srcType))
3270 #if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
3272 if (srcType == TYP_SIMD8)
3274 return INS_movsdsse2;
3277 #endif // FEATURE_SIMD
3278 if (compiler->canUseVexEncoding())
3280 return (aligned) ? INS_movapd : INS_movupd;
3284 // SSE2 Note: always prefer movaps/movups over movapd/movupd since the
3285 // former doesn't require 66h prefix and one byte smaller than the
3287 return (aligned) ? INS_movaps : INS_movups;
3289 #elif defined(_TARGET_ARM64_)
3292 assert(!"ins_Load with SIMD type");
3296 if (varTypeIsFloating(srcType))
3298 #if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
3299 if (srcType == TYP_DOUBLE)
3301 return INS_movsdsse2;
3303 else if (srcType == TYP_FLOAT)
3309 assert(!"unhandled floating type");
3311 #elif defined(_TARGET_ARM64_)
3313 #elif defined(_TARGET_ARM_)
3316 assert(!varTypeIsFloating(srcType));
3320 #if defined(_TARGET_XARCH_)
3321 if (!varTypeIsSmall(srcType))
3325 else if (varTypeIsUnsigned(srcType))
3334 #elif defined(_TARGET_ARMARCH_)
3335 if (!varTypeIsSmall(srcType))
3337 #if defined(_TARGET_ARM64_)
3338 if (!varTypeIsI(srcType) && !varTypeIsUnsigned(srcType))
3343 #endif // defined(_TARGET_ARM64_)
3348 else if (varTypeIsByte(srcType))
3350 if (varTypeIsUnsigned(srcType))
3355 else if (varTypeIsShort(srcType))
3357 if (varTypeIsUnsigned(srcType))
3366 assert(ins != INS_invalid);
3370 /*****************************************************************************
3372 * Get the machine dependent instruction for performing a reg-reg copy for dstType
3375 * dstType - destination type
3377 instruction CodeGen::ins_Copy(var_types dstType)
3379 #if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
3380 if (varTypeIsSIMD(dstType))
3384 else if (varTypeIsFloating(dstType))
3386 // Both float and double copy can use movaps
3393 #elif defined(_TARGET_ARM64_)
3394 if (varTypeIsFloating(dstType))
3402 #elif defined(_TARGET_ARM_)
3403 assert(!varTypeIsSIMD(dstType));
3404 if (varTypeIsFloating(dstType))
3412 #elif defined(_TARGET_X86_)
3413 assert(!varTypeIsSIMD(dstType));
3414 assert(!varTypeIsFloating(dstType));
3417 #error "Unknown _TARGET_"
3421 /*****************************************************************************
3423 * Get the machine dependent instruction for performing a store for dstType
3426 * dstType - destination type
3427 * aligned - whether destination is properly aligned if dstType is a SIMD type
3429 instruction CodeGenInterface::ins_Store(var_types dstType, bool aligned /*=false*/)
3431 instruction ins = INS_invalid;
3433 #if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
3434 if (varTypeIsSIMD(dstType))
3437 if (dstType == TYP_SIMD8)
3439 return INS_movsdsse2;
3442 #endif // FEATURE_SIMD
3443 if (compiler->canUseVexEncoding())
3445 return (aligned) ? INS_movapd : INS_movupd;
3449 // SSE2 Note: always prefer movaps/movups over movapd/movupd since the
3450 // former doesn't require 66h prefix and one byte smaller than the
3452 return (aligned) ? INS_movaps : INS_movups;
3455 else if (varTypeIsFloating(dstType))
3457 if (dstType == TYP_DOUBLE)
3459 return INS_movsdsse2;
3461 else if (dstType == TYP_FLOAT)
3467 assert(!"unhandled floating type");
3470 #elif defined(_TARGET_ARM64_)
3471 if (varTypeIsSIMD(dstType) || varTypeIsFloating(dstType))
3473 // All sizes of SIMD and FP instructions use INS_str
3476 #elif defined(_TARGET_ARM_)
3477 assert(!varTypeIsSIMD(dstType));
3478 if (varTypeIsFloating(dstType))
3483 assert(!varTypeIsSIMD(dstType));
3484 assert(!varTypeIsFloating(dstType));
3487 #if defined(_TARGET_XARCH_)
3489 #elif defined(_TARGET_ARMARCH_)
3490 if (!varTypeIsSmall(dstType))
3492 else if (varTypeIsByte(dstType))
3494 else if (varTypeIsShort(dstType))
3500 assert(ins != INS_invalid);
3504 #if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
3506 bool CodeGen::isMoveIns(instruction ins)
3508 return (ins == INS_mov);
3511 instruction CodeGenInterface::ins_FloatLoad(var_types type)
3513 // Do Not use this routine in RyuJIT backend. Instead use ins_Load()/ins_Store()
3517 // everything is just an addressing mode variation on x64
3518 instruction CodeGen::ins_FloatStore(var_types type)
3520 // Do Not use this routine in RyuJIT backend. Instead use ins_Store()
3524 instruction CodeGen::ins_FloatCopy(var_types type)
3526 // Do Not use this routine in RyuJIT backend. Instead use ins_Load().
3530 instruction CodeGen::ins_FloatCompare(var_types type)
3532 return (type == TYP_FLOAT) ? INS_ucomiss : INS_ucomisd;
3535 instruction CodeGen::ins_CopyIntToFloat(var_types srcType, var_types dstType)
3537 // On SSE2/AVX - the same instruction is used for moving double/quad word to XMM/YMM register.
3538 assert((srcType == TYP_INT) || (srcType == TYP_UINT) || (srcType == TYP_LONG) || (srcType == TYP_ULONG));
3540 #if !defined(_TARGET_64BIT_)
3541 // No 64-bit registers on x86.
3542 assert((srcType != TYP_LONG) && (srcType != TYP_ULONG));
3543 #endif // !defined(_TARGET_64BIT_)
3545 return INS_mov_i2xmm;
3548 instruction CodeGen::ins_CopyFloatToInt(var_types srcType, var_types dstType)
3550 // On SSE2/AVX - the same instruction is used for moving double/quad word of XMM/YMM to an integer register.
3551 assert((dstType == TYP_INT) || (dstType == TYP_UINT) || (dstType == TYP_LONG) || (dstType == TYP_ULONG));
3553 #if !defined(_TARGET_64BIT_)
3554 // No 64-bit registers on x86.
3555 assert((dstType != TYP_LONG) && (dstType != TYP_ULONG));
3556 #endif // !defined(_TARGET_64BIT_)
3558 return INS_mov_xmm2i;
3561 instruction CodeGen::ins_MathOp(genTreeOps oper, var_types type)
3566 #ifdef LEGACY_BACKEND
3569 return type == TYP_DOUBLE ? INS_addsd : INS_addss;
3571 #ifdef LEGACY_BACKEND
3574 return type == TYP_DOUBLE ? INS_subsd : INS_subss;
3576 #ifdef LEGACY_BACKEND
3579 return type == TYP_DOUBLE ? INS_mulsd : INS_mulss;
3581 #ifdef LEGACY_BACKEND
3584 return type == TYP_DOUBLE ? INS_divsd : INS_divss;
3586 return type == TYP_DOUBLE ? INS_andpd : INS_andps;
3588 return type == TYP_DOUBLE ? INS_orpd : INS_orps;
3590 return type == TYP_DOUBLE ? INS_xorpd : INS_xorps;
3596 instruction CodeGen::ins_FloatSqrt(var_types type)
3598 instruction ins = INS_invalid;
3600 if (type == TYP_DOUBLE)
3604 else if (type == TYP_FLOAT)
3610 assert(!"ins_FloatSqrt: Unsupported type");
3617 // Conversions to or from floating point values
3618 instruction CodeGen::ins_FloatConv(var_types to, var_types from)
3620 // AVX: For now we support only conversion from Int/Long -> float
3624 // int/long -> float/double use the same instruction but type size would be different.
3630 return INS_cvtsi2ss;
3632 return INS_cvtsi2sd;
3642 return INS_cvttss2si;
3644 return INS_cvttss2si;
3646 return ins_Move_Extend(TYP_FLOAT, false);
3648 return INS_cvtss2sd;
3658 return INS_cvttsd2si;
3660 return INS_cvttsd2si;
3662 return INS_cvtsd2ss;
3664 return ins_Move_Extend(TYP_DOUBLE, false);
3675 #elif defined(_TARGET_ARM_)
3677 bool CodeGen::isMoveIns(instruction ins)
3679 return (ins == INS_vmov) || (ins == INS_mov);
3682 instruction CodeGenInterface::ins_FloatLoad(var_types type)
3684 assert(type == TYP_DOUBLE || type == TYP_FLOAT);
3687 instruction CodeGen::ins_FloatStore(var_types type)
3689 assert(type == TYP_DOUBLE || type == TYP_FLOAT);
3692 instruction CodeGen::ins_FloatCopy(var_types type)
3694 assert(type == TYP_DOUBLE || type == TYP_FLOAT);
3698 instruction CodeGen::ins_CopyIntToFloat(var_types srcType, var_types dstType)
3700 assert((dstType == TYP_FLOAT) || (dstType == TYP_DOUBLE));
3701 assert((srcType == TYP_INT) || (srcType == TYP_UINT) || (srcType == TYP_LONG) || (srcType == TYP_ULONG));
3703 if ((srcType == TYP_LONG) || (srcType == TYP_ULONG))
3705 return INS_vmov_i2d;
3709 return INS_vmov_i2f;
3713 instruction CodeGen::ins_CopyFloatToInt(var_types srcType, var_types dstType)
3715 assert((srcType == TYP_FLOAT) || (srcType == TYP_DOUBLE));
3716 assert((dstType == TYP_INT) || (dstType == TYP_UINT) || (dstType == TYP_LONG) || (dstType == TYP_ULONG));
3718 if ((dstType == TYP_LONG) || (dstType == TYP_ULONG))
3720 return INS_vmov_d2i;
3724 return INS_vmov_f2i;
3728 instruction CodeGen::ins_FloatCompare(var_types type)
3730 // Not used and not implemented
3734 instruction CodeGen::ins_FloatSqrt(var_types type)
3736 // Not used and not implemented
3740 instruction CodeGen::ins_MathOp(genTreeOps oper, var_types type)
3745 #ifdef LEGACY_BACKEND
3750 #ifdef LEGACY_BACKEND
3755 #ifdef LEGACY_BACKEND
3761 #ifdef LEGACY_BACKEND
3772 instruction CodeGen::ins_FloatConv(var_types to, var_types from)
3780 return INS_vcvt_i2f;
3782 return INS_vcvt_i2d;
3791 return INS_vcvt_u2f;
3793 return INS_vcvt_u2d;
3802 NYI("long to float");
3804 NYI("long to double");
3813 return INS_vcvt_f2i;
3815 return INS_vcvt_f2u;
3817 NYI("float to long");
3819 return INS_vcvt_f2d;
3830 return INS_vcvt_d2i;
3832 return INS_vcvt_d2u;
3834 NYI("double to long");
3836 return INS_vcvt_d2f;
3848 #endif // #elif defined(_TARGET_ARM_)
3850 /*****************************************************************************
3852 * Machine independent way to return
3854 void CodeGen::instGen_Return(unsigned stkArgSize)
3856 #if defined(_TARGET_XARCH_)
3857 if (stkArgSize == 0)
3863 inst_IV(INS_ret, stkArgSize);
3865 #elif defined(_TARGET_ARM_)
3867 // The return on ARM is folded into the pop multiple instruction
3868 // and as we do not know the exact set of registers that we will
3869 // need to restore (pop) when we first call instGen_Return we will
3870 // instead just not emit anything for this method on the ARM
3871 // The return will be part of the pop multiple and that will be
3872 // part of the epilog that is generated by genFnEpilog()
3873 #elif defined(_TARGET_ARM64_)
3874 // This function shouldn't be used on ARM64.
3877 NYI("instGen_Return");
3881 /*****************************************************************************
3883 * Emit a MemoryBarrier instruction
3885 * Note: all MemoryBarriers instructions can be removed by
3886 * SET COMPlus_JitNoMemoryBarriers=1
3888 #ifdef _TARGET_ARM64_
3889 void CodeGen::instGen_MemoryBarrier(insBarrier barrierType)
3891 void CodeGen::instGen_MemoryBarrier()
3895 if (JitConfig.JitNoMemoryBarriers() == 1)
3901 #if defined(_TARGET_XARCH_)
3903 getEmitter()->emitIns_I_AR(INS_or, EA_4BYTE, 0, REG_SPBASE, 0);
3904 #elif defined(_TARGET_ARM_)
3905 getEmitter()->emitIns_I(INS_dmb, EA_4BYTE, 0xf);
3906 #elif defined(_TARGET_ARM64_)
3907 getEmitter()->emitIns_BARR(INS_dmb, barrierType);
3909 #error "Unknown _TARGET_"
3913 /*****************************************************************************
3915 * Machine independent way to move a Zero value into a register
3917 void CodeGen::instGen_Set_Reg_To_Zero(emitAttr size, regNumber reg, insFlags flags)
3919 #if defined(_TARGET_XARCH_)
3920 getEmitter()->emitIns_R_R(INS_xor, size, reg, reg);
3921 #elif defined(_TARGET_ARMARCH_)
3922 getEmitter()->emitIns_R_I(INS_mov, size, reg, 0 ARM_ARG(flags));
3924 #error "Unknown _TARGET_"
3926 regTracker.rsTrackRegIntCns(reg, 0);
3929 #ifdef LEGACY_BACKEND
3930 /*****************************************************************************
3932 * Machine independent way to move an immediate value into a register
3934 void CodeGen::instGen_Set_Reg_To_Imm(emitAttr size, regNumber reg, ssize_t imm, insFlags flags)
3936 if (!compiler->opts.compReloc)
3938 size = EA_SIZE(size); // Strip any Reloc flags from size if we aren't doing relocs
3941 if ((imm == 0) && !EA_IS_RELOC(size))
3943 instGen_Set_Reg_To_Zero(size, reg, flags);
3947 #if defined(_TARGET_XARCH_)
3948 getEmitter()->emitIns_R_I(INS_mov, size, reg, imm);
3949 #elif defined(_TARGET_ARM_)
3951 if (EA_IS_RELOC(size))
3953 genMov32RelocatableImmediate(size, imm, reg);
3955 else if (arm_Valid_Imm_For_Mov(imm))
3957 getEmitter()->emitIns_R_I(INS_mov, size, reg, imm, flags);
3959 else // We have to use a movw/movt pair of instructions
3961 ssize_t imm_lo16 = (imm & 0xffff);
3962 ssize_t imm_hi16 = (imm >> 16) & 0xffff;
3964 assert(arm_Valid_Imm_For_Mov(imm_lo16));
3965 assert(imm_hi16 != 0);
3967 getEmitter()->emitIns_R_I(INS_movw, size, reg, imm_lo16);
3969 // If we've got a low register, the high word is all bits set,
3970 // and the high bit of the low word is set, we can sign extend
3971 // halfword and save two bytes of encoding. This can happen for
3972 // small magnitude negative numbers 'n' for -32768 <= n <= -1.
3974 if (getEmitter()->isLowRegister(reg) && (imm_hi16 == 0xffff) && ((imm_lo16 & 0x8000) == 0x8000))
3976 getEmitter()->emitIns_R_R(INS_sxth, EA_2BYTE, reg, reg);
3980 getEmitter()->emitIns_R_I(INS_movt, size, reg, imm_hi16);
3983 if (flags == INS_FLAGS_SET)
3984 getEmitter()->emitIns_R_R(INS_mov, size, reg, reg, INS_FLAGS_SET);
3986 #elif defined(_TARGET_ARM64_)
3987 NYI_ARM64("instGen_Set_Reg_To_Imm");
3989 #error "Unknown _TARGET_"
3992 regTracker.rsTrackRegIntCns(reg, imm);
3994 #endif // LEGACY_BACKEND
3996 /*****************************************************************************
3998 * Machine independent way to set the flags based on
3999 * comparing a register with zero
4001 void CodeGen::instGen_Compare_Reg_To_Zero(emitAttr size, regNumber reg)
4003 #if defined(_TARGET_XARCH_)
4004 getEmitter()->emitIns_R_R(INS_test, size, reg, reg);
4005 #elif defined(_TARGET_ARMARCH_)
4006 getEmitter()->emitIns_R_I(INS_cmp, size, reg, 0);
4008 #error "Unknown _TARGET_"
4012 /*****************************************************************************
4014 * Machine independent way to set the flags based upon
4015 * comparing a register with another register
4017 void CodeGen::instGen_Compare_Reg_To_Reg(emitAttr size, regNumber reg1, regNumber reg2)
4019 #if defined(_TARGET_XARCH_) || defined(_TARGET_ARMARCH_)
4020 getEmitter()->emitIns_R_R(INS_cmp, size, reg1, reg2);
4022 #error "Unknown _TARGET_"
4026 /*****************************************************************************
4028 * Machine independent way to set the flags based upon
4029 * comparing a register with an immediate
4031 void CodeGen::instGen_Compare_Reg_To_Imm(emitAttr size, regNumber reg, ssize_t imm)
4035 instGen_Compare_Reg_To_Zero(size, reg);
4039 #if defined(_TARGET_XARCH_)
4040 #if defined(_TARGET_AMD64_)
4041 if ((EA_SIZE(size) == EA_8BYTE) && (((int)imm != (ssize_t)imm) || EA_IS_CNS_RELOC(size)))
4043 #ifndef LEGACY_BACKEND
4044 assert(!"Invalid immediate for instGen_Compare_Reg_To_Imm");
4045 #else // LEGACY_BACKEND
4046 // Load imm into a register
4047 regNumber immReg = regSet.rsGrabReg(RBM_ALLINT & ~genRegMask(reg));
4048 instGen_Set_Reg_To_Imm(size, immReg, (ssize_t)imm);
4049 getEmitter()->emitIns_R_R(INS_cmp, EA_TYPE(size), reg, immReg);
4050 #endif // LEGACY_BACKEND
4053 #endif // _TARGET_AMD64_
4055 getEmitter()->emitIns_R_I(INS_cmp, size, reg, imm);
4057 #elif defined(_TARGET_ARM_)
4058 if (arm_Valid_Imm_For_Alu(imm) || arm_Valid_Imm_For_Alu(-imm))
4060 getEmitter()->emitIns_R_I(INS_cmp, size, reg, imm);
4062 else // We need a scratch register
4064 #ifndef LEGACY_BACKEND
4065 assert(!"Invalid immediate for instGen_Compare_Reg_To_Imm");
4066 #else // LEGACY_BACKEND
4067 // Load imm into a register
4068 regNumber immReg = regSet.rsGrabReg(RBM_ALLINT & ~genRegMask(reg));
4069 instGen_Set_Reg_To_Imm(size, immReg, (ssize_t)imm);
4070 getEmitter()->emitIns_R_R(INS_cmp, size, reg, immReg);
4071 #endif // !LEGACY_BACKEND
4073 #elif defined(_TARGET_ARM64_)
4074 if (true) // TODO-ARM64-NYI: arm_Valid_Imm_For_Alu(imm) || arm_Valid_Imm_For_Alu(-imm))
4076 getEmitter()->emitIns_R_I(INS_cmp, size, reg, imm);
4078 else // We need a scratch register
4080 assert(!"Invalid immediate for instGen_Compare_Reg_To_Imm");
4083 #error "Unknown _TARGET_"
4088 /*****************************************************************************
4090 * Machine independent way to move a stack based local variable into a register
4092 void CodeGen::instGen_Load_Reg_From_Lcl(var_types srcType, regNumber dstReg, int varNum, int offs)
4094 emitAttr size = emitTypeSize(srcType);
4096 getEmitter()->emitIns_R_S(ins_Load(srcType), size, dstReg, varNum, offs);
4099 /*****************************************************************************
4101 * Machine independent way to move a register into a stack based local variable
4103 void CodeGen::instGen_Store_Reg_Into_Lcl(var_types dstType, regNumber srcReg, int varNum, int offs)
4105 emitAttr size = emitTypeSize(dstType);
4107 getEmitter()->emitIns_S_R(ins_Store(dstType), size, srcReg, varNum, offs);
4110 /*****************************************************************************
4112 * Machine independent way to move an immediate into a stack based local variable
4114 void CodeGen::instGen_Store_Imm_Into_Lcl(
4115 var_types dstType, emitAttr sizeAttr, ssize_t imm, int varNum, int offs, regNumber regToUse)
4117 #ifdef _TARGET_XARCH_
4118 #ifdef _TARGET_AMD64_
4119 if ((EA_SIZE(sizeAttr) == EA_8BYTE) && (((int)imm != (ssize_t)imm) || EA_IS_CNS_RELOC(sizeAttr)))
4121 assert(!"Invalid immediate for instGen_Store_Imm_Into_Lcl");
4124 #endif // _TARGET_AMD64_
4126 getEmitter()->emitIns_S_I(ins_Store(dstType), sizeAttr, varNum, offs, (int)imm);
4128 #elif defined(_TARGET_ARMARCH_)
4129 // Load imm into a register
4130 CLANG_FORMAT_COMMENT_ANCHOR;
4132 #ifndef LEGACY_BACKEND
4133 regNumber immReg = regToUse;
4134 assert(regToUse != REG_NA);
4135 #else // LEGACY_BACKEND
4136 regNumber immReg = (regToUse == REG_NA) ? regSet.rsGrabReg(RBM_ALLINT) : regToUse;
4137 #endif // LEGACY_BACKEND
4138 instGen_Set_Reg_To_Imm(sizeAttr, immReg, (ssize_t)imm);
4139 instGen_Store_Reg_Into_Lcl(dstType, immReg, varNum, offs);
4140 if (EA_IS_RELOC(sizeAttr))
4142 regTracker.rsTrackRegTrash(immReg);
4145 #error "Unknown _TARGET_"
4149 /*****************************************************************************/
4150 /*****************************************************************************/
4151 /*****************************************************************************/