}
};
-/*****************************************************************************/
-
-extern BasicBlock* __cdecl verAllocBasicBlock();
-
-#ifdef DEBUG
-extern void __cdecl verDispBasicBlocks();
-#endif
-
/*****************************************************************************
*
* The following call-backs supplied by the client; it's used by the code
void genCodeForLockAdd(GenTreeOp* node);
#endif
- //-------------------------------------------------------------------------
- // 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.
#ifdef DEBUG
static const char* genSizeStr(emitAttr size);
-
- void genStressRegs(GenTree* tree);
#endif // DEBUG
void genCodeForBBlist();
void genSetScopeInfo();
- void genRemoveBBsection(BasicBlock* head, BasicBlock* tail);
-
protected:
/*
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
void genSIMDZero(var_types targetType, var_types baseType, regNumber targetReg);
void genSIMDIntrinsicInit(GenTreeSIMD* simdNode);
void genSIMDIntrinsicInitN(GenTreeSIMD* simdNode);
- void genSIMDIntrinsicInitArray(GenTreeSIMD* simdNode);
void genSIMDIntrinsicUnOp(GenTreeSIMD* simdNode);
void genSIMDIntrinsicBinOp(GenTreeSIMD* simdNode);
void genSIMDIntrinsicRelOp(GenTreeSIMD* simdNode);
void genSIMDExtractUpperHalf(GenTreeSIMD* simdNode, regNumber srcReg, regNumber tgtReg);
void genSIMDIntrinsicWiden(GenTreeSIMD* simdNode);
void genSIMDIntrinsic(GenTreeSIMD* simdNode);
- void genSIMDCheck(GenTree* treeNode);
// TYP_SIMD12 (i.e Vector3 of size 12 bytes) is not a hardware supported size and requires
// two reads/writes on 64-bit targets. These routines abstract reading/writing of Vector3
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, target_ssize_t val, emitAttr size, insFlags flags = INS_FLAGS_DONT_CARE);
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(GenTreeCall* call,
- size_t argSize,
- emitAttr retSize MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize));
-
- void instEmit_RM(instruction ins, GenTree* tree, GenTree* addr, unsigned offs);
-
- void instEmit_RM_RV(instruction ins, emitAttr size, GenTree* tree, regNumber reg, unsigned offs);
-
- void instEmit_RV_RM(instruction ins, emitAttr size, regNumber reg, GenTree* tree, unsigned offs);
-
- void instEmit_RV_RIA(instruction ins, regNumber reg1, regNumber reg2, unsigned offs);
-
void inst_TT(instruction ins, GenTree* tree, unsigned offs = 0, int shfv = 0, emitAttr size = EA_UNKNOWN);
void inst_TT_RV(instruction ins,
emitAttr size = EA_UNKNOWN,
insFlags flags = INS_FLAGS_DONT_CARE);
- void inst_TT_IV(instruction ins,
- GenTree* 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,
- GenTree* tree,
- unsigned offs = 0,
- insFlags flags = INS_FLAGS_DONT_CARE);
-
- void inst_AT_IV(instruction ins, emitAttr size, GenTree* baseTree, int icon, unsigned offs = 0);
-
void inst_RV_TT(instruction ins,
regNumber reg,
GenTree* tree,
emitAttr size = EA_UNKNOWN,
insFlags flags = INS_FLAGS_DONT_CARE);
- void inst_RV_TT_IV(instruction ins, regNumber reg, GenTree* tree, int val);
-
void inst_FS_TT(instruction ins, GenTree* tree);
void inst_RV_SH(instruction ins, emitAttr size, regNumber reg, unsigned val, insFlags flags = INS_FLAGS_DONT_CARE);
void inst_mov_RV_ST(regNumber reg, GenTree* tree);
- void instGetAddrMode(GenTree* addr, regNumber* baseReg, unsigned* indScale, regNumber* indReg, unsigned* cns);
-
void inst_set_SV_var(GenTree* tree);
#ifdef _TARGET_ARM_
#endif // SCALED_ADDR_MODES
ssize_t* cnsPtr) = 0;
- void genCalcFrameSize();
-
GCInfo gcInfo;
RegSet regSet;
// Methods for spilling - used by RegSet
void spillReg(var_types type, TempDsc* tmp, regNumber reg);
void reloadReg(var_types type, TempDsc* tmp, regNumber reg);
- void reloadFloatReg(var_types type, TempDsc* tmp, regNumber reg);
// The following method is used by xarch emitter for handling contained tree temps.
TempDsc* getSpillTempDsc(GenTree* tree);
Compiler* pComp,
RefCountState state = RCS_NORMAL,
bool propagate = true);
- void setPrefReg(regNumber regNum, Compiler* pComp);
- void addPrefReg(regMaskTP regMask, Compiler* pComp);
bool IsFloatRegType() const
{
return isFloatRegType(lvType) || lvIsHfaRegArg();
int m_numFilteredMethods;
CompTimeInfo m_filtered;
- // This method computes the number of cycles/sec for the current machine. The cycles are those counted
- // by GetThreadCycleTime; we assume that these are of equal duration, though that is not necessarily true.
- // If any OS interaction fails, returns 0.0.
- double CyclesPerSecond();
-
// This can use what ever data you want to determine if the value to be added
// belongs in the filtered section (it's always included in the unfiltered section)
bool IncludedInFilteredData(CompTimeInfo& info);
GenTree* gtNewSIMDVectorOne(var_types simdType, var_types baseType, unsigned size);
#endif
- GenTreeBlk* gtNewBlkOpNode(
- genTreeOps oper, GenTree* dst, GenTree* srcOrFillVal, GenTree* sizeOrClsTok, bool isVolatile);
-
GenTree* gtNewBlkOpNode(GenTree* dst, GenTree* srcOrFillVal, unsigned size, bool isVolatile, bool isCopyBlock);
GenTree* gtNewPutArgReg(var_types type, GenTree* arg, regNumber argReg);
GenTree** gtFindLink(GenTree* stmt, GenTree* node);
bool gtHasCatchArg(GenTree* tree);
- bool gtHasUnmanagedCall(GenTree* tree);
typedef ArrayStack<GenTree*> GenTreeStack;
unsigned lvaLclSize(unsigned varNum);
unsigned lvaLclExactSize(unsigned varNum);
- bool lvaLclVarRefs(GenTree* tree, GenTree** findPtr, varRefKinds* refsPtr, void* result);
-
- // Call lvaLclVarRefs on "true"; accumulate "*result" into whichever of
- // "allVars" and "trkdVars" is indiated by the nullness of "findPtr"; return
- // the return result.
- bool lvaLclVarRefsAccum(
- GenTree* tree, GenTree** findPtr, varRefKinds* refsPtr, ALLVARSET_TP* allVars, VARSET_TP* trkdVars);
-
- // If "findPtr" is non-NULL, assumes "result" is an "ALLVARSET_TP*", and
- // (destructively) unions "allVars" into "*result". Otherwise, assumes "result" is a "VARSET_TP*",
- // and (destructively) unions "trkedVars" into "*result".
- void lvaLclVarRefsAccumIntoRes(GenTree** findPtr,
- void* result,
- ALLVARSET_VALARG_TP allVars,
- VARSET_VALARG_TP trkdVars);
-
bool lvaHaveManyLocals() const;
unsigned lvaGrabTemp(bool shortLifetime DEBUGARG(const char* reason));
};
BlockListNode* impBlockListNodeFreeList;
- BlockListNode* AllocBlockListNode();
void FreeBlockListNode(BlockListNode* node);
bool impIsValueType(typeInfo* pTypeInfo);
bool fgBlockIsGoodTailDuplicationCandidate(BasicBlock* block);
- bool fgOptimizeFallthroughTailDup(BasicBlock* block, BasicBlock* target);
-
bool fgOptimizeEmptyBlock(BasicBlock* block);
bool fgOptimizeBranchToEmptyUnconditional(BasicBlock* block, BasicBlock* bDest);
#endif
static GenTree* fgGetFirstNode(GenTree* tree);
- static bool fgTreeIsInStmt(GenTree* tree, GenTreeStmt* stmt);
- void fgTraverseRPO();
//--------------------- Walking the trees in the IR -----------------------
private:
GenTree* fgInsertStmtListAfter(BasicBlock* block, GenTree* stmtAfter, GenTree* stmtList);
- GenTree* fgMorphSplitTree(GenTree** splitPoint, GenTree* stmt, BasicBlock* blk);
-
// Create a new temporary variable to hold the result of *ppTree,
// and transform the graph accordingly.
GenTree* fgInsertCommaFormTemp(GenTree** ppTree, CORINFO_CLASS_HANDLE structType = nullptr);
GenTree* fgMorphCopyBlock(GenTree* tree);
GenTree* fgMorphForRegisterFP(GenTree* tree);
GenTree* fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac = nullptr);
- GenTree* fgMorphSmpOpPre(GenTree* tree);
GenTree* fgMorphModToSubMulDiv(GenTreeOp* tree);
GenTree* fgMorphSmpOpOptional(GenTreeOp* tree);
GenTree* fgMorphRecognizeBoxNullable(GenTree* compare);
public:
void optInit();
-protected:
- LclVarDsc* optIsTrackedLocal(GenTree* tree);
-
-public:
void optRemoveRangeCheck(GenTree* tree, GenTree* stmt);
bool optIsRangeCheckRemovable(GenTree* tree);
public:
void optVnNonNullPropCurStmt(BasicBlock* block, GenTree* stmt, GenTree* tree);
fgWalkResult optVNConstantPropCurStmt(BasicBlock* block, GenTree* stmt, GenTree* tree);
- GenTree* optVNConstantPropOnRelOp(GenTree* tree);
GenTree* optVNConstantPropOnJTrue(BasicBlock* block, GenTree* stmt, GenTree* test);
GenTree* optVNConstantPropOnTree(BasicBlock* block, GenTree* stmt, GenTree* tree);
GenTree* optPrepareTreeForReplacement(GenTree* extractTree, GenTree* replaceTree);
GenTree* optConstantAssertionProp(AssertionDsc* curAssertion,
GenTree* tree,
GenTree* stmt DEBUGARG(AssertionIndex index));
- GenTree* optVnConstantAssertionProp(GenTree* tree, GenTree* stmt);
// Assertion propagation functions.
GenTree* optAssertionProp(ASSERT_VALARG_TP assertions, GenTree* tree, GenTree* stmt);
unsigned loopNum,
BasicBlock* head,
BasicBlock* slow);
- void optInsertLoopCloningStress(BasicBlock* head);
protected:
ssize_t optGetArrayRefScaleAndIndex(GenTree* mul, GenTree** pIndex DEBUGARG(bool bRngChk));
- GenTree* optFindLocalInit(BasicBlock* block, GenTree* local, VARSET_TP* pKilledInOut, bool* isKilledAfterInit);
bool optReachWithoutCall(BasicBlock* srcBB, BasicBlock* dstBB);
// Method entry-points, instrs
- void* eeGetFieldAddress(CORINFO_FIELD_HANDLE handle, void*** ppIndir);
-
CORINFO_METHOD_HANDLE eeMarkNativeTarget(CORINFO_METHOD_HANDLE method);
CORINFO_EE_INFO eeInfo;
#endif
}
- // Exceptions
-
- unsigned eeGetEHcount(CORINFO_METHOD_HANDLE handle);
-
// Debugging support - Line number info
void eeGetStmtOffsets();
void unwindPushPopMaskInt(regMaskTP mask, bool useOpsize16);
void unwindPushPopMaskFloat(regMaskTP mask);
- void unwindSplit(FuncInfoDsc* func);
#endif // _TARGET_ARM_
// if this changes "*pDest".
BOOL tiMergeToCommonParent(typeInfo* pDest, const typeInfo* pSrc, bool* changed) const;
- // Set pDest from the primitive value type.
- // Eg. System.Int32 -> ELEMENT_TYPE_I4
-
- BOOL tiFromPrimitiveValueClass(typeInfo* pDest, const typeInfo* pVC) const;
-
#ifdef DEBUG
// <BUGNUM> VSW 471305
// IJW allows assigning REF to BYREF. The following allows us to temporarily
}
};
-class IncLclVarRefCountsVisitor final : public GenTreeVisitor<IncLclVarRefCountsVisitor>
-{
-public:
- enum
- {
- DoPreOrder = true,
- DoLclVarsOnly = true
- };
-
- IncLclVarRefCountsVisitor(Compiler* compiler);
- Compiler::fgWalkResult PreOrderVisit(GenTree** use, GenTree* user);
-
- static Compiler::fgWalkResult WalkTree(Compiler* compiler, GenTree* tree);
-};
-
-class DecLclVarRefCountsVisitor final : public GenTreeVisitor<DecLclVarRefCountsVisitor>
-{
-public:
- enum
- {
- DoPreOrder = true,
- DoLclVarsOnly = true
- };
-
- DecLclVarRefCountsVisitor(Compiler* compiler);
- Compiler::fgWalkResult PreOrderVisit(GenTree** use, GenTree* user);
-
- static Compiler::fgWalkResult WalkTree(Compiler* compiler, GenTree* tree);
-};
-
/*
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
void dLiveness();
void dCVarSet(VARSET_VALARG_TP vars);
-void dVarSet(VARSET_VALARG_TP vars);
void dRegMask(regMaskTP mask);
void dFuncIR();
}
}
-/*****************************************************************************
- * If the tree is a tracked local variable, return its LclVarDsc ptr.
- */
-
-inline LclVarDsc* Compiler::optIsTrackedLocal(GenTree* tree)
-{
- LclVarDsc* varDsc;
- unsigned lclNum;
-
- if (tree->gtOper != GT_LCL_VAR)
- {
- return nullptr;
- }
-
- lclNum = tree->gtLclVarCommon.gtLclNum;
-
- assert(lclNum < lvaCount);
- varDsc = lvaTable + lclNum;
-
- /* if variable not tracked, return NULL */
- if (!varDsc->lvTracked)
- {
- return nullptr;
- }
-
- return varDsc;
-}
-
/*
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
CompMemKindMacro(FlowList)
CompMemKindMacro(TreeStatementList)
CompMemKindMacro(SiScope)
-CompMemKindMacro(FlatFPStateX87)
CompMemKindMacro(DominatorMemory)
CompMemKindMacro(LSRA)
CompMemKindMacro(LSRA_Interval)
// DataFlow flow(m_pCompiler);
// flow.ForwardAnalysis(callback);
//
-// The "callback" object needs to implement the necessary callback
-// functions that the "flow" object will call as the data flow
-// analysis progresses.
+// The "callback" object needs to implement the following member
+// functions that the "flow" object will call as the data flow
+// analysis progresses:
//
+// class Callback
+// {
+// public:
+// void StartMerge(BasicBlock* block);
+// void Merge(BasicBlock* block, BasicBlock* pred, flowList* preds);
+// bool EndMerge(BasicBlock* block);
+// };
#pragma once
#include "compiler.h"
DataFlow();
public:
- // The callback interface that needs to be implemented by anyone
- // needing updates by the dataflow object.
- class Callback
- {
- public:
- Callback(Compiler* pCompiler);
-
- void StartMerge(BasicBlock* block);
- void Merge(BasicBlock* block, BasicBlock* pred, flowList* preds);
- bool EndMerge(BasicBlock* block);
-
- private:
- Compiler* m_pCompiler;
- };
-
DataFlow(Compiler* pCompiler);
template <typename TCallback>
#ifdef TRANSLATE_PDB
- inline void SetIDSource(instrDesc* pID);
void MapCode(int ilOffset, BYTE* imgDest);
void MapFunc(int imgOff,
int procLen,
static emitJumpKind emitInsToJumpKind(instruction ins);
static emitJumpKind emitReverseJumpKind(emitJumpKind jumpKind);
-#ifdef _TARGET_ARM_
- static unsigned emitJumpKindCondCode(emitJumpKind jumpKind);
-#endif
-
#ifdef DEBUG
void emitInsSanityCheck(instrDesc* id);
#endif
/* Liveness of stack variables, and registers */
- void emitUpdateLiveGCvars(int offs, BYTE* addr, bool birth);
void emitUpdateLiveGCvars(VARSET_VALARG_TP vars, BYTE* addr);
void emitUpdateLiveGCregs(GCtype gcType, regMaskTP regs, BYTE* addr);
#endif // DEBUG
-/*****************************************************************************
- *
- * Given an arbitrary expression tree, attempts to find the set of all local variables
- * referenced by the tree, and return them as "*result".
- * If "findPtr" is null, this is a tracked variable set;
- * if it is non-null, this is an "all var set."
- * The "*result" value is valid only if the call returns "true." It may return "false"
- * for several reasons:
- * If "findPtr" is NULL, and the expression contains an untracked variable.
- * If "findPtr" is non-NULL, and the expression contains a variable that can't be represented
- * in an "all var set."
- * If the expression accesses address-exposed variables.
- *
- * If there
- * are any indirections or global refs in the expression, the "*refsPtr" argument
- * will be assigned the appropriate bit set based on the 'varRefKinds' type.
- * It won't be assigned anything when there are no indirections or global
- * references, though, so this value should be initialized before the call.
- * If we encounter an expression that is equal to *findPtr we set *findPtr
- * to NULL.
- */
-bool Compiler::lvaLclVarRefs(GenTree* tree, GenTree** findPtr, varRefKinds* refsPtr, void* result)
-{
- genTreeOps oper;
- unsigned kind;
- varRefKinds refs = VR_NONE;
- ALLVARSET_TP allVars(AllVarSetOps::UninitVal());
- VARSET_TP trkdVars(VarSetOps::UninitVal());
- if (findPtr)
- {
- AllVarSetOps::AssignNoCopy(this, allVars, AllVarSetOps::MakeEmpty(this));
- }
- else
- {
- VarSetOps::AssignNoCopy(this, trkdVars, VarSetOps::MakeEmpty(this));
- }
-
-AGAIN:
-
- assert(tree);
- assert(tree->gtOper != GT_STMT);
-
- /* Remember whether we've come across the expression we're looking for */
-
- if (findPtr && *findPtr == tree)
- {
- *findPtr = nullptr;
- }
-
- /* Figure out what kind of a node we have */
-
- oper = tree->OperGet();
- kind = tree->OperKind();
-
- /* Is this a constant or leaf node? */
-
- if (kind & (GTK_CONST | GTK_LEAF))
- {
- if (oper == GT_LCL_VAR)
- {
- unsigned lclNum = tree->gtLclVarCommon.gtLclNum;
-
- /* Should we use the variable table? */
-
- if (findPtr)
- {
- if (lclNum >= lclMAX_ALLSET_TRACKED)
- {
- return false;
- }
-
- AllVarSetOps::AddElemD(this, allVars, lclNum);
- }
- else
- {
- assert(lclNum < lvaCount);
- LclVarDsc* varDsc = lvaTable + lclNum;
-
- if (varDsc->lvTracked == false)
- {
- return false;
- }
-
- // Don't deal with expressions with address-exposed variables.
- if (varDsc->lvAddrExposed)
- {
- return false;
- }
-
- VarSetOps::AddElemD(this, trkdVars, varDsc->lvVarIndex);
- }
- }
- else if (oper == GT_LCL_FLD)
- {
- /* We can't track every field of every var. Moreover, indirections
- may access different parts of the var as different (but
- overlapping) fields. So just treat them as indirect accesses */
-
- if (varTypeIsGC(tree->TypeGet()))
- {
- refs = VR_IND_REF;
- }
- else
- {
- refs = VR_IND_SCL;
- }
- }
- else if (oper == GT_CLS_VAR)
- {
- refs = VR_GLB_VAR;
- }
-
- if (refs != VR_NONE)
- {
- /* Write it back to callers parameter using an 'or' */
- *refsPtr = varRefKinds((*refsPtr) | refs);
- }
- lvaLclVarRefsAccumIntoRes(findPtr, result, allVars, trkdVars);
- return true;
- }
-
- /* Is it a 'simple' unary/binary operator? */
-
- if (kind & GTK_SMPOP)
- {
- if (oper == GT_IND)
- {
- assert(tree->gtOp.gtOp2 == nullptr);
-
- /* Set the proper indirection bit */
-
- if ((tree->gtFlags & GTF_IND_INVARIANT) == 0)
- {
- if (varTypeIsGC(tree->TypeGet()))
- {
- refs = VR_IND_REF;
- }
- else
- {
- refs = VR_IND_SCL;
- }
-
- // If the flag GTF_IND_TGTANYWHERE is set this indirection
- // could also point at a global variable
-
- if (tree->gtFlags & GTF_IND_TGTANYWHERE)
- {
- refs = varRefKinds(((int)refs) | ((int)VR_GLB_VAR));
- }
- }
-
- /* Write it back to callers parameter using an 'or' */
- *refsPtr = varRefKinds((*refsPtr) | refs);
-
- // For IL volatile memory accesses we mark the GT_IND node
- // with a GTF_DONT_CSE flag.
- //
- // This flag is also set for the left hand side of an assignment.
- //
- // If this flag is set then we return false
- //
- if (tree->gtFlags & GTF_DONT_CSE)
- {
- return false;
- }
- }
-
- if (tree->gtGetOp2IfPresent())
- {
- /* It's a binary operator */
- if (!lvaLclVarRefsAccum(tree->gtOp.gtOp1, findPtr, refsPtr, &allVars, &trkdVars))
- {
- return false;
- }
- // Otherwise...
- tree = tree->gtOp.gtOp2;
- assert(tree);
- goto AGAIN;
- }
- else
- {
- /* It's a unary (or nilary) operator */
-
- tree = tree->gtOp.gtOp1;
- if (tree)
- {
- goto AGAIN;
- }
-
- lvaLclVarRefsAccumIntoRes(findPtr, result, allVars, trkdVars);
- return true;
- }
- }
-
- switch (oper)
- {
- case GT_ARR_ELEM:
- if (!lvaLclVarRefsAccum(tree->gtArrElem.gtArrObj, findPtr, refsPtr, &allVars, &trkdVars))
- {
- return false;
- }
-
- unsigned dim;
- for (dim = 0; dim < tree->gtArrElem.gtArrRank; dim++)
- {
- VARSET_TP tmpVs(VarSetOps::UninitVal());
- if (!lvaLclVarRefsAccum(tree->gtArrElem.gtArrInds[dim], findPtr, refsPtr, &allVars, &trkdVars))
- {
- return false;
- }
- }
- lvaLclVarRefsAccumIntoRes(findPtr, result, allVars, trkdVars);
- return true;
-
- case GT_ARR_OFFSET:
- if (!lvaLclVarRefsAccum(tree->gtArrOffs.gtOffset, findPtr, refsPtr, &allVars, &trkdVars))
- {
- return false;
- }
- // Otherwise...
- if (!lvaLclVarRefsAccum(tree->gtArrOffs.gtIndex, findPtr, refsPtr, &allVars, &trkdVars))
- {
- return false;
- }
- // Otherwise...
- if (!lvaLclVarRefsAccum(tree->gtArrOffs.gtArrObj, findPtr, refsPtr, &allVars, &trkdVars))
- {
- return false;
- }
- // Otherwise...
- lvaLclVarRefsAccumIntoRes(findPtr, result, allVars, trkdVars);
- return true;
-
- case GT_ARR_BOUNDS_CHECK:
-#ifdef FEATURE_SIMD
- case GT_SIMD_CHK:
-#endif // FEATURE_SIMD
-#ifdef FEATURE_HW_INTRINSICS
- case GT_HW_INTRINSIC_CHK:
-#endif // FEATURE_HW_INTRINSICS
- {
- if (!lvaLclVarRefsAccum(tree->gtBoundsChk.gtIndex, findPtr, refsPtr, &allVars, &trkdVars))
- {
- return false;
- }
- // Otherwise...
- if (!lvaLclVarRefsAccum(tree->gtBoundsChk.gtArrLen, findPtr, refsPtr, &allVars, &trkdVars))
- {
- return false;
- }
- // Otherwise...
- lvaLclVarRefsAccumIntoRes(findPtr, result, allVars, trkdVars);
- return true;
- }
-
- case GT_STORE_DYN_BLK:
- if (!lvaLclVarRefsAccum(tree->gtDynBlk.Data(), findPtr, refsPtr, &allVars, &trkdVars))
- {
- return false;
- }
- // Otherwise...
- __fallthrough;
- case GT_DYN_BLK:
- if (!lvaLclVarRefsAccum(tree->gtDynBlk.Addr(), findPtr, refsPtr, &allVars, &trkdVars))
- {
- return false;
- }
- // Otherwise...
- if (!lvaLclVarRefsAccum(tree->gtDynBlk.gtDynamicSize, findPtr, refsPtr, &allVars, &trkdVars))
- {
- return false;
- }
- // Otherwise...
- lvaLclVarRefsAccumIntoRes(findPtr, result, allVars, trkdVars);
- break;
-
- case GT_CALL:
- /* Allow calls to the Shared Static helper */
- if (IsSharedStaticHelper(tree))
- {
- *refsPtr = varRefKinds((*refsPtr) | VR_INVARIANT);
- lvaLclVarRefsAccumIntoRes(findPtr, result, allVars, trkdVars);
- return true;
- }
- break;
- default:
- break;
-
- } // end switch (oper)
-
- return false;
-}
-
-bool Compiler::lvaLclVarRefsAccum(
- GenTree* tree, GenTree** findPtr, varRefKinds* refsPtr, ALLVARSET_TP* allVars, VARSET_TP* trkdVars)
-{
- if (findPtr)
- {
- ALLVARSET_TP tmpVs(AllVarSetOps::UninitVal());
- if (!lvaLclVarRefs(tree, findPtr, refsPtr, &tmpVs))
- {
- return false;
- }
- // Otherwise...
- AllVarSetOps::UnionD(this, *allVars, tmpVs);
- }
- else
- {
- VARSET_TP tmpVs(VarSetOps::UninitVal());
- if (!lvaLclVarRefs(tree, findPtr, refsPtr, &tmpVs))
- {
- return false;
- }
- // Otherwise...
- VarSetOps::UnionD(this, *trkdVars, tmpVs);
- }
- return true;
-}
-
-void Compiler::lvaLclVarRefsAccumIntoRes(GenTree** findPtr,
- void* result,
- ALLVARSET_VALARG_TP allVars,
- VARSET_VALARG_TP trkdVars)
-{
- if (findPtr)
- {
- ALLVARSET_TP* avsPtr = (ALLVARSET_TP*)result;
- AllVarSetOps::AssignNoCopy(this, (*avsPtr), allVars);
- }
- else
- {
- VARSET_TP* vsPtr = (VARSET_TP*)result;
- VarSetOps::AssignNoCopy(this, (*vsPtr), trkdVars);
- }
-}
-
/*****************************************************************************
*
* Return a relational operator that is the reverse of the given one.
const size_t TREE_NODE_SZ_LARGE = sizeof(GenTreeCall);
-/*****************************************************************************
- * Types returned by GenTree::lvaLclVarRefs()
- */
-
enum varRefKinds
{
VR_INVARIANT = 0x00, // an invariant value
VR_IND_SCL = 0x02, // a non-object reference
VR_GLB_VAR = 0x04, // a global (clsVar)
};
-// Add a temp define to avoid merge conflict.
-#define VR_IND_PTR VR_IND_REF
/*****************************************************************************/
#endif // !GENTREE_H
#else
#define DOUBLE_ALIGN 0 // no special handling for double alignment
#endif
-/*****************************************************************************/
-#ifdef DEBUG
-extern void _cdecl debugStop(const char* why, ...);
-#endif
-/*****************************************************************************/
#ifdef DEBUG
void record(unsigned size);
private:
- void ensureAllocated();
-
unsigned m_sizeCount;
const unsigned* const m_sizeTable;
unsigned m_counts[HISTOGRAM_MAX_SIZE_COUNT];
void gcMarkRegSetByref(regMaskTP regMask DEBUGARG(bool forceOutput = false));
void gcMarkRegSetNpt(regMaskTP regMask DEBUGARG(bool forceOutput = false));
void gcMarkRegPtrVal(regNumber reg, var_types type);
- void gcMarkRegPtrVal(GenTree* tree);
#ifdef DEBUG
void gcDspGCrefSetChanges(regMaskTP gcRegGCrefSetNew DEBUGARG(bool forceOutput = false));
#endif // FEATURE_HW_INTRINSICS
// Utility functions
- void MorphBlkIntoHelperCall(GenTree* pTree, GenTree* treeStmt);
-
public:
static bool IndirsAreEquivalent(GenTree* pTreeA, GenTree* pTreeB);
public:
RefInfoListNodePool(Compiler* compiler, unsigned preallocate = defaultPreallocation);
RefInfoListNode* GetNode(RefPosition* r, GenTree* t, unsigned regIdx = 0);
- void ReturnNodes(RefInfoList& list);
void ReturnNode(RefInfoListNode* listNode);
};
void resolveEdges();
- // Finally, the register assignments are written back to the tree nodes.
- void recordRegisterAssignments();
-
// Keep track of how many temp locations we'll need for spill
void initMaxSpill();
void updateMaxSpill(RefPosition* refPosition);
bool canSpillReg(RegRecord* physRegRecord, LsraLocation refLocation, unsigned* recentAssignedRefWeight);
bool isRegInUse(RegRecord* regRec, RefPosition* refPosition);
- RefType CheckBlockType(BasicBlock* block, BasicBlock* prevBlock);
-
// insert refpositions representing prolog zero-inits which will be added later
void insertZeroInitRefPositions();
- void AddMapping(GenTree* node, LsraLocation loc);
-
// add physreg refpositions for a tree node, based on calling convention and instruction selection predictions
void addRefsForPhysRegMask(regMaskTP mask, LsraLocation currentLoc, RefType refType, bool isLastUse);
return false;
}
- static Compiler::fgWalkResult markAddrModeOperandsHelperMD(GenTree* tree, void* p);
-
// Helpers for getKillSetForNode().
regMaskTP getKillSetForStoreInd(GenTreeStoreInd* tree);
regMaskTP getKillSetForShiftRotate(GenTreeOp* tree);
void associateRefPosWithInterval(RefPosition* rp);
- void associateRefPosWithRegister(RefPosition* rp);
-
unsigned getWeight(RefPosition* refPos);
/*****************************************************************************
regNumber reg = REG_NA,
BasicBlock* currentBlock = nullptr);
- void dumpBlockHeader(BasicBlock* block);
-
void validateIntervals();
#endif // DEBUG
pendingDelayFree = false;
}
- RefInfoListNode* getRefInfo(GenTree* node);
- RefInfoListNode* getRefInfo(GenTree* node, int multiRegIdx);
-
RefPosition* BuildUse(GenTree* operand, regMaskTP candidates = RBM_NONE, int multiRegIdx = 0);
void setDelayFree(RefPosition* use);
// These methods return the number of sources.
int BuildNode(GenTree* stmt);
- void BuildCheckByteable(GenTree* tree);
GenTree* getTgtPrefOperand(GenTreeOp* tree);
- bool CheckAndSetDelayFree(GenTree* delayUseSrc);
bool supportsSpecialPutArg();
int BuildSimple(GenTree* tree);
return scale;
}
-/*****************************************************************************
- * Find the last assignment to of the local variable in the block. Return
- * RHS or NULL. If any local variable in the RHS has been killed in
- * intervening code, return NULL. If the variable being searched for is killed
- * in the intervening code, return NULL.
- *
- */
-
-GenTree* Compiler::optFindLocalInit(BasicBlock* block,
- GenTree* local,
- VARSET_TP* pKilledInOut,
- bool* pLhsRhsKilledAfterInit)
-{
- assert(pKilledInOut);
- assert(pLhsRhsKilledAfterInit);
-
- *pLhsRhsKilledAfterInit = false;
-
- unsigned LclNum = local->gtLclVarCommon.gtLclNum;
-
- GenTree* list = block->bbTreeList;
- if (list == nullptr)
- {
- return nullptr;
- }
-
- GenTree* rhs = nullptr;
- GenTree* stmt = list;
- do
- {
- stmt = stmt->gtPrev;
- if (stmt == nullptr)
- {
- break;
- }
-
- GenTree* tree = stmt->gtStmt.gtStmtExpr;
- // If we encounter an assignment to a local variable,
- if (tree->OperIs(GT_ASG) && (tree->gtOp.gtOp1->gtOper == GT_LCL_VAR))
- {
- // And the assigned variable equals the input local,
- if (tree->gtOp.gtOp1->gtLclVarCommon.gtLclNum == LclNum)
- {
- // If the assignment is '=' and it is not a conditional, then return rhs.
- if ((tree->gtFlags & GTF_COLON_COND) == 0)
- {
- rhs = tree->gtOp.gtOp2;
- }
- // If the assignment is 'op=' or a conditional equal, then the search ends here,
- // as we found a kill to the input local.
- else
- {
- *pLhsRhsKilledAfterInit = true;
- assert(rhs == nullptr);
- }
- break;
- }
- else
- {
- LclVarDsc* varDsc = optIsTrackedLocal(tree->gtOp.gtOp1);
- if (varDsc == nullptr)
- {
- return nullptr;
- }
- VarSetOps::AddElemD(this, *pKilledInOut, varDsc->lvVarIndex);
- }
- }
- } while (stmt != list);
-
- if (rhs == nullptr)
- {
- return nullptr;
- }
-
- // If any local in the RHS is killed in intervening code, or RHS has an indirection, return NULL.
- varRefKinds rhsRefs = VR_NONE;
- VARSET_TP rhsLocals(VarSetOps::UninitVal());
- bool b = lvaLclVarRefs(rhs, nullptr, &rhsRefs, &rhsLocals);
- if (!b || !VarSetOps::IsEmptyIntersection(this, rhsLocals, *pKilledInOut) || (rhsRefs != VR_NONE))
- {
- // If RHS has been indirectly referenced, consider it a write and a kill.
- *pLhsRhsKilledAfterInit = true;
- return nullptr;
- }
-
- return rhs;
-}
-
//------------------------------------------------------------------------------
// optObtainLoopCloningOpts: Identify optimization candidates and update
// the "context" for array optimizations.
virtual void DoPhase() override;
static void RewriteAssignmentIntoStoreLcl(GenTreeOp* assignment);
- static void MorphAsgIntoStoreObj(Compiler::fgWalkData* data, GenTreeStmt* stmt, GenTree** ppTree);
private:
inline LIR::Range& BlockRange() const
template <typename T>
static T EvalOp(VNFunc vnf, T v0);
- // returns vnf(v0) for int/INT32
- int EvalOpInt(VNFunc vnf, int v0);
-
// returns vnf(v0, v1).
template <typename T>
T EvalOp(VNFunc vnf, T v0, T v1);
- // returns vnf(v0, v1) for int/INT32
- int EvalOpInt(VNFunc vnf, int v0, int v1);
-
// return vnf(v0) or vnf(v0, v1), respectively (must, of course be unary/binary ops, respectively.)
template <typename T>
static T EvalOpSpecialized(VNFunc vnf, T v0);
template <typename T>
static int EvalComparison(VNFunc vnf, T v0, T v1);
- template <typename T>
- static int EvalOrderedComparisonFloat(VNFunc vnf, T v0, T v1);
// Should only instantiate (in a non-trivial way) for "int" and "INT64". Returns true iff dividing "v0" by "v1"
// would produce integer overflow (an ArithmeticException -- *not* division by zero, which is separate.)
// It returns NoVN for a "typ" that has no one value, such as TYP_REF.
ValueNum VNOneForType(var_types typ);
- // Returns the value number for negative one of the given "typ".
- // It returns NoVN for a "typ" that has no negative one value, such as TYP_REF, or TYP_UINT
- ValueNum VNNegOneForType(var_types typ);
-
// Create or return the existimg value number representing a singleton exception set
// for the the exception value "x".
ValueNum VNExcSetSingleton(ValueNum x);
return ConstantValueInternal<T>(vn DEBUGARG(true));
}
- // Given a value number "vn", go through the list of VNs that are handles
- // to find if it is present, if so, return "true", else "false."
- bool IsHandle(ValueNum vn);
-
// Requires "mthFunc" to be an intrinsic math function (one of the allowable values for the "gtMath" field
// of a GenTreeMath node). For unary ops, return the value number for the application of this function to
// "arg0VN". For binary ops, return the value number for the application of this function to "arg0VN" and
// Returns true if "vn" is a reserved value number
static bool isReservedVN(ValueNum);
-#define VALUENUM_SUPPORT_MERGE 0
-#if VALUENUM_SUPPORT_MERGE
- // If we're going to support the Merge operation, and do it right, we really need to use an entire
- // egraph data structure, so that we can do congruence closure, and discover congruences implied
- // by the eq-class merge.
-
- // It may be that we provisionally give two expressions distinct value numbers, then later discover
- // that the values of the expressions are provably equal. We allow the two value numbers to be
- // "merged" -- after the merge, they represent the same abstract value.
- void MergeVNs(ValueNum vn1, ValueNum vn2);
-#endif
-
private:
// We will allocate value numbers in "chunks". Each chunk will have the same type and "constness".
static const unsigned LogChunkSize = 6;