// inline
regMaskTP CodeGenInterface::genGetRegMask(GenTree* tree)
{
- assert(tree->gtOper == GT_LCL_VAR || tree->gtOper == GT_REG_VAR);
+ assert(tree->gtOper == GT_LCL_VAR);
regMaskTP regMask = RBM_NONE;
const LclVarDsc* varDsc = compiler->lvaTable + tree->gtLclVarCommon.gtLclNum;
#ifdef FEATURE_COUNT_GC_WRITE_BARRIERS
// We classify the "tgt" trees as follows:
// If "tgt" is of the form (where [ x ] indicates an optional x, and { x1, ..., xn } means "one of the x_i forms"):
- // IND [-> ADDR -> IND] -> { GT_LCL_VAR, GT_REG_VAR, ADD({GT_LCL_VAR, GT_REG_VAR}, X), ADD(X, (GT_LCL_VAR,
- // GT_REG_VAR)) }
- // then let "v" be the GT_LCL_VAR or GT_REG_VAR.
+ // IND [-> ADDR -> IND] -> { GT_LCL_VAR, ADD({GT_LCL_VAR}, X), ADD(X, (GT_LCL_VAR)) }
+ // then let "v" be the GT_LCL_VAR.
// * If "v" is the return buffer argument, classify as CWBKind_RetBuf.
// * If "v" is another by-ref argument, classify as CWBKind_ByRefArg.
// * Otherwise, classify as CWBKind_OtherByRefLocal.
{
indArg = indArg->gtOp.gtOp1->gtOp.gtOp1;
}
- if (indArg->gtOper == GT_LCL_VAR || indArg->gtOper == GT_REG_VAR)
+ if (indArg->gtOper == GT_LCL_VAR)
{
lcl = indArg;
}
else if (indArg->gtOper == GT_ADD)
{
- if (indArg->gtOp.gtOp1->gtOper == GT_LCL_VAR || indArg->gtOp.gtOp1->gtOper == GT_REG_VAR)
+ if (indArg->gtOp.gtOp1->gtOper == GT_LCL_VAR)
{
lcl = indArg->gtOp.gtOp1;
}
- else if (indArg->gtOp.gtOp2->gtOper == GT_LCL_VAR || indArg->gtOp.gtOp2->gtOper == GT_REG_VAR)
+ else if (indArg->gtOp.gtOp2->gtOper == GT_LCL_VAR)
{
lcl = indArg->gtOp.gtOp2;
}
if (lcl != NULL)
{
wbKind = CWBKind_OtherByRefLocal; // Unclassified local variable.
- unsigned lclNum = 0;
- if (lcl->gtOper == GT_LCL_VAR)
- lclNum = lcl->gtLclVarCommon.gtLclNum;
- else
- {
- assert(lcl->gtOper == GT_REG_VAR);
- lclNum = lcl->gtRegVar.gtLclNum;
- }
+ unsigned lclNum = lcl->AsLclVar()->GetLclNum();
if (lclNum == compiler->info.compRetBuffArg)
{
wbKind = CWBKind_RetBuf; // Ret buff. Can happen if the struct exceeds the size limit.
var_types lclTyp = genActualType(varDsc->TypeGet());
emitAttr size = emitTypeSize(lclTyp);
- bool restoreRegVar = false;
- if (tree->gtOper == GT_REG_VAR)
- {
- tree->SetOper(GT_LCL_VAR);
- restoreRegVar = true;
- }
-
instruction storeIns = ins_Store(lclTyp, compiler->isSIMDTypeLocalAligned(varNum));
assert(varDsc->lvRegNum == tree->gtRegNum);
inst_TT_RV(storeIns, tree, tree->gtRegNum, 0, size);
- if (restoreRegVar)
- {
- tree->SetOper(GT_REG_VAR);
- }
-
genUpdateRegLife(varDsc, /*isBorn*/ false, /*isDying*/ true DEBUGARG(tree));
gcInfo.gcMarkRegSetNpt(varDsc->lvRegMask());
case GT_LCL_FLD_ADDR:
case GT_STORE_LCL_FLD:
case GT_STORE_LCL_VAR:
- case GT_REG_VAR:
-
if (tree->gtFlags & GTF_VAR_DEF)
{
chars += printf("[VAR_DEF]");
chars += printf("[VAR_CSE_REF]");
}
#endif
- if (op == GT_REG_VAR)
- {
- if (tree->gtFlags & GTF_REG_BIRTH)
- {
- chars += printf("[REG_BIRTH]");
- }
- }
break;
case GT_NOP:
case GT_LCL_VAR:
case GT_LCL_VAR_ADDR:
case GT_STORE_LCL_VAR:
- case GT_REG_VAR:
-
lclNum = tree->gtLclVarCommon.gtLclNum;
comp->gtGetLclVarNameInfo(lclNum, &ilKind, &ilName, &ilNum);
if (ilName != nullptr)
}
}
- if (op == GT_REG_VAR)
- {
- if (isFloatRegType(tree->gtType))
- {
- assert(tree->gtRegVar.gtRegNum == tree->gtRegNum);
- chars += printf("(FPV%u)", tree->gtRegNum);
- }
- else
- {
- chars += printf("(%s)", comp->compRegVarName(tree->gtRegVar.gtRegNum));
- }
- }
-
hasSsa = true;
break;
#endif // !FEATURE_EH_FUNCLETS
case GT_PHI_ARG:
case GT_JMPTABLE:
- case GT_REG_VAR:
case GT_CLS_VAR:
case GT_CLS_VAR_ADDR:
case GT_ARGPLACE:
#endif // !FEATURE_EH_FUNCLETS
case GT_PHI_ARG:
case GT_JMPTABLE:
- case GT_REG_VAR:
case GT_CLS_VAR:
case GT_CLS_VAR_ADDR:
case GT_ARGPLACE:
{
VARSET_TP varBits(VarSetOps::MakeEmpty(this));
- assert(tree->gtOper == GT_LCL_VAR || tree->gtOper == GT_LCL_FLD || tree->gtOper == GT_REG_VAR);
+ assert(tree->gtOper == GT_LCL_VAR || tree->gtOper == GT_LCL_FLD);
unsigned int lclNum = tree->gtLclVarCommon.gtLclNum;
LclVarDsc* varDsc = lvaTable + lclNum;
case GT_CLS_VAR:
return WBF_BarrierUnchecked;
- case GT_REG_VAR: /* Definitely not in the managed heap */
- case GT_LCL_VAR:
+ case GT_LCL_VAR: /* Definitely not in the managed heap */
case GT_LCL_FLD:
case GT_STORE_LCL_VAR:
case GT_STORE_LCL_FLD:
// No need for a GC barrier when writing to a local variable.
return GCInfo::WBF_NoBarrier;
}
- if (tgtAddr->OperGet() == GT_LCL_VAR || tgtAddr->OperGet() == GT_REG_VAR)
+ if (tgtAddr->OperGet() == GT_LCL_VAR)
{
- unsigned lclNum = 0;
- if (tgtAddr->gtOper == GT_LCL_VAR)
- {
- lclNum = tgtAddr->gtLclVar.gtLclNum;
- }
- else
- {
- assert(tgtAddr->gtOper == GT_REG_VAR);
- lclNum = tgtAddr->gtRegVar.gtLclNum;
- }
+ unsigned lclNum = tgtAddr->AsLclVar()->GetLclNum();
LclVarDsc* varDsc = &compiler->lvaTable[lclNum];
/* static */
void GenTree::InitNodeSize()
{
- /* 'GT_LCL_VAR' often gets changed to 'GT_REG_VAR' */
-
- assert(GenTree::s_gtNodeSizes[GT_LCL_VAR] >= GenTree::s_gtNodeSizes[GT_REG_VAR]);
-
/* Set all sizes to 'small' first */
for (unsigned op = 0; op <= GT_COUNT; op++)
static_assert_no_msg(sizeof(GenTreeLclVarCommon) <= TREE_NODE_SZ_SMALL);
static_assert_no_msg(sizeof(GenTreeLclVar) <= TREE_NODE_SZ_SMALL);
static_assert_no_msg(sizeof(GenTreeLclFld) <= TREE_NODE_SZ_SMALL);
- static_assert_no_msg(sizeof(GenTreeRegVar) <= TREE_NODE_SZ_SMALL);
static_assert_no_msg(sizeof(GenTreeCC) <= TREE_NODE_SZ_SMALL);
static_assert_no_msg(sizeof(GenTreeCast) <= TREE_NODE_SZ_LARGE); // *** large node
static_assert_no_msg(sizeof(GenTreeBox) <= TREE_NODE_SZ_LARGE); // *** large node
#endif // !FEATURE_EH_FUNCLETS
case GT_PHI_ARG:
case GT_JMPTABLE:
- case GT_REG_VAR:
case GT_CLS_VAR:
case GT_CLS_VAR_ADDR:
case GT_ARGPLACE:
GenTreeClsVar(tree->gtType, tree->gtClsVar.gtClsVarHnd, tree->gtClsVar.gtFieldSeq);
break;
- case GT_REG_VAR:
- assert(!"clone regvar");
-
default:
if (!complexOK)
{
copy = gtNewArgPlaceHolderNode(tree->gtType, tree->gtArgPlace.gtArgPlaceClsHnd);
goto DONE;
- case GT_REG_VAR:
- NO_WAY("Cloning of GT_REG_VAR node not supported");
- goto DONE;
-
case GT_FTN_ADDR:
copy = new (this, oper) GenTreeFptrVal(tree->gtType, tree->gtFptrVal.gtFptrMethod);
#endif // !FEATURE_EH_FUNCLETS
case GT_PHI_ARG:
case GT_JMPTABLE:
- case GT_REG_VAR:
case GT_CLS_VAR:
case GT_CLS_VAR_ADDR:
case GT_ARGPLACE:
case GT_LCL_FLD_ADDR:
case GT_STORE_LCL_FLD:
case GT_STORE_LCL_VAR:
- case GT_REG_VAR:
if (tree->gtFlags & GTF_VAR_USEASG)
{
printf("U");
}
break;
- case GT_REG_VAR:
- printf(" ");
- gtDispLclVar(tree->gtRegVar.gtLclNum);
- if (isFloatRegType(tree->gtType))
- {
- assert(tree->gtRegVar.gtRegNum == tree->gtRegNum);
- printf(" FPV%u", tree->gtRegNum);
- }
- else
- {
- printf(" %s", compRegVarName(tree->gtRegVar.gtRegNum));
- }
-
- varNum = tree->gtRegVar.gtLclNum;
- varDsc = &lvaTable[varNum];
-
- if (varDsc->lvTracked && fgLocalVarLivenessDone && ((tree->gtFlags & GTF_VAR_DEATH) != 0))
- {
- printf(" (last use)");
- }
-
- break;
-
case GT_JMP:
{
const char* methodName;
// well to make sure it's the right operator for the particular flag.
//---------------------------------------------------------------------
-// NB: GTF_VAR_* and GTF_REG_* share the same namespace of flags, because
-// GT_LCL_VAR nodes may be changed to GT_REG_VAR nodes without resetting
-// the flags. These are also used by GT_LCL_FLD.
+// NB: GTF_VAR_* and GTF_REG_* share the same namespace of flags.
+// These flags are also used by GT_LCL_FLD.
#define GTF_VAR_DEF 0x80000000 // GT_LCL_VAR -- this is a definition
#define GTF_VAR_USEASG 0x40000000 // GT_LCL_VAR -- this is a partial definition, a use of the previous definition is implied
// A partial definition usually occurs when a struct field is assigned to (s.f = ...) or
// TODO-Cleanup: Currently, GTF_REG_BIRTH is used only by stackfp
// We should consider using it more generally for VAR_BIRTH, instead of
// GTF_VAR_DEF && !GTF_VAR_USEASG
-#define GTF_REG_BIRTH 0x04000000 // GT_REG_VAR -- enregistered variable born here
-#define GTF_VAR_DEATH 0x02000000 // GT_LCL_VAR, GT_REG_VAR -- variable dies here (last use)
+#define GTF_REG_BIRTH 0x04000000 // GT_LCL_VAR, -- enregistered variable born here
+#define GTF_VAR_DEATH 0x02000000 // GT_LCL_VAR, -- variable dies here (last use)
#define GTF_VAR_ARR_INDEX 0x00000020 // The variable is part of (the index portion of) an array index expression.
// Shares a value with GTF_REVERSE_OPS, which is meaningless for local var.
static bool OperIsLocal(genTreeOps gtOper)
{
bool result = (OperKind(gtOper) & GTK_LOCAL) != 0;
- assert(result == (gtOper == GT_LCL_VAR || gtOper == GT_PHI_ARG || gtOper == GT_REG_VAR ||
- gtOper == GT_LCL_FLD || gtOper == GT_STORE_LCL_VAR || gtOper == GT_STORE_LCL_FLD));
+ assert(result == (gtOper == GT_LCL_VAR || gtOper == GT_PHI_ARG || gtOper == GT_LCL_FLD ||
+ gtOper == GT_STORE_LCL_VAR || gtOper == GT_STORE_LCL_FLD));
return result;
}
static bool OperIsScalarLocal(genTreeOps gtOper)
{
- return (gtOper == GT_LCL_VAR || gtOper == GT_REG_VAR || gtOper == GT_STORE_LCL_VAR);
+ return (gtOper == GT_LCL_VAR || gtOper == GT_STORE_LCL_VAR);
}
static bool OperIsNonPhiLocal(genTreeOps gtOper)
bool IsRegVarDeath() const
{
- assert(OperGet() == GT_REG_VAR);
+ unreached();
return (gtFlags & GTF_VAR_DEATH) ? true : false;
}
bool IsRegVarBirth() const
{
- assert(OperGet() == GT_REG_VAR);
+ unreached();
return (gtFlags & GTF_REG_BIRTH) ? true : false;
}
+
bool IsReverseOp() const
{
return (gtFlags & GTF_REVERSE_OPS) ? true : false;
}
+
bool IsUnsigned() const
{
return ((gtFlags & GTF_UNSIGNED) != 0);
#endif
};
-struct GenTreeRegVar : public GenTreeLclVarCommon
-{
- // TODO-Cleanup: Note that the base class GenTree already has a gtRegNum field.
- // It's not clear exactly why a GT_REG_VAR has a separate field. When
- // GT_REG_VAR is created, the two are identical. It appears that they may
- // or may not remain so. In particular, there is a comment in stackfp.cpp
- // that states:
- //
- // There used to be an assertion: assert(src->gtRegNum == src->gtRegVar.gtRegNum, ...)
- // here, but there's actually no reason to assume that. AFAICT, for FP vars under stack FP,
- // src->gtRegVar.gtRegNum is the allocated stack pseudo-register, but src->gtRegNum is the
- // FP stack position into which that is loaded to represent a particular use of the variable.
- //
- // It might be the case that only for stackfp do they ever differ.
- //
- // The following might be possible: the GT_REG_VAR node has a last use prior to a complex
- // subtree being evaluated. It could then be spilled from the register. Later,
- // it could be unspilled into a different register, which would be recorded at
- // the unspill time in the GenTree::gtRegNum, whereas GenTreeRegVar::gtRegNum
- // is left alone. It's not clear why that is useful.
- //
- // Assuming there is a particular use, like stack fp, that requires it, maybe we
- // can get rid of GT_REG_VAR and just leave it as GT_LCL_VAR, using the base class gtRegNum field.
- // If we need it for stackfp, we could add a GenTreeStackFPRegVar type, which carries both the
- // pieces of information, in a clearer and more specific way (in particular, with
- // a different member name).
- //
-
-private:
- regNumberSmall _gtRegNum;
-
-public:
- GenTreeRegVar(var_types type, unsigned lclNum, regNumber regNum) : GenTreeLclVarCommon(GT_REG_VAR, type, lclNum)
- {
- gtRegNum = regNum;
- }
-
- // The register number is stored in a small format (8 bits), but the getters return and the setters take
- // a full-size (unsigned) format, to localize the casts here.
-
- __declspec(property(get = GetRegNum, put = SetRegNum)) regNumber gtRegNum;
-
- regNumber GetRegNum() const
- {
- return (regNumber)_gtRegNum;
- }
-
- void SetRegNum(regNumber reg)
- {
- _gtRegNum = (regNumberSmall)reg;
- assert(_gtRegNum == reg);
- }
-
-#if DEBUGGABLE_GENTREE
- GenTreeRegVar() : GenTreeLclVarCommon()
- {
- }
-#endif
-};
-
/* gtCast -- conversion to a different type (GT_CAST) */
struct GenTreeCast : public GenTreeOp
// Nodes used only within the code generator:
//-----------------------------------------------------------------------------
-GTNODE(REG_VAR , GenTreeLclVar ,0,GTK_LEAF|GTK_LOCAL) // register variable
GTNODE(CLS_VAR , GenTreeClsVar ,0,GTK_LEAF) // static data member
GTNODE(CLS_VAR_ADDR , GenTreeClsVar ,0,GTK_LEAF) // static data member address
GTNODE(ARGPLACE , GenTreeArgPlace ,0,GTK_LEAF|GTK_NOVALUE|GTK_NOTLIR) // placeholder for a register arg
GTSTRUCT_1(LngCon , GT_CNS_LNG)
GTSTRUCT_1(DblCon , GT_CNS_DBL)
GTSTRUCT_1(StrCon , GT_CNS_STR)
-GTSTRUCT_N(LclVarCommon, GT_LCL_VAR, GT_LCL_FLD, GT_REG_VAR, GT_PHI_ARG, GT_STORE_LCL_VAR, GT_STORE_LCL_FLD, GT_LCL_VAR_ADDR, GT_LCL_FLD_ADDR)
+GTSTRUCT_N(LclVarCommon, GT_LCL_VAR, GT_LCL_FLD, GT_PHI_ARG, GT_STORE_LCL_VAR, GT_STORE_LCL_FLD, GT_LCL_VAR_ADDR, GT_LCL_FLD_ADDR)
GTSTRUCT_3(LclVar , GT_LCL_VAR, GT_LCL_VAR_ADDR, GT_STORE_LCL_VAR)
GTSTRUCT_3(LclFld , GT_LCL_FLD, GT_STORE_LCL_FLD, GT_LCL_FLD_ADDR)
-GTSTRUCT_1(RegVar , GT_REG_VAR)
GTSTRUCT_1(Cast , GT_CAST)
GTSTRUCT_1(Box , GT_BOX)
GTSTRUCT_1(Field , GT_FIELD)
VARSET_TP newLiveSet(VarSetOps::MakeCopy(this, liveSet));
assert(fgLocalVarLivenessDone == true);
GenTree* lclVarTree = tree; // After the tests below, "lclVarTree" will be the local variable.
- if (tree->gtOper == GT_LCL_VAR || tree->gtOper == GT_LCL_FLD || tree->gtOper == GT_REG_VAR ||
+ if (tree->gtOper == GT_LCL_VAR || tree->gtOper == GT_LCL_FLD ||
(lclVarTree = fgIsIndirOfAddrOfLocal(tree)) != nullptr)
{
const VARSET_TP& varBits(fgGetVarBits(lclVarTree));
{
if (treeNode->OperIsLocal() || treeNode->OperIsLocalAddr())
{
- // This should neither be a GT_REG_VAR nor GT_PHI_ARG.
- assert((treeNode->OperGet() != GT_REG_VAR) && (treeNode->OperGet() != GT_PHI_ARG));
+ // This should not be a GT_PHI_ARG.
+ assert(treeNode->OperGet() != GT_PHI_ARG);
GenTreeLclVarCommon* lcl = treeNode->AsLclVarCommon();
LclVarDsc* lclVar = &comp->lvaTable[lcl->gtLclNum];
{
structHnd = call->gtRetClsHnd;
if (info.compCompHnd->isStructRequiringStackAllocRetBuf(structHnd) &&
- !((dest->OperGet() == GT_LCL_VAR || dest->OperGet() == GT_REG_VAR) &&
- dest->gtLclVar.gtLclNum == info.compRetBuffArg))
+ !(dest->OperGet() == GT_LCL_VAR && dest->gtLclVar.gtLclNum == info.compRetBuffArg))
{
origDest = dest;
return GT_STORE_LCL_VAR;
case GT_LCL_FLD:
return GT_STORE_LCL_FLD;
- case GT_REG_VAR:
- noway_assert(!"reg vars only supported in classic backend\n");
- unreached();
default:
noway_assert(!"not a data load opcode\n");
unreached();
{
case GT_LCL_VAR:
case GT_LCL_FLD:
- case GT_REG_VAR:
case GT_PHI_ARG:
RewriteAssignmentIntoStoreLclCore(assignment, location, value, locationOp);
BlockRange().Remove(location);
// In case of multi-reg call nodes only the spill flag
// associated with the reg is cleared. Spill flag on
// call node should be cleared by the caller of this method.
- assert(tree->gtOper != GT_REG_VAR);
assert((tree->gtFlags & GTF_SPILL) != 0);
unsigned regFlags = 0;
switch (oper)
{
case GT_LCL_VAR:
- case GT_REG_VAR:
{
GenTreeLclVarCommon* lcl = tree->AsLclVarCommon();
unsigned lclNum = lcl->gtLclNum;
switch (lhs->OperGet())
{
case GT_LCL_VAR:
- case GT_REG_VAR:
{
GenTreeLclVarCommon* lcl = lhs->AsLclVarCommon();
unsigned lclDefSsaNum = GetSsaNumForLocalVarDef(lcl);