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,
52 #if defined(_TARGET_XARCH_)
53 // Bit masks used in negating a float or double number.
54 // This is to avoid creating more than one data constant for these bitmasks when a
55 // method has more than one GT_NEG operation on floating point values.
56 CORINFO_FIELD_HANDLE negBitmaskFlt;
57 CORINFO_FIELD_HANDLE negBitmaskDbl;
59 // Bit masks used in computing Math.Abs() of a float or double number.
60 CORINFO_FIELD_HANDLE absBitmaskFlt;
61 CORINFO_FIELD_HANDLE absBitmaskDbl;
63 // Bit mask used in U8 -> double conversion to adjust the result.
64 CORINFO_FIELD_HANDLE u8ToDblBitmask;
66 // Generates SSE2 code for the given tree as "Operand BitWiseOp BitMask"
67 void genSSE2BitwiseOp(GenTree* treeNode);
69 // Generates SSE41 code for the given tree as a round operation
70 void genSSE41RoundOp(GenTreeOp* treeNode);
71 #endif // defined(_TARGET_XARCH_)
73 void genPrepForCompiler();
75 void genPrepForEHCodegen();
77 inline RegState* regStateForType(var_types t)
79 return varTypeIsFloating(t) ? &floatRegState : &intRegState;
81 inline RegState* regStateForReg(regNumber reg)
83 return genIsValidFloatReg(reg) ? &floatRegState : &intRegState;
86 regNumber genFramePointerReg()
88 if (isFramePointerUsed())
104 static emitJumpKind genJumpKindForOper(genTreeOps cmp, CompareKind compareKind);
106 // For a given compare oper tree, returns the conditions to use with jmp/set in 'jmpKind' array.
107 // The corresponding elements of jmpToTrueLabel indicate whether the target of the jump is to the
108 // 'true' label or a 'false' label.
110 // 'true' label corresponds to jump target of the current basic block i.e. the target to
111 // branch to on compare condition being true. 'false' label corresponds to the target to
112 // branch to on condition being false.
113 static void genJumpKindsForTree(GenTree* cmpTree, emitJumpKind jmpKind[2], bool jmpToTrueLabel[2]);
115 static bool genShouldRoundFP();
117 GenTreeIndir indirForm(var_types type, GenTree* base);
119 GenTreeIntCon intForm(var_types type, ssize_t value);
121 void genRangeCheck(GenTree* node);
123 void genLockedInstructions(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, size_t value, 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[lclMAX_TRACKED];
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 #include "codegenlinear.h"
769 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
770 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
774 XX The interface to generate a machine-instruction. XX
775 XX Currently specific to x86 XX
776 XX TODO-Cleanup: Consider factoring this out of CodeGen XX
778 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
779 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
785 void instGen(instruction ins);
786 #ifdef _TARGET_XARCH_
787 void instNop(unsigned size);
790 void inst_JMP(emitJumpKind jmp, BasicBlock* tgtBlock);
792 void inst_SET(emitJumpKind condition, regNumber reg);
794 void inst_RV(instruction ins, regNumber reg, var_types type, emitAttr size = EA_UNKNOWN);
796 void inst_RV_RV(instruction ins,
799 var_types type = TYP_I_IMPL,
800 emitAttr size = EA_UNKNOWN,
801 insFlags flags = INS_FLAGS_DONT_CARE);
803 void inst_RV_RV_RV(instruction ins,
808 insFlags flags = INS_FLAGS_DONT_CARE);
810 void inst_IV(instruction ins, int val);
811 void inst_IV_handle(instruction ins, int val);
812 void inst_FS(instruction ins, unsigned stk = 0);
814 void inst_RV_IV(instruction ins, regNumber reg, ssize_t val, emitAttr size, insFlags flags = INS_FLAGS_DONT_CARE);
816 void inst_ST_RV(instruction ins, TempDsc* tmp, unsigned ofs, regNumber reg, var_types type);
817 void inst_ST_IV(instruction ins, TempDsc* tmp, unsigned ofs, int val, var_types type);
819 void inst_SA_RV(instruction ins, unsigned ofs, regNumber reg, var_types type);
820 void inst_SA_IV(instruction ins, unsigned ofs, int val, var_types type);
823 instruction ins, regNumber reg, TempDsc* tmp, unsigned ofs, var_types type, emitAttr size = EA_UNKNOWN);
824 void inst_FS_ST(instruction ins, emitAttr size, TempDsc* tmp, unsigned ofs);
826 void instEmit_indCall(GenTreeCall* call,
828 emitAttr retSize MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize));
830 void instEmit_RM(instruction ins, GenTree* tree, GenTree* addr, unsigned offs);
832 void instEmit_RM_RV(instruction ins, emitAttr size, GenTree* tree, regNumber reg, unsigned offs);
834 void instEmit_RV_RM(instruction ins, emitAttr size, regNumber reg, GenTree* tree, unsigned offs);
836 void instEmit_RV_RIA(instruction ins, regNumber reg1, regNumber reg2, unsigned offs);
838 void inst_TT(instruction ins, GenTree* tree, unsigned offs = 0, int shfv = 0, emitAttr size = EA_UNKNOWN);
840 void inst_TT_RV(instruction ins,
844 emitAttr size = EA_UNKNOWN,
845 insFlags flags = INS_FLAGS_DONT_CARE);
847 void inst_TT_IV(instruction ins,
851 emitAttr size = EA_UNKNOWN,
852 insFlags flags = INS_FLAGS_DONT_CARE);
854 void inst_RV_AT(instruction ins,
860 insFlags flags = INS_FLAGS_DONT_CARE);
862 void inst_AT_IV(instruction ins, emitAttr size, GenTree* baseTree, int icon, unsigned offs = 0);
864 void inst_RV_TT(instruction ins,
868 emitAttr size = EA_UNKNOWN,
869 insFlags flags = INS_FLAGS_DONT_CARE);
871 void inst_RV_TT_IV(instruction ins, regNumber reg, GenTree* tree, int val);
873 void inst_FS_TT(instruction ins, GenTree* tree);
875 void inst_RV_SH(instruction ins, emitAttr size, regNumber reg, unsigned val, insFlags flags = INS_FLAGS_DONT_CARE);
877 void inst_TT_SH(instruction ins, GenTree* tree, unsigned val, unsigned offs = 0);
879 void inst_RV_CL(instruction ins, regNumber reg, var_types type = TYP_I_IMPL);
881 void inst_TT_CL(instruction ins, GenTree* tree, unsigned offs = 0);
883 #if defined(_TARGET_XARCH_)
884 void inst_RV_RV_IV(instruction ins, emitAttr size, regNumber reg1, regNumber reg2, unsigned ival);
887 void inst_RV_RR(instruction ins, emitAttr size, regNumber reg1, regNumber reg2);
889 void inst_RV_ST(instruction ins, emitAttr size, regNumber reg, GenTree* tree);
891 void inst_mov_RV_ST(regNumber reg, GenTree* tree);
893 void instGetAddrMode(GenTree* addr, regNumber* baseReg, unsigned* indScale, regNumber* indReg, unsigned* cns);
895 void inst_set_SV_var(GenTree* tree);
898 bool arm_Valid_Imm_For_Instr(instruction ins, ssize_t imm, insFlags flags);
899 bool arm_Valid_Disp_For_LdSt(ssize_t disp, var_types type);
900 bool arm_Valid_Imm_For_Alu(ssize_t imm);
901 bool arm_Valid_Imm_For_Mov(ssize_t imm);
902 bool arm_Valid_Imm_For_Small_Mov(regNumber reg, ssize_t imm, insFlags flags);
903 bool arm_Valid_Imm_For_Add(ssize_t imm, insFlags flag);
904 bool arm_Valid_Imm_For_Add_SP(ssize_t imm);
905 bool arm_Valid_Imm_For_BL(ssize_t addr);
907 bool ins_Writes_Dest(instruction ins);
910 bool isMoveIns(instruction ins);
911 instruction ins_Move_Extend(var_types srcType, bool srcInReg);
913 instruction ins_Copy(var_types dstType);
914 instruction ins_CopyIntToFloat(var_types srcType, var_types dstTyp);
915 instruction ins_CopyFloatToInt(var_types srcType, var_types dstTyp);
916 static instruction ins_FloatStore(var_types type = TYP_DOUBLE);
917 static instruction ins_FloatCopy(var_types type = TYP_DOUBLE);
918 instruction ins_FloatConv(var_types to, var_types from);
919 instruction ins_FloatCompare(var_types type);
920 instruction ins_MathOp(genTreeOps oper, var_types type);
921 instruction ins_FloatSqrt(var_types type);
923 void instGen_Return(unsigned stkArgSize);
925 #ifdef _TARGET_ARM64_
926 void instGen_MemoryBarrier(insBarrier barrierType = INS_BARRIER_ISH);
928 void instGen_MemoryBarrier();
931 void instGen_Set_Reg_To_Zero(emitAttr size, regNumber reg, insFlags flags = INS_FLAGS_DONT_CARE);
933 void instGen_Set_Reg_To_Imm(emitAttr size, regNumber reg, ssize_t imm, insFlags flags = INS_FLAGS_DONT_CARE);
935 void instGen_Compare_Reg_To_Zero(emitAttr size, regNumber reg);
937 void instGen_Compare_Reg_To_Reg(emitAttr size, regNumber reg1, regNumber reg2);
939 void instGen_Compare_Reg_To_Imm(emitAttr size, regNumber reg, ssize_t imm);
941 void instGen_Load_Reg_From_Lcl(var_types srcType, regNumber dstReg, int varNum, int offs);
943 void instGen_Store_Reg_Into_Lcl(var_types dstType, regNumber srcReg, int varNum, int offs);
945 void instGen_Store_Imm_Into_Lcl(
946 var_types dstType, emitAttr sizeAttr, ssize_t imm, int varNum, int offs, regNumber regToUse = REG_NA);
949 void __cdecl instDisp(instruction ins, bool noNL, const char* fmt, ...);
952 #ifdef _TARGET_XARCH_
953 instruction genMapShiftInsToShiftByConstantIns(instruction ins, int shiftByValue);
954 #endif // _TARGET_XARCH_
957 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
958 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
961 XX Inline functions XX
963 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
964 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
967 #ifdef _TARGET_XARCH_
968 /*****************************************************************************
970 * Generate a floating-point instruction that has one operand given by
971 * a tree (which has been made addressable).
974 inline void CodeGen::inst_FS_TT(instruction ins, GenTree* tree)
976 assert(instIsFP(ins));
978 assert(varTypeIsFloating(tree->gtType));
980 inst_TT(ins, tree, 0);
984 /*****************************************************************************
986 * Generate a "shift reg, cl" instruction.
989 inline void CodeGen::inst_RV_CL(instruction ins, regNumber reg, var_types type)
991 inst_RV(ins, reg, type);
994 #endif // _CODEGEN_H_