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_) && !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(GenTree* treeNode);
69 // Generates SSE41 code for the given tree as a round operation
70 void genSSE41RoundOp(GenTreeOp* treeNode);
71 #endif // defined(_TARGET_XARCH_) && !FEATURE_STACK_FP_X87
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 #ifdef LEGACY_BACKEND
147 regNumber findStkLclInReg(unsigned lclNum)
150 genInterruptibleUsed = true;
152 return regTracker.rsLclIsInReg(lclNum);
156 //-------------------------------------------------------------------------
158 bool genUseBlockInit; // true if we plan to block-initialize the local stack frame
159 unsigned genInitStkLclCnt; // The count of local variables that we need to zero init
161 // Keeps track of how many bytes we've pushed on the processor's stack.
163 unsigned genStackLevel;
165 void SubtractStackLevel(unsigned adjustment)
167 assert(genStackLevel >= 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 AddStackLevel(unsigned adjustment)
178 unsigned newStackLevel = genStackLevel + adjustment;
179 if (genStackLevel != newStackLevel)
181 JITDUMP("Adjusting stack level from %d to %d\n", genStackLevel, newStackLevel);
183 genStackLevel = newStackLevel;
186 void SetStackLevel(unsigned newStackLevel)
188 if (genStackLevel != newStackLevel)
190 JITDUMP("Setting stack level from %d to %d\n", genStackLevel, newStackLevel);
192 genStackLevel = newStackLevel;
197 bool genNeedPrologStackProbe;
199 void genGenerateStackProbe();
202 #ifdef LEGACY_BACKEND
203 regMaskTP genNewLiveRegMask(GenTree* first, GenTree* second);
205 // During codegen, determine the LiveSet after tree.
206 // Preconditions: must be called during codegen, when compCurLife and
207 // compCurLifeTree are being maintained, and tree must occur in the current
209 VARSET_VALRET_TP genUpdateLiveSetForward(GenTree* tree);
212 //-------------------------------------------------------------------------
216 // Allocates storage for the GC info, writes the GC info into that storage, records the address of the
217 // GC info of the method with the EE, and returns a pointer to the "info" portion (just post-header) of
218 // the GC info. Requires "codeSize" to be the size of the generated code, "prologSize" and "epilogSize"
219 // to be the sizes of the prolog and epilog, respectively. In DEBUG, makes a check involving the
220 // "codePtr", assumed to be a pointer to the start of the generated code.
221 CLANG_FORMAT_COMMENT_ANCHOR;
223 #ifdef JIT32_GCENCODER
224 void* genCreateAndStoreGCInfo(unsigned codeSize, unsigned prologSize, unsigned epilogSize DEBUGARG(void* codePtr));
225 void* genCreateAndStoreGCInfoJIT32(unsigned codeSize,
227 unsigned epilogSize DEBUGARG(void* codePtr));
228 #else // !JIT32_GCENCODER
229 void genCreateAndStoreGCInfo(unsigned codeSize, unsigned prologSize, unsigned epilogSize DEBUGARG(void* codePtr));
230 void genCreateAndStoreGCInfoX64(unsigned codeSize, unsigned prologSize DEBUGARG(void* codePtr));
231 #endif // !JIT32_GCENCODER
233 /**************************************************************************
235 *************************************************************************/
238 // the current (pending) label ref, a label which has been referenced but not yet seen
239 BasicBlock* genPendingCallLabel;
242 // Last instr we have displayed for dspInstrs
243 unsigned genCurDispOffset;
245 static const char* genInsName(instruction ins);
248 //-------------------------------------------------------------------------
250 // JIT-time constants for use in multi-dimensional array code generation.
251 unsigned genOffsetOfMDArrayLowerBound(var_types elemType, unsigned rank, unsigned dimension);
252 unsigned genOffsetOfMDArrayDimensionSize(var_types elemType, unsigned rank, unsigned dimension);
255 static const char* genSizeStr(emitAttr size);
257 void genStressRegs(GenTree* tree);
260 void genCodeForBBlist();
263 #ifndef LEGACY_BACKEND
264 // genSpillVar is called by compUpdateLifeVar in the !LEGACY_BACKEND case
265 void genSpillVar(GenTree* tree);
266 #endif // !LEGACY_BACKEND
269 #ifndef LEGACY_BACKEND
270 void genEmitHelperCall(unsigned helper, int argSize, emitAttr retSize, regNumber callTarget = REG_NA);
272 void genEmitHelperCall(unsigned helper, int argSize, emitAttr retSize);
275 void genGCWriteBarrier(GenTree* tgt, GCInfo::WriteBarrierForm wbf);
277 BasicBlock* genCreateTempLabel();
279 void genDefineTempLabel(BasicBlock* label);
281 void genAdjustSP(ssize_t delta);
283 void genAdjustStackLevel(BasicBlock* block);
285 void genExitCode(BasicBlock* block);
287 #ifdef LEGACY_BACKEND
288 GenTree* genMakeConst(const void* cnsAddr, var_types cnsType, GenTree* cnsTree, bool dblAlign);
291 void genJumpToThrowHlpBlk(emitJumpKind jumpKind, SpecialCodeKind codeKind, GenTree* failBlk = nullptr);
293 void genCheckOverflow(GenTree* tree);
295 //-------------------------------------------------------------------------
297 // Prolog/epilog generation
299 //-------------------------------------------------------------------------
302 // Prolog functions and data (there are a few exceptions for more generally used things)
305 void genEstablishFramePointer(int delta, bool reportUnwindData);
306 void genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbered, RegState* regState);
307 void genEnregisterIncomingStackArgs();
308 void genCheckUseBlockInit();
309 #if defined(UNIX_AMD64_ABI) && defined(FEATURE_SIMD)
310 void genClearStackVec3ArgUpperBits();
311 #endif // UNIX_AMD64_ABI && FEATURE_SIMD
313 #if defined(_TARGET_ARM64_)
314 bool genInstrWithConstant(instruction ins,
320 bool inUnwindRegion = false);
322 void genStackPointerAdjustment(ssize_t spAdjustment, regNumber tmpReg, bool* pTmpRegIsZero);
324 void genPrologSaveRegPair(regNumber reg1,
328 bool lastSavedWasPreviousPair,
330 bool* pTmpRegIsZero);
332 void genPrologSaveReg(regNumber reg1, int spOffset, int spDelta, regNumber tmpReg, bool* pTmpRegIsZero);
334 void genEpilogRestoreRegPair(
335 regNumber reg1, regNumber reg2, int spOffset, int spDelta, regNumber tmpReg, bool* pTmpRegIsZero);
337 void genEpilogRestoreReg(regNumber reg1, int spOffset, int spDelta, regNumber tmpReg, bool* pTmpRegIsZero);
339 void genSaveCalleeSavedRegistersHelp(regMaskTP regsToSaveMask, int lowestCalleeSavedOffset, int spDelta);
341 void genRestoreCalleeSavedRegistersHelp(regMaskTP regsToRestoreMask, int lowestCalleeSavedOffset, int spDelta);
343 void genPushCalleeSavedRegisters(regNumber initReg, bool* pInitRegZeroed);
345 void genPushCalleeSavedRegisters();
348 void genAllocLclFrame(unsigned frameSize, regNumber initReg, bool* pInitRegZeroed, regMaskTP maskArgRegsLiveIn);
350 #if defined(_TARGET_ARM_)
352 void genPushFltRegs(regMaskTP regMask);
353 void genPopFltRegs(regMaskTP regMask);
354 regMaskTP genStackAllocRegisterMask(unsigned frameSize, regMaskTP maskCalleeSavedFloat);
356 regMaskTP genJmpCallArgMask();
358 void genFreeLclFrame(unsigned frameSize,
359 /* IN OUT */ bool* pUnwindStarted,
362 void genMov32RelocatableDisplacement(BasicBlock* block, regNumber reg);
363 void genMov32RelocatableDataLabel(unsigned value, regNumber reg);
364 void genMov32RelocatableImmediate(emitAttr size, size_t value, regNumber reg);
366 bool genUsedPopToReturn; // True if we use the pop into PC to return,
367 // False if we didn't and must branch to LR to return.
369 // A set of information that is used by funclet prolog and epilog generation. It is collected once, before
370 // funclet prologs and epilogs are generated, and used by all funclet prologs and epilogs, which must all be the
372 struct FuncletFrameInfoDsc
374 regMaskTP fiSaveRegs; // Set of registers saved in the funclet prolog (includes LR)
375 unsigned fiFunctionCallerSPtoFPdelta; // Delta between caller SP and the frame pointer
376 unsigned fiSpDelta; // Stack pointer delta
377 unsigned fiPSP_slot_SP_offset; // PSP slot offset from SP
378 int fiPSP_slot_CallerSP_offset; // PSP slot offset from Caller SP
381 FuncletFrameInfoDsc genFuncletInfo;
383 #elif defined(_TARGET_ARM64_)
385 // A set of information that is used by funclet prolog and epilog generation. It is collected once, before
386 // funclet prologs and epilogs are generated, and used by all funclet prologs and epilogs, which must all be the
388 struct FuncletFrameInfoDsc
390 regMaskTP fiSaveRegs; // Set of callee-saved registers saved in the funclet prolog (includes LR)
391 int fiFunction_CallerSP_to_FP_delta; // Delta between caller SP and the frame pointer in the parent function
393 int fiSP_to_FPLR_save_delta; // FP/LR register save offset from SP (positive)
394 int fiSP_to_PSP_slot_delta; // PSP slot offset from SP (positive)
395 int fiSP_to_CalleeSave_delta; // First callee-saved register slot offset from SP (positive)
396 int fiCallerSP_to_PSP_slot_delta; // PSP slot offset from Caller SP (negative)
397 int fiFrameType; // Funclet frame types are numbered. See genFuncletProlog() for details.
398 int fiSpDelta1; // Stack pointer delta 1 (negative)
399 int fiSpDelta2; // Stack pointer delta 2 (negative)
402 FuncletFrameInfoDsc genFuncletInfo;
404 #elif defined(_TARGET_AMD64_)
406 // A set of information that is used by funclet prolog and epilog generation. It is collected once, before
407 // funclet prologs and epilogs are generated, and used by all funclet prologs and epilogs, which must all be the
409 struct FuncletFrameInfoDsc
411 unsigned fiFunction_InitialSP_to_FP_delta; // Delta between Initial-SP and the frame pointer
412 unsigned fiSpDelta; // Stack pointer delta
413 int fiPSP_slot_InitialSP_offset; // PSP slot offset from Initial-SP
416 FuncletFrameInfoDsc genFuncletInfo;
418 #endif // _TARGET_AMD64_
420 #if defined(_TARGET_XARCH_) && !FEATURE_STACK_FP_X87
422 // Save/Restore callee saved float regs to stack
423 void genPreserveCalleeSavedFltRegs(unsigned lclFrameSize);
424 void genRestoreCalleeSavedFltRegs(unsigned lclFrameSize);
425 // Generate VZeroupper instruction to avoid AVX/SSE transition penalty
426 void genVzeroupperIfNeeded(bool check256bitOnly = true);
428 #endif // _TARGET_XARCH_ && FEATURE_STACK_FP_X87
430 #if !FEATURE_STACK_FP_X87
431 void genZeroInitFltRegs(const regMaskTP& initFltRegs, const regMaskTP& initDblRegs, const regNumber& initReg);
432 #endif // !FEATURE_STACK_FP_X87
434 regNumber genGetZeroReg(regNumber initReg, bool* pInitRegZeroed);
436 void genZeroInitFrame(int untrLclHi, int untrLclLo, regNumber initReg, bool* pInitRegZeroed);
438 void genReportGenericContextArg(regNumber initReg, bool* pInitRegZeroed);
440 void genSetGSSecurityCookie(regNumber initReg, bool* pInitRegZeroed);
442 void genFinalizeFrame();
444 #ifdef PROFILING_SUPPORTED
445 void genProfilingEnterCallback(regNumber initReg, bool* pInitRegZeroed);
446 void genProfilingLeaveCallback(unsigned helper = CORINFO_HELP_PROF_FCN_LEAVE);
447 #endif // PROFILING_SUPPORTED
449 void genPrologPadForReJit();
452 void genEmitCall(int callType,
453 CORINFO_METHOD_HANDLE methHnd,
454 INDEBUG_LDISASM_COMMA(CORINFO_SIG_INFO* sigInfo)
456 X86_ARG(ssize_t argSize),
458 MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize),
460 regNumber base = REG_NA,
462 bool isNoGC = false);
466 void genEmitCall(int callType,
467 CORINFO_METHOD_HANDLE methHnd,
468 INDEBUG_LDISASM_COMMA(CORINFO_SIG_INFO* sigInfo)
470 X86_ARG(ssize_t argSize),
472 MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize),
473 IL_OFFSETX ilOffset);
479 CLANG_FORMAT_COMMENT_ANCHOR;
481 #if defined(_TARGET_ARM_)
482 bool genCanUsePopToReturn(regMaskTP maskPopRegsInt, bool jmpEpilog);
485 #if defined(_TARGET_ARM64_)
487 void genPopCalleeSavedRegistersAndFreeLclFrame(bool jmpEpilog);
489 #else // !defined(_TARGET_ARM64_)
491 void genPopCalleeSavedRegisters(bool jmpEpilog = false);
493 #endif // !defined(_TARGET_ARM64_)
496 // Common or driving functions
499 void genReserveProlog(BasicBlock* block); // currently unused
500 void genReserveEpilog(BasicBlock* block);
502 void genFnEpilog(BasicBlock* block);
504 #if FEATURE_EH_FUNCLETS
506 void genReserveFuncletProlog(BasicBlock* block);
507 void genReserveFuncletEpilog(BasicBlock* block);
508 void genFuncletProlog(BasicBlock* block);
509 void genFuncletEpilog();
510 void genCaptureFuncletPrologEpilogInfo();
512 void genSetPSPSym(regNumber initReg, bool* pInitRegZeroed);
514 void genUpdateCurrentFunclet(BasicBlock* block);
515 #if defined(_TARGET_ARM_)
516 void genInsertNopForUnwinder(BasicBlock* block);
519 #else // FEATURE_EH_FUNCLETS
521 // This is a no-op when there are no funclets!
522 void genUpdateCurrentFunclet(BasicBlock* block)
527 #if defined(_TARGET_ARM_)
528 void genInsertNopForUnwinder(BasicBlock* block)
534 #endif // FEATURE_EH_FUNCLETS
536 void genGeneratePrologsAndEpilogs();
538 #if defined(DEBUG) && defined(_TARGET_ARM64_)
539 void genArm64EmitterUnitTests();
542 #if defined(DEBUG) && defined(LATE_DISASM) && defined(_TARGET_AMD64_)
543 void genAmd64EmitterUnitTests();
546 //-------------------------------------------------------------------------
548 // End prolog/epilog generation
550 //-------------------------------------------------------------------------
552 void genSinglePush();
554 regMaskTP genPushRegs(regMaskTP regs, regMaskTP* byrefRegs, regMaskTP* noRefRegs);
555 void genPopRegs(regMaskTP regs, regMaskTP byrefRegs, regMaskTP noRefRegs);
558 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
559 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
561 XX Debugging Support XX
563 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
564 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
568 void genIPmappingDisp(unsigned mappingNum, Compiler::IPmappingDsc* ipMapping);
569 void genIPmappingListDisp();
572 void genIPmappingAdd(IL_OFFSETX offset, bool isLabel);
573 void genIPmappingAddToFront(IL_OFFSETX offset);
574 void genIPmappingGen();
576 void genEnsureCodeEmitted(IL_OFFSETX offsx);
578 //-------------------------------------------------------------------------
579 // scope info for the variables
581 void genSetScopeInfo(unsigned which,
582 UNATIVE_OFFSET startOffs,
583 UNATIVE_OFFSET length,
587 Compiler::siVarLoc& loc);
589 void genSetScopeInfo();
591 void genRemoveBBsection(BasicBlock* head, BasicBlock* tail);
595 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
596 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
600 XX Keeps track of the scopes during code-generation. XX
601 XX This is used to translate the local-variable debugging information XX
602 XX from IL offsets to native code offsets. XX
604 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
605 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
608 /*****************************************************************************/
609 /*****************************************************************************
612 * This class is called during code gen at block-boundaries, and when the
613 * set of live variables changes. It keeps track of the scope of the variables
614 * in terms of the native code PC.
620 void siBeginBlock(BasicBlock* block);
622 void siEndBlock(BasicBlock* block);
624 virtual void siUpdate();
626 void siCheckVarScope(unsigned varNum, IL_OFFSET offs);
628 void siCloseAllOpenScopes();
631 void siDispOpenScopes();
634 /**************************************************************************
636 *************************************************************************/
641 emitLocation scStartLoc; // emitter location of start of scope
642 emitLocation scEndLoc; // emitter location of end of scope
644 unsigned scVarNum; // index into lvaTable
645 unsigned scLVnum; // 'which' in eeGetLVinfo()
647 unsigned scStackLevel; // Only for stk-vars
648 bool scAvailable : 1; // It has a home / Home recycled - TODO-Cleanup: it appears this is unused (always true)
654 siScope siOpenScopeList, siScopeList, *siOpenScopeLast, *siScopeLast;
658 VARSET_TP siLastLife; // Life at last call to siUpdate()
660 // Tracks the last entry for each tracked register variable
662 siScope* siLatestTrackedScopes[lclMAX_TRACKED];
664 IL_OFFSET siLastEndOffs; // IL offset of the (exclusive) end of the last block processed
666 #if FEATURE_EH_FUNCLETS
667 bool siInFuncletRegion; // Have we seen the start of the funclet region?
668 #endif // FEATURE_EH_FUNCLETS
672 siScope* siNewScope(unsigned LVnum, unsigned varNum);
674 void siRemoveFromOpenScopeList(siScope* scope);
676 void siEndTrackedScope(unsigned varIndex);
678 void siEndScope(unsigned varNum);
680 void siEndScope(siScope* scope);
683 bool siVerifyLocalVarTab();
689 const char* siRegVarName(size_t offs, size_t size, unsigned reg);
692 const char* siStackVarName(size_t offs, size_t size, unsigned reg, unsigned stkOffs);
693 #endif // LATE_DISASM
697 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
698 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
700 XX PrologScopeInfo XX
702 XX We need special handling in the prolog block, as the parameter variables XX
703 XX may not be in the same position described by genLclVarTable - they all XX
704 XX start out on the stack XX
706 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
707 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
713 void psiAdjustStackLevel(unsigned size);
715 void psiMoveESPtoEBP();
717 void psiMoveToReg(unsigned varNum, regNumber reg = REG_NA, regNumber otherReg = REG_NA);
719 void psiMoveToStack(unsigned varNum);
723 /**************************************************************************
725 *************************************************************************/
730 emitLocation scStartLoc; // emitter location of start of scope
731 emitLocation scEndLoc; // emitter location of end of scope
733 unsigned scSlotNum; // index into lclVarTab
734 unsigned scLVnum; // 'which' in eeGetLVinfo()
741 regNumberSmall scRegNum;
744 // - "other half" of long var on architectures with 32 bit size registers - x86.
745 // - for System V structs it stores the second register
746 // used to pass a register passed struct.
747 regNumberSmall scOtherReg;
752 regNumberSmall scBaseReg;
753 NATIVE_OFFSET scOffset;
761 psiScope psiOpenScopeList, psiScopeList, *psiOpenScopeLast, *psiScopeLast;
763 unsigned psiScopeCnt;
765 // Implementation Functions
767 psiScope* psiNewPrologScope(unsigned LVnum, unsigned slotNum);
769 void psiEndPrologScope(psiScope* scope);
771 void psSetScopeOffset(psiScope* newScope, LclVarDsc* lclVarDsc1);
773 /*****************************************************************************
776 * This struct holds the LocalVarInfo in terms of the generated native code
777 * after a call to genSetScopeInfo()
782 struct TrnslLocalVarInfo
787 UNATIVE_OFFSET tlviStartPC;
790 Compiler::siVarLoc tlviVarLoc;
793 // Array of scopes of LocalVars in terms of native code
795 TrnslLocalVarInfo* genTrnslLocalVarInfo;
796 unsigned genTrnslLocalVarCount;
799 #ifndef LEGACY_BACKEND
800 #include "codegenlinear.h"
801 #else // LEGACY_BACKEND
802 #include "codegenclassic.h"
803 #endif // LEGACY_BACKEND
806 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
807 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
811 XX The interface to generate a machine-instruction. XX
812 XX Currently specific to x86 XX
813 XX TODO-Cleanup: Consider factoring this out of CodeGen XX
815 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
816 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
822 #ifdef LEGACY_BACKEND
823 regNumber genGetZeroRegister();
826 void instGen(instruction ins);
827 #ifdef _TARGET_XARCH_
828 void instNop(unsigned size);
831 void inst_JMP(emitJumpKind jmp, BasicBlock* tgtBlock);
833 void inst_SET(emitJumpKind condition, regNumber reg);
835 void inst_RV(instruction ins, regNumber reg, var_types type, emitAttr size = EA_UNKNOWN);
837 void inst_RV_RV(instruction ins,
840 var_types type = TYP_I_IMPL,
841 emitAttr size = EA_UNKNOWN,
842 insFlags flags = INS_FLAGS_DONT_CARE);
844 void inst_RV_RV_RV(instruction ins,
849 insFlags flags = INS_FLAGS_DONT_CARE);
851 void inst_IV(instruction ins, int val);
852 void inst_IV_handle(instruction ins, int val);
853 void inst_FS(instruction ins, unsigned stk = 0);
855 void inst_RV_IV(instruction ins, regNumber reg, ssize_t val, emitAttr size, insFlags flags = INS_FLAGS_DONT_CARE);
857 void inst_ST_RV(instruction ins, TempDsc* tmp, unsigned ofs, regNumber reg, var_types type);
858 void inst_ST_IV(instruction ins, TempDsc* tmp, unsigned ofs, int val, var_types type);
860 void inst_SA_RV(instruction ins, unsigned ofs, regNumber reg, var_types type);
861 void inst_SA_IV(instruction ins, unsigned ofs, int val, var_types type);
864 instruction ins, regNumber reg, TempDsc* tmp, unsigned ofs, var_types type, emitAttr size = EA_UNKNOWN);
865 void inst_FS_ST(instruction ins, emitAttr size, TempDsc* tmp, unsigned ofs);
867 void instEmit_indCall(GenTreeCall* call,
869 emitAttr retSize MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize));
871 void instEmit_RM(instruction ins, GenTree* tree, GenTree* addr, unsigned offs);
873 void instEmit_RM_RV(instruction ins, emitAttr size, GenTree* tree, regNumber reg, unsigned offs);
875 void instEmit_RV_RM(instruction ins, emitAttr size, regNumber reg, GenTree* tree, unsigned offs);
877 void instEmit_RV_RIA(instruction ins, regNumber reg1, regNumber reg2, unsigned offs);
879 void inst_TT(instruction ins, GenTree* tree, unsigned offs = 0, int shfv = 0, emitAttr size = EA_UNKNOWN);
881 void inst_TT_RV(instruction ins,
885 emitAttr size = EA_UNKNOWN,
886 insFlags flags = INS_FLAGS_DONT_CARE);
888 void inst_TT_IV(instruction ins,
892 emitAttr size = EA_UNKNOWN,
893 insFlags flags = INS_FLAGS_DONT_CARE);
895 void inst_RV_AT(instruction ins,
901 insFlags flags = INS_FLAGS_DONT_CARE);
903 void inst_AT_IV(instruction ins, emitAttr size, GenTree* baseTree, int icon, unsigned offs = 0);
905 void inst_RV_TT(instruction ins,
909 emitAttr size = EA_UNKNOWN,
910 insFlags flags = INS_FLAGS_DONT_CARE);
912 void inst_RV_TT_IV(instruction ins, regNumber reg, GenTree* tree, int val);
914 void inst_FS_TT(instruction ins, GenTree* tree);
916 void inst_RV_SH(instruction ins, emitAttr size, regNumber reg, unsigned val, insFlags flags = INS_FLAGS_DONT_CARE);
918 void inst_TT_SH(instruction ins, GenTree* tree, unsigned val, unsigned offs = 0);
920 void inst_RV_CL(instruction ins, regNumber reg, var_types type = TYP_I_IMPL);
922 void inst_TT_CL(instruction ins, GenTree* tree, unsigned offs = 0);
924 #if defined(_TARGET_XARCH_)
925 void inst_RV_RV_IV(instruction ins, emitAttr size, regNumber reg1, regNumber reg2, unsigned ival);
928 void inst_RV_RR(instruction ins, emitAttr size, regNumber reg1, regNumber reg2);
930 void inst_RV_ST(instruction ins, emitAttr size, regNumber reg, GenTree* tree);
932 void inst_mov_RV_ST(regNumber reg, GenTree* tree);
934 void instGetAddrMode(GenTree* addr, regNumber* baseReg, unsigned* indScale, regNumber* indReg, unsigned* cns);
936 void inst_set_SV_var(GenTree* tree);
939 bool arm_Valid_Imm_For_Instr(instruction ins, ssize_t imm, insFlags flags);
940 bool arm_Valid_Disp_For_LdSt(ssize_t disp, var_types type);
941 bool arm_Valid_Imm_For_Alu(ssize_t imm);
942 bool arm_Valid_Imm_For_Mov(ssize_t imm);
943 bool arm_Valid_Imm_For_Small_Mov(regNumber reg, ssize_t imm, insFlags flags);
944 bool arm_Valid_Imm_For_Add(ssize_t imm, insFlags flag);
945 bool arm_Valid_Imm_For_Add_SP(ssize_t imm);
946 bool arm_Valid_Imm_For_BL(ssize_t addr);
948 bool ins_Writes_Dest(instruction ins);
951 bool isMoveIns(instruction ins);
952 instruction ins_Move_Extend(var_types srcType, bool srcInReg);
954 instruction ins_Copy(var_types dstType);
955 instruction ins_CopyIntToFloat(var_types srcType, var_types dstTyp);
956 instruction ins_CopyFloatToInt(var_types srcType, var_types dstTyp);
957 static instruction ins_FloatStore(var_types type = TYP_DOUBLE);
958 static instruction ins_FloatCopy(var_types type = TYP_DOUBLE);
959 instruction ins_FloatConv(var_types to, var_types from);
960 instruction ins_FloatCompare(var_types type);
961 instruction ins_MathOp(genTreeOps oper, var_types type);
962 instruction ins_FloatSqrt(var_types type);
964 void instGen_Return(unsigned stkArgSize);
966 #ifdef _TARGET_ARM64_
967 void instGen_MemoryBarrier(insBarrier barrierType = INS_BARRIER_ISH);
969 void instGen_MemoryBarrier();
972 void instGen_Set_Reg_To_Zero(emitAttr size, regNumber reg, insFlags flags = INS_FLAGS_DONT_CARE);
974 void instGen_Set_Reg_To_Imm(emitAttr size, regNumber reg, ssize_t imm, insFlags flags = INS_FLAGS_DONT_CARE);
976 void instGen_Compare_Reg_To_Zero(emitAttr size, regNumber reg);
978 void instGen_Compare_Reg_To_Reg(emitAttr size, regNumber reg1, regNumber reg2);
980 void instGen_Compare_Reg_To_Imm(emitAttr size, regNumber reg, ssize_t imm);
982 void instGen_Load_Reg_From_Lcl(var_types srcType, regNumber dstReg, int varNum, int offs);
984 void instGen_Store_Reg_Into_Lcl(var_types dstType, regNumber srcReg, int varNum, int offs);
986 void instGen_Store_Imm_Into_Lcl(
987 var_types dstType, emitAttr sizeAttr, ssize_t imm, int varNum, int offs, regNumber regToUse = REG_NA);
990 void __cdecl instDisp(instruction ins, bool noNL, const char* fmt, ...);
993 #ifdef _TARGET_XARCH_
994 instruction genMapShiftInsToShiftByConstantIns(instruction ins, int shiftByValue);
995 #endif // _TARGET_XARCH_
998 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
999 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1002 XX Inline functions XX
1004 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1005 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1008 #ifdef _TARGET_XARCH_
1009 /*****************************************************************************
1011 * Generate a floating-point instruction that has one operand given by
1012 * a tree (which has been made addressable).
1015 inline void CodeGen::inst_FS_TT(instruction ins, GenTree* tree)
1017 assert(instIsFP(ins));
1019 assert(varTypeIsFloating(tree->gtType));
1021 inst_TT(ins, tree, 0);
1025 /*****************************************************************************
1027 * Generate a "shift reg, cl" instruction.
1030 inline void CodeGen::inst_RV_CL(instruction ins, regNumber reg, var_types type)
1032 inst_RV(ins, reg, type);
1035 #endif // _CODEGEN_H_