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.
6 // This class contains all the data & functionality for code generation
7 // of a method, except for the target-specific elements, which are
8 // primarily in the Target class.
13 #include "compiler.h" // temporary??
14 #include "codegeninterface.h"
16 #include "jitgcinfo.h"
18 #if defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_) || defined(_TARGET_ARM_)
19 #define FOREACH_REGISTER_FILE(file) \
20 for ((file) = &(this->intRegState); (file) != NULL; \
21 (file) = ((file) == &(this->intRegState)) ? &(this->floatRegState) : NULL)
23 #define FOREACH_REGISTER_FILE(file) (file) = &(this->intRegState);
26 class CodeGen : public CodeGenInterface
29 friend class DisAssembler;
32 // This could use further abstraction
33 CodeGen(Compiler* theCompiler);
35 virtual void genGenerateCode(void** codePtr, ULONG* nativeSizeOfCode);
36 // TODO-Cleanup: Abstract out the part of this that finds the addressing mode, and
38 virtual bool genCreateAddrMode(GenTree* addr,
45 #endif // SCALED_ADDR_MODES
49 #if defined(_TARGET_XARCH_)
50 // Bit masks used in negating a float or double number.
51 // This is to avoid creating more than one data constant for these bitmasks when a
52 // method has more than one GT_NEG operation on floating point values.
53 CORINFO_FIELD_HANDLE negBitmaskFlt;
54 CORINFO_FIELD_HANDLE negBitmaskDbl;
56 // Bit masks used in computing Math.Abs() of a float or double number.
57 CORINFO_FIELD_HANDLE absBitmaskFlt;
58 CORINFO_FIELD_HANDLE absBitmaskDbl;
60 // Bit mask used in U8 -> double conversion to adjust the result.
61 CORINFO_FIELD_HANDLE u8ToDblBitmask;
63 // Generates SSE2 code for the given tree as "Operand BitWiseOp BitMask"
64 void genSSE2BitwiseOp(GenTree* treeNode);
66 // Generates SSE41 code for the given tree as a round operation
67 void genSSE41RoundOp(GenTreeOp* treeNode);
68 #endif // defined(_TARGET_XARCH_)
70 void genPrepForCompiler();
72 void genPrepForEHCodegen();
74 inline RegState* regStateForType(var_types t)
76 return varTypeIsFloating(t) ? &floatRegState : &intRegState;
78 inline RegState* regStateForReg(regNumber reg)
80 return genIsValidFloatReg(reg) ? &floatRegState : &intRegState;
83 regNumber genFramePointerReg()
85 if (isFramePointerUsed())
101 static emitJumpKind genJumpKindForOper(genTreeOps cmp, CompareKind compareKind);
103 // For a given compare oper tree, returns the conditions to use with jmp/set in 'jmpKind' array.
104 // The corresponding elements of jmpToTrueLabel indicate whether the target of the jump is to the
105 // 'true' label or a 'false' label.
107 // 'true' label corresponds to jump target of the current basic block i.e. the target to
108 // branch to on compare condition being true. 'false' label corresponds to the target to
109 // branch to on condition being false.
110 static void genJumpKindsForTree(GenTree* cmpTree, emitJumpKind jmpKind[2], bool jmpToTrueLabel[2]);
112 static bool genShouldRoundFP();
114 GenTreeIndir indirForm(var_types type, GenTree* base);
116 GenTreeIntCon intForm(var_types type, ssize_t value);
118 void genRangeCheck(GenTree* node);
120 void genLockedInstructions(GenTreeOp* node);
121 #ifdef _TARGET_XARCH_
122 void genCodeForLockAdd(GenTreeOp* node);
125 //-------------------------------------------------------------------------
126 // Register-related methods
131 // On some targets such as the ARM we may need to have an extra reserved register
132 // that is used when addressing stack based locals and stack based temps.
133 // This method returns the regNumber that should be used when an extra register
134 // is needed to access the stack based locals and stack based temps.
136 regNumber rsGetRsvdReg()
138 // We should have already added this register to the mask
139 // of reserved registers in regSet.rdMaskResvd
140 noway_assert((regSet.rsMaskResvd & RBM_OPT_RSVD) != 0);
144 #endif // REG_OPT_RSVD
146 //-------------------------------------------------------------------------
148 bool genUseBlockInit; // true if we plan to block-initialize the local stack frame
149 unsigned genInitStkLclCnt; // The count of local variables that we need to zero init
151 // Keeps track of how many bytes we've pushed on the processor's stack.
153 unsigned genStackLevel;
155 void SubtractStackLevel(unsigned adjustment)
157 assert(genStackLevel >= adjustment);
158 unsigned newStackLevel = genStackLevel - adjustment;
159 if (genStackLevel != newStackLevel)
161 JITDUMP("Adjusting stack level from %d to %d\n", genStackLevel, newStackLevel);
163 genStackLevel = newStackLevel;
166 void AddStackLevel(unsigned adjustment)
168 unsigned newStackLevel = genStackLevel + adjustment;
169 if (genStackLevel != newStackLevel)
171 JITDUMP("Adjusting stack level from %d to %d\n", genStackLevel, newStackLevel);
173 genStackLevel = newStackLevel;
176 void SetStackLevel(unsigned newStackLevel)
178 if (genStackLevel != newStackLevel)
180 JITDUMP("Setting stack level from %d to %d\n", genStackLevel, newStackLevel);
182 genStackLevel = newStackLevel;
187 bool genNeedPrologStackProbe;
189 void genGenerateStackProbe();
192 //-------------------------------------------------------------------------
196 // Allocates storage for the GC info, writes the GC info into that storage, records the address of the
197 // GC info of the method with the EE, and returns a pointer to the "info" portion (just post-header) of
198 // the GC info. Requires "codeSize" to be the size of the generated code, "prologSize" and "epilogSize"
199 // to be the sizes of the prolog and epilog, respectively. In DEBUG, makes a check involving the
200 // "codePtr", assumed to be a pointer to the start of the generated code.
201 CLANG_FORMAT_COMMENT_ANCHOR;
203 #ifdef JIT32_GCENCODER
204 void* genCreateAndStoreGCInfo(unsigned codeSize, unsigned prologSize, unsigned epilogSize DEBUGARG(void* codePtr));
205 void* genCreateAndStoreGCInfoJIT32(unsigned codeSize,
207 unsigned epilogSize DEBUGARG(void* codePtr));
208 #else // !JIT32_GCENCODER
209 void genCreateAndStoreGCInfo(unsigned codeSize, unsigned prologSize, unsigned epilogSize DEBUGARG(void* codePtr));
210 void genCreateAndStoreGCInfoX64(unsigned codeSize, unsigned prologSize DEBUGARG(void* codePtr));
211 #endif // !JIT32_GCENCODER
213 /**************************************************************************
215 *************************************************************************/
218 // the current (pending) label ref, a label which has been referenced but not yet seen
219 BasicBlock* genPendingCallLabel;
222 // Last instr we have displayed for dspInstrs
223 unsigned genCurDispOffset;
225 static const char* genInsName(instruction ins);
228 //-------------------------------------------------------------------------
230 // JIT-time constants for use in multi-dimensional array code generation.
231 unsigned genOffsetOfMDArrayLowerBound(var_types elemType, unsigned rank, unsigned dimension);
232 unsigned genOffsetOfMDArrayDimensionSize(var_types elemType, unsigned rank, unsigned dimension);
235 static const char* genSizeStr(emitAttr size);
237 void genStressRegs(GenTree* tree);
240 void genCodeForBBlist();
243 void genSpillVar(GenTree* tree);
246 void genEmitHelperCall(unsigned helper, int argSize, emitAttr retSize, regNumber callTarget = REG_NA);
248 void genGCWriteBarrier(GenTree* tgt, GCInfo::WriteBarrierForm wbf);
250 BasicBlock* genCreateTempLabel();
252 void genDefineTempLabel(BasicBlock* label);
254 void genAdjustSP(ssize_t delta);
256 void genAdjustStackLevel(BasicBlock* block);
258 void genExitCode(BasicBlock* block);
260 void genJumpToThrowHlpBlk(emitJumpKind jumpKind, SpecialCodeKind codeKind, GenTree* failBlk = nullptr);
262 void genCheckOverflow(GenTree* tree);
264 //-------------------------------------------------------------------------
266 // Prolog/epilog generation
268 //-------------------------------------------------------------------------
271 // Prolog functions and data (there are a few exceptions for more generally used things)
274 void genEstablishFramePointer(int delta, bool reportUnwindData);
275 void genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbered, RegState* regState);
276 void genEnregisterIncomingStackArgs();
277 void genCheckUseBlockInit();
278 #if defined(UNIX_AMD64_ABI) && defined(FEATURE_SIMD)
279 void genClearStackVec3ArgUpperBits();
280 #endif // UNIX_AMD64_ABI && FEATURE_SIMD
282 #if defined(_TARGET_ARM64_)
283 bool genInstrWithConstant(instruction ins,
289 bool inUnwindRegion = false);
291 void genStackPointerAdjustment(ssize_t spAdjustment, regNumber tmpReg, bool* pTmpRegIsZero);
293 void genPrologSaveRegPair(regNumber reg1,
297 bool lastSavedWasPreviousPair,
299 bool* pTmpRegIsZero);
301 void genPrologSaveReg(regNumber reg1, int spOffset, int spDelta, regNumber tmpReg, bool* pTmpRegIsZero);
303 void genEpilogRestoreRegPair(
304 regNumber reg1, regNumber reg2, int spOffset, int spDelta, regNumber tmpReg, bool* pTmpRegIsZero);
306 void genEpilogRestoreReg(regNumber reg1, int spOffset, int spDelta, regNumber tmpReg, bool* pTmpRegIsZero);
308 void genSaveCalleeSavedRegistersHelp(regMaskTP regsToSaveMask, int lowestCalleeSavedOffset, int spDelta);
310 void genRestoreCalleeSavedRegistersHelp(regMaskTP regsToRestoreMask, int lowestCalleeSavedOffset, int spDelta);
312 void genPushCalleeSavedRegisters(regNumber initReg, bool* pInitRegZeroed);
314 void genPushCalleeSavedRegisters();
317 void genAllocLclFrame(unsigned frameSize, regNumber initReg, bool* pInitRegZeroed, regMaskTP maskArgRegsLiveIn);
319 #if defined(_TARGET_ARM_)
321 void genPushFltRegs(regMaskTP regMask);
322 void genPopFltRegs(regMaskTP regMask);
323 regMaskTP genStackAllocRegisterMask(unsigned frameSize, regMaskTP maskCalleeSavedFloat);
325 regMaskTP genJmpCallArgMask();
327 void genFreeLclFrame(unsigned frameSize,
328 /* IN OUT */ bool* pUnwindStarted,
331 void genMov32RelocatableDisplacement(BasicBlock* block, regNumber reg);
332 void genMov32RelocatableDataLabel(unsigned value, regNumber reg);
333 void genMov32RelocatableImmediate(emitAttr size, BYTE* addr, regNumber reg);
335 bool genUsedPopToReturn; // True if we use the pop into PC to return,
336 // False if we didn't and must branch to LR to return.
338 // A set of information that is used by funclet prolog and epilog generation. It is collected once, before
339 // funclet prologs and epilogs are generated, and used by all funclet prologs and epilogs, which must all be the
341 struct FuncletFrameInfoDsc
343 regMaskTP fiSaveRegs; // Set of registers saved in the funclet prolog (includes LR)
344 unsigned fiFunctionCallerSPtoFPdelta; // Delta between caller SP and the frame pointer
345 unsigned fiSpDelta; // Stack pointer delta
346 unsigned fiPSP_slot_SP_offset; // PSP slot offset from SP
347 int fiPSP_slot_CallerSP_offset; // PSP slot offset from Caller SP
350 FuncletFrameInfoDsc genFuncletInfo;
352 #elif defined(_TARGET_ARM64_)
354 // A set of information that is used by funclet prolog and epilog generation. It is collected once, before
355 // funclet prologs and epilogs are generated, and used by all funclet prologs and epilogs, which must all be the
357 struct FuncletFrameInfoDsc
359 regMaskTP fiSaveRegs; // Set of callee-saved registers saved in the funclet prolog (includes LR)
360 int fiFunction_CallerSP_to_FP_delta; // Delta between caller SP and the frame pointer in the parent function
362 int fiSP_to_FPLR_save_delta; // FP/LR register save offset from SP (positive)
363 int fiSP_to_PSP_slot_delta; // PSP slot offset from SP (positive)
364 int fiSP_to_CalleeSave_delta; // First callee-saved register slot offset from SP (positive)
365 int fiCallerSP_to_PSP_slot_delta; // PSP slot offset from Caller SP (negative)
366 int fiFrameType; // Funclet frame types are numbered. See genFuncletProlog() for details.
367 int fiSpDelta1; // Stack pointer delta 1 (negative)
368 int fiSpDelta2; // Stack pointer delta 2 (negative)
371 FuncletFrameInfoDsc genFuncletInfo;
373 #elif defined(_TARGET_AMD64_)
375 // A set of information that is used by funclet prolog and epilog generation. It is collected once, before
376 // funclet prologs and epilogs are generated, and used by all funclet prologs and epilogs, which must all be the
378 struct FuncletFrameInfoDsc
380 unsigned fiFunction_InitialSP_to_FP_delta; // Delta between Initial-SP and the frame pointer
381 unsigned fiSpDelta; // Stack pointer delta
382 int fiPSP_slot_InitialSP_offset; // PSP slot offset from Initial-SP
385 FuncletFrameInfoDsc genFuncletInfo;
387 #endif // _TARGET_AMD64_
389 #if defined(_TARGET_XARCH_)
391 // Save/Restore callee saved float regs to stack
392 void genPreserveCalleeSavedFltRegs(unsigned lclFrameSize);
393 void genRestoreCalleeSavedFltRegs(unsigned lclFrameSize);
394 // Generate VZeroupper instruction to avoid AVX/SSE transition penalty
395 void genVzeroupperIfNeeded(bool check256bitOnly = true);
397 #endif // _TARGET_XARCH_
399 void genZeroInitFltRegs(const regMaskTP& initFltRegs, const regMaskTP& initDblRegs, const regNumber& initReg);
401 regNumber genGetZeroReg(regNumber initReg, bool* pInitRegZeroed);
403 void genZeroInitFrame(int untrLclHi, int untrLclLo, regNumber initReg, bool* pInitRegZeroed);
405 void genReportGenericContextArg(regNumber initReg, bool* pInitRegZeroed);
407 void genSetGSSecurityCookie(regNumber initReg, bool* pInitRegZeroed);
409 void genFinalizeFrame();
411 #ifdef PROFILING_SUPPORTED
412 void genProfilingEnterCallback(regNumber initReg, bool* pInitRegZeroed);
413 void genProfilingLeaveCallback(unsigned helper = CORINFO_HELP_PROF_FCN_LEAVE);
414 #endif // PROFILING_SUPPORTED
416 void genPrologPadForReJit();
419 void genEmitCall(int callType,
420 CORINFO_METHOD_HANDLE methHnd,
421 INDEBUG_LDISASM_COMMA(CORINFO_SIG_INFO* sigInfo)
423 X86_ARG(ssize_t argSize),
425 MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize),
427 regNumber base = REG_NA,
429 bool isNoGC = false);
433 void genEmitCall(int callType,
434 CORINFO_METHOD_HANDLE methHnd,
435 INDEBUG_LDISASM_COMMA(CORINFO_SIG_INFO* sigInfo)
437 X86_ARG(ssize_t argSize),
439 MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize),
440 IL_OFFSETX ilOffset);
446 CLANG_FORMAT_COMMENT_ANCHOR;
448 #if defined(_TARGET_ARM_)
449 bool genCanUsePopToReturn(regMaskTP maskPopRegsInt, bool jmpEpilog);
452 #if defined(_TARGET_ARM64_)
454 void genPopCalleeSavedRegistersAndFreeLclFrame(bool jmpEpilog);
456 #else // !defined(_TARGET_ARM64_)
458 void genPopCalleeSavedRegisters(bool jmpEpilog = false);
460 #endif // !defined(_TARGET_ARM64_)
463 // Common or driving functions
466 void genReserveProlog(BasicBlock* block); // currently unused
467 void genReserveEpilog(BasicBlock* block);
469 void genFnEpilog(BasicBlock* block);
471 #if FEATURE_EH_FUNCLETS
473 void genReserveFuncletProlog(BasicBlock* block);
474 void genReserveFuncletEpilog(BasicBlock* block);
475 void genFuncletProlog(BasicBlock* block);
476 void genFuncletEpilog();
477 void genCaptureFuncletPrologEpilogInfo();
479 void genSetPSPSym(regNumber initReg, bool* pInitRegZeroed);
481 void genUpdateCurrentFunclet(BasicBlock* block);
482 #if defined(_TARGET_ARM_)
483 void genInsertNopForUnwinder(BasicBlock* block);
486 #else // FEATURE_EH_FUNCLETS
488 // This is a no-op when there are no funclets!
489 void genUpdateCurrentFunclet(BasicBlock* block)
494 #if defined(_TARGET_ARM_)
495 void genInsertNopForUnwinder(BasicBlock* block)
501 #endif // FEATURE_EH_FUNCLETS
503 void genGeneratePrologsAndEpilogs();
505 #if defined(DEBUG) && defined(_TARGET_ARM64_)
506 void genArm64EmitterUnitTests();
509 #if defined(DEBUG) && defined(LATE_DISASM) && defined(_TARGET_AMD64_)
510 void genAmd64EmitterUnitTests();
513 //-------------------------------------------------------------------------
515 // End prolog/epilog generation
517 //-------------------------------------------------------------------------
519 void genSinglePush();
521 regMaskTP genPushRegs(regMaskTP regs, regMaskTP* byrefRegs, regMaskTP* noRefRegs);
522 void genPopRegs(regMaskTP regs, regMaskTP byrefRegs, regMaskTP noRefRegs);
525 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
526 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
528 XX Debugging Support XX
530 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
531 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
535 void genIPmappingDisp(unsigned mappingNum, Compiler::IPmappingDsc* ipMapping);
536 void genIPmappingListDisp();
539 void genIPmappingAdd(IL_OFFSETX offset, bool isLabel);
540 void genIPmappingAddToFront(IL_OFFSETX offset);
541 void genIPmappingGen();
543 void genEnsureCodeEmitted(IL_OFFSETX offsx);
545 //-------------------------------------------------------------------------
546 // scope info for the variables
548 void genSetScopeInfo(unsigned which,
549 UNATIVE_OFFSET startOffs,
550 UNATIVE_OFFSET length,
554 Compiler::siVarLoc& loc);
556 void genSetScopeInfo();
558 void genRemoveBBsection(BasicBlock* head, BasicBlock* tail);
562 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
563 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
567 XX Keeps track of the scopes during code-generation. XX
568 XX This is used to translate the local-variable debugging information XX
569 XX from IL offsets to native code offsets. XX
571 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
572 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
575 /*****************************************************************************/
576 /*****************************************************************************
579 * This class is called during code gen at block-boundaries, and when the
580 * set of live variables changes. It keeps track of the scope of the variables
581 * in terms of the native code PC.
587 void siBeginBlock(BasicBlock* block);
589 void siEndBlock(BasicBlock* block);
591 virtual void siUpdate();
593 void siCheckVarScope(unsigned varNum, IL_OFFSET offs);
595 void siCloseAllOpenScopes();
598 void siDispOpenScopes();
601 /**************************************************************************
603 *************************************************************************/
608 emitLocation scStartLoc; // emitter location of start of scope
609 emitLocation scEndLoc; // emitter location of end of scope
611 unsigned scVarNum; // index into lvaTable
612 unsigned scLVnum; // 'which' in eeGetLVinfo()
614 unsigned scStackLevel; // Only for stk-vars
615 bool scAvailable : 1; // It has a home / Home recycled - TODO-Cleanup: it appears this is unused (always true)
621 siScope siOpenScopeList, siScopeList, *siOpenScopeLast, *siScopeLast;
625 VARSET_TP siLastLife; // Life at last call to siUpdate()
627 // Tracks the last entry for each tracked register variable
629 siScope** siLatestTrackedScopes;
631 IL_OFFSET siLastEndOffs; // IL offset of the (exclusive) end of the last block processed
633 #if FEATURE_EH_FUNCLETS
634 bool siInFuncletRegion; // Have we seen the start of the funclet region?
635 #endif // FEATURE_EH_FUNCLETS
639 siScope* siNewScope(unsigned LVnum, unsigned varNum);
641 void siRemoveFromOpenScopeList(siScope* scope);
643 void siEndTrackedScope(unsigned varIndex);
645 void siEndScope(unsigned varNum);
647 void siEndScope(siScope* scope);
650 bool siVerifyLocalVarTab();
656 const char* siRegVarName(size_t offs, size_t size, unsigned reg);
659 const char* siStackVarName(size_t offs, size_t size, unsigned reg, unsigned stkOffs);
660 #endif // LATE_DISASM
664 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
665 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
667 XX PrologScopeInfo XX
669 XX We need special handling in the prolog block, as the parameter variables XX
670 XX may not be in the same position described by genLclVarTable - they all XX
671 XX start out on the stack XX
673 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
674 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
680 void psiAdjustStackLevel(unsigned size);
682 void psiMoveESPtoEBP();
684 void psiMoveToReg(unsigned varNum, regNumber reg = REG_NA, regNumber otherReg = REG_NA);
686 void psiMoveToStack(unsigned varNum);
690 /**************************************************************************
692 *************************************************************************/
697 emitLocation scStartLoc; // emitter location of start of scope
698 emitLocation scEndLoc; // emitter location of end of scope
700 unsigned scSlotNum; // index into lclVarTab
701 unsigned scLVnum; // 'which' in eeGetLVinfo()
708 regNumberSmall scRegNum;
711 // - "other half" of long var on architectures with 32 bit size registers - x86.
712 // - for System V structs it stores the second register
713 // used to pass a register passed struct.
714 regNumberSmall scOtherReg;
719 regNumberSmall scBaseReg;
720 NATIVE_OFFSET scOffset;
728 psiScope psiOpenScopeList, psiScopeList, *psiOpenScopeLast, *psiScopeLast;
730 unsigned psiScopeCnt;
732 // Implementation Functions
734 psiScope* psiNewPrologScope(unsigned LVnum, unsigned slotNum);
736 void psiEndPrologScope(psiScope* scope);
738 void psSetScopeOffset(psiScope* newScope, LclVarDsc* lclVarDsc1);
740 /*****************************************************************************
743 * This struct holds the LocalVarInfo in terms of the generated native code
744 * after a call to genSetScopeInfo()
749 struct TrnslLocalVarInfo
754 UNATIVE_OFFSET tlviStartPC;
757 Compiler::siVarLoc tlviVarLoc;
760 // Array of scopes of LocalVars in terms of native code
762 TrnslLocalVarInfo* genTrnslLocalVarInfo;
763 unsigned genTrnslLocalVarCount;
766 void genSetRegToConst(regNumber targetReg, var_types targetType, GenTree* tree);
767 void genCodeForTreeNode(GenTree* treeNode);
768 void genCodeForBinary(GenTree* treeNode);
770 #if defined(_TARGET_X86_)
771 void genCodeForLongUMod(GenTreeOp* node);
772 #endif // _TARGET_X86_
774 void genCodeForDivMod(GenTreeOp* treeNode);
775 void genCodeForMul(GenTreeOp* treeNode);
776 void genCodeForMulHi(GenTreeOp* treeNode);
777 void genLeaInstruction(GenTreeAddrMode* lea);
778 void genSetRegToCond(regNumber dstReg, GenTree* tree);
780 #if defined(_TARGET_ARMARCH_)
781 void genScaledAdd(emitAttr attr, regNumber targetReg, regNumber baseReg, regNumber indexReg, int scale);
782 #endif // _TARGET_ARMARCH_
784 #if defined(_TARGET_ARM_)
785 void genCodeForMulLong(GenTreeMultiRegOp* treeNode);
786 #endif // _TARGET_ARM_
788 #if !defined(_TARGET_64BIT_)
789 void genLongToIntCast(GenTree* treeNode);
792 void genIntToIntCast(GenTree* treeNode);
793 void genFloatToFloatCast(GenTree* treeNode);
794 void genFloatToIntCast(GenTree* treeNode);
795 void genIntToFloatCast(GenTree* treeNode);
796 void genCkfinite(GenTree* treeNode);
797 void genCodeForCompare(GenTreeOp* tree);
798 void genIntrinsic(GenTree* treeNode);
799 void genPutArgStk(GenTreePutArgStk* treeNode);
800 void genPutArgReg(GenTreeOp* tree);
801 #if FEATURE_ARG_SPLIT
802 void genPutArgSplit(GenTreePutArgSplit* treeNode);
803 #endif // FEATURE_ARG_SPLIT
805 #if defined(_TARGET_XARCH_)
806 unsigned getBaseVarForPutArgStk(GenTree* treeNode);
807 #endif // _TARGET_XARCH_
809 unsigned getFirstArgWithStackSlot();
811 void genCompareFloat(GenTree* treeNode);
812 void genCompareInt(GenTree* treeNode);
815 enum SIMDScalarMoveType{
816 SMT_ZeroInitUpper, // zero initlaize target upper bits
817 SMT_ZeroInitUpper_SrcHasUpperZeros, // zero initialize target upper bits; source upper bits are known to be zero
818 SMT_PreserveUpper // preserve target upper bits
821 #ifdef _TARGET_ARM64_
822 insOpts genGetSimdInsOpt(emitAttr size, var_types elementType);
824 instruction getOpForSIMDIntrinsic(SIMDIntrinsicID intrinsicId, var_types baseType, unsigned* ival = nullptr);
825 void genSIMDScalarMove(
826 var_types targetType, var_types type, regNumber target, regNumber src, SIMDScalarMoveType moveType);
827 void genSIMDZero(var_types targetType, var_types baseType, regNumber targetReg);
828 void genSIMDIntrinsicInit(GenTreeSIMD* simdNode);
829 void genSIMDIntrinsicInitN(GenTreeSIMD* simdNode);
830 void genSIMDIntrinsicInitArray(GenTreeSIMD* simdNode);
831 void genSIMDIntrinsicUnOp(GenTreeSIMD* simdNode);
832 void genSIMDIntrinsicBinOp(GenTreeSIMD* simdNode);
833 void genSIMDIntrinsicRelOp(GenTreeSIMD* simdNode);
834 void genSIMDIntrinsicDotProduct(GenTreeSIMD* simdNode);
835 void genSIMDIntrinsicSetItem(GenTreeSIMD* simdNode);
836 void genSIMDIntrinsicGetItem(GenTreeSIMD* simdNode);
837 void genSIMDIntrinsicShuffleSSE2(GenTreeSIMD* simdNode);
838 void genSIMDIntrinsicUpperSave(GenTreeSIMD* simdNode);
839 void genSIMDIntrinsicUpperRestore(GenTreeSIMD* simdNode);
840 void genSIMDLo64BitConvert(SIMDIntrinsicID intrinsicID,
845 regNumber targetReg);
846 void genSIMDIntrinsic32BitConvert(GenTreeSIMD* simdNode);
847 void genSIMDIntrinsic64BitConvert(GenTreeSIMD* simdNode);
848 void genSIMDIntrinsicNarrow(GenTreeSIMD* simdNode);
849 void genSIMDExtractUpperHalf(GenTreeSIMD* simdNode, regNumber srcReg, regNumber tgtReg);
850 void genSIMDIntrinsicWiden(GenTreeSIMD* simdNode);
851 void genSIMDIntrinsic(GenTreeSIMD* simdNode);
852 void genSIMDCheck(GenTree* treeNode);
854 // TYP_SIMD12 (i.e Vector3 of size 12 bytes) is not a hardware supported size and requires
855 // two reads/writes on 64-bit targets. These routines abstract reading/writing of Vector3
856 // values through an indirection. Note that Vector3 locals allocated on stack would have
857 // their size rounded to TARGET_POINTER_SIZE (which is 8 bytes on 64-bit targets) and hence
858 // Vector3 locals could be treated as TYP_SIMD16 while reading/writing.
859 void genStoreIndTypeSIMD12(GenTree* treeNode);
860 void genLoadIndTypeSIMD12(GenTree* treeNode);
861 void genStoreLclTypeSIMD12(GenTree* treeNode);
862 void genLoadLclTypeSIMD12(GenTree* treeNode);
864 void genStoreSIMD12ToStack(regNumber operandReg, regNumber tmpReg);
865 void genPutArgStkSIMD12(GenTree* treeNode);
866 #endif // _TARGET_X86_
867 #endif // FEATURE_SIMD
869 #ifdef FEATURE_HW_INTRINSICS
870 void genHWIntrinsic(GenTreeHWIntrinsic* node);
871 #if defined(_TARGET_XARCH_)
872 void genHWIntrinsic_R_RM(GenTreeHWIntrinsic* node, instruction ins, emitAttr attr);
873 void genHWIntrinsic_R_RM_I(GenTreeHWIntrinsic* node, instruction ins, int8_t ival);
874 void genHWIntrinsic_R_R_RM(GenTreeHWIntrinsic* node, instruction ins, emitAttr attr);
875 void genHWIntrinsic_R_R_RM_I(GenTreeHWIntrinsic* node, instruction ins, int8_t ival);
876 void genHWIntrinsic_R_R_RM_R(GenTreeHWIntrinsic* node, instruction ins);
877 void genHWIntrinsic_R_R_R_RM(
878 instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, regNumber op2Reg, GenTree* op3);
879 void genSSEIntrinsic(GenTreeHWIntrinsic* node);
880 void genSSE2Intrinsic(GenTreeHWIntrinsic* node);
881 void genSSE41Intrinsic(GenTreeHWIntrinsic* node);
882 void genSSE42Intrinsic(GenTreeHWIntrinsic* node);
883 void genAvxOrAvx2Intrinsic(GenTreeHWIntrinsic* node);
884 void genAESIntrinsic(GenTreeHWIntrinsic* node);
885 void genBMI1Intrinsic(GenTreeHWIntrinsic* node);
886 void genBMI2Intrinsic(GenTreeHWIntrinsic* node);
887 void genFMAIntrinsic(GenTreeHWIntrinsic* node);
888 void genLZCNTIntrinsic(GenTreeHWIntrinsic* node);
889 void genPCLMULQDQIntrinsic(GenTreeHWIntrinsic* node);
890 void genPOPCNTIntrinsic(GenTreeHWIntrinsic* node);
891 template <typename HWIntrinsicSwitchCaseBody>
892 void genHWIntrinsicJumpTableFallback(NamedIntrinsic intrinsic,
893 regNumber nonConstImmReg,
896 HWIntrinsicSwitchCaseBody emitSwCase);
897 #endif // defined(_TARGET_XARCH_)
898 #if defined(_TARGET_ARM64_)
899 instruction getOpForHWIntrinsic(GenTreeHWIntrinsic* node, var_types instrType);
900 void genHWIntrinsicUnaryOp(GenTreeHWIntrinsic* node);
901 void genHWIntrinsicCrcOp(GenTreeHWIntrinsic* node);
902 void genHWIntrinsicSimdBinaryOp(GenTreeHWIntrinsic* node);
903 void genHWIntrinsicSimdExtractOp(GenTreeHWIntrinsic* node);
904 void genHWIntrinsicSimdInsertOp(GenTreeHWIntrinsic* node);
905 void genHWIntrinsicSimdSelectOp(GenTreeHWIntrinsic* node);
906 void genHWIntrinsicSimdSetAllOp(GenTreeHWIntrinsic* node);
907 void genHWIntrinsicSimdUnaryOp(GenTreeHWIntrinsic* node);
908 void genHWIntrinsicSimdBinaryRMWOp(GenTreeHWIntrinsic* node);
909 void genHWIntrinsicSimdTernaryRMWOp(GenTreeHWIntrinsic* node);
910 void genHWIntrinsicShaHashOp(GenTreeHWIntrinsic* node);
911 void genHWIntrinsicShaRotateOp(GenTreeHWIntrinsic* node);
912 template <typename HWIntrinsicSwitchCaseBody>
913 void genHWIntrinsicSwitchTable(regNumber swReg, regNumber tmpReg, int swMax, HWIntrinsicSwitchCaseBody emitSwCase);
914 #endif // defined(_TARGET_XARCH_)
915 #endif // FEATURE_HW_INTRINSICS
917 #if !defined(_TARGET_64BIT_)
919 // CodeGen for Long Ints
921 void genStoreLongLclVar(GenTree* treeNode);
923 #endif // !defined(_TARGET_64BIT_)
925 void genProduceReg(GenTree* tree);
926 void genUnspillRegIfNeeded(GenTree* tree);
927 regNumber genConsumeReg(GenTree* tree);
928 void genCopyRegIfNeeded(GenTree* tree, regNumber needReg);
929 void genConsumeRegAndCopy(GenTree* tree, regNumber needReg);
931 void genConsumeIfReg(GenTree* tree)
933 if (!tree->isContained())
935 (void)genConsumeReg(tree);
939 void genRegCopy(GenTree* tree);
940 void genTransferRegGCState(regNumber dst, regNumber src);
941 void genConsumeAddress(GenTree* addr);
942 void genConsumeAddrMode(GenTreeAddrMode* mode);
943 void genSetBlockSize(GenTreeBlk* blkNode, regNumber sizeReg);
944 void genConsumeBlockSrc(GenTreeBlk* blkNode);
945 void genSetBlockSrc(GenTreeBlk* blkNode, regNumber srcReg);
946 void genConsumeBlockOp(GenTreeBlk* blkNode, regNumber dstReg, regNumber srcReg, regNumber sizeReg);
948 #ifdef FEATURE_PUT_STRUCT_ARG_STK
949 void genConsumePutStructArgStk(GenTreePutArgStk* putArgStkNode,
953 #endif // FEATURE_PUT_STRUCT_ARG_STK
954 #if FEATURE_ARG_SPLIT
955 void genConsumeArgSplitStruct(GenTreePutArgSplit* putArgNode);
956 #endif // FEATURE_ARG_SPLIT
958 void genConsumeRegs(GenTree* tree);
959 void genConsumeOperands(GenTreeOp* tree);
960 void genEmitGSCookieCheck(bool pushReg);
961 void genSetRegToIcon(regNumber reg, ssize_t val, var_types type = TYP_INT, insFlags flags = INS_FLAGS_DONT_CARE);
962 void genCodeForShift(GenTree* tree);
964 #if defined(_TARGET_X86_) || defined(_TARGET_ARM_)
965 void genCodeForShiftLong(GenTree* tree);
968 #ifdef _TARGET_XARCH_
969 void genCodeForShiftRMW(GenTreeStoreInd* storeInd);
970 void genCodeForBT(GenTreeOp* bt);
971 #endif // _TARGET_XARCH_
973 void genCodeForCast(GenTreeOp* tree);
974 void genCodeForLclAddr(GenTree* tree);
975 void genCodeForIndexAddr(GenTreeIndexAddr* tree);
976 void genCodeForIndir(GenTreeIndir* tree);
977 void genCodeForNegNot(GenTree* tree);
978 void genCodeForLclVar(GenTreeLclVar* tree);
979 void genCodeForLclFld(GenTreeLclFld* tree);
980 void genCodeForStoreLclFld(GenTreeLclFld* tree);
981 void genCodeForStoreLclVar(GenTreeLclVar* tree);
982 void genCodeForReturnTrap(GenTreeOp* tree);
983 void genCodeForJcc(GenTreeCC* tree);
984 void genCodeForSetcc(GenTreeCC* setcc);
985 void genCodeForStoreInd(GenTreeStoreInd* tree);
986 void genCodeForSwap(GenTreeOp* tree);
987 void genCodeForCpObj(GenTreeObj* cpObjNode);
988 void genCodeForCpBlk(GenTreeBlk* cpBlkNode);
989 void genCodeForCpBlkRepMovs(GenTreeBlk* cpBlkNode);
990 void genCodeForCpBlkUnroll(GenTreeBlk* cpBlkNode);
991 void genCodeForPhysReg(GenTreePhysReg* tree);
992 void genCodeForNullCheck(GenTreeOp* tree);
993 void genCodeForCmpXchg(GenTreeCmpXchg* tree);
995 void genAlignStackBeforeCall(GenTreePutArgStk* putArgStk);
996 void genAlignStackBeforeCall(GenTreeCall* call);
997 void genRemoveAlignmentAfterCall(GenTreeCall* call, unsigned bias = 0);
999 #if defined(UNIX_X86_ABI)
1001 unsigned curNestedAlignment; // Keep track of alignment adjustment required during codegen.
1002 unsigned maxNestedAlignment; // The maximum amount of alignment adjustment required.
1004 void SubtractNestedAlignment(unsigned adjustment)
1006 assert(curNestedAlignment >= adjustment);
1007 unsigned newNestedAlignment = curNestedAlignment - adjustment;
1008 if (curNestedAlignment != newNestedAlignment)
1010 JITDUMP("Adjusting stack nested alignment from %d to %d\n", curNestedAlignment, newNestedAlignment);
1012 curNestedAlignment = newNestedAlignment;
1015 void AddNestedAlignment(unsigned adjustment)
1017 unsigned newNestedAlignment = curNestedAlignment + adjustment;
1018 if (curNestedAlignment != newNestedAlignment)
1020 JITDUMP("Adjusting stack nested alignment from %d to %d\n", curNestedAlignment, newNestedAlignment);
1022 curNestedAlignment = newNestedAlignment;
1024 if (curNestedAlignment > maxNestedAlignment)
1026 JITDUMP("Max stack nested alignment changed from %d to %d\n", maxNestedAlignment, curNestedAlignment);
1027 maxNestedAlignment = curNestedAlignment;
1033 #ifndef _TARGET_X86_
1034 void genPutArgStkFieldList(GenTreePutArgStk* putArgStk, unsigned outArgVarNum);
1035 #endif // !_TARGET_X86_
1037 #ifdef FEATURE_PUT_STRUCT_ARG_STK
1039 bool genAdjustStackForPutArgStk(GenTreePutArgStk* putArgStk);
1040 void genPushReg(var_types type, regNumber srcReg);
1041 void genPutArgStkFieldList(GenTreePutArgStk* putArgStk);
1042 #endif // _TARGET_X86_
1044 void genPutStructArgStk(GenTreePutArgStk* treeNode);
1046 unsigned genMove8IfNeeded(unsigned size, regNumber tmpReg, GenTree* srcAddr, unsigned offset);
1047 unsigned genMove4IfNeeded(unsigned size, regNumber tmpReg, GenTree* srcAddr, unsigned offset);
1048 unsigned genMove2IfNeeded(unsigned size, regNumber tmpReg, GenTree* srcAddr, unsigned offset);
1049 unsigned genMove1IfNeeded(unsigned size, regNumber tmpReg, GenTree* srcAddr, unsigned offset);
1050 void genStructPutArgRepMovs(GenTreePutArgStk* putArgStkNode);
1051 void genStructPutArgUnroll(GenTreePutArgStk* putArgStkNode);
1052 void genStoreRegToStackArg(var_types type, regNumber reg, int offset);
1053 #endif // FEATURE_PUT_STRUCT_ARG_STK
1055 void genCodeForLoadOffset(instruction ins, emitAttr size, regNumber dst, GenTree* base, unsigned offset);
1056 void genCodeForStoreOffset(instruction ins, emitAttr size, regNumber src, GenTree* base, unsigned offset);
1058 #ifdef _TARGET_ARM64_
1059 void genCodeForLoadPairOffset(regNumber dst, regNumber dst2, GenTree* base, unsigned offset);
1060 void genCodeForStorePairOffset(regNumber src, regNumber src2, GenTree* base, unsigned offset);
1061 #endif // _TARGET_ARM64_
1063 void genCodeForStoreBlk(GenTreeBlk* storeBlkNode);
1064 void genCodeForInitBlk(GenTreeBlk* initBlkNode);
1065 void genCodeForInitBlkRepStos(GenTreeBlk* initBlkNode);
1066 void genCodeForInitBlkUnroll(GenTreeBlk* initBlkNode);
1067 void genJumpTable(GenTree* tree);
1068 void genTableBasedSwitch(GenTree* tree);
1069 void genCodeForArrIndex(GenTreeArrIndex* treeNode);
1070 void genCodeForArrOffset(GenTreeArrOffs* treeNode);
1071 instruction genGetInsForOper(genTreeOps oper, var_types type);
1072 bool genEmitOptimizedGCWriteBarrier(GCInfo::WriteBarrierForm writeBarrierForm, GenTree* addr, GenTree* data);
1073 void genCallInstruction(GenTreeCall* call);
1074 void genJmpMethod(GenTree* jmp);
1075 BasicBlock* genCallFinally(BasicBlock* block);
1076 void genCodeForJumpTrue(GenTree* tree);
1077 #ifdef _TARGET_ARM64_
1078 void genCodeForJumpCompare(GenTreeOp* tree);
1079 #endif // _TARGET_ARM64_
1081 #if FEATURE_EH_FUNCLETS
1082 void genEHCatchRet(BasicBlock* block);
1083 #else // !FEATURE_EH_FUNCLETS
1084 void genEHFinallyOrFilterRet(BasicBlock* block);
1085 #endif // !FEATURE_EH_FUNCLETS
1087 void genMultiRegCallStoreToLocal(GenTree* treeNode);
1089 // Deals with codegen for muti-register struct returns.
1090 bool isStructReturn(GenTree* treeNode);
1091 void genStructReturn(GenTree* treeNode);
1093 #if defined(_TARGET_X86_) || defined(_TARGET_ARM_)
1094 void genLongReturn(GenTree* treeNode);
1095 #endif // _TARGET_X86_ || _TARGET_ARM_
1097 #if defined(_TARGET_X86_)
1098 void genFloatReturn(GenTree* treeNode);
1099 #endif // _TARGET_X86_
1101 #if defined(_TARGET_ARM64_)
1102 void genSimpleReturn(GenTree* treeNode);
1103 #endif // _TARGET_ARM64_
1105 void genReturn(GenTree* treeNode);
1107 void genLclHeap(GenTree* tree);
1109 bool genIsRegCandidateLocal(GenTree* tree)
1111 if (!tree->IsLocal())
1115 const LclVarDsc* varDsc = &compiler->lvaTable[tree->gtLclVarCommon.gtLclNum];
1116 return (varDsc->lvIsRegCandidate());
1119 #ifdef FEATURE_PUT_STRUCT_ARG_STK
1122 #else // !_TARGET_X86_
1123 unsigned m_stkArgVarNum;
1124 unsigned m_stkArgOffset;
1125 #endif // !_TARGET_X86_
1126 #endif // !FEATURE_PUT_STRUCT_ARG_STK
1129 GenTree* lastConsumedNode;
1130 void genNumberOperandUse(GenTree* const operand, int& useNum) const;
1131 void genCheckConsumeNode(GenTree* const node);
1133 inline void genCheckConsumeNode(GenTree* treeNode)
1139 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1140 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1144 XX The interface to generate a machine-instruction. XX
1145 XX Currently specific to x86 XX
1146 XX TODO-Cleanup: Consider factoring this out of CodeGen XX
1148 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1149 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1155 void instGen(instruction ins);
1156 #ifdef _TARGET_XARCH_
1157 void instNop(unsigned size);
1160 void inst_JMP(emitJumpKind jmp, BasicBlock* tgtBlock);
1162 void inst_SET(emitJumpKind condition, regNumber reg);
1164 void inst_RV(instruction ins, regNumber reg, var_types type, emitAttr size = EA_UNKNOWN);
1166 void inst_RV_RV(instruction ins,
1169 var_types type = TYP_I_IMPL,
1170 emitAttr size = EA_UNKNOWN,
1171 insFlags flags = INS_FLAGS_DONT_CARE);
1173 void inst_RV_RV_RV(instruction ins,
1178 insFlags flags = INS_FLAGS_DONT_CARE);
1180 void inst_IV(instruction ins, int val);
1181 void inst_IV_handle(instruction ins, int val);
1182 void inst_FS(instruction ins, unsigned stk = 0);
1184 void inst_RV_IV(instruction ins, regNumber reg, ssize_t val, emitAttr size, insFlags flags = INS_FLAGS_DONT_CARE);
1186 void inst_ST_RV(instruction ins, TempDsc* tmp, unsigned ofs, regNumber reg, var_types type);
1187 void inst_ST_IV(instruction ins, TempDsc* tmp, unsigned ofs, int val, var_types type);
1189 void inst_SA_RV(instruction ins, unsigned ofs, regNumber reg, var_types type);
1190 void inst_SA_IV(instruction ins, unsigned ofs, int val, var_types type);
1193 instruction ins, regNumber reg, TempDsc* tmp, unsigned ofs, var_types type, emitAttr size = EA_UNKNOWN);
1194 void inst_FS_ST(instruction ins, emitAttr size, TempDsc* tmp, unsigned ofs);
1196 void instEmit_indCall(GenTreeCall* call,
1198 emitAttr retSize MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize));
1200 void instEmit_RM(instruction ins, GenTree* tree, GenTree* addr, unsigned offs);
1202 void instEmit_RM_RV(instruction ins, emitAttr size, GenTree* tree, regNumber reg, unsigned offs);
1204 void instEmit_RV_RM(instruction ins, emitAttr size, regNumber reg, GenTree* tree, unsigned offs);
1206 void instEmit_RV_RIA(instruction ins, regNumber reg1, regNumber reg2, unsigned offs);
1208 void inst_TT(instruction ins, GenTree* tree, unsigned offs = 0, int shfv = 0, emitAttr size = EA_UNKNOWN);
1210 void inst_TT_RV(instruction ins,
1214 emitAttr size = EA_UNKNOWN,
1215 insFlags flags = INS_FLAGS_DONT_CARE);
1217 void inst_TT_IV(instruction ins,
1221 emitAttr size = EA_UNKNOWN,
1222 insFlags flags = INS_FLAGS_DONT_CARE);
1224 void inst_RV_AT(instruction ins,
1230 insFlags flags = INS_FLAGS_DONT_CARE);
1232 void inst_AT_IV(instruction ins, emitAttr size, GenTree* baseTree, int icon, unsigned offs = 0);
1234 void inst_RV_TT(instruction ins,
1238 emitAttr size = EA_UNKNOWN,
1239 insFlags flags = INS_FLAGS_DONT_CARE);
1241 void inst_RV_TT_IV(instruction ins, regNumber reg, GenTree* tree, int val);
1243 void inst_FS_TT(instruction ins, GenTree* tree);
1245 void inst_RV_SH(instruction ins, emitAttr size, regNumber reg, unsigned val, insFlags flags = INS_FLAGS_DONT_CARE);
1247 void inst_TT_SH(instruction ins, GenTree* tree, unsigned val, unsigned offs = 0);
1249 void inst_RV_CL(instruction ins, regNumber reg, var_types type = TYP_I_IMPL);
1251 void inst_TT_CL(instruction ins, GenTree* tree, unsigned offs = 0);
1253 #if defined(_TARGET_XARCH_)
1254 void inst_RV_RV_IV(instruction ins, emitAttr size, regNumber reg1, regNumber reg2, unsigned ival);
1257 void inst_RV_RR(instruction ins, emitAttr size, regNumber reg1, regNumber reg2);
1259 void inst_RV_ST(instruction ins, emitAttr size, regNumber reg, GenTree* tree);
1261 void inst_mov_RV_ST(regNumber reg, GenTree* tree);
1263 void instGetAddrMode(GenTree* addr, regNumber* baseReg, unsigned* indScale, regNumber* indReg, unsigned* cns);
1265 void inst_set_SV_var(GenTree* tree);
1268 bool arm_Valid_Imm_For_Instr(instruction ins, ssize_t imm, insFlags flags);
1269 bool arm_Valid_Disp_For_LdSt(ssize_t disp, var_types type);
1270 bool arm_Valid_Imm_For_Alu(ssize_t imm);
1271 bool arm_Valid_Imm_For_Mov(ssize_t imm);
1272 bool arm_Valid_Imm_For_Small_Mov(regNumber reg, ssize_t imm, insFlags flags);
1273 bool arm_Valid_Imm_For_Add(ssize_t imm, insFlags flag);
1274 bool arm_Valid_Imm_For_Add_SP(ssize_t imm);
1275 bool arm_Valid_Imm_For_BL(ssize_t addr);
1277 bool ins_Writes_Dest(instruction ins);
1280 bool isMoveIns(instruction ins);
1281 instruction ins_Move_Extend(var_types srcType, bool srcInReg);
1283 instruction ins_Copy(var_types dstType);
1284 instruction ins_CopyIntToFloat(var_types srcType, var_types dstTyp);
1285 instruction ins_CopyFloatToInt(var_types srcType, var_types dstTyp);
1286 static instruction ins_FloatStore(var_types type = TYP_DOUBLE);
1287 static instruction ins_FloatCopy(var_types type = TYP_DOUBLE);
1288 instruction ins_FloatConv(var_types to, var_types from);
1289 instruction ins_FloatCompare(var_types type);
1290 instruction ins_MathOp(genTreeOps oper, var_types type);
1291 instruction ins_FloatSqrt(var_types type);
1293 void instGen_Return(unsigned stkArgSize);
1295 #ifdef _TARGET_ARM64_
1296 void instGen_MemoryBarrier(insBarrier barrierType = INS_BARRIER_ISH);
1298 void instGen_MemoryBarrier();
1301 void instGen_Set_Reg_To_Zero(emitAttr size, regNumber reg, insFlags flags = INS_FLAGS_DONT_CARE);
1303 void instGen_Set_Reg_To_Imm(emitAttr size, regNumber reg, ssize_t imm, insFlags flags = INS_FLAGS_DONT_CARE);
1305 void instGen_Compare_Reg_To_Zero(emitAttr size, regNumber reg);
1307 void instGen_Compare_Reg_To_Reg(emitAttr size, regNumber reg1, regNumber reg2);
1309 void instGen_Compare_Reg_To_Imm(emitAttr size, regNumber reg, ssize_t imm);
1311 void instGen_Load_Reg_From_Lcl(var_types srcType, regNumber dstReg, int varNum, int offs);
1313 void instGen_Store_Reg_Into_Lcl(var_types dstType, regNumber srcReg, int varNum, int offs);
1315 void instGen_Store_Imm_Into_Lcl(
1316 var_types dstType, emitAttr sizeAttr, ssize_t imm, int varNum, int offs, regNumber regToUse = REG_NA);
1319 void __cdecl instDisp(instruction ins, bool noNL, const char* fmt, ...);
1322 #ifdef _TARGET_XARCH_
1323 instruction genMapShiftInsToShiftByConstantIns(instruction ins, int shiftByValue);
1324 #endif // _TARGET_XARCH_
1327 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1328 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1331 XX Inline functions XX
1333 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1334 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1337 #ifdef _TARGET_XARCH_
1338 /*****************************************************************************
1340 * Generate a floating-point instruction that has one operand given by
1341 * a tree (which has been made addressable).
1344 inline void CodeGen::inst_FS_TT(instruction ins, GenTree* tree)
1346 assert(instIsFP(ins));
1348 assert(varTypeIsFloating(tree->gtType));
1350 inst_TT(ins, tree, 0);
1354 /*****************************************************************************
1356 * Generate a "shift reg, cl" instruction.
1359 inline void CodeGen::inst_RV_CL(instruction ins, regNumber reg, var_types type)
1361 inst_RV(ins, reg, type);
1364 #endif // _CODEGEN_H_