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);
124 #ifdef _TARGET_XARCH_
125 void genCodeForLockAdd(GenTreeOp* node);
128 //-------------------------------------------------------------------------
129 // Register-related methods
134 // On some targets such as the ARM we may need to have an extra reserved register
135 // that is used when addressing stack based locals and stack based temps.
136 // This method returns the regNumber that should be used when an extra register
137 // is needed to access the stack based locals and stack based temps.
139 regNumber rsGetRsvdReg()
141 // We should have already added this register to the mask
142 // of reserved registers in regSet.rdMaskResvd
143 noway_assert((regSet.rsMaskResvd & RBM_OPT_RSVD) != 0);
147 #endif // REG_OPT_RSVD
149 //-------------------------------------------------------------------------
151 bool genUseBlockInit; // true if we plan to block-initialize the local stack frame
152 unsigned genInitStkLclCnt; // The count of local variables that we need to zero init
154 // Keeps track of how many bytes we've pushed on the processor's stack.
156 unsigned genStackLevel;
158 void SubtractStackLevel(unsigned adjustment)
160 assert(genStackLevel >= adjustment);
161 unsigned newStackLevel = genStackLevel - adjustment;
162 if (genStackLevel != newStackLevel)
164 JITDUMP("Adjusting stack level from %d to %d\n", genStackLevel, newStackLevel);
166 genStackLevel = newStackLevel;
169 void AddStackLevel(unsigned adjustment)
171 unsigned newStackLevel = genStackLevel + adjustment;
172 if (genStackLevel != newStackLevel)
174 JITDUMP("Adjusting stack level from %d to %d\n", genStackLevel, newStackLevel);
176 genStackLevel = newStackLevel;
179 void SetStackLevel(unsigned newStackLevel)
181 if (genStackLevel != newStackLevel)
183 JITDUMP("Setting stack level from %d to %d\n", genStackLevel, newStackLevel);
185 genStackLevel = newStackLevel;
190 bool genNeedPrologStackProbe;
192 void genGenerateStackProbe();
195 //-------------------------------------------------------------------------
199 // Allocates storage for the GC info, writes the GC info into that storage, records the address of the
200 // GC info of the method with the EE, and returns a pointer to the "info" portion (just post-header) of
201 // the GC info. Requires "codeSize" to be the size of the generated code, "prologSize" and "epilogSize"
202 // to be the sizes of the prolog and epilog, respectively. In DEBUG, makes a check involving the
203 // "codePtr", assumed to be a pointer to the start of the generated code.
204 CLANG_FORMAT_COMMENT_ANCHOR;
206 #ifdef JIT32_GCENCODER
207 void* genCreateAndStoreGCInfo(unsigned codeSize, unsigned prologSize, unsigned epilogSize DEBUGARG(void* codePtr));
208 void* genCreateAndStoreGCInfoJIT32(unsigned codeSize,
210 unsigned epilogSize DEBUGARG(void* codePtr));
211 #else // !JIT32_GCENCODER
212 void genCreateAndStoreGCInfo(unsigned codeSize, unsigned prologSize, unsigned epilogSize DEBUGARG(void* codePtr));
213 void genCreateAndStoreGCInfoX64(unsigned codeSize, unsigned prologSize DEBUGARG(void* codePtr));
214 #endif // !JIT32_GCENCODER
216 /**************************************************************************
218 *************************************************************************/
221 // the current (pending) label ref, a label which has been referenced but not yet seen
222 BasicBlock* genPendingCallLabel;
225 // Last instr we have displayed for dspInstrs
226 unsigned genCurDispOffset;
228 static const char* genInsName(instruction ins);
231 //-------------------------------------------------------------------------
233 // JIT-time constants for use in multi-dimensional array code generation.
234 unsigned genOffsetOfMDArrayLowerBound(var_types elemType, unsigned rank, unsigned dimension);
235 unsigned genOffsetOfMDArrayDimensionSize(var_types elemType, unsigned rank, unsigned dimension);
238 static const char* genSizeStr(emitAttr size);
240 void genStressRegs(GenTree* tree);
243 void genCodeForBBlist();
246 void genSpillVar(GenTree* tree);
249 void genEmitHelperCall(unsigned helper, int argSize, emitAttr retSize, regNumber callTarget = REG_NA);
251 void genGCWriteBarrier(GenTree* tgt, GCInfo::WriteBarrierForm wbf);
253 BasicBlock* genCreateTempLabel();
255 void genDefineTempLabel(BasicBlock* label);
257 void genAdjustSP(ssize_t delta);
259 void genAdjustStackLevel(BasicBlock* block);
261 void genExitCode(BasicBlock* block);
263 void genJumpToThrowHlpBlk(emitJumpKind jumpKind, SpecialCodeKind codeKind, GenTree* failBlk = nullptr);
265 void genCheckOverflow(GenTree* tree);
267 //-------------------------------------------------------------------------
269 // Prolog/epilog generation
271 //-------------------------------------------------------------------------
274 // Prolog functions and data (there are a few exceptions for more generally used things)
277 void genEstablishFramePointer(int delta, bool reportUnwindData);
278 void genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbered, RegState* regState);
279 void genEnregisterIncomingStackArgs();
280 void genCheckUseBlockInit();
281 #if defined(UNIX_AMD64_ABI) && defined(FEATURE_SIMD)
282 void genClearStackVec3ArgUpperBits();
283 #endif // UNIX_AMD64_ABI && FEATURE_SIMD
285 #if defined(_TARGET_ARM64_)
286 bool genInstrWithConstant(instruction ins,
292 bool inUnwindRegion = false);
294 void genStackPointerAdjustment(ssize_t spAdjustment, regNumber tmpReg, bool* pTmpRegIsZero);
296 void genPrologSaveRegPair(regNumber reg1,
300 bool lastSavedWasPreviousPair,
302 bool* pTmpRegIsZero);
304 void genPrologSaveReg(regNumber reg1, int spOffset, int spDelta, regNumber tmpReg, bool* pTmpRegIsZero);
306 void genEpilogRestoreRegPair(
307 regNumber reg1, regNumber reg2, int spOffset, int spDelta, regNumber tmpReg, bool* pTmpRegIsZero);
309 void genEpilogRestoreReg(regNumber reg1, int spOffset, int spDelta, regNumber tmpReg, bool* pTmpRegIsZero);
311 void genSaveCalleeSavedRegistersHelp(regMaskTP regsToSaveMask, int lowestCalleeSavedOffset, int spDelta);
313 void genRestoreCalleeSavedRegistersHelp(regMaskTP regsToRestoreMask, int lowestCalleeSavedOffset, int spDelta);
315 void genPushCalleeSavedRegisters(regNumber initReg, bool* pInitRegZeroed);
317 void genPushCalleeSavedRegisters();
320 void genAllocLclFrame(unsigned frameSize, regNumber initReg, bool* pInitRegZeroed, regMaskTP maskArgRegsLiveIn);
322 #if defined(_TARGET_ARM_)
324 void genPushFltRegs(regMaskTP regMask);
325 void genPopFltRegs(regMaskTP regMask);
326 regMaskTP genStackAllocRegisterMask(unsigned frameSize, regMaskTP maskCalleeSavedFloat);
328 regMaskTP genJmpCallArgMask();
330 void genFreeLclFrame(unsigned frameSize,
331 /* IN OUT */ bool* pUnwindStarted,
334 void genMov32RelocatableDisplacement(BasicBlock* block, regNumber reg);
335 void genMov32RelocatableDataLabel(unsigned value, regNumber reg);
336 void genMov32RelocatableImmediate(emitAttr size, size_t value, regNumber reg);
338 bool genUsedPopToReturn; // True if we use the pop into PC to return,
339 // False if we didn't and must branch to LR to return.
341 // A set of information that is used by funclet prolog and epilog generation. It is collected once, before
342 // funclet prologs and epilogs are generated, and used by all funclet prologs and epilogs, which must all be the
344 struct FuncletFrameInfoDsc
346 regMaskTP fiSaveRegs; // Set of registers saved in the funclet prolog (includes LR)
347 unsigned fiFunctionCallerSPtoFPdelta; // Delta between caller SP and the frame pointer
348 unsigned fiSpDelta; // Stack pointer delta
349 unsigned fiPSP_slot_SP_offset; // PSP slot offset from SP
350 int fiPSP_slot_CallerSP_offset; // PSP slot offset from Caller SP
353 FuncletFrameInfoDsc genFuncletInfo;
355 #elif defined(_TARGET_ARM64_)
357 // A set of information that is used by funclet prolog and epilog generation. It is collected once, before
358 // funclet prologs and epilogs are generated, and used by all funclet prologs and epilogs, which must all be the
360 struct FuncletFrameInfoDsc
362 regMaskTP fiSaveRegs; // Set of callee-saved registers saved in the funclet prolog (includes LR)
363 int fiFunction_CallerSP_to_FP_delta; // Delta between caller SP and the frame pointer in the parent function
365 int fiSP_to_FPLR_save_delta; // FP/LR register save offset from SP (positive)
366 int fiSP_to_PSP_slot_delta; // PSP slot offset from SP (positive)
367 int fiSP_to_CalleeSave_delta; // First callee-saved register slot offset from SP (positive)
368 int fiCallerSP_to_PSP_slot_delta; // PSP slot offset from Caller SP (negative)
369 int fiFrameType; // Funclet frame types are numbered. See genFuncletProlog() for details.
370 int fiSpDelta1; // Stack pointer delta 1 (negative)
371 int fiSpDelta2; // Stack pointer delta 2 (negative)
374 FuncletFrameInfoDsc genFuncletInfo;
376 #elif defined(_TARGET_AMD64_)
378 // A set of information that is used by funclet prolog and epilog generation. It is collected once, before
379 // funclet prologs and epilogs are generated, and used by all funclet prologs and epilogs, which must all be the
381 struct FuncletFrameInfoDsc
383 unsigned fiFunction_InitialSP_to_FP_delta; // Delta between Initial-SP and the frame pointer
384 unsigned fiSpDelta; // Stack pointer delta
385 int fiPSP_slot_InitialSP_offset; // PSP slot offset from Initial-SP
388 FuncletFrameInfoDsc genFuncletInfo;
390 #endif // _TARGET_AMD64_
392 #if defined(_TARGET_XARCH_)
394 // Save/Restore callee saved float regs to stack
395 void genPreserveCalleeSavedFltRegs(unsigned lclFrameSize);
396 void genRestoreCalleeSavedFltRegs(unsigned lclFrameSize);
397 // Generate VZeroupper instruction to avoid AVX/SSE transition penalty
398 void genVzeroupperIfNeeded(bool check256bitOnly = true);
400 #endif // _TARGET_XARCH_
402 void genZeroInitFltRegs(const regMaskTP& initFltRegs, const regMaskTP& initDblRegs, const regNumber& initReg);
404 regNumber genGetZeroReg(regNumber initReg, bool* pInitRegZeroed);
406 void genZeroInitFrame(int untrLclHi, int untrLclLo, regNumber initReg, bool* pInitRegZeroed);
408 void genReportGenericContextArg(regNumber initReg, bool* pInitRegZeroed);
410 void genSetGSSecurityCookie(regNumber initReg, bool* pInitRegZeroed);
412 void genFinalizeFrame();
414 #ifdef PROFILING_SUPPORTED
415 void genProfilingEnterCallback(regNumber initReg, bool* pInitRegZeroed);
416 void genProfilingLeaveCallback(unsigned helper = CORINFO_HELP_PROF_FCN_LEAVE);
417 #endif // PROFILING_SUPPORTED
419 void genPrologPadForReJit();
422 void genEmitCall(int callType,
423 CORINFO_METHOD_HANDLE methHnd,
424 INDEBUG_LDISASM_COMMA(CORINFO_SIG_INFO* sigInfo)
426 X86_ARG(ssize_t argSize),
428 MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize),
430 regNumber base = REG_NA,
432 bool isNoGC = false);
436 void genEmitCall(int callType,
437 CORINFO_METHOD_HANDLE methHnd,
438 INDEBUG_LDISASM_COMMA(CORINFO_SIG_INFO* sigInfo)
440 X86_ARG(ssize_t argSize),
442 MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize),
443 IL_OFFSETX ilOffset);
449 CLANG_FORMAT_COMMENT_ANCHOR;
451 #if defined(_TARGET_ARM_)
452 bool genCanUsePopToReturn(regMaskTP maskPopRegsInt, bool jmpEpilog);
455 #if defined(_TARGET_ARM64_)
457 void genPopCalleeSavedRegistersAndFreeLclFrame(bool jmpEpilog);
459 #else // !defined(_TARGET_ARM64_)
461 void genPopCalleeSavedRegisters(bool jmpEpilog = false);
463 #endif // !defined(_TARGET_ARM64_)
466 // Common or driving functions
469 void genReserveProlog(BasicBlock* block); // currently unused
470 void genReserveEpilog(BasicBlock* block);
472 void genFnEpilog(BasicBlock* block);
474 #if FEATURE_EH_FUNCLETS
476 void genReserveFuncletProlog(BasicBlock* block);
477 void genReserveFuncletEpilog(BasicBlock* block);
478 void genFuncletProlog(BasicBlock* block);
479 void genFuncletEpilog();
480 void genCaptureFuncletPrologEpilogInfo();
482 void genSetPSPSym(regNumber initReg, bool* pInitRegZeroed);
484 void genUpdateCurrentFunclet(BasicBlock* block);
485 #if defined(_TARGET_ARM_)
486 void genInsertNopForUnwinder(BasicBlock* block);
489 #else // FEATURE_EH_FUNCLETS
491 // This is a no-op when there are no funclets!
492 void genUpdateCurrentFunclet(BasicBlock* block)
497 #if defined(_TARGET_ARM_)
498 void genInsertNopForUnwinder(BasicBlock* block)
504 #endif // FEATURE_EH_FUNCLETS
506 void genGeneratePrologsAndEpilogs();
508 #if defined(DEBUG) && defined(_TARGET_ARM64_)
509 void genArm64EmitterUnitTests();
512 #if defined(DEBUG) && defined(LATE_DISASM) && defined(_TARGET_AMD64_)
513 void genAmd64EmitterUnitTests();
516 //-------------------------------------------------------------------------
518 // End prolog/epilog generation
520 //-------------------------------------------------------------------------
522 void genSinglePush();
524 regMaskTP genPushRegs(regMaskTP regs, regMaskTP* byrefRegs, regMaskTP* noRefRegs);
525 void genPopRegs(regMaskTP regs, regMaskTP byrefRegs, regMaskTP noRefRegs);
528 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
529 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
531 XX Debugging Support XX
533 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
534 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
538 void genIPmappingDisp(unsigned mappingNum, Compiler::IPmappingDsc* ipMapping);
539 void genIPmappingListDisp();
542 void genIPmappingAdd(IL_OFFSETX offset, bool isLabel);
543 void genIPmappingAddToFront(IL_OFFSETX offset);
544 void genIPmappingGen();
546 void genEnsureCodeEmitted(IL_OFFSETX offsx);
548 //-------------------------------------------------------------------------
549 // scope info for the variables
551 void genSetScopeInfo(unsigned which,
552 UNATIVE_OFFSET startOffs,
553 UNATIVE_OFFSET length,
557 Compiler::siVarLoc& loc);
559 void genSetScopeInfo();
561 void genRemoveBBsection(BasicBlock* head, BasicBlock* tail);
565 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
566 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
570 XX Keeps track of the scopes during code-generation. XX
571 XX This is used to translate the local-variable debugging information XX
572 XX from IL offsets to native code offsets. XX
574 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
575 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
578 /*****************************************************************************/
579 /*****************************************************************************
582 * This class is called during code gen at block-boundaries, and when the
583 * set of live variables changes. It keeps track of the scope of the variables
584 * in terms of the native code PC.
590 void siBeginBlock(BasicBlock* block);
592 void siEndBlock(BasicBlock* block);
594 virtual void siUpdate();
596 void siCheckVarScope(unsigned varNum, IL_OFFSET offs);
598 void siCloseAllOpenScopes();
601 void siDispOpenScopes();
604 /**************************************************************************
606 *************************************************************************/
611 emitLocation scStartLoc; // emitter location of start of scope
612 emitLocation scEndLoc; // emitter location of end of scope
614 unsigned scVarNum; // index into lvaTable
615 unsigned scLVnum; // 'which' in eeGetLVinfo()
617 unsigned scStackLevel; // Only for stk-vars
618 bool scAvailable : 1; // It has a home / Home recycled - TODO-Cleanup: it appears this is unused (always true)
624 siScope siOpenScopeList, siScopeList, *siOpenScopeLast, *siScopeLast;
628 VARSET_TP siLastLife; // Life at last call to siUpdate()
630 // Tracks the last entry for each tracked register variable
632 siScope* siLatestTrackedScopes[lclMAX_TRACKED];
634 IL_OFFSET siLastEndOffs; // IL offset of the (exclusive) end of the last block processed
636 #if FEATURE_EH_FUNCLETS
637 bool siInFuncletRegion; // Have we seen the start of the funclet region?
638 #endif // FEATURE_EH_FUNCLETS
642 siScope* siNewScope(unsigned LVnum, unsigned varNum);
644 void siRemoveFromOpenScopeList(siScope* scope);
646 void siEndTrackedScope(unsigned varIndex);
648 void siEndScope(unsigned varNum);
650 void siEndScope(siScope* scope);
653 bool siVerifyLocalVarTab();
659 const char* siRegVarName(size_t offs, size_t size, unsigned reg);
662 const char* siStackVarName(size_t offs, size_t size, unsigned reg, unsigned stkOffs);
663 #endif // LATE_DISASM
667 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
668 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
670 XX PrologScopeInfo XX
672 XX We need special handling in the prolog block, as the parameter variables XX
673 XX may not be in the same position described by genLclVarTable - they all XX
674 XX start out on the stack XX
676 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
677 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
683 void psiAdjustStackLevel(unsigned size);
685 void psiMoveESPtoEBP();
687 void psiMoveToReg(unsigned varNum, regNumber reg = REG_NA, regNumber otherReg = REG_NA);
689 void psiMoveToStack(unsigned varNum);
693 /**************************************************************************
695 *************************************************************************/
700 emitLocation scStartLoc; // emitter location of start of scope
701 emitLocation scEndLoc; // emitter location of end of scope
703 unsigned scSlotNum; // index into lclVarTab
704 unsigned scLVnum; // 'which' in eeGetLVinfo()
711 regNumberSmall scRegNum;
714 // - "other half" of long var on architectures with 32 bit size registers - x86.
715 // - for System V structs it stores the second register
716 // used to pass a register passed struct.
717 regNumberSmall scOtherReg;
722 regNumberSmall scBaseReg;
723 NATIVE_OFFSET scOffset;
731 psiScope psiOpenScopeList, psiScopeList, *psiOpenScopeLast, *psiScopeLast;
733 unsigned psiScopeCnt;
735 // Implementation Functions
737 psiScope* psiNewPrologScope(unsigned LVnum, unsigned slotNum);
739 void psiEndPrologScope(psiScope* scope);
741 void psSetScopeOffset(psiScope* newScope, LclVarDsc* lclVarDsc1);
743 /*****************************************************************************
746 * This struct holds the LocalVarInfo in terms of the generated native code
747 * after a call to genSetScopeInfo()
752 struct TrnslLocalVarInfo
757 UNATIVE_OFFSET tlviStartPC;
760 Compiler::siVarLoc tlviVarLoc;
763 // Array of scopes of LocalVars in terms of native code
765 TrnslLocalVarInfo* genTrnslLocalVarInfo;
766 unsigned genTrnslLocalVarCount;
769 #include "codegenlinear.h"
772 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
773 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
777 XX The interface to generate a machine-instruction. XX
778 XX Currently specific to x86 XX
779 XX TODO-Cleanup: Consider factoring this out of CodeGen XX
781 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
782 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
788 void instGen(instruction ins);
789 #ifdef _TARGET_XARCH_
790 void instNop(unsigned size);
793 void inst_JMP(emitJumpKind jmp, BasicBlock* tgtBlock);
795 void inst_SET(emitJumpKind condition, regNumber reg);
797 void inst_RV(instruction ins, regNumber reg, var_types type, emitAttr size = EA_UNKNOWN);
799 void inst_RV_RV(instruction ins,
802 var_types type = TYP_I_IMPL,
803 emitAttr size = EA_UNKNOWN,
804 insFlags flags = INS_FLAGS_DONT_CARE);
806 void inst_RV_RV_RV(instruction ins,
811 insFlags flags = INS_FLAGS_DONT_CARE);
813 void inst_IV(instruction ins, int val);
814 void inst_IV_handle(instruction ins, int val);
815 void inst_FS(instruction ins, unsigned stk = 0);
817 void inst_RV_IV(instruction ins, regNumber reg, ssize_t val, emitAttr size, insFlags flags = INS_FLAGS_DONT_CARE);
819 void inst_ST_RV(instruction ins, TempDsc* tmp, unsigned ofs, regNumber reg, var_types type);
820 void inst_ST_IV(instruction ins, TempDsc* tmp, unsigned ofs, int val, var_types type);
822 void inst_SA_RV(instruction ins, unsigned ofs, regNumber reg, var_types type);
823 void inst_SA_IV(instruction ins, unsigned ofs, int val, var_types type);
826 instruction ins, regNumber reg, TempDsc* tmp, unsigned ofs, var_types type, emitAttr size = EA_UNKNOWN);
827 void inst_FS_ST(instruction ins, emitAttr size, TempDsc* tmp, unsigned ofs);
829 void instEmit_indCall(GenTreeCall* call,
831 emitAttr retSize MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize));
833 void instEmit_RM(instruction ins, GenTree* tree, GenTree* addr, unsigned offs);
835 void instEmit_RM_RV(instruction ins, emitAttr size, GenTree* tree, regNumber reg, unsigned offs);
837 void instEmit_RV_RM(instruction ins, emitAttr size, regNumber reg, GenTree* tree, unsigned offs);
839 void instEmit_RV_RIA(instruction ins, regNumber reg1, regNumber reg2, unsigned offs);
841 void inst_TT(instruction ins, GenTree* tree, unsigned offs = 0, int shfv = 0, emitAttr size = EA_UNKNOWN);
843 void inst_TT_RV(instruction ins,
847 emitAttr size = EA_UNKNOWN,
848 insFlags flags = INS_FLAGS_DONT_CARE);
850 void inst_TT_IV(instruction ins,
854 emitAttr size = EA_UNKNOWN,
855 insFlags flags = INS_FLAGS_DONT_CARE);
857 void inst_RV_AT(instruction ins,
863 insFlags flags = INS_FLAGS_DONT_CARE);
865 void inst_AT_IV(instruction ins, emitAttr size, GenTree* baseTree, int icon, unsigned offs = 0);
867 void inst_RV_TT(instruction ins,
871 emitAttr size = EA_UNKNOWN,
872 insFlags flags = INS_FLAGS_DONT_CARE);
874 void inst_RV_TT_IV(instruction ins, regNumber reg, GenTree* tree, int val);
876 void inst_FS_TT(instruction ins, GenTree* tree);
878 void inst_RV_SH(instruction ins, emitAttr size, regNumber reg, unsigned val, insFlags flags = INS_FLAGS_DONT_CARE);
880 void inst_TT_SH(instruction ins, GenTree* tree, unsigned val, unsigned offs = 0);
882 void inst_RV_CL(instruction ins, regNumber reg, var_types type = TYP_I_IMPL);
884 void inst_TT_CL(instruction ins, GenTree* tree, unsigned offs = 0);
886 #if defined(_TARGET_XARCH_)
887 void inst_RV_RV_IV(instruction ins, emitAttr size, regNumber reg1, regNumber reg2, unsigned ival);
890 void inst_RV_RR(instruction ins, emitAttr size, regNumber reg1, regNumber reg2);
892 void inst_RV_ST(instruction ins, emitAttr size, regNumber reg, GenTree* tree);
894 void inst_mov_RV_ST(regNumber reg, GenTree* tree);
896 void instGetAddrMode(GenTree* addr, regNumber* baseReg, unsigned* indScale, regNumber* indReg, unsigned* cns);
898 void inst_set_SV_var(GenTree* tree);
901 bool arm_Valid_Imm_For_Instr(instruction ins, ssize_t imm, insFlags flags);
902 bool arm_Valid_Disp_For_LdSt(ssize_t disp, var_types type);
903 bool arm_Valid_Imm_For_Alu(ssize_t imm);
904 bool arm_Valid_Imm_For_Mov(ssize_t imm);
905 bool arm_Valid_Imm_For_Small_Mov(regNumber reg, ssize_t imm, insFlags flags);
906 bool arm_Valid_Imm_For_Add(ssize_t imm, insFlags flag);
907 bool arm_Valid_Imm_For_Add_SP(ssize_t imm);
908 bool arm_Valid_Imm_For_BL(ssize_t addr);
910 bool ins_Writes_Dest(instruction ins);
913 bool isMoveIns(instruction ins);
914 instruction ins_Move_Extend(var_types srcType, bool srcInReg);
916 instruction ins_Copy(var_types dstType);
917 instruction ins_CopyIntToFloat(var_types srcType, var_types dstTyp);
918 instruction ins_CopyFloatToInt(var_types srcType, var_types dstTyp);
919 static instruction ins_FloatStore(var_types type = TYP_DOUBLE);
920 static instruction ins_FloatCopy(var_types type = TYP_DOUBLE);
921 instruction ins_FloatConv(var_types to, var_types from);
922 instruction ins_FloatCompare(var_types type);
923 instruction ins_MathOp(genTreeOps oper, var_types type);
924 instruction ins_FloatSqrt(var_types type);
926 void instGen_Return(unsigned stkArgSize);
928 #ifdef _TARGET_ARM64_
929 void instGen_MemoryBarrier(insBarrier barrierType = INS_BARRIER_ISH);
931 void instGen_MemoryBarrier();
934 void instGen_Set_Reg_To_Zero(emitAttr size, regNumber reg, insFlags flags = INS_FLAGS_DONT_CARE);
936 void instGen_Set_Reg_To_Imm(emitAttr size, regNumber reg, ssize_t imm, insFlags flags = INS_FLAGS_DONT_CARE);
938 void instGen_Compare_Reg_To_Zero(emitAttr size, regNumber reg);
940 void instGen_Compare_Reg_To_Reg(emitAttr size, regNumber reg1, regNumber reg2);
942 void instGen_Compare_Reg_To_Imm(emitAttr size, regNumber reg, ssize_t imm);
944 void instGen_Load_Reg_From_Lcl(var_types srcType, regNumber dstReg, int varNum, int offs);
946 void instGen_Store_Reg_Into_Lcl(var_types dstType, regNumber srcReg, int varNum, int offs);
948 void instGen_Store_Imm_Into_Lcl(
949 var_types dstType, emitAttr sizeAttr, ssize_t imm, int varNum, int offs, regNumber regToUse = REG_NA);
952 void __cdecl instDisp(instruction ins, bool noNL, const char* fmt, ...);
955 #ifdef _TARGET_XARCH_
956 instruction genMapShiftInsToShiftByConstantIns(instruction ins, int shiftByValue);
957 #endif // _TARGET_XARCH_
960 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
961 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
964 XX Inline functions XX
966 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
967 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
970 #ifdef _TARGET_XARCH_
971 /*****************************************************************************
973 * Generate a floating-point instruction that has one operand given by
974 * a tree (which has been made addressable).
977 inline void CodeGen::inst_FS_TT(instruction ins, GenTree* tree)
979 assert(instIsFP(ins));
981 assert(varTypeIsFloating(tree->gtType));
983 inst_TT(ins, tree, 0);
987 /*****************************************************************************
989 * Generate a "shift reg, cl" instruction.
992 inline void CodeGen::inst_RV_CL(instruction ins, regNumber reg, var_types type)
994 inst_RV(ins, reg, type);
997 #endif // _CODEGEN_H_