diff options
Diffstat (limited to 'src/jit/codegen.h')
-rwxr-xr-x | src/jit/codegen.h | 967 |
1 files changed, 967 insertions, 0 deletions
diff --git a/src/jit/codegen.h b/src/jit/codegen.h new file mode 100755 index 0000000000..0c4a311186 --- /dev/null +++ b/src/jit/codegen.h @@ -0,0 +1,967 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +// +// This class contains all the data & functionality for code generation +// of a method, except for the target-specific elements, which are +// primarily in the Target class. +// + +#ifndef _CODEGEN_H_ +#define _CODEGEN_H_ +#include "compiler.h" // temporary?? +#include "codegeninterface.h" +#include "regset.h" +#include "jitgcinfo.h" + +#if defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_) || defined(_TARGET_ARM_) +#define FOREACH_REGISTER_FILE(file) \ + for ((file) = &(this->intRegState); (file) != NULL; \ + (file) = ((file) == &(this->intRegState)) ? &(this->floatRegState) : NULL) +#else +#define FOREACH_REGISTER_FILE(file) (file) = &(this->intRegState); +#endif + +class CodeGen : public CodeGenInterface +{ + friend class emitter; + friend class DisAssembler; + +public: + // This could use further abstraction + CodeGen(Compiler* theCompiler); + + virtual void genGenerateCode(void** codePtr, ULONG* nativeSizeOfCode); + // TODO-Cleanup: Abstract out the part of this that finds the addressing mode, and + // move it to Lower + virtual bool genCreateAddrMode(GenTreePtr addr, + int mode, + bool fold, + regMaskTP regMask, + bool* revPtr, + GenTreePtr* rv1Ptr, + GenTreePtr* rv2Ptr, +#if SCALED_ADDR_MODES + unsigned* mulPtr, +#endif + unsigned* cnsPtr, + bool nogen = false); + + +private: +#if defined(_TARGET_XARCH_) && !FEATURE_STACK_FP_X87 + // Bit masks used in negating a float or double number. + // The below gentrees encapsulate the data offset to the bitmasks as GT_CLS_VAR nodes. + // This is to avoid creating more than one data constant for these bitmasks when a + // method has more than one GT_NEG operation on floating point values. + GenTreePtr negBitmaskFlt; + GenTreePtr negBitmaskDbl; + + // Bit masks used in computing Math.Abs() of a float or double number. + GenTreePtr absBitmaskFlt; + GenTreePtr absBitmaskDbl; + + // Bit mask used in U8 -> double conversion to adjust the result. + GenTreePtr u8ToDblBitmask; + + // Generates SSE2 code for the given tree as "Operand BitWiseOp BitMask" + void genSSE2BitwiseOp(GenTreePtr treeNode); +#endif // defined(_TARGET_XARCH_) && !FEATURE_STACK_FP_X87 + + void genPrepForCompiler(); + + void genPrepForEHCodegen(); + + inline RegState* regStateForType(var_types t) + { + return varTypeIsFloating(t) ? &floatRegState : &intRegState; + } + inline RegState* regStateForReg(regNumber reg) + { + return genIsValidFloatReg(reg) ? &floatRegState : &intRegState; + } + + regNumber genFramePointerReg() + { + if (isFramePointerUsed()) + { + return REG_FPBASE; + } + else + { + return REG_SPBASE; + } + } + + enum CompareKind + { + CK_SIGNED, + CK_UNSIGNED, + CK_LOGICAL + }; + static emitJumpKind genJumpKindForOper(genTreeOps cmp, CompareKind compareKind); + + // For a given compare oper tree, returns the conditions to use with jmp/set in 'jmpKind' array. + // The corresponding elements of jmpToTrueLabel indicate whether the target of the jump is to the + // 'true' label or a 'false' label. + // + // 'true' label corresponds to jump target of the current basic block i.e. the target to + // branch to on compare condition being true. 'false' label corresponds to the target to + // branch to on condition being false. + static void genJumpKindsForTree(GenTreePtr cmpTree, emitJumpKind jmpKind[2], bool jmpToTrueLabel[2]); + +#if !defined(_TARGET_64BIT_) + static void genJumpKindsForTreeLongHi(GenTreePtr cmpTree, emitJumpKind jmpKind[2]); +#endif //! defined(_TARGET_64BIT_) + + static bool genShouldRoundFP(); + + GenTreeIndir indirForm(var_types type, GenTree* base); + + GenTreeIntCon intForm(var_types type, ssize_t value); + + void genRangeCheck(GenTree* node); + + void genLockedInstructions(GenTree* node); + + //------------------------------------------------------------------------- + // Register-related methods + + void rsInit(); + +#ifdef REG_OPT_RSVD + // On some targets such as the ARM we may need to have an extra reserved register + // that is used when addressing stack based locals and stack based temps. + // This method returns the regNumber that should be used when an extra register + // is needed to access the stack based locals and stack based temps. + // + regNumber rsGetRsvdReg() + { + // We should have already added this register to the mask + // of reserved registers in regSet.rdMaskResvd + noway_assert((regSet.rsMaskResvd & RBM_OPT_RSVD) != 0); + + return REG_OPT_RSVD; + } +#endif // REG_OPT_RSVD + + regNumber findStkLclInReg(unsigned lclNum) + { +#ifdef DEBUG + genInterruptibleUsed = true; +#endif + return regTracker.rsLclIsInReg(lclNum); + } + + //------------------------------------------------------------------------- + + bool genUseBlockInit; // true if we plan to block-initialize the local stack frame + unsigned genInitStkLclCnt; // The count of local variables that we need to zero init + + // Keeps track of how many bytes we've pushed on the processor's stack. + // + unsigned genStackLevel; + +#if STACK_PROBES + // Stack Probes + bool genNeedPrologStackProbe; + + void genGenerateStackProbe(); +#endif + +#ifdef LEGACY_BACKEND + regMaskTP genNewLiveRegMask(GenTreePtr first, GenTreePtr second); + + // During codegen, determine the LiveSet after tree. + // Preconditions: must be called during codegen, when compCurLife and + // compCurLifeTree are being maintained, and tree must occur in the current + // statement. + VARSET_VALRET_TP genUpdateLiveSetForward(GenTreePtr tree); +#endif + + //------------------------------------------------------------------------- + + void genReportEH(); + + // Allocates storage for the GC info, writes the GC info into that storage, records the address of the + // GC info of the method with the EE, and returns a pointer to the "info" portion (just post-header) of + // the GC info. Requires "codeSize" to be the size of the generated code, "prologSize" and "epilogSize" + // to be the sizes of the prolog and epilog, respectively. In DEBUG, makes a check involving the + // "codePtr", assumed to be a pointer to the start of the generated code. + CLANG_FORMAT_COMMENT_ANCHOR; + +#ifdef JIT32_GCENCODER + void* genCreateAndStoreGCInfo(unsigned codeSize, unsigned prologSize, unsigned epilogSize DEBUGARG(void* codePtr)); + void* genCreateAndStoreGCInfoJIT32(unsigned codeSize, + unsigned prologSize, + unsigned epilogSize DEBUGARG(void* codePtr)); +#else // !JIT32_GCENCODER + void genCreateAndStoreGCInfo(unsigned codeSize, unsigned prologSize, unsigned epilogSize DEBUGARG(void* codePtr)); + void genCreateAndStoreGCInfoX64(unsigned codeSize, unsigned prologSize DEBUGARG(void* codePtr)); +#endif // !JIT32_GCENCODER + + /************************************************************************** + * PROTECTED + *************************************************************************/ + +protected: + // the current (pending) label ref, a label which has been referenced but not yet seen + BasicBlock* genPendingCallLabel; + +#ifdef DEBUG + // Last instr we have displayed for dspInstrs + unsigned genCurDispOffset; + + static const char* genInsName(instruction ins); +#endif // DEBUG + + //------------------------------------------------------------------------- + + // JIT-time constants for use in multi-dimensional array code generation. + unsigned genOffsetOfMDArrayLowerBound(var_types elemType, unsigned rank, unsigned dimension); + unsigned genOffsetOfMDArrayDimensionSize(var_types elemType, unsigned rank, unsigned dimension); + +#ifdef DEBUG + static const char* genSizeStr(emitAttr size); + + void genStressRegs(GenTreePtr tree); +#endif // DEBUG + + void genCodeForBBlist(); + +public: +#ifndef LEGACY_BACKEND + // genSpillVar is called by compUpdateLifeVar in the !LEGACY_BACKEND case + void genSpillVar(GenTreePtr tree); +#endif // !LEGACY_BACKEND + +protected: +#ifndef LEGACY_BACKEND + void genEmitHelperCall(unsigned helper, int argSize, emitAttr retSize, regNumber callTarget = REG_NA); +#else + void genEmitHelperCall(unsigned helper, int argSize, emitAttr retSize); +#endif + + void genGCWriteBarrier(GenTreePtr tree, GCInfo::WriteBarrierForm wbf); + + BasicBlock* genCreateTempLabel(); + + void genDefineTempLabel(BasicBlock* label); + + void genAdjustSP(ssize_t delta); + + void genExitCode(BasicBlock* block); + + //------------------------------------------------------------------------- + + GenTreePtr genMakeConst(const void* cnsAddr, var_types cnsType, GenTreePtr cnsTree, bool dblAlign); + + //------------------------------------------------------------------------- + + void genJumpToThrowHlpBlk(emitJumpKind jumpKind, SpecialCodeKind codeKind, GenTreePtr failBlk = nullptr); + + void genCheckOverflow(GenTreePtr tree); + + //------------------------------------------------------------------------- + // + // Prolog/epilog generation + // + //------------------------------------------------------------------------- + + // + // Prolog functions and data (there are a few exceptions for more generally used things) + // + + void genEstablishFramePointer(int delta, bool reportUnwindData); + void genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbered, RegState* regState); + void genEnregisterIncomingStackArgs(); + void genCheckUseBlockInit(); +#if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING) && defined(FEATURE_SIMD) + void genClearStackVec3ArgUpperBits(); +#endif // FEATURE_UNIX_AMD64_STRUCT_PASSING && FEATURE_SIMD + +#if defined(_TARGET_ARM64_) + bool genInstrWithConstant(instruction ins, + emitAttr attr, + regNumber reg1, + regNumber reg2, + ssize_t imm, + regNumber tmpReg, + bool inUnwindRegion = false); + + void genStackPointerAdjustment(ssize_t spAdjustment, regNumber tmpReg, bool* pTmpRegIsZero); + + void genPrologSaveRegPair(regNumber reg1, + regNumber reg2, + int spOffset, + int spDelta, + bool lastSavedWasPreviousPair, + regNumber tmpReg, + bool* pTmpRegIsZero); + + void genPrologSaveReg(regNumber reg1, int spOffset, int spDelta, regNumber tmpReg, bool* pTmpRegIsZero); + + void genEpilogRestoreRegPair( + regNumber reg1, regNumber reg2, int spOffset, int spDelta, regNumber tmpReg, bool* pTmpRegIsZero); + + void genEpilogRestoreReg(regNumber reg1, int spOffset, int spDelta, regNumber tmpReg, bool* pTmpRegIsZero); + + void genSaveCalleeSavedRegistersHelp(regMaskTP regsToSaveMask, int lowestCalleeSavedOffset, int spDelta); + + void genRestoreCalleeSavedRegistersHelp(regMaskTP regsToRestoreMask, int lowestCalleeSavedOffset, int spDelta); + + void genPushCalleeSavedRegisters(regNumber initReg, bool* pInitRegZeroed); +#else + void genPushCalleeSavedRegisters(); +#endif + + void genAllocLclFrame(unsigned frameSize, regNumber initReg, bool* pInitRegZeroed, regMaskTP maskArgRegsLiveIn); + +#if defined(_TARGET_ARM_) + + void genPushFltRegs(regMaskTP regMask); + void genPopFltRegs(regMaskTP regMask); + regMaskTP genStackAllocRegisterMask(unsigned frameSize, regMaskTP maskCalleeSavedFloat); + + regMaskTP genJmpCallArgMask(); + + void genFreeLclFrame(unsigned frameSize, + /* IN OUT */ bool* pUnwindStarted, + bool jmpEpilog); + + bool genUsedPopToReturn; // True if we use the pop into PC to return, + // False if we didn't and must branch to LR to return. + + // A set of information that is used by funclet prolog and epilog generation. It is collected once, before + // funclet prologs and epilogs are generated, and used by all funclet prologs and epilogs, which must all be the + // same. + struct FuncletFrameInfoDsc + { + regMaskTP fiSaveRegs; // Set of registers saved in the funclet prolog (includes LR) + unsigned fiFunctionCallerSPtoFPdelta; // Delta between caller SP and the frame pointer + unsigned fiSpDelta; // Stack pointer delta + unsigned fiPSP_slot_SP_offset; // PSP slot offset from SP + int fiPSP_slot_CallerSP_offset; // PSP slot offset from Caller SP + }; + + FuncletFrameInfoDsc genFuncletInfo; + +#elif defined(_TARGET_ARM64_) + + // A set of information that is used by funclet prolog and epilog generation. It is collected once, before + // funclet prologs and epilogs are generated, and used by all funclet prologs and epilogs, which must all be the + // same. + struct FuncletFrameInfoDsc + { + regMaskTP fiSaveRegs; // Set of callee-saved registers saved in the funclet prolog (includes LR) + int fiFunction_CallerSP_to_FP_delta; // Delta between caller SP and the frame pointer in the parent function + // (negative) + int fiSP_to_FPLR_save_delta; // FP/LR register save offset from SP (positive) + int fiSP_to_PSP_slot_delta; // PSP slot offset from SP (positive) + int fiSP_to_CalleeSave_delta; // First callee-saved register slot offset from SP (positive) + int fiCallerSP_to_PSP_slot_delta; // PSP slot offset from Caller SP (negative) + int fiFrameType; // Funclet frame types are numbered. See genFuncletProlog() for details. + int fiSpDelta1; // Stack pointer delta 1 (negative) + int fiSpDelta2; // Stack pointer delta 2 (negative) + }; + + FuncletFrameInfoDsc genFuncletInfo; + +#elif defined(_TARGET_AMD64_) + + // A set of information that is used by funclet prolog and epilog generation. It is collected once, before + // funclet prologs and epilogs are generated, and used by all funclet prologs and epilogs, which must all be the + // same. + struct FuncletFrameInfoDsc + { + unsigned fiFunction_InitialSP_to_FP_delta; // Delta between Initial-SP and the frame pointer + unsigned fiSpDelta; // Stack pointer delta + int fiPSP_slot_InitialSP_offset; // PSP slot offset from Initial-SP + }; + + FuncletFrameInfoDsc genFuncletInfo; + +#endif // _TARGET_AMD64_ + +#if defined(_TARGET_XARCH_) && !FEATURE_STACK_FP_X87 + + // Save/Restore callee saved float regs to stack + void genPreserveCalleeSavedFltRegs(unsigned lclFrameSize); + void genRestoreCalleeSavedFltRegs(unsigned lclFrameSize); + +#endif // _TARGET_XARCH_ && FEATURE_STACK_FP_X87 + +#if !FEATURE_STACK_FP_X87 + void genZeroInitFltRegs(const regMaskTP& initFltRegs, const regMaskTP& initDblRegs, const regNumber& initReg); +#endif // !FEATURE_STACK_FP_X87 + + regNumber genGetZeroReg(regNumber initReg, bool* pInitRegZeroed); + + void genZeroInitFrame(int untrLclHi, int untrLclLo, regNumber initReg, bool* pInitRegZeroed); + + void genReportGenericContextArg(regNumber initReg, bool* pInitRegZeroed); + + void genSetGSSecurityCookie(regNumber initReg, bool* pInitRegZeroed); + + void genFinalizeFrame(); + +#ifdef PROFILING_SUPPORTED + void genProfilingEnterCallback(regNumber initReg, bool* pInitRegZeroed); + void genProfilingLeaveCallback(unsigned helper = CORINFO_HELP_PROF_FCN_LEAVE); +#endif // PROFILING_SUPPORTED + + void genPrologPadForReJit(); + + void genEmitCall(int callType, + CORINFO_METHOD_HANDLE methHnd, + INDEBUG_LDISASM_COMMA(CORINFO_SIG_INFO* sigInfo) void* addr X86_ARG(ssize_t argSize), + emitAttr retSize MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize), + IL_OFFSETX ilOffset, + regNumber base = REG_NA, + bool isJump = false, + bool isNoGC = false); + + void genEmitCall(int callType, + CORINFO_METHOD_HANDLE methHnd, + INDEBUG_LDISASM_COMMA(CORINFO_SIG_INFO* sigInfo) GenTreeIndir* indir X86_ARG(ssize_t argSize), + emitAttr retSize MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize), + IL_OFFSETX ilOffset); + + // + // Epilog functions + // + CLANG_FORMAT_COMMENT_ANCHOR; + +#if defined(_TARGET_ARM_) + bool genCanUsePopToReturn(regMaskTP maskPopRegsInt, bool jmpEpilog); +#endif + +#if defined(_TARGET_ARM64_) + + void genPopCalleeSavedRegistersAndFreeLclFrame(bool jmpEpilog); + +#else // !defined(_TARGET_ARM64_) + + void genPopCalleeSavedRegisters(bool jmpEpilog = false); + +#endif // !defined(_TARGET_ARM64_) + + // + // Common or driving functions + // + + void genReserveProlog(BasicBlock* block); // currently unused + void genReserveEpilog(BasicBlock* block); + void genFnProlog(); + void genFnEpilog(BasicBlock* block); + +#if FEATURE_EH_FUNCLETS + + void genReserveFuncletProlog(BasicBlock* block); + void genReserveFuncletEpilog(BasicBlock* block); + void genFuncletProlog(BasicBlock* block); + void genFuncletEpilog(); + void genCaptureFuncletPrologEpilogInfo(); + + void genSetPSPSym(regNumber initReg, bool* pInitRegZeroed); + + void genUpdateCurrentFunclet(BasicBlock* block); + +#else // FEATURE_EH_FUNCLETS + + // This is a no-op when there are no funclets! + void genUpdateCurrentFunclet(BasicBlock* block) + { + return; + } + +#endif // FEATURE_EH_FUNCLETS + + void genGeneratePrologsAndEpilogs(); + +#if defined(DEBUG) && defined(_TARGET_ARM64_) + void genArm64EmitterUnitTests(); +#endif + +#if defined(DEBUG) && defined(LATE_DISASM) && defined(_TARGET_AMD64_) + void genAmd64EmitterUnitTests(); +#endif + +//------------------------------------------------------------------------- +// +// End prolog/epilog generation +// +//------------------------------------------------------------------------- + +/*****************************************************************************/ +#ifdef DEBUGGING_SUPPORT +/*****************************************************************************/ + +#ifdef DEBUG + void genIPmappingDisp(unsigned mappingNum, Compiler::IPmappingDsc* ipMapping); + void genIPmappingListDisp(); +#endif // DEBUG + + void genIPmappingAdd(IL_OFFSETX offset, bool isLabel); + void genIPmappingAddToFront(IL_OFFSETX offset); + void genIPmappingGen(); + + void genEnsureCodeEmitted(IL_OFFSETX offsx); + + //------------------------------------------------------------------------- + // scope info for the variables + + void genSetScopeInfo(unsigned which, + UNATIVE_OFFSET startOffs, + UNATIVE_OFFSET length, + unsigned varNum, + unsigned LVnum, + bool avail, + Compiler::siVarLoc& loc); + + void genSetScopeInfo(); + + void genRemoveBBsection(BasicBlock* head, BasicBlock* tail); + +protected: + /* + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + XX XX + XX ScopeInfo XX + XX XX + XX Keeps track of the scopes during code-generation. XX + XX This is used to translate the local-variable debugging information XX + XX from IL offsets to native code offsets. XX + XX XX + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + */ + + /*****************************************************************************/ + /***************************************************************************** + * ScopeInfo + * + * This class is called during code gen at block-boundaries, and when the + * set of live variables changes. It keeps track of the scope of the variables + * in terms of the native code PC. + */ + +public: + void siInit(); + + void siBeginBlock(BasicBlock* block); + + void siEndBlock(BasicBlock* block); + + virtual void siUpdate(); + + void siCheckVarScope(unsigned varNum, IL_OFFSET offs); + + void siCloseAllOpenScopes(); + +#ifdef DEBUG + void siDispOpenScopes(); +#endif + + /************************************************************************** + * PROTECTED + *************************************************************************/ + +protected: + struct siScope + { + emitLocation scStartLoc; // emitter location of start of scope + emitLocation scEndLoc; // emitter location of end of scope + + unsigned scVarNum; // index into lvaTable + unsigned scLVnum; // 'which' in eeGetLVinfo() + + unsigned scStackLevel; // Only for stk-vars + bool scAvailable : 1; // It has a home / Home recycled - TODO-Cleanup: it appears this is unused (always true) + + siScope* scPrev; + siScope* scNext; + }; + + siScope siOpenScopeList, siScopeList, *siOpenScopeLast, *siScopeLast; + + unsigned siScopeCnt; + + VARSET_TP siLastLife; // Life at last call to siUpdate() + + // Tracks the last entry for each tracked register variable + + siScope* siLatestTrackedScopes[lclMAX_TRACKED]; + + IL_OFFSET siLastEndOffs; // IL offset of the (exclusive) end of the last block processed + +#if FEATURE_EH_FUNCLETS + bool siInFuncletRegion; // Have we seen the start of the funclet region? +#endif // FEATURE_EH_FUNCLETS + + // Functions + + siScope* siNewScope(unsigned LVnum, unsigned varNum); + + void siRemoveFromOpenScopeList(siScope* scope); + + void siEndTrackedScope(unsigned varIndex); + + void siEndScope(unsigned varNum); + + void siEndScope(siScope* scope); + +#ifdef DEBUG + bool siVerifyLocalVarTab(); +#endif + +#ifdef LATE_DISASM +public: + /* virtual */ + const char* siRegVarName(size_t offs, size_t size, unsigned reg); + + /* virtual */ + const char* siStackVarName(size_t offs, size_t size, unsigned reg, unsigned stkOffs); +#endif // LATE_DISASM + +public: + /* + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + XX XX + XX PrologScopeInfo XX + XX XX + XX We need special handling in the prolog block, as the parameter variables XX + XX may not be in the same position described by genLclVarTable - they all XX + XX start out on the stack XX + XX XX + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + */ + +public: + void psiBegProlog(); + + void psiAdjustStackLevel(unsigned size); + + void psiMoveESPtoEBP(); + + void psiMoveToReg(unsigned varNum, regNumber reg = REG_NA, regNumber otherReg = REG_NA); + + void psiMoveToStack(unsigned varNum); + + void psiEndProlog(); + + /************************************************************************** + * PROTECTED + *************************************************************************/ + +protected: + struct psiScope + { + emitLocation scStartLoc; // emitter location of start of scope + emitLocation scEndLoc; // emitter location of end of scope + + unsigned scSlotNum; // index into lclVarTab + unsigned scLVnum; // 'which' in eeGetLVinfo() + + bool scRegister; + + union { + struct + { + regNumberSmall scRegNum; + + // Used for: + // - "other half" of long var on architectures with 32 bit size registers - x86. + // - for System V structs it stores the second register + // used to pass a register passed struct. + regNumberSmall scOtherReg; + } u1; + + struct + { + regNumberSmall scBaseReg; + NATIVE_OFFSET scOffset; + } u2; + }; + + psiScope* scPrev; + psiScope* scNext; + }; + + psiScope psiOpenScopeList, psiScopeList, *psiOpenScopeLast, *psiScopeLast; + + unsigned psiScopeCnt; + + // Implementation Functions + + psiScope* psiNewPrologScope(unsigned LVnum, unsigned slotNum); + + void psiEndPrologScope(psiScope* scope); + + void psSetScopeOffset(psiScope* newScope, LclVarDsc* lclVarDsc1); + +/***************************************************************************** + * TrnslLocalVarInfo + * + * This struct holds the LocalVarInfo in terms of the generated native code + * after a call to genSetScopeInfo() + */ + +#ifdef DEBUG + + struct TrnslLocalVarInfo + { + unsigned tlviVarNum; + unsigned tlviLVnum; + VarName tlviName; + UNATIVE_OFFSET tlviStartPC; + size_t tlviLength; + bool tlviAvailable; + Compiler::siVarLoc tlviVarLoc; + }; + + // Array of scopes of LocalVars in terms of native code + + TrnslLocalVarInfo* genTrnslLocalVarInfo; + unsigned genTrnslLocalVarCount; +#endif + +/*****************************************************************************/ +#endif // DEBUGGING_SUPPORT +/*****************************************************************************/ + +#ifndef LEGACY_BACKEND +#include "codegenlinear.h" +#else // LEGACY_BACKEND +#include "codegenclassic.h" +#endif // LEGACY_BACKEND + + /* + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + XX XX + XX Instruction XX + XX XX + XX The interface to generate a machine-instruction. XX + XX Currently specific to x86 XX + XX TODO-Cleanup: Consider factoring this out of CodeGen XX + XX XX + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + */ + +public: + void instInit(); + + regNumber genGetZeroRegister(); + + void instGen(instruction ins); +#ifdef _TARGET_XARCH_ + void instNop(unsigned size); +#endif + + void inst_JMP(emitJumpKind jmp, BasicBlock* tgtBlock); + + void inst_SET(emitJumpKind condition, regNumber reg); + + void inst_RV(instruction ins, regNumber reg, var_types type, emitAttr size = EA_UNKNOWN); + + void inst_RV_RV(instruction ins, + regNumber reg1, + regNumber reg2, + var_types type = TYP_I_IMPL, + emitAttr size = EA_UNKNOWN, + insFlags flags = INS_FLAGS_DONT_CARE); + + void inst_RV_RV_RV(instruction ins, + regNumber reg1, + regNumber reg2, + regNumber reg3, + emitAttr size, + insFlags flags = INS_FLAGS_DONT_CARE); + + void inst_IV(instruction ins, int val); + void inst_IV_handle(instruction ins, int val); + void inst_FS(instruction ins, unsigned stk = 0); + + void inst_RV_IV(instruction ins, regNumber reg, ssize_t val, emitAttr size, insFlags flags = INS_FLAGS_DONT_CARE); + + void inst_ST_RV(instruction ins, TempDsc* tmp, unsigned ofs, regNumber reg, var_types type); + void inst_ST_IV(instruction ins, TempDsc* tmp, unsigned ofs, int val, var_types type); + + void inst_SA_RV(instruction ins, unsigned ofs, regNumber reg, var_types type); + void inst_SA_IV(instruction ins, unsigned ofs, int val, var_types type); + + void inst_RV_ST( + instruction ins, regNumber reg, TempDsc* tmp, unsigned ofs, var_types type, emitAttr size = EA_UNKNOWN); + void inst_FS_ST(instruction ins, emitAttr size, TempDsc* tmp, unsigned ofs); + + void instEmit_indCall(GenTreePtr call, + size_t argSize, + emitAttr retSize MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize)); + + void instEmit_RM(instruction ins, GenTreePtr tree, GenTreePtr addr, unsigned offs); + + void instEmit_RM_RV(instruction ins, emitAttr size, GenTreePtr tree, regNumber reg, unsigned offs); + + void instEmit_RV_RM(instruction ins, emitAttr size, regNumber reg, GenTreePtr tree, unsigned offs); + + void instEmit_RV_RIA(instruction ins, regNumber reg1, regNumber reg2, unsigned offs); + + void inst_TT(instruction ins, GenTreePtr tree, unsigned offs = 0, int shfv = 0, emitAttr size = EA_UNKNOWN); + + void inst_TT_RV(instruction ins, + GenTreePtr tree, + regNumber reg, + unsigned offs = 0, + emitAttr size = EA_UNKNOWN, + insFlags flags = INS_FLAGS_DONT_CARE); + + void inst_TT_IV(instruction ins, + GenTreePtr tree, + ssize_t val, + unsigned offs = 0, + emitAttr size = EA_UNKNOWN, + insFlags flags = INS_FLAGS_DONT_CARE); + + void inst_RV_AT(instruction ins, + emitAttr size, + var_types type, + regNumber reg, + GenTreePtr tree, + unsigned offs = 0, + insFlags flags = INS_FLAGS_DONT_CARE); + + void inst_AT_IV(instruction ins, emitAttr size, GenTreePtr baseTree, int icon, unsigned offs = 0); + + void inst_RV_TT(instruction ins, + regNumber reg, + GenTreePtr tree, + unsigned offs = 0, + emitAttr size = EA_UNKNOWN, + insFlags flags = INS_FLAGS_DONT_CARE); + + void inst_RV_TT_IV(instruction ins, regNumber reg, GenTreePtr tree, int val); + + void inst_FS_TT(instruction ins, GenTreePtr tree); + + void inst_RV_SH(instruction ins, emitAttr size, regNumber reg, unsigned val, insFlags flags = INS_FLAGS_DONT_CARE); + + void inst_TT_SH(instruction ins, GenTreePtr tree, unsigned val, unsigned offs = 0); + + void inst_RV_CL(instruction ins, regNumber reg, var_types type = TYP_I_IMPL); + + void inst_TT_CL(instruction ins, GenTreePtr tree, unsigned offs = 0); + +#if defined(_TARGET_XARCH_) + void inst_RV_RV_IV(instruction ins, emitAttr size, regNumber reg1, regNumber reg2, unsigned ival); +#endif + + void inst_RV_RR(instruction ins, emitAttr size, regNumber reg1, regNumber reg2); + + void inst_RV_ST(instruction ins, emitAttr size, regNumber reg, GenTreePtr tree); + + void inst_mov_RV_ST(regNumber reg, GenTreePtr tree); + + void instGetAddrMode(GenTreePtr addr, regNumber* baseReg, unsigned* indScale, regNumber* indReg, unsigned* cns); + + void inst_set_SV_var(GenTreePtr tree); + +#ifdef _TARGET_ARM_ + bool arm_Valid_Imm_For_Instr(instruction ins, ssize_t imm, insFlags flags); + bool arm_Valid_Disp_For_LdSt(ssize_t disp, var_types type); + bool arm_Valid_Imm_For_Alu(ssize_t imm); + bool arm_Valid_Imm_For_Mov(ssize_t imm); + bool arm_Valid_Imm_For_Small_Mov(regNumber reg, ssize_t imm, insFlags flags); + bool arm_Valid_Imm_For_Add(ssize_t imm, insFlags flag); + bool arm_Valid_Imm_For_Add_SP(ssize_t imm); + bool arm_Valid_Imm_For_BL(ssize_t addr); + + bool ins_Writes_Dest(instruction ins); +#endif + + bool isMoveIns(instruction ins); + instruction ins_Move_Extend(var_types srcType, bool srcInReg); + + instruction ins_Copy(var_types dstType); + instruction ins_CopyIntToFloat(var_types srcType, var_types dstTyp); + instruction ins_CopyFloatToInt(var_types srcType, var_types dstTyp); + static instruction ins_FloatStore(var_types type = TYP_DOUBLE); + static instruction ins_FloatCopy(var_types type = TYP_DOUBLE); + instruction ins_FloatConv(var_types to, var_types from); + instruction ins_FloatCompare(var_types type); + instruction ins_MathOp(genTreeOps oper, var_types type); + instruction ins_FloatSqrt(var_types type); + + void instGen_Return(unsigned stkArgSize); + + void instGen_MemoryBarrier(); + + void instGen_Set_Reg_To_Zero(emitAttr size, regNumber reg, insFlags flags = INS_FLAGS_DONT_CARE); + + void instGen_Set_Reg_To_Imm(emitAttr size, regNumber reg, ssize_t imm, insFlags flags = INS_FLAGS_DONT_CARE); + + void instGen_Compare_Reg_To_Zero(emitAttr size, regNumber reg); + + void instGen_Compare_Reg_To_Reg(emitAttr size, regNumber reg1, regNumber reg2); + + void instGen_Compare_Reg_To_Imm(emitAttr size, regNumber reg, ssize_t imm); + + void instGen_Load_Reg_From_Lcl(var_types srcType, regNumber dstReg, int varNum, int offs); + + void instGen_Store_Reg_Into_Lcl(var_types dstType, regNumber srcReg, int varNum, int offs); + + void instGen_Store_Imm_Into_Lcl( + var_types dstType, emitAttr sizeAttr, ssize_t imm, int varNum, int offs, regNumber regToUse = REG_NA); + +#ifdef DEBUG + void __cdecl instDisp(instruction ins, bool noNL, const char* fmt, ...); +#endif + +#ifdef _TARGET_XARCH_ + instruction genMapShiftInsToShiftByConstantIns(instruction ins, int shiftByValue); +#endif // _TARGET_XARCH_ +}; + +/*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +XX XX +XX Instruction XX +XX Inline functions XX +XX XX +XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +*/ + +#ifdef _TARGET_XARCH_ +/***************************************************************************** + * + * Generate a floating-point instruction that has one operand given by + * a tree (which has been made addressable). + */ + +inline void CodeGen::inst_FS_TT(instruction ins, GenTreePtr tree) +{ + assert(instIsFP(ins)); + + assert(varTypeIsFloating(tree->gtType)); + + inst_TT(ins, tree, 0); +} +#endif + +/***************************************************************************** + * + * Generate a "shift reg, cl" instruction. + */ + +inline void CodeGen::inst_RV_CL(instruction ins, regNumber reg, var_types type) +{ + inst_RV(ins, reg, type); +} + +#endif // _CODEGEN_H_ |