diff options
Diffstat (limited to 'src/jit/codegenclassic.h')
-rw-r--r-- | src/jit/codegenclassic.h | 606 |
1 files changed, 606 insertions, 0 deletions
diff --git a/src/jit/codegenclassic.h b/src/jit/codegenclassic.h new file mode 100644 index 0000000000..81b7b34194 --- /dev/null +++ b/src/jit/codegenclassic.h @@ -0,0 +1,606 @@ +// 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 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 + +public: +regNumber genIsEnregisteredIntVariable(GenTreePtr tree); + +void sched_AM(instruction ins, + emitAttr size, + regNumber ireg, + bool rdst, + GenTreePtr tree, + unsigned offs, + bool cons = false, + int cval = 0, + insFlags flags = INS_FLAGS_DONT_CARE); + +protected: +#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 genIncRegBy(regNumber reg, ssize_t ival, GenTreePtr tree, var_types dstType = TYP_INT, bool ovfl = false); + +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) +// + +regMaskTP genPInvokeMethodProlog(regMaskTP initRegs); + +void genPInvokeMethodEpilog(); + +regNumber genPInvokeCallProlog(LclVarDsc* varDsc, + int argSize, + CORINFO_METHOD_HANDLE methodToken, + BasicBlock* returnLabel); + +void genPInvokeCallEpilog(LclVarDsc* varDsc, regMaskTP retVal); + +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 genCodeForCopyObj(GenTreePtr tree, regMaskTP destReg); + +void genCodeForBlkOp(GenTreePtr tree, regMaskTP destReg); + +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); + +//------------------------------------------------------------------------- +// +// If we know that the flags register is set to a value that corresponds +// to the current value of a register or variable, the following values +// record that information. +// + +emitLocation genFlagsEqLoc; +regNumber genFlagsEqReg; +unsigned genFlagsEqVar; + +void genFlagsEqualToNone(); +void genFlagsEqualToReg(GenTreePtr tree, regNumber reg); +void genFlagsEqualToVar(GenTreePtr tree, unsigned var); +bool genFlagsAreReg(regNumber reg); +bool genFlagsAreVar(unsigned var); + +#endif // LEGACY_BACKEND + +#endif // _CODEGENCLASSIC_H_ |