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(GenTreePtr addr,
52 #if defined(_TARGET_XARCH_) && !FEATURE_STACK_FP_X87
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(GenTreePtr treeNode);
68 #endif // defined(_TARGET_XARCH_) && !FEATURE_STACK_FP_X87
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(GenTreePtr 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);
122 //-------------------------------------------------------------------------
123 // Register-related methods
128 // On some targets such as the ARM we may need to have an extra reserved register
129 // that is used when addressing stack based locals and stack based temps.
130 // This method returns the regNumber that should be used when an extra register
131 // is needed to access the stack based locals and stack based temps.
133 regNumber rsGetRsvdReg()
135 // We should have already added this register to the mask
136 // of reserved registers in regSet.rdMaskResvd
137 noway_assert((regSet.rsMaskResvd & RBM_OPT_RSVD) != 0);
141 #endif // REG_OPT_RSVD
143 #ifdef LEGACY_BACKEND
144 regNumber findStkLclInReg(unsigned lclNum)
147 genInterruptibleUsed = true;
149 return regTracker.rsLclIsInReg(lclNum);
153 //-------------------------------------------------------------------------
155 bool genUseBlockInit; // true if we plan to block-initialize the local stack frame
156 unsigned genInitStkLclCnt; // The count of local variables that we need to zero init
158 // Keeps track of how many bytes we've pushed on the processor's stack.
160 unsigned genStackLevel;
162 void SubtractStackLevel(unsigned adjustment)
164 assert(genStackLevel >= adjustment);
165 unsigned newStackLevel = genStackLevel - adjustment;
166 if (genStackLevel != newStackLevel)
168 JITDUMP("Adjusting stack level from %d to %d\n", genStackLevel, newStackLevel);
170 genStackLevel = newStackLevel;
173 void AddStackLevel(unsigned adjustment)
175 unsigned newStackLevel = genStackLevel + adjustment;
176 if (genStackLevel != newStackLevel)
178 JITDUMP("Adjusting stack level from %d to %d\n", genStackLevel, newStackLevel);
180 genStackLevel = newStackLevel;
183 void SetStackLevel(unsigned newStackLevel)
185 if (genStackLevel != newStackLevel)
187 JITDUMP("Setting stack level from %d to %d\n", genStackLevel, newStackLevel);
189 genStackLevel = newStackLevel;
194 bool genNeedPrologStackProbe;
196 void genGenerateStackProbe();
199 #ifdef LEGACY_BACKEND
200 regMaskTP genNewLiveRegMask(GenTreePtr first, GenTreePtr second);
202 // During codegen, determine the LiveSet after tree.
203 // Preconditions: must be called during codegen, when compCurLife and
204 // compCurLifeTree are being maintained, and tree must occur in the current
206 VARSET_VALRET_TP genUpdateLiveSetForward(GenTreePtr tree);
209 //-------------------------------------------------------------------------
213 // Allocates storage for the GC info, writes the GC info into that storage, records the address of the
214 // GC info of the method with the EE, and returns a pointer to the "info" portion (just post-header) of
215 // the GC info. Requires "codeSize" to be the size of the generated code, "prologSize" and "epilogSize"
216 // to be the sizes of the prolog and epilog, respectively. In DEBUG, makes a check involving the
217 // "codePtr", assumed to be a pointer to the start of the generated code.
218 CLANG_FORMAT_COMMENT_ANCHOR;
220 #ifdef JIT32_GCENCODER
221 void* genCreateAndStoreGCInfo(unsigned codeSize, unsigned prologSize, unsigned epilogSize DEBUGARG(void* codePtr));
222 void* genCreateAndStoreGCInfoJIT32(unsigned codeSize,
224 unsigned epilogSize DEBUGARG(void* codePtr));
225 #else // !JIT32_GCENCODER
226 void genCreateAndStoreGCInfo(unsigned codeSize, unsigned prologSize, unsigned epilogSize DEBUGARG(void* codePtr));
227 void genCreateAndStoreGCInfoX64(unsigned codeSize, unsigned prologSize DEBUGARG(void* codePtr));
228 #endif // !JIT32_GCENCODER
230 /**************************************************************************
232 *************************************************************************/
235 // the current (pending) label ref, a label which has been referenced but not yet seen
236 BasicBlock* genPendingCallLabel;
239 // Last instr we have displayed for dspInstrs
240 unsigned genCurDispOffset;
242 static const char* genInsName(instruction ins);
245 //-------------------------------------------------------------------------
247 // JIT-time constants for use in multi-dimensional array code generation.
248 unsigned genOffsetOfMDArrayLowerBound(var_types elemType, unsigned rank, unsigned dimension);
249 unsigned genOffsetOfMDArrayDimensionSize(var_types elemType, unsigned rank, unsigned dimension);
252 static const char* genSizeStr(emitAttr size);
254 void genStressRegs(GenTreePtr tree);
257 void genCodeForBBlist();
260 #ifndef LEGACY_BACKEND
261 // genSpillVar is called by compUpdateLifeVar in the !LEGACY_BACKEND case
262 void genSpillVar(GenTreePtr tree);
263 #endif // !LEGACY_BACKEND
266 #ifndef LEGACY_BACKEND
267 void genEmitHelperCall(unsigned helper, int argSize, emitAttr retSize, regNumber callTarget = REG_NA);
269 void genEmitHelperCall(unsigned helper, int argSize, emitAttr retSize);
272 void genGCWriteBarrier(GenTreePtr tree, GCInfo::WriteBarrierForm wbf);
274 BasicBlock* genCreateTempLabel();
276 void genDefineTempLabel(BasicBlock* label);
278 void genAdjustSP(ssize_t delta);
280 void genAdjustStackLevel(BasicBlock* block);
282 void genExitCode(BasicBlock* block);
284 #ifdef LEGACY_BACKEND
285 GenTreePtr genMakeConst(const void* cnsAddr, var_types cnsType, GenTreePtr cnsTree, bool dblAlign);
288 void genJumpToThrowHlpBlk(emitJumpKind jumpKind, SpecialCodeKind codeKind, GenTreePtr failBlk = nullptr);
290 void genCheckOverflow(GenTreePtr tree);
292 //-------------------------------------------------------------------------
294 // Prolog/epilog generation
296 //-------------------------------------------------------------------------
299 // Prolog functions and data (there are a few exceptions for more generally used things)
302 void genEstablishFramePointer(int delta, bool reportUnwindData);
303 void genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbered, RegState* regState);
304 void genEnregisterIncomingStackArgs();
305 void genCheckUseBlockInit();
306 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING) && defined(FEATURE_SIMD)
307 void genClearStackVec3ArgUpperBits();
308 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING && FEATURE_SIMD
310 #if defined(_TARGET_ARM64_)
311 bool genInstrWithConstant(instruction ins,
317 bool inUnwindRegion = false);
319 void genStackPointerAdjustment(ssize_t spAdjustment, regNumber tmpReg, bool* pTmpRegIsZero);
321 void genPrologSaveRegPair(regNumber reg1,
325 bool lastSavedWasPreviousPair,
327 bool* pTmpRegIsZero);
329 void genPrologSaveReg(regNumber reg1, int spOffset, int spDelta, regNumber tmpReg, bool* pTmpRegIsZero);
331 void genEpilogRestoreRegPair(
332 regNumber reg1, regNumber reg2, int spOffset, int spDelta, regNumber tmpReg, bool* pTmpRegIsZero);
334 void genEpilogRestoreReg(regNumber reg1, int spOffset, int spDelta, regNumber tmpReg, bool* pTmpRegIsZero);
336 void genSaveCalleeSavedRegistersHelp(regMaskTP regsToSaveMask, int lowestCalleeSavedOffset, int spDelta);
338 void genRestoreCalleeSavedRegistersHelp(regMaskTP regsToRestoreMask, int lowestCalleeSavedOffset, int spDelta);
340 void genPushCalleeSavedRegisters(regNumber initReg, bool* pInitRegZeroed);
342 void genPushCalleeSavedRegisters();
345 void genAllocLclFrame(unsigned frameSize, regNumber initReg, bool* pInitRegZeroed, regMaskTP maskArgRegsLiveIn);
347 #if defined(_TARGET_ARM_)
349 void genPushFltRegs(regMaskTP regMask);
350 void genPopFltRegs(regMaskTP regMask);
351 regMaskTP genStackAllocRegisterMask(unsigned frameSize, regMaskTP maskCalleeSavedFloat);
353 regMaskTP genJmpCallArgMask();
355 void genFreeLclFrame(unsigned frameSize,
356 /* IN OUT */ bool* pUnwindStarted,
359 void genMov32RelocatableDisplacement(BasicBlock* block, regNumber reg);
360 void genMov32RelocatableDataLabel(unsigned value, regNumber reg);
361 void genMov32RelocatableImmediate(emitAttr size, unsigned value, regNumber reg);
363 bool genUsedPopToReturn; // True if we use the pop into PC to return,
364 // False if we didn't and must branch to LR to return.
366 // A set of information that is used by funclet prolog and epilog generation. It is collected once, before
367 // funclet prologs and epilogs are generated, and used by all funclet prologs and epilogs, which must all be the
369 struct FuncletFrameInfoDsc
371 regMaskTP fiSaveRegs; // Set of registers saved in the funclet prolog (includes LR)
372 unsigned fiFunctionCallerSPtoFPdelta; // Delta between caller SP and the frame pointer
373 unsigned fiSpDelta; // Stack pointer delta
374 unsigned fiPSP_slot_SP_offset; // PSP slot offset from SP
375 int fiPSP_slot_CallerSP_offset; // PSP slot offset from Caller SP
378 FuncletFrameInfoDsc genFuncletInfo;
380 #elif defined(_TARGET_ARM64_)
382 // A set of information that is used by funclet prolog and epilog generation. It is collected once, before
383 // funclet prologs and epilogs are generated, and used by all funclet prologs and epilogs, which must all be the
385 struct FuncletFrameInfoDsc
387 regMaskTP fiSaveRegs; // Set of callee-saved registers saved in the funclet prolog (includes LR)
388 int fiFunction_CallerSP_to_FP_delta; // Delta between caller SP and the frame pointer in the parent function
390 int fiSP_to_FPLR_save_delta; // FP/LR register save offset from SP (positive)
391 int fiSP_to_PSP_slot_delta; // PSP slot offset from SP (positive)
392 int fiSP_to_CalleeSave_delta; // First callee-saved register slot offset from SP (positive)
393 int fiCallerSP_to_PSP_slot_delta; // PSP slot offset from Caller SP (negative)
394 int fiFrameType; // Funclet frame types are numbered. See genFuncletProlog() for details.
395 int fiSpDelta1; // Stack pointer delta 1 (negative)
396 int fiSpDelta2; // Stack pointer delta 2 (negative)
399 FuncletFrameInfoDsc genFuncletInfo;
401 #elif defined(_TARGET_AMD64_)
403 // A set of information that is used by funclet prolog and epilog generation. It is collected once, before
404 // funclet prologs and epilogs are generated, and used by all funclet prologs and epilogs, which must all be the
406 struct FuncletFrameInfoDsc
408 unsigned fiFunction_InitialSP_to_FP_delta; // Delta between Initial-SP and the frame pointer
409 unsigned fiSpDelta; // Stack pointer delta
410 int fiPSP_slot_InitialSP_offset; // PSP slot offset from Initial-SP
413 FuncletFrameInfoDsc genFuncletInfo;
415 #endif // _TARGET_AMD64_
417 #if defined(_TARGET_XARCH_) && !FEATURE_STACK_FP_X87
419 // Save/Restore callee saved float regs to stack
420 void genPreserveCalleeSavedFltRegs(unsigned lclFrameSize);
421 void genRestoreCalleeSavedFltRegs(unsigned lclFrameSize);
422 // Generate VZeroupper instruction to avoid AVX/SSE transition penalty
423 void genVzeroupperIfNeeded(bool check256bitOnly = true);
425 #endif // _TARGET_XARCH_ && FEATURE_STACK_FP_X87
427 #if !FEATURE_STACK_FP_X87
428 void genZeroInitFltRegs(const regMaskTP& initFltRegs, const regMaskTP& initDblRegs, const regNumber& initReg);
429 #endif // !FEATURE_STACK_FP_X87
431 regNumber genGetZeroReg(regNumber initReg, bool* pInitRegZeroed);
433 void genZeroInitFrame(int untrLclHi, int untrLclLo, regNumber initReg, bool* pInitRegZeroed);
435 void genReportGenericContextArg(regNumber initReg, bool* pInitRegZeroed);
437 void genSetGSSecurityCookie(regNumber initReg, bool* pInitRegZeroed);
439 void genFinalizeFrame();
441 #ifdef PROFILING_SUPPORTED
442 void genProfilingEnterCallback(regNumber initReg, bool* pInitRegZeroed);
443 void genProfilingLeaveCallback(unsigned helper = CORINFO_HELP_PROF_FCN_LEAVE);
444 #endif // PROFILING_SUPPORTED
446 void genPrologPadForReJit();
449 void genEmitCall(int callType,
450 CORINFO_METHOD_HANDLE methHnd,
451 INDEBUG_LDISASM_COMMA(CORINFO_SIG_INFO* sigInfo)
453 X86_ARG(ssize_t argSize),
455 MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize),
457 regNumber base = REG_NA,
459 bool isNoGC = false);
463 void genEmitCall(int callType,
464 CORINFO_METHOD_HANDLE methHnd,
465 INDEBUG_LDISASM_COMMA(CORINFO_SIG_INFO* sigInfo)
467 X86_ARG(ssize_t argSize),
469 MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize),
470 IL_OFFSETX ilOffset);
476 CLANG_FORMAT_COMMENT_ANCHOR;
478 #if defined(_TARGET_ARM_)
479 bool genCanUsePopToReturn(regMaskTP maskPopRegsInt, bool jmpEpilog);
482 #if defined(_TARGET_ARM64_)
484 void genPopCalleeSavedRegistersAndFreeLclFrame(bool jmpEpilog);
486 #else // !defined(_TARGET_ARM64_)
488 void genPopCalleeSavedRegisters(bool jmpEpilog = false);
490 #endif // !defined(_TARGET_ARM64_)
493 // Common or driving functions
496 void genReserveProlog(BasicBlock* block); // currently unused
497 void genReserveEpilog(BasicBlock* block);
499 void genFnEpilog(BasicBlock* block);
501 #if FEATURE_EH_FUNCLETS
503 void genReserveFuncletProlog(BasicBlock* block);
504 void genReserveFuncletEpilog(BasicBlock* block);
505 void genFuncletProlog(BasicBlock* block);
506 void genFuncletEpilog();
507 void genCaptureFuncletPrologEpilogInfo();
509 void genSetPSPSym(regNumber initReg, bool* pInitRegZeroed);
511 void genUpdateCurrentFunclet(BasicBlock* block);
512 #if defined(_TARGET_ARM_)
513 void genInsertNopForUnwinder(BasicBlock* block);
516 #else // FEATURE_EH_FUNCLETS
518 // This is a no-op when there are no funclets!
519 void genUpdateCurrentFunclet(BasicBlock* block)
524 #if defined(_TARGET_ARM_)
525 void genInsertNopForUnwinder(BasicBlock* block)
531 #endif // FEATURE_EH_FUNCLETS
533 void genGeneratePrologsAndEpilogs();
535 #if defined(DEBUG) && defined(_TARGET_ARM64_)
536 void genArm64EmitterUnitTests();
539 #if defined(DEBUG) && defined(LATE_DISASM) && defined(_TARGET_AMD64_)
540 void genAmd64EmitterUnitTests();
543 //-------------------------------------------------------------------------
545 // End prolog/epilog generation
547 //-------------------------------------------------------------------------
549 void genSinglePush();
551 regMaskTP genPushRegs(regMaskTP regs, regMaskTP* byrefRegs, regMaskTP* noRefRegs);
552 void genPopRegs(regMaskTP regs, regMaskTP byrefRegs, regMaskTP noRefRegs);
555 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
556 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
558 XX Debugging Support XX
560 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
561 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
565 void genIPmappingDisp(unsigned mappingNum, Compiler::IPmappingDsc* ipMapping);
566 void genIPmappingListDisp();
569 void genIPmappingAdd(IL_OFFSETX offset, bool isLabel);
570 void genIPmappingAddToFront(IL_OFFSETX offset);
571 void genIPmappingGen();
573 void genEnsureCodeEmitted(IL_OFFSETX offsx);
575 //-------------------------------------------------------------------------
576 // scope info for the variables
578 void genSetScopeInfo(unsigned which,
579 UNATIVE_OFFSET startOffs,
580 UNATIVE_OFFSET length,
584 Compiler::siVarLoc& loc);
586 void genSetScopeInfo();
588 void genRemoveBBsection(BasicBlock* head, BasicBlock* tail);
592 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
593 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
597 XX Keeps track of the scopes during code-generation. XX
598 XX This is used to translate the local-variable debugging information XX
599 XX from IL offsets to native code offsets. XX
601 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
602 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
605 /*****************************************************************************/
606 /*****************************************************************************
609 * This class is called during code gen at block-boundaries, and when the
610 * set of live variables changes. It keeps track of the scope of the variables
611 * in terms of the native code PC.
617 void siBeginBlock(BasicBlock* block);
619 void siEndBlock(BasicBlock* block);
621 virtual void siUpdate();
623 void siCheckVarScope(unsigned varNum, IL_OFFSET offs);
625 void siCloseAllOpenScopes();
628 void siDispOpenScopes();
631 /**************************************************************************
633 *************************************************************************/
638 emitLocation scStartLoc; // emitter location of start of scope
639 emitLocation scEndLoc; // emitter location of end of scope
641 unsigned scVarNum; // index into lvaTable
642 unsigned scLVnum; // 'which' in eeGetLVinfo()
644 unsigned scStackLevel; // Only for stk-vars
645 bool scAvailable : 1; // It has a home / Home recycled - TODO-Cleanup: it appears this is unused (always true)
651 siScope siOpenScopeList, siScopeList, *siOpenScopeLast, *siScopeLast;
655 VARSET_TP siLastLife; // Life at last call to siUpdate()
657 // Tracks the last entry for each tracked register variable
659 siScope* siLatestTrackedScopes[lclMAX_TRACKED];
661 IL_OFFSET siLastEndOffs; // IL offset of the (exclusive) end of the last block processed
663 #if FEATURE_EH_FUNCLETS
664 bool siInFuncletRegion; // Have we seen the start of the funclet region?
665 #endif // FEATURE_EH_FUNCLETS
669 siScope* siNewScope(unsigned LVnum, unsigned varNum);
671 void siRemoveFromOpenScopeList(siScope* scope);
673 void siEndTrackedScope(unsigned varIndex);
675 void siEndScope(unsigned varNum);
677 void siEndScope(siScope* scope);
680 bool siVerifyLocalVarTab();
686 const char* siRegVarName(size_t offs, size_t size, unsigned reg);
689 const char* siStackVarName(size_t offs, size_t size, unsigned reg, unsigned stkOffs);
690 #endif // LATE_DISASM
694 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
695 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
697 XX PrologScopeInfo XX
699 XX We need special handling in the prolog block, as the parameter variables XX
700 XX may not be in the same position described by genLclVarTable - they all XX
701 XX start out on the stack XX
703 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
704 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
710 void psiAdjustStackLevel(unsigned size);
712 void psiMoveESPtoEBP();
714 void psiMoveToReg(unsigned varNum, regNumber reg = REG_NA, regNumber otherReg = REG_NA);
716 void psiMoveToStack(unsigned varNum);
720 /**************************************************************************
722 *************************************************************************/
727 emitLocation scStartLoc; // emitter location of start of scope
728 emitLocation scEndLoc; // emitter location of end of scope
730 unsigned scSlotNum; // index into lclVarTab
731 unsigned scLVnum; // 'which' in eeGetLVinfo()
738 regNumberSmall scRegNum;
741 // - "other half" of long var on architectures with 32 bit size registers - x86.
742 // - for System V structs it stores the second register
743 // used to pass a register passed struct.
744 regNumberSmall scOtherReg;
749 regNumberSmall scBaseReg;
750 NATIVE_OFFSET scOffset;
758 psiScope psiOpenScopeList, psiScopeList, *psiOpenScopeLast, *psiScopeLast;
760 unsigned psiScopeCnt;
762 // Implementation Functions
764 psiScope* psiNewPrologScope(unsigned LVnum, unsigned slotNum);
766 void psiEndPrologScope(psiScope* scope);
768 void psSetScopeOffset(psiScope* newScope, LclVarDsc* lclVarDsc1);
770 /*****************************************************************************
773 * This struct holds the LocalVarInfo in terms of the generated native code
774 * after a call to genSetScopeInfo()
779 struct TrnslLocalVarInfo
784 UNATIVE_OFFSET tlviStartPC;
787 Compiler::siVarLoc tlviVarLoc;
790 // Array of scopes of LocalVars in terms of native code
792 TrnslLocalVarInfo* genTrnslLocalVarInfo;
793 unsigned genTrnslLocalVarCount;
796 #ifndef LEGACY_BACKEND
797 #include "codegenlinear.h"
798 #else // LEGACY_BACKEND
799 #include "codegenclassic.h"
800 #endif // LEGACY_BACKEND
803 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
804 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
808 XX The interface to generate a machine-instruction. XX
809 XX Currently specific to x86 XX
810 XX TODO-Cleanup: Consider factoring this out of CodeGen XX
812 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
813 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
819 #ifdef LEGACY_BACKEND
820 regNumber genGetZeroRegister();
823 void instGen(instruction ins);
824 #ifdef _TARGET_XARCH_
825 void instNop(unsigned size);
828 void inst_JMP(emitJumpKind jmp, BasicBlock* tgtBlock);
830 void inst_SET(emitJumpKind condition, regNumber reg);
832 void inst_RV(instruction ins, regNumber reg, var_types type, emitAttr size = EA_UNKNOWN);
834 void inst_RV_RV(instruction ins,
837 var_types type = TYP_I_IMPL,
838 emitAttr size = EA_UNKNOWN,
839 insFlags flags = INS_FLAGS_DONT_CARE);
841 void inst_RV_RV_RV(instruction ins,
846 insFlags flags = INS_FLAGS_DONT_CARE);
848 void inst_IV(instruction ins, int val);
849 void inst_IV_handle(instruction ins, int val);
850 void inst_FS(instruction ins, unsigned stk = 0);
852 void inst_RV_IV(instruction ins, regNumber reg, ssize_t val, emitAttr size, insFlags flags = INS_FLAGS_DONT_CARE);
854 void inst_ST_RV(instruction ins, TempDsc* tmp, unsigned ofs, regNumber reg, var_types type);
855 void inst_ST_IV(instruction ins, TempDsc* tmp, unsigned ofs, int val, var_types type);
857 void inst_SA_RV(instruction ins, unsigned ofs, regNumber reg, var_types type);
858 void inst_SA_IV(instruction ins, unsigned ofs, int val, var_types type);
861 instruction ins, regNumber reg, TempDsc* tmp, unsigned ofs, var_types type, emitAttr size = EA_UNKNOWN);
862 void inst_FS_ST(instruction ins, emitAttr size, TempDsc* tmp, unsigned ofs);
864 void instEmit_indCall(GenTreeCall* call,
866 emitAttr retSize MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize));
868 void instEmit_RM(instruction ins, GenTreePtr tree, GenTreePtr addr, unsigned offs);
870 void instEmit_RM_RV(instruction ins, emitAttr size, GenTreePtr tree, regNumber reg, unsigned offs);
872 void instEmit_RV_RM(instruction ins, emitAttr size, regNumber reg, GenTreePtr tree, unsigned offs);
874 void instEmit_RV_RIA(instruction ins, regNumber reg1, regNumber reg2, unsigned offs);
876 void inst_TT(instruction ins, GenTreePtr tree, unsigned offs = 0, int shfv = 0, emitAttr size = EA_UNKNOWN);
878 void inst_TT_RV(instruction ins,
882 emitAttr size = EA_UNKNOWN,
883 insFlags flags = INS_FLAGS_DONT_CARE);
885 void inst_TT_IV(instruction ins,
889 emitAttr size = EA_UNKNOWN,
890 insFlags flags = INS_FLAGS_DONT_CARE);
892 void inst_RV_AT(instruction ins,
898 insFlags flags = INS_FLAGS_DONT_CARE);
900 void inst_AT_IV(instruction ins, emitAttr size, GenTreePtr baseTree, int icon, unsigned offs = 0);
902 void inst_RV_TT(instruction ins,
906 emitAttr size = EA_UNKNOWN,
907 insFlags flags = INS_FLAGS_DONT_CARE);
909 void inst_RV_TT_IV(instruction ins, regNumber reg, GenTreePtr tree, int val);
911 void inst_FS_TT(instruction ins, GenTreePtr tree);
913 void inst_RV_SH(instruction ins, emitAttr size, regNumber reg, unsigned val, insFlags flags = INS_FLAGS_DONT_CARE);
915 void inst_TT_SH(instruction ins, GenTreePtr tree, unsigned val, unsigned offs = 0);
917 void inst_RV_CL(instruction ins, regNumber reg, var_types type = TYP_I_IMPL);
919 void inst_TT_CL(instruction ins, GenTreePtr tree, unsigned offs = 0);
921 #if defined(_TARGET_XARCH_)
922 void inst_RV_RV_IV(instruction ins, emitAttr size, regNumber reg1, regNumber reg2, unsigned ival);
925 void inst_RV_RR(instruction ins, emitAttr size, regNumber reg1, regNumber reg2);
927 void inst_RV_ST(instruction ins, emitAttr size, regNumber reg, GenTreePtr tree);
929 void inst_mov_RV_ST(regNumber reg, GenTreePtr tree);
931 void instGetAddrMode(GenTreePtr addr, regNumber* baseReg, unsigned* indScale, regNumber* indReg, unsigned* cns);
933 void inst_set_SV_var(GenTreePtr tree);
936 bool arm_Valid_Imm_For_Instr(instruction ins, ssize_t imm, insFlags flags);
937 bool arm_Valid_Disp_For_LdSt(ssize_t disp, var_types type);
938 bool arm_Valid_Imm_For_Alu(ssize_t imm);
939 bool arm_Valid_Imm_For_Mov(ssize_t imm);
940 bool arm_Valid_Imm_For_Small_Mov(regNumber reg, ssize_t imm, insFlags flags);
941 bool arm_Valid_Imm_For_Add(ssize_t imm, insFlags flag);
942 bool arm_Valid_Imm_For_Add_SP(ssize_t imm);
943 bool arm_Valid_Imm_For_BL(ssize_t addr);
945 bool ins_Writes_Dest(instruction ins);
948 bool isMoveIns(instruction ins);
949 instruction ins_Move_Extend(var_types srcType, bool srcInReg);
951 instruction ins_Copy(var_types dstType);
952 instruction ins_CopyIntToFloat(var_types srcType, var_types dstTyp);
953 instruction ins_CopyFloatToInt(var_types srcType, var_types dstTyp);
954 static instruction ins_FloatStore(var_types type = TYP_DOUBLE);
955 static instruction ins_FloatCopy(var_types type = TYP_DOUBLE);
956 instruction ins_FloatConv(var_types to, var_types from);
957 instruction ins_FloatCompare(var_types type);
958 instruction ins_MathOp(genTreeOps oper, var_types type);
959 instruction ins_FloatSqrt(var_types type);
961 void instGen_Return(unsigned stkArgSize);
963 #ifdef _TARGET_ARM64_
964 void instGen_MemoryBarrier(insBarrier barrierType = INS_BARRIER_ISH);
966 void instGen_MemoryBarrier();
969 void instGen_Set_Reg_To_Zero(emitAttr size, regNumber reg, insFlags flags = INS_FLAGS_DONT_CARE);
971 void instGen_Set_Reg_To_Imm(emitAttr size, regNumber reg, ssize_t imm, insFlags flags = INS_FLAGS_DONT_CARE);
973 void instGen_Compare_Reg_To_Zero(emitAttr size, regNumber reg);
975 void instGen_Compare_Reg_To_Reg(emitAttr size, regNumber reg1, regNumber reg2);
977 void instGen_Compare_Reg_To_Imm(emitAttr size, regNumber reg, ssize_t imm);
979 void instGen_Load_Reg_From_Lcl(var_types srcType, regNumber dstReg, int varNum, int offs);
981 void instGen_Store_Reg_Into_Lcl(var_types dstType, regNumber srcReg, int varNum, int offs);
983 void instGen_Store_Imm_Into_Lcl(
984 var_types dstType, emitAttr sizeAttr, ssize_t imm, int varNum, int offs, regNumber regToUse = REG_NA);
987 void __cdecl instDisp(instruction ins, bool noNL, const char* fmt, ...);
990 #ifdef _TARGET_XARCH_
991 instruction genMapShiftInsToShiftByConstantIns(instruction ins, int shiftByValue);
992 #endif // _TARGET_XARCH_
995 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
996 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
999 XX Inline functions XX
1001 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1002 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1005 #ifdef _TARGET_XARCH_
1006 /*****************************************************************************
1008 * Generate a floating-point instruction that has one operand given by
1009 * a tree (which has been made addressable).
1012 inline void CodeGen::inst_FS_TT(instruction ins, GenTreePtr tree)
1014 assert(instIsFP(ins));
1016 assert(varTypeIsFloating(tree->gtType));
1018 inst_TT(ins, tree, 0);
1022 /*****************************************************************************
1024 * Generate a "shift reg, cl" instruction.
1027 inline void CodeGen::inst_RV_CL(instruction ins, regNumber reg, var_types type)
1029 inst_RV(ins, reg, type);
1032 #endif // _CODEGEN_H_