diff options
Diffstat (limited to 'src/jit/codegenclassic.h')
-rw-r--r-- | src/jit/codegenclassic.h | 706 |
1 files changed, 706 insertions, 0 deletions
diff --git a/src/jit/codegenclassic.h b/src/jit/codegenclassic.h new file mode 100644 index 0000000000..04f49a3541 --- /dev/null +++ b/src/jit/codegenclassic.h @@ -0,0 +1,706 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +// +// This file contains the members of CodeGen that are defined and used +// only by the "classic" JIT backend. It is included by CodeGen.h in the +// definition of the CodeGen class. +// + +#ifndef _CODEGENCLASSIC_H_ +#define _CODEGENCLASSIC_H_ + +#ifdef LEGACY_BACKEND // Not necessary (it's this way in the #include location), but helpful to IntelliSense + +#if FEATURE_STACK_FP_X87 + VARSET_TP genFPregVars; // mask corresponding to genFPregCnt + unsigned genFPdeadRegCnt; // The dead unpopped part of genFPregCnt +#endif // FEATURE_STACK_FP_X87 + + + //------------------------------------------------------------------------- + + void genSetRegToIcon (regNumber reg, + ssize_t val, + var_types type = TYP_INT, + insFlags flags = INS_FLAGS_DONT_CARE); + + regNumber genGetRegSetToIcon (ssize_t val, + regMaskTP regBest = 0, + var_types type = TYP_INT); + void genDecRegBy (regNumber reg, + ssize_t ival, + GenTreePtr tree); + + void genMulRegBy (regNumber reg, + ssize_t ival, + GenTreePtr tree, + var_types dstType = TYP_INT, + bool ovfl = false); + + //------------------------------------------------------------------------- + + bool genRegTrashable (regNumber reg, + GenTreePtr tree); + + // + // Prolog functions and data (there are a few exceptions for more generally used things) + // + + regNumber genLclHeap (GenTreePtr size); + + void genSinglePush (); + + void genSinglePop (); + + + void genDyingVars (VARSET_VALARG_TP beforeSet, + VARSET_VALARG_TP afterSet); + + bool genContainsVarDeath (GenTreePtr from, GenTreePtr to, unsigned varNum); + + void genComputeReg (GenTreePtr tree, + regMaskTP needReg, + RegSet::ExactReg mustReg, + RegSet::KeepReg keepReg, + bool freeOnly = false); + + void genCompIntoFreeReg (GenTreePtr tree, + regMaskTP needReg, + RegSet::KeepReg keepReg); + + void genReleaseReg (GenTreePtr tree); + + void genRecoverReg (GenTreePtr tree, + regMaskTP needReg, + RegSet::KeepReg keepReg); + + void genMoveRegPairHalf (GenTreePtr tree, + regNumber dst, + regNumber src, + int off = 0); + + void genMoveRegPair (GenTreePtr tree, + regMaskTP needReg, + regPairNo newPair); + + void genComputeRegPair (GenTreePtr tree, + regPairNo needRegPair, + regMaskTP avoidReg, + RegSet::KeepReg keepReg, + bool freeOnly = false); + + void genCompIntoFreeRegPair(GenTreePtr tree, + regMaskTP avoidReg, + RegSet::KeepReg keepReg); + + void genComputeAddressable(GenTreePtr tree, + regMaskTP addrReg, + RegSet::KeepReg keptReg, + regMaskTP needReg, + RegSet::KeepReg keepReg, + bool freeOnly = false); + + void genReleaseRegPair (GenTreePtr tree); + + void genRecoverRegPair (GenTreePtr tree, + regPairNo regPair, + RegSet::KeepReg keepReg); + + void genEvalIntoFreeRegPair(GenTreePtr tree, + regPairNo regPair, + regMaskTP avoidReg); + + void genMakeRegPairAvailable(regPairNo regPair); + + bool genMakeIndAddrMode (GenTreePtr addr, + GenTreePtr oper, + bool forLea, + regMaskTP regMask, + RegSet::KeepReg keepReg, + regMaskTP * useMaskPtr, + bool deferOp = false); + + regMaskTP genMakeRvalueAddressable(GenTreePtr tree, + regMaskTP needReg, + RegSet::KeepReg keepReg, + bool forLoadStore, + bool smallOK = false); + + regMaskTP genMakeAddressable (GenTreePtr tree, + regMaskTP needReg, + RegSet::KeepReg keepReg, + bool smallOK = false, + bool deferOK = false); + + regMaskTP genMakeAddrArrElem (GenTreePtr arrElem, + GenTreePtr tree, + regMaskTP needReg, + RegSet::KeepReg keepReg); + + regMaskTP genMakeAddressable2 (GenTreePtr tree, + regMaskTP needReg, + RegSet::KeepReg keepReg, + bool forLoadStore, + bool smallOK = false, + bool deferOK = false, + bool evalSideEffs = false); + + bool genStillAddressable (GenTreePtr tree); + + + regMaskTP genRestoreAddrMode (GenTreePtr addr, + GenTreePtr tree, + bool lockPhase); + + regMaskTP genRestAddressable (GenTreePtr tree, + regMaskTP addrReg, + regMaskTP lockMask); + + regMaskTP genKeepAddressable (GenTreePtr tree, + regMaskTP addrReg, + regMaskTP avoidMask = RBM_NONE); + + void genDoneAddressable (GenTreePtr tree, + regMaskTP addrReg, + RegSet::KeepReg keptReg); + + GenTreePtr genMakeAddrOrFPstk (GenTreePtr tree, + regMaskTP * regMaskPtr, + bool roundResult); + + void genEmitGSCookieCheck(bool pushReg); + + void genEvalSideEffects (GenTreePtr tree); + + + void genCondJump (GenTreePtr cond, + BasicBlock * destTrue = NULL, + BasicBlock * destFalse = NULL, + bool bStackFPFixup = true); + + + emitJumpKind genCondSetFlags (GenTreePtr cond); + + + void genJCC (genTreeOps cmp, + BasicBlock * block, + var_types type); + + void genJccLongHi (genTreeOps cmp, + BasicBlock * jumpTrue, + BasicBlock * jumpFalse, + bool unsOper = false); + + void genJccLongLo (genTreeOps cmp, + BasicBlock * jumpTrue, + BasicBlock * jumpFalse); + + void genCondJumpLng (GenTreePtr cond, + BasicBlock * jumpTrue, + BasicBlock * jumpFalse, + bool bFPTransition = false); + + bool genUse_fcomip(); + + void genTableSwitch (regNumber reg, + unsigned jumpCnt, + BasicBlock ** jumpTab); + + regMaskTP WriteBarrier (GenTreePtr tgt, + GenTreePtr assignVal, + regMaskTP addrReg); + + void genCodeForTreeConst (GenTreePtr tree, + regMaskTP destReg, + regMaskTP bestReg = RBM_NONE); + + void genCodeForTreeLeaf (GenTreePtr tree, + regMaskTP destReg, + regMaskTP bestReg = RBM_NONE); + + // If "tree" is a comma node, generates code for the left comma arguments, + // in order, returning the first right argument in the list that is not + // a comma node. + GenTreePtr genCodeForCommaTree (GenTreePtr tree); + + void genCodeForTreeLeaf_GT_JMP (GenTreePtr tree); + + static Compiler::fgWalkPreFn fgIsVarAssignedTo; + + void genCodeForQmark (GenTreePtr tree, + regMaskTP destReg, + regMaskTP bestReg); + + bool genCodeForQmarkWithCMOV (GenTreePtr tree, + regMaskTP destReg, + regMaskTP bestReg); + +#ifdef _TARGET_XARCH_ + void genCodeForMultEAX (GenTreePtr tree); +#endif +#ifdef _TARGET_ARM_ + void genCodeForMult64 (GenTreePtr tree, + regMaskTP destReg, + regMaskTP bestReg); +#endif + + void genCodeForTreeSmpBinArithLogOp (GenTreePtr tree, + regMaskTP destReg, + regMaskTP bestReg); + + void genCodeForTreeSmpBinArithLogAsgOp (GenTreePtr tree, + regMaskTP destReg, + regMaskTP bestReg); + + void genCodeForUnsignedMod (GenTreePtr tree, + regMaskTP destReg, + regMaskTP bestReg); + + void genCodeForSignedMod (GenTreePtr tree, + regMaskTP destReg, + regMaskTP bestReg); + + void genCodeForUnsignedDiv (GenTreePtr tree, + regMaskTP destReg, + regMaskTP bestReg); + + void genCodeForSignedDiv (GenTreePtr tree, + regMaskTP destReg, + regMaskTP bestReg); + + void genCodeForGeneralDivide (GenTreePtr tree, + regMaskTP destReg, + regMaskTP bestReg); + + void genCodeForAsgShift (GenTreePtr tree, + regMaskTP destReg, + regMaskTP bestReg); + + void genCodeForShift (GenTreePtr tree, + regMaskTP destReg, + regMaskTP bestReg); + + void genCodeForRelop (GenTreePtr tree, + regMaskTP destReg, + regMaskTP bestReg); + + void genCodeForTreeSmpOp (GenTreePtr tree, + regMaskTP destReg, + regMaskTP bestReg = RBM_NONE); + + regNumber genIntegerCast(GenTree *tree, regMaskTP needReg, regMaskTP bestReg); + + void genCodeForNumericCast(GenTreePtr tree, + regMaskTP destReg, + regMaskTP bestReg); + + void genCodeForTreeSmpOp_GT_ADDR (GenTreePtr tree, + regMaskTP destReg, + regMaskTP bestReg = RBM_NONE); + + void genCodeForTreeSmpOpAsg (GenTreePtr tree); + + void genCodeForTreeSmpOpAsg_DONE_ASSG(GenTreePtr tree, + regMaskTP addrReg, + regNumber reg, + bool ovfl); + + void genCodeForTreeSpecialOp (GenTreePtr tree, + regMaskTP destReg, + regMaskTP bestReg = RBM_NONE); + + void genCodeForTree (GenTreePtr tree, + regMaskTP destReg, + regMaskTP bestReg = RBM_NONE); + + void genCodeForTree_DONE_LIFE (GenTreePtr tree, + regNumber reg) + { + /* We've computed the value of 'tree' into 'reg' */ + + assert(reg != 0xFEEFFAAFu); + assert(!IsUninitialized(reg)); + + genMarkTreeInReg(tree, reg); + } + + void genCodeForTree_DONE_LIFE (GenTreePtr tree, + regPairNo regPair) + { + /* We've computed the value of 'tree' into 'regPair' */ + + genMarkTreeInRegPair(tree, regPair); + } + + void genCodeForTree_DONE (GenTreePtr tree, + regNumber reg) + { + /* Check whether this subtree has freed up any variables */ + + genUpdateLife(tree); + + genCodeForTree_DONE_LIFE(tree, reg); + } + + void genCodeForTree_REG_VAR1 (GenTreePtr tree) + { + /* Value is already in a register */ + + regNumber reg = tree->gtRegNum; + + gcInfo.gcMarkRegPtrVal(reg, tree->TypeGet()); + + genCodeForTree_DONE(tree, reg); + } + + void genCodeForTreeLng (GenTreePtr tree, + regMaskTP needReg, + regMaskTP avoidReg); + + regPairNo genCodeForLongModInt(GenTreePtr tree, + regMaskTP needReg); + + unsigned genRegCountForLiveIntEnregVars(GenTreePtr tree); + +#ifdef _TARGET_ARM_ + void genStoreFromFltRetRegs (GenTreePtr tree); + void genLoadIntoFltRetRegs (GenTreePtr tree); + void genLdStFltRetRegsPromotedVar (LclVarDsc* varDsc, bool isLoadIntoFltReg); +#endif + +#if CPU_HAS_FP_SUPPORT + void genRoundFpExpression(GenTreePtr op, + var_types type = TYP_UNDEF); + void genCodeForTreeFlt (GenTreePtr tree, + regMaskTP needReg = RBM_ALLFLOAT, + regMaskTP bestReg = RBM_NONE); +#endif + +// FP stuff +#include "fp.h" + + void genCodeForJumpTable (GenTreePtr tree); + void genCodeForSwitchTable (GenTreePtr tree); + void genCodeForSwitch (GenTreePtr tree); + + regMaskTP genPushRegs (regMaskTP regs, + regMaskTP * byrefRegs, + regMaskTP * noRefRegs); + void genPopRegs (regMaskTP regs, + regMaskTP byrefRegs, + regMaskTP noRefRegs); + + size_t genPushArgList (GenTreePtr call); + +#ifdef _TARGET_ARM_ + // We are generating code for a promoted struct local variable. Fill the next slot (register or + // 4-byte stack slot) with one or more field variables of the promoted struct local -- or 2 such slots + // if the next field is a 64-bit value. + // The arguments are: + // "arg" is the current argument node. + // + // "curArgTabEntry" arg table entry pointer for "arg". + // + // "promotedStructLocalVarDesc" describes the struct local being copied, assumed non-NULL. + // + // "fieldSize" is somewhat misnamed; it must be the element in the struct's GC layout describing the next slot + // of the struct -- it will be EA_4BYTE, EA_GCREF, or EA_BYREF. + // + // "*pNextPromotedStructFieldVar" must be the the local variable number of the next field variable to copy; + // this location will be updated by the call to reflect the bytes that are copied. + // + // "*pBytesOfNextSlotOfCurPromotedStruct" must be the number of bytes within the struct local at which the next + // slot to be copied starts. This location will be updated by the call to reflect the bytes that are copied. + // + // "*pCurRegNum" must be the current argument register number, and will be updated if argument registers are filled. + // + // "argOffset" must be the offset of the next slot to be filled in the outgoing argument area, if the argument is to be + // put in the outgoing arg area of the stack (or else should be INT_MAX if the next slot to be filled is a register). + // (Strictly speaking, after the addition of "argOffsetOfFirstStackSlot", this arg is redundant, and is only used + // in assertions, and could be removed.) + // + // "fieldOffsetOfFirstStackSlot" must be the offset within the promoted struct local of the first slot that should be + // copied to the outgoing argument area -- non-zero only in the case of a struct that spans registers and stack slots. + // + // "argOffsetOfFirstStackSlot" must be the 4-byte-aligned offset of the first offset in the outgoing argument area which could + // contain part of the struct. (Explicit alignment may mean it doesn't actually contain part of the struct.) + // + // "*deadFieldVarRegs" is an out parameter, the set of registers containing promoted field variables that become dead after + // this (implicit) use. + // + // "*pRegTmp" -- if a temporary register is needed, and this is not REG_STK, uses that register. Otherwise, if it is REG_STK, + // allocates a register, uses it, and sets "*pRegTmp" to the allocated register. + // + // Returns "true" iff it filled two slots with an 8-byte value. + bool genFillSlotFromPromotedStruct(GenTreePtr arg, + fgArgTabEntryPtr curArgTabEntry, + LclVarDsc* promotedStructLocalVarDesc, + emitAttr fieldSize, + unsigned* pNextPromotedStructFieldVar, // IN/OUT + unsigned *pBytesOfNextSlotOfCurPromotedStruct, // IN/OUT + regNumber* pCurRegNum, // IN/OUT + int argOffset, + int fieldOffsetOfFirstStackSlot, + int argOffsetOfFirstStackSlot, + regMaskTP* deadFieldVarRegs, // OUT + regNumber* pRegTmp); // IN/OUT + + +#endif // _TARGET_ARM_ + // Requires that "curr" is a cpblk. If the RHS is a promoted struct local, + // then returns a regMaskTP representing the set of registers holding + // fieldVars of the RHS that go dead with this use (as determined by the live set + // of cpBlk). + regMaskTP genFindDeadFieldRegs(GenTreePtr cpBlk); + + void SetupLateArgs (GenTreePtr call); + +#ifdef _TARGET_ARM_ + void PushMkRefAnyArg (GenTreePtr mkRefAnyTree, + fgArgTabEntryPtr curArgTabEntry, + regMaskTP regNeedMask); +#endif // _TARGET_ARM_ + + regMaskTP genLoadIndirectCallTarget(GenTreePtr call); + + regMaskTP genCodeForCall (GenTreePtr call, + bool valUsed); + + GenTreePtr genGetAddrModeBase (GenTreePtr tree); + + GenTreePtr genIsAddrMode (GenTreePtr tree, + GenTreePtr * indxPtr); +private: + + bool genIsLocalLastUse (GenTreePtr tree); + + bool genIsRegCandidateLocal(GenTreePtr tree); + + //========================================================================= + // Debugging support + //========================================================================= + + + +#if FEATURE_STACK_FP_X87 + /* + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + XX XX + XX Flat FP model XX + XX XX + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + */ + + bool StackFPIsSameAsFloat (double d); + bool FlatFPSameRegisters (FlatFPStateX87* pState, regMaskTP mask); + + // FlatFPStateX87_ functions are the actual verbs to do stuff + // like doing a transition, loading register, etc. It's also + // responsible for emitting the x87 code to do so. We keep + // them in Compiler because we don't want to store a pointer to the + // emitter. + void FlatFPX87_Kill (FlatFPStateX87* pState, unsigned iVirtual); + void FlatFPX87_PushVirtual (FlatFPStateX87* pState, unsigned iRegister, bool bEmitCode = true); + unsigned FlatFPX87_Pop (FlatFPStateX87* pState, bool bEmitCode = true); + unsigned FlatFPX87_Top (FlatFPStateX87* pState, bool bEmitCode = true); + void FlatFPX87_Unload (FlatFPStateX87* pState, unsigned iVirtual, bool bEmitCode = true); +#endif + + // Codegen functions. This is the API that codegen will use + regMaskTP genPushArgumentStackFP (GenTreePtr arg); + void genRoundFpExpressionStackFP (GenTreePtr op, var_types type = TYP_UNDEF); + void genCodeForTreeStackFP_Const (GenTreePtr tree); + void genCodeForTreeStackFP_Leaf (GenTreePtr tree); + void genCodeForTreeStackFP_SmpOp (GenTreePtr tree); + void genCodeForTreeStackFP_Special (GenTreePtr tree); + void genCodeForTreeStackFP_Cast (GenTreePtr tree); + void genCodeForTreeStackFP (GenTreePtr tree); + void genCondJumpFltStackFP (GenTreePtr cond, + BasicBlock * jumpTrue, + BasicBlock * jumpFalse, + bool bDoTransition = true); + void genCondJumpFloat (GenTreePtr cond, + BasicBlock * jumpTrue, + BasicBlock * jumpFalse); + void genCondJumpLngStackFP (GenTreePtr cond, + BasicBlock * jumpTrue, + BasicBlock * jumpFalse); + + void genFloatConst(GenTree *tree, RegSet::RegisterPreference *pref); + void genFloatLeaf(GenTree *tree, RegSet::RegisterPreference *pref); + void genFloatSimple(GenTree *tree, RegSet::RegisterPreference *pref); + void genFloatMath(GenTree *tree, RegSet::RegisterPreference *pref); + void genFloatCheckFinite(GenTree *tree, RegSet::RegisterPreference *pref); + void genLoadFloat(GenTreePtr tree, regNumber reg); + void genFloatAssign(GenTree *tree); + void genFloatArith(GenTree *tree, RegSet::RegisterPreference *pref); + void genFloatAsgArith(GenTree *tree); + + regNumber genAssignArithFloat(genTreeOps oper, + GenTreePtr dst, regNumber dstreg, + GenTreePtr src, regNumber srcreg); + + + GenTreePtr genMakeAddressableFloat(GenTreePtr tree, + regMaskTP * regMaskIntPtr, regMaskTP * regMaskFltPtr, + bool bCollapseConstantDoubles = true); + + void genCodeForTreeFloat(GenTreePtr tree, + RegSet::RegisterPreference *pref = NULL); + + void genCodeForTreeFloat(GenTreePtr tree, + regMaskTP needReg, regMaskTP bestReg); + + regNumber genArithmFloat(genTreeOps oper, + GenTreePtr dst, regNumber dstreg, + GenTreePtr src, regNumber srcreg, + bool bReverse); + void genCodeForTreeCastFloat(GenTreePtr tree, RegSet::RegisterPreference *pref); + void genCodeForTreeCastToFloat(GenTreePtr tree, RegSet::RegisterPreference *pref); + void genCodeForTreeCastFromFloat(GenTreePtr tree, RegSet::RegisterPreference *pref); + void genKeepAddressableFloat(GenTreePtr tree, regMaskTP * regMaskIntPtr, regMaskTP * regMaskFltPtr); + void genDoneAddressableFloat(GenTreePtr tree, regMaskTP addrRegInt, regMaskTP addrRegFlt, RegSet::KeepReg keptReg); + void genComputeAddressableFloat(GenTreePtr tree, regMaskTP addrRegInt, regMaskTP addrRegFlt, RegSet::KeepReg keptReg, regMaskTP needReg, RegSet::KeepReg keepReg, bool freeOnly = false); + void genRoundFloatExpression(GenTreePtr op, var_types type); + + + +#if FEATURE_STACK_FP_X87 + // Assumes then block will be generated before else block. + struct QmarkStateStackFP + { + FlatFPStateX87 stackState; + }; + + void genQMarkRegVarTransition (GenTreePtr nextNode, VARSET_VALARG_TP liveset); + void genQMarkBeforeElseStackFP (QmarkStateStackFP* pState, VARSET_VALARG_TP varsetCond, GenTreePtr nextNode); + void genQMarkAfterElseBlockStackFP (QmarkStateStackFP* pState, VARSET_VALARG_TP varsetCond, GenTreePtr nextNode); + void genQMarkAfterThenBlockStackFP (QmarkStateStackFP* pState); + +#endif + + GenTreePtr genMakeAddressableStackFP (GenTreePtr tree, regMaskTP * regMaskIntPtr, regMaskTP * regMaskFltPtr, bool bCollapseConstantDoubles = true); + void genKeepAddressableStackFP (GenTreePtr tree, regMaskTP * regMaskIntPtr, regMaskTP * regMaskFltPtr); + void genDoneAddressableStackFP (GenTreePtr tree, regMaskTP addrRegInt, regMaskTP addrRegFlt, RegSet::KeepReg keptReg); + + + void genCodeForTreeStackFP_Asg (GenTreePtr tree); + void genCodeForTreeStackFP_AsgArithm (GenTreePtr tree); + void genCodeForTreeStackFP_Arithm (GenTreePtr tree); + void genCodeForTreeStackFP_DONE (GenTreePtr tree, regNumber reg); + void genCodeForTreeFloat_DONE (GenTreePtr tree, regNumber reg); + + void genSetupStateStackFP (BasicBlock* block); + regMaskTP genRegMaskFromLivenessStackFP (VARSET_VALARG_TP varset); + + // bReverse means make op1 addressable and codegen for op2. + // If op1 or op2 are comma expressions, will do code-gen for their non-last comma parts, + // and set op1 and op2 to the remaining non-comma expressions. + void genSetupForOpStackFP (GenTreePtr& op1, GenTreePtr& op2, + bool bReverse, + bool bMakeOp1Addressable, + bool bOp1ReadOnly, + bool bOp2ReadOnly); + + +#if FEATURE_STACK_FP_X87 + +#ifdef DEBUG + bool ConsistentAfterStatementStackFP (); +#endif + +private: + void SpillTempsStackFP (regMaskTP canSpillMask); + void SpillForCallStackFP (); + void UnspillRegVarsStackFp (); + + // Transition API. Takes care of the stack matching of basicblock boundaries + void genCodeForPrologStackFP (); + void genCodeForEndBlockTransitionStackFP (BasicBlock* block); + + void genCodeForBBTransitionStackFP (BasicBlock* pDst); + void genCodeForTransitionStackFP (FlatFPStateX87* pSrc, FlatFPStateX87* pDst); + void genCodeForTransitionFromMask (FlatFPStateX87* pSrc, regMaskTP mask, bool bEmitCode = true); + BasicBlock* genTransitionBlockStackFP (FlatFPStateX87* pState, BasicBlock* pFrom, BasicBlock* pTarget); + + // This is the API codegen will use to emit virtual fp code. In theory, nobody above this API + // should know about x87 instructions. + + int genNumberTemps (); + void genDiscardStackFP (GenTreePtr tree); + void genRegRenameWithMasks (regNumber dstReg, regNumber srcReg); + void genRegVarBirthStackFP (GenTreePtr tree); + void genRegVarBirthStackFP (LclVarDsc* varDsc); + void genRegVarDeathStackFP (GenTreePtr tree); + void genRegVarDeathStackFP (LclVarDsc* varDsc); + void genLoadStackFP (GenTreePtr tree, regNumber reg); + void genMovStackFP (GenTreePtr dst, regNumber dstreg, GenTreePtr src, regNumber srcreg); + bool genCompInsStackFP (GenTreePtr tos, GenTreePtr other); + regNumber genArithmStackFP (genTreeOps oper, GenTreePtr dst, regNumber dstreg, GenTreePtr src, regNumber srcreg, bool bReverse); + regNumber genAsgArithmStackFP (genTreeOps oper, GenTreePtr dst, regNumber dstreg, GenTreePtr src, regNumber srcreg); + void genCondJmpInsStackFP (emitJumpKind jumpKind, + BasicBlock * jumpTrue, + BasicBlock * jumpFalse, + bool bDoTransition = true); + void genTableSwitchStackFP (regNumber reg, + unsigned jumpCnt, + BasicBlock ** jumpTab); + + void JitDumpFPState (); +#else // !FEATURE_STACK_FP_X87 + void SpillForCallRegisterFP (regMaskTP noSpillMask); +#endif // !FEATURE_STACK_FP_X87 + + // When bOnlyNoMemAccess = true, the load will be generated only for constant loading that doesn't + // involve memory accesses, (ie: fldz for positive zero, or fld1 for 1). Will return true the function + // did the load + bool genConstantLoadStackFP (GenTreePtr tree, + bool bOnlyNoMemAccess = false); + void genEndOfStatement (); + + +#if FEATURE_STACK_FP_X87 + struct genRegVarDiesInSubTreeData + { + regNumber reg; + bool result; + }; + static Compiler::fgWalkPreFn genRegVarDiesInSubTreeWorker; + bool genRegVarDiesInSubTree (GenTreePtr tree, regNumber reg); +#endif // FEATURE_STACK_FP_X87 + + // Float spill + void UnspillFloat (RegSet::SpillDsc *spillDsc); + void UnspillFloat (GenTreePtr tree); + void UnspillFloat (LclVarDsc * varDsc); + void UnspillFloatMachineDep (RegSet::SpillDsc *spillDsc); + void UnspillFloatMachineDep (RegSet::SpillDsc* spillDsc, bool useSameReg); + void RemoveSpillDsc (RegSet::SpillDsc* spillDsc); + +protected : + struct genLivenessSet + { + VARSET_TP liveSet; + VARSET_TP varPtrSet; + regMaskSmall maskVars; + regMaskSmall gcRefRegs; + regMaskSmall byRefRegs; + + genLivenessSet() : VARSET_INIT_NOCOPY(liveSet, VarSetOps::UninitVal()), + VARSET_INIT_NOCOPY(varPtrSet, VarSetOps::UninitVal()) + {} + }; + + void saveLiveness (genLivenessSet * ls); + void restoreLiveness (genLivenessSet * ls); + void checkLiveness (genLivenessSet * ls); + void unspillLiveness (genLivenessSet * ls); + +#endif // LEGACY_BACKEND + +#endif _CODEGENCLASSIC_H_ |